2019-07-03 21:29:05 +00:00
|
|
|
/*
|
|
|
|
* FpImageDevice - An image based fingerprint reader device
|
|
|
|
* Copyright (C) 2019 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
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define FP_COMPONENT "image_device"
|
|
|
|
#include "fpi-log.h"
|
|
|
|
|
2019-12-11 12:40:47 +00:00
|
|
|
#include "fp-image-device-private.h"
|
2019-07-03 21:29:05 +00:00
|
|
|
|
|
|
|
#define BOZORTH3_DEFAULT_THRESHOLD 40
|
|
|
|
|
|
|
|
/**
|
|
|
|
* SECTION: fp-image-device
|
|
|
|
* @title: FpImageDevice
|
|
|
|
* @short_description: Image device subclass
|
|
|
|
*
|
|
|
|
* This is a helper class for the commonly found image based devices.
|
|
|
|
*/
|
|
|
|
|
|
|
|
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpImageDevice, fp_image_device, FP_TYPE_DEVICE)
|
|
|
|
|
2019-11-22 12:51:16 +00:00
|
|
|
enum {
|
|
|
|
PROP_0,
|
|
|
|
PROP_FPI_STATE,
|
|
|
|
N_PROPS
|
|
|
|
};
|
|
|
|
|
|
|
|
static GParamSpec *properties[N_PROPS];
|
2019-07-03 21:29:05 +00:00
|
|
|
|
2019-11-22 13:50:48 +00:00
|
|
|
enum {
|
|
|
|
FPI_STATE_CHANGED,
|
|
|
|
|
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
2019-07-03 21:29:05 +00:00
|
|
|
/*******************************************************/
|
|
|
|
|
|
|
|
/* TODO:
|
|
|
|
* - sanitize_image seems a bit odd, in particular the sizing stuff.
|
|
|
|
**/
|
|
|
|
|
|
|
|
/* Static helper functions */
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
pending_activation_timeout (gpointer user_data)
|
|
|
|
{
|
|
|
|
FpImageDevice *self = FP_IMAGE_DEVICE (user_data);
|
|
|
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
|
|
|
|
|
|
priv->pending_activation_timeout_id = 0;
|
|
|
|
|
|
|
|
if (priv->pending_activation_timeout_waiting_finger_off)
|
|
|
|
fpi_device_action_error (FP_DEVICE (self),
|
|
|
|
fpi_device_retry_new_msg (FP_DEVICE_RETRY_REMOVE_FINGER,
|
|
|
|
"Remove finger before requesting another scan operation"));
|
|
|
|
else
|
|
|
|
fpi_device_action_error (FP_DEVICE (self),
|
|
|
|
fpi_device_retry_new (FP_DEVICE_RETRY_GENERAL));
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Callbacks/vfuncs */
|
|
|
|
static void
|
|
|
|
fp_image_device_open (FpDevice *device)
|
|
|
|
{
|
|
|
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
|
|
|
|
|
|
|
|
/* Nothing special about opening an image device, just
|
|
|
|
* forward the request. */
|
|
|
|
cls->img_open (FP_IMAGE_DEVICE (device));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fp_image_device_close (FpDevice *device)
|
|
|
|
{
|
|
|
|
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
|
|
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
|
|
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
|
|
|
|
|
|
/* In the close case we may need to wait/force deactivation first.
|
|
|
|
* Three possible cases:
|
|
|
|
* 1. We are inactive
|
|
|
|
* -> immediately close
|
|
|
|
* 2. We are waiting for finger off
|
2020-04-14 11:50:07 +00:00
|
|
|
* -> immediately deactivate
|
2019-07-03 21:29:05 +00:00
|
|
|
* 3. We are deactivating
|
|
|
|
* -> handled by deactivate_complete */
|
|
|
|
|
|
|
|
if (!priv->active)
|
|
|
|
cls->img_close (self);
|
2019-12-16 21:45:00 +00:00
|
|
|
else if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE)
|
2019-12-11 12:40:47 +00:00
|
|
|
fpi_image_device_deactivate (self);
|
2019-07-03 21:29:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fp_image_device_cancel_action (FpDevice *device)
|
|
|
|
{
|
|
|
|
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
2019-12-04 18:54:07 +00:00
|
|
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
2019-12-16 21:45:00 +00:00
|
|
|
FpiDeviceAction action;
|
2019-07-03 21:29:05 +00:00
|
|
|
|
|
|
|
action = fpi_device_get_current_action (device);
|
|
|
|
|
|
|
|
/* We can only cancel capture operations, in that case, deactivate and return
|
|
|
|
* an error immediately. */
|
2019-12-16 21:45:00 +00:00
|
|
|
if (action == FPI_DEVICE_ACTION_ENROLL ||
|
|
|
|
action == FPI_DEVICE_ACTION_VERIFY ||
|
|
|
|
action == FPI_DEVICE_ACTION_IDENTIFY ||
|
|
|
|
action == FPI_DEVICE_ACTION_CAPTURE)
|
2019-07-03 21:29:05 +00:00
|
|
|
{
|
2019-12-04 18:54:07 +00:00
|
|
|
priv->cancelling = TRUE;
|
2019-12-11 12:40:47 +00:00
|
|
|
fpi_image_device_deactivate (self);
|
2019-12-04 18:54:07 +00:00
|
|
|
priv->cancelling = FALSE;
|
2019-07-03 21:29:05 +00:00
|
|
|
|
|
|
|
/* XXX: Some nicer way of doing this would be good. */
|
|
|
|
fpi_device_action_error (FP_DEVICE (self),
|
|
|
|
g_error_new (G_IO_ERROR,
|
|
|
|
G_IO_ERROR_CANCELLED,
|
|
|
|
"Device operation was cancelled"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fp_image_device_start_capture_action (FpDevice *device)
|
|
|
|
{
|
|
|
|
FpImageDevice *self = FP_IMAGE_DEVICE (device);
|
|
|
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
2019-12-16 21:45:00 +00:00
|
|
|
FpiDeviceAction action;
|
2019-07-03 21:29:05 +00:00
|
|
|
|
|
|
|
/* There is just one action that we cannot support out
|
|
|
|
* of the box, which is a capture without first waiting
|
|
|
|
* for a finger to be on the device.
|
|
|
|
*/
|
|
|
|
action = fpi_device_get_current_action (device);
|
2019-12-16 21:45:00 +00:00
|
|
|
if (action == FPI_DEVICE_ACTION_CAPTURE)
|
2019-07-03 21:29:05 +00:00
|
|
|
{
|
|
|
|
gboolean wait_for_finger;
|
|
|
|
|
|
|
|
fpi_device_get_capture_data (device, &wait_for_finger);
|
|
|
|
|
|
|
|
if (!wait_for_finger)
|
|
|
|
{
|
|
|
|
fpi_device_action_error (device, fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2019-12-16 21:45:00 +00:00
|
|
|
else if (action == FPI_DEVICE_ACTION_ENROLL)
|
2019-07-03 21:29:05 +00:00
|
|
|
{
|
|
|
|
FpPrint *enroll_print = NULL;
|
|
|
|
|
|
|
|
fpi_device_get_enroll_data (device, &enroll_print);
|
2019-12-16 21:45:00 +00:00
|
|
|
fpi_print_set_type (enroll_print, FPI_PRINT_NBIS);
|
2019-07-03 21:29:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
priv->enroll_stage = 0;
|
2019-12-04 14:50:06 +00:00
|
|
|
priv->enroll_await_on_pending = FALSE;
|
2019-07-03 21:29:05 +00:00
|
|
|
|
|
|
|
/* The device might still be deactivating from a previous call.
|
|
|
|
* In that situation, try to wait for a bit before reporting back an
|
|
|
|
* error (which will usually say that the user should remove the
|
|
|
|
* finger).
|
|
|
|
*/
|
2019-12-16 21:45:00 +00:00
|
|
|
if (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE || priv->active)
|
2019-07-03 21:29:05 +00:00
|
|
|
{
|
|
|
|
g_debug ("Got a new request while the device was still active");
|
|
|
|
g_assert (priv->pending_activation_timeout_id == 0);
|
|
|
|
priv->pending_activation_timeout_id =
|
|
|
|
g_timeout_add (100, pending_activation_timeout, device);
|
|
|
|
|
2019-12-16 21:45:00 +00:00
|
|
|
if (priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
|
2019-07-03 21:29:05 +00:00
|
|
|
priv->pending_activation_timeout_waiting_finger_off = TRUE;
|
|
|
|
else
|
|
|
|
priv->pending_activation_timeout_waiting_finger_off = FALSE;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* And activate the device; we rely on fpi_image_device_activate_complete()
|
|
|
|
* to be called when done (or immediately). */
|
2019-12-11 12:40:47 +00:00
|
|
|
fpi_image_device_activate (self);
|
2019-07-03 21:29:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************/
|
|
|
|
|
|
|
|
static void
|
|
|
|
fp_image_device_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
FpImageDevice *self = (FpImageDevice *) object;
|
|
|
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
|
|
|
|
|
|
g_assert (priv->active == FALSE);
|
2019-11-22 12:08:33 +00:00
|
|
|
g_clear_handle_id (&priv->pending_activation_timeout_id, g_source_remove);
|
2019-07-03 21:29:05 +00:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (fp_image_device_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fp_image_device_default_activate (FpImageDevice *self)
|
|
|
|
{
|
|
|
|
fpi_image_device_activate_complete (self, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fp_image_device_default_deactivate (FpImageDevice *self)
|
|
|
|
{
|
|
|
|
fpi_image_device_deactivate_complete (self, NULL);
|
|
|
|
}
|
|
|
|
|
2019-11-22 12:51:16 +00:00
|
|
|
static void
|
|
|
|
fp_image_device_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
FpImageDevice *self = FP_IMAGE_DEVICE (object);
|
|
|
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
|
|
|
case PROP_FPI_STATE:
|
|
|
|
g_value_set_enum (value, priv->state);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-02 17:46:00 +00:00
|
|
|
static void
|
|
|
|
fp_image_device_constructed (GObject *obj)
|
|
|
|
{
|
|
|
|
FpImageDevice *self = FP_IMAGE_DEVICE (obj);
|
|
|
|
FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
|
|
|
|
FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
|
|
|
|
|
|
|
|
/* Set default values. */
|
|
|
|
fpi_device_set_nr_enroll_stages (FP_DEVICE (self), IMG_ENROLL_STAGES);
|
|
|
|
|
|
|
|
priv->bz3_threshold = BOZORTH3_DEFAULT_THRESHOLD;
|
|
|
|
if (cls->bz3_threshold > 0)
|
|
|
|
priv->bz3_threshold = cls->bz3_threshold;
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (fp_image_device_parent_class)->constructed (obj);
|
|
|
|
}
|
|
|
|
|
2019-07-03 21:29:05 +00:00
|
|
|
static void
|
|
|
|
fp_image_device_class_init (FpImageDeviceClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
FpDeviceClass *fp_device_class = FP_DEVICE_CLASS (klass);
|
|
|
|
|
|
|
|
object_class->finalize = fp_image_device_finalize;
|
2019-11-22 12:51:16 +00:00
|
|
|
object_class->get_property = fp_image_device_get_property;
|
2020-01-02 17:46:00 +00:00
|
|
|
object_class->constructed = fp_image_device_constructed;
|
2019-07-03 21:29:05 +00:00
|
|
|
|
|
|
|
fp_device_class->open = fp_image_device_open;
|
|
|
|
fp_device_class->close = fp_image_device_close;
|
|
|
|
fp_device_class->enroll = fp_image_device_start_capture_action;
|
|
|
|
fp_device_class->verify = fp_image_device_start_capture_action;
|
|
|
|
fp_device_class->identify = fp_image_device_start_capture_action;
|
|
|
|
fp_device_class->capture = fp_image_device_start_capture_action;
|
|
|
|
|
|
|
|
fp_device_class->cancel = fp_image_device_cancel_action;
|
|
|
|
|
|
|
|
/* Default implementations */
|
|
|
|
klass->activate = fp_image_device_default_activate;
|
|
|
|
klass->deactivate = fp_image_device_default_deactivate;
|
2019-11-22 12:51:16 +00:00
|
|
|
|
2019-12-18 11:03:42 +00:00
|
|
|
/**
|
|
|
|
* FpImageDevice::fpi-image-device-state: (skip)
|
|
|
|
*
|
|
|
|
* This property is only for internal purposes.
|
|
|
|
*
|
|
|
|
* Stability: private
|
|
|
|
*/
|
2019-11-22 12:51:16 +00:00
|
|
|
properties[PROP_FPI_STATE] =
|
2019-12-18 11:03:42 +00:00
|
|
|
g_param_spec_enum ("fpi-image-device-state",
|
2019-11-22 12:51:16 +00:00
|
|
|
"Image Device State",
|
|
|
|
"Private: The state of the image device",
|
2019-12-16 21:45:00 +00:00
|
|
|
FPI_TYPE_IMAGE_DEVICE_STATE,
|
|
|
|
FPI_IMAGE_DEVICE_STATE_INACTIVE,
|
2019-11-22 12:51:16 +00:00
|
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
|
|
|
|
2019-12-18 11:03:42 +00:00
|
|
|
/**
|
|
|
|
* FpImageDevice::fpi-image-device-state-changed: (skip)
|
|
|
|
* @image_device: A #FpImageDevice
|
|
|
|
* @new_state: The new state of the device
|
|
|
|
*
|
|
|
|
* This signal is only for internal purposes.
|
|
|
|
*
|
|
|
|
* Stability: private
|
|
|
|
*/
|
2019-11-22 13:50:48 +00:00
|
|
|
signals[FPI_STATE_CHANGED] =
|
2019-12-18 11:03:42 +00:00
|
|
|
g_signal_new ("fpi-image-device-state-changed",
|
2019-11-22 13:50:48 +00:00
|
|
|
G_TYPE_FROM_CLASS (object_class),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (FpImageDeviceClass, change_state),
|
|
|
|
NULL, NULL, NULL,
|
2019-12-16 21:45:00 +00:00
|
|
|
G_TYPE_NONE, 1, FPI_TYPE_IMAGE_DEVICE_STATE);
|
2019-11-22 13:50:48 +00:00
|
|
|
|
2019-11-22 12:51:16 +00:00
|
|
|
g_object_class_install_properties (object_class, N_PROPS, properties);
|
2019-07-03 21:29:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
fp_image_device_init (FpImageDevice *self)
|
|
|
|
{
|
|
|
|
}
|