Compare commits

..

19 Commits

Author SHA1 Message Date
Benjamin Berg
8fad2652ee Release 1.94.3 2022-02-11 19:36:43 +01:00
Benjamin Berg
6f5ba3cbb5 udev-hwdb: Update unsupported device list 2022-02-11 19:36:22 +01:00
doomsdayrs
754ccfb865 Convert README to markdown
Just a minor change, but makes the file a bit more readable.
2022-02-11 19:36:22 +01:00
Doomsdayrs
d3014f1684 Delete TODO 2022-02-11 19:36:22 +01:00
Devyn Cairns
3568051686 goodixmoc: support for clear_storage
The internal storage of this device can get messed up by other operating
systems, so it's handy to be able to clear it.

I'm not 100% sure whether the commands I've sent to the device are
exactly what is supposed to be used (just a guess), but it did seem to
work, and it even fixed another issue I had.
2022-02-11 18:08:53 +00:00
Benjamin Berg
9ce6ed4164 goodixmoc: Report recognized print after a match failure
The API should return the recognized print, even if none of the prints
given in the gallery (or the one passed to verify) matched. Without this
the garbage-collection of left-over prints does not work, causing issues
after reinstall.

Fixes: #444
2022-02-03 14:49:49 +01:00
Benjamin Berg
e0fd178bec goodixmoc: Log which the ID that produced the duplicate 2022-02-03 14:49:49 +01:00
Benjamin Berg
168ab98021 examples: Check whether the returned date is valid
Prints may have an invalid date. Extend the checks so that this is also
caught in addition to a NULL date.
2022-02-03 14:49:49 +01:00
Benjamin Berg
ae5696a9bb goodixmoc: Change error message for corrupted headers
Otherwise you can't tell from the log whether parsing the body or header
failed.
2022-02-03 14:49:49 +01:00
Benjamin Berg
038c7108a6 goodixmoc: Further template parsing fixes
In commit 5c28654d9 ("goodixmoc: Fix print template parsing") the length
check for the verify and duplicate check responses by requiring two
extra bytes at the end of the message.

There were also issues in other places where the length was not checked
correctly, including a scenario that could cause a read beyond the end
of the buffer.

