Introduce an early reporting mechanism for verify and match
It is a good idea to report match results early, to e.g. log in a user immediately even if more device interaction is needed. Add new _full variants for the verify/identify functions, with a corresponding callback. Also move driver result reporting into new fpi_device_{identify,verify}_report functions and remove the reporting from the fpi_device_{identify,verify}_complete calls. Basic updates to code is done in places. Only the upekts driver is actually modified from a behaviour point of view. The image driver code should be restructured quite a bit to split the reporting and only report completion after device deactivation. This should simplifiy the code quite a bit again.
This commit is contained in:
parent
8292c449f7
commit
4d5c34e11a
13 changed files with 385 additions and 102 deletions
|
@ -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>
|
||||
|
|
|
@ -152,6 +152,7 @@ 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,
|
||||
NULL, NULL, NULL,
|
||||
(GAsyncReadyCallback) on_verify_completed,
|
||||
verify_data);
|
||||
}
|
||||
|
@ -205,6 +206,7 @@ start_verification (FpDevice *dev, VerifyData *verify_data)
|
|||
|
||||
g_print ("Print loaded. Time to verify!\n");
|
||||
fp_device_verify (dev, verify_print, NULL,
|
||||
NULL, NULL, NULL,
|
||||
(GAsyncReadyCallback) on_verify_completed,
|
||||
verify_data);
|
||||
}
|
||||
|
|
|
@ -592,16 +592,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;
|
||||
}
|
||||
|
||||
|
@ -638,21 +635,21 @@ verify_msg_cb (FpiDeviceSynaptics *self,
|
|||
{
|
||||
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_report (device, FPI_MATCH_FAIL, NULL, NULL);
|
||||
fpi_device_verify_complete (device, NULL);
|
||||
}
|
||||
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 +672,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;
|
||||
}
|
||||
|
|
|
@ -832,7 +832,7 @@ initsm_done (FpiSsm *ssm, FpDevice *dev, GError *error)
|
|||
}
|
||||
|
||||
static FpiSsm *
|
||||
deinitsm_new (FpDevice *dev)
|
||||
deinitsm_new (FpDevice *dev, void *user_data)
|
||||
{
|
||||
return fpi_ssm_new (dev, deinitsm_state_handler, DEINITSM_NUM_STATES);
|
||||
}
|
||||
|
@ -988,7 +988,7 @@ static void
|
|||
do_enroll_stop (FpDevice *dev, FpPrint *print, GError *error)
|
||||
{
|
||||
EnrollStopData *data = g_new0 (EnrollStopData, 1);
|
||||
FpiSsm *ssm = deinitsm_new (dev);
|
||||
FpiSsm *ssm = deinitsm_new (dev, data);
|
||||
|
||||
data->print = g_object_ref (print);
|
||||
data->error = error;
|
||||
|
@ -1225,8 +1225,7 @@ enroll (FpDevice *dev)
|
|||
|
||||
typedef struct
|
||||
{
|
||||
FpiMatchResult res;
|
||||
GError *error;
|
||||
GError *error;
|
||||
} VerifyStopData;
|
||||
|
||||
static void
|
||||
|
@ -1244,17 +1243,25 @@ 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
|
||||
do_verify_stop (FpDevice *dev, FpiMatchResult res, GError *error)
|
||||
{
|
||||
VerifyStopData *data = g_new0 (VerifyStopData, 1);
|
||||
FpiSsm *ssm = deinitsm_new (dev);
|
||||
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -809,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().
|
||||
*/
|
||||
|
@ -820,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))
|
||||
|
@ -848,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);
|
||||
}
|
||||
|
@ -886,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);
|
||||
}
|
||||
|
@ -902,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
|
||||
*
|
||||
|
@ -913,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))
|
||||
|
@ -941,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);
|
||||
}
|
||||
|
@ -974,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);
|
||||
}
|
||||
|
@ -1332,6 +1364,7 @@ fp_device_verify_sync (FpDevice *device,
|
|||
fp_device_verify (device,
|
||||
enrolled_print,
|
||||
cancellable,
|
||||
NULL, NULL, NULL,
|
||||
async_result_ready, &task);
|
||||
while (!task)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
@ -1367,6 +1400,7 @@ fp_device_identify_sync (FpDevice *device,
|
|||
fp_device_identify (device,
|
||||
prints,
|
||||
cancellable,
|
||||
NULL, NULL, NULL,
|
||||
async_result_ready, &task);
|
||||
while (!task)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
|
|
@ -125,6 +125,30 @@ typedef void (*FpEnrollProgress) (FpDevice *device,
|
|||
gpointer user_data,
|
||||
GError *error);
|
||||
|
||||
/**
|
||||
* FpMatchCb:
|
||||
* @device: a #FpDevice
|
||||
* @success: Whether a print was retrieved, %FALSE means @error is set
|
||||
* @match: (nullable) (transfer none): The matching 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. This callback
|
||||
* because it makes sense for drivers to wait e.g. on finger removal before
|
||||
* finishing the operation. However, the success/failure can often be reported
|
||||
* at an earlier time, and there is no need to make the user wait.
|
||||
*
|
||||
* The passed error is guaranteed to be of type %FP_DEVICE_RETRY if set. Actual
|
||||
* error conditions will not be reported using this function. Such an error may
|
||||
* still happen even if this callback has been called.
|
||||
*/
|
||||
typedef void (*FpMatchCb) (FpDevice *device,
|
||||
gboolean success,
|
||||
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 +184,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);
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
@ -907,67 +932,65 @@ fpi_device_enroll_complete (FpDevice *device, FpPrint *print, GError *error)
|
|||
/**
|
||||
* fpi_device_verify_complete:
|
||||
* @device: The #FpDevice
|
||||
* @result: The #FpiMatchResult of the operation
|
||||
* @print: (transfer floating) 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");
|
||||
|
||||
data = g_task_get_task_data (priv->current_task);
|
||||
|
||||
clear_device_cancel_action (device);
|
||||
|
||||
if (print)
|
||||
g_object_ref_sink (print);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (priv->current_task),
|
||||
"print",
|
||||
print,
|
||||
g_object_unref);
|
||||
|
||||
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; reporting operation 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: (transfer none): The matching #FpPrint from the passed gallery, or %NULL if none matched
|
||||
* @print: (transfer floating): The scanned #FpPrint, may be %NULL
|
||||
* @error: The #GError or %NULL on success
|
||||
*
|
||||
* Finish an ongoing identify operation. The match that was identified is
|
||||
|
@ -976,46 +999,47 @@ 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);
|
||||
|
||||
if (match)
|
||||
g_object_ref (match);
|
||||
|
||||
if (print)
|
||||
g_object_ref_sink (print);
|
||||
|
||||
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; reporting operation 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1187,3 +1211,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->error == NULL, 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->error == NULL, data->match, data->print, data->match_data, data->error);
|
||||
}
|
||||
|
|
|
@ -229,13 +229,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,
|
||||
|
@ -250,5 +246,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
|
||||
|
|
|
@ -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)
|
||||
|
@ -231,7 +233,9 @@ fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, g
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -95,8 +95,16 @@ fpi_device_fake_verify (FpDevice *device)
|
|||
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
|
||||
|
@ -128,8 +136,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
|
||||
|
|
|
@ -1166,12 +1166,12 @@ test_driver_complete_actions_errors (void)
|
|||
|
||||
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||||
"*assertion*current_action*failed");
|
||||
fpi_device_verify_complete (device, FPI_MATCH_FAIL, NULL, NULL);
|
||||
fpi_device_verify_complete (device, NULL);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||||
"*assertion*current_action*failed");
|
||||
fpi_device_identify_complete (device, NULL, NULL, NULL);
|
||||
fpi_device_identify_complete (device, NULL);
|
||||
g_test_assert_expected_messages ();
|
||||
|
||||
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
|
||||
|
|
|
@ -220,7 +220,7 @@ 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('whorl')
|
||||
while self._verify_match is None:
|
||||
ctx.iteration(True)
|
||||
|
@ -228,7 +228,7 @@ 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)
|
||||
|
@ -250,14 +250,14 @@ class VirtualImage(unittest.TestCase):
|
|||
self._identify_match, self._identify_fp = self.dev.identify_finish(res)
|
||||
|
||||
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)
|
||||
|
@ -290,7 +290,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,7 +298,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('tented_arch')
|
||||
while self._verify_match is None:
|
||||
ctx.iteration(True)
|
||||
|
|
Loading…
Reference in a new issue