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
*.swp
Makefile
Makefile.in
config.h*
aclocal.m4
autom4te.cache
config.guess
config.log
config.status
config.sub
configure
depcomp
install-sh
.deps
.libs
compile
ChangeLog
_build
+13 -35
View File
@@ -1,15 +1,17 @@
include:
- local: '.gitlab-ci/libfprint-templates.yaml'
- project: 'wayland/ci-templates'
ref: master
file: '/templates/fedora.yml'
variables:
extends: .libfprint_common_variables
FEDORA_TAG: rawhide
FEDORA_VERSION: rawhide
FEDORA_IMAGE: "$CI_REGISTRY/libfprint/$CI_PROJECT_NAME/fedora/$FEDORA_VERSION:$FEDORA_TAG"
BUNDLE: "org.freedesktop.libfprint.Demo.flatpak"
LAST_ABI_BREAK: "056ea541ddc97f5806cffbd99a12dc87e4da3546"
include:
- project: 'wayland/ci-templates'
ref: master
file: '/templates/fedora.yml'
stages:
- check-source
- build
@@ -106,9 +108,6 @@ test_indent:
.flatpak_master_template: &flatpak_master
image: registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:3.32
stage: flatpack
except:
variables:
- $CI_PIPELINE_SOURCE == "schedule"
variables:
MANIFEST_PATH: "demo/org.freedesktop.libfprint.Demo.json"
# From demo/org.freedesktop.libfprint.Demo.json
@@ -128,8 +127,11 @@ flatpak-manual master:
<<: *flatpak_master
when: manual
except:
- tags
- master
refs:
- tags
- master
variables:
- $CI_PIPELINE_SOURCE == "schedule"
# CONTAINERS creation stage
container_fedora_build:
@@ -140,28 +142,4 @@ container_fedora_build:
variables:
GIT_STRATEGY: none # no need to pull the whole tree for rebuilding the image
# a list of packages to install
FEDORA_RPMS:
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
FEDORA_RPMS: $LIBFPRINT_DEPENDENCIES
+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
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
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_error_quark
FpEnrollProgress
FpMatchCb
fp_device_get_driver
fp_device_get_device_id
fp_device_get_name
@@ -159,6 +160,8 @@ fpi_device_identify_complete
fpi_device_capture_complete
fpi_device_delete_complete
fpi_device_enroll_progress
fpi_device_verify_report
fpi_device_identify_report
</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')
docpath = join_paths(get_option('datadir'), 'gtk-doc', 'html')
gnome.gtkdoc(meson.project_name(),
gnome.gtkdoc(versioned_libname,
main_xml: 'libfprint-docs.xml',
src_dir: join_paths(meson.source_root(), 'libfprint'),
dependencies: libfprint_dep,
content_files: content_files,
expand_content_files: expand_content_files,
scan_args: [
#'--rebuild-sections',
'--ignore-headers=' + ' '.join(private_headers),
],
ignore_headers: private_headers,
fixxref_args: [
'--html-dir=@0@'.format(docpath),
'--extra-dir=@0@'.format(join_paths(glib_docpath, 'glib')),
+3 -3
View File
@@ -1,8 +1,8 @@
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_NAME', meson.project_name())
ent_conf.set('PACKAGE_STRING', meson.project_name())
ent_conf.set('PACKAGE_NAME', versioned_libname)
ent_conf.set('PACKAGE_STRING', versioned_libname)
ent_conf.set('PACKAGE_TARNAME', 'libfprint-' + meson.project_version())
ent_conf.set('PACKAGE_URL', 'https://fprint.freedesktop.org/')
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
*/
#define FP_COMPONENT "example-enroll"
#include <stdio.h>
#include <libfprint/fprint.h>
+2
View File
@@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-mange-prints"
#include <stdio.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
*/
#define FP_COMPONENT "example-storage"
#include <libfprint/fprint.h>
#include <libfprint/fpi-compat.h>
#include "storage.h"
#include <errno.h>
@@ -161,8 +164,8 @@ FpPrint *
print_create_template (FpDevice *dev, FpFinger finger)
{
g_autoptr(GDateTime) datetime = NULL;
g_autoptr(GDate) date = NULL;
FpPrint *template = NULL;
GDate *date = NULL;
gint year, month, day;
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);
date = g_date_new_dmy (day, month, year);
fp_print_set_enroll_date (template, date);
g_date_free (date);
return template;
}
+2
View File
@@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-utilities"
#include <libfprint/fprint.h>
#include <stdio.h>
+70 -23
View File
@@ -19,6 +19,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#define FP_COMPONENT "example-verify"
#include <stdio.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);
}
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,
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))
{
g_warning ("Failed to verify print: %s", error->message);
g_main_loop_quit (verify_data->loop);
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;
if (error->domain != FP_DEVICE_RETRY)
{
verify_quit (dev, verify_data);
return;
}
}
g_print ("Verify again? [Y/n]? ");
@@ -98,8 +103,48 @@ on_verify_completed (FpDevice *dev, GAsyncResult *res, void *user_data)
return;
}
fp_device_close (dev, NULL, (GAsyncReadyCallback) on_device_closed,
verify_data);
verify_quit (dev, 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
@@ -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?",
finger_to_string (verify_data->finger));
g_main_loop_quit (verify_data->loop);
verify_quit (dev, verify_data);
return;
}
@@ -152,13 +197,14 @@ on_list_completed (FpDevice *dev, GAsyncResult *res, gpointer user_data)
g_print ("Print loaded. Time to verify!\n");
fp_device_verify (dev, verify_print, NULL,
on_match_cb, verify_data, NULL,
(GAsyncReadyCallback) on_verify_completed,
verify_data);
}
else
{
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");
verify_data->ret_value = EXIT_FAILURE;
g_main_loop_quit (verify_data->loop);
verify_quit (dev, verify_data);
return;
}
@@ -199,12 +245,13 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
g_warning ("Failed to load fingerprint data");
g_warning ("Did you remember to enroll your %s finger first?",
finger_to_string (verify_data->finger));
g_main_loop_quit (verify_data->loop);
verify_quit (dev, verify_data);
return;
}
g_print ("Print loaded. Time to verify!\n");
fp_device_verify (dev, verify_print, NULL,
NULL, NULL, NULL,
(GAsyncReadyCallback) on_verify_completed,
verify_data);
}
@@ -220,7 +267,7 @@ on_device_opened (FpDevice *dev, GAsyncResult *res, void *user_data)
if (!fp_device_open_finish (dev, res, &error))
{
g_warning ("Failed to open device: %s", error->message);
g_main_loop_quit (verify_data->loop);
verify_quit (dev, verify_data);
return;
}
-2
View File
@@ -585,8 +585,6 @@ capture_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
G_DEBUG_HERE ();
/* XXX: cancellation was specially handled by doing nothing! */
/* either max frames captured or timed out waiting for the next frame */
if (!error ||
(g_error_matches (error, G_USB_DEVICE_ERROR, G_USB_DEVICE_ERROR_TIMED_OUT) &&
+37 -33
View File
@@ -279,17 +279,10 @@ cmd_ssm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
self->cmd_ssm = NULL;
/* Notify about the SSM failure from here instead. */
if (error)
{
callback (self, NULL, error);
}
else if (self->cmd_complete_on_removal)
{
callback (self, NULL, self->cmd_complete_error);
self->cmd_complete_error = NULL;
}
if (error || self->cmd_complete_on_removal)
callback (self, NULL, error);
self->cmd_complete_on_removal = FALSE;
g_clear_pointer (&self->cmd_complete_error, g_error_free);
}
static void
@@ -527,8 +520,8 @@ list_msg_cb (FpiDeviceSynaptics *self,
userid[12] == '-' && userid[14] == '-' && userid[23] == '-')
{
g_autofree gchar *copy = g_strdup (userid);
g_autoptr(GDate) date = NULL;
gint32 date_ymd;
GDate *date = NULL;
gint32 finger;
gchar *username;
/* Try to parse information from the string. */
@@ -543,7 +536,6 @@ list_msg_cb (FpiDeviceSynaptics *self,
date = g_date_new ();
fp_print_set_enroll_date (print, date);
g_date_free (date);
copy[14] = '\0';
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);
}
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
verify_msg_cb (FpiDeviceSynaptics *self,
bmkt_response_t *resp,
@@ -592,16 +600,13 @@ verify_msg_cb (FpiDeviceSynaptics *self,
if (error)
{
fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error);
fpi_device_verify_complete (device, error);
return;
}
if (resp == NULL && self->cmd_complete_on_removal)
{
fpi_device_verify_complete (device,
GPOINTER_TO_INT (self->cmd_complete_data),
NULL,
error);
fpi_device_verify_complete (device, NULL);
return;
}
@@ -620,39 +625,40 @@ verify_msg_cb (FpiDeviceSynaptics *self,
break;
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!");
self->cmd_complete_on_removal = TRUE;
self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_ERROR);
self->cmd_complete_error = fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL);
fp_info ("Match error occurred");
fpi_device_verify_report (device, FPI_MATCH_ERROR, NULL,
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
verify_complete_after_finger_removal (self);
}
else if (resp->result == BMKT_FP_NO_MATCH)
{
fp_dbg ("delaying match failure until after finger removal!");
self->cmd_complete_on_removal = TRUE;
self->cmd_complete_data = GINT_TO_POINTER (FPI_MATCH_FAIL);
self->cmd_complete_error = NULL;
fp_info ("Print didn't match");
fpi_device_verify_report (device, FPI_MATCH_FAIL, NULL, error);
verify_complete_after_finger_removal (self);
}
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");
fpi_device_verify_complete (device,
FPI_MATCH_ERROR,
NULL,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
}
else
{
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;
case BMKT_RSP_VERIFY_OK:
fp_info ("Verify was successful! for user: %s finger: %d score: %f",
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;
}
}
@@ -675,8 +681,6 @@ verify (FpDevice *device)
if (!parse_print_data (data, &finger, &user_id, &user_id_len))
{
fpi_device_verify_complete (device,
FPI_MATCH_ERROR,
NULL,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
return;
}
-2
View File
@@ -110,8 +110,6 @@ struct _FpiDeviceSynaptics
FpiSsm *cmd_ssm;
FpiUsbTransfer *cmd_pending_transfer;
gboolean cmd_complete_on_removal;
GError *cmd_complete_error;
void *cmd_complete_data;
bmkt_sensor_version_t mis_version;
+16 -7
View File
@@ -902,8 +902,10 @@ enroll_start_sm_cb_msg28 (FpDevice *dev,
FpiSsm *ssm = user_data;
if (error)
fpi_ssm_mark_failed (ssm, error);
if (type != READ_MSG_RESPONSE)
{
fpi_ssm_mark_failed (ssm, error);
}
else if (type != READ_MSG_RESPONSE)
{
fp_err ("expected response, got %d seq=%x", type, seq);
fpi_ssm_mark_failed (ssm, fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
@@ -1225,8 +1227,7 @@ enroll (FpDevice *dev)
typedef struct
{
FpiMatchResult res;
GError *error;
GError *error;
} VerifyStopData;
static void
@@ -1244,7 +1245,12 @@ verify_stop_deinit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
if (error)
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
@@ -1253,8 +1259,11 @@ do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error)
VerifyStopData *data = g_new0 (VerifyStopData, 1);
FpiSsm *ssm = deinitsm_new (dev, data);
data->res = res;
data->error = error;
/* 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;
fpi_ssm_start (ssm, verify_stop_deinit_cb);
fpi_ssm_set_data (ssm, data, (GDestroyNotify) verify_stop_data_free);
+1
View File
@@ -21,6 +21,7 @@
#pragma once
#include "fpi-compat.h"
#include "fpi-assembling.h"
#include "fpi-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++)
{
GType driver = g_array_index (priv->drivers, GType, i);
g_autoptr(GTypeClass) type_class = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (type_class);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_USB)
@@ -288,8 +287,7 @@ fp_context_init (FpContext *self)
for (i = 0; i < priv->drivers->len;)
{
GType driver = g_array_index (priv->drivers, GType, i);
g_autoptr(GTypeClass) type_class = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (type_class);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
if (!is_driver_allowed (cls->id))
g_array_remove_index (priv->drivers, i);
@@ -363,8 +361,7 @@ fp_context_enumerate (FpContext *context)
for (i = 0; i < priv->drivers->len; i++)
{
GType driver = g_array_index (priv->drivers, GType, i);
g_autoptr(GTypeClass) type_class = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (type_class);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
const FpIdEntry *entry;
if (cls->type != FP_DEVICE_TYPE_VIRTUAL)
+17
View File
@@ -63,3 +63,20 @@ typedef struct
} FpEnrollData;
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->enroll_progress_cb = progress_cb;
data->enroll_progress_data = progress_data;
data->enroll_progress_destroy = progress_destroy;
// 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);
@@ -808,10 +809,13 @@ fp_device_enroll_finish (FpDevice *device,
* @device: a #FpDevice
* @enrolled_print: a #FpPrint to verify
* @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
* @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
* fp_device_verify_finish().
*/
@@ -819,11 +823,15 @@ void
fp_device_verify (FpDevice *device,
FpPrint *enrolled_print,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
GDestroyNotify match_destroy,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data;
task = g_task_new (device, cancellable, callback, user_data);
if (g_task_return_error_if_cancelled (task))
@@ -847,9 +855,14 @@ fp_device_verify (FpDevice *device,
priv->current_task = g_steal_pointer (&task);
maybe_cancel_on_cancelled (device, cancellable);
g_task_set_task_data (priv->current_task,
g_object_ref (enrolled_print),
g_object_unref);
data = g_new0 (FpMatchData, 1);
data->enrolled_print = g_object_ref (enrolled_print);
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);
}
@@ -885,7 +898,11 @@ fp_device_verify_finish (FpDevice *device,
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)
g_object_ref (*print);
}
@@ -901,6 +918,9 @@ fp_device_verify_finish (FpDevice *device,
* @device: a #FpDevice
* @prints: (element-type FpPrint) (transfer none): #GPtrArray of #FpPrint
* @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
* @user_data: the data to pass to @callback
*
@@ -912,11 +932,15 @@ void
fp_device_identify (FpDevice *device,
GPtrArray *prints,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
GDestroyNotify match_destroy,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr(GTask) task = NULL;
FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data;
task = g_task_new (device, cancellable, callback, user_data);
if (g_task_return_error_if_cancelled (task))
@@ -940,9 +964,14 @@ fp_device_identify (FpDevice *device,
priv->current_task = g_steal_pointer (&task);
maybe_cancel_on_cancelled (device, cancellable);
g_task_set_task_data (priv->current_task,
g_ptr_array_ref (prints),
(GDestroyNotify) g_ptr_array_unref);
data = g_new0 (FpMatchData, 1);
data->gallery = g_ptr_array_ref (prints);
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);
}
@@ -973,15 +1002,19 @@ fp_device_identify_finish (FpDevice *device,
FpPrint **print,
GError **error)
{
FpMatchData *data;
data = g_task_get_task_data (G_TASK (result));
if (print)
{
*print = g_object_get_data (G_OBJECT (result), "print");
*print = data->print;
if (*print)
g_object_ref (*print);
}
if (match)
{
*match = g_object_get_data (G_OBJECT (result), "match");
*match = data->match;
if (*match)
g_object_ref (*match);
}
@@ -1180,6 +1213,14 @@ fp_device_list_prints (FpDevice *device,
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_task = g_steal_pointer (&task);
maybe_cancel_on_cancelled (device, cancellable);
@@ -1308,6 +1349,8 @@ fp_device_enroll_sync (FpDevice *device,
* @device: a #FpDevice
* @enrolled_print: a #FpPrint to verify
* @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
* @print: (out) (transfer full) (nullable): Location to store the scanned print, or %NULL to ignore
* @error: Return location for errors, or %NULL to ignore
@@ -1320,6 +1363,8 @@ gboolean
fp_device_verify_sync (FpDevice *device,
FpPrint *enrolled_print,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
gboolean *match,
FpPrint **print,
GError **error)
@@ -1331,6 +1376,7 @@ fp_device_verify_sync (FpDevice *device,
fp_device_verify (device,
enrolled_print,
cancellable,
match_cb, match_data, NULL,
async_result_ready, &task);
while (!task)
g_main_context_iteration (NULL, TRUE);
@@ -1343,6 +1389,8 @@ fp_device_verify_sync (FpDevice *device,
* @device: a #FpDevice
* @prints: (element-type FpPrint) (transfer none): #GPtrArray of #FpPrint
* @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
* @print: (out) (transfer full) (nullable): Location for the new #FpPrint, or %NULL
* @error: Return location for errors, or %NULL to ignore
@@ -1355,6 +1403,8 @@ gboolean
fp_device_identify_sync (FpDevice *device,
GPtrArray *prints,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
FpPrint **match,
FpPrint **print,
GError **error)
@@ -1366,6 +1416,7 @@ fp_device_identify_sync (FpDevice *device,
fp_device_identify (device,
prints,
cancellable,
match_cb, match_data, NULL,
async_result_ready, &task);
while (!task)
g_main_context_iteration (NULL, TRUE);
+47
View File
@@ -125,6 +125,43 @@ typedef void (*FpEnrollProgress) (FpDevice *device,
gpointer user_data,
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_device_id (FpDevice *device);
@@ -160,12 +197,18 @@ void fp_device_enroll (FpDevice *device,
void fp_device_verify (FpDevice *device,
FpPrint *enrolled_print,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
GDestroyNotify match_destroy,
GAsyncReadyCallback callback,
gpointer user_data);
void fp_device_identify (FpDevice *device,
GPtrArray *prints,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
GDestroyNotify match_destroy,
GAsyncReadyCallback callback,
gpointer user_data);
@@ -231,12 +274,16 @@ FpPrint * fp_device_enroll_sync (FpDevice *device,
gboolean fp_device_verify_sync (FpDevice *device,
FpPrint *enrolled_print,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
gboolean *match,
FpPrint **print,
GError **error);
gboolean fp_device_identify_sync (FpDevice *device,
GPtrArray *prints,
GCancellable *cancellable,
FpMatchCb match_cb,
gpointer match_data,
FpPrint **match,
FpPrint **print,
GError **error);
+2 -3
View File
@@ -21,6 +21,7 @@
#define FP_COMPONENT "print"
#include "fp-print-private.h"
#include "fpi-compat.h"
#include "fpi-log.h"
/**
@@ -752,8 +753,8 @@ fp_print_deserialize (const guchar *data,
g_autoptr(GVariant) raw_value = NULL;
g_autoptr(GVariant) value = NULL;
g_autoptr(GVariant) print_data = NULL;
g_autoptr(GDate) date = NULL;
guchar *aligned_data = NULL;
GDate *date = NULL;
guint8 finger_int8;
FpFinger finger;
g_autofree gchar *username = NULL;
@@ -881,8 +882,6 @@ fp_print_deserialize (const guchar *data,
"enroll_date", date,
NULL);
g_date_free (date);
return g_steal_pointer (&result);
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 "fp-context.h"
#include "fpi-compat.h"
/**
* fpi_get_driver_types:
+244 -50
View File
@@ -420,6 +420,23 @@ enroll_data_free (FpEnrollData *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:
* @device: The #FpDevice
@@ -476,12 +493,16 @@ fpi_device_get_verify_data (FpDevice *device,
FpPrint **print)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data;
g_return_if_fail (FP_IS_DEVICE (device));
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)
*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)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data;
g_return_if_fail (FP_IS_DEVICE (device));
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)
*prints = g_task_get_task_data (priv->current_task);
*prints = data->gallery;
}
/**
@@ -596,11 +621,11 @@ fpi_device_action_error (FpDevice *device,
break;
case FPI_DEVICE_ACTION_VERIFY:
fpi_device_verify_complete (device, FPI_MATCH_ERROR, NULL, error);
fpi_device_verify_complete (device, error);
break;
case FPI_DEVICE_ACTION_IDENTIFY:
fpi_device_identify_complete (device, NULL, NULL, error);
fpi_device_identify_complete (device, error);
break;
case FPI_DEVICE_ACTION_CAPTURE:
@@ -826,8 +851,6 @@ fpi_device_close_complete (FpDevice *device, GError *error)
g_debug ("Device reported close completion");
clear_device_cancel_action (device);
priv->is_open = FALSE;
g_object_notify (G_OBJECT (device), "open");
switch (priv->type)
{
@@ -852,10 +875,16 @@ fpi_device_close_complete (FpDevice *device, GError *error)
}
if (!error)
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
GUINT_TO_POINTER (TRUE));
{
priv->is_open = FALSE;
g_object_notify (G_OBJECT (device), "open");
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
GUINT_TO_POINTER (TRUE));
}
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:
* @device: The #FpDevice
* @result: The #FpiMatchResult of the operation
* @print: The scanned #FpPrint
* @error: A #GError if result is %FPI_MATCH_ERROR
*
* Finish an ongoing verify operation. The returned print should be
* 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
fpi_device_verify_complete (FpDevice *device,
FpiMatchResult result,
FpPrint *print,
GError *error)
fpi_device_verify_complete (FpDevice *device,
GError *error)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data;
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_VERIFY);
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),
"print",
print,
g_object_unref);
clear_device_cancel_action (device);
if (!error)
{
if (result != FPI_MATCH_ERROR)
if (!data->result_reported)
{
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT,
GINT_TO_POINTER (result));
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
{
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);
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT,
GINT_TO_POINTER (data->match != NULL ? FPI_MATCH_SUCCESS : FPI_MATCH_FAIL));
}
}
else
{
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
if (result != FPI_MATCH_ERROR)
/* Replace a retry error with a general error, this is a driver bug. */
if (error->domain == FP_DEVICE_RETRY)
{
g_warning ("Driver passed an error but also provided a match result, returning error!");
g_object_unref (print);
g_warning ("Driver reported a retry error to fpi_device_verify_complete. "
"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:
* @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
*
* Finish an ongoing identify operation. The match that was identified is
@@ -973,40 +1006,50 @@ fpi_device_verify_complete (FpDevice *device,
*/
void
fpi_device_identify_complete (FpDevice *device,
FpPrint *match,
FpPrint *print,
GError *error)
{
FpDevicePrivate *priv = fp_device_get_instance_private (device);
FpMatchData *data;
g_return_if_fail (FP_IS_DEVICE (device));
g_return_if_fail (priv->current_action == FPI_DEVICE_ACTION_IDENTIFY);
g_debug ("Device reported identify completion");
data = g_task_get_task_data (priv->current_task);
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)
{
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_BOOL,
GUINT_TO_POINTER (TRUE));
if (!data->result_reported)
{
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
{
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_INT, GINT_TO_POINTER (TRUE));
}
}
else
{
fpi_device_return_task_in_idle (device, FP_DEVICE_TASK_RETURN_ERROR, error);
if (match)
/* Replace a retry error with a general error, this is a driver bug. */
if (error->domain == FP_DEVICE_RETRY)
{
g_warning ("Driver passed an error but also provided a match result, returning error!");
g_clear_object (&match);
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:
* @device: The #FpDevice
* @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
*
* 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);
if (print)
g_object_ref_sink (print);
if (error && print)
{
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_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);
}
+10 -6
View File
@@ -237,13 +237,9 @@ void fpi_device_close_complete (FpDevice *device,
void fpi_device_enroll_complete (FpDevice *device,
FpPrint *print,
GError *error);
void fpi_device_verify_complete (FpDevice *device,
FpiMatchResult result,
FpPrint *print,
GError *error);
void fpi_device_verify_complete (FpDevice *device,
GError *error);
void fpi_device_identify_complete (FpDevice *device,
FpPrint *match,
FpPrint *print,
GError *error);
void fpi_device_capture_complete (FpDevice *device,
FpImage *image,
@@ -258,5 +254,13 @@ void fpi_device_enroll_progress (FpDevice *device,
gint completed_stages,
FpPrint *print,
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
+42 -6
View File
@@ -210,7 +210,9 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
else
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);
}
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)
{
result = g_object_ref (template);
result = template;
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);
}
else
@@ -410,12 +414,30 @@ fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
priv->enroll_await_on_pending = TRUE;
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
{
/* We abort the operation and let the surrounding code retry in the
* non-enroll case (this is identical to a session error). */
g_debug ("Abort current operation due to retry (non-enroll case)");
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
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
*
* 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
fpi_image_device_session_error (FpImageDevice *self, GError *error)
@@ -453,17 +477,29 @@ fpi_image_device_session_error (FpImageDevice *self, GError *error)
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)
{
g_warning ("Driver reported session error; translating to deactivation failure.");
fpi_image_device_deactivate_complete (self, error);
g_warning ("Driver reported session error while deactivating already, ignoring. This indicates a driver bug.");
g_clear_error (&error);
return;
}
if (error->domain == FP_DEVICE_RETRY)
g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
priv->cancelling = TRUE;
fpi_image_device_deactivate (self);
priv->cancelling = FALSE;
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++)
{
GType driver = g_array_index (drivers, GType, i);
g_autoptr(GTypeClass) type_class = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (type_class);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
const FpIdEntry *entry;
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++)
{
GType driver = g_array_index (drivers, GType, i);
g_autoptr(GTypeClass) type_class = g_type_class_ref (driver);
FpDeviceClass *cls = FP_DEVICE_CLASS (type_class);
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
if (cls->type != FP_DEVICE_TYPE_USB)
continue;
+8 -4
View File
@@ -177,7 +177,7 @@ other_sources = []
fp_enums = gnome.mkenums_simple('fp-enums',
sources: libfprint_public_headers,
install_header: true,
install_dir: get_option('includedir') / meson.project_name(),
install_dir: get_option('includedir') / versioned_libname,
)
fp_enums_h = fp_enums[1]
@@ -209,6 +209,10 @@ deps = [
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: [
root_inc,
include_directories('nbis/include'),
@@ -248,7 +252,7 @@ libfprint_drivers = static_library('fprint-drivers',
mapfile = files('libfprint.ver')
vflag = '-Wl,--version-script,@0@/@1@'.format(meson.source_root(), mapfile[0])
libfprint = library('fprint',
libfprint = library(versioned_libname.split('lib')[1],
sources: [
fp_enums,
libfprint_sources,
@@ -272,7 +276,7 @@ libfprint_dep = declare_dependency(link_with: libfprint,
])
install_headers(['fprint.h'] + libfprint_public_headers,
subdir: meson.project_name()
subdir: versioned_libname
)
libfprint_private_dep = declare_dependency(
@@ -292,7 +296,7 @@ udev_rules = executable('fprint-list-udev-rules',
if get_option('udev_rules')
custom_target('udev-rules',
output: '60-fprint-autosuspend.rules',
output: '60-@0@-autosuspend.rules'.format(versioned_libname),
capture: true,
command: [ udev_rules ],
install: true,
View File
+8 -8
View File
@@ -1,10 +1,10 @@
project('libfprint', [ 'c', 'cpp' ],
version: '1.90.0',
version: '1.90.1',
license: 'LGPLv2.1+',
default_options: [
'buildtype=debugoptimized',
'warning_level=1',
'c_std=c99',
'c_std=gnu99',
],
meson_version: '>= 0.49.0')
@@ -53,10 +53,9 @@ common_cflags = cc.get_supported_arguments([
'-DGLIB_VERSION_MIN_REQUIRED=' + glib_version_def,
'-DGLIB_VERSION_MAX_ALLOWED=' + glib_version_def,
'-D_GNU_SOURCE',
'-DG_LOG_DOMAIN="libfprint"',
'-DG_LOG_DOMAIN="@0@"'.format(meson.project_name()),
])
c_cflags = cc.get_supported_arguments([
'-std=gnu99',
'-Wimplicit-function-declaration',
'-Wmissing-prototypes',
'-Wnested-externs',
@@ -75,11 +74,12 @@ soversion = 2
current = 0
revision = 0
libversion = '@0@.@1@.@2@'.format(soversion, current, revision)
versioned_libname = meson.project_name() + '-' + soversion.to_string()
# Dependencies
glib_dep = dependency('glib-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)
# The following dependencies are only used for tests
@@ -208,10 +208,10 @@ subdir('tests')
pkgconfig = import('pkgconfig')
pkgconfig.generate(
name: meson.project_name(),
name: versioned_libname,
description: 'Generic C API for fingerprint reader access',
version: meson.project_version(),
libraries: libfprint,
subdirs: meson.project_name(),
filebase: meson.project_name() + '@0@'.format(soversion),
subdirs: versioned_libname,
filebase: versioned_libname,
)
+30 -7
View File
@@ -26,12 +26,35 @@ if get_option('introspection')
envs.prepend('GI_TYPELIB_PATH', join_paths(meson.build_root(), 'libfprint'))
if 'virtual_image' in drivers
test('virtual-image',
find_program('virtual-image.py'),
args: '--verbose',
env: envs,
depends: libfprint_typelib,
)
python3 = find_program('python3')
unittest_inspector = find_program('unittest_inspector.py')
base_args = files('virtual-image.py')
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,
env: envs,
)
endforeach
else
test('virtual-image',
find_program('sh'),
@@ -43,7 +66,7 @@ if get_option('introspection')
driver_envs = envs
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,
find_program('umockdev-test.py'),
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);
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);
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,
fake_dev->ret_error);
}
@@ -47,9 +53,15 @@ fpi_device_fake_open (FpDevice *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);
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);
}
@@ -58,9 +70,15 @@ fpi_device_fake_close (FpDevice *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);
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);
}
@@ -70,13 +88,20 @@ fpi_device_fake_enroll (FpDevice *device)
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
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);
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);
if (!print && !fake_dev->ret_error)
fpi_device_get_enroll_data (device, &print);
fake_dev->last_called_function = fpi_device_fake_enroll;
fpi_device_enroll_complete (device,
print ? g_object_ref (print) : NULL,
fake_dev->ret_error);
@@ -88,15 +113,29 @@ fpi_device_fake_verify (FpDevice *device)
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
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);
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);
if (!print && !fake_dev->ret_error)
fpi_device_get_verify_data (device, &print);
fake_dev->last_called_function = fpi_device_fake_verify;
fpi_device_verify_complete (device, fake_dev->ret_result, print,
fake_dev->ret_error);
if (!fake_dev->ret_error || fake_dev->ret_error->domain == FP_DEVICE_RETRY)
{
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
@@ -105,7 +144,15 @@ fpi_device_fake_identify (FpDevice *device)
FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device);
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);
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);
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;
fpi_device_identify_complete (device, match, fake_dev->ret_print,
fake_dev->ret_error);
if (!fake_dev->ret_error || fake_dev->ret_error->domain == FP_DEVICE_RETRY)
{
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
@@ -137,10 +190,16 @@ fpi_device_fake_capture (FpDevice *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;
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);
}
@@ -149,9 +208,15 @@ fpi_device_fake_list (FpDevice *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);
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);
}
@@ -160,10 +225,16 @@ fpi_device_fake_delete (FpDevice *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;
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);
}
@@ -172,9 +243,8 @@ fpi_device_fake_cancel (FpDevice *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;
g_assert_cmpuint (fpi_device_get_current_action (device), !=, FPI_DEVICE_ACTION_NONE);
}
static void
+1
View File
@@ -30,6 +30,7 @@ struct _FpiDeviceFake
FpDevice parent;
gpointer last_called_function;
gboolean return_action_error;
GError *ret_error;
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)
+79 -38
View File
@@ -1,20 +1,24 @@
#!/usr/bin/env python3
import gi
gi.require_version('FPrint', '2.0')
from gi.repository import FPrint, GLib, Gio
import os
import sys
import unittest
import socket
import struct
import subprocess
import shutil
import glob
import cairo
import tempfile
try:
import gi
gi.require_version('FPrint', '2.0')
from gi.repository import FPrint, GLib, Gio
import os
import sys
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
wrapper = os.getenv('LIBFPRINT_TEST_WRAPPER')
@@ -97,15 +101,13 @@ class VirtualImage(unittest.TestCase):
del self.con
self.dev.close_sync()
def send_retry(self, retry_error=1, iterate=True):
# The default (1) is too-short
self.sendall(struct.pack('ii', -1, retry_error))
def send_retry(self, retry_error=FPrint.DeviceRetry.TOO_SHORT, iterate=True):
self.con.sendall(struct.pack('ii', -1, retry_error))
while iterate and ctx.pending():
ctx.iteration(False)
def send_error(self, device_error=0, iterate=True):
# The default (0) is a generic error
self.sendall(struct.pack('ii', -1, retry_error))
def send_error(self, device_error=FPrint.DeviceError.GENERAL, iterate=True):
self.con.sendall(struct.pack('ii', -2, device_error))
while iterate and ctx.pending():
ctx.iteration(False)
@@ -212,15 +214,16 @@ class VirtualImage(unittest.TestCase):
done = False
def verify_cb(dev, res):
match, fp = dev.verify_finish(res)
self._verify_match = match
self._verify_fp = fp
try:
self._verify_match, self._verify_fp = dev.verify_finish(res)
except gi.repository.GLib.Error as e:
self._verify_error = e
fp_whorl = self.enroll_print('whorl')
self._verify_match = 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')
while self._verify_match is None:
ctx.iteration(True)
@@ -228,41 +231,79 @@ class VirtualImage(unittest.TestCase):
self._verify_match = 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')
while self._verify_match is None:
ctx.iteration(True)
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):
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_tented_arch = self.enroll_print('tented_arch')
def identify_cb(dev, res):
print('Identify finished')
self._identify_match, self._identify_fp = self.dev.identify_finish(res)
try:
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.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')
while self._identify_fp is None:
ctx.iteration(True)
assert(self._identify_match is fp_tented_arch)
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')
while self._identify_fp is None:
ctx.iteration(True)
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):
done = False
@@ -290,7 +331,7 @@ class VirtualImage(unittest.TestCase):
self._verify_match = 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')
while self._verify_match is None:
ctx.iteration(True)
@@ -298,12 +339,12 @@ class VirtualImage(unittest.TestCase):
self._verify_match = 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')
while self._verify_match is None:
ctx.iteration(True)
assert(not self._verify_match)
# avoid writing to stderr
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))
if __name__ == '__main__':
# avoid writing to stderr
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))