Related: #444
2022-02-03 14:49:44 +01:00
Aris Lin
eb1013cdb6 synaptics: Remove PID 0xC9 2022-01-28 19:25:24 +08:00
mincrmatt12
5beac0ded7 elanspi: Try to avoid cancellation problems 2021-12-23 05:35:38 +00:00
mincrmatt12
7565562903 elanspi: Adjust register tables (fixes #438)
New values taken from a newer version of the official driver.
2021-12-22 00:20:57 -05:00
Dmitrii Shcherbakov
999bca076c 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.
2021-12-16 12:53:41 +01:00
Benjamin Berg
e198b04222 elanspi: Silence some SSMs that may log excessively otherwise 2021-12-02 13:54:59 +01:00
Benjamin Berg
3981c42d3e ssm: Add API to silence most state change debug messages
Otherwise tightly looping SSMs (primarily SPI transfers), will flood the
logs in inappropriate ways.
2021-12-02 13:54:59 +01:00
Benjamin Berg
31afd3ba5c elanspi: Move debug print so that it contains all information
Two of the printed variables were only calculated after the message was
printed, making the logged information less useful than it could be.
2021-12-02 13:53:54 +01:00
Benjamin Berg
05fd2c58cb context: Ensure mainloop is idle before enumeration completes
This ensures that we have processed all hotplug events before
considering enumeration to be complete. This is important due to USB
persist being turned off. At resume time, devices will disappear and
immediately re-appear. In this situatoin, enumerate could first see the
old state with a removed device resulting in it to not be discovered.

As a hotplug event is semingly emitted by the kernel immediately, we
can simply make sure to process this hotplug event before returning
from enumerate.

Closes: fprintd#119
2021-12-01 15:29:18 +00:00
Matthew Mirvish
a033154b2e doc: Fix broken documentation for FpiDeviceUdevSubtypeFlags enum
Added description and fixed incorrect name in comment, so now gtkdoc
actually shows useful information.
2021-11-15 17:10:44 -05:00
30 changed files with 527 additions and 152 deletions

10
NEWS
View File

@@ -1,6 +1,16 @@
This file lists notable changes in each release. For the full history of all This file lists notable changes in each release. For the full history of all
changes, see ChangeLog. changes, see ChangeLog.
2021-11-02: v1.94.3 release
Highlights:
* Ensure idle mainloop before completing enumeration (fprintd#119)
* It is now possible to extend already enrolled prints
* elanspi: Fix timeout error with some hardware (#438)
* elanspi: Fix cancellation issues
* goodixmoc: Return matching device print; fixes duplicate checking (#444)
* goodixmoc: Support clearing the storage (usually unused)
2021-11-02: v1.94.2 release 2021-11-02: v1.94.2 release
Highlights: Highlights:

View File

@@ -1,9 +1,10 @@
libfprint # libfprint
=========
libfprint is part of the fprint project: libfprint is part of the fprint project:
https://fprint.freedesktop.org/ https://fprint.freedesktop.org/
## History
libfprint was originally developed as part of an academic project at the libfprint was originally developed as part of an academic project at the
University of Manchester with the aim of hiding differences between different University of Manchester with the aim of hiding differences between different
consumer fingerprint scanners and providing a single uniform API to application consumer fingerprint scanners and providing a single uniform API to application
@@ -15,6 +16,8 @@ from this one, although I try to keep them as similar as possible (I'm not
hiding anything in the academic branch, it's just the open source release hiding anything in the academic branch, it's just the open source release
contains some commits excluded from the academic project). contains some commits excluded from the academic project).
## License
THE UNIVERSITY OF MANCHESTER DOES NOT ENDORSE THIS THIS SOFTWARE RELEASE AND THE UNIVERSITY OF MANCHESTER DOES NOT ENDORSE THIS THIS SOFTWARE RELEASE AND
IS IN NO WAY RESPONSIBLE FOR THE CODE CONTAINED WITHIN, OR ANY DAMAGES CAUSED IS IN NO WAY RESPONSIBLE FOR THE CODE CONTAINED WITHIN, OR ANY DAMAGES CAUSED
BY USING OR DISTRIBUTING THE SOFTWARE. Development does not happen on BY USING OR DISTRIBUTING THE SOFTWARE. Development does not happen on

30
TODO
View File

@@ -1,30 +0,0 @@
LIBRARY
=======
test suite against NFIQ compliance set
make library optionally asynchronous and maybe thread-safe
nbis cleanups
API function to determine if img device supports uncond. capture
race-free way of saying "save this print but don't overwrite"
NEW DRIVERS
===========
Sunplus 895 driver
AES3400/3500 driver
ID Mouse driver
Support for 2nd generation MS devices
Support for 2nd generation UPEK devices
IMAGING
=======
ignore first frame or two with aes2501
aes2501: increase threshold "sum" for end-of-image detection
aes2501 gain calibration
aes4000 gain calibration
aes4000 resampling
PPMM parameter to get_minutiae seems to have no effect
nbis minutiae should be stored in endian-independent format
PORTABILITY
===========
OpenBSD can't do -Wshadow or visibility
OpenBSD: add compat codes for ENOTSUP ENODATA and EPROTO

View File

@@ -181,7 +181,6 @@ usb:v06CBp00DF*
usb:v06CBp00F9* usb:v06CBp00F9*
usb:v06CBp00FC* usb:v06CBp00FC*
usb:v06CBp00C2* usb:v06CBp00C2*
usb:v06CBp00C9*
usb:v06CBp0100* usb:v06CBp0100*
usb:v06CBp00F0* usb:v06CBp00F0*
usb:v06CBp0103* usb:v06CBp0103*
@@ -268,15 +267,19 @@ usb:v06CBp008A*
usb:v06CBp009A* usb:v06CBp009A*
usb:v06CBp009B* usb:v06CBp009B*
usb:v06CBp00A2* usb:v06CBp00A2*
usb:v06CBp00A8*
usb:v06CBp00B7* usb:v06CBp00B7*
usb:v06CBp00BB* usb:v06CBp00BB*
usb:v06CBp00BE* usb:v06CBp00BE*
usb:v06CBp00C4* usb:v06CBp00C4*
usb:v06CBp00CB* usb:v06CBp00CB*
usb:v06CBp00C9*
usb:v06CBp00D8* usb:v06CBp00D8*
usb:v06CBp00DA* usb:v06CBp00DA*
usb:v06CBp00DC*
usb:v06CBp00E7* usb:v06CBp00E7*
usb:v06CBp00E9* usb:v06CBp00E9*
usb:v06CBp00FD*
usb:v0A5Cp5801* usb:v0A5Cp5801*
usb:v0A5Cp5805* usb:v0A5Cp5805*
usb:v0A5Cp5834* usb:v0A5Cp5834*
@@ -288,6 +291,7 @@ usb:v0A5Cp5844*
usb:v0A5Cp5845* usb:v0A5Cp5845*
usb:v0BDAp5812* usb:v0BDAp5812*
usb:v10A5p0007* usb:v10A5p0007*
usb:v10A5p9200*
usb:v1188p9545* usb:v1188p9545*
usb:v138Ap0007* usb:v138Ap0007*
usb:v138Ap003A* usb:v138Ap003A*
@@ -305,6 +309,7 @@ usb:v1491p0088*
usb:v16D1p1027* usb:v16D1p1027*
usb:v1C7Ap0300* usb:v1C7Ap0300*
usb:v1C7Ap0575* usb:v1C7Ap0575*
usb:v1C7Ap0576*
usb:v27C6p5042* usb:v27C6p5042*
usb:v27C6p5110* usb:v27C6p5110*
usb:v27C6p5117* usb:v27C6p5117*
@@ -324,7 +329,9 @@ usb:v27C6p55A2*
usb:v27C6p55A4* usb:v27C6p55A4*
usb:v27C6p55B4* usb:v27C6p55B4*
usb:v27C6p5740* usb:v27C6p5740*
usb:v27C6p5E0A*
usb:v2808p9338* usb:v2808p9338*
usb:v298Dp2020*
usb:v298Dp2033* usb:v298Dp2033*
usb:v3538p0930* usb:v3538p0930*
ID_AUTOSUSPEND=1 ID_AUTOSUSPEND=1

View File

@@ -260,6 +260,7 @@ fpi_ssm_get_device
fpi_ssm_get_error fpi_ssm_get_error
fpi_ssm_dup_error fpi_ssm_dup_error
fpi_ssm_get_cur_state fpi_ssm_get_cur_state
fpi_ssm_silence_debug
fpi_ssm_spi_transfer_cb fpi_ssm_spi_transfer_cb
fpi_ssm_spi_transfer_with_weak_pointer_cb fpi_ssm_spi_transfer_with_weak_pointer_cb
fpi_ssm_usb_transfer_cb fpi_ssm_usb_transfer_cb

View File

@@ -35,6 +35,7 @@ typedef struct _EnrollData
unsigned int sigint_handler; unsigned int sigint_handler;
FpFinger finger; FpFinger finger;
int ret_value; int ret_value;
gboolean update_fingerprint;
} EnrollData; } EnrollData;
static void 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 /* 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 * metadata that the print contains, so we can always save a local copy
* containing the handle to the device print */ * 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) if (r < 0)
{ {
g_warning ("Data save failed, code %d", r); g_warning ("Data save failed, code %d", r);
@@ -124,6 +126,40 @@ on_enroll_progress (FpDevice *device,
fp_device_get_nr_enroll_stages (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 static void
on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data) 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; 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 " printf ("You will need to successfully scan your %s finger %d times to "
"complete the process.\n\n", finger_to_string (enroll_data->finger), "complete the process.\n\n", finger_to_string (enroll_data->finger),
fp_device_get_nr_enroll_stages (dev)); fp_device_get_nr_enroll_stages (dev));
printf ("Scan your finger now.\n"); 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, fp_device_enroll (dev, print_template, enroll_data->cancellable,
on_enroll_progress, NULL, NULL, on_enroll_progress, NULL, NULL,
(GAsyncReadyCallback) on_enroll_completed, (GAsyncReadyCallback) on_enroll_completed,
@@ -171,11 +220,9 @@ main (void)
FpDevice *dev; FpDevice *dev;
FpFinger finger; FpFinger finger;
g_print ("This program will enroll the selected finger, unconditionally " g_print ("This program will enroll the selected finger overwriting any print for the same"
"overwriting any print for the same finger that was enrolled " " finger that was enrolled previously. Fingerprint updates without erasing old data"
"previously. If you want to continue, press enter, otherwise hit " " are possible on devices supporting that. Ctrl+C interrupts program execution.\n");
"Ctrl+C\n");
getchar ();
g_print ("Choose the finger to enroll:\n"); g_print ("Choose the finger to enroll:\n");
finger = finger_chooser (); finger = finger_chooser ();

View File

@@ -143,6 +143,7 @@ on_identify_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
if (match) if (match)
{ {
g_autoptr(FpPrint) matched_print = g_object_ref (match); g_autoptr(FpPrint) matched_print = g_object_ref (match);
const GDate *date;
char date_str[128] = {}; char date_str[128] = {};
identify_data->ret_value = EXIT_SUCCESS; identify_data->ret_value = EXIT_SUCCESS;
@@ -155,7 +156,8 @@ on_identify_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
matched_print = g_steal_pointer (&stored_print); matched_print = g_steal_pointer (&stored_print);
} }
if (fp_print_get_enroll_date (matched_print)) date = fp_print_get_enroll_date (matched_print);
if (date && g_date_valid (date))
g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0", g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0",
fp_print_get_enroll_date (matched_print)); fp_print_get_enroll_date (matched_print));
else else

View File

