Merge tag 'v1.90.1' into tod

Tag 1.90.1
This commit is contained in:
Marco Trevisan (Treviño)
2020-02-27 05:24:32 +01:00
39 changed files with 1851 additions and 357 deletions
+1 -22
View File
@@ -1,24 +1,3 @@
ltmain.sh
missing
stamp-h1
libtool
*.la
*.lo
*.o *.o
*.swp *.swp
Makefile _build
Makefile.in
config.h*
aclocal.m4
autom4te.cache
config.guess
config.log
config.status
config.sub
configure
depcomp
install-sh
.deps
.libs
compile
ChangeLog
+11 -33
View File
@@ -1,15 +1,17 @@
include:
- local: '.gitlab-ci/libfprint-templates.yaml'
- project: 'wayland/ci-templates'
ref: master
file: '/templates/fedora.yml'
variables: variables:
extends: .libfprint_common_variables
FEDORA_TAG: rawhide FEDORA_TAG: rawhide
FEDORA_VERSION: rawhide FEDORA_VERSION: rawhide
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FEDORA_VERSION:$FEDORA_TAG" FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FEDORA_VERSION:$FEDORA_TAG"
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak" BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546" LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
include:
- project: 'wayland/ci-templates'
ref: master
file: '/templates/fedora.yml'
stages: stages:
- check-source - check-source
- build - build
@@ -106,9 +108,6 @@ test_indent:
.flatpak_master_template: &flatpak_master .flatpak_master_template: &flatpak_master
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.32 image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.32
stage: flatpack stage: flatpack
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
variables: variables:
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json" MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
# From demo/org.freedesktop.libfprint.Demo.json # From demo/org.freedesktop.libfprint.Demo.json
@@ -128,8 +127,11 @@ flatpak-manual master:
<<: *flatpak_master <<: *flatpak_master
when: manual when: manual
except: except:
refs:
- tags - tags
- master - master
variables:
- $CI_PIPELINE_SOURCE == "schedule"
# CONTAINERS creation stage # CONTAINERS creation stage
container_fedora_build: container_fedora_build:
@@ -140,28 +142,4 @@ container_fedora_build:
variables: variables:
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
# a list of packages to install # a list of packages to install
FEDORA_RPMS: FEDORA_RPMS: $LIBFPRINT_DEPENDENCIES
doxygen
flatpak-builder
gcc
gcc-c++
gcovr
git
glib2-devel
glibc-devel
gobject-introspection-devel
gtk-doc
gtk3-devel
libabigail
libgusb-devel
libX11-devel
libXv-devel
meson
nss-devel
pixman-devel
python3-cairo
python3-gobject
systemd
umockdev
uncrustify
valgrind
+26
View File
@@ -0,0 +1,26 @@
.libfprint_common_variables:
LIBFPRINT_DEPENDENCIES:
doxygen
flatpak-builder
gcc
gcc-c++
gcovr
git
glib2-devel
glibc-devel
gobject-introspection-devel
gtk-doc
gtk3-devel
libabigail
libgusb-devel
libX11-devel
libXv-devel
meson
nss-devel
pixman-devel
python3-cairo
python3-gobject
systemd
umockdev
uncrustify
valgrind
+35
View File
@@ -1,6 +1,41 @@
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.
2019-11-20: v1.90.1 release
This release fixes a lot of the regressions introduced in 1.90.0. Please note
that both the driver and external APIs have changed, as both the verify and
the identify functions now have early reporting mechanisms.
The soname for the library, as well as a number of file locations have also
changed. While this allows installation in parallel with the 1.0 version of
libfprint, we recommend installing only one, and migrating from version 1.0 to
version 2.0 alongside its main consumer (fprintd).
Only major changes are listed below. A lot of other cleanup work and small
fixes have also been merged.
* Library:
- Add support to run tests in gdb/valgrind
- Allow testing on all architectures
- Avoid image device AWAIT_FINGER_ON to deactivate state transitions
- Fix verify/identify error propagation to library user
- Correctly read image device information from class data
- Continue enroll after an image driver reported a retry error
- Change external API to allow reporting match results early
- A lot of new unit tests and integration tests have been added
* Drivers API
- Support variadic arguments in error functions
- Various re-definitions of ownership handling
- Add convenience API to change state after a timeout
- Add unit tests for all the drivers API
* Drivers:
- elan: Ensure correct deactivation of device
- uru4000: Fix IRQ handler registration and internal state handling
- uru4000: Fix control transfer request type
- synaptics: Ensure errors are only reported after finger removal
2019-11-20: v1.90.0 release 2019-11-20: v1.90.0 release
This release updates the core of the library to use GLib routines and Gio This release updates the core of the library to use GLib routines and Gio
+3
View File
@@ -26,6 +26,7 @@ FpDeviceError
fp_device_retry_quark fp_device_retry_quark
fp_device_error_quark fp_device_error_quark
FpEnrollProgress FpEnrollProgress
FpMatchCb
fp_device_get_driver fp_device_get_driver
fp_device_get_device_id fp_device_get_device_id
fp_device_get_name fp_device_get_name
@@ -159,6 +160,8 @@ fpi_device_identify_complete
fpi_device_capture_complete fpi_device_capture_complete
fpi_device_delete_complete fpi_device_delete_complete
fpi_device_enroll_progress fpi_device_enroll_progress
fpi_device_verify_report
fpi_device_identify_report
</SECTION> </SECTION>
<SECTION> <SECTION>
+2 -5
View File
@@ -23,16 +23,13 @@ glib_prefix = dependency('glib-2.0').get_pkgconfig_variable('prefix')
glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html') glib_docpath = join_paths(glib_prefix, 'share', 'gtk-doc', 'html')
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html') docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
gnome.gtkdoc(meson.project_name(), gnome.gtkdoc(versioned_libname,
main_xml: 'libfprint-docs.xml', main_xml: 'libfprint-docs.xml',
src_dir: join_paths(meson.source_root(), 'libfprint'), src_dir: join_paths(meson.source_root(), 'libfprint'),
dependencies: libfprint_dep, dependencies: libfprint_dep,
content_files: content_files, content_files: content_files,
expand_content_files: expand_content_files, expand_content_files: expand_content_files,
scan_args: [ ignore_headers: private_headers,
#'--rebuild-sections',
'--ignore-headers=' + ' '.join(private_headers),
],
fixxref_args: [ fixxref_args: [
'--html-dir=@0@'.format(docpath), '--html-dir=@0@'.format(docpath),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')), '--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
+3 -3
View File
@@ -1,8 +1,8 @@
ent_conf = configuration_data() ent_conf = configuration_data()
ent_conf.set('PACKAGE', meson.project_name()) ent_conf.set('PACKAGE', versioned_libname)
ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues') ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.freedesktop.org/libfprint/libfprint/issues')
ent_conf.set('PACKAGE_NAME', meson.project_name()) ent_conf.set('PACKAGE_NAME', versioned_libname)
ent_conf.set('PACKAGE_STRING', meson.project_name()) ent_conf.set('PACKAGE_STRING', versioned_libname)
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version()) ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/') ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
ent_conf.set('PACKAGE_VERSION', meson.project_version()) ent_conf.set('PACKAGE_VERSION', meson.project_version())
+2
View File
@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#define FP_COMPONENT "example-enroll"
#include <stdio.h> #include <stdio.h>
#include <libfprint/fprint.h> #include <libfprint/fprint.h>
+2
View File
@@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#define FP_COMPONENT "example-mange-prints"
#include <stdio.h> #include <stdio.h>
#include <libfprint/fprint.h> #include <libfprint/fprint.h>
+4 -2
View File
@@ -19,7 +19,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#define FP_COMPONENT "example-storage"
#include <libfprint/fprint.h> #include <libfprint/fprint.h>
#include <libfprint/fpi-compat.h>
#include "storage.h" #include "storage.h"
#include <errno.h> #include <errno.h>
@@ -161,8 +164,8 @@ FpPrint *
print_create_template (FpDevice *dev, FpFinger finger) print_create_template (FpDevice *dev, FpFinger finger)
{ {
g_autoptr(GDateTime) datetime = NULL; g_autoptr(GDateTime) datetime = NULL;
g_autoptr(GDate) date = NULL;
FpPrint *template = NULL; FpPrint *template = NULL;
GDate *date = NULL;
gint year, month, day; gint year, month, day;
template = fp_print_new (dev); template = fp_print_new (dev);
@@ -172,7 +175,6 @@ print_create_template (FpDevice *dev, FpFinger finger)
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);
fp_print_set_enroll_date (template, date); fp_print_set_enroll_date (template, date);
g_date_free (date);
return template; return template;
} }
+2
View File
@@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#define FP_COMPONENT "example-utilities"
#include <libfprint/fprint.h> #include <libfprint/fprint.h>
#include <stdio.h> #include <stdio.h>
+69 -22
View File
@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#define FP_COMPONENT "example-verify"
#include <stdio.h> #include <stdio.h>
#include <libfprint/fprint.h> #include <libfprint/fprint.h>
@@ -55,6 +57,19 @@ on_device_closed (FpDevice *dev, GAsyncResult *res, void *user_data)
g_main_loop_quit (verify_data->loop); g_main_loop_quit (verify_data->loop);
} }
static void
verify_quit (FpDevice *dev,
VerifyData *verify_data)
{
if (!fp_device_is_open (dev))
{
g_main_loop_quit (verify_data->loop);
return;
}
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, verify_data);
}
static void start_verification (FpDevice *dev, static void start_verification (FpDevice *dev,
VerifyData *verify_data); VerifyData *verify_data);
@@ -71,23 +86,13 @@ on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
if (!fp_device_verify_finish (dev, res, &match, &print, &error)) if (!fp_device_verify_finish (dev, res, &match, &print, &error))
{ {
g_warning ("Failed to verify print: %s", error->message); g_warning ("Failed to verify print: %s", error->message);
g_main_loop_quit (verify_data->loop); verify_data->ret_value = EXIT_FAILURE;
if (error->domain != FP_DEVICE_RETRY)
{
verify_quit (dev, verify_data);
return; return;
} }
if (print && fp_device_supports_capture (dev) &&
print_image_save (print, "verify.pgm"))
g_print ("Print image saved as verify.pgm\n");
if (match)
{
g_print ("MATCH!\n");
verify_data->ret_value = EXIT_SUCCESS;
}
else
{
g_print ("NO MATCH!\n");
verify_data->ret_value = EXIT_FAILURE;
} }
g_print ("Verify again? [Y/n]? "); g_print ("Verify again? [Y/n]? ");
@@ -98,8 +103,48 @@ on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
return; return;
} }
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed, verify_quit (dev, verify_data);
verify_data); }
static void
on_match_cb (FpDevice *dev, FpPrint *match, FpPrint *print,
gpointer user_data, GError *error)
{
VerifyData *verify_data = user_data;
if (error)
{
g_warning ("Match report: Finger not matched, retry error reported: %s",
error->message);
return;
}
if (print && fp_device_supports_capture (dev) &&
print_image_save (print, "verify.pgm"))
g_print ("Print image saved as verify.pgm\n");
if (match)
{
char date_str[128];
verify_data->ret_value = EXIT_SUCCESS;
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 "
"with print %s, enrolled on date %s by user %s",
fp_device_get_name (dev),
finger_to_string (fp_print_get_finger (match)),
fp_print_get_description (match), date_str,
fp_print_get_username (match));
g_print ("MATCH!\n");
}
else
{
g_debug ("Match report: Finger not matched");
g_print ("NO MATCH!\n");
}
} }
static void static void
@@ -143,7 +188,7 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
{ {
g_warning ("Did you remember to enroll your %s finger first?", g_warning ("Did you remember to enroll your %s finger first?",
finger_to_string (verify_data->finger)); finger_to_string (verify_data->finger));
g_main_loop_quit (verify_data->loop); verify_quit (dev, verify_data);
return; return;
} }
@@ -152,13 +197,14 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
g_print ("Print loaded. Time to verify!\n"); g_print ("Print loaded. Time to verify!\n");
fp_device_verify (dev, verify_print, NULL, fp_device_verify (dev, verify_print, NULL,
on_match_cb, verify_data, NULL,
(GAsyncReadyCallback) on_verify_completed, (GAsyncReadyCallback) on_verify_completed,
verify_data); verify_data);
} }
else else
{ {
g_warning ("Loading prints failed with error %s", error->message); g_warning ("Loading prints failed with error %s", error->message);
g_main_loop_quit (verify_data->loop); verify_quit (dev, verify_data);
} }
} }
@@ -175,7 +221,7 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
{ {
g_warning ("Unknown finger selected"); g_warning ("Unknown finger selected");
verify_data->ret_value = EXIT_FAILURE; verify_data->ret_value = EXIT_FAILURE;
g_main_loop_quit (verify_data->loop); verify_quit (dev, verify_data);
return; return;
} }
@@ -199,12 +245,13 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
g_warning ("Failed to load fingerprint data"); g_warning ("Failed to load fingerprint data");
g_warning ("Did you remember to enroll your %s finger first?", g_warning ("Did you remember to enroll your %s finger first?",
finger_to_string (verify_data->finger)); finger_to_string (verify_data->finger));
g_main_loop_quit (verify_data->loop); verify_quit (dev, verify_data);
return; return;
} }
g_print ("Print loaded. Time to verify!\n"); g_print ("Print loaded. Time to verify!\n");
fp_device_verify (dev, verify_print, NULL, fp_device_verify (dev, verify_print, NULL,
NULL, NULL, NULL,
(GAsyncReadyCallback) on_verify_completed, (GAsyncReadyCallback) on_verify_completed,
verify_data); verify_data);
} }
@@ -220,7 +267,7 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
if (!fp_device_open_finish (dev, res, &error)) if (!fp_device_open_finish (dev, res, &error))
{ {
g_warning ("Failed to open device: %s", error->message); g_warning ("Failed to open device: %s", error->message);
g_main_loop_quit (verify_data->loop); verify_quit (dev, verify_data);
return; return;
} }
-2
View File
@@ -585,8 +585,6 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
G_DEBUG_HERE (); G_DEBUG_HERE ();
/* XXX: cancellation was specially handled by doing nothing! */
/* either max frames captured or timed out waiting for the next frame */ /* either max frames captured or timed out waiting for the next frame */
if (!error || if (!error ||
(g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) && (g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) &&
+36 -32
View File
@@ -279,17 +279,10 @@ cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
self->cmd_ssm = NULL; self->cmd_ssm = NULL;
/* Notify about the SSM failure from here instead. */ /* Notify about the SSM failure from here instead. */
if (error) if (error || self->cmd_complete_on_removal)
{
callback (self, NULL, error); callback (self, NULL, error);
}
else if (self->cmd_complete_on_removal)
{
callback (self, NULL, self->cmd_complete_error);
self->cmd_complete_error = NULL;
}
self->cmd_complete_on_removal = FALSE; self->cmd_complete_on_removal = FALSE;
g_clear_pointer (&self->cmd_complete_error, g_error_free);
} }
static void static void
@@ -527,8 +520,8 @@ list_msg_cb (FpiDeviceSynaptics *self,
userid[12] == '-' && userid[14] == '-' && userid[23] == '-') userid[12] == '-' && userid[14] == '-' && userid[23] == '-')
{ {
g_autofree gchar *copy = g_strdup (userid); g_autofree gchar *copy = g_strdup (userid);
g_autoptr(GDate) date = NULL;
gint32 date_ymd; gint32 date_ymd;
GDate *date = NULL;
gint32 finger; gint32 finger;
gchar *username; gchar *username;
/* Try to parse information from the string. */ /* Try to parse information from the string. */
@@ -543,7 +536,6 @@ list_msg_cb (FpiDeviceSynaptics *self,
date = g_date_new (); date = g_date_new ();
fp_print_set_enroll_date (print, date); fp_print_set_enroll_date (print, date);
g_date_free (date);
copy[14] = '\0'; copy[14] = '\0';
finger = g_ascii_strtoll (copy + 13, NULL, 16); finger = g_ascii_strtoll (copy + 13, NULL, 16);
@@ -582,6 +574,22 @@ list (FpDevice *device)
synaptics_sensor_cmd (self, 0, BMKT_CMD_GET_TEMPLATE_RECORDS, NULL, 0, list_msg_cb); synaptics_sensor_cmd (self, 0, BMKT_CMD_GET_TEMPLATE_RECORDS, NULL, 0, list_msg_cb);
} }
static void
verify_complete_after_finger_removal (FpiDeviceSynaptics *self)
{
FpDevice *device = FP_DEVICE (self);
if (self->finger_on_sensor)
{
fp_dbg ("delaying verify report until after finger removal!");
self->cmd_complete_on_removal = TRUE;
}
else
{
fpi_device_verify_complete (device, NULL);
}
}
static void static void
verify_msg_cb (FpiDeviceSynaptics *self, verify_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp, bmkt_response_t *resp,
@@ -592,16 +600,13 @@ verify_msg_cb (FpiDeviceSynaptics *self,
if (error) if (error)
{ {
fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error); fpi_device_verify_complete (device, error);
return; return;
} }
if (resp == NULL && self->cmd_complete_on_removal) if (resp == NULL && self->cmd_complete_on_removal)
{ {
fpi_device_verify_complete (device, fpi_device_verify_complete (device, NULL);
GPOINTER_TO_INT (self->cmd_complete_data),
NULL,
error);
return; return;
} }
@@ -620,39 +625,40 @@ verify_msg_cb (FpiDeviceSynaptics *self,
break; break;
case BMKT_RSP_VERIFY_FAIL: case BMKT_RSP_VERIFY_FAIL:
if(resp->result == BMKT_SENSOR_STIMULUS_ERROR) if (resp->result == BMKT_SENSOR_STIMULUS_ERROR)
{ {
fp_dbg ("delaying retry error until after finger removal!"); fp_info ("Match error occurred");
self->cmd_complete_on_removal = TRUE; fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL,
self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_ERROR); fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
self->cmd_complete_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL); verify_complete_after_finger_removal (self);
} }
else if (resp->result == BMKT_FP_NO_MATCH) else if (resp->result == BMKT_FP_NO_MATCH)
{ {
fp_dbg ("delaying match failure until after finger removal!"); fp_info ("Print didn't match");
self->cmd_complete_on_removal = TRUE; fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, error);
self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_FAIL); verify_complete_after_finger_removal (self);
self->cmd_complete_error = NULL;
} }
else if (BMKT_FP_DATABASE_NO_RECORD_EXISTS) else if (resp->result == BMKT_FP_DATABASE_NO_RECORD_EXISTS)
{ {
fp_info ("Print is not in database"); fp_info ("Print is not in database");
fpi_device_verify_complete (device, fpi_device_verify_complete (device,
FPI_MATCH_ERROR,
NULL,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND)); fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
} }
else else
{ {
fp_warn ("Verify has failed: %d", resp->result); fp_warn ("Verify has failed: %d", resp->result);
fpi_device_verify_complete (device, FPI_MATCH_FAIL, NULL, NULL); fpi_device_verify_complete (device,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Unexpected result from device %d",
resp->result));
} }
break; break;
case BMKT_RSP_VERIFY_OK: case BMKT_RSP_VERIFY_OK:
fp_info ("Verify was successful! for user: %s finger: %d score: %f", fp_info ("Verify was successful! for user: %s finger: %d score: %f",
verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result); verify_resp->user_id, verify_resp->finger_id, verify_resp->match_result);
fpi_device_verify_complete (device, FPI_MATCH_SUCCESS, NULL, NULL); fpi_device_verify_report (device, FPI_MATCH_SUCCESS, NULL, NULL);
fpi_device_verify_complete (device, NULL);
break; break;
} }
} }
@@ -675,8 +681,6 @@ verify (FpDevice *device)
if (!parse_print_data (data, &finger, &user_id, &user_id_len)) if (!parse_print_data (data, &finger, &user_id, &user_id_len))
{ {
fpi_device_verify_complete (device, fpi_device_verify_complete (device,
FPI_MATCH_ERROR,
NULL,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID)); fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
return; return;
} }
-2
View File
@@ -110,8 +110,6 @@ struct _FpiDeviceSynaptics
FpiSsm *cmd_ssm; FpiSsm *cmd_ssm;
FpiUsbTransfer *cmd_pending_transfer; FpiUsbTransfer *cmd_pending_transfer;
gboolean cmd_complete_on_removal; gboolean cmd_complete_on_removal;
GError *cmd_complete_error;
void *cmd_complete_data;
bmkt_sensor_version_t mis_version; bmkt_sensor_version_t mis_version;
+13 -4
View File
@@ -902,8 +902,10 @@ enroll_start_sm_cb_msg28 (FpDevice *dev,
FpiSsm *ssm = user_data; FpiSsm *ssm = user_data;
if (error) if (error)
{
fpi_ssm_mark_failed (ssm, error); fpi_ssm_mark_failed (ssm, error);
if (type != READ_MSG_RESPONSE) }
else if (type != READ_MSG_RESPONSE)
{ {
fp_err ("expected response, got %d seq=%x", type, seq); fp_err ("expected response, got %d seq=%x", type, seq);
fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO, fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -1225,7 +1227,6 @@ enroll (FpDevice *dev)
typedef struct typedef struct
{ {
FpiMatchResult res;
GError *error; GError *error;
} VerifyStopData; } VerifyStopData;
@@ -1244,7 +1245,12 @@ verify_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
if (error) if (error)
fp_warn ("Error deinitializing: %s", error->message); fp_warn ("Error deinitializing: %s", error->message);
fpi_device_verify_complete (dev, data->res, NULL, data->error); if (data->error)
fpi_device_verify_complete (dev, data->error);
else
fpi_device_verify_complete (dev, g_steal_pointer (&error));
g_error_free (error);
} }
static void static void
@@ -1253,7 +1259,10 @@ do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error)
VerifyStopData *data = g_new0 (VerifyStopData, 1); VerifyStopData *data = g_new0 (VerifyStopData, 1);
FpiSsm *ssm = deinitsm_new (dev, data); FpiSsm *ssm = deinitsm_new (dev, data);
data->res = res; /* Report the error immediately if possible, otherwise delay it. */
if (!error && error->domain != FP_DEVICE_RETRY)
fpi_device_verify_report (dev, res, NULL, error);
else
data->error = error; data->error = error;
fpi_ssm_start (ssm, verify_stop_deinit_cb); fpi_ssm_start (ssm, verify_stop_deinit_cb);
+1
View File
@@ -21,6 +21,7 @@
#pragma once #pragma once
#include "fpi-compat.h"
#include "fpi-assembling.h" #include "fpi-assembling.h"
#include "fpi-device.h" #include "fpi-device.h"
#include "fpi-image-device.h" #include "fpi-image-device.h"
+3 -6
View File
@@ -136,8 +136,7 @@ usb_device_added_cb (FpContext *self, GUsbDevice *device, GUsbContext *usb_ctx)
for (i = 0; i < priv->drivers->len; i++) for (i = 0; i < priv->drivers->len; i++)
{ {
GType driver = g_array_index (priv->drivers, GType, i); GType driver = g_array_index (priv->drivers, GType, i);
g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (type_class);
const FpIdEntry *entry; const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_USB) if (cls->type != FP_DEVICE_TYPE_USB)
@@ -288,8 +287,7 @@ fp_context_init (FpContext *self)
for (i = 0; i < priv->drivers->len;) for (i = 0; i < priv->drivers->len;)
{ {
GType driver = g_array_index (priv->drivers, GType, i); GType driver = g_array_index (priv->drivers, GType, i);
g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (type_class);
if (!is_driver_allowed (cls->id)) if (!is_driver_allowed (cls->id))
g_array_remove_index (priv->drivers, i); g_array_remove_index (priv->drivers, i);
@@ -363,8 +361,7 @@ fp_context_enumerate (FpContext *context)
for (i = 0; i < priv->drivers->len; i++) for (i = 0; i < priv->drivers->len; i++)
{ {
GType driver = g_array_index (priv->drivers, GType, i); GType driver = g_array_index (priv->drivers, GType, i);
g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (type_class);
const FpIdEntry *entry; const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_VIRTUAL) if (cls->type != FP_DEVICE_TYPE_VIRTUAL)
+17
View File
@@ -63,3 +63,20 @@ typedef struct
} FpEnrollData; } FpEnrollData;
void enroll_data_free (FpEnrollData *enroll_data); void enroll_data_free (FpEnrollData *enroll_data);
typedef struct
{
FpPrint *enrolled_print; /* verify */
GPtrArray *gallery; /* identify */
gboolean result_reported;
FpPrint *match;
FpPrint *print;
GError *error;
FpMatchCb match_cb;
gpointer match_data;
GDestroyNotify match_destroy;
} FpMatchData;
void match_data_free (FpMatchData *match_data);
+61 -10
View File
@@ -775,6 +775,7 @@ fp_device_enroll (FpDevice *device,
data->print = g_object_ref_sink (template_print); data->print = g_object_ref_sink (template_print);
data->enroll_progress_cb = progress_cb; data->enroll_progress_cb = progress_cb;
data->enroll_progress_data = progress_data; data->enroll_progress_data = progress_data;
data->enroll_progress_destroy = progress_destroy;
// Attach the progress data as task data so that it is destroyed // Attach the progress data as task data so that it is destroyed
g_task_set_task_data (priv->current_task, data, (GDestroyNotify) enroll_data_free); g_task_set_task_data (priv->current_task, data, (GDestroyNotify) enroll_data_free);
@@ -808,10 +809,13 @@ fp_device_enroll_finish (FpDevice *device,
* @device: a #FpDevice * @device: a #FpDevice
* @enrolled_print: a #FpPrint to verify * @enrolled_print: a #FpPrint to verify
* @cancellable: (nullable): a #GCancellable, or %NULL * @cancellable: (nullable): a #GCancellable, or %NULL
* @match_cb: (nullable) (scope notified): match reporting callback
* @match_data: (closure match_cb): user data for @match_cb
* @match_destroy: (destroy match_data): Destroy notify for @match_data
* @callback: the function to call on completion * @callback: the function to call on completion
* @user_data: the data to pass to @callback * @user_data: the data to pass to @callback
* *
* Start an asynchronous operation to close the device. The callback will * Start an asynchronous operation to verify a print. The callback will
* be called once the operation has finished. Retrieve the result with * be called once the operation has finished. Retrieve the result with
* fp_device_verify_finish(). * fp_device_verify_finish().
*/ */
@@ -819,11 +823,15 @@ void
fp_device_verify (FpDevice *device, fp_device_verify (FpDevice *device,
FpPrint *enrolled_print, FpPrint *enrolled_print,
GCancellable *cancellable, GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
GDestroyNotify match_destroy,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
g_autoptr(GTask) task = NULL; g_autoptr(GTask) task = NULL;
FpDevicePrivate *priv = fp_device_get_instance_private (device); FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data;
task = g_task_new (device, cancellable, callback, user_data); task = g_task_new (device, cancellable, callback, user_data);
if (g_task_return_error_if_cancelled (task)) if (g_task_return_error_if_cancelled (task))
@@ -847,9 +855,14 @@ fp_device_verify (FpDevice *device,
priv->current_task = g_steal_pointer (&task); priv->current_task = g_steal_pointer (&task);
maybe_cancel_on_cancelled (device, cancellable); maybe_cancel_on_cancelled (device, cancellable);
g_task_set_task_data (priv->current_task, data = g_new0 (FpMatchData, 1);
g_object_ref (enrolled_print), data->enrolled_print = g_object_ref (enrolled_print);
g_object_unref); data->match_cb = match_cb;
data->match_data = match_data;
data->match_destroy = match_destroy;
// Attach the match data as task data so that it is destroyed
g_task_set_task_data (priv->current_task, data, (GDestroyNotify) match_data_free);
FP_DEVICE_GET_CLASS (device)->verify (device); FP_DEVICE_GET_CLASS (device)->verify (device);
} }
@@ -885,7 +898,11 @@ fp_device_verify_finish (FpDevice *device,
if (print) if (print)
{ {
*print = g_object_get_data (G_OBJECT (result), "print"); FpMatchData *data;
data = g_task_get_task_data (G_TASK (result));
*print = data->print;
if (*print) if (*print)
g_object_ref (*print); g_object_ref (*print);
} }
@@ -901,6 +918,9 @@ fp_device_verify_finish (FpDevice *device,
* @device: a #FpDevice * @device: a #FpDevice
* @prints: (element-type FpPrint) (transfer none): #GPtrArray of #FpPrint * @prints: (element-type FpPrint) (transfer none): #GPtrArray of #FpPrint
* @cancellable: (nullable): a #GCancellable, or %NULL * @cancellable: (nullable): a #GCancellable, or %NULL
* @match_cb: (nullable) (scope notified): match reporting callback
* @match_data: (closure match_cb): user data for @match_cb
* @match_destroy: (destroy match_data): Destroy notify for @match_data
* @callback: the function to call on completion * @callback: the function to call on completion
* @user_data: the data to pass to @callback * @user_data: the data to pass to @callback
* *
@@ -912,11 +932,15 @@ void
fp_device_identify (FpDevice *device, fp_device_identify (FpDevice *device,
GPtrArray *prints, GPtrArray *prints,
GCancellable *cancellable, GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
GDestroyNotify match_destroy,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
g_autoptr(GTask) task = NULL; g_autoptr(GTask) task = NULL;
FpDevicePrivate *priv = fp_device_get_instance_private (device); FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data;
task = g_task_new (device, cancellable, callback, user_data); task = g_task_new (device, cancellable, callback, user_data);
if (g_task_return_error_if_cancelled (task)) if (g_task_return_error_if_cancelled (task))
@@ -940,9 +964,14 @@ fp_device_identify (FpDevice *device,
priv->current_task = g_steal_pointer (&task); priv->current_task = g_steal_pointer (&task);
maybe_cancel_on_cancelled (device, cancellable); maybe_cancel_on_cancelled (device, cancellable);
g_task_set_task_data (priv->current_task, data = g_new0 (FpMatchData, 1);
g_ptr_array_ref (prints), data->gallery = g_ptr_array_ref (prints);
(GDestroyNotify) g_ptr_array_unref); data->match_cb = match_cb;
data->match_data = match_data;
data->match_destroy = match_destroy;
// Attach the match data as task data so that it is destroyed
g_task_set_task_data (priv->current_task, data, (GDestroyNotify) match_data_free);
FP_DEVICE_GET_CLASS (device)->identify (device); FP_DEVICE_GET_CLASS (device)->identify (device);
} }
@@ -973,15 +1002,19 @@ fp_device_identify_finish (FpDevice *device,
FpPrint **print, FpPrint **print,
GError **error) GError **error)
{ {
FpMatchData *data;
data = g_task_get_task_data (G_TASK (result));
if (print) if (print)
{ {
*print = g_object_get_data (G_OBJECT (result), "print"); *print = data->print;
if (*print) if (*print)
g_object_ref (*print); g_object_ref (*print);
} }
if (match) if (match)
{ {
*match = g_object_get_data (G_OBJECT (result), "match"); *match = data->match;
if (*match) if (*match)
g_object_ref (*match); g_object_ref (*match);
} }
@@ -1180,6 +1213,14 @@ fp_device_list_prints (FpDevice *device,
return; return;
} }
if (!fp_device_has_storage (device))
{
g_task_return_error (task,
fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
"Device has no storage"));
return;
}
priv->current_action = FPI_DEVICE_ACTION_LIST; priv->current_action = FPI_DEVICE_ACTION_LIST;
priv->current_task = g_steal_pointer (&task); priv->current_task = g_steal_pointer (&task);
maybe_cancel_on_cancelled (device, cancellable); maybe_cancel_on_cancelled (device, cancellable);
@@ -1308,6 +1349,8 @@ fp_device_enroll_sync (FpDevice *device,
* @device: a #FpDevice * @device: a #FpDevice
* @enrolled_print: a #FpPrint to verify * @enrolled_print: a #FpPrint to verify
* @cancellable: (nullable): a #GCancellable, or %NULL * @cancellable: (nullable): a #GCancellable, or %NULL
* @match_cb: (nullable) (scope call): match reporting callback
* @match_data: (closure match_cb): user data for @match_cb
* @match: (out): Whether the user presented the correct finger * @match: (out): Whether the user presented the correct finger
* @print: (out) (transfer full) (nullable): Location to store the scanned print, or %NULL to ignore * @print: (out) (transfer full) (nullable): Location to store the scanned print, or %NULL to ignore
* @error: Return location for errors, or %NULL to ignore * @error: Return location for errors, or %NULL to ignore
@@ -1320,6 +1363,8 @@ gboolean
fp_device_verify_sync (FpDevice *device, fp_device_verify_sync (FpDevice *device,
FpPrint *enrolled_print, FpPrint *enrolled_print,
GCancellable *cancellable, GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
gboolean *match, gboolean *match,
FpPrint **print, FpPrint **print,
GError **error) GError **error)
@@ -1331,6 +1376,7 @@ fp_device_verify_sync (FpDevice *device,
fp_device_verify (device, fp_device_verify (device,
enrolled_print, enrolled_print,
cancellable, cancellable,
match_cb, match_data, NULL,
async_result_ready, &task); async_result_ready, &task);
while (!task) while (!task)
g_main_context_iteration (NULL, TRUE); g_main_context_iteration (NULL, TRUE);
@@ -1343,6 +1389,8 @@ fp_device_verify_sync (FpDevice *device,
* @device: a #FpDevice * @device: a #FpDevice
* @prints: (element-type FpPrint) (transfer none): #GPtrArray of #FpPrint * @prints: (element-type FpPrint) (transfer none): #GPtrArray of #FpPrint
* @cancellable: (nullable): a #GCancellable, or %NULL * @cancellable: (nullable): a #GCancellable, or %NULL
* @match_cb: (nullable) (scope call): match reporting callback
* @match_data: (closure match_cb): user data for @match_cb
* @match: (out) (transfer full) (nullable): Location for the matched #FpPrint, or %NULL * @match: (out) (transfer full) (nullable): Location for the matched #FpPrint, or %NULL
* @print: (out) (transfer full) (nullable): Location for the new #FpPrint, or %NULL * @print: (out) (transfer full) (nullable): Location for the new #FpPrint, or %NULL
* @error: Return location for errors, or %NULL to ignore * @error: Return location for errors, or %NULL to ignore
@@ -1355,6 +1403,8 @@ gboolean
fp_device_identify_sync (FpDevice *device, fp_device_identify_sync (FpDevice *device,
GPtrArray *prints, GPtrArray *prints,
GCancellable *cancellable, GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
FpPrint **match, FpPrint **match,
FpPrint **print, FpPrint **print,
GError **error) GError **error)
@@ -1366,6 +1416,7 @@ fp_device_identify_sync (FpDevice *device,
fp_device_identify (device, fp_device_identify (device,
prints, prints,
cancellable, cancellable,
match_cb, match_data, NULL,
async_result_ready, &task); async_result_ready, &task);
while (!task) while (!task)
g_main_context_iteration (NULL, TRUE); g_main_context_iteration (NULL, TRUE);
+47
View File
@@ -125,6 +125,43 @@ typedef void (*FpEnrollProgress) (FpDevice *device,
gpointer user_data, gpointer user_data,
GError *error); GError *error);
/**
* FpMatchCb:
* @device: a #FpDevice
* @match: (nullable) (transfer none): The matching print if any matched @print
* @print: (nullable) (transfer none): The newly scanned print
* @user_data: (nullable) (transfer none): User provided data
* @error: (nullable) (transfer none): #GError or %NULL
*
* Report the result of a match (identify or verify) operation.
*
* If @match is non-%NULL, then it is set to the matching #FpPrint as passed
* to the match operation. In this case @error will always be %NULL.
*
* If @error is not %NULL then its domain is guaranteed to be
* %FP_DEVICE_RETRY. All other error conditions will not be reported using
* this callback. If such an error occurs before a match/no-match decision
* can be made, then this callback will not be called. Should an error
* happen afterwards, then you will get a match report through this callback
* and an error when the operation finishes.
*
* If @match and @error are %NULL, then a finger was presented but it did not
* match any known print.
*
* @print represents the newly scanned print. The driver may or may not
* provide this information. Image based devices will provide it and it
* allows access to the raw data.
*
* This callback exists because it makes sense for drivers to wait e.g. on
* finger removal before completing the match operation. However, the
* success/failure can often be reported at an earlier time, and there is
* no need to make the user wait.
*/
typedef void (*FpMatchCb) (FpDevice *device,
FpPrint *match,
FpPrint *print,
gpointer user_data,
GError *error);
const gchar *fp_device_get_driver (FpDevice *device); const gchar *fp_device_get_driver (FpDevice *device);
const gchar *fp_device_get_device_id (FpDevice *device); const gchar *fp_device_get_device_id (FpDevice *device);
@@ -160,12 +197,18 @@ void fp_device_enroll (FpDevice *device,
void fp_device_verify (FpDevice *device, void fp_device_verify (FpDevice *device,
FpPrint *enrolled_print, FpPrint *enrolled_print,
GCancellable *cancellable, GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
GDestroyNotify match_destroy,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data); gpointer user_data);
void fp_device_identify (FpDevice *device, void fp_device_identify (FpDevice *device,
GPtrArray *prints, GPtrArray *prints,
GCancellable *cancellable, GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
GDestroyNotify match_destroy,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data); gpointer user_data);
@@ -231,12 +274,16 @@ FpPrint * fp_device_enroll_sync (FpDevice *device,
gboolean fp_device_verify_sync (FpDevice *device, gboolean fp_device_verify_sync (FpDevice *device,
FpPrint *enrolled_print, FpPrint *enrolled_print,
GCancellable *cancellable, GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
gboolean *match, gboolean *match,
FpPrint **print, FpPrint **print,
GError **error); GError **error);
gboolean fp_device_identify_sync (FpDevice *device, gboolean fp_device_identify_sync (FpDevice *device,
GPtrArray *prints, GPtrArray *prints,
GCancellable *cancellable, GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
FpPrint **match, FpPrint **match,
FpPrint **print, FpPrint **print,
GError **error); GError **error);
+2 -3
View File
@@ -21,6 +21,7 @@
#define FP_COMPONENT "print" #define FP_COMPONENT "print"
#include "fp-print-private.h" #include "fp-print-private.h"
#include "fpi-compat.h"
#include "fpi-log.h" #include "fpi-log.h"
/** /**
@@ -752,8 +753,8 @@ fp_print_deserialize (const guchar *data,
g_autoptr(GVariant) raw_value = NULL; g_autoptr(GVariant) raw_value = NULL;
g_autoptr(GVariant) value = NULL; g_autoptr(GVariant) value = NULL;
g_autoptr(GVariant) print_data = NULL; g_autoptr(GVariant) print_data = NULL;
g_autoptr(GDate) date = NULL;
guchar *aligned_data = NULL; guchar *aligned_data = NULL;
GDate *date = NULL;
guint8 finger_int8; guint8 finger_int8;
FpFinger finger; FpFinger finger;
g_autofree gchar *username = NULL; g_autofree gchar *username = NULL;
@@ -881,8 +882,6 @@ fp_print_deserialize (const guchar *data,
"enroll_date", date, "enroll_date", date,
NULL); NULL);
g_date_free (date);
return g_steal_pointer (&result); return g_steal_pointer (&result);
invalid_format: invalid_format:
+39
View File
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <glib-object.h>
#if !GLIB_CHECK_VERSION (2, 57, 0)
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GTypeClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GEnumClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GParamSpec, g_param_spec_unref);
#else
/* Re-define G_SOURCE_FUNC as we are technically not allowed to use it with
* the version we depend on currently. */
#undef G_SOURCE_FUNC
#endif
#define G_SOURCE_FUNC(f) ((GSourceFunc) (void (*)(void))(f))
#if !GLIB_CHECK_VERSION (2, 63, 3)
typedef struct _FpDeviceClass FpDeviceClass;
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpDeviceClass, g_type_class_unref);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (GDate, g_date_free);
#endif
+1
View File
@@ -20,6 +20,7 @@
#include <gusb.h> #include <gusb.h>
#include "fp-context.h" #include "fp-context.h"
#include "fpi-compat.h"
/** /**
* fpi_get_driver_types: * fpi_get_driver_types:
+242 -48
View File
@@ -420,6 +420,23 @@ enroll_data_free (FpEnrollData *data)
g_free (data); g_free (data);
} }
void
match_data_free (FpMatchData *data)
{
g_clear_object (&data->print);
g_clear_object (&data->match);
g_clear_error (&data->error);
if (data->match_destroy)
data->match_destroy (data->match_data);
data->match_data = NULL;
g_clear_object (&data->enrolled_print);
g_clear_pointer (&data->gallery, g_ptr_array_unref);
g_free (data);
}
/** /**
* fpi_device_get_enroll_data: * fpi_device_get_enroll_data:
* @device: The #FpDevice * @device: The #FpDevice
@@ -476,12 +493,16 @@ fpi_device_get_verify_data (FpDevice *device,
FpPrint **print) FpPrint **print)
{ {
FpDevicePrivate *priv = fp_device_get_instance_private (device); FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data;
g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY); g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY);
data = g_task_get_task_data (priv->current_task);
g_assert (data);
if (print) if (print)
*print = g_task_get_task_data (priv->current_task); *print = data->enrolled_print;
} }
/** /**
@@ -496,12 +517,16 @@ fpi_device_get_identify_data (FpDevice *device,
GPtrArray **prints) GPtrArray **prints)
{ {
FpDevicePrivate *priv = fp_device_get_instance_private (device); FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data;
g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY); g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY);
data = g_task_get_task_data (priv->current_task);
g_assert (data);
if (prints) if (prints)
*prints = g_task_get_task_data (priv->current_task); *prints = data->gallery;
} }
/** /**
@@ -596,11 +621,11 @@ fpi_device_action_error (FpDevice *device,
break; break;
case FPI_DEVICE_ACTION_VERIFY: case FPI_DEVICE_ACTION_VERIFY:
fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error); fpi_device_verify_complete (device, error);
break; break;
case FPI_DEVICE_ACTION_IDENTIFY: case FPI_DEVICE_ACTION_IDENTIFY:
fpi_device_identify_complete (device, NULL, NULL, error); fpi_device_identify_complete (device, error);
break; break;
case FPI_DEVICE_ACTION_CAPTURE: case FPI_DEVICE_ACTION_CAPTURE:
@@ -826,8 +851,6 @@ fpi_device_close_complete (FpDevice *device, GError *error)
g_debug ("Device reported close completion"); g_debug ("Device reported close completion");
clear_device_cancel_action (device); clear_device_cancel_action (device);
priv->is_open = FALSE;
g_object_notify (G_OBJECT (device), "open");
switch (priv->type) switch (priv->type)
{ {
@@ -852,10 +875,16 @@ fpi_device_close_complete (FpDevice *device, GError *error)
} }
if (!error) if (!error)
{
priv->is_open = FALSE;
g_object_notify (G_OBJECT (device), "open");
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
GUINT_TO_POINTER (TRUE)); GUINT_TO_POINTER (TRUE));
}
else else
{
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
}
} }
/** /**
@@ -907,64 +936,68 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
/** /**
* fpi_device_verify_complete: * fpi_device_verify_complete:
* @device: The #FpDevice * @device: The #FpDevice
* @result: The #FpiMatchResult of the operation
* @print: The scanned #FpPrint
* @error: A #GError if result is %FPI_MATCH_ERROR * @error: A #GError if result is %FPI_MATCH_ERROR
* *
* Finish an ongoing verify operation. The returned print should be * Finish an ongoing verify operation. The returned print should be
* representing the new scan and not the one passed for verification. * representing the new scan and not the one passed for verification.
*
* Note that @error should only be set for actual errors. In the case
* of retry errors, report these using fpi_device_verify_report()
* and then call this function without any error argument.
*/ */
void void
fpi_device_verify_complete (FpDevice *device, fpi_device_verify_complete (FpDevice *device,
FpiMatchResult result,
FpPrint *print,
GError *error) GError *error)
{ {
FpDevicePrivate *priv = fp_device_get_instance_private (device); FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data;
g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY); g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY);
g_debug ("Device reported verify completion"); g_debug ("Device reported verify completion");
clear_device_cancel_action (device); data = g_task_get_task_data (priv->current_task);
g_object_set_data_full (G_OBJECT (priv->current_task), clear_device_cancel_action (device);
"print",
print,
g_object_unref);
if (!error) if (!error)
{ {
if (result != FPI_MATCH_ERROR) if (!data->result_reported)
{
g_warning ("Driver reported successful verify complete but did not report the result earlier. Reporting error instead");
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR,
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
}
else if (data->error)
{
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, g_steal_pointer (&data->error));
}
else
{ {
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT, fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT,
GINT_TO_POINTER (result)); GINT_TO_POINTER (data->match != NULL ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL));
}
else
{
g_warning ("Driver did not provide an error for a failed verify operation!");
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Driver failed to provide an error!");
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
} }
} }
else else
{ {
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); /* Replace a retry error with a general error, this is a driver bug. */
if (result != FPI_MATCH_ERROR) if (error->domain == FP_DEVICE_RETRY)
{ {
g_warning ("Driver passed an error but also provided a match result, returning error!"); g_warning ("Driver reported a retry error to fpi_device_verify_complete. "
g_object_unref (print); "This is not permissible and needs to be reported using "
"fpi_device_verify_report, reporting general verification "
"failure instead.");
g_clear_error (&error);
error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL);
} }
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
} }
} }
/** /**
* fpi_device_identify_complete: * fpi_device_identify_complete:
* @device: The #FpDevice * @device: The #FpDevice
* @match: The matching #FpPrint from the passed gallery, or %NULL if none matched
* @print: The scanned #FpPrint, may be %NULL
* @error: The #GError or %NULL on success * @error: The #GError or %NULL on success
* *
* Finish an ongoing identify operation. The match that was identified is * Finish an ongoing identify operation. The match that was identified is
@@ -973,41 +1006,51 @@ fpi_device_verify_complete (FpDevice *device,
*/ */
void void
fpi_device_identify_complete (FpDevice *device, fpi_device_identify_complete (FpDevice *device,
FpPrint *match,
FpPrint *print,
GError *error) GError *error)
{ {
FpDevicePrivate *priv = fp_device_get_instance_private (device); FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data;
g_return_if_fail (FP_IS_DEVICE (device)); g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY); g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY);
g_debug ("Device reported identify completion"); g_debug ("Device reported identify completion");
data = g_task_get_task_data (priv->current_task);
clear_device_cancel_action (device); clear_device_cancel_action (device);
g_object_set_data_full (G_OBJECT (priv->current_task),
"print",
print,
g_object_unref);
g_object_set_data_full (G_OBJECT (priv->current_task),
"match",
match,
g_object_unref);
if (!error) if (!error)
{ {
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL, if (!data->result_reported)
GUINT_TO_POINTER (TRUE)); {
g_warning ("Driver reported successful identify complete but did not report the result earlier. Reporting error instead");
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR,
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
}
else if (data->error)
{
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, g_steal_pointer (&data->error));
} }
else else
{ {
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error); fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT, GINT_TO_POINTER (TRUE));
if (match)
{
g_warning ("Driver passed an error but also provided a match result, returning error!");
g_clear_object (&match);
} }
} }
else
{
/* Replace a retry error with a general error, this is a driver bug. */
if (error->domain == FP_DEVICE_RETRY)
{
g_warning ("Driver reported a retry error to fpi_device_identify_complete. "
"This is not permissible and needs to be reported using "
"fpi_device_identify_report, reporting general identification "
"failure instead.");
g_clear_error (&error);
error = fpi_device_error_new (FP_DEVICE_ERROR_GENERAL);
}
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
}
} }
@@ -1134,7 +1177,7 @@ fpi_device_list_complete (FpDevice *device,
* fpi_device_enroll_progress: * fpi_device_enroll_progress:
* @device: The #FpDevice * @device: The #FpDevice
* @completed_stages: The number of stages that are completed at this point * @completed_stages: The number of stages that are completed at this point
* @print: (transfer full): The #FpPrint for the newly completed stage or %NULL on failure * @print: (transfer floating): The #FpPrint for the newly completed stage or %NULL on failure
* @error: (transfer full): The #GError or %NULL on success * @error: (transfer full): The #GError or %NULL on success
* *
* Notify about the progress of the enroll operation. This is important for UI interaction. * Notify about the progress of the enroll operation. This is important for UI interaction.
@@ -1155,6 +1198,9 @@ fpi_device_enroll_progress (FpDevice *device,
g_debug ("Device reported enroll progress, reported %i of %i have been completed", completed_stages, priv->nr_enroll_stages); g_debug ("Device reported enroll progress, reported %i of %i have been completed", completed_stages, priv->nr_enroll_stages);
if (print)
g_object_ref_sink (print);
if (error && print) if (error && print)
{ {
g_warning ("Driver passed an error and also provided a print, returning error!"); g_warning ("Driver passed an error and also provided a print, returning error!");
@@ -1175,3 +1221,151 @@ fpi_device_enroll_progress (FpDevice *device,
g_clear_error (&error); g_clear_error (&error);
g_clear_object (&print); g_clear_object (&print);
} }
/**
* fpi_device_verify_report:
* @device: The #FpDevice
* @result: The #FpiMatchResult of the operation
* @print: (transfer floating) The scanned #FpPrint
* @error: A #GError if result is %FPI_MATCH_ERROR
*
* Report the result of a verify operation. Note that the passed @error must be
* a retry error with the %FP_DEVICE_RETRY domain. For all other error cases,
* the error should passed to fpi_device_verify_complete().
*/
void
fpi_device_verify_report (FpDevice *device,
FpiMatchResult result,
FpPrint *print,
GError *error)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data = g_task_get_task_data (priv->current_task);
gboolean call_cb = TRUE;
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY);
g_return_if_fail (data->result_reported == FALSE);
data->result_reported = TRUE;
g_debug ("Device reported verify result");
if (print)
print = g_object_ref_sink (print);
if (error || result == FPI_MATCH_ERROR)
{
if (result != FPI_MATCH_ERROR)
g_warning ("Driver reported an error code without setting match result to error!");
if (error == NULL)
{
g_warning ("Driver reported an error without specifying a retry code, assuming general retry error!");
error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
}
if (print)
{
g_warning ("Driver reported a print together with an error!");
g_clear_object (&print);
}
data->error = error;
if (error->domain != FP_DEVICE_RETRY)
{
g_warning ("Driver reported a verify error that was not in the retry domain, delaying report!");
call_cb = FALSE;
}
}
else
{
if (result == FPI_MATCH_SUCCESS)
{
fpi_device_get_verify_data (device, &data->match);
g_object_ref (data->match);
}
data->print = g_steal_pointer (&print);
}
if (call_cb && data->match_cb)
data->match_cb (device, data->match, data->print, data->match_data, data->error);
}
/**
* fpi_device_identify_report:
* @device: The #FpDevice
* @match: (transfer none): The #FpPrint from the gallery that matched
* @print: (transfer floating): The scanned #FpPrint
* @error: A #GError if result is %FPI_MATCH_ERROR
*
* Report the result of a identify operation. Note that the passed @error must be
* a retry error with the %FP_DEVICE_RETRY domain. For all other error cases,
* the error should passed to fpi_device_identify_complete().
*/
void
fpi_device_identify_report (FpDevice *device,
FpPrint *match,
FpPrint *print,
GError *error)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data = g_task_get_task_data (priv->current_task);
gboolean call_cb = TRUE;
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY);
g_return_if_fail (data->result_reported == FALSE);
data->result_reported = TRUE;
if (match)
g_object_ref (match);
if (print)
print = g_object_ref_sink (print);
if (match && !g_ptr_array_find (data->gallery, match, NULL))
{
g_warning ("Driver reported a match to a print that was not in the gallery, ignoring match.");
g_clear_object (&match);
}
g_debug ("Device reported identify result");
if (error)
{
if (match != NULL)
{
g_warning ("Driver reported an error code but also provided a match!");
g_clear_object (&match);
}
if (print)
{
g_warning ("Driver reported a print together with an error!");
g_clear_object (&print);
}
data->error = error;
if (error->domain != FP_DEVICE_RETRY)
{
g_warning ("Driver reported a verify error that was not in the retry domain, delaying report!");
call_cb = FALSE;
}
}
else
{
if (match)
data->match = g_steal_pointer (&match);
if (print)
data->print = g_steal_pointer (&print);
}
if (call_cb && data->match_cb)
data->match_cb (device, data->match, data->print, data->match_data, data->error);
}
+8 -4
View File
@@ -238,12 +238,8 @@ void fpi_device_enroll_complete (FpDevice *device,
FpPrint *print, FpPrint *print,
GError *error); GError *error);
void fpi_device_verify_complete (FpDevice *device, void fpi_device_verify_complete (FpDevice *device,
FpiMatchResult result,
FpPrint *print,
GError *error); GError *error);
void fpi_device_identify_complete (FpDevice *device, void fpi_device_identify_complete (FpDevice *device,
FpPrint *match,
FpPrint *print,
GError *error); GError *error);
void fpi_device_capture_complete (FpDevice *device, void fpi_device_capture_complete (FpDevice *device,
FpImage *image, FpImage *image,
@@ -258,5 +254,13 @@ void fpi_device_enroll_progress (FpDevice *device,
gint completed_stages, gint completed_stages,
FpPrint *print, FpPrint *print,
GError *error); GError *error);
void fpi_device_verify_report (FpDevice *device,
FpiMatchResult result,
FpPrint *print,
GError *error);
void fpi_device_identify_report (FpDevice *device,
FpPrint *match,
FpPrint *print,
GError *error);
G_END_DECLS G_END_DECLS
+42 -6
View File
@@ -210,7 +210,9 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
else else
result = FPI_MATCH_ERROR; result = FPI_MATCH_ERROR;
fpi_device_verify_complete (device, result, g_steal_pointer (&print), error); if (!error || error->domain == FP_DEVICE_RETRY)
fpi_device_verify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
fpi_device_verify_complete (device, error);
fpi_image_device_deactivate (self); fpi_image_device_deactivate (self);
} }
else if (action == FPI_DEVICE_ACTION_IDENTIFY) else if (action == FPI_DEVICE_ACTION_IDENTIFY)
@@ -226,12 +228,14 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS) if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS)
{ {
result = g_object_ref (template); result = template;
break; break;
} }
} }
fpi_device_identify_complete (device, result, g_steal_pointer (&print), error); if (!error || error->domain == FP_DEVICE_RETRY)
fpi_device_identify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
fpi_device_identify_complete (device, error);
fpi_image_device_deactivate (self); fpi_image_device_deactivate (self);
} }
else else
@@ -410,12 +414,30 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
priv->enroll_await_on_pending = TRUE; priv->enroll_await_on_pending = TRUE;
fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF); fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
} }
else if (action == FPI_DEVICE_ACTION_VERIFY)
{
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_verify_complete (FP_DEVICE (self), NULL);
}
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
{
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_identify_complete (FP_DEVICE (self), NULL);
}
else else
{ {
/* We abort the operation and let the surrounding code retry in the /* We abort the operation and let the surrounding code retry in the
* non-enroll case (this is identical to a session error). */ * non-enroll case (this is identical to a session error). */
g_debug ("Abort current operation due to retry (non-enroll case)"); g_debug ("Abort current operation due to retry (non-enroll case)");
priv->cancelling = TRUE;
fpi_image_device_deactivate (self); fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_action_error (FP_DEVICE (self), error); fpi_device_action_error (FP_DEVICE (self), error);
} }
} }
@@ -426,7 +448,9 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
* @error: The #GError to report * @error: The #GError to report
* *
* Report an error while interacting with the device. This effectively * Report an error while interacting with the device. This effectively
* aborts the current ongoing action. * aborts the current ongoing action. Note that doing so will result in
* the deactivation handler to be called and this function must not be
* used to report an error during deactivation.
*/ */
void void
fpi_image_device_session_error (FpImageDevice *self, GError *error) fpi_image_device_session_error (FpImageDevice *self, GError *error)
@@ -453,17 +477,29 @@ fpi_image_device_session_error (FpImageDevice *self, GError *error)
return; return;
} }
} }
else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
fpi_device_action_is_cancelled (FP_DEVICE (self)))
{
/* Ignore cancellation errors here, as we will explicitly deactivate
* anyway (or, may already have done so at this point).
*/
g_debug ("Driver reported a cancellation error, this is expected but not required. Ignoring.");
g_clear_error (&error);
return;
}
else if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE) else if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
{ {
g_warning ("Driver reported session error; translating to deactivation failure."); g_warning ("Driver reported session error while deactivating already, ignoring. This indicates a driver bug.");
fpi_image_device_deactivate_complete (self, error); g_clear_error (&error);
return; return;
} }
if (error->domain == FP_DEVICE_RETRY) if (error->domain == FP_DEVICE_RETRY)
g_warning ("Driver should report retries using fpi_image_device_retry_scan!"); g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
priv->cancelling = TRUE;
fpi_image_device_deactivate (self); fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
fpi_device_action_error (FP_DEVICE (self), error); fpi_device_action_error (FP_DEVICE (self), error);
} }
+1 -2
View File
@@ -38,8 +38,7 @@ insert_drivers (GList *list)
for (i = 0; i < drivers->len; i++) for (i = 0; i < drivers->len; i++)
{ {
GType driver = g_array_index (drivers, GType, i); GType driver = g_array_index (drivers, GType, i);
g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (type_class);
const FpIdEntry *entry; const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_USB) if (cls->type != FP_DEVICE_TYPE_USB)
+1 -2
View File
@@ -104,8 +104,7 @@ main (int argc, char **argv)
for (i = 0; i < drivers->len; i++) for (i = 0; i < drivers->len; i++)
{ {
GType driver = g_array_index (drivers, GType, i); GType driver = g_array_index (drivers, GType, i);
g_autoptr(GTypeClass) type_class = g_type_class_ref (driver); g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (type_class);
if (cls->type != FP_DEVICE_TYPE_USB) if (cls->type != FP_DEVICE_TYPE_USB)
continue; continue;
+8 -4
View File
@@ -177,7 +177,7 @@ other_sources = []
fp_enums = gnome.mkenums_simple('fp-enums', fp_enums = gnome.mkenums_simple('fp-enums',
sources: libfprint_public_headers, sources: libfprint_public_headers,
install_header: true, install_header: true,
install_dir: get_option('includedir') / meson.project_name(), install_dir: get_option('includedir') / versioned_libname,
) )
fp_enums_h = fp_enums[1] fp_enums_h = fp_enums[1]
@@ -209,6 +209,10 @@ deps = [
nss_dep, nss_dep,
] ]
# These are empty and only exist so that the include directories are created
# in the build tree. This silences a build time warning.
subdir('nbis/include')
subdir('nbis/libfprint-include')
deps += declare_dependency(include_directories: [ deps += declare_dependency(include_directories: [
root_inc, root_inc,
include_directories('nbis/include'), include_directories('nbis/include'),
@@ -248,7 +252,7 @@ libfprint_drivers = static_library('fprint-drivers',
mapfile = files('libfprint.ver') mapfile = files('libfprint.ver')
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0]) vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0])
libfprint = library('fprint', libfprint = library(versioned_libname.split('lib')[1],
sources: [ sources: [
fp_enums, fp_enums,
libfprint_sources, libfprint_sources,
@@ -272,7 +276,7 @@ libfprint_dep = declare_dependency(link_with: libfprint,
]) ])
install_headers(['fprint.h'] + libfprint_public_headers, install_headers(['fprint.h'] + libfprint_public_headers,
subdir: meson.project_name() subdir: versioned_libname
) )
libfprint_private_dep = declare_dependency( libfprint_private_dep = declare_dependency(
@@ -292,7 +296,7 @@ udev_rules = executable('fprint-list-udev-rules',
if get_option('udev_rules') if get_option('udev_rules')
custom_target('udev-rules', custom_target('udev-rules',
output: '60-fprint-autosuspend.rules', output: '60-@0@-autosuspend.rules'.format(versioned_libname),
capture: true, capture: true,
command: [ udev_rules ], command: [ udev_rules ],
install: true, install: true,
View File
+8 -8
View File
@@ -1,10 +1,10 @@
project('libfprint', [ 'c', 'cpp' ], project('libfprint', [ 'c', 'cpp' ],
version: '1.90.0', version: '1.90.1',
license: 'LGPLv2.1+', license: 'LGPLv2.1+',
default_options: [ default_options: [
'buildtype=debugoptimized', 'buildtype=debugoptimized',
'warning_level=1', 'warning_level=1',
'c_std=c99', 'c_std=gnu99',
], ],
meson_version: '>= 0.49.0') meson_version: '>= 0.49.0')
@@ -53,10 +53,9 @@ common_cflags = cc.get_supported_arguments([
'-DGLIB_VERSION_MIN_REQUIRED=' + glib_version_def, '-DGLIB_VERSION_MIN_REQUIRED=' + glib_version_def,
'-DGLIB_VERSION_MAX_ALLOWED=' + glib_version_def, '-DGLIB_VERSION_MAX_ALLOWED=' + glib_version_def,
'-D_GNU_SOURCE', '-D_GNU_SOURCE',
'-DG_LOG_DOMAIN="libfprint"', '-DG_LOG_DOMAIN="@0@"'.format(meson.project_name()),
]) ])
c_cflags = cc.get_supported_arguments([ c_cflags = cc.get_supported_arguments([
'-std=gnu99',
'-Wimplicit-function-declaration', '-Wimplicit-function-declaration',
'-Wmissing-prototypes', '-Wmissing-prototypes',
'-Wnested-externs', '-Wnested-externs',
@@ -75,11 +74,12 @@ soversion = 2
current = 0 current = 0
revision = 0 revision = 0
libversion = '@0@.@1@.@2@'.format(soversion, current, revision) libversion = '@0@.@1@.@2@'.format(soversion, current, revision)
versioned_libname = meson.project_name() + '-' + soversion.to_string()
# Dependencies # Dependencies
glib_dep = dependency('glib-2.0', version: '>=' + glib_min_version) glib_dep = dependency('glib-2.0', version: '>=' + glib_min_version)
gio_dep = dependency('gio-unix-2.0', version: '>=' + glib_min_version) gio_dep = dependency('gio-unix-2.0', version: '>=' + glib_min_version)
gusb_dep = dependency('gusb', version: '>= 0.3.0') gusb_dep = dependency('gusb', version: '>= 0.2.0')
mathlib_dep = cc.find_library('m', required: false) mathlib_dep = cc.find_library('m', required: false)
# The following dependencies are only used for tests # The following dependencies are only used for tests
@@ -208,10 +208,10 @@ subdir('tests')
pkgconfig = import('pkgconfig') pkgconfig = import('pkgconfig')
pkgconfig.generate( pkgconfig.generate(
name: meson.project_name(), name: versioned_libname,
description: 'Generic C API for fingerprint reader access', description: 'Generic C API for fingerprint reader access',
version: meson.project_version(), version: meson.project_version(),
libraries: libfprint, libraries: libfprint,
subdirs: meson.project_name(), subdirs: versioned_libname,
filebase: meson.project_name() + '@0@'.format(soversion), filebase: versioned_libname,
) )
+28 -5
View File
@@ -26,12 +26,35 @@ if get_option('introspection')
envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint')) envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint'))
if 'virtual_image' in drivers if 'virtual_image' in drivers
test('virtual-image', python3 = find_program('python3')
find_program('virtual-image.py'), unittest_inspector = find_program('unittest_inspector.py')
args: '--verbose', base_args = files('virtual-image.py')
env: envs, suite = []
r = run_command(unittest_inspector, files('virtual-image.py'))
unit_tests = r.stdout().strip().split('\n')
if r.returncode() == 0 and unit_tests.length() > 0
suite += 'virtual-image'
else
unit_tests = ['virtual-image']
endif
foreach ut: unit_tests
ut_suite = suite
ut_args = base_args
if unit_tests.length() > 1
ut_args += ut
ut_suite += ut.split('.')[0]
endif
test(ut,
python3,
args: ut_args,
suite: ut_suite,
depends: libfprint_typelib, depends: libfprint_typelib,
env: envs,
) )
endforeach
else else
test('virtual-image', test('virtual-image',
find_program('sh'), find_program('sh'),
@@ -43,7 +66,7 @@ if get_option('introspection')
driver_envs = envs driver_envs = envs
driver_envs.set('FP_DRIVERS_WHITELIST', driver_test) driver_envs.set('FP_DRIVERS_WHITELIST', driver_test)
if driver_test in drivers if driver_test in drivers and gusb_dep.version().version_compare('>= 0.3.0')
test(driver_test, test(driver_test,
find_program('umockdev-test.py'), find_program('umockdev-test.py'),
args: join_paths(meson.current_source_dir(), driver_test), args: join_paths(meson.current_source_dir(), driver_test),
+89 -19
View File
@@ -35,9 +35,15 @@ fpi_device_fake_probe (FpDevice *device)
FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device); FpDeviceClass *dev_class = FP_DEVICE_GET_CLASS (device);
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
fake_dev->last_called_function = fpi_device_fake_probe;
g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_PROBE); g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_PROBE);
fake_dev->last_called_function = fpi_device_fake_probe; if (fake_dev->return_action_error)
{
fpi_device_action_error (device, fake_dev->ret_error);
return;
}
fpi_device_probe_complete (device, dev_class->id, dev_class->full_name, fpi_device_probe_complete (device, dev_class->id, dev_class->full_name,
fake_dev->ret_error); fake_dev->ret_error);
} }
@@ -47,9 +53,15 @@ fpi_device_fake_open (FpDevice *device)
{ {
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
fake_dev->last_called_function = fpi_device_fake_open;
g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_OPEN); g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_OPEN);
fake_dev->last_called_function = fpi_device_fake_open; if (fake_dev->return_action_error)
{
fpi_device_action_error (device, fake_dev->ret_error);
return;
}
fpi_device_open_complete (device, fake_dev->ret_error); fpi_device_open_complete (device, fake_dev->ret_error);
} }
@@ -58,9 +70,15 @@ fpi_device_fake_close (FpDevice *device)
{ {
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
fake_dev->last_called_function = fpi_device_fake_close;
g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_CLOSE); g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_CLOSE);
fake_dev->last_called_function = fpi_device_fake_close; if (fake_dev->return_action_error)
{
fpi_device_action_error (device, fake_dev->ret_error);
return;
}
fpi_device_close_complete (device, fake_dev->ret_error); fpi_device_close_complete (device, fake_dev->ret_error);
} }
@@ -70,13 +88,20 @@ fpi_device_fake_enroll (FpDevice *device)
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
FpPrint *print = fake_dev->ret_print; FpPrint *print = fake_dev->ret_print;
fake_dev->last_called_function = fpi_device_fake_enroll;
g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_ENROLL); g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_ENROLL);
if (fake_dev->return_action_error)
{
fpi_device_action_error (device, fake_dev->ret_error);
return;
}
fpi_device_get_enroll_data (device, (FpPrint **) &fake_dev->action_data); fpi_device_get_enroll_data (device, (FpPrint **) &fake_dev->action_data);
if (!print && !fake_dev->ret_error) if (!print && !fake_dev->ret_error)
fpi_device_get_enroll_data (device, &print); fpi_device_get_enroll_data (device, &print);
fake_dev->last_called_function = fpi_device_fake_enroll;
fpi_device_enroll_complete (device, fpi_device_enroll_complete (device,
print ? g_object_ref (print) : NULL, print ? g_object_ref (print) : NULL,
fake_dev->ret_error); fake_dev->ret_error);
@@ -88,15 +113,29 @@ fpi_device_fake_verify (FpDevice *device)
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
FpPrint *print = fake_dev->ret_print; FpPrint *print = fake_dev->ret_print;
fake_dev->last_called_function = fpi_device_fake_verify;
g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_VERIFY); g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_VERIFY);
if (fake_dev->return_action_error)
{
fpi_device_action_error (device, fake_dev->ret_error);
return;
}
fpi_device_get_verify_data (device, (FpPrint **) &fake_dev->action_data); fpi_device_get_verify_data (device, (FpPrint **) &fake_dev->action_data);
if (!print && !fake_dev->ret_error) if (!print && !fake_dev->ret_error)
fpi_device_get_verify_data (device, &print); fpi_device_get_verify_data (device, &print);
fake_dev->last_called_function = fpi_device_fake_verify; if (!fake_dev->ret_error || fake_dev->ret_error->domain == FP_DEVICE_RETRY)
fpi_device_verify_complete (device, fake_dev->ret_result, print, {
fake_dev->ret_error); fpi_device_verify_report (device, fake_dev->ret_result, print, fake_dev->ret_error);
fpi_device_verify_complete (device, NULL);
}
else
{
fpi_device_verify_complete (device, fake_dev->ret_error);
}
} }
static void static void
@@ -105,7 +144,15 @@ fpi_device_fake_identify (FpDevice *device)
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
FpPrint *match = fake_dev->ret_match; FpPrint *match = fake_dev->ret_match;
fake_dev->last_called_function = fpi_device_fake_identify;
g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_IDENTIFY); g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_IDENTIFY);
if (fake_dev->return_action_error)
{
fpi_device_action_error (device, fake_dev->ret_error);
return;
}
fpi_device_get_identify_data (device, (GPtrArray **) &fake_dev->action_data); fpi_device_get_identify_data (device, (GPtrArray **) &fake_dev->action_data);
if (!match && !fake_dev->ret_error) if (!match && !fake_dev->ret_error)
@@ -127,9 +174,15 @@ fpi_device_fake_identify (FpDevice *device)
} }
} }
fake_dev->last_called_function = fpi_device_fake_identify; if (!fake_dev->ret_error || fake_dev->ret_error->domain == FP_DEVICE_RETRY)
fpi_device_identify_complete (device, match, fake_dev->ret_print, {
fake_dev->ret_error); fpi_device_identify_report (device, match, fake_dev->ret_print, fake_dev->ret_error);
fpi_device_identify_complete (device, NULL);
}
else
{
fpi_device_identify_complete (device, fake_dev->ret_error);
}
} }
static void static void
@@ -137,10 +190,16 @@ fpi_device_fake_capture (FpDevice *device)
{ {
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_CAPTURE);
fpi_device_get_capture_data (device, (gboolean *) &fake_dev->action_data);
fake_dev->last_called_function = fpi_device_fake_capture; fake_dev->last_called_function = fpi_device_fake_capture;
g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_CAPTURE);
if (fake_dev->return_action_error)
{
fpi_device_action_error (device, fake_dev->ret_error);
return;
}
fpi_device_get_capture_data (device, (gboolean *) &fake_dev->action_data);
fpi_device_capture_complete (device, fake_dev->ret_image, fake_dev->ret_error); fpi_device_capture_complete (device, fake_dev->ret_image, fake_dev->ret_error);
} }
@@ -149,9 +208,15 @@ fpi_device_fake_list (FpDevice *device)
{ {
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
fake_dev->last_called_function = fpi_device_fake_list;
g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_LIST); g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_LIST);
fake_dev->last_called_function = fpi_device_fake_list; if (fake_dev->return_action_error)
{
fpi_device_action_error (device, fake_dev->ret_error);
return;
}
fpi_device_list_complete (device, fake_dev->ret_list, fake_dev->ret_error); fpi_device_list_complete (device, fake_dev->ret_list, fake_dev->ret_error);
} }
@@ -160,10 +225,16 @@ fpi_device_fake_delete (FpDevice *device)
{ {
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_DELETE);
fpi_device_get_delete_data (device, (gpointer) & fake_dev->action_data);
fake_dev->last_called_function = fpi_device_fake_delete; fake_dev->last_called_function = fpi_device_fake_delete;
g_assert_cmpuint (fpi_device_get_current_action (device), ==, FPI_DEVICE_ACTION_DELETE);
if (fake_dev->return_action_error)
{
fpi_device_action_error (device, fake_dev->ret_error);
return;
}
fpi_device_get_delete_data (device, (gpointer) (&fake_dev->action_data));
fpi_device_delete_complete (device, fake_dev->ret_error); fpi_device_delete_complete (device, fake_dev->ret_error);
} }
@@ -172,9 +243,8 @@ fpi_device_fake_cancel (FpDevice *device)
{ {
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
g_assert_cmpuint (fpi_device_get_current_action (device), !=, FPI_DEVICE_ACTION_NONE);
fake_dev->last_called_function = fpi_device_fake_cancel; fake_dev->last_called_function = fpi_device_fake_cancel;
g_assert_cmpuint (fpi_device_get_current_action (device), !=, FPI_DEVICE_ACTION_NONE);
} }
static void static void
+1
View File
@@ -30,6 +30,7 @@ struct _FpiDeviceFake
FpDevice parent; FpDevice parent;
gpointer last_called_function; gpointer last_called_function;
gboolean return_action_error;
GError *ret_error; GError *ret_error;
FpPrint *ret_print; FpPrint *ret_print;
+905 -62
View File
File diff suppressed because it is too large Load Diff
+46
View File
@@ -0,0 +1,46 @@
#! /usr/bin/env python3
# Copyright © 2020, Canonical Ltd
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
# Authors:
# Marco Trevisan <marco.trevisan@canonical.com>
import argparse
import importlib.util
import inspect
import os
import unittest
def list_tests(module):
tests = []
for name, obj in inspect.getmembers(module):
if inspect.isclass(obj) and issubclass(obj, unittest.TestCase):
cases = unittest.defaultTestLoader.getTestCaseNames(obj)
tests += [ (obj, '{}.{}'.format(name, t)) for t in cases ]
return tests
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('unittest_source', type=argparse.FileType('r'))
args = parser.parse_args()
source_path = args.unittest_source.name
spec = importlib.util.spec_from_file_location(
os.path.basename(source_path), source_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
for machine, human in list_tests(module):
print(human)
+78 -37
View File
@@ -1,20 +1,24 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import gi
gi.require_version('FPrint', '2.0')
from gi.repository import FPrint, GLib, Gio
import os
import sys import sys
import unittest try:
import socket import gi
import struct gi.require_version('FPrint', '2.0')
import subprocess from gi.repository import FPrint, GLib, Gio
import shutil
import glob import os
import cairo import sys
import tempfile import unittest
import socket
import struct
import subprocess
import shutil
import glob
import cairo
import tempfile
except Exception as e:
print("Missing dependencies: %s" % str(e))
sys.exit(77)
# Re-run the test with the passed wrapper if set # Re-run the test with the passed wrapper if set
wrapper = os.getenv('LIBFPRINT_TEST_WRAPPER') wrapper = os.getenv('LIBFPRINT_TEST_WRAPPER')
@@ -97,15 +101,13 @@ class VirtualImage(unittest.TestCase):
del self.con del self.con
self.dev.close_sync() self.dev.close_sync()
def send_retry(self, retry_error=1, iterate=True): def send_retry(self, retry_error=FPrint.DeviceRetry.TOO_SHORT, iterate=True):
# The default (1) is too-short self.con.sendall(struct.pack('ii', -1, retry_error))
self.sendall(struct.pack('ii', -1, retry_error))
while iterate and ctx.pending(): while iterate and ctx.pending():
ctx.iteration(False) ctx.iteration(False)
def send_error(self, device_error=0, iterate=True): def send_error(self, device_error=FPrint.DeviceError.GENERAL, iterate=True):
# The default (0) is a generic error self.con.sendall(struct.pack('ii', -2, device_error))
self.sendall(struct.pack('ii', -1, retry_error))
while iterate and ctx.pending(): while iterate and ctx.pending():
ctx.iteration(False) ctx.iteration(False)
@@ -212,15 +214,16 @@ class VirtualImage(unittest.TestCase):
done = False done = False
def verify_cb(dev, res): def verify_cb(dev, res):
match, fp = dev.verify_finish(res) try:
self._verify_match = match self._verify_match, self._verify_fp = dev.verify_finish(res)
self._verify_fp = fp except gi.repository.GLib.Error as e:
self._verify_error = e
fp_whorl = self.enroll_print('whorl') fp_whorl = self.enroll_print('whorl')
self._verify_match = None self._verify_match = None
self._verify_fp = None self._verify_fp = None
self.dev.verify(fp_whorl, None, verify_cb) self.dev.verify(fp_whorl, callback=verify_cb)
self.send_image('whorl') self.send_image('whorl')
while self._verify_match is None: while self._verify_match is None:
ctx.iteration(True) ctx.iteration(True)
@@ -228,41 +231,79 @@ class VirtualImage(unittest.TestCase):
self._verify_match = None self._verify_match = None
self._verify_fp = None self._verify_fp = None
self.dev.verify(fp_whorl, None, verify_cb) self.dev.verify(fp_whorl, callback=verify_cb)
self.send_image('tented_arch') self.send_image('tented_arch')
while self._verify_match is None: while self._verify_match is None:
ctx.iteration(True) ctx.iteration(True)
assert(not self._verify_match) assert(not self._verify_match)
# Test verify error cases
self._verify_fp = None
self._verify_error = None
self.dev.verify(fp_whorl, callback=verify_cb)
self.send_retry()
while self._verify_fp is None and self._verify_error is None:
ctx.iteration(True)
assert(self._verify_error is not None)
assert(self._verify_error.matches(FPrint.device_retry_quark(), FPrint.DeviceRetry.TOO_SHORT))
self._verify_fp = None
self._verify_error = None
self.dev.verify(fp_whorl, callback=verify_cb)
self.send_error()
while self._verify_fp is None and self._verify_error is None:
ctx.iteration(True)
assert(self._verify_error is not None)
print(self._verify_error)
assert(self._verify_error.matches(FPrint.device_error_quark(), FPrint.DeviceError.GENERAL))
def test_identify(self): def test_identify(self):
done = False done = False
def verify_cb(dev, res):
r, fp = dev.verify_finish(res)
self._verify_match = r
self._verify_fp = fp
fp_whorl = self.enroll_print('whorl') fp_whorl = self.enroll_print('whorl')
fp_tented_arch = self.enroll_print('tented_arch') fp_tented_arch = self.enroll_print('tented_arch')
def identify_cb(dev, res): def identify_cb(dev, res):
print('Identify finished') print('Identify finished')
try:
self._identify_match, self._identify_fp = self.dev.identify_finish(res) self._identify_match, self._identify_fp = self.dev.identify_finish(res)
except gi.repository.GLib.Error as e:
print(e)
self._identify_error = e
self._identify_fp = None self._identify_fp = None
self.dev.identify([fp_whorl, fp_tented_arch], None, identify_cb) self.dev.identify([fp_whorl, fp_tented_arch], callback=identify_cb)
self.send_image('tented_arch') self.send_image('tented_arch')
while self._identify_fp is None: while self._identify_fp is None:
ctx.iteration(True) ctx.iteration(True)
assert(self._identify_match is fp_tented_arch) assert(self._identify_match is fp_tented_arch)
self._identify_fp = None self._identify_fp = None
self.dev.identify([fp_whorl, fp_tented_arch], None, identify_cb) self.dev.identify([fp_whorl, fp_tented_arch], callback=identify_cb)
self.send_image('whorl') self.send_image('whorl')
while self._identify_fp is None: while self._identify_fp is None:
ctx.iteration(True) ctx.iteration(True)
assert(self._identify_match is fp_whorl) assert(self._identify_match is fp_whorl)
# Test error cases
self._identify_fp = None
self._identify_error = None
self.dev.identify([fp_whorl, fp_tented_arch], callback=identify_cb)
self.send_retry()
while self._identify_fp is None and self._identify_error is None:
ctx.iteration(True)
assert(self._identify_error is not None)
assert(self._identify_error.matches(FPrint.device_retry_quark(), FPrint.DeviceRetry.TOO_SHORT))
self._identify_fp = None
self._identify_error = None
self.dev.identify([fp_whorl, fp_tented_arch], callback=identify_cb)
self.send_error()
while self._identify_fp is None and self._identify_error is None:
ctx.iteration(True)
assert(self._identify_error is not None)
assert(self._identify_error.matches(FPrint.device_error_quark(), FPrint.DeviceError.GENERAL))
def test_verify_serialized(self): def test_verify_serialized(self):
done = False done = False
@@ -290,7 +331,7 @@ class VirtualImage(unittest.TestCase):
self._verify_match = None self._verify_match = None
self._verify_fp = None self._verify_fp = None
self.dev.verify(fp_whorl_new, None, verify_cb) self.dev.verify(fp_whorl_new, callback=verify_cb)
self.send_image('whorl') self.send_image('whorl')
while self._verify_match is None: while self._verify_match is None:
ctx.iteration(True) ctx.iteration(True)
@@ -298,12 +339,12 @@ class VirtualImage(unittest.TestCase):
self._verify_match = None self._verify_match = None
self._verify_fp = None self._verify_fp = None
self.dev.verify(fp_whorl_new, None, verify_cb) self.dev.verify(fp_whorl_new, callback=verify_cb)
self.send_image('tented_arch') self.send_image('tented_arch')
while self._verify_match is None: while self._verify_match is None:
ctx.iteration(True) ctx.iteration(True)
assert(not self._verify_match) assert(not self._verify_match)
# avoid writing to stderr if __name__ == '__main__':
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2)) # avoid writing to stderr
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))