GCC Code Coverage Report


Directory: ./
File: libfprint/fp-device.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 620 671 92.4%
Functions: 68 68 100.0%
Branches: 269 374 71.9%

Line Branch Exec Source
1 /*
2 * FpDevice - A fingerprint reader device
3 * Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
4 * Copyright (C) 2019 Marco Trevisan <marco.trevisan@canonical.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #define FP_COMPONENT "device"
22 #include "fpi-log.h"
23
24 #include "fp-device-private.h"
25
26 /**
27 * SECTION: fp-device
28 * @title: FpDevice
29 * @short_description: Fingerpint device routines
30 *
31 * These are the public #FpDevice routines.
32 */
33
34 static void fp_device_async_initable_iface_init (GAsyncInitableIface *iface);
35
36
3/5
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 1684800 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 123 times.
✗ Branch 4 not taken.
3381882 G_DEFINE_TYPE_EXTENDED (FpDevice, fp_device, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT,
37 G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,
38 fp_device_async_initable_iface_init)
39 G_ADD_PRIVATE (FpDevice))
40
41 enum {
42 PROP_0,
43 PROP_DRIVER,
44 PROP_DEVICE_ID,
45 PROP_NAME,
46 PROP_OPEN,
47 PROP_REMOVED,
48 PROP_NR_ENROLL_STAGES,
49 PROP_SCAN_TYPE,
50 PROP_FINGER_STATUS,
51 PROP_TEMPERATURE,
52 PROP_FPI_ENVIRON,
53 PROP_FPI_USB_DEVICE,
54 PROP_FPI_UDEV_DATA_SPIDEV,
55 PROP_FPI_UDEV_DATA_HIDRAW,
56 PROP_FPI_DRIVER_DATA,
57 N_PROPS
58 };
59
60 static GParamSpec *properties[N_PROPS];
61
62 enum {
63 REMOVED_SIGNAL,
64 N_SIGNALS
65 };
66
67 static guint signals[N_SIGNALS] = { 0, };
68
69 /**
70 * fp_device_retry_quark:
71 *
72 * Return value: Quark representing a retryable error.
73 **/
74
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 251 times.
285 G_DEFINE_QUARK (fp - device - retry - quark, fp_device_retry)
75
76 /**
77 * fp_device_error_quark:
78 *
79 * Return value: Quark representing a device error.
80 **/
81
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 206 times.
254 G_DEFINE_QUARK (fp - device - error - quark, fp_device_error)
82
83 static gboolean
84 12 fp_device_cancel_in_idle_cb (gpointer user_data)
85 {
86 12 FpDevice *self = user_data;
87
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (self);
88 12 FpDevicePrivate *priv = fp_device_get_instance_private (self);
89
90
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 g_assert (cls->cancel);
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 g_assert (priv->current_action != FPI_DEVICE_ACTION_NONE);
92
93 12 g_debug ("Idle cancelling on ongoing operation!");
94
95 12 priv->current_idle_cancel_source = NULL;
96
97
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 if (priv->critical_section)
98 1 priv->cancel_queued = TRUE;
99 else
100 11 cls->cancel (self);
101
102 12 fpi_device_report_finger_status (self, FP_FINGER_STATUS_NONE);
103
104 12 return G_SOURCE_REMOVE;
105 }
106
107 /* Notify the class that the task was cancelled; this should be connected
108 * with the GTask as the user_data object for automatic cleanup together
109 * with the task. */
110 static void
111 16 fp_device_cancelled_cb (GCancellable *cancellable, FpDevice *self)
112 {
113 16 FpDevicePrivate *priv = fp_device_get_instance_private (self);
114
115 16 priv->current_idle_cancel_source = g_idle_source_new ();
116 16 g_source_set_callback (priv->current_idle_cancel_source,
117 fp_device_cancel_in_idle_cb,
118 self,
119 NULL);
120 16 g_source_attach (priv->current_idle_cancel_source,
121 g_task_get_context (priv->current_task));
122 16 g_source_unref (priv->current_idle_cancel_source);
123 16 }
124
125 /* Forward the external task cancellable to the internal one. */
126 static void
127 12 fp_device_task_cancelled_cb (GCancellable *cancellable, FpDevice *self)
128 {
129 12 FpDevicePrivate *priv = fp_device_get_instance_private (self);
130
131 12 g_cancellable_cancel (priv->current_cancellable);
132 12 }
133
134 static void
135 852 setup_task_cancellable (FpDevice *device)
136 {
137 852 FpDevicePrivate *priv = fp_device_get_instance_private (device);
138 852 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
139
140 /* Create an internal cancellable and hook it up. */
141 852 priv->current_cancellable = g_cancellable_new ();
142
2/2
✓ Branch 0 taken 809 times.
✓ Branch 1 taken 43 times.
852 if (cls->cancel)
143 {
144 809 priv->current_cancellable_id = g_cancellable_connect (priv->current_cancellable,
145 G_CALLBACK (fp_device_cancelled_cb),
146 device,
147 NULL);
148 }
149
150 /* Task cancellable is the externally visible one, make our internal one
151 * a slave of the external one. */
152
2/2
✓ Branch 1 taken 175 times.
✓ Branch 2 taken 677 times.
852 if (g_task_get_cancellable (priv->current_task))
153 {
154 175 priv->current_task_cancellable_id = g_cancellable_connect (g_task_get_cancellable (priv->current_task),
155 G_CALLBACK (fp_device_task_cancelled_cb),
156 device,
157 NULL);
158 }
159 852 }
160
161 static void
162 235 fp_device_constructed (GObject *object)
163 {
164 235 FpDevice *self = (FpDevice *) object;
165
1/2
✓ Branch 0 taken 235 times.
✗ Branch 1 not taken.
235 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (self);
166 235 FpDevicePrivate *priv = fp_device_get_instance_private (self);
167
168
1/2
✓ Branch 0 taken 235 times.
✗ Branch 1 not taken.
235 g_assert (cls->features != FP_DEVICE_FEATURE_NONE);
169
170 235 priv->type = cls->type;
171
1/2
✓ Branch 0 taken 235 times.
✗ Branch 1 not taken.
235 if (cls->nr_enroll_stages)
172 235 priv->nr_enroll_stages = cls->nr_enroll_stages;
173 235 priv->scan_type = cls->scan_type;
174 235 priv->features = cls->features;
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 235 times.
235 priv->device_name = g_strdup (cls->full_name);
176 235 priv->device_id = g_strdup ("0");
177
178
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 234 times.
235 if (cls->temp_hot_seconds > 0)
179 {
180 1 priv->temp_hot_seconds = cls->temp_hot_seconds;
181 1 priv->temp_cold_seconds = cls->temp_cold_seconds;
182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert (priv->temp_cold_seconds > 0);
183 }
184
2/2
✓ Branch 0 taken 227 times.
✓ Branch 1 taken 7 times.
234 else if (cls->temp_hot_seconds == 0)
185 {
186 227 priv->temp_hot_seconds = DEFAULT_TEMP_HOT_SECONDS;
187 227 priv->temp_cold_seconds = DEFAULT_TEMP_COLD_SECONDS;
188 }
189 else
190 {
191 /* Temperature management disabled */
192 7 priv->temp_hot_seconds = -1;
193 7 priv->temp_cold_seconds = -1;
194 }
195
196 /* Start out at not completely cold (i.e. assume we are only at the upper
197 * bound of COLD).
198 * To be fair, the warm-up from 0 to WARM should be really short either way.
199 *
200 * Note that a call to fpi_device_update_temp() is not needed here as no
201 * timeout must be registered.
202 */
203 235 priv->temp_current = FP_TEMPERATURE_COLD;
204 235 priv->temp_current_ratio = TEMP_COLD_THRESH;
205 235 priv->temp_last_update = g_get_monotonic_time ();
206 235 priv->temp_last_active = FALSE;
207
208 235 G_OBJECT_CLASS (fp_device_parent_class)->constructed (object);
209 235 }
210
211 static void
212 227 fp_device_finalize (GObject *object)
213 {
214 227 FpDevice *self = (FpDevice *) object;
215 227 FpDevicePrivate *priv = fp_device_get_instance_private (self);
216
217
1/2
✓ Branch 0 taken 227 times.
✗ Branch 1 not taken.
227 g_assert (priv->current_action == FPI_DEVICE_ACTION_NONE);
218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 227 times.
227 g_assert (priv->current_task == NULL);
219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 227 times.
227 if (priv->is_open)
220 g_warning ("User destroyed open device! Not cleaning up properly!");
221
222
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 161 times.
227 g_clear_pointer (&priv->temp_timeout, g_source_destroy);
223
224 227 g_slist_free_full (priv->sources, (GDestroyNotify) g_source_destroy);
225
226
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 227 times.
227 g_clear_pointer (&priv->current_idle_cancel_source, g_source_destroy);
227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 227 times.
227 g_clear_pointer (&priv->current_task_idle_return_source, g_source_destroy);
228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 227 times.
227 g_clear_pointer (&priv->critical_section_flush_source, g_source_destroy);
229
230
1/2
✓ Branch 0 taken 227 times.
✗ Branch 1 not taken.
227 g_clear_pointer (&priv->device_id, g_free);
231
1/2
✓ Branch 0 taken 227 times.
✗ Branch 1 not taken.
227 g_clear_pointer (&priv->device_name, g_free);
232
233
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 202 times.
227 g_clear_object (&priv->usb_device);
234
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 119 times.
227 g_clear_pointer (&priv->virtual_env, g_free);
235
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 226 times.
227 g_clear_pointer (&priv->udev_data.spidev_path, g_free);
236
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 226 times.
227 g_clear_pointer (&priv->udev_data.hidraw_path, g_free);
237
238 227 G_OBJECT_CLASS (fp_device_parent_class)->finalize (object);
239 227 }
240
241 static void
242 182 fp_device_get_property (GObject *object,
243 guint prop_id,
244 GValue *value,
245 GParamSpec *pspec)
246 {
247 182 FpDevice *self = FP_DEVICE (object);
248 182 FpDevicePrivate *priv = fp_device_get_instance_private (self);
249
9/13
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 8 times.
✓ Branch 8 taken 165 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
182 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (self);
250
251
9/13
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 8 times.
✓ Branch 8 taken 165 times.
✓ Branch 9 taken 1 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
182 switch (prop_id)
252 {
253 1 case PROP_NR_ENROLL_STAGES:
254 1 g_value_set_uint (value, priv->nr_enroll_stages);
255 1 break;
256
257 1 case PROP_SCAN_TYPE:
258 1 g_value_set_enum (value, priv->scan_type);
259 1 break;
260
261 3 case PROP_FINGER_STATUS:
262 3 g_value_set_flags (value, priv->finger_status);
263 3 break;
264
265 case PROP_TEMPERATURE:
266 g_value_set_enum (value, priv->temp_current);
267 break;
268
269 case PROP_DRIVER:
270 1 g_value_set_static_string (value, FP_DEVICE_GET_CLASS (self)->id);
271 1 break;
272
273 1 case PROP_DEVICE_ID:
274 1 g_value_set_string (value, priv->device_id);
275 1 break;
276
277 1 case PROP_NAME:
278 1 g_value_set_string (value, priv->device_name);
279 1 break;
280
281 8 case PROP_OPEN:
282 8 g_value_set_boolean (value, priv->is_open);
283 8 break;
284
285 165 case PROP_REMOVED:
286 165 g_value_set_boolean (value, priv->is_removed);
287 165 break;
288
289 1 case PROP_FPI_USB_DEVICE:
290 1 g_value_set_object (value, priv->usb_device);
291 1 break;
292
293 case PROP_FPI_UDEV_DATA_SPIDEV:
294 if (cls->type == FP_DEVICE_TYPE_UDEV)
295 g_value_set_string (value, priv->udev_data.spidev_path);
296 else
297 g_value_set_string (value, NULL);
298 break;
299
300 case PROP_FPI_UDEV_DATA_HIDRAW:
301 if (cls->type == FP_DEVICE_TYPE_UDEV)
302 g_value_set_string (value, priv->udev_data.hidraw_path);
303 else
304 g_value_set_string (value, NULL);
305 break;
306
307 default:
308 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
309 }
310 182 }
311
312 static void
313 1175 fp_device_set_property (GObject *object,
314 guint prop_id,
315 const GValue *value,
316 GParamSpec *pspec)
317 {
318 1175 FpDevice *self = FP_DEVICE (object);
319 1175 FpDevicePrivate *priv = fp_device_get_instance_private (self);
320
5/6
✓ Branch 0 taken 235 times.
✓ Branch 1 taken 235 times.
✓ Branch 2 taken 235 times.
✓ Branch 3 taken 235 times.
✓ Branch 4 taken 235 times.
✗ Branch 5 not taken.
1175 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (self);
321
322 /* _construct has not run yet, so we cannot use priv->type. */
323
5/6
✓ Branch 0 taken 235 times.
✓ Branch 1 taken 235 times.
✓ Branch 2 taken 235 times.
✓ Branch 3 taken 235 times.
✓ Branch 4 taken 235 times.
✗ Branch 5 not taken.
1175 switch (prop_id)
324 {
325 235 case PROP_FPI_ENVIRON:
326
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 28 times.
235 if (cls->type == FP_DEVICE_TYPE_VIRTUAL)
327 207 priv->virtual_env = g_value_dup_string (value);
328 else
329
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
28 g_assert (g_value_get_string (value) == NULL);
330 break;
331
332 235 case PROP_FPI_USB_DEVICE:
333
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 208 times.
235 if (cls->type == FP_DEVICE_TYPE_USB)
334 27 priv->usb_device = g_value_dup_object (value);
335 else
336
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 208 times.
208 g_assert (g_value_get_object (value) == NULL);
337 break;
338
339 235 case PROP_FPI_UDEV_DATA_SPIDEV:
340
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 234 times.
235 if (cls->type == FP_DEVICE_TYPE_UDEV)
341 1 priv->udev_data.spidev_path = g_value_dup_string (value);
342 else
343
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 234 times.
234 g_assert (g_value_get_string (value) == NULL);
344 break;
345
346 235 case PROP_FPI_UDEV_DATA_HIDRAW:
347
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 234 times.
235 if (cls->type == FP_DEVICE_TYPE_UDEV)
348 1 priv->udev_data.hidraw_path = g_value_dup_string (value);
349 else
350
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 234 times.
234 g_assert (g_value_get_string (value) == NULL);
351 break;
352
353 235 case PROP_FPI_DRIVER_DATA:
354 235 priv->driver_data = g_value_get_uint64 (value);
355 235 break;
356
357 default:
358 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
359 }
360 1175 }
361
362 static void
363 146 device_idle_probe_cb (FpDevice *self, gpointer user_data)
364 {
365 /* This should not be an idle handler, see comment where it is registered.
366 *
367 * This effectively disables USB "persist" for us, and possibly turns off
368 * USB wakeup if it was enabled for some reason.
369 */
370 146 fpi_device_configure_wakeup (self, FALSE);
371
372
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 56 times.
146 if (!FP_DEVICE_GET_CLASS (self)->probe)
373 90 fpi_device_probe_complete (self, NULL, NULL, NULL);
374 else
375 56 FP_DEVICE_GET_CLASS (self)->probe (self);
376
377 146 return;
378 }
379
380 static void
381 146 fp_device_async_initable_init_async (GAsyncInitable *initable,
382 int io_priority,
383 GCancellable *cancellable,
384 GAsyncReadyCallback callback,
385 gpointer user_data)
386 {
387 146 g_autoptr(GTask) task = NULL;
388 146 FpDevice *self = FP_DEVICE (initable);
389 146 FpDevicePrivate *priv = fp_device_get_instance_private (self);
390
391 /* It is next to impossible to call async_init at the wrong time. */
392
1/2
✓ Branch 0 taken 146 times.
✗ Branch 1 not taken.
146 g_assert (!priv->is_open);
393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 146 times.
146 g_assert (!priv->current_task);
394
395 146 task = g_task_new (self, cancellable, callback, user_data);
396
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 146 times.
146 if (g_task_return_error_if_cancelled (task))
397 return;
398
399 146 priv->current_action = FPI_DEVICE_ACTION_PROBE;
400 146 priv->current_task = g_steal_pointer (&task);
401 146 setup_task_cancellable (self);
402
403 /* We push this into an idle handler for compatibility with libgusb
404 * 0.3.7 and before.
405 * See https://github.com/hughsie/libgusb/pull/50
406 */
407 146 g_source_set_name (fpi_device_add_timeout (self, 0, device_idle_probe_cb, NULL, NULL),
408 "libusb probe in idle");
409 }
410
411 static gboolean
412 144 fp_device_async_initable_init_finish (GAsyncInitable *initable,
413 GAsyncResult *res,
414 GError **error)
415 {
416 144 return g_task_propagate_boolean (G_TASK (res), error);
417 }
418
419 static void
420 123 fp_device_async_initable_iface_init (GAsyncInitableIface *iface)
421 {
422 123 iface->init_async = fp_device_async_initable_init_async;
423 123 iface->init_finish = fp_device_async_initable_init_finish;
424 123 }
425
426 static void
427 123 fp_device_class_init (FpDeviceClass *klass)
428 {
429 123 GObjectClass *object_class = G_OBJECT_CLASS (klass);
430
431 123 object_class->constructed = fp_device_constructed;
432 123 object_class->finalize = fp_device_finalize;
433 123 object_class->get_property = fp_device_get_property;
434 123 object_class->set_property = fp_device_set_property;
435
436 246 properties[PROP_NR_ENROLL_STAGES] =
437 123 g_param_spec_uint ("nr-enroll-stages",
438 "EnrollStages",
439 "Number of enroll stages needed on the device",
440 0, G_MAXUINT,
441 0,
442 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
443
444 246 properties[PROP_SCAN_TYPE] =
445 123 g_param_spec_enum ("scan-type",
446 "ScanType",
447 "The scan type of the device",
448 FP_TYPE_SCAN_TYPE, FP_SCAN_TYPE_SWIPE,
449 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
450
451 246 properties[PROP_FINGER_STATUS] =
452 123 g_param_spec_flags ("finger-status",
453 "FingerStatus",
454 "The status of the finger",
455 FP_TYPE_FINGER_STATUS_FLAGS, FP_FINGER_STATUS_NONE,
456 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
457
458 246 properties[PROP_TEMPERATURE] =
459 123 g_param_spec_enum ("temperature",
460 "Temperature",
461 "The temperature estimation for device to prevent overheating.",
462 FP_TYPE_TEMPERATURE, FP_TEMPERATURE_COLD,
463 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
464
465 246 properties[PROP_DRIVER] =
466 123 g_param_spec_string ("driver",
467 "Driver",
468 "String describing the driver",
469 NULL,
470 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
471
472 246 properties[PROP_DEVICE_ID] =
473 123 g_param_spec_string ("device-id",
474 "Device ID",
475 "String describing the device, often generic but may be a serial number",
476 "",
477 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
478
479 246 properties[PROP_NAME] =
480 123 g_param_spec_string ("name",
481 "Device Name",
482 "Human readable name for the device",
483 NULL,
484 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
485
486 246 properties[PROP_OPEN] =
487 123 g_param_spec_boolean ("open",
488 "Opened",
489 "Whether the device is open or not", FALSE,
490 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
491
492 246 properties[PROP_REMOVED] =
493 123 g_param_spec_boolean ("removed",
494 "Removed",
495 "Whether the device has been removed from the system", FALSE,
496 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE);
497
498 /**
499 * FpDevice::removed:
500 * @device: the #FpDevice instance that emitted the signal
501 *
502 * This signal is emitted after the device has been removed and no operation
503 * is pending anymore.
504 *
505 * The API user is still required to close a removed device. The above
506 * guarantee means that the call to close the device can be made immediately
507 * from the signal handler.
508 *
509 * The close operation will return FP_DEVICE_ERROR_REMOVED, but the device
510 * will still be considered closed afterwards.
511 *
512 * The device will only be removed from the #FpContext after it has been
513 * closed by the API user.
514 **/
515 123 signals[REMOVED_SIGNAL] = g_signal_new ("removed",
516 G_TYPE_FROM_CLASS (klass),
517 G_SIGNAL_RUN_LAST,
518 0,
519 NULL,
520 NULL,
521 g_cclosure_marshal_VOID__VOID,
522 G_TYPE_NONE,
523 0);
524
525 /* Private properties */
526
527 /**
528 * FpDevice::fpi-environ: (skip)
529 *
530 * This property is only for internal purposes.
531 *
532 * Stability: private
533 */
534 246 properties[PROP_FPI_ENVIRON] =
535 123 g_param_spec_string ("fpi-environ",
536 "Virtual Environment",
537 "Private: The environment variable for the virtual device",
538 NULL,
539 G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
540
541 /**
542 * FpDevice::fpi-usb-device: (skip)
543 *
544 * This property is only for internal purposes.
545 *
546 * Stability: private
547 */
548 246 properties[PROP_FPI_USB_DEVICE] =
549 123 g_param_spec_object ("fpi-usb-device",
550 "USB Device",
551 "Private: The USB device for the device",
552 G_USB_TYPE_DEVICE,
553 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
554 /**
555 * FpDevice::fpi-udev-data-spidev: (skip)
556 *
557 * This property is only for internal purposes.
558 *
559 * Stability: private
560 */
561 246 properties[PROP_FPI_UDEV_DATA_SPIDEV] =
562 123 g_param_spec_string ("fpi-udev-data-spidev",
563 "Udev data: spidev path",
564 "Private: The path to /dev/spidevN.M",
565 NULL,
566 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
567 /**
568 * FpDevice::fpi-udev-data-hidraw: (skip)
569 *
570 * This property is only for internal purposes.
571 *
572 * Stability: private
573 */
574 246 properties[PROP_FPI_UDEV_DATA_HIDRAW] =
575 123 g_param_spec_string ("fpi-udev-data-hidraw",
576 "Udev data: hidraw path",
577 "Private: The path to /dev/hidrawN",
578 NULL,
579 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
580
581 /**
582 * FpDevice::fpi-driver-data: (skip)
583 *
584 * This property is only for internal purposes.
585 *
586 * Stability: private
587 */
588 246 properties[PROP_FPI_DRIVER_DATA] =
589 123 g_param_spec_uint64 ("fpi-driver-data",
590 "Driver Data",
591 "Private: The driver data from the ID table entry",
592 0,
593 G_MAXUINT64,
594 0,
595 G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
596
597 123 g_object_class_install_properties (object_class, N_PROPS, properties);
598 123 }
599
600 static void
601 235 fp_device_init (FpDevice *self)
602 {
603 235 }
604
605 /**
606 * fp_device_get_driver:
607 * @device: A #FpDevice
608 *
609 * Returns: (transfer none): The ID of the driver
610 */
611 const gchar *
612 24515 fp_device_get_driver (FpDevice *device)
613 {
614
1/2
✓ Branch 1 taken 24515 times.
✗ Branch 2 not taken.
24515 g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
615
616 24515 return FP_DEVICE_GET_CLASS (device)->id;
617 }
618
619 /**
620 * fp_device_get_device_id:
621 * @device: A #FpDevice
622 *
623 * Returns: (transfer none): The ID of the device
624 */
625 const gchar *
626 5821 fp_device_get_device_id (FpDevice *device)
627 {
628 5821 FpDevicePrivate *priv = fp_device_get_instance_private (device);
629
630
1/2
✓ Branch 1 taken 5821 times.
✗ Branch 2 not taken.
5821 g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
631
632 5821 return priv->device_id;
633 }
634
635 /**
636 * fp_device_get_name:
637 * @device: A #FpDevice
638 *
639 * Returns: (transfer none): The human readable name of the device
640 */
641 const gchar *
642 161 fp_device_get_name (FpDevice *device)
643 {
644 161 FpDevicePrivate *priv = fp_device_get_instance_private (device);
645
646
1/2
✓ Branch 1 taken 161 times.
✗ Branch 2 not taken.
161 g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
647
648 161 return priv->device_name;
649 }
650
651 /**
652 * fp_device_is_open:
653 * @device: A #FpDevice
654 *
655 * Returns: Whether the device is open or not
656 */
657 gboolean
658 492 fp_device_is_open (FpDevice *device)
659 {
660 492 FpDevicePrivate *priv = fp_device_get_instance_private (device);
661
662
1/2
✓ Branch 1 taken 492 times.
✗ Branch 2 not taken.
492 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
663
664 492 return priv->is_open;
665 }
666
667 /**
668 * fp_device_get_scan_type:
669 * @device: A #FpDevice
670 *
671 * Retrieves the scan type of the device.
672 *
673 * Returns: The #FpScanType
674 */
675 FpScanType
676 14 fp_device_get_scan_type (FpDevice *device)
677 {
678 14 FpDevicePrivate *priv = fp_device_get_instance_private (device);
679
680
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 g_return_val_if_fail (FP_IS_DEVICE (device), FP_SCAN_TYPE_SWIPE);
681
682 14 return priv->scan_type;
683 }
684
685 /**
686 * fp_device_get_finger_status:
687 * @device: A #FpDevice
688 *
689 * Retrieves the finger status flags for the device.
690 * This can be used by the UI to present the relevant feedback, although it
691 * is not guaranteed to be a relevant value when not performing any action.
692 *
693 * Returns: The current #FpFingerStatusFlags
694 */
695 FpFingerStatusFlags
696 817 fp_device_get_finger_status (FpDevice *device)
697 {
698 817 FpDevicePrivate *priv = fp_device_get_instance_private (device);
699
700
1/2
✓ Branch 1 taken 817 times.
✗ Branch 2 not taken.
817 g_return_val_if_fail (FP_IS_DEVICE (device), FP_FINGER_STATUS_NONE);
701
702 817 return priv->finger_status;
703 }
704
705 /**
706 * fp_device_get_nr_enroll_stages:
707 * @device: A #FpDevice
708 *
709 * Retrieves the number of enroll stages for this device.
710 *
711 * Returns: The number of enroll stages
712 */
713 gint
714 474 fp_device_get_nr_enroll_stages (FpDevice *device)
715 {
716 474 FpDevicePrivate *priv = fp_device_get_instance_private (device);
717
718
1/2
✓ Branch 1 taken 474 times.
✗ Branch 2 not taken.
474 g_return_val_if_fail (FP_IS_DEVICE (device), -1);
719
720 474 return priv->nr_enroll_stages;
721 }
722
723 /**
724 * fp_device_get_temperature:
725 * @device: A #FpDevice
726 *
727 * Retrieves simple temperature information for device. It is not possible
728 * to use a device when this is #FP_TEMPERATURE_HOT.
729 *
730 * Returns: The current temperature estimation.
731 */
732 FpTemperature
733 16 fp_device_get_temperature (FpDevice *device)
734 {
735 16 FpDevicePrivate *priv = fp_device_get_instance_private (device);
736
737
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 g_return_val_if_fail (FP_IS_DEVICE (device), -1);
738
739 16 return priv->temp_current;
740 }
741
742 /**
743 * fp_device_supports_identify:
744 * @device: A #FpDevice
745 *
746 * Check whether the device supports identification.
747 *
748 * Returns: Whether the device supports identification
749 * Deprecated: 1.92.0: Use fp_device_has_feature() instead.
750 */
751 gboolean
752 42 fp_device_supports_identify (FpDevice *device)
753 {
754 42 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
755 42 FpDevicePrivate *priv = fp_device_get_instance_private (device);
756
757
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
758
759
4/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 30 times.
42 return cls->identify && !!(priv->features & FP_DEVICE_FEATURE_IDENTIFY);
760 }
761
762 /**
763 * fp_device_supports_capture:
764 * @device: A #FpDevice
765 *
766 * Check whether the device supports capturing images.
767 *
768 * Returns: Whether the device supports image capture
769 * Deprecated: 1.92.0: Use fp_device_has_feature() instead.
770 */
771 gboolean
772 5 fp_device_supports_capture (FpDevice *device)
773 {
774 5 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
775 5 FpDevicePrivate *priv = fp_device_get_instance_private (device);
776
777
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
778
779
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
5 return cls->capture && !!(priv->features & FP_DEVICE_FEATURE_CAPTURE);
780 }
781
782 /**
783 * fp_device_has_storage:
784 * @device: A #FpDevice
785 *
786 * Whether the device has on-chip storage. If it has, you can list the
787 * prints stored on the with fp_device_list_prints() and you should
788 * always delete prints from the device again using
789 * fp_device_delete_print().
790 * Deprecated: 1.92.0: Use fp_device_has_feature() instead.
791 */
792 gboolean
793 6 fp_device_has_storage (FpDevice *device)
794 {
795 6 FpDevicePrivate *priv = fp_device_get_instance_private (device);
796
797
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
798
799 6 return !!(priv->features & FP_DEVICE_FEATURE_STORAGE);
800 }
801
802 /**
803 * fp_device_open:
804 * @device: a #FpDevice
805 * @cancellable: (nullable): a #GCancellable, or %NULL
806 * @callback: the function to call on completion
807 * @user_data: the data to pass to @callback
808 *
809 * Start an asynchronous operation to open the device. The callback will
810 * be called once the operation has finished. Retrieve the result with
811 * fp_device_open_finish().
812 */
813 void
814 206 fp_device_open (FpDevice *device,
815 GCancellable *cancellable,
816 GAsyncReadyCallback callback,
817 gpointer user_data)
818 {
819 206 g_autoptr(GTask) task = NULL;
820 206 FpDevicePrivate *priv = fp_device_get_instance_private (device);
821 206 GError *error = NULL;
822
823 206 task = g_task_new (device, cancellable, callback, user_data);
824
1/2
✓ Branch 1 taken 206 times.
✗ Branch 2 not taken.
206 if (g_task_return_error_if_cancelled (task))
825 return;
826
827
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 205 times.
206 if (priv->is_open)
828 {
829 1 g_task_return_error (task,
830 fpi_device_error_new (FP_DEVICE_ERROR_ALREADY_OPEN));
831 1 return;
832 }
833
834
3/4
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 204 times.
205 if (priv->current_task || priv->is_suspended)
835 {
836 1 g_task_return_error (task,
837 fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
838 1 return;
839 }
840
841
2/3
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 179 times.
204 switch (priv->type)
842 {
843 25 case FP_DEVICE_TYPE_USB:
844
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
25 if (!g_usb_device_open (priv->usb_device, &error))
845 {
846 g_task_return_error (task, error);
847 return;
848 }
849 break;
850
851 case FP_DEVICE_TYPE_VIRTUAL:
852 case FP_DEVICE_TYPE_UDEV:
853 break;
854
855 default:
856 g_assert_not_reached ();
857 g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
858 return;
859 }
860
861 204 priv->current_action = FPI_DEVICE_ACTION_OPEN;
862 204 priv->current_task = g_steal_pointer (&task);
863 204 setup_task_cancellable (device);
864 204 fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE);
865
866 204 FP_DEVICE_GET_CLASS (device)->open (device);
867 }
868
869 /**
870 * fp_device_open_finish:
871 * @device: A #FpDevice
872 * @result: A #GAsyncResult
873 * @error: Return location for errors, or %NULL to ignore
874 *
875 * Finish an asynchronous operation to open the device.
876 * See fp_device_open().
877 *
878 * Returns: (type void): %FALSE on error, %TRUE otherwise
879 */
880 gboolean
881 205 fp_device_open_finish (FpDevice *device,
882 GAsyncResult *result,
883 GError **error)
884 {
885 205 return g_task_propagate_boolean (G_TASK (result), error);
886 }
887
888 /**
889 * fp_device_close:
890 * @device: a #FpDevice
891 * @cancellable: (nullable): a #GCancellable, or %NULL
892 * @callback: the function to call on completion
893 * @user_data: the data to pass to @callback
894 *
895 * Start an asynchronous operation to close the device. The callback will
896 * be called once the operation has finished. Retrieve the result with
897 * fp_device_close_finish().
898 */
899 void
900 203 fp_device_close (FpDevice *device,
901 GCancellable *cancellable,
902 GAsyncReadyCallback callback,
903 gpointer user_data)
904 {
905 197 g_autoptr(GTask) task = NULL;
906 203 FpDevicePrivate *priv = fp_device_get_instance_private (device);
907
908 203 task = g_task_new (device, cancellable, callback, user_data);
909
1/2
✓ Branch 1 taken 203 times.
✗ Branch 2 not taken.
203 if (g_task_return_error_if_cancelled (task))
910 return;
911
912
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 199 times.
203 if (!priv->is_open)
913 {
914 4 g_task_return_error (task,
915 fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
916 4 return;
917 }
918
919
3/4
✓ Branch 0 taken 197 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 197 times.
199 if (priv->current_task || priv->is_suspended)
920 {
921 2 g_task_return_error (task,
922 fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
923 2 return;
924 }
925
926 197 priv->current_action = FPI_DEVICE_ACTION_CLOSE;
927 197 priv->current_task = g_steal_pointer (&task);
928 197 setup_task_cancellable (device);
929
930 197 FP_DEVICE_GET_CLASS (device)->close (device);
931 }
932
933 /**
934 * fp_device_close_finish:
935 * @device: A #FpDevice
936 * @result: A #GAsyncResult
937 * @error: Return location for errors, or %NULL to ignore
938 *
939 * Finish an asynchronous operation to close the device.
940 * See fp_device_close().
941 *
942 * Returns: (type void): %FALSE on error, %TRUE otherwise
943 */
944 gboolean
945 195 fp_device_close_finish (FpDevice *device,
946 GAsyncResult *result,
947 GError **error)
948 {
949 195 return g_task_propagate_boolean (G_TASK (result), error);
950 }
951
952 /**
953 * fp_device_suspend:
954 * @device: a #FpDevice
955 * @cancellable: (nullable): a #GCancellable, or %NULL, currently not used
956 * @callback: the function to call on completion
957 * @user_data: the data to pass to @callback
958 *
959 * Prepare the device for system suspend. Retrieve the result with
960 * fp_device_suspend_finish().
961 *
962 * The suspend method can be called at any time (even if the device is not
963 * opened) and must be paired with a corresponding resume call. It is undefined
964 * when or how any ongoing operation is finished. This call might wait for an
965 * ongoing operation to finish, might cancel the ongoing operation or may
966 * prepare the device so that the host is resumed when the operation can be
967 * finished.
968 *
969 * If an ongoing operation must be cancelled then it will complete with an error
970 * code of #FP_DEVICE_ERROR_BUSY before the suspend async routine finishes.
971 *
972 * Any operation started while the device is suspended will fail with
973 * #FP_DEVICE_ERROR_BUSY, this includes calls to open or close the device.
974 */
975 void
976 7 fp_device_suspend (FpDevice *device,
977 GCancellable *cancellable,
978 GAsyncReadyCallback callback,
979 gpointer user_data)
980 {
981 7 g_autoptr(GTask) task = NULL;
982 7 FpDevicePrivate *priv = fp_device_get_instance_private (device);
983
984 7 task = g_task_new (device, cancellable, callback, user_data);
985
986
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (priv->suspend_resume_task || priv->is_suspended)
987 {
988 g_task_return_error (task,
989 fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
990 return;
991 }
992
993
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (priv->is_removed)
994 {
995 g_task_return_error (task,
996 fpi_device_error_new (FP_DEVICE_ERROR_REMOVED));
997 return;
998 }
999
1000 7 priv->suspend_resume_task = g_steal_pointer (&task);
1001
1002 7 fpi_device_suspend (device);
1003 }
1004
1005 /**
1006 * fp_device_suspend_finish:
1007 * @device: A #FpDevice
1008 * @result: A #GAsyncResult
1009 * @error: Return location for errors, or %NULL to ignore
1010 *
1011 * Finish an asynchronous operation to prepare the device for suspend.
1012 * See fp_device_suspend().
1013 *
1014 * The API user should accept an error of #FP_DEVICE_ERROR_NOT_SUPPORTED.
1015 *
1016 * Returns: (type void): %FALSE on error, %TRUE otherwise
1017 */
1018 gboolean
1019 6 fp_device_suspend_finish (FpDevice *device,
1020 GAsyncResult *result,
1021 GError **error)
1022 {
1023 6 return g_task_propagate_boolean (G_TASK (result), error);
1024 }
1025
1026 /**
1027 * fp_device_resume:
1028 * @device: a #FpDevice
1029 * @cancellable: (nullable): a #GCancellable, or %NULL, currently not used
1030 * @callback: the function to call on completion
1031 * @user_data: the data to pass to @callback
1032 *
1033 * Resume device after system suspend. Retrieve the result with
1034 * fp_device_suspend_finish().
1035 *
1036 * Note that it is not defined when any ongoing operation may return (success or
1037 * error). You must be ready to handle this before, during or after the
1038 * resume operation.
1039 */
1040 void
1041 7 fp_device_resume (FpDevice *device,
1042 GCancellable *cancellable,
1043 GAsyncReadyCallback callback,
1044 gpointer user_data)
1045 {
1046 7 g_autoptr(GTask) task = NULL;
1047 7 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1048
1049 7 task = g_task_new (device, cancellable, callback, user_data);
1050
1051
2/4
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
7 if (priv->suspend_resume_task || !priv->is_suspended)
1052 {
1053 g_task_return_error (task,
1054 fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
1055 return;
1056 }
1057
1058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (priv->is_removed)
1059 {
1060 g_task_return_error (task,
1061 fpi_device_error_new (FP_DEVICE_ERROR_REMOVED));
1062 return;
1063 }
1064
1065 7 priv->suspend_resume_task = g_steal_pointer (&task);
1066
1067 7 fpi_device_resume (device);
1068 }
1069
1070 /**
1071 * fp_device_resume_finish:
1072 * @device: A #FpDevice
1073 * @result: A #GAsyncResult
1074 * @error: Return location for errors, or %NULL to ignore
1075 *
1076 * Finish an asynchronous operation to resume the device after suspend.
1077 * See fp_device_resume().
1078 *
1079 * The API user should accept an error of #FP_DEVICE_ERROR_NOT_SUPPORTED.
1080 *
1081 * Returns: (type void): %FALSE on error, %TRUE otherwise
1082 */
1083 gboolean
1084 6 fp_device_resume_finish (FpDevice *device,
1085 GAsyncResult *result,
1086 GError **error)
1087 {
1088 6 return g_task_propagate_boolean (G_TASK (result), error);
1089 }
1090
1091 static void
1092 64 enroll_data_free (FpEnrollData *data)
1093 {
1094
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 33 times.
64 if (data->enroll_progress_destroy)
1095 31 data->enroll_progress_destroy (data->enroll_progress_data);
1096 64 data->enroll_progress_data = NULL;
1097
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 g_clear_object (&data->print);
1098 64 g_free (data);
1099 64 }
1100
1101 /**
1102 * fp_device_enroll:
1103 * @device: a #FpDevice
1104 * @template_print: (transfer floating): a #FpPrint
1105 * @cancellable: (nullable): a #GCancellable, or %NULL
1106 * @progress_cb: (nullable) (scope notified): progress reporting callback
1107 * @progress_data: (closure progress_cb): user data for @progress_cb
1108 * @progress_destroy: (destroy progress_data): Destroy notify for @progress_data
1109 * @callback: (scope async): the function to call on completion
1110 * @user_data: the data to pass to @callback
1111 *
1112 * Start an asynchronous operation to enroll a print. The callback will
1113 * be called once the operation has finished. Retrieve the result with
1114 * fp_device_enroll_finish().
1115 *
1116 * The @template_print parameter is a #FpPrint with available metadata filled
1117 * in and, optionally, with existing fingerprint data to be updated with newly
1118 * enrolled fingerprints if a device driver supports it. The driver may make use
1119 * of the metadata, when e.g. storing the print on device memory. It is undefined
1120 * whether this print is filled in by the driver and returned, or whether the
1121 * driver will return a newly created print after enrollment succeeded.
1122 */
1123 void
1124 69 fp_device_enroll (FpDevice *device,
1125 FpPrint *template_print,
1126 GCancellable *cancellable,
1127 FpEnrollProgress progress_cb,
1128 gpointer progress_data,
1129 GDestroyNotify progress_destroy,
1130 GAsyncReadyCallback callback,
1131 gpointer user_data)
1132 {
1133 69 g_autoptr(GTask) task = NULL;
1134 69 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1135 69 FpEnrollData *data;
1136 69 FpiPrintType print_type;
1137
1138 69 task = g_task_new (device, cancellable, callback, user_data);
1139
1/2
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
69 if (g_task_return_error_if_cancelled (task))
1140 return;
1141
1142
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 68 times.
69 if (!priv->is_open)
1143 {
1144 1 g_task_return_error (task,
1145 fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
1146 1 return;
1147 }
1148
1149
3/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 67 times.
68 if (priv->current_task || priv->is_suspended)
1150 {
1151 1 g_task_return_error (task,
1152 fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
1153 1 return;
1154 }
1155
1156
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
67 if (!FP_IS_PRINT (template_print))
1157 {
1158 g_task_return_error (task,
1159 fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
1160 "User did not pass a print template!"));
1161 return;
1162 }
1163
1164 67 g_object_get (template_print, "fpi-type", &print_type, NULL);
1165
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 62 times.
67 if (print_type != FPI_PRINT_UNDEFINED)
1166 {
1167
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
5 if (!fp_device_has_feature (device, FP_DEVICE_FEATURE_UPDATE_PRINT))
1168 {
1169 1 g_task_return_error (task,
1170 fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
1171 "A device does not support print updates!"));
1172 1 return;
1173 }
1174
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (!fp_print_compatible (template_print, device))
1175 {
1176 2 g_task_return_error (task,
1177 fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
1178 "The print and device must have a matching driver and device id"
1179 " for a fingerprint update to succeed"));
1180 2 return;
1181 }
1182 }
1183
1184 64 fpi_device_update_temp (device, TRUE);
1185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
64 if (priv->temp_current == FP_TEMPERATURE_HOT)
1186 {
1187 g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_TOO_HOT));
1188 fpi_device_update_temp (device, FALSE);
1189 return;
1190 }
1191
1192 64 priv->current_action = FPI_DEVICE_ACTION_ENROLL;
1193 64 priv->current_task = g_steal_pointer (&task);
1194 64 setup_task_cancellable (device);
1195
1196 64 data = g_new0 (FpEnrollData, 1);
1197 64 data->print = g_object_ref_sink (template_print);
1198 64 data->enroll_progress_cb = progress_cb;
1199 64 data->enroll_progress_data = progress_data;
1200 64 data->enroll_progress_destroy = progress_destroy;
1201
1202 // Attach the progress data as task data so that it is destroyed
1203 64 g_task_set_task_data (priv->current_task, data, (GDestroyNotify) enroll_data_free);
1204
1205 64 FP_DEVICE_GET_CLASS (device)->enroll (device);
1206 }
1207
1208 /**
1209 * fp_device_enroll_finish:
1210 * @device: A #FpDevice
1211 * @result: A #GAsyncResult
1212 * @error: Return location for errors, or %NULL to ignore
1213 *
1214 * Finish an asynchronous operation to enroll a print. You should check
1215 * for an error of type %FP_DEVICE_RETRY to prompt the user again if there
1216 * was an interaction issue.
1217 * See fp_device_enroll().
1218 *
1219 * Returns: (transfer full): The enrolled #FpPrint, or %NULL on error
1220 */
1221 FpPrint *
1222 69 fp_device_enroll_finish (FpDevice *device,
1223 GAsyncResult *result,
1224 GError **error)
1225 {
1226 69 return g_task_propagate_pointer (G_TASK (result), error);
1227 }
1228
1229 static void
1230 88 match_data_free (FpMatchData *data)
1231 {
1232
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 42 times.
88 g_clear_object (&data->print);
1233
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 51 times.
88 g_clear_object (&data->match);
1234 88 g_clear_error (&data->error);
1235
1236
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 70 times.
88 if (data->match_destroy)
1237 18 data->match_destroy (data->match_data);
1238 88 data->match_data = NULL;
1239
1240
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 39 times.
88 g_clear_object (&data->enrolled_print);
1241
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 49 times.
88 g_clear_pointer (&data->gallery, g_ptr_array_unref);
1242
1243 88 g_free (data);
1244 88 }
1245
1246 /**
1247 * fp_device_verify:
1248 * @device: a #FpDevice
1249 * @enrolled_print: a #FpPrint to verify
1250 * @cancellable: (nullable): a #GCancellable, or %NULL
1251 * @match_cb: (nullable) (scope notified): match reporting callback
1252 * @match_data: (closure match_cb): user data for @match_cb
1253 * @match_destroy: (destroy match_data): Destroy notify for @match_data
1254 * @callback: the function to call on completion
1255 * @user_data: the data to pass to @callback
1256 *
1257 * Start an asynchronous operation to verify a print. The callback will
1258 * be called once the operation has finished. Retrieve the result with
1259 * fp_device_verify_finish().
1260 */
1261 void
1262 56 fp_device_verify (FpDevice *device,
1263 FpPrint *enrolled_print,
1264 GCancellable *cancellable,
1265 FpMatchCb match_cb,
1266 gpointer match_data,
1267 GDestroyNotify match_destroy,
1268 GAsyncReadyCallback callback,
1269 gpointer user_data)
1270 {
1271 53 g_autoptr(GTask) task = NULL;
1272 56 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1273 56 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
1274 56 FpMatchData *data;
1275
1276 56 task = g_task_new (device, cancellable, callback, user_data);
1277
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 if (g_task_return_error_if_cancelled (task))
1278 return;
1279
1280
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 55 times.
56 if (!priv->is_open)
1281 {
1282 1 g_task_return_error (task,
1283 fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
1284 1 return;
1285 }
1286
1287
3/4
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
55 if (priv->current_task || priv->is_suspended)
1288 {
1289 1 g_task_return_error (task,
1290 fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
1291 1 return;
1292 }
1293
1294
3/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 53 times.
54 if (!cls->verify || !(priv->features & FP_DEVICE_FEATURE_VERIFY))
1295 {
1296 1 g_task_return_error (task,
1297 fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
1298 "Device has no verification support"));
1299 1 return;
1300 }
1301
1302 53 fpi_device_update_temp (device, TRUE);
1303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (priv->temp_current == FP_TEMPERATURE_HOT)
1304 {
1305 g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_TOO_HOT));
1306 fpi_device_update_temp (device, FALSE);
1307 return;
1308 }
1309
1310 53 priv->current_action = FPI_DEVICE_ACTION_VERIFY;
1311 53 priv->current_task = g_steal_pointer (&task);
1312 53 setup_task_cancellable (device);
1313
1314 53 data = g_new0 (FpMatchData, 1);
1315 53 data->enrolled_print = g_object_ref (enrolled_print);
1316 53 data->match_cb = match_cb;
1317 53 data->match_data = match_data;
1318 53 data->match_destroy = match_destroy;
1319
1320 // Attach the match data as task data so that it is destroyed
1321 53 g_task_set_task_data (priv->current_task, data, (GDestroyNotify) match_data_free);
1322
1323 53 cls->verify (device);
1324 }
1325
1326 /**
1327 * fp_device_verify_finish:
1328 * @device: A #FpDevice
1329 * @result: A #GAsyncResult
1330 * @match: (out): Whether the user presented the correct finger
1331 * @print: (out) (transfer full) (nullable): Location to store the scanned print, or %NULL to ignore
1332 * @error: Return location for errors, or %NULL to ignore
1333 *
1334 * Finish an asynchronous operation to verify an enrolled print. You should check
1335 * for an error of type %FP_DEVICE_RETRY to prompt the user again if there
1336 * was an interaction issue.
1337 *
1338 * With @print you can fetch the newly created print and retrieve the image data if available.
1339 *
1340 * See fp_device_verify().
1341 *
1342 * Returns: (type void): %FALSE on error, %TRUE otherwise
1343 */
1344 gboolean
1345 55 fp_device_verify_finish (FpDevice *device,
1346 GAsyncResult *result,
1347 gboolean *match,
1348 FpPrint **print,
1349 GError **error)
1350 {
1351 55 gint res;
1352
1353 55 res = g_task_propagate_int (G_TASK (result), error);
1354
1355
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 3 times.
55 if (print)
1356 {
1357 52 FpMatchData *data;
1358
1359 52 data = g_task_get_task_data (G_TASK (result));
1360
1361
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 3 times.
52 *print = data ? data->print : NULL;
1362
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 28 times.
52 if (*print)
1363 24 g_object_ref (*print);
1364 }
1365
1366
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 3 times.
55 if (match)
1367 52 *match = res == FPI_MATCH_SUCCESS;
1368
1369 55 return res != FPI_MATCH_ERROR;
1370 }
1371
1372 /**
1373 * fp_device_identify:
1374 * @device: a #FpDevice
1375 * @prints: (element-type FpPrint) (transfer none): #GPtrArray of #FpPrint
1376 * @cancellable: (nullable): a #GCancellable, or %NULL
1377 * @match_cb: (nullable) (scope notified): match reporting callback
1378 * @match_data: (closure match_cb): user data for @match_cb
1379 * @match_destroy: (destroy match_data): Destroy notify for @match_data
1380 * @callback: the function to call on completion
1381 * @user_data: the data to pass to @callback
1382 *
1383 * Start an asynchronous operation to identify prints. The callback will
1384 * be called once the operation has finished. Retrieve the result with
1385 * fp_device_identify_finish().
1386 */
1387 void
1388 49 fp_device_identify (FpDevice *device,
1389 GPtrArray *prints,
1390 GCancellable *cancellable,
1391 FpMatchCb match_cb,
1392 gpointer match_data,
1393 GDestroyNotify match_destroy,
1394 GAsyncReadyCallback callback,
1395 gpointer user_data)
1396 {
1397 43 g_autoptr(GTask) task = NULL;
1398 49 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1399 49 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
1400 49 FpMatchData *data;
1401 49 int i;
1402
1403 49 task = g_task_new (device, cancellable, callback, user_data);
1404
2/2
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 1 times.
49 if (g_task_return_error_if_cancelled (task))
1405 return;
1406
1407
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 47 times.
48 if (!priv->is_open)
1408 {
1409 1 g_task_return_error (task,
1410 fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
1411 1 return;
1412 }
1413
1414
3/4
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
47 if (priv->current_task || priv->is_suspended)
1415 {
1416 1 g_task_return_error (task,
1417 fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
1418 1 return;
1419 }
1420
1421
3/4
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 45 times.
46 if (!cls->identify || !(priv->features & FP_DEVICE_FEATURE_IDENTIFY))
1422 {
1423 1 g_task_return_error (task,
1424 fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
1425 "Device has not identification support"));
1426 1 return;
1427 }
1428
1429
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 44 times.
45 if (prints == NULL)
1430 {
1431 1 g_task_return_error (task,
1432 fpi_device_error_new_msg (FP_DEVICE_ERROR_DATA_INVALID,
1433 "Invalid gallery array"));
1434 1 return;
1435 }
1436
1437 44 fpi_device_update_temp (device, TRUE);
1438
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 if (priv->temp_current == FP_TEMPERATURE_HOT)
1439 {
1440 1 g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_TOO_HOT));
1441 1 fpi_device_update_temp (device, FALSE);
1442 1 return;
1443 }
1444
1445 43 priv->current_action = FPI_DEVICE_ACTION_IDENTIFY;
1446 43 priv->current_task = g_steal_pointer (&task);
1447 43 setup_task_cancellable (device);
1448
1449 43 data = g_new0 (FpMatchData, 1);
1450 /* We cannot store the gallery directly, because the ptr array may not own
1451 * a reference to each print. Also, the caller could in principle modify the
1452 * GPtrArray afterwards.
1453 */
1454 43 data->gallery = g_ptr_array_new_full (prints->len, g_object_unref);
1455
2/2
✓ Branch 0 taken 6034 times.
✓ Branch 1 taken 43 times.
6077 for (i = 0; i < prints->len; i++)
1456 6034 g_ptr_array_add (data->gallery, g_object_ref (g_ptr_array_index (prints, i)));
1457 43 data->match_cb = match_cb;
1458 43 data->match_data = match_data;
1459 43 data->match_destroy = match_destroy;
1460
1461 // Attach the match data as task data so that it is destroyed
1462 43 g_task_set_task_data (priv->current_task, data, (GDestroyNotify) match_data_free);
1463
1464 43 cls->identify (device);
1465 }
1466
1467 /**
1468 * fp_device_identify_finish:
1469 * @device: A #FpDevice
1470 * @result: A #GAsyncResult
1471 * @match: (out) (transfer full) (nullable): Location for the matched #FpPrint, or %NULL
1472 * @print: (out) (transfer full) (nullable): Location for the new #FpPrint, or %NULL
1473 * @error: Return location for errors, or %NULL to ignore
1474 *
1475 * Finish an asynchronous operation to identify a print. You should check
1476 * for an error of type %FP_DEVICE_RETRY to prompt the user again if there
1477 * was an interaction issue.
1478 *
1479 * Use @match to find the print that matched. With @print you can fetch the
1480 * newly created print and retrieve the image data if available.
1481 *
1482 * See fp_device_identify().
1483 *
1484 * Returns: (type void): %FALSE on error, %TRUE otherwise
1485 */
1486 gboolean
1487 49 fp_device_identify_finish (FpDevice *device,
1488 GAsyncResult *result,
1489 FpPrint **match,
1490 FpPrint **print,
1491 GError **error)
1492 {
1493 49 FpMatchData *data;
1494
1495 49 data = g_task_get_task_data (G_TASK (result));
1496
1497
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 6 times.
49 if (print)
1498 {
1499
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 5 times.
43 *print = data ? data->print : NULL;
1500
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 22 times.
43 if (*print)
1501 21 g_object_ref (*print);
1502 }
1503
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 6 times.
49 if (match)
1504 {
1505
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 5 times.
43 *match = data ? data->match : NULL;
1506
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 25 times.
43 if (*match)
1507 18 g_object_ref (*match);
1508 }
1509
1510 49 return g_task_propagate_boolean (G_TASK (result), error);
1511 }
1512
1513 /**
1514 * fp_device_capture:
1515 * @device: a #FpDevice
1516 * @wait_for_finger: Whether to wait for a finger or not
1517 * @cancellable: (nullable): a #GCancellable, or %NULL
1518 * @callback: the function to call on completion
1519 * @user_data: the data to pass to @callback
1520 *
1521 * Start an asynchronous operation to capture an image. The callback will
1522 * be called once the operation has finished. Retrieve the result with
1523 * fp_device_capture_finish().
1524 */
1525 void
1526 25 fp_device_capture (FpDevice *device,
1527 gboolean wait_for_finger,
1528 GCancellable *cancellable,
1529 GAsyncReadyCallback callback,
1530 gpointer user_data)
1531 {
1532 20 g_autoptr(GTask) task = NULL;
1533 25 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1534 25 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
1535
1536 25 task = g_task_new (device, cancellable, callback, user_data);
1537
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
25 if (g_task_return_error_if_cancelled (task))
1538 return;
1539
1540
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 24 times.
25 if (!priv->is_open)
1541 {
1542 1 g_task_return_error (task,
1543 fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
1544 1 return;
1545 }
1546
1547
3/4
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
24 if (priv->current_task || priv->is_suspended)
1548 {
1549 1 g_task_return_error (task,
1550 fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
1551 1 return;
1552 }
1553
1554
4/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 20 times.
23 if (!cls->capture || !(priv->features & FP_DEVICE_FEATURE_CAPTURE))
1555 {
1556 3 g_task_return_error (task,
1557 fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
1558 "Device has no verification support"));
1559 3 return;
1560 }
1561
1562 20 fpi_device_update_temp (device, TRUE);
1563
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if (priv->temp_current == FP_TEMPERATURE_HOT)
1564 {
1565 g_task_return_error (task, fpi_device_error_new (FP_DEVICE_ERROR_TOO_HOT));
1566 fpi_device_update_temp (device, FALSE);
1567 return;
1568 }
1569
1570 20 priv->current_action = FPI_DEVICE_ACTION_CAPTURE;
1571 20 priv->current_task = g_steal_pointer (&task);
1572 20 setup_task_cancellable (device);
1573
1574 20 priv->wait_for_finger = wait_for_finger;
1575
1576 20 cls->capture (device);
1577 }
1578
1579 /**
1580 * fp_device_capture_finish:
1581 * @device: A #FpDevice
1582 * @result: A #GAsyncResult
1583 * @error: Return location for errors, or %NULL to ignore
1584 *
1585 * Finish an asynchronous operation to capture an image. You should check
1586 * for an error of type %FP_DEVICE_RETRY to prompt the user again if there
1587 * was an interaction issue.
1588 *
1589 * See fp_device_capture().
1590 *
1591 * Returns: (transfer full): #FpImage or %NULL on error
1592 */
1593 FpImage *
1594 25 fp_device_capture_finish (FpDevice *device,
1595 GAsyncResult *result,
1596 GError **error)
1597 {
1598 25 return g_task_propagate_pointer (G_TASK (result), error);
1599 }
1600
1601 /**
1602 * fp_device_delete_print:
1603 * @device: a #FpDevice
1604 * @enrolled_print: a #FpPrint to delete
1605 * @cancellable: (nullable): a #GCancellable, or %NULL
1606 * @callback: the function to call on completion
1607 * @user_data: the data to pass to @callback
1608 *
1609 * Start an asynchronous operation to delete a print from the device.
1610 * The callback will be called once the operation has finished. Retrieve
1611 * the result with fp_device_delete_print_finish().
1612 *
1613 * This only makes sense on devices that store prints on-chip, but is safe
1614 * to always call.
1615 */
1616 void
1617 24 fp_device_delete_print (FpDevice *device,
1618 FpPrint *enrolled_print,
1619 GCancellable *cancellable,
1620 GAsyncReadyCallback callback,
1621 gpointer user_data)
1622 {
1623 22 g_autoptr(GTask) task = NULL;
1624 24 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1625 24 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
1626
1627 24 task = g_task_new (device, cancellable, callback, user_data);
1628
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 if (g_task_return_error_if_cancelled (task))
1629 return;
1630
1631
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 23 times.
24 if (!priv->is_open)
1632 {
1633 1 g_task_return_error (task,
1634 fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
1635 1 return;
1636 }
1637
1638
3/4
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
23 if (priv->current_task || priv->is_suspended)
1639 {
1640 1 g_task_return_error (task,
1641 fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
1642 1 return;
1643 }
1644
1645 /* Succeed immediately if delete is not implemented. */
1646
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 if (!cls->delete || !(priv->features & FP_DEVICE_FEATURE_STORAGE_DELETE))
1647 {
1648 g_task_return_boolean (task, TRUE);
1649 return;
1650 }
1651
1652 22 priv->current_action = FPI_DEVICE_ACTION_DELETE;
1653 22 priv->current_task = g_steal_pointer (&task);
1654 22 setup_task_cancellable (device);
1655
1656 22 g_task_set_task_data (priv->current_task,
1657 g_object_ref (enrolled_print),
1658 g_object_unref);
1659
1660 22 cls->delete (device);
1661 }
1662
1663 /**
1664 * fp_device_delete_print_finish:
1665 * @device: A #FpDevice
1666 * @result: A #GAsyncResult
1667 * @error: Return location for errors, or %NULL to ignore
1668 *
1669 * Finish an asynchronous operation to delete an enrolled print.
1670 *
1671 * See fp_device_delete_print().
1672 *
1673 * Returns: (type void): %FALSE on error, %TRUE otherwise
1674 */
1675 gboolean
1676 24 fp_device_delete_print_finish (FpDevice *device,
1677 GAsyncResult *result,
1678 GError **error)
1679 {
1680 24 return g_task_propagate_boolean (G_TASK (result), error);
1681 }
1682
1683 /**
1684 * fp_device_list_prints:
1685 * @device: a #FpDevice
1686 * @cancellable: (nullable): a #GCancellable, or %NULL
1687 * @callback: the function to call on completion
1688 * @user_data: the data to pass to @callback
1689 *
1690 * Start an asynchronous operation to list all prints stored on the device.
1691 * This only makes sense on devices that store prints on-chip.
1692 *
1693 * Retrieve the result with fp_device_list_prints_finish().
1694 */
1695 void
1696 49 fp_device_list_prints (FpDevice *device,
1697 GCancellable *cancellable,
1698 GAsyncReadyCallback callback,
1699 gpointer user_data)
1700 {
1701 46 g_autoptr(GTask) task = NULL;
1702 49 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1703 49 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
1704
1705 49 task = g_task_new (device, cancellable, callback, user_data);
1706
1/2
✓ Branch 1 taken 49 times.
✗ Branch 2 not taken.
49 if (g_task_return_error_if_cancelled (task))
1707 return;
1708
1709
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 48 times.
49 if (!priv->is_open)
1710 {
1711 1 g_task_return_error (task,
1712 fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
1713 1 return;
1714 }
1715
1716
3/4
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 47 times.
48 if (priv->current_task || priv->is_suspended)
1717 {
1718 1 g_task_return_error (task,
1719 fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
1720 1 return;
1721 }
1722
1723
3/4
✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 46 times.
47 if (!cls->list || !(priv->features & FP_DEVICE_FEATURE_STORAGE))
1724 {
1725 1 g_task_return_error (task,
1726 fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
1727 "Device has no storage"));
1728 1 return;
1729 }
1730
1731 46 priv->current_action = FPI_DEVICE_ACTION_LIST;
1732 46 priv->current_task = g_steal_pointer (&task);
1733 46 setup_task_cancellable (device);
1734
1735 46 cls->list (device);
1736 }
1737
1738 /**
1739 * fp_device_list_prints_finish:
1740 * @device: A #FpDevice
1741 * @result: A #GAsyncResult
1742 * @error: Return location for errors, or %NULL to ignore
1743 *
1744 * Finish an asynchronous operation to list all device stored prints.
1745 *
1746 * See fp_device_list_prints().
1747 *
1748 * Returns: (element-type FpPrint) (transfer container): Array of prints or %NULL on error
1749 */
1750 GPtrArray *
1751 49 fp_device_list_prints_finish (FpDevice *device,
1752 GAsyncResult *result,
1753 GError **error)
1754 {
1755 49 return g_task_propagate_pointer (G_TASK (result), error);
1756 }
1757
1758 /**
1759 * fp_device_clear_storage:
1760 * @device: a #FpDevice
1761 * @cancellable: (nullable): a #GCancellable, or %NULL
1762 * @callback: the function to call on completion
1763 * @user_data: the data to pass to @callback
1764 *
1765 * Start an asynchronous operation to delete all prints from the device.
1766 * The callback will be called once the operation has finished. Retrieve
1767 * the result with fp_device_clear_storage_finish().
1768 *
1769 * This only makes sense on devices that store prints on-chip, but is safe
1770 * to always call.
1771 */
1772 void
1773 57 fp_device_clear_storage (FpDevice *device,
1774 GCancellable *cancellable,
1775 GAsyncReadyCallback callback,
1776 gpointer user_data)
1777 {
1778 114 g_autoptr(GTask) task = NULL;
1779 57 FpDevicePrivate *priv = fp_device_get_instance_private (device);
1780 57 FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
1781
1782 57 task = g_task_new (device, cancellable, callback, user_data);
1783
1/2
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
57 if (g_task_return_error_if_cancelled (task))
1784 return;
1785
1786
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 if (!priv->is_open)
1787 {
1788 g_task_return_error (task,
1789 fpi_device_error_new (FP_DEVICE_ERROR_NOT_OPEN));
1790 return;
1791 }
1792
1793
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 if (priv->current_task)
1794 {
1795 g_task_return_error (task,
1796 fpi_device_error_new (FP_DEVICE_ERROR_BUSY));
1797 return;
1798 }
1799
1800
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 if (!(priv->features & FP_DEVICE_FEATURE_STORAGE))
1801 {
1802 g_task_return_error (task,
1803 fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
1804 "Device has no storage."));
1805 return;
1806 }
1807
1808
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 if (!(priv->features & FP_DEVICE_FEATURE_STORAGE_CLEAR))
1809 {
1810 g_task_return_error (task,
1811 fpi_device_error_new_msg (FP_DEVICE_ERROR_NOT_SUPPORTED,
1812 "Device doesn't support clearing storage."));
1813 return;
1814 }
1815
1816 57 priv->current_action = FPI_DEVICE_ACTION_CLEAR_STORAGE;
1817 57 priv->current_task = g_steal_pointer (&task);
1818 57 setup_task_cancellable (device);
1819
1820 57 cls->clear_storage (device);
1821
1822 57 return;
1823 }
1824
1825 /**
1826 * fp_device_clear_storage_finish:
1827 * @device: A #FpDevice
1828 * @result: A #GAsyncResult
1829 * @error: Return location for errors, or %NULL to ignore
1830 *
1831 * Finish an asynchronous operation to delete all enrolled prints.
1832 *
1833 * See fp_device_clear_storage().
1834 *
1835 * Returns: (type void): %FALSE on error, %TRUE otherwise
1836 */
1837 gboolean
1838 57 fp_device_clear_storage_finish (FpDevice *device,
1839 GAsyncResult *result,
1840 GError **error)
1841 {
1842 57 return g_task_propagate_boolean (G_TASK (result), error);
1843 }
1844
1845 static void
1846 635 async_result_ready (GObject *source_object, GAsyncResult *res, gpointer user_data)
1847 {
1848 635 GTask **task = user_data;
1849
1850 635 *task = g_object_ref (G_TASK (res));
1851 635 }
1852
1853 /**
1854 * fp_device_open_sync:
1855 * @device: a #FpDevice
1856 * @cancellable: (nullable): a #GCancellable, or %NULL
1857 * @error: Return location for errors, or %NULL to ignore
1858 *
1859 * Open the device synchronously.
1860 *
1861 * Returns: (type void): %FALSE on error, %TRUE otherwise
1862 */
1863 gboolean
1864 196 fp_device_open_sync (FpDevice *device,
1865 GCancellable *cancellable,
1866 GError **error)
1867 {
1868 392 g_autoptr(GAsyncResult) task = NULL;
1869
1870
1/2
✓ Branch 1 taken 196 times.
✗ Branch 2 not taken.
196 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
1871
1872 196 fp_device_open (device, cancellable, async_result_ready, &task);
1873
2/2
✓ Branch 1 taken 424 times.
✓ Branch 2 taken 196 times.
620 while (!task)
1874 424 g_main_context_iteration (NULL, TRUE);
1875
1876 196 return fp_device_open_finish (device, task, error);
1877 }
1878
1879 /**
1880 * fp_device_close_sync:
1881 * @device: a #FpDevice
1882 * @cancellable: (nullable): a #GCancellable, or %NULL
1883 * @error: Return location for errors, or %NULL to ignore
1884 *
1885 * Close the device synchronously.
1886 *
1887 * Returns: (type void): %FALSE on error, %TRUE otherwise
1888 */
1889 gboolean
1890 191 fp_device_close_sync (FpDevice *device,
1891 GCancellable *cancellable,
1892 GError **error)
1893 {
1894 382 g_autoptr(GAsyncResult) task = NULL;
1895
1896
1/2
✓ Branch 1 taken 191 times.
✗ Branch 2 not taken.
191 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
1897
1898 191 fp_device_close (device, cancellable, async_result_ready, &task);
1899
2/2
✓ Branch 1 taken 275 times.
✓ Branch 2 taken 191 times.
466 while (!task)
1900 275 g_main_context_iteration (NULL, TRUE);
1901
1902 191 return fp_device_close_finish (device, task, error);
1903 }
1904
1905 /**
1906 * fp_device_enroll_sync:
1907 * @device: a #FpDevice
1908 * @template_print: (transfer floating): A #FpPrint to fill in or use
1909 * as a template.
1910 * @cancellable: (nullable): a #GCancellable, or %NULL
1911 * @progress_cb: (nullable) (scope call): progress reporting callback
1912 * @progress_data: user data for @progress_cb
1913 * @error: Return location for errors, or %NULL to ignore
1914 *
1915 * Enroll a new print. See fp_device_enroll(). It is undefined whether
1916 * @template_print is updated or a newly created #FpPrint is returned.
1917 *
1918 * Returns:(transfer full): A #FpPrint on success, %NULL otherwise
1919 */
1920 FpPrint *
1921 37 fp_device_enroll_sync (FpDevice *device,
1922 FpPrint *template_print,
1923 GCancellable *cancellable,
1924 FpEnrollProgress progress_cb,
1925 gpointer progress_data,
1926 GError **error)
1927 {
1928 74 g_autoptr(GAsyncResult) task = NULL;
1929
1930
1/2
✓ Branch 1 taken 37 times.
✗ Branch 2 not taken.
37 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
1931
1932 37 fp_device_enroll (device, template_print, cancellable,
1933 progress_cb, progress_data, NULL,
1934 async_result_ready, &task);
1935
2/2
✓ Branch 1 taken 2128 times.
✓ Branch 2 taken 37 times.
2165 while (!task)
1936 2128 g_main_context_iteration (NULL, TRUE);
1937
1938 37 return fp_device_enroll_finish (device, task, error);
1939 }
1940
1941 /**
1942 * fp_device_verify_sync:
1943 * @device: a #FpDevice
1944 * @enrolled_print: a #FpPrint to verify
1945 * @cancellable: (nullable): a #GCancellable, or %NULL
1946 * @match_cb: (nullable) (scope call): match reporting callback
1947 * @match_data: (closure match_cb): user data for @match_cb
1948 * @match: (out): Whether the user presented the correct finger
1949 * @print: (out) (transfer full) (nullable): Location to store the scanned print, or %NULL to ignore
1950 * @error: Return location for errors, or %NULL to ignore
1951 *
1952 * Verify a given print synchronously.
1953 *
1954 * Returns: (type void): %FALSE on error, %TRUE otherwise
1955 */
1956 gboolean
1957 35 fp_device_verify_sync (FpDevice *device,
1958 FpPrint *enrolled_print,
1959 GCancellable *cancellable,
1960 FpMatchCb match_cb,
1961 gpointer match_data,
1962 gboolean *match,
1963 FpPrint **print,
1964 GError **error)
1965 {
1966 70 g_autoptr(GAsyncResult) task = NULL;
1967
1968
1/2
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
35 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
1969
1970 35 fp_device_verify (device,
1971 enrolled_print,
1972 cancellable,
1973 match_cb, match_data, NULL,
1974 async_result_ready, &task);
1975
2/2
✓ Branch 1 taken 200 times.
✓ Branch 2 taken 35 times.
235 while (!task)
1976 200 g_main_context_iteration (NULL, TRUE);
1977
1978 35 return fp_device_verify_finish (device, task, match, print, error);
1979 }
1980
1981 /**
1982 * fp_device_identify_sync:
1983 * @device: a #FpDevice
1984 * @prints: (element-type FpPrint) (transfer none): #GPtrArray of #FpPrint
1985 * @cancellable: (nullable): a #GCancellable, or %NULL
1986 * @match_cb: (nullable) (scope call): match reporting callback
1987 * @match_data: (closure match_cb): user data for @match_cb
1988 * @match: (out) (transfer full) (nullable): Location for the matched #FpPrint, or %NULL
1989 * @print: (out) (transfer full) (nullable): Location for the new #FpPrint, or %NULL
1990 * @error: Return location for errors, or %NULL to ignore
1991 *
1992 * Identify a print synchronously.
1993 *
1994 * Returns: (type void): %FALSE on error, %TRUE otherwise
1995 */
1996 gboolean
1997 17 fp_device_identify_sync (FpDevice *device,
1998 GPtrArray *prints,
1999 GCancellable *cancellable,
2000 FpMatchCb match_cb,
2001 gpointer match_data,
2002 FpPrint **match,
2003 FpPrint **print,
2004 GError **error)
2005 {
2006 34 g_autoptr(GAsyncResult) task = NULL;
2007
2008
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
2009
2010 17 fp_device_identify (device,
2011 prints,
2012 cancellable,
2013 match_cb, match_data, NULL,
2014 async_result_ready, &task);
2015
2/2
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 17 times.
34 while (!task)
2016 17 g_main_context_iteration (NULL, TRUE);
2017
2018 17 return fp_device_identify_finish (device, task, match, print, error);
2019 }
2020
2021
2022 /**
2023 * fp_device_capture_sync:
2024 * @device: a #FpDevice
2025 * @wait_for_finger: Whether to wait for a finger or not
2026 * @cancellable: (nullable): a #GCancellable, or %NULL
2027 * @error: Return location for errors, or %NULL to ignore
2028 *
2029 * Start an synchronous operation to capture an image.
2030 *
2031 * Returns: (transfer full): A new #FpImage or %NULL on error
2032 */
2033 FpImage *
2034 24 fp_device_capture_sync (FpDevice *device,
2035 gboolean wait_for_finger,
2036 GCancellable *cancellable,
2037 GError **error)
2038 {
2039 48 g_autoptr(GAsyncResult) task = NULL;
2040
2041
1/2
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
24 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
2042
2043 24 fp_device_capture (device,
2044 wait_for_finger,
2045 cancellable,
2046 async_result_ready, &task);
2047
2/2
✓ Branch 1 taken 24461 times.
✓ Branch 2 taken 24 times.
24485 while (!task)
2048 24461 g_main_context_iteration (NULL, TRUE);
2049
2050 24 return fp_device_capture_finish (device, task, error);
2051 }
2052
2053 /**
2054 * fp_device_delete_print_sync:
2055 * @device: a #FpDevice
2056 * @enrolled_print: a #FpPrint to verify
2057 * @cancellable: (nullable): a #GCancellable, or %NULL
2058 * @error: Return location for errors, or %NULL to ignore
2059 *
2060 * Delete a given print from the device.
2061 *
2062 * Returns: (type void): %FALSE on error, %TRUE otherwise
2063 */
2064 gboolean
2065 22 fp_device_delete_print_sync (FpDevice *device,
2066 FpPrint *enrolled_print,
2067 GCancellable *cancellable,
2068 GError **error)
2069 {
2070 44 g_autoptr(GAsyncResult) task = NULL;
2071
2072
1/2
✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
22 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
2073
2074 22 fp_device_delete_print (device,
2075 enrolled_print,
2076 cancellable,
2077 async_result_ready, &task);
2078
2/2
✓ Branch 1 taken 77 times.
✓ Branch 2 taken 22 times.
99 while (!task)
2079 77 g_main_context_iteration (NULL, TRUE);
2080
2081 22 return fp_device_delete_print_finish (device, task, error);
2082 }
2083
2084 /**
2085 * fp_device_list_prints_sync:
2086 * @device: a #FpDevice
2087 * @cancellable: (nullable): a #GCancellable, or %NULL
2088 * @error: Return location for errors, or %NULL to ignore
2089 *
2090 * List device stored prints synchronously.
2091 *
2092 * Returns: (element-type FpPrint) (transfer container): Array of prints, or %NULL on error
2093 */
2094 GPtrArray *
2095 48 fp_device_list_prints_sync (FpDevice *device,
2096 GCancellable *cancellable,
2097 GError **error)
2098 {
2099 96 g_autoptr(GAsyncResult) task = NULL;
2100
2101
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
2102
2103 48 fp_device_list_prints (device,
2104 NULL,
2105 async_result_ready, &task);
2106
2/2
✓ Branch 1 taken 171 times.
✓ Branch 2 taken 48 times.
219 while (!task)
2107 171 g_main_context_iteration (NULL, TRUE);
2108
2109 48 return fp_device_list_prints_finish (device, task, error);
2110 }
2111
2112
2113 /**
2114 * fp_device_clear_storage_sync:
2115 * @device: a #FpDevice
2116 * @cancellable: (nullable): a #GCancellable, or %NULL
2117 * @error: Return location for errors, or %NULL to ignore
2118 *
2119 * Clear sensor storage.
2120 *
2121 * Returns: (type void): %FALSE on error, %TRUE otherwise
2122 */
2123 gboolean
2124 57 fp_device_clear_storage_sync (FpDevice *device,
2125 GCancellable *cancellable,
2126 GError **error)
2127 {
2128 114 g_autoptr(GAsyncResult) task = NULL;
2129
2130
1/2
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
57 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
2131
2132 57 fp_device_clear_storage (device,
2133 cancellable,
2134 async_result_ready, &task);
2135
2/2
✓ Branch 1 taken 115 times.
✓ Branch 2 taken 57 times.
172 while (!task)
2136 115 g_main_context_iteration (NULL, TRUE);
2137
2138 57 return fp_device_clear_storage_finish (device, task, error);
2139 }
2140
2141 /**
2142 * fp_device_suspend_sync:
2143 * @device: a #FpDevice
2144 * @cancellable: (nullable): a #GCancellable, or %NULL, currently not used
2145 * @error: Return location for errors, or %NULL to ignore
2146 *
2147 * Prepare device for suspend.
2148 *
2149 * Returns: (type void): %FALSE on error, %TRUE otherwise
2150 */
2151 gboolean
2152 4 fp_device_suspend_sync (FpDevice *device,
2153 GCancellable *cancellable,
2154 GError **error)
2155 {
2156 8 g_autoptr(GAsyncResult) task = NULL;
2157
2158
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
2159
2160 4 fp_device_suspend (device, cancellable, async_result_ready, &task);
2161
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 4 times.
14 while (!task)
2162 10 g_main_context_iteration (NULL, TRUE);
2163
2164 4 return fp_device_suspend_finish (device, task, error);
2165 }
2166
2167 /**
2168 * fp_device_resume_sync:
2169 * @device: a #FpDevice
2170 * @cancellable: (nullable): a #GCancellable, or %NULL, currently not used
2171 * @error: Return location for errors, or %NULL to ignore
2172 *
2173 * Resume device after suspend.
2174 *
2175 * Returns: (type void): %FALSE on error, %TRUE otherwise
2176 */
2177 gboolean
2178 4 fp_device_resume_sync (FpDevice *device,
2179 GCancellable *cancellable,
2180 GError **error)
2181 {
2182 8 g_autoptr(GAsyncResult) task = NULL;
2183
2184
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
2185
2186 4 fp_device_resume (device, cancellable, async_result_ready, &task);
2187
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 4 times.
9 while (!task)
2188 5 g_main_context_iteration (NULL, TRUE);
2189
2190 4 return fp_device_resume_finish (device, task, error);
2191 }
2192
2193 /**
2194 * fp_device_get_features:
2195 * @device: a #FpDevice
2196 *
2197 * Gets the #FpDeviceFeature's supported by the @device.
2198 *
2199 * Returns: #FpDeviceFeature flags of supported features
2200 */
2201 FpDeviceFeature
2202 333 fp_device_get_features (FpDevice *device)
2203 {
2204 333 FpDevicePrivate *priv = fp_device_get_instance_private (device);
2205
2206
1/2
✓ Branch 1 taken 333 times.
✗ Branch 2 not taken.
333 g_return_val_if_fail (FP_IS_DEVICE (device), FP_DEVICE_FEATURE_NONE);
2207
2208 333 return priv->features;
2209 }
2210
2211 /**
2212 * fp_device_has_feature:
2213 * @device: a #FpDevice
2214 * @feature: #FpDeviceFeature flags to check against device supported features
2215 *
2216 * Checks if @device supports the requested #FpDeviceFeature's.
2217 * See fp_device_get_features()
2218 *
2219 * Returns: %TRUE if supported, %FALSE otherwise
2220 */
2221 gboolean
2222 267 fp_device_has_feature (FpDevice *device,
2223 FpDeviceFeature feature)
2224 {
2225
1/2
✓ Branch 1 taken 267 times.
✗ Branch 2 not taken.
267 g_return_val_if_fail (FP_IS_DEVICE (device), FALSE);
2226
2227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267 times.
267 if (feature == FP_DEVICE_FEATURE_NONE)
2228 return fp_device_get_features (device) == feature;
2229
2230 267 return (fp_device_get_features (device) & feature) == feature;
2231 }
2232