@@ -161,7 +161,7 @@ on_list_completed (FpDevice *dev,
finger_to_string (fp_print_get_finger (print)), finger_to_string (fp_print_get_finger (print)),
fp_print_get_username (print)); fp_print_get_username (print));
if (date) if (date && g_date_valid (date))
{ {
g_date_strftime (buf, G_N_ELEMENTS (buf), "%Y-%m-%d\0", date); g_date_strftime (buf, G_N_ELEMENTS (buf), "%Y-%m-%d\0", date);
g_print (", enrolled on %s", buf); g_print (", enrolled on %s", buf);

View File

@@ -102,8 +102,23 @@ save_data (GVariant *data)
return 0; 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 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); 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(GVariant) val = NULL;
g_autoptr(GVariantDict) dict = NULL; g_autoptr(GVariantDict) dict = NULL;
const guchar *stored_data = NULL;
gsize stored_len;
dict = load_data (); dict = load_data ();
val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay")); val = g_variant_dict_lookup_value (dict, descr, G_VARIANT_TYPE ("ay"));
if (val) if (val)
{ return load_print_from_data (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 NULL; return NULL;
} }
@@ -207,16 +209,30 @@ gallery_data_load (FpDevice *dev)
} }
FpPrint * 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(GDateTime) datetime = NULL;
g_autoptr(GDate) date = 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; FpPrint *template = NULL;
gint year, month, day; gint year, month, day;
template = fp_print_new (dev); if (load_existing)
fp_print_set_finger (template, finger); {
fp_print_set_username (template, g_get_user_name ()); 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 (); datetime = g_date_time_new_now_local ();
g_date_time_get_ymd (datetime, &year, &month, &day); g_date_time_get_ymd (datetime, &year, &month, &day);
date = g_date_new_dmy (day, month, year); date = g_date_new_dmy (day, month, year);

View File

@@ -21,12 +21,14 @@
#pragma once #pragma once
int print_data_save (FpPrint *print, int print_data_save (FpPrint *print,
FpFinger finger); FpFinger finger,
gboolean update_fingerprint);
FpPrint * print_data_load (FpDevice *dev, FpPrint * print_data_load (FpDevice *dev,
FpFinger finger); FpFinger finger);
GPtrArray * gallery_data_load (FpDevice *dev); GPtrArray * gallery_data_load (FpDevice *dev);
FpPrint * print_create_template (FpDevice *dev, FpPrint * print_create_template (FpDevice *dev,
FpFinger finger); FpFinger finger,
const gboolean load_existing);
gboolean print_image_save (FpPrint *print, gboolean print_image_save (FpPrint *print,
const char *path); const char *path);
gboolean save_image_to_pgm (FpImage *img, gboolean save_image_to_pgm (FpImage *img,

View File

@@ -130,12 +130,14 @@ on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
if (match) if (match)
{ {
char date_str[128]; const GDate *date = fp_print_get_enroll_date (match);
char date_str[128] = "<unknown>";
verify_data->ret_value = EXIT_SUCCESS; verify_data->ret_value = EXIT_SUCCESS;
g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0", if (date && g_date_valid (date))
fp_print_get_enroll_date (match)); g_date_strftime (date_str, G_N_ELEMENTS (date_str), "%Y-%m-%d\0",
fp_print_get_enroll_date (match));
g_debug ("Match report: device %s matched finger %s successifully " g_debug ("Match report: device %s matched finger %s successifully "
"with print %s, enrolled on date %s by user %s", "with print %s, enrolled on date %s by user %s",
fp_device_get_name (dev), fp_device_get_name (dev),

View File

@@ -439,6 +439,12 @@ elanspi_capture_old_line_handler (FpiSpiTransfer *transfer, FpDevice *dev, gpoin
} }
else else
{ {
/* check for termination */
if (fpi_device_get_current_action (dev) == FPI_DEVICE_ACTION_NONE)
{
fpi_ssm_mark_completed (transfer->ssm);
return;
}
/* check for cancellation */ /* check for cancellation */
if (fpi_device_action_is_cancelled (dev)) if (fpi_device_action_is_cancelled (dev))
{ {
@@ -606,6 +612,7 @@ elanspi_calibrate_old_handler (FpiSsm *ssm, FpDevice *dev)
case ELANSPI_CALIBOLD_CHECKFIN_CAPTURE: case ELANSPI_CALIBOLD_CHECKFIN_CAPTURE:
case ELANSPI_CALIBOLD_DACFINE_CAPTURE: case ELANSPI_CALIBOLD_DACFINE_CAPTURE:
chld = fpi_ssm_new (dev, elanspi_capture_old_handler, ELANSPI_CAPTOLD_NSTATES); chld = fpi_ssm_new (dev, elanspi_capture_old_handler, ELANSPI_CAPTOLD_NSTATES);
fpi_ssm_silence_debug (chld);
fpi_ssm_start_subsm (ssm, chld); fpi_ssm_start_subsm (ssm, chld);
return; return;
@@ -860,6 +867,7 @@ elanspi_calibrate_hv_handler (FpiSsm *ssm, FpDevice *dev)
case ELANSPI_CALIBHV_CAPTURE: case ELANSPI_CALIBHV_CAPTURE:
chld = fpi_ssm_new (dev, elanspi_capture_hv_handler, ELANSPI_CAPTHV_NSTATES); chld = fpi_ssm_new (dev, elanspi_capture_hv_handler, ELANSPI_CAPTHV_NSTATES);
fpi_ssm_silence_debug (chld);
fpi_ssm_start_subsm (ssm, chld); fpi_ssm_start_subsm (ssm, chld);
return; return;
@@ -1115,6 +1123,7 @@ do_sw_reset:
chld = fpi_ssm_new_full (dev, elanspi_calibrate_hv_handler, ELANSPI_CALIBHV_NSTATES, ELANSPI_CALIBHV_PROTECT, "HV calibrate"); chld = fpi_ssm_new_full (dev, elanspi_calibrate_hv_handler, ELANSPI_CALIBHV_NSTATES, ELANSPI_CALIBHV_PROTECT, "HV calibrate");
else else
chld = fpi_ssm_new_full (dev, elanspi_calibrate_old_handler, ELANSPI_CALIBOLD_NSTATES, ELANSPI_CALIBOLD_PROTECT, "old calibrate"); chld = fpi_ssm_new_full (dev, elanspi_calibrate_old_handler, ELANSPI_CALIBOLD_NSTATES, ELANSPI_CALIBOLD_PROTECT, "old calibrate");
fpi_ssm_silence_debug (chld);
fpi_ssm_start_subsm (ssm, chld); fpi_ssm_start_subsm (ssm, chld);
return; return;
@@ -1123,6 +1132,7 @@ do_sw_reset:
chld = fpi_ssm_new (dev, elanspi_capture_hv_handler, ELANSPI_CAPTHV_NSTATES); chld = fpi_ssm_new (dev, elanspi_capture_hv_handler, ELANSPI_CAPTHV_NSTATES);
else else
chld = fpi_ssm_new (dev, elanspi_capture_old_handler, ELANSPI_CAPTOLD_NSTATES); chld = fpi_ssm_new (dev, elanspi_capture_old_handler, ELANSPI_CAPTOLD_NSTATES);
fpi_ssm_silence_debug (chld);
fpi_ssm_start_subsm (ssm, chld); fpi_ssm_start_subsm (ssm, chld);
return; return;
@@ -1219,8 +1229,6 @@ elanspi_guess_image (FpiDeviceElanSpi *self, guint16 *raw_image)
sq_stddev /= (frame_width * frame_height); sq_stddev /= (frame_width * frame_height);
fp_dbg ("<guess> stddev=%" G_GUINT64_FORMAT "d, ip=%d, is_fp=%d, is_empty=%d", sq_stddev, invalid_percent, is_fp, is_empty);
if (invalid_percent < ELANSPI_MAX_REAL_INVALID_PERCENT) if (invalid_percent < ELANSPI_MAX_REAL_INVALID_PERCENT)
is_fp += 1; is_fp += 1;
if (invalid_percent > ELANSPI_MIN_EMPTY_INVALID_PERCENT) if (invalid_percent > ELANSPI_MIN_EMPTY_INVALID_PERCENT)
@@ -1231,6 +1239,8 @@ elanspi_guess_image (FpiDeviceElanSpi *self, guint16 *raw_image)
if (sq_stddev < ELANSPI_MAX_EMPTY_STDDEV) if (sq_stddev < ELANSPI_MAX_EMPTY_STDDEV)
is_empty += 1; is_empty += 1;
fp_dbg ("<guess> stddev=%" G_GUINT64_FORMAT "d, ip=%d, is_fp=%d, is_empty=%d", sq_stddev, invalid_percent, is_fp, is_empty);
if (is_fp > is_empty) if (is_fp > is_empty)
return ELANSPI_GUESS_FINGERPRINT; return ELANSPI_GUESS_FINGERPRINT;
else if (is_empty > is_fp) else if (is_empty > is_fp)
@@ -1482,11 +1492,12 @@ elanspi_fp_capture_ssm_handler (FpiSsm *ssm, FpDevice *dev)
if (self->deactivating) if (self->deactivating)
{ {
fp_dbg ("<capture> got deactivate; exiting"); fp_dbg ("<capture> got deactivate; exiting");
self->deactivating = FALSE;
fpi_ssm_mark_completed (ssm); fpi_ssm_mark_completed (ssm);
/* mark deactivate done */ /* mark deactivate done */
fpi_image_device_deactivate_complete (FP_IMAGE_DEVICE (dev), NULL); fpi_image_device_deactivate_complete (FP_IMAGE_DEVICE (dev), NULL);
self->deactivating = FALSE;
return; return;
} }
@@ -1495,6 +1506,7 @@ elanspi_fp_capture_ssm_handler (FpiSsm *ssm, FpDevice *dev)
chld = fpi_ssm_new (dev, elanspi_capture_hv_handler, ELANSPI_CAPTHV_NSTATES); chld = fpi_ssm_new (dev, elanspi_capture_hv_handler, ELANSPI_CAPTHV_NSTATES);
else else
chld = fpi_ssm_new (dev, elanspi_capture_old_handler, ELANSPI_CAPTOLD_NSTATES); chld = fpi_ssm_new (dev, elanspi_capture_old_handler, ELANSPI_CAPTOLD_NSTATES);
fpi_ssm_silence_debug (chld);
fpi_ssm_start_subsm (ssm, chld); fpi_ssm_start_subsm (ssm, chld);
return; return;

View File

@@ -97,7 +97,37 @@ static const struct elanspi_reg_entry elanspi_calibration_table_default[] = {
{0xff, 0xff} {0xff, 0xff}
}; };
static const struct elanspi_reg_entry elanspi_calibration_table_id567[] = { static const struct elanspi_reg_entry elanspi_calibration_table_id6[] = {
{0x2A, 0x07},
{0x1, 0x00},
{0x2, 0x5f},
{0x3, 0x00},
{0x4, 0x5f},
{0x5, 0x60},
{0x6, 0xC0},
{0x7, 0x80},
{0x8, 0x04},
{0xA, 0x97},
{0xB, 0x72},
{0xC, 0x69},
{0xF, 0x2A},
{0x11, 0x2A},
{0x13, 0x27},
{0x15, 0x67},
{0x18, 0x04},
{0x21, 0x20},
{0x22, 0x36},
{0x29, 0x02},
{0x2A, 0x03},
{0x2A, 0x5F},
{0x2B, 0xC0},
{0x2C, 0x10},
{0x2E, 0xFF},
{0xff, 0xff}
};
static const struct elanspi_reg_entry elanspi_calibration_table_id57[] = {
{0x2A, 0x07}, {0x2A, 0x07},
{0x5, 0x60}, {0x5, 0x60},
{0x6, 0xC0}, {0x6, 0xC0},
@@ -143,9 +173,9 @@ static const struct elanspi_regtable elanspi_calibration_table_old = {
.other = elanspi_calibration_table_default, .other = elanspi_calibration_table_default,
.entries = { .entries = {
{ .sid = 0x0, .table = elanspi_calibration_table_id0 }, { .sid = 0x0, .table = elanspi_calibration_table_id0 },
{ .sid = 0x5, .table = elanspi_calibration_table_id567 }, { .sid = 0x5, .table = elanspi_calibration_table_id57 },
{ .sid = 0x6, .table = elanspi_calibration_table_id567 }, { .sid = 0x6, .table = elanspi_calibration_table_id6 },
{ .sid = 0x7, .table = elanspi_calibration_table_id567 }, { .sid = 0x7, .table = elanspi_calibration_table_id57 },
{ .sid = 0x0, .table = NULL } { .sid = 0x0, .table = NULL }
} }
}; };

View File

@@ -159,7 +159,7 @@ fp_cmd_receive_cb (FpiUsbTransfer *transfer,
{ {
fpi_ssm_mark_failed (transfer->ssm, fpi_ssm_mark_failed (transfer->ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Corrupted message received")); "Corrupted message header received"));
return; return;
} }
@@ -420,12 +420,9 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp, gxfp_cmd_response_t *resp,
GError *error) GError *error)
{ {
g_autoptr(GPtrArray) templates = NULL;
FpDevice *device = FP_DEVICE (self); FpDevice *device = FP_DEVICE (self);
FpPrint *match = NULL; FpPrint *new_scan = NULL;
FpPrint *print = NULL; FpPrint *matching = NULL;
gint cnt = 0;
gboolean find = false;
if (error) if (error)
{ {
@@ -434,46 +431,34 @@ fp_verify_cb (FpiDeviceGoodixMoc *self,
} }
if (resp->verify.match) if (resp->verify.match)
{ {
match = fp_print_from_template (self, &resp->verify.template); new_scan = fp_print_from_template (self, &resp->verify.template);
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY) if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
{ {
templates = g_ptr_array_sized_new (1); fpi_device_get_verify_data (device, &matching);
fpi_device_get_verify_data (device, &print); if (!fp_print_equal (matching, new_scan))
g_ptr_array_add (templates, print); matching = NULL;
} }
else else
{ {
GPtrArray *templates = NULL;
fpi_device_get_identify_data (device, &templates); fpi_device_get_identify_data (device, &templates);
g_ptr_array_ref (templates);
}
for (cnt = 0; cnt < templates->len; cnt++)
{
print = g_ptr_array_index (templates, cnt);
if (fp_print_equal (print, match)) for (gint i = 0; i < templates->len; i++)
{ {
find = true; if (fp_print_equal (g_ptr_array_index (templates, i), new_scan))
break; {
matching = g_ptr_array_index (templates, i);
break;
}
} }
}
if (find)
{
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
fpi_device_verify_report (device, FPI_MATCH_SUCCESS, match, error);
else
fpi_device_identify_report (device, print, match, error);
} }
} }
if (!find) if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY)
{ fpi_device_verify_report (device, matching ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL, new_scan, error);
if (fpi_device_get_current_action (device) == FPI_DEVICE_ACTION_VERIFY) else
fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, error); fpi_device_identify_report (device, matching, new_scan, error);
else
fpi_device_identify_report (device, NULL, NULL, error);
}
fpi_ssm_next_state (self->task_ssm); fpi_ssm_next_state (self->task_ssm);
@@ -764,9 +749,14 @@ fp_enroll_check_duplicate_cb (FpiDeviceGoodixMoc *self,
} }
if (resp->check_duplicate_resp.duplicate) if (resp->check_duplicate_resp.duplicate)
{ {
g_autoptr(FpPrint) print = NULL;
print = g_object_ref_sink (fp_print_from_template (self, &resp->check_duplicate_resp.template));
fpi_ssm_mark_failed (self->task_ssm, fpi_ssm_mark_failed (self->task_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_DUPLICATE, fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_DUPLICATE,
"Finger has already enrolled")); "Finger was already enrolled as '%s'",
fp_print_get_description (print)));
return; return;
} }
@@ -1170,6 +1160,32 @@ fp_template_delete_cb (FpiDeviceGoodixMoc *self,
fp_info ("Successfully deleted enrolled user"); fp_info ("Successfully deleted enrolled user");
fpi_device_delete_complete (device, NULL); fpi_device_delete_complete (device, NULL);
} }
static void
fp_template_delete_all_cb (FpiDeviceGoodixMoc *self,
gxfp_cmd_response_t *resp,
GError *error)
{
FpDevice *device = FP_DEVICE (self);
if (error)
{
fpi_device_clear_storage_complete (device, error);
return;
}
if ((resp->result >= GX_FAILED) && (resp->result != GX_ERROR_FINGER_ID_NOEXIST))
{
fpi_device_clear_storage_complete (FP_DEVICE (self),
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Failed clear storage, result: 0x%x",
resp->result));
return;
}
fp_info ("Successfully cleared storage");
fpi_device_clear_storage_complete (device, NULL);
}
/****************************************************************************** /******************************************************************************
* *
* fp_template_list Function * fp_template_list Function
@@ -1493,6 +1509,19 @@ gx_fp_template_delete (FpDevice *device)
} }
static void
gx_fp_template_delete_all (FpDevice *device)
{
FpiDeviceGoodixMoc *self = FPI_DEVICE_GOODIXMOC (device);
goodix_sensor_cmd (self, MOC_CMD0_DELETETEMPLATE, MOC_CMD1_DELETE_ALL,
false,
NULL,
0,
fp_template_delete_all_cb);
}
static void static void
fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self) fpi_device_goodixmoc_init (FpiDeviceGoodixMoc *self)
{ {
@@ -1536,6 +1565,7 @@ fpi_device_goodixmoc_class_init (FpiDeviceGoodixMocClass *klass)
dev_class->probe = gx_fp_probe; dev_class->probe = gx_fp_probe;
dev_class->enroll = gx_fp_enroll; dev_class->enroll = gx_fp_enroll;
dev_class->delete = gx_fp_template_delete; dev_class->delete = gx_fp_template_delete;
dev_class->clear_storage = gx_fp_template_delete_all;
dev_class->list = gx_fp_template_list; dev_class->list = gx_fp_template_list;
dev_class->verify = gx_fp_verify_identify; dev_class->verify = gx_fp_verify_identify;
dev_class->identify = gx_fp_verify_identify; dev_class->identify = gx_fp_verify_identify;

View File

@@ -259,12 +259,9 @@ gx_proto_parse_fingerid (
if (buffer[Offset++] != 67) if (buffer[Offset++] != 67)
return -1; return -1;
fid_buffer_size--;
template->type = buffer[Offset++]; template->type = buffer[Offset++];
fid_buffer_size--;
template->finger_index = buffer[Offset++]; template->finger_index = buffer[Offset++];
fid_buffer_size--;
Offset++; Offset++;
memcpy (template->accountid, &buffer[Offset], sizeof (template->accountid)); memcpy (template->accountid, &buffer[Offset], sizeof (template->accountid));
Offset += sizeof (template->accountid); Offset += sizeof (template->accountid);
@@ -273,6 +270,8 @@ gx_proto_parse_fingerid (
template->payload.size = buffer[Offset++]; template->payload.size = buffer[Offset++];
if (template->payload.size > sizeof (template->payload.data)) if (template->payload.size > sizeof (template->payload.data))
return -1; return -1;
if (template->payload.size + Offset > fid_buffer_size)
return -1;
memset (template->payload.data, 0, template->payload.size); memset (template->payload.data, 0, template->payload.size);
memcpy (template->payload.data, &buffer[Offset], template->payload.size); memcpy (template->payload.data, &buffer[Offset], template->payload.size);
@@ -365,9 +364,12 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint16_t buffer_len, pgxfp_c
if (buffer_len < 3) if (buffer_len < 3)
return -1; return -1;
uint16_t tid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + 1)); uint16_t tid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + 1));
if ((buffer_len < tid_size + 3) || (buffer_len > sizeof (template_format_t)) + 3) offset += 3;
if (buffer_len < tid_size + offset)
return -1;
if (gx_proto_parse_fingerid (buffer + offset, tid_size, &presp->check_duplicate_resp.template) != 0)
return -1; return -1;
memcpy (&presp->check_duplicate_resp.template, buffer + 3, tid_size);
} }
break; break;
@@ -380,9 +382,12 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint16_t buffer_len, pgxfp_c
fingerlist = buffer + 2; fingerlist = buffer + 2;
for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++) for(uint8_t num = 0; num < presp->finger_list_resp.finger_num; num++)
{ {
uint16_t fingerid_length = GUINT16_FROM_LE (*(uint16_t *) (fingerlist + offset)); uint16_t fingerid_length;
if (buffer_len < offset + 2)
return -1;
fingerid_length = GUINT16_FROM_LE (*(uint16_t *) (fingerlist + offset));
offset += 2; offset += 2;
if (buffer_len < fingerid_length + offset + 2) if (buffer_len < fingerid_length + offset)
return -1; return -1;
if (gx_proto_parse_fingerid (fingerlist + offset, if (gx_proto_parse_fingerid (fingerlist + offset,
fingerid_length, fingerid_length,
@@ -405,7 +410,7 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint16_t buffer_len, pgxfp_c
presp->verify.match = (buffer[0] == 0) ? true : false; presp->verify.match = (buffer[0] == 0) ? true : false;
if (presp->verify.match) if (presp->verify.match)
{ {
if (buffer_len < sizeof (template_format_t) + 10) if (buffer_len < 10)
return -1; return -1;
offset += 1; offset += 1;
presp->verify.rejectdetail = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset)); presp->verify.rejectdetail = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset));
@@ -416,6 +421,8 @@ gx_proto_parse_body (uint16_t cmd, uint8_t *buffer, uint16_t buffer_len, pgxfp_c
offset += 1; offset += 1;
fingerid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset)); fingerid_size = GUINT16_FROM_LE (*(uint16_t *) (buffer + offset));
offset += 2; offset += 2;
if (buffer_len < fingerid_size + offset)
return -1;
if (gx_proto_parse_fingerid (buffer + offset, fingerid_size, &presp->verify.template) != 0) if (gx_proto_parse_fingerid (buffer + offset, fingerid_size, &presp->verify.template) != 0)
{ {
presp->result = GX_FAILED; presp->result = GX_FAILED;

View File

@@ -36,7 +36,6 @@ static const FpIdEntry id_table[] = {
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F9, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F9, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00FC, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00FC, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C2, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C2, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00C9, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0100, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0100, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F0, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x00F0, },
{ .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0103, }, { .vid = SYNAPTICS_VENDOR_ID, .pid = 0x0103, },

View File

@@ -426,6 +426,7 @@ void
fp_context_enumerate (FpContext *context) fp_context_enumerate (FpContext *context)
{ {
FpContextPrivate *priv = fp_context_get_instance_private (context); FpContextPrivate *priv = fp_context_get_instance_private (context);
gboolean dispatched;
gint i; gint i;
g_return_if_fail (FP_IS_CONTEXT (context)); g_return_if_fail (FP_IS_CONTEXT (context));
@@ -564,8 +565,19 @@ fp_context_enumerate (FpContext *context)
} }
#endif #endif
while (priv->pending_devices) /* Iterate until 1. we have no pending devices, and 2. the mainloop is idle
g_main_context_iteration (NULL, TRUE); * This takes care of processing hotplug events that happened during
* enumeration.
* This is important due to USB `persist` being turned off. At resume time,
* devices will disappear and immediately re-appear. In this situation,
* enumerate could first see the old state with a removed device resulting
* in it to not be discovered.
* As a hotplug event is seemingly emitted by the kernel immediately, we can
* simply make sure to process all events before returning from enumerate.
*/
dispatched = TRUE;
while (priv->pending_devices || dispatched)
dispatched = g_main_context_iteration (NULL, !!priv->pending_devices);
} }
/** /**

View File

@@ -1189,10 +1189,11 @@ fp_device_resume_finish (FpDevice *device,
* fp_device_enroll_finish(). * fp_device_enroll_finish().
* *
* The @template_print parameter is a #FpPrint with available metadata filled * 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 * in and, optionally, with existing fingerprint data to be updated with newly
* device memory. It is undefined whether this print is filled in by the driver * enrolled fingerprints if a device driver supports it. The driver may make use
* and returned, or whether the driver will return a newly created print after * of the metadata, when e.g. storing the print on device memory. It is undefined
* enrollment succeeded. * 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 void
fp_device_enroll (FpDevice *device, fp_device_enroll (FpDevice *device,
@@ -1229,19 +1230,30 @@ fp_device_enroll (FpDevice *device,
if (!FP_IS_PRINT (template_print)) if (!FP_IS_PRINT (template_print))
{ {
g_warning ("User did not pass a print template!");
g_task_return_error (task, 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; return;
} }
g_object_get (template_print, "fpi-type", &print_type, NULL); g_object_get (template_print, "fpi-type", &print_type, NULL);
if (print_type != FPI_PRINT_UNDEFINED) if (print_type != FPI_PRINT_UNDEFINED)
{ {
g_warning ("Passed print template must be newly created and blank!"); if (!fp_device_has_feature (device, FP_DEVICE_FEATURE_UPDATE_PRINT))
g_task_return_error (task, {
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); g_task_return_error (task,
return; 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; priv->current_action = FPI_DEVICE_ACTION_ENROLL;

View File

@@ -59,6 +59,7 @@ typedef enum {
* @FP_DEVICE_FEATURE_STORAGE_CLEAR: Supports clearing the whole storage * @FP_DEVICE_FEATURE_STORAGE_CLEAR: Supports clearing the whole storage
* @FP_DEVICE_FEATURE_DUPLICATES_CHECK: Natively supports duplicates detection * @FP_DEVICE_FEATURE_DUPLICATES_CHECK: Natively supports duplicates detection
* @FP_DEVICE_FEATURE_ALWAYS_ON: Whether the device can run continuously * @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 >*/ { typedef enum /*< flags >*/ {
FP_DEVICE_FEATURE_NONE = 0, FP_DEVICE_FEATURE_NONE = 0,
@@ -71,6 +72,7 @@ typedef enum /*< flags >*/ {
FP_DEVICE_FEATURE_STORAGE_CLEAR = 1 << 6, FP_DEVICE_FEATURE_STORAGE_CLEAR = 1 << 6,
FP_DEVICE_FEATURE_DUPLICATES_CHECK = 1 << 7, FP_DEVICE_FEATURE_DUPLICATES_CHECK = 1 << 7,
FP_DEVICE_FEATURE_ALWAYS_ON = 1 << 8, FP_DEVICE_FEATURE_ALWAYS_ON = 1 << 8,
FP_DEVICE_FEATURE_UPDATE_PRINT = 1 << 9,
} FpDeviceFeature; } FpDeviceFeature;
/** /**

View File

@@ -101,6 +101,7 @@ fp_image_device_start_capture_action (FpDevice *device)
FpImageDevice *self = FP_IMAGE_DEVICE (device); FpImageDevice *self = FP_IMAGE_DEVICE (device);
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self); FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
FpiDeviceAction action; FpiDeviceAction action;
FpiPrintType print_type;
/* There is just one action that we cannot support out /* There is just one action that we cannot support out
* of the box, which is a capture without first waiting * 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; FpPrint *enroll_print = NULL;
fpi_device_get_enroll_data (device, &enroll_print); 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; priv->enroll_stage = 0;
@@ -221,6 +224,7 @@ fp_image_device_class_init (FpImageDeviceClass *klass)
fp_device_class->cancel = fp_image_device_cancel_action; fp_device_class->cancel = fp_image_device_cancel_action;
fpi_device_class_auto_initialize_features (fp_device_class); fpi_device_class_auto_initialize_features (fp_device_class);
fp_device_class->features |= FP_DEVICE_FEATURE_UPDATE_PRINT;
/* Default implementations */ /* Default implementations */
klass->activate = fp_image_device_default_activate; klass->activate = fp_image_device_default_activate;

View File

@@ -61,6 +61,7 @@ enum {
/* Private property*/ /* Private property*/
PROP_FPI_TYPE, PROP_FPI_TYPE,
PROP_FPI_DATA, PROP_FPI_DATA,
PROP_FPI_PRINTS,
N_PROPS N_PROPS
}; };
@@ -133,6 +134,10 @@ fp_print_get_property (GObject *object,
g_value_set_variant (value, self->data); g_value_set_variant (value, self->data);
break; break;
case PROP_FPI_PRINTS:
g_value_set_pointer (value, self->prints);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 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); self->data = g_value_dup_variant (value);
break; break;
case PROP_FPI_PRINTS:
g_clear_pointer (&self->prints, g_ptr_array_unref);
self->prints = g_value_get_pointer (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
} }
@@ -299,6 +309,19 @@ fp_print_class_init (FpPrintClass *klass)
NULL, NULL,
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE); 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); g_object_class_install_properties (object_class, N_PROPS, properties);
} }

