41f8737b48
We can avoid having multiple device feature-check functions now and just rely on a few. Add uncrustify config to properly handle begin/end deprecation macros.
1717 lines
51 KiB
C
1717 lines
51 KiB
C
/*
|
|
* FpDevice - A fingerprint reader device
|
|
* Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
|
|
* Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.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 "device"
|
|
#include "fpi-log.h"
|
|
|
|
#include "fp-device-private.h"
|
|
|
|
/**
|
|
* SECTION: fp-device
|
|
* @title: FpDevice
|
|
* @short_description: Fingerpint device routines
|
|
*
|
|
* These are the public #FpDevice routines.
|
|
*/
|
|
|
|
static void fp_device_async_initable_iface_init (GAsyncInitableIface *iface);
|
|
|
|
G_DEFINE_TYPE_EXTENDED (FpDevice, fp_device, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT,
|
|
G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
|
|
fp_device_async_initable_iface_init)
|
|
G_ADD_PRIVATE (FpDevice))
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_DRIVER,
|
|
PROP_DEVICE_ID,
|
|
PROP_NAME,
|
|
PROP_OPEN,
|
|
PROP_REMOVED,
|
|
PROP_NR_ENROLL_STAGES,
|
|
PROP_SCAN_TYPE,
|
|
PROP_FINGER_STATUS,
|
|
PROP_FPI_ENVIRON,
|
|
PROP_FPI_USB_DEVICE,
|
|
PROP_FPI_UDEV_DATA_SPIDEV,
|
|
PROP_FPI_UDEV_DATA_HIDRAW,
|
|
PROP_FPI_DRIVER_DATA,
|
|
N_PROPS
|
|
};
|
|
|
|
static GParamSpec *properties[N_PROPS];
|
|
|
|
enum {
|
|
REMOVED_SIGNAL,
|
|
N_SIGNALS
|
|
};
|
|
|
|
static guint signals[N_SIGNALS] = { 0, };
|
|
|
|
/**
|
|
* fp_device_retry_quark:
|
|
*
|
|
* Return value: Quark representing a retryable error.
|
|
**/
|
|
G_DEFINE_QUARK (fp - device - retry - quark, fp_device_retry)
|
|
|
|
/**
|
|
* fp_device_error_quark:
|
|
*
|
|
* Return value: Quark representing a device error.
|
|
**/
|
|
G_DEFINE_QUARK (fp - device - error - quark, fp_device_error)
|
|
|
|
static gboolean
|
|
fp_device_cancel_in_idle_cb (gpointer user_data)
|
|
{
|
|
FpDevice *self = user_data;
|
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (self);
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (self);
|
|
|
|
g_assert (cls->cancel);
|
|
g_assert (priv->current_action != FPI_DEVICE_ACTION_NONE);
|
|
|
|
g_debug ("Idle cancelling on ongoing operation!");
|
|
|
|
priv->current_idle_cancel_source = NULL;
|
|
|
|
cls->cancel (self);
|
|
|
|
fpi_device_report_finger_status (self, FP_FINGER_STATUS_NONE);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
/* Notify the class that the task was cancelled; this should be connected
|
|
* with the GTask as the user_data object for automatic cleanup together
|
|
* with the task. */
|
|
static void
|
|
fp_device_cancelled_cb (GCancellable *cancellable, FpDevice *self)
|
|
{
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (self);
|
|
|
|
priv->current_idle_cancel_source = g_idle_source_new ();
|
|
g_source_set_callback (priv->current_idle_cancel_source,
|
|
fp_device_cancel_in_idle_cb,
|
|
self,
|
|
NULL);
|
|
g_source_attach (priv->current_idle_cancel_source, NULL);
|
|
g_source_unref (priv->current_idle_cancel_source);
|
|
}
|
|
|
|
static void
|
|
maybe_cancel_on_cancelled (FpDevice *device,
|
|
GCancellable *cancellable)
|
|
{
|
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
|
|
if (!cancellable || !cls->cancel)
|
|
return;
|
|
|
|
priv->current_cancellable_id = g_cancellable_connect (cancellable,
|
|
G_CALLBACK (fp_device_cancelled_cb),
|
|
device,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
fp_device_constructed (GObject *object)
|
|
{
|
|
FpDevice *self = (FpDevice *) object;
|
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (self);
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (self);
|
|
|
|
g_assert (cls->features != FP_DEVICE_FEATURE_NONE);
|
|
|
|
priv->type = cls->type;
|
|
if (cls->nr_enroll_stages)
|
|
priv->nr_enroll_stages = cls->nr_enroll_stages;
|
|
priv->scan_type = cls->scan_type;
|
|
priv->device_name = g_strdup (cls->full_name);
|
|
priv->device_id = g_strdup ("0");
|
|
|
|
G_OBJECT_CLASS (fp_device_parent_class)->constructed (object);
|
|
}
|
|
|
|
static void
|
|
fp_device_finalize (GObject *object)
|
|
{
|
|
FpDevice *self = (FpDevice *) object;
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (self);
|
|
|
|
g_assert (priv->current_action == FPI_DEVICE_ACTION_NONE);
|
|
g_assert (priv->current_task == NULL);
|
|
if (priv->is_open)
|
|
g_warning ("User destroyed open device! Not cleaning up properly!");
|
|
|
|
g_slist_free_full (priv->sources, (GDestroyNotify) g_source_destroy);
|
|
|
|
g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy);
|
|
g_clear_pointer (&priv->current_task_idle_return_source, g_source_destroy);
|
|
|
|
g_clear_pointer (&priv->device_id, g_free);
|
|
g_clear_pointer (&priv->device_name, g_free);
|
|
|
|
g_clear_object (&priv->usb_device);
|
|
g_clear_pointer (&priv->virtual_env, g_free);
|
|
g_clear_pointer (&priv->udev_data.spidev_path, g_free);
|
|
g_clear_pointer (&priv->udev_data.hidraw_path, g_free);
|
|
|
|
G_OBJECT_CLASS (fp_device_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
fp_device_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
FpDevice *self = FP_DEVICE (object);
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (self);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_NR_ENROLL_STAGES:
|
|
g_value_set_uint (value, priv->nr_enroll_stages);
|
|
break;
|
|
|
|
case PROP_SCAN_TYPE:
|
|
g_value_set_enum (value, priv->scan_type);
|
|
break;
|
|
|
|
case PROP_FINGER_STATUS:
|
|
g_value_set_flags (value, priv->finger_status);
|
|
break;
|
|
|
|
case PROP_DRIVER:
|
|
g_value_set_static_string (value, FP_DEVICE_GET_CLASS (self)->id);
|
|
break;
|
|
|
|
case PROP_DEVICE_ID:
|
|
g_value_set_string (value, priv->device_id);
|
|
break;
|
|
|
|
case PROP_NAME:
|
|
g_value_set_string (value, priv->device_name);
|
|
break;
|
|
|
|
case PROP_OPEN:
|
|
g_value_set_boolean (value, priv->is_open);
|
|
break;
|
|
|
|
case PROP_REMOVED:
|
|
g_value_set_boolean (value, priv->is_removed);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_device_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
FpDevice *self = FP_DEVICE (object);
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (self);
|
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (self);
|
|
|
|
/* _construct has not run yet, so we cannot use priv->type. */
|
|
switch (prop_id)
|
|
{
|
|
case PROP_FPI_ENVIRON:
|
|
if (cls->type == FP_DEVICE_TYPE_VIRTUAL)
|
|
priv->virtual_env = g_value_dup_string (value);
|
|
else
|
|
g_assert (g_value_get_string (value) == NULL);
|
|
break;
|
|
|
|
case PROP_FPI_USB_DEVICE:
|
|
if (cls->type == FP_DEVICE_TYPE_USB)
|
|
priv->usb_device = g_value_dup_object (value);
|
|
else
|
|
g_assert (g_value_get_object (value) == NULL);
|
|
break;
|
|
|
|
case PROP_FPI_UDEV_DATA_SPIDEV:
|
|
if (cls->type == FP_DEVICE_TYPE_UDEV)
|
|
priv->udev_data.spidev_path = g_value_dup_string (value);
|
|
else
|
|
g_assert (g_value_get_string (value) == NULL);
|
|
break;
|
|
|
|
case PROP_FPI_UDEV_DATA_HIDRAW:
|
|
if (cls->type == FP_DEVICE_TYPE_UDEV)
|
|
priv->udev_data.hidraw_path = g_value_dup_string (value);
|
|
else
|
|
g_assert (g_value_get_string (value) == NULL);
|
|
break;
|
|
|
|
case PROP_FPI_DRIVER_DATA:
|
|
priv->driver_data = g_value_get_uint64 (value);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fp_device_async_initable_init_async (GAsyncInitable *initable,
|
|
int io_priority,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr(GTask) task = NULL;
|
|
FpDevice *self = FP_DEVICE (initable);
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (self);
|
|
|
|
/* It is next to impossible to call async_init at the wrong time. */
|
|
g_assert (!priv->is_open);
|
|
g_assert (!priv->current_task);
|
|
|
|
task = g_task_new (self, cancellable, callback, user_data);
|
|
if (g_task_return_error_if_cancelled (task))
|
|
return;
|
|
|
|
if (!FP_DEVICE_GET_CLASS (self)->probe)
|
|
{
|
|
g_task_return_boolean (task, TRUE);
|
|
return;
|
|
}
|
|
|
|
priv->current_action = FPI_DEVICE_ACTION_PROBE;
|
|
priv->current_task = g_steal_pointer (&task);
|
|
maybe_cancel_on_cancelled (self, cancellable);
|
|
|
|
FP_DEVICE_GET_CLASS (self)->probe (self);
|
|
}
|
|
|
|
static gboolean
|
|
fp_device_async_initable_init_finish (GAsyncInitable *initable,
|
|
GAsyncResult *res,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_boolean (G_TASK (res), error);
|
|
}
|
|
|
|
static void
|
|
fp_device_async_initable_iface_init (GAsyncInitableIface *iface)
|
|
{
|
|
iface->init_async = fp_device_async_initable_init_async;
|
|
iface->init_finish = fp_device_async_initable_init_finish;
|
|
}
|
|
|
|
static void
|
|
fp_device_class_init (FpDeviceClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->constructed = fp_device_constructed;
|
|
object_class->finalize = fp_device_finalize;
|
|
object_class->get_property = fp_device_get_property;
|
|
object_class->set_property = fp_device_set_property;
|
|
|
|
properties[PROP_NR_ENROLL_STAGES] =
|
|
g_param_spec_uint ("nr-enroll-stages",
|
|
"EnrollStages",
|
|
"Number of enroll stages needed on the device",
|
|
0, G_MAXUINT,
|
|
0,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
|
|
|
properties[PROP_SCAN_TYPE] =
|
|
g_param_spec_enum ("scan-type",
|
|
"ScanType",
|
|
"The scan type of the device",
|
|
FP_TYPE_SCAN_TYPE, FP_SCAN_TYPE_SWIPE,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
|
|
|
properties[PROP_FINGER_STATUS] =
|
|
g_param_spec_flags ("finger-status",
|
|
"FingerStatus",
|
|
"The status of the finger",
|
|
FP_TYPE_FINGER_STATUS_FLAGS, FP_FINGER_STATUS_NONE,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
|
|
|
properties[PROP_DRIVER] =
|
|
g_param_spec_string ("driver",
|
|
"Driver",
|
|
"String describing the driver",
|
|
NULL,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
|
|
|
properties[PROP_DEVICE_ID] =
|
|
g_param_spec_string ("device-id",
|
|
"Device ID",
|
|
"String describing the device, often generic but may be a serial number",
|
|
"",
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
|
|
|
properties[PROP_NAME] =
|
|
g_param_spec_string ("name",
|
|
"Device Name",
|
|
"Human readable name for the device",
|
|
NULL,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
|
|
|
properties[PROP_OPEN] =
|
|
g_param_spec_boolean ("open",
|
|
"Opened",
|
|
"Whether the device is open or not", FALSE,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
|
|
|
properties[PROP_REMOVED] =
|
|
g_param_spec_boolean ("removed",
|
|
"Removed",
|
|
"Whether the device has been removed from the system", FALSE,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
|
|
|
|
/**
|
|
* FpDevice::removed:
|
|
* @device: the #FpDevice instance that emitted the signal
|
|
*
|
|
* This signal is emitted after the device has been removed and no operation
|
|
* is pending anymore.
|
|
*
|
|
* The API user is still required to close a removed device. The above
|
|
* guarantee means that the call to close the device can be made immediately
|
|
* from the signal handler.
|
|
*
|
|
* The close operation will return FP_DEVICE_ERROR_REMOVED, but the device
|
|
* will still be considered closed afterwards.
|
|
*
|
|
* The device will only be removed from the #FpContext after it has been
|
|
* closed by the API user.
|
|
**/
|
|
signals[REMOVED_SIGNAL] = g_signal_new ("removed",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
g_cclosure_marshal_VOID__VOID,
|
|
G_TYPE_NONE,
|
|
0);
|
|
|
|
/* Private properties */
|
|
|
|
/**
|
|
* FpDevice::fpi-environ: (skip)
|
|
*
|
|
* This property is only for internal purposes.
|
|
*
|
|
* Stability: private
|
|
*/
|
|
properties[PROP_FPI_ENVIRON] =
|
|
g_param_spec_string ("fpi-environ",
|
|
"Virtual Environment",
|
|
"Private: The environment variable for the virtual device",
|
|
NULL,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
|
|
|
/**
|
|
* FpDevice::fpi-usb-device: (skip)
|
|
*
|
|
* This property is only for internal purposes.
|
|
*
|
|
* Stability: private
|
|
*/
|
|
properties[PROP_FPI_USB_DEVICE] =
|
|
g_param_spec_object ("fpi-usb-device",
|
|
"USB Device",
|
|
"Private: The USB device for the device",
|
|
G_USB_TYPE_DEVICE,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
|
/**
|
|
* FpDevice::fpi-udev-data-spidev: (skip)
|
|
*
|
|
* This property is only for internal purposes.
|
|
*
|
|
* Stability: private
|
|
*/
|
|
properties[PROP_FPI_UDEV_DATA_SPIDEV] =
|
|
g_param_spec_string ("fpi-udev-data-spidev",
|
|
"Udev data: spidev path",
|
|
"Private: The path to /dev/spidevN.M",
|
|
NULL,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
|
/**
|
|
* FpDevice::fpi-udev-data-hidraw: (skip)
|
|
*
|
|
* This property is only for internal purposes.
|
|
*
|
|
* Stability: private
|
|
*/
|
|
properties[PROP_FPI_UDEV_DATA_HIDRAW] =
|
|
g_param_spec_string ("fpi-udev-data-hidraw",
|
|
"Udev data: hidraw path",
|
|
"Private: The path to /dev/hidrawN",
|
|
NULL,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
|
|
|
/**
|
|
* FpDevice::fpi-driver-data: (skip)
|
|
*
|
|
* This property is only for internal purposes.
|
|
*
|
|
* Stability: private
|
|
*/
|
|
properties[PROP_FPI_DRIVER_DATA] =
|
|
g_param_spec_uint64 ("fpi-driver-data",
|
|
"Driver Data",
|
|
"Private: The driver data from the ID table entry",
|
|
0,
|
|
G_MAXUINT64,
|
|
0,
|
|
G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
|
|
|
g_object_class_install_properties (object_class, N_PROPS, properties);
|
|
}
|
|
|
|
static void
|
|
fp_device_init (FpDevice *self)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* fp_device_get_driver:
|
|
* @device: A #FpDevice
|
|
*
|
|
* Returns: (transfer none): The ID of the driver
|
|
*/
|
|
const gchar *
|
|
fp_device_get_driver (FpDevice *device)
|
|
{
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
|
|
|
|
return FP_DEVICE_GET_CLASS (device)->id;
|
|
}
|
|
|
|
/**
|
|
* fp_device_get_device_id:
|
|
* @device: A #FpDevice
|
|
*
|
|
* Returns: (transfer none): The ID of the device
|
|
*/
|
|
const gchar *
|
|
fp_device_get_device_id (FpDevice *device)
|
|
{
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
|
|
|
|
return priv->device_id;
|
|
}
|
|
|
|
/**
|
|
* fp_device_get_name:
|
|
* @device: A #FpDevice
|
|
*
|
|
* Returns: (transfer none): The human readable name of the device
|
|
*/
|
|
const gchar *
|
|
fp_device_get_name (FpDevice *device)
|
|
{
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
|
|
|
|
return priv->device_name;
|
|
}
|
|
|
|
/**
|
|
* fp_device_is_open:
|
|
* @device: A #FpDevice
|
|
*
|
|
* Returns: Whether the device is open or not
|
|
*/
|
|
gboolean
|
|
fp_device_is_open (FpDevice *device)
|
|
{
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
return priv->is_open;
|
|
}
|
|
|
|
/**
|
|
* fp_device_get_scan_type:
|
|
* @device: A #FpDevice
|
|
*
|
|
* Retrieves the scan type of the device.
|
|
*
|
|
* Returns: The #FpScanType
|
|
*/
|
|
FpScanType
|
|
fp_device_get_scan_type (FpDevice *device)
|
|
{
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FP_SCAN_TYPE_SWIPE);
|
|
|
|
return priv->scan_type;
|
|
}
|
|
|
|
/**
|
|
* fp_device_get_finger_status:
|
|
* @device: A #FpDevice
|
|
*
|
|
* Retrieves the finger status flags for the device.
|
|
* This can be used by the UI to present the relevant feedback, although it
|
|
* is not guaranteed to be a relevant value when not performing any action.
|
|
*
|
|
* Returns: The current #FpFingerStatusFlags
|
|
*/
|
|
FpFingerStatusFlags
|
|
fp_device_get_finger_status (FpDevice *device)
|
|
{
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FP_FINGER_STATUS_NONE);
|
|
|
|
return priv->finger_status;
|
|
}
|
|
|
|
/**
|
|
* fp_device_get_nr_enroll_stages:
|
|
* @device: A #FpDevice
|
|
*
|
|
* Retrieves the number of enroll stages for this device.
|
|
*
|
|
* Returns: The number of enroll stages
|
|
*/
|
|
gint
|
|
fp_device_get_nr_enroll_stages (FpDevice *device)
|
|
{
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), -1);
|
|
|
|
return priv->nr_enroll_stages;
|
|
}
|
|
|
|
/**
|
|
* fp_device_supports_identify:
|
|
* @device: A #FpDevice
|
|
*
|
|
* Check whether the device supports identification.
|
|
*
|
|
* Returns: Whether the device supports identification
|
|
* Deprecated: 1.92.0: Use fp_device_has_feature() instead.
|
|
*/
|
|
gboolean
|
|
fp_device_supports_identify (FpDevice *device)
|
|
{
|
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
return cls->identify && !!(cls->features & FP_DEVICE_FEATURE_IDENTIFY);
|
|
}
|
|
|
|
/**
|
|
* fp_device_supports_capture:
|
|
* @device: A #FpDevice
|
|
*
|
|
* Check whether the device supports capturing images.
|
|
*
|
|
* Returns: Whether the device supports image capture
|
|
* Deprecated: 1.92.0: Use fp_device_has_feature() instead.
|
|
*/
|
|
gboolean
|
|
fp_device_supports_capture (FpDevice *device)
|
|
{
|
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
return cls->capture && !!(cls->features & FP_DEVICE_FEATURE_CAPTURE);
|
|
}
|
|
|
|
/**
|
|
* fp_device_has_storage:
|
|
* @device: A #FpDevice
|
|
*
|
|
* Whether the device has on-chip storage. If it has, you can list the
|
|
* prints stored on the with fp_device_list_prints() and you should
|
|
* always delete prints from the device again using
|
|
* fp_device_delete_print().
|
|
* Deprecated: 1.92.0: Use fp_device_has_feature() instead.
|
|
*/
|
|
gboolean
|
|
fp_device_has_storage (FpDevice *device)
|
|
{
|
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
return !!(cls->features & FP_DEVICE_FEATURE_STORAGE);
|
|
}
|
|
|
|
/**
|
|
* fp_device_open:
|
|
* @device: a #FpDevice
|
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
* @callback: the function to call on completion
|
|
* @user_data: the data to pass to @callback
|
|
*
|
|
* Start an asynchronous operation to open the device. The callback will
|
|
* be called once the operation has finished. Retrieve the result with
|
|
* fp_device_open_finish().
|
|
*/
|
|
void
|
|
fp_device_open (FpDevice *device,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr(GTask) task = NULL;
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
GError *error = NULL;
|
|
|
|
task = g_task_new (device, cancellable, callback, user_data);
|
|
if (g_task_return_error_if_cancelled (task))
|
|
return;
|
|
|
|
if (priv->is_open)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_ALREADY_OPEN));
|
|
return;
|
|
}
|
|
|
|
if (priv->current_task)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
|
|
return;
|
|
}
|
|
|
|
switch (priv->type)
|
|
{
|
|
case FP_DEVICE_TYPE_USB:
|
|
if (!g_usb_device_open (priv->usb_device, &error))
|
|
{
|
|
g_task_return_error (task, error);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case FP_DEVICE_TYPE_VIRTUAL:
|
|
case FP_DEVICE_TYPE_UDEV:
|
|
break;
|
|
|
|
default:
|
|
g_assert_not_reached ();
|
|
g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
|
|
return;
|
|
}
|
|
|
|
priv->current_action = FPI_DEVICE_ACTION_OPEN;
|
|
priv->current_task = g_steal_pointer (&task);
|
|
maybe_cancel_on_cancelled (device, cancellable);
|
|
fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
|
|
|
|
FP_DEVICE_GET_CLASS (device)->open (device);
|
|
}
|
|
|
|
/**
|
|
* fp_device_open_finish:
|
|
* @device: A #FpDevice
|
|
* @result: A #GAsyncResult
|
|
* @error: Return location for errors, or %NULL to ignore
|
|
*
|
|
* Finish an asynchronous operation to open the device.
|
|
* See fp_device_open().
|
|
*
|
|
* Returns: (type void): %FALSE on error, %TRUE otherwise
|
|
*/
|
|
gboolean
|
|
fp_device_open_finish (FpDevice *device,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_boolean (G_TASK (result), error);
|
|
}
|
|
|
|
/**
|
|
* fp_device_close:
|
|
* @device: a #FpDevice
|
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
* @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
|
|
* be called once the operation has finished. Retrieve the result with
|
|
* fp_device_close_finish().
|
|
*/
|
|
void
|
|
fp_device_close (FpDevice *device,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr(GTask) task = NULL;
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
|
|
task = g_task_new (device, cancellable, callback, user_data);
|
|
if (g_task_return_error_if_cancelled (task))
|
|
return;
|
|
|
|
if (!priv->is_open)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
|
|
return;
|
|
}
|
|
|
|
if (priv->current_task)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
|
|
return;
|
|
}
|
|
|
|
priv->current_action = FPI_DEVICE_ACTION_CLOSE;
|
|
priv->current_task = g_steal_pointer (&task);
|
|
maybe_cancel_on_cancelled (device, cancellable);
|
|
|
|
FP_DEVICE_GET_CLASS (device)->close (device);
|
|
}
|
|
|
|
/**
|
|
* fp_device_close_finish:
|
|
* @device: A #FpDevice
|
|
* @result: A #GAsyncResult
|
|
* @error: Return location for errors, or %NULL to ignore
|
|
*
|
|
* Finish an asynchronous operation to close the device.
|
|
* See fp_device_close().
|
|
*
|
|
* Returns: (type void): %FALSE on error, %TRUE otherwise
|
|
*/
|
|
gboolean
|
|
fp_device_close_finish (FpDevice *device,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_boolean (G_TASK (result), error);
|
|
}
|
|
|
|
|
|
/**
|
|
* fp_device_enroll:
|
|
* @device: a #FpDevice
|
|
* @template_print: (transfer floating): a #FpPrint
|
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
* @progress_cb: (nullable) (scope notified): progress reporting callback
|
|
* @progress_data: (closure progress_cb): user data for @progress_cb
|
|
* @progress_destroy: (destroy progress_data): Destroy notify for @progress_data
|
|
* @callback: (scope async): the function to call on completion
|
|
* @user_data: the data to pass to @callback
|
|
*
|
|
* Start an asynchronous operation to enroll a print. The callback will
|
|
* be called once the operation has finished. Retrieve the result with
|
|
* fp_device_enroll_finish().
|
|
*
|
|
* The @template_print parameter is a #FpPrint with available metadata filled
|
|
* in. The driver may make use of this metadata, when e.g. storing the print on
|
|
* device memory. It is undefined whether this print is filled in by the driver
|
|
* and returned, or whether the driver will return a newly created print after
|
|
* enrollment succeeded.
|
|
*/
|
|
void
|
|
fp_device_enroll (FpDevice *device,
|
|
FpPrint *template_print,
|
|
GCancellable *cancellable,
|
|
FpEnrollProgress progress_cb,
|
|
gpointer progress_data,
|
|
GDestroyNotify progress_destroy,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr(GTask) task = NULL;
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
FpEnrollData *data;
|
|
FpiPrintType print_type;
|
|
|
|
task = g_task_new (device, cancellable, callback, user_data);
|
|
if (g_task_return_error_if_cancelled (task))
|
|
return;
|
|
|
|
if (!priv->is_open)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
|
|
return;
|
|
}
|
|
|
|
if (priv->current_task)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
|
|
return;
|
|
}
|
|
|
|
if (!FP_IS_PRINT (template_print))
|
|
{
|
|
g_warning ("User did not pass a print template!");
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
|
|
return;
|
|
}
|
|
|
|
g_object_get (template_print, "fpi-type", &print_type, NULL);
|
|
if (print_type != FPI_PRINT_UNDEFINED)
|
|
{
|
|
g_warning ("Passed print template must be newly created and blank!");
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_DATA_INVALID));
|
|
return;
|
|
}
|
|
|
|
priv->current_action = FPI_DEVICE_ACTION_ENROLL;
|
|
priv->current_task = g_steal_pointer (&task);
|
|
maybe_cancel_on_cancelled (device, cancellable);
|
|
|
|
data = g_new0 (FpEnrollData, 1);
|
|
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);
|
|
|
|
FP_DEVICE_GET_CLASS (device)->enroll (device);
|
|
}
|
|
|
|
/**
|
|
* fp_device_enroll_finish:
|
|
* @device: A #FpDevice
|
|
* @result: A #GAsyncResult
|
|
* @error: Return location for errors, or %NULL to ignore
|
|
*
|
|
* Finish an asynchronous operation to enroll a print. You should check
|
|
* for an error of type %FP_DEVICE_RETRY to prompt the user again if there
|
|
* was an interaction issue.
|
|
* See fp_device_enroll().
|
|
*
|
|
* Returns: (transfer full): The enrolled #FpPrint, or %NULL on error
|
|
*/
|
|
FpPrint *
|
|
fp_device_enroll_finish (FpDevice *device,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_pointer (G_TASK (result), error);
|
|
}
|
|
|
|
/**
|
|
* fp_device_verify:
|
|
* @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 verify a print. The callback will
|
|
* be called once the operation has finished. Retrieve the result with
|
|
* fp_device_verify_finish().
|
|
*/
|
|
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);
|
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
|
|
FpMatchData *data;
|
|
|
|
task = g_task_new (device, cancellable, callback, user_data);
|
|
if (g_task_return_error_if_cancelled (task))
|
|
return;
|
|
|
|
if (!priv->is_open)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
|
|
return;
|
|
}
|
|
|
|
if (priv->current_task)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
|
|
return;
|
|
}
|
|
|
|
if (!cls->verify || !(cls->features & FP_DEVICE_FEATURE_VERIFY))
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
|
|
"Device has no verification support"));
|
|
return;
|
|
}
|
|
|
|
priv->current_action = FPI_DEVICE_ACTION_VERIFY;
|
|
priv->current_task = g_steal_pointer (&task);
|
|
maybe_cancel_on_cancelled (device, cancellable);
|
|
|
|
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);
|
|
|
|
cls->verify (device);
|
|
}
|
|
|
|
/**
|
|
* fp_device_verify_finish:
|
|
* @device: A #FpDevice
|
|
* @result: A #GAsyncResult
|
|
* @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
|
|
*
|
|
* Finish an asynchronous operation to verify an enrolled print. You should check
|
|
* for an error of type %FP_DEVICE_RETRY to prompt the user again if there
|
|
* was an interaction issue.
|
|
*
|
|
* With @print you can fetch the newly created print and retrieve the image data if available.
|
|
*
|
|
* See fp_device_verify().
|
|
*
|
|
* Returns: (type void): %FALSE on error, %TRUE otherwise
|
|
*/
|
|
gboolean
|
|
fp_device_verify_finish (FpDevice *device,
|
|
GAsyncResult *result,
|
|
gboolean *match,
|
|
FpPrint **print,
|
|
GError **error)
|
|
{
|
|
gint res;
|
|
|
|
res = g_task_propagate_int (G_TASK (result), error);
|
|
|
|
if (print)
|
|
{
|
|
FpMatchData *data;
|
|
|
|
data = g_task_get_task_data (G_TASK (result));
|
|
|
|
*print = data ? data->print : NULL;
|
|
if (*print)
|
|
g_object_ref (*print);
|
|
}
|
|
|
|
if (match)
|
|
*match = res == FPI_MATCH_SUCCESS;
|
|
|
|
return res != FPI_MATCH_ERROR;
|
|
}
|
|
|
|
/**
|
|
* fp_device_identify:
|
|
* @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
|
|
*
|
|
* Start an asynchronous operation to identify prints. The callback will
|
|
* be called once the operation has finished. Retrieve the result with
|
|
* fp_device_identify_finish().
|
|
*/
|
|
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);
|
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
|
|
FpMatchData *data;
|
|
int i;
|
|
|
|
task = g_task_new (device, cancellable, callback, user_data);
|
|
if (g_task_return_error_if_cancelled (task))
|
|
return;
|
|
|
|
if (!priv->is_open)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
|
|
return;
|
|
}
|
|
|
|
if (priv->current_task)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
|
|
return;
|
|
}
|
|
|
|
if (!cls->identify || !(cls->features & FP_DEVICE_FEATURE_IDENTIFY))
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
|
|
"Device has not identification support"));
|
|
return;
|
|
}
|
|
|
|
priv->current_action = FPI_DEVICE_ACTION_IDENTIFY;
|
|
priv->current_task = g_steal_pointer (&task);
|
|
maybe_cancel_on_cancelled (device, cancellable);
|
|
|
|
data = g_new0 (FpMatchData, 1);
|
|
/* We cannot store the gallery directly, because the ptr array may not own
|
|
* a reference to each print. Also, the caller could in principle modify the
|
|
* GPtrArray afterwards.
|
|
*/
|
|
data->gallery = g_ptr_array_new_full (prints->len, g_object_unref);
|
|
for (i = 0; i < prints->len; i++)
|
|
g_ptr_array_add (data->gallery, g_object_ref (g_ptr_array_index (prints, i)));
|
|
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);
|
|
|
|
cls->identify (device);
|
|
}
|
|
|
|
/**
|
|
* fp_device_identify_finish:
|
|
* @device: A #FpDevice
|
|
* @result: A #GAsyncResult
|
|
* @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
|
|
*
|
|
* Finish an asynchronous operation to identify a print. You should check
|
|
* for an error of type %FP_DEVICE_RETRY to prompt the user again if there
|
|
* was an interaction issue.
|
|
*
|
|
* Use @match to find the print that matched. With @print you can fetch the
|
|
* newly created print and retrieve the image data if available.
|
|
*
|
|
* See fp_device_identify().
|
|
*
|
|
* Returns: (type void): %FALSE on error, %TRUE otherwise
|
|
*/
|
|
gboolean
|
|
fp_device_identify_finish (FpDevice *device,
|
|
GAsyncResult *result,
|
|
FpPrint **match,
|
|
FpPrint **print,
|
|
GError **error)
|
|
{
|
|
FpMatchData *data;
|
|
|
|
data = g_task_get_task_data (G_TASK (result));
|
|
|
|
if (print)
|
|
{
|
|
*print = data ? data->print : NULL;
|
|
if (*print)
|
|
g_object_ref (*print);
|
|
}
|
|
if (match)
|
|
{
|
|
*match = data ? data->match : NULL;
|
|
if (*match)
|
|
g_object_ref (*match);
|
|
}
|
|
|
|
return g_task_propagate_boolean (G_TASK (result), error);
|
|
}
|
|
|
|
/**
|
|
* fp_device_capture:
|
|
* @device: a #FpDevice
|
|
* @wait_for_finger: Whether to wait for a finger or not
|
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
* @callback: the function to call on completion
|
|
* @user_data: the data to pass to @callback
|
|
*
|
|
* Start an asynchronous operation to capture an image. The callback will
|
|
* be called once the operation has finished. Retrieve the result with
|
|
* fp_device_capture_finish().
|
|
*/
|
|
void
|
|
fp_device_capture (FpDevice *device,
|
|
gboolean wait_for_finger,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr(GTask) task = NULL;
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
|
|
|
|
task = g_task_new (device, cancellable, callback, user_data);
|
|
if (g_task_return_error_if_cancelled (task))
|
|
return;
|
|
|
|
if (!priv->is_open)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
|
|
return;
|
|
}
|
|
|
|
if (priv->current_task)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
|
|
return;
|
|
}
|
|
|
|
if (!cls->capture || !(cls->features & FP_DEVICE_FEATURE_CAPTURE))
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
|
|
"Device has no verification support"));
|
|
return;
|
|
}
|
|
|
|
priv->current_action = FPI_DEVICE_ACTION_CAPTURE;
|
|
priv->current_task = g_steal_pointer (&task);
|
|
maybe_cancel_on_cancelled (device, cancellable);
|
|
|
|
priv->wait_for_finger = wait_for_finger;
|
|
|
|
cls->capture (device);
|
|
}
|
|
|
|
/**
|
|
* fp_device_capture_finish:
|
|
* @device: A #FpDevice
|
|
* @result: A #GAsyncResult
|
|
* @error: Return location for errors, or %NULL to ignore
|
|
*
|
|
* Finish an asynchronous operation to capture an image. You should check
|
|
* for an error of type %FP_DEVICE_RETRY to prompt the user again if there
|
|
* was an interaction issue.
|
|
*
|
|
* See fp_device_capture().
|
|
*
|
|
* Returns: (transfer full): #FpImage or %NULL on error
|
|
*/
|
|
FpImage *
|
|
fp_device_capture_finish (FpDevice *device,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_pointer (G_TASK (result), error);
|
|
}
|
|
|
|
/**
|
|
* fp_device_delete_print:
|
|
* @device: a #FpDevice
|
|
* @enrolled_print: a #FpPrint to delete
|
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
* @callback: the function to call on completion
|
|
* @user_data: the data to pass to @callback
|
|
*
|
|
* Start an asynchronous operation to delete a print from the device.
|
|
* The callback will be called once the operation has finished. Retrieve
|
|
* the result with fp_device_delete_print_finish().
|
|
*
|
|
* This only makes sense on devices that store prints on-chip, but is safe
|
|
* to always call.
|
|
*/
|
|
void
|
|
fp_device_delete_print (FpDevice *device,
|
|
FpPrint *enrolled_print,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr(GTask) task = NULL;
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
|
|
|
|
task = g_task_new (device, cancellable, callback, user_data);
|
|
if (g_task_return_error_if_cancelled (task))
|
|
return;
|
|
|
|
if (!priv->is_open)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
|
|
return;
|
|
}
|
|
|
|
if (priv->current_task)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
|
|
return;
|
|
}
|
|
|
|
/* Succeed immediately if delete is not implemented. */
|
|
if (!cls->delete || !(cls->features & FP_DEVICE_FEATURE_STORAGE_DELETE))
|
|
{
|
|
g_task_return_boolean (task, TRUE);
|
|
return;
|
|
}
|
|
|
|
priv->current_action = FPI_DEVICE_ACTION_DELETE;
|
|
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);
|
|
|
|
cls->delete (device);
|
|
}
|
|
|
|
/**
|
|
* fp_device_delete_print_finish:
|
|
* @device: A #FpDevice
|
|
* @result: A #GAsyncResult
|
|
* @error: Return location for errors, or %NULL to ignore
|
|
*
|
|
* Finish an asynchronous operation to delete an enrolled print.
|
|
*
|
|
* See fp_device_delete_print().
|
|
*
|
|
* Returns: (type void): %FALSE on error, %TRUE otherwise
|
|
*/
|
|
gboolean
|
|
fp_device_delete_print_finish (FpDevice *device,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_boolean (G_TASK (result), error);
|
|
}
|
|
|
|
/**
|
|
* fp_device_list_prints:
|
|
* @device: a #FpDevice
|
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
* @callback: the function to call on completion
|
|
* @user_data: the data to pass to @callback
|
|
*
|
|
* Start an asynchronous operation to list all prints stored on the device.
|
|
* This only makes sense on devices that store prints on-chip.
|
|
*
|
|
* Retrieve the result with fp_device_list_prints_finish().
|
|
*/
|
|
void
|
|
fp_device_list_prints (FpDevice *device,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer user_data)
|
|
{
|
|
g_autoptr(GTask) task = NULL;
|
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
|
|
|
|
task = g_task_new (device, cancellable, callback, user_data);
|
|
if (g_task_return_error_if_cancelled (task))
|
|
return;
|
|
|
|
if (!priv->is_open)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
|
|
return;
|
|
}
|
|
|
|
if (priv->current_task)
|
|
{
|
|
g_task_return_error (task,
|
|
fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
|
|
return;
|
|
}
|
|
|
|
if (!cls->list || !(cls->features & FP_DEVICE_FEATURE_STORAGE))
|
|
{
|
|
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);
|
|
|
|
cls->list (device);
|
|
}
|
|
|
|
/**
|
|
* fp_device_list_prints_finish:
|
|
* @device: A #FpDevice
|
|
* @result: A #GAsyncResult
|
|
* @error: Return location for errors, or %NULL to ignore
|
|
*
|
|
* Finish an asynchronous operation to list all device stored prints.
|
|
*
|
|
* See fp_device_list_prints().
|
|
*
|
|
* Returns: (element-type FpPrint) (transfer container): Array of prints or %NULL on error
|
|
*/
|
|
GPtrArray *
|
|
fp_device_list_prints_finish (FpDevice *device,
|
|
GAsyncResult *result,
|
|
GError **error)
|
|
{
|
|
return g_task_propagate_pointer (G_TASK (result), error);
|
|
}
|
|
|
|
static void
|
|
async_result_ready (GObject *source_object, GAsyncResult *res, gpointer user_data)
|
|
{
|
|
GTask **task = user_data;
|
|
|
|
*task = g_object_ref (G_TASK (res));
|
|
}
|
|
|
|
/**
|
|
* fp_device_open_sync:
|
|
* @device: a #FpDevice
|
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
* @error: Return location for errors, or %NULL to ignore
|
|
*
|
|
* Open the device synchronously.
|
|
*
|
|
* Returns: (type void): %FALSE on error, %TRUE otherwise
|
|
*/
|
|
gboolean
|
|
fp_device_open_sync (FpDevice *device,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GAsyncResult) task = NULL;
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
fp_device_open (device, cancellable, async_result_ready, &task);
|
|
while (!task)
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
return fp_device_open_finish (device, task, error);
|
|
}
|
|
|
|
/**
|
|
* fp_device_close_sync:
|
|
* @device: a #FpDevice
|
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
* @error: Return location for errors, or %NULL to ignore
|
|
*
|
|
* Close the device synchronously.
|
|
*
|
|
* Returns: (type void): %FALSE on error, %TRUE otherwise
|
|
*/
|
|
gboolean
|
|
fp_device_close_sync (FpDevice *device,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GAsyncResult) task = NULL;
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
fp_device_close (device, cancellable, async_result_ready, &task);
|
|
while (!task)
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
return fp_device_close_finish (device, task, error);
|
|
}
|
|
|
|
/**
|
|
* fp_device_enroll_sync:
|
|
* @device: a #FpDevice
|
|
* @template_print: (transfer floating): A #FpPrint to fill in or use
|
|
* as a template.
|
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
* @progress_cb: (nullable) (scope call): progress reporting callback
|
|
* @progress_data: user data for @progress_cb
|
|
* @error: Return location for errors, or %NULL to ignore
|
|
*
|
|
* Enroll a new print. See fp_device_enroll(). It is undefined whether
|
|
* @template_print is updated or a newly created #FpPrint is returned.
|
|
*
|
|
* Returns:(transfer full): A #FpPrint on success, %NULL otherwise
|
|
*/
|
|
FpPrint *
|
|
fp_device_enroll_sync (FpDevice *device,
|
|
FpPrint *template_print,
|
|
GCancellable *cancellable,
|
|
FpEnrollProgress progress_cb,
|
|
gpointer progress_data,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GAsyncResult) task = NULL;
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
fp_device_enroll (device, template_print, cancellable,
|
|
progress_cb, progress_data, NULL,
|
|
async_result_ready, &task);
|
|
while (!task)
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
return fp_device_enroll_finish (device, task, error);
|
|
}
|
|
|
|
/**
|
|
* fp_device_verify_sync:
|
|
* @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
|
|
*
|
|
* Verify a given print synchronously.
|
|
*
|
|
* Returns: (type void): %FALSE on error, %TRUE otherwise
|
|
*/
|
|
gboolean
|
|
fp_device_verify_sync (FpDevice *device,
|
|
FpPrint *enrolled_print,
|
|
GCancellable *cancellable,
|
|
FpMatchCb match_cb,
|
|
gpointer match_data,
|
|
gboolean *match,
|
|
FpPrint **print,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GAsyncResult) task = NULL;
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
fp_device_verify (device,
|
|
enrolled_print,
|
|
cancellable,
|
|
match_cb, match_data, NULL,
|
|
async_result_ready, &task);
|
|
while (!task)
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
return fp_device_verify_finish (device, task, match, print, error);
|
|
}
|
|
|
|
/**
|
|
* fp_device_identify_sync:
|
|
* @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
|
|
*
|
|
* Identify a print synchronously.
|
|
*
|
|
* Returns: (type void): %FALSE on error, %TRUE otherwise
|
|
*/
|
|
gboolean
|
|
fp_device_identify_sync (FpDevice *device,
|
|
GPtrArray *prints,
|
|
GCancellable *cancellable,
|
|
FpMatchCb match_cb,
|
|
gpointer match_data,
|
|
FpPrint **match,
|
|
FpPrint **print,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GAsyncResult) task = NULL;
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
fp_device_identify (device,
|
|
prints,
|
|
cancellable,
|
|
match_cb, match_data, NULL,
|
|
async_result_ready, &task);
|
|
while (!task)
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
return fp_device_identify_finish (device, task, match, print, error);
|
|
}
|
|
|
|
|
|
/**
|
|
* fp_device_capture_sync:
|
|
* @device: a #FpDevice
|
|
* @wait_for_finger: Whether to wait for a finger or not
|
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
* @error: Return location for errors, or %NULL to ignore
|
|
*
|
|
* Start an synchronous operation to capture an image.
|
|
*
|
|
* Returns: (transfer full): A new #FpImage or %NULL on error
|
|
*/
|
|
FpImage *
|
|
fp_device_capture_sync (FpDevice *device,
|
|
gboolean wait_for_finger,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GAsyncResult) task = NULL;
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
fp_device_capture (device,
|
|
wait_for_finger,
|
|
cancellable,
|
|
async_result_ready, &task);
|
|
while (!task)
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
return fp_device_capture_finish (device, task, error);
|
|
}
|
|
|
|
/**
|
|
* fp_device_delete_print_sync:
|
|
* @device: a #FpDevice
|
|
* @enrolled_print: a #FpPrint to verify
|
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
* @error: Return location for errors, or %NULL to ignore
|
|
*
|
|
* Delete a given print from the device.
|
|
*
|
|
* Returns: %FALSE on error, %TRUE otherwise
|
|
*/
|
|
gboolean
|
|
fp_device_delete_print_sync (FpDevice *device,
|
|
FpPrint *enrolled_print,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GAsyncResult) task = NULL;
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
fp_device_delete_print (device,
|
|
enrolled_print,
|
|
cancellable,
|
|
async_result_ready, &task);
|
|
while (!task)
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
return fp_device_delete_print_finish (device, task, error);
|
|
}
|
|
|
|
/**
|
|
* fp_device_list_prints_sync:
|
|
* @device: a #FpDevice
|
|
* @cancellable: (nullable): a #GCancellable, or %NULL
|
|
* @error: Return location for errors, or %NULL to ignore
|
|
*
|
|
* List device stored prints synchronously.
|
|
*
|
|
* Returns: (element-type FpPrint) (transfer container): Array of prints, or %NULL on error
|
|
*/
|
|
GPtrArray *
|
|
fp_device_list_prints_sync (FpDevice *device,
|
|
GCancellable *cancellable,
|
|
GError **error)
|
|
{
|
|
g_autoptr(GAsyncResult) task = NULL;
|
|
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
fp_device_list_prints (device,
|
|
NULL,
|
|
async_result_ready, &task);
|
|
while (!task)
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
return fp_device_list_prints_finish (device, task, error);
|
|
}
|
|
|
|
/**
|
|
* fp_device_get_features:
|
|
* @device: a #FpDevice
|
|
*
|
|
* Gets the #FpDeviceFeature's supported by the @device.
|
|
*
|
|
* Returns: #FpDeviceFeature flags of supported features
|
|
*/
|
|
FpDeviceFeature
|
|
fp_device_get_features (FpDevice *device)
|
|
{
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FP_DEVICE_FEATURE_NONE);
|
|
|
|
return FP_DEVICE_GET_CLASS (device)->features;
|
|
}
|
|
|
|
/**
|
|
* fp_device_has_feature:
|
|
* @device: a #FpDevice
|
|
* @feature: #FpDeviceFeature flags to check against device supported features
|
|
*
|
|
* Checks if @device supports the requested #FpDeviceFeature's.
|
|
* See fp_device_get_features()
|
|
*
|
|
* Returns: %TRUE if supported, %FALSE otherwise
|
|
*/
|
|
gboolean
|
|
fp_device_has_feature (FpDevice *device,
|
|
FpDeviceFeature feature)
|
|
{
|
|
g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
|
|
|
|
if (feature == FP_DEVICE_FEATURE_NONE)
|
|
return fp_device_get_features (device) == feature;
|
|
|
|
return (fp_device_get_features (device) & feature) == feature;
|
|
}
|