summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitrii Shcherbakov <dmitriis@users.noreply.gitlab.freedesktop.org>2021-08-29 14:18:29 +0300
committerBenjamin Berg <bberg@redhat.com>2021-12-16 12:53:41 +0100
commit999bca076cd69a6ae4df6dd668bcf45a6565fc44 (patch)
treea38fe215d9a30f34309a879e2b5840fd49cec259
parente198b0422220f14831de799e7a9bf7f0696df95f (diff)
Allow FpPrint data to be extended on enrollment.
* Allow FPI_PRINT_NBIS to be extended rather than overridden if a user supplies an existing FpPrint template with data; * Prints will only be extended if a device has the required feature. For image-based devices this feature is added by default since they typically do not have storage (this can be overridden at the child class level). Extending an existing FpPrint requires passing a template print with existing data during the enrollment process. This is done because the caller is responsible for maintaining the fingerprint database and doing the necessary deserialization operations if needed. The existing example program is updated to show how to do that.
-rw-r--r--examples/enroll.c63
-rw-r--r--examples/storage.c54
-rw-r--r--examples/storage.h8
-rw-r--r--libfprint/fp-device.c32
-rw-r--r--libfprint/fp-device.h2
-rw-r--r--libfprint/fp-image-device.c6
-rw-r--r--libfprint/fp-print.c23
-rw-r--r--tests/test-fpi-device.c124
-rwxr-xr-xtests/virtual-image.py45
9 files changed, 305 insertions, 52 deletions
diff --git a/examples/enroll.c b/examples/enroll.c
index f133c8b..10dfa5d 100644
--- a/examples/enroll.c
+++ b/examples/enroll.c
@@ -35,6 +35,7 @@ typedef struct _EnrollData
unsigned int sigint_handler;
FpFinger finger;
int ret_value;
+ gboolean update_fingerprint;
} EnrollData;
static void
@@ -84,7 +85,8 @@ on_enroll_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
/* Even if the device has storage, it may not be able to save all the
* metadata that the print contains, so we can always save a local copy
* containing the handle to the device print */
- int r = print_data_save (print, enroll_data->finger);
+ int r = print_data_save (print, enroll_data->finger,
+ enroll_data->update_fingerprint);
if (r < 0)
{
g_warning ("Data save failed, code %d", r);
@@ -124,6 +126,40 @@ on_enroll_progress (FpDevice *device,
fp_device_get_nr_enroll_stages (device));
}
+static gboolean
+should_update_fingerprint (void)
+{
+ int update_choice;
+ gboolean update_fingerprint = FALSE;
+
+ printf ("Should an existing fingerprint be updated instead of being replaced (if present)? "
+ "Enter Y/y or N/n to make a choice.\n");
+ update_choice = getchar ();
+ if (update_choice == EOF)
+ {
+ g_warning ("EOF encountered while reading a character");
+ return EXIT_FAILURE;
+ }
+
+ switch (update_choice)
+ {
+ case 'y':
+ case 'Y':
+ update_fingerprint = TRUE;
+ break;
+
+ case 'n':
+ case 'N':
+ update_fingerprint = FALSE;
+ break;
+
+ default:
+ g_warning ("Invalid choice %c, should be Y/y or N/n.", update_choice);
+ return EXIT_FAILURE;
+ }
+ return update_fingerprint;
+}
+
static void
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
{
@@ -139,13 +175,26 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
return;
}
- printf ("Opened device. It's now time to enroll your finger.\n\n");
+ printf ("Opened device.\n");
+
+ if (fp_device_has_feature (dev, FP_DEVICE_FEATURE_UPDATE_PRINT))
+ {
+ printf ("The device supports fingerprint updates.\n");
+ enroll_data->update_fingerprint = should_update_fingerprint ();
+ }
+ else
+ {
+ printf ("The device doesn't support fingerprint updates. Old prints will be erased.\n");
+ enroll_data->update_fingerprint = FALSE;
+ }
+
+ printf ("It's now time to enroll your finger.\n\n");
printf ("You will need to successfully scan your %s finger %d times to "
"complete the process.\n\n", finger_to_string (enroll_data->finger),
fp_device_get_nr_enroll_stages (dev));
printf ("Scan your finger now.\n");
- print_template = print_create_template (dev, enroll_data->finger);
+ print_template = print_create_template (dev, enroll_data->finger, enroll_data->update_fingerprint);
fp_device_enroll (dev, print_template, enroll_data->cancellable,
on_enroll_progress, NULL, NULL,
(GAsyncReadyCallback) on_enroll_completed,
@@ -171,11 +220,9 @@ main (void)
FpDevice *dev;
FpFinger finger;
- g_print ("This program will enroll the selected finger, unconditionally "
- "overwriting any print for the same finger that was enrolled "
- "previously. If you want to continue, press enter, otherwise hit "
- "Ctrl+C\n");
- getchar ();
+ g_print ("This program will enroll the selected finger overwriting any print for the same"
+ " finger that was enrolled previously. Fingerprint updates without erasing old data"
+ " are possible on devices supporting that. Ctrl+C interrupts program execution.\n");
g_print ("Choose the finger to enroll:\n");
finger = finger_chooser ();
diff --git a/examples/storage.c b/examples/storage.c
index 6c92dba..b84c72d 100644
--- a/examples/storage.c
+++ b/examples/storage.c
@@ -102,8 +102,23 @@ save_data (GVariant *data)
return 0;
}
+static FpPrint *
+load_print_from_data (GVariant *data)
+{
+ const guchar *stored_data = NULL;
+ gsize stored_len;
+ FpPrint *print;
+
+ g_autoptr(GError) error = NULL;
+ stored_data = (const guchar *) g_variant_get_fixed_array (data, &stored_len, 1);
+ print = fp_print_deserialize (stored_data, stored_len, &error);
+ if (error)
+ g_warning ("Error deserializing data: %s", error->message);
+ return print;
+}
+
int
-print_data_save (FpPrint *print, FpFinger finger)
+print_data_save (FpPrint *print, FpFinger finger, gboolean update_fingerprint)
{
g_autofree gchar *descr = get_print_data_descriptor (print, NULL, finger);
@@ -137,25 +152,12 @@ print_data_load (FpDevice *dev, FpFinger finger)
g_autoptr(GVariant) val = NULL;
g_autoptr(GVariantDict) dict = NULL;
- const guchar *stored_data = NULL;
- gsize stored_len;
dict = load_data ();
val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay"));
if (val)
- {
- FpPrint *print;
- g_autoptr(GError) error = NULL;
-
- stored_data = (const guchar *) g_variant_get_fixed_array (val, &stored_len, 1);
- print = fp_print_deserialize (stored_data, stored_len, &error);
-
- if (error)
- g_warning ("Error deserializing data: %s", error->message);
-
- return print;
- }
+ return load_print_from_data (val);
return NULL;
}
@@ -207,16 +209,30 @@ gallery_data_load (FpDevice *dev)
}
FpPrint *
-print_create_template (FpDevice *dev, FpFinger finger)
+print_create_template (FpDevice *dev, FpFinger finger, gboolean load_existing)
{
+ g_autoptr(GVariantDict) dict = NULL;
g_autoptr(GDateTime) datetime = NULL;
g_autoptr(GDate) date = NULL;
+ g_autoptr(GVariant) existing_val = NULL;
+ g_autofree gchar *descr = get_print_data_descriptor (NULL, dev, finger);
FpPrint *template = NULL;
gint year, month, day;
- template = fp_print_new (dev);
- fp_print_set_finger (template, finger);
- fp_print_set_username (template, g_get_user_name ());
+ if (load_existing)
+ {
+ dict = load_data ();
+ existing_val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay"));
+ if (existing_val != NULL)
+ template = load_print_from_data (existing_val);
+ }
+ if (template == NULL)
+ {
+ template = fp_print_new (dev);
+ fp_print_set_finger (template, finger);
+ fp_print_set_username (template, g_get_user_name ());
+ }
+
datetime = g_date_time_new_now_local ();
g_date_time_get_ymd (datetime, &year, &month, &day);
date = g_date_new_dmy (day, month, year);
diff --git a/examples/storage.h b/examples/storage.h
index 81390bd..0922b90 100644
--- a/examples/storage.h
+++ b/examples/storage.h
@@ -21,12 +21,14 @@
#pragma once
int print_data_save (FpPrint *print,
- FpFinger finger);
+ FpFinger finger,
+ gboolean update_fingerprint);
FpPrint * print_data_load (FpDevice *dev,
FpFinger finger);
GPtrArray * gallery_data_load (FpDevice *dev);
-FpPrint * print_create_template (FpDevice *dev,
- FpFinger finger);
+FpPrint * print_create_template (FpDevice *dev,
+ FpFinger finger,
+ const gboolean load_existing);
gboolean print_image_save (FpPrint *print,
const char *path);
gboolean save_image_to_pgm (FpImage *img,
diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c
index 35e2f2b..82f309e 100644
--- a/libfprint/fp-device.c
+++ b/libfprint/fp-device.c
@@ -1189,10 +1189,11 @@ fp_device_resume_finish (FpDevice *device,
* fp_device_enroll_finish().
*
* The @template_print parameter is a #FpPrint with available metadata filled
- * in. The driver may make use of this metadata, when e.g. storing the print on
- * device memory. It is undefined whether this print is filled in by the driver
- * and returned, or whether the driver will return a newly created print after
- * enrollment succeeded.
+ * in and, optionally, with existing fingerprint data to be updated with newly
+ * enrolled fingerprints if a device driver supports it. The driver may make use
+ * of the metadata, when e.g. storing the print on device memory. It is undefined
+ * whether this print is filled in by the driver and returned, or whether the
+ * driver will return a newly created print after enrollment succeeded.
*/
void
fp_device_enroll (FpDevice *device,
@@ -1229,19 +1230,30 @@ fp_device_enroll (FpDevice *device,
if (!FP_IS_PRINT (template_print))
{
- g_warning ("User did not pass a print template!");
g_task_return_error (task,
- fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
+ fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
+ "User did not pass a print template!"));
return;
}
g_object_get (template_print, "fpi-type", &print_type, NULL);
if (print_type != FPI_PRINT_UNDEFINED)
{
- g_warning ("Passed print template must be newly created and blank!");
- g_task_return_error (task,
- fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
- return;
+ if (!fp_device_has_feature (device, FP_DEVICE_FEATURE_UPDATE_PRINT))
+ {
+ g_task_return_error (task,
+ fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
+ "A device does not support print updates!"));
+ return;
+ }
+ if (!fp_print_compatible (template_print, device))
+ {
+ g_task_return_error (task,
+ fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
+ "The print and device must have a matching driver and device id"
+ " for a fingerprint update to succeed"));
+ return;
+ }
}
priv->current_action = FPI_DEVICE_ACTION_ENROLL;
diff --git a/libfprint/fp-device.h b/libfprint/fp-device.h
index 85be34c..9dda747 100644
--- a/libfprint/fp-device.h
+++ b/libfprint/fp-device.h
@@ -59,6 +59,7 @@ typedef enum {
* @FP_DEVICE_FEATURE_STORAGE_CLEAR: Supports clearing the whole storage
* @FP_DEVICE_FEATURE_DUPLICATES_CHECK: Natively supports duplicates detection
* @FP_DEVICE_FEATURE_ALWAYS_ON: Whether the device can run continuously
+ * @FP_DEVICE_FEATURE_UPDATE_PRINT: Supports updating an existing print record using new scans
*/
typedef enum /*< flags >*/ {
FP_DEVICE_FEATURE_NONE = 0,
@@ -71,6 +72,7 @@ typedef enum /*< flags >*/ {
FP_DEVICE_FEATURE_STORAGE_CLEAR = 1 << 6,
FP_DEVICE_FEATURE_DUPLICATES_CHECK = 1 << 7,
FP_DEVICE_FEATURE_ALWAYS_ON = 1 << 8,
+ FP_DEVICE_FEATURE_UPDATE_PRINT = 1 << 9,
} FpDeviceFeature;
/**
diff --git a/libfprint/fp-image-device.c b/libfprint/fp-image-device.c
index 82e69f9..519ad75 100644
--- a/libfprint/fp-image-device.c
+++ b/libfprint/fp-image-device.c
@@ -101,6 +101,7 @@ fp_image_device_start_capture_action (FpDevice *device)
FpImageDevice *self = FP_IMAGE_DEVICE (device);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action;
+ FpiPrintType print_type;
/* There is just one action that we cannot support out
* of the box, which is a capture without first waiting
@@ -124,7 +125,9 @@ fp_image_device_start_capture_action (FpDevice *device)
FpPrint *enroll_print = NULL;
fpi_device_get_enroll_data (device, &enroll_print);
- fpi_print_set_type (enroll_print, FPI_PRINT_NBIS);
+ g_object_get (enroll_print, "fpi-type", &print_type, NULL);
+ if (print_type != FPI_PRINT_NBIS)
+ fpi_print_set_type (enroll_print, FPI_PRINT_NBIS);
}
priv->enroll_stage = 0;
@@ -221,6 +224,7 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
fp_device_class->cancel = fp_image_device_cancel_action;
fpi_device_class_auto_initialize_features (fp_device_class);
+ fp_device_class->features |= FP_DEVICE_FEATURE_UPDATE_PRINT;
/* Default implementations */
klass->activate = fp_image_device_default_activate;
diff --git a/libfprint/fp-print.c b/libfprint/fp-print.c
index c8a1b07..8532b6c 100644
--- a/libfprint/fp-print.c
+++ b/libfprint/fp-print.c
@@ -61,6 +61,7 @@ enum {
/* Private property*/
PROP_FPI_TYPE,
PROP_FPI_DATA,
+ PROP_FPI_PRINTS,
N_PROPS
};
@@ -133,6 +134,10 @@ fp_print_get_property (GObject *object,
g_value_set_variant (value, self->data);
break;
+ case PROP_FPI_PRINTS:
+ g_value_set_pointer (value, self->prints);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -188,6 +193,11 @@ fp_print_set_property (GObject *object,
self->data = g_value_dup_variant (value);
break;
+ case PROP_FPI_PRINTS:
+ g_clear_pointer (&self->prints, g_ptr_array_unref);
+ self->prints = g_value_get_pointer (value);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -299,6 +309,19 @@ fp_print_class_init (FpPrintClass *klass)
NULL,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
+ /**
+ * FpPrint::fpi-prints: (skip)
+ *
+ * This property is only for internal purposes.
+ *
+ * Stability: private
+ */
+ properties[PROP_FPI_PRINTS] =
+ g_param_spec_pointer ("fpi-prints",
+ "Prints",
+ "Prints for internal use only",
+ G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
+
g_object_class_install_properties (object_class, N_PROPS, properties);
}
diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c
index 408e2f9..ff658e9 100644
--- a/tests/test-fpi-device.c
+++ b/tests/test-fpi-device.c
@@ -27,6 +27,7 @@
#include "fpi-compat.h"
#include "fpi-log.h"
#include "test-device-fake.h"
+#include "fp-print-private.h"
/* Utility functions */
@@ -143,6 +144,16 @@ make_fake_print (FpDevice *device,
}
static FpPrint *
+make_fake_nbis_print (FpDevice *device)
+{
+ FpPrint *enrolled_print = fp_print_new (device);
+
+ fpi_print_set_type (enrolled_print, FPI_PRINT_NBIS);
+
+ return enrolled_print;
+}
+
+static FpPrint *
make_fake_print_reffed (FpDevice *device,
GVariant *print_data)
{
@@ -1045,7 +1056,6 @@ test_driver_enroll_error_no_print (void)
out_print =
fp_device_enroll_sync (device, fp_print_new (device), NULL, NULL, NULL, &error);
- g_test_assert_expected_messages ();
g_assert (fake_dev->last_called_function == dev_class->enroll);
g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL);
g_assert_null (out_print);
@@ -1053,6 +1063,111 @@ test_driver_enroll_error_no_print (void)
g_clear_error (&error);
}
+static void
+test_driver_enroll_update_nbis (void)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
+ g_autoptr(FpAutoCloseDevice) device = NULL;
+ g_autoptr(FpPrint) template_print = NULL;
+ FpiDeviceFake *fake_dev = NULL;
+ FpPrint *out_print = NULL;
+
+ dev_class->features |= FP_DEVICE_FEATURE_UPDATE_PRINT;
+ device = auto_close_fake_device_new ();
+ fake_dev = FPI_DEVICE_FAKE (device);
+
+ template_print = make_fake_nbis_print (device);
+ fake_dev->ret_print = template_print;
+
+ out_print =
+ fp_device_enroll_sync (device, template_print, NULL, NULL, NULL, &error);
+
+ g_assert (fake_dev->last_called_function == dev_class->enroll);
+ g_assert (fake_dev->action_data == template_print);
+
+ g_assert_no_error (error);
+ g_assert (out_print == template_print);
+}
+
+static void
+test_driver_enroll_update_nbis_wrong_device (void)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
+ g_autoptr(FpAutoCloseDevice) device = NULL;
+ g_autoptr(FpPrint) template_print = NULL;
+ FpiDeviceFake *fake_dev = NULL;
+ FpPrint *out_print = NULL;
+
+ dev_class->features |= FP_DEVICE_FEATURE_UPDATE_PRINT;
+
+ device = auto_close_fake_device_new ();
+ fake_dev = FPI_DEVICE_FAKE (device);
+
+ template_print = make_fake_nbis_print (device);
+ template_print->device_id = g_strdup ("wrong_device");
+ fake_dev->ret_print = template_print;
+
+ out_print =
+ fp_device_enroll_sync (device, template_print, NULL, NULL, NULL, &error);
+
+ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID);
+ g_assert (out_print == NULL);
+}
+
+static void
+test_driver_enroll_update_nbis_wrong_driver (void)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
+ g_autoptr(FpAutoCloseDevice) device = NULL;
+ g_autoptr(FpPrint) template_print = NULL;
+ FpiDeviceFake *fake_dev = NULL;
+ FpPrint *out_print = NULL;
+
+ dev_class->features |= FP_DEVICE_FEATURE_UPDATE_PRINT;
+
+ device = auto_close_fake_device_new ();
+ fake_dev = FPI_DEVICE_FAKE (device);
+
+ template_print = make_fake_nbis_print (device);
+ template_print->driver = g_strdup ("wrong_driver");
+ fake_dev->ret_print = template_print;
+
+ out_print =
+ fp_device_enroll_sync (device, template_print, NULL, NULL, NULL, &error);
+
+ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID);
+ g_assert (out_print == NULL);
+}
+
+static void
+test_driver_enroll_update_nbis_missing_feature (void)
+{
+ g_autoptr(GError) error = NULL;
+ g_autoptr(FpAutoResetClass) dev_class = auto_reset_device_class ();
+ g_autoptr(FpAutoCloseDevice) device = NULL;
+ g_autoptr(FpPrint) template_print = NULL;
+ FpiDeviceFake *fake_dev = NULL;
+ FpPrint *out_print = NULL;
+
+ device = auto_close_fake_device_new ();
+ fake_dev = FPI_DEVICE_FAKE (device);
+
+ template_print = make_fake_nbis_print (device);
+ fake_dev->ret_print = template_print;
+
+ out_print =
+ fp_device_enroll_sync (device, template_print, NULL, NULL, NULL, &error);
+
+ g_assert (fake_dev->last_called_function == dev_class->open);
+ g_assert (fake_dev->action_data == NULL);
+
+ g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID);
+ g_assert (out_print == NULL);
+}
+
typedef struct
{
gint completed_stages;
@@ -3306,6 +3421,13 @@ main (int argc, char *argv[])
g_test_add_func ("/driver/enroll/error", test_driver_enroll_error);
g_test_add_func ("/driver/enroll/error/no_print", test_driver_enroll_error_no_print);
g_test_add_func ("/driver/enroll/progress", test_driver_enroll_progress);
+ g_test_add_func ("/driver/enroll/update_nbis", test_driver_enroll_update_nbis);
+ g_test_add_func ("/driver/enroll/update_nbis_wrong_device",
+ test_driver_enroll_update_nbis_wrong_device);
+ g_test_add_func ("/driver/enroll/update_nbis_wrong_driver",
+ test_driver_enroll_update_nbis_wrong_driver);
+ g_test_add_func ("/driver/enroll/update_nbis_missing_feature",
+ test_driver_enroll_update_nbis_missing_feature);
g_test_add_func ("/driver/verify", test_driver_verify);
g_test_add_func ("/driver/verify/fail", test_driver_verify_fail);
g_test_add_func ("/driver/verify/retry", test_driver_verify_retry);
diff --git a/tests/virtual-image.py b/tests/virtual-image.py
index 7605b58..e4a464e 100755
--- a/tests/virtual-image.py
+++ b/tests/virtual-image.py
@@ -136,6 +136,7 @@ class VirtualImage(unittest.TestCase):
self.assertTrue(self.dev.has_feature(FPrint.DeviceFeature.CAPTURE))
self.assertTrue(self.dev.has_feature(FPrint.DeviceFeature.IDENTIFY))
self.assertTrue(self.dev.has_feature(FPrint.DeviceFeature.VERIFY))
+ self.assertTrue(self.dev.has_feature(FPrint.DeviceFeature.UPDATE_PRINT))
self.assertFalse(self.dev.has_feature(FPrint.DeviceFeature.DUPLICATES_CHECK))
self.assertFalse(self.dev.has_feature(FPrint.DeviceFeature.STORAGE))
self.assertFalse(self.dev.has_feature(FPrint.DeviceFeature.STORAGE_LIST))
@@ -144,7 +145,8 @@ class VirtualImage(unittest.TestCase):
self.assertEqual(self.dev.get_features(),
FPrint.DeviceFeature.CAPTURE |
FPrint.DeviceFeature.IDENTIFY |
- FPrint.DeviceFeature.VERIFY)
+ FPrint.DeviceFeature.VERIFY |
+ FPrint.DeviceFeature.UPDATE_PRINT)
def test_capture_prevents_close(self):
cancel = Gio.Cancellable()
@@ -167,7 +169,7 @@ class VirtualImage(unittest.TestCase):
while not self._cancelled:
ctx.iteration(True)
- def enroll_print(self, image):
+ def enroll_print(self, image, template=None):
self._step = 0
self._enrolled = None
@@ -181,14 +183,15 @@ class VirtualImage(unittest.TestCase):
self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NONE)
self._enrolled = fp
- template = FPrint.Print.new(self.dev)
- template.props.finger = FPrint.Finger.LEFT_THUMB
- template.props.username = "testuser"
- template.props.description = "test print"
- datetime = GLib.DateTime.new_now_local()
- date = GLib.Date()
- date.set_dmy(*datetime.get_ymd()[::-1])
- template.props.enroll_date = date
+ if template is None:
+ template = FPrint.Print.new(self.dev)
+ template.props.finger = FPrint.Finger.LEFT_THUMB
+ template.props.username = "testuser"
+ template.props.description = "test print"
+ datetime = GLib.DateTime.new_now_local()
+ date = GLib.Date()
+ date.set_dmy(*datetime.get_ymd()[::-1])
+ template.props.enroll_date = date
self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NONE)
self.dev.enroll(template, None, progress_cb, tuple(), done_cb)
@@ -264,6 +267,28 @@ class VirtualImage(unittest.TestCase):
ctx.iteration(True)
assert(not self._verify_match)
+ # Test fingerprint updates
+ # Enroll a second print
+ fp_whorl_tended_arch = self.enroll_print('tented_arch', fp_whorl)
+
+ # Make sure the first print verifies successfully after the update
+ self._verify_match = None
+ self._verify_fp = None
+ self.dev.verify(fp_whorl_tended_arch, callback=verify_cb)
+ self.send_image('whorl')
+ while self._verify_match is None:
+ ctx.iteration(True)
+ assert(self._verify_match)
+
+ # Make sure the second print verifies successfully after the update
+ self._verify_match = None
+ self._verify_fp = None
+ self.dev.verify(fp_whorl_tended_arch, callback=verify_cb)
+ self.send_image('tented_arch')
+ while self._verify_match is None:
+ ctx.iteration(True)
+ assert(self._verify_match)
+
# Test verify error cases
self._verify_fp = None
self._verify_error = None