View File

@@ -25,9 +25,11 @@
#include "fpi-print.h" #include "fpi-print.h"
/** /**
* FpiDeviceUdevSubtype: * FpiDeviceUdevSubtypeFlags:
* @FPI_DEVICE_UDEV_SUBTYPE_SPIDEV: The device requires an spidev node * @FPI_DEVICE_UDEV_SUBTYPE_SPIDEV: The device requires an spidev node
* @FPI_DEVICE_UDEV_SUBTYPE_HIDRAW: The device requires a hidraw node * @FPI_DEVICE_UDEV_SUBTYPE_HIDRAW: The device requires a hidraw node
*
* Bitfield of required hardware resources for a udev-backed device.
*/ */
typedef enum { typedef enum {
FPI_DEVICE_UDEV_SUBTYPE_SPIDEV = 1 << 0, FPI_DEVICE_UDEV_SUBTYPE_SPIDEV = 1 << 0,

View File

@@ -81,6 +81,7 @@ struct _FpiSsm
int start_cleanup; int start_cleanup;
int cur_state; int cur_state;
gboolean completed; gboolean completed;
gboolean silence;
GSource *timeout; GSource *timeout;
GError *error; GError *error;
FpiSsmCompletedCallback callback; FpiSsmCompletedCallback callback;
@@ -245,10 +246,11 @@ fpi_ssm_free (FpiSsm *machine)
/* Invoke the state handler */ /* Invoke the state handler */
static void static void
__ssm_call_handler (FpiSsm *machine) __ssm_call_handler (FpiSsm *machine, gboolean force_msg)
{ {
fp_dbg ("[%s] %s entering state %d", fp_device_get_driver (machine->dev), if (force_msg || !machine->silence)
machine->name, machine->cur_state); fp_dbg ("[%s] %s entering state %d", fp_device_get_driver (machine->dev),
machine->name, machine->cur_state);
machine->handler (machine, machine->dev); machine->handler (machine, machine->dev);
} }
@@ -275,7 +277,7 @@ fpi_ssm_start (FpiSsm *ssm, FpiSsmCompletedCallback callback)
ssm->cur_state = 0; ssm->cur_state = 0;
ssm->completed = FALSE; ssm->completed = FALSE;
ssm->error = NULL; ssm->error = NULL;
__ssm_call_handler (ssm); __ssm_call_handler (ssm, TRUE);
} }
static void static void
@@ -346,7 +348,7 @@ fpi_ssm_mark_completed (FpiSsm *machine)
if (next_state < machine->nr_states) if (next_state < machine->nr_states)
{ {
machine->cur_state = next_state; machine->cur_state = next_state;
__ssm_call_handler (machine); __ssm_call_handler (machine, TRUE);
return; return;
} }
@@ -460,7 +462,7 @@ fpi_ssm_next_state (FpiSsm *machine)
if (machine->cur_state == machine->nr_states) if (machine->cur_state == machine->nr_states)
fpi_ssm_mark_completed (machine); fpi_ssm_mark_completed (machine);
else else
__ssm_call_handler (machine); __ssm_call_handler (machine, FALSE);
} }
void void
@@ -537,7 +539,7 @@ fpi_ssm_jump_to_state (FpiSsm *machine, int state)
if (machine->cur_state == machine->nr_states) if (machine->cur_state == machine->nr_states)
fpi_ssm_mark_completed (machine); fpi_ssm_mark_completed (machine);
else else
__ssm_call_handler (machine); __ssm_call_handler (machine, FALSE);
} }
typedef struct typedef struct
@@ -642,6 +644,22 @@ fpi_ssm_dup_error (FpiSsm *machine)
return NULL; return NULL;
} }
/**
* fpi_ssm_silence_debug:
* @machine: an #FpiSsm state machine
*
* Turn off state change debug messages from this SSM. This does not disable
* all messages, as e.g. the initial state, SSM completion and cleanup states
* are still printed out.
*
* Use if the SSM loops and would flood the debug log otherwise.
*/
void
fpi_ssm_silence_debug (FpiSsm *machine)
{
machine->silence = TRUE;
}
/** /**
* fpi_ssm_usb_transfer_cb: * fpi_ssm_usb_transfer_cb:
* @transfer: a #FpiUsbTransfer * @transfer: a #FpiUsbTransfer

View File

@@ -96,6 +96,8 @@ GError * fpi_ssm_get_error (FpiSsm *machine);
GError * fpi_ssm_dup_error (FpiSsm *machine); GError * fpi_ssm_dup_error (FpiSsm *machine);
int fpi_ssm_get_cur_state (FpiSsm *machine); int fpi_ssm_get_cur_state (FpiSsm *machine);
void fpi_ssm_silence_debug (FpiSsm *machine);
/* Callbacks to be used by the driver instead of implementing their own /* Callbacks to be used by the driver instead of implementing their own
* logic. * logic.
*/ */

View File

@@ -42,15 +42,19 @@ static const FpIdEntry whitelist_id_table[] = {
{ .vid = 0x06cb, .pid = 0x009a }, { .vid = 0x06cb, .pid = 0x009a },
{ .vid = 0x06cb, .pid = 0x009b }, { .vid = 0x06cb, .pid = 0x009b },
{ .vid = 0x06cb, .pid = 0x00a2 }, { .vid = 0x06cb, .pid = 0x00a2 },
{ .vid = 0x06cb, .pid = 0x00a8 },
{ .vid = 0x06cb, .pid = 0x00b7 }, { .vid = 0x06cb, .pid = 0x00b7 },
{ .vid = 0x06cb, .pid = 0x00bb }, { .vid = 0x06cb, .pid = 0x00bb },
{ .vid = 0x06cb, .pid = 0x00be }, { .vid = 0x06cb, .pid = 0x00be },
{ .vid = 0x06cb, .pid = 0x00c4 }, { .vid = 0x06cb, .pid = 0x00c4 },
{ .vid = 0x06cb, .pid = 0x00cb }, { .vid = 0x06cb, .pid = 0x00cb },
{ .vid = 0x06cb, .pid = 0x00c9 },
{ .vid = 0x06cb, .pid = 0x00d8 }, { .vid = 0x06cb, .pid = 0x00d8 },
{ .vid = 0x06cb, .pid = 0x00da }, { .vid = 0x06cb, .pid = 0x00da },
{ .vid = 0x06cb, .pid = 0x00dc },
{ .vid = 0x06cb, .pid = 0x00e7 }, { .vid = 0x06cb, .pid = 0x00e7 },
{ .vid = 0x06cb, .pid = 0x00e9 }, { .vid = 0x06cb, .pid = 0x00e9 },
{ .vid = 0x06cb, .pid = 0x00fd },
{ .vid = 0x0a5c, .pid = 0x5801 }, { .vid = 0x0a5c, .pid = 0x5801 },
{ .vid = 0x0a5c, .pid = 0x5805 }, { .vid = 0x0a5c, .pid = 0x5805 },
{ .vid = 0x0a5c, .pid = 0x5834 }, { .vid = 0x0a5c, .pid = 0x5834 },
@@ -62,6 +66,7 @@ static const FpIdEntry whitelist_id_table[] = {
{ .vid = 0x0a5c, .pid = 0x5845 }, { .vid = 0x0a5c, .pid = 0x5845 },
{ .vid = 0x0bda, .pid = 0x5812 }, { .vid = 0x0bda, .pid = 0x5812 },
{ .vid = 0x10a5, .pid = 0x0007 }, { .vid = 0x10a5, .pid = 0x0007 },
{ .vid = 0x10a5, .pid = 0x9200 },
{ .vid = 0x1188, .pid = 0x9545 }, { .vid = 0x1188, .pid = 0x9545 },
{ .vid = 0x138a, .pid = 0x0007 }, { .vid = 0x138a, .pid = 0x0007 },
{ .vid = 0x138a, .pid = 0x003a }, { .vid = 0x138a, .pid = 0x003a },
@@ -79,6 +84,7 @@ static const FpIdEntry whitelist_id_table[] = {
{ .vid = 0x16d1, .pid = 0x1027 }, { .vid = 0x16d1, .pid = 0x1027 },
{ .vid = 0x1c7a, .pid = 0x0300 }, { .vid = 0x1c7a, .pid = 0x0300 },
{ .vid = 0x1c7a, .pid = 0x0575 }, { .vid = 0x1c7a, .pid = 0x0575 },
{ .vid = 0x1c7a, .pid = 0x0576 },
{ .vid = 0x27c6, .pid = 0x5042 }, { .vid = 0x27c6, .pid = 0x5042 },
{ .vid = 0x27c6, .pid = 0x5110 }, { .vid = 0x27c6, .pid = 0x5110 },
{ .vid = 0x27c6, .pid = 0x5117 }, { .vid = 0x27c6, .pid = 0x5117 },
@@ -98,7 +104,9 @@ static const FpIdEntry whitelist_id_table[] = {
{ .vid = 0x27c6, .pid = 0x55a4 }, { .vid = 0x27c6, .pid = 0x55a4 },
{ .vid = 0x27c6, .pid = 0x55b4 }, { .vid = 0x27c6, .pid = 0x55b4 },
{ .vid = 0x27c6, .pid = 0x5740 }, { .vid = 0x27c6, .pid = 0x5740 },
{ .vid = 0x27c6, .pid = 0x5e0a },
{ .vid = 0x2808, .pid = 0x9338 }, { .vid = 0x2808, .pid = 0x9338 },
{ .vid = 0x298d, .pid = 0x2020 },
{ .vid = 0x298d, .pid = 0x2033 }, { .vid = 0x298d, .pid = 0x2033 },
{ .vid = 0x3538, .pid = 0x0930 }, { .vid = 0x3538, .pid = 0x0930 },
{ .vid = 0 }, { .vid = 0 },

View File

@@ -1,5 +1,5 @@
project('libfprint', [ 'c', 'cpp' ], project('libfprint', [ 'c', 'cpp' ],
version: '1.94.2', version: '1.94.3',
license: 'LGPLv2.1+', license: 'LGPLv2.1+',
default_options: [ default_options: [
'buildtype=debugoptimized', 'buildtype=debugoptimized',

View File

@@ -24,6 +24,10 @@ TW 8c62
TW 805a TW 805a
TW 04 TW 04
TW aa07 TW aa07
TW 8100
TW 825f
TW 8300
TW 845f
TW 8560 TW 8560
TW 86c0 TW 86c0
TW 8780 TW 8780
@@ -38,8 +42,11 @@ TW 9567
TW 9804 TW 9804
TW a120 TW a120
TW a236 TW a236
TW a902
TW aa03
TW aa5f TW aa5f
TW abc0 TW abc0
TW ac10
TW aeff TW aeff
TW 01 TW 01
TW 03ff TW 03ff

View File

@@ -21,7 +21,7 @@ assert d.has_feature(FPrint.DeviceFeature.DUPLICATES_CHECK)
assert d.has_feature(FPrint.DeviceFeature.STORAGE) assert d.has_feature(FPrint.DeviceFeature.STORAGE)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_LIST) assert d.has_feature(FPrint.DeviceFeature.STORAGE_LIST)
assert d.has_feature(FPrint.DeviceFeature.STORAGE_DELETE) assert d.has_feature(FPrint.DeviceFeature.STORAGE_DELETE)
assert not d.has_feature(FPrint.DeviceFeature.STORAGE_CLEAR) assert d.has_feature(FPrint.DeviceFeature.STORAGE_CLEAR)
d.open_sync() d.open_sync()

View File

@@ -27,6 +27,7 @@
#include "fpi-compat.h" #include "fpi-compat.h"
#include "fpi-log.h" #include "fpi-log.h"
#include "test-device-fake.h" #include "test-device-fake.h"
#include "fp-print-private.h"
/* Utility functions */ /* Utility functions */
@@ -142,6 +143,16 @@ make_fake_print (FpDevice *device,
return enrolled_print; return enrolled_print;
} }
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 * static FpPrint *
make_fake_print_reffed (FpDevice *device, make_fake_print_reffed (FpDevice *device,
GVariant *print_data) GVariant *print_data)
@@ -1045,7 +1056,6 @@ test_driver_enroll_error_no_print (void)
out_print = out_print =
fp_device_enroll_sync (device, fp_print_new (device), NULL, NULL, NULL, &error); 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 (fake_dev->last_called_function == dev_class->enroll);
g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL); g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL);
g_assert_null (out_print); g_assert_null (out_print);
@@ -1053,6 +1063,111 @@ test_driver_enroll_error_no_print (void)
g_clear_error (&error); 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 typedef struct
{ {
gint completed_stages; 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", 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/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/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", test_driver_verify);
g_test_add_func ("/driver/verify/fail", test_driver_verify_fail); g_test_add_func ("/driver/verify/fail", test_driver_verify_fail);
g_test_add_func ("/driver/verify/retry", test_driver_verify_retry); g_test_add_func ("/driver/verify/retry", test_driver_verify_retry);

View File

@@ -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.CAPTURE))
self.assertTrue(self.dev.has_feature(FPrint.DeviceFeature.IDENTIFY)) 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.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.DUPLICATES_CHECK))
self.assertFalse(self.dev.has_feature(FPrint.DeviceFeature.STORAGE)) self.assertFalse(self.dev.has_feature(FPrint.DeviceFeature.STORAGE))
self.assertFalse(self.dev.has_feature(FPrint.DeviceFeature.STORAGE_LIST)) self.assertFalse(self.dev.has_feature(FPrint.DeviceFeature.STORAGE_LIST))
@@ -144,7 +145,8 @@ class VirtualImage(unittest.TestCase):
self.assertEqual(self.dev.get_features(), self.assertEqual(self.dev.get_features(),
FPrint.DeviceFeature.CAPTURE | FPrint.DeviceFeature.CAPTURE |
FPrint.DeviceFeature.IDENTIFY | FPrint.DeviceFeature.IDENTIFY |
FPrint.DeviceFeature.VERIFY) FPrint.DeviceFeature.VERIFY |
FPrint.DeviceFeature.UPDATE_PRINT)
def test_capture_prevents_close(self): def test_capture_prevents_close(self):
cancel = Gio.Cancellable() cancel = Gio.Cancellable()
@@ -167,7 +169,7 @@ class VirtualImage(unittest.TestCase):
while not self._cancelled: while not self._cancelled:
ctx.iteration(True) ctx.iteration(True)
def enroll_print(self, image): def enroll_print(self, image, template=None):
self._step = 0 self._step = 0
self._enrolled = None self._enrolled = None
@@ -181,14 +183,15 @@ class VirtualImage(unittest.TestCase):
self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NONE) self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NONE)
self._enrolled = fp self._enrolled = fp
template = FPrint.Print.new(self.dev) if template is None:
template.props.finger = FPrint.Finger.LEFT_THUMB template = FPrint.Print.new(self.dev)
template.props.username = "testuser" template.props.finger = FPrint.Finger.LEFT_THUMB
template.props.description = "test print" template.props.username = "testuser"
datetime = GLib.DateTime.new_now_local() template.props.description = "test print"
date = GLib.Date() datetime = GLib.DateTime.new_now_local()
date.set_dmy(*datetime.get_ymd()[::-1]) date = GLib.Date()
template.props.enroll_date = date date.set_dmy(*datetime.get_ymd()[::-1])
template.props.enroll_date = date
self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NONE) self.assertEqual(self.dev.get_finger_status(), FPrint.FingerStatusFlags.NONE)
self.dev.enroll(template, None, progress_cb, tuple(), done_cb) self.dev.enroll(template, None, progress_cb, tuple(), done_cb)
@@ -264,6 +267,28 @@ class VirtualImage(unittest.TestCase):
ctx.iteration(True) ctx.iteration(True)
assert(not self._verify_match) 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 # Test verify error cases
self._verify_fp = None self._verify_fp = None
self._verify_error = None self._verify_error = None