GCC Code Coverage Report


Directory: ./
File: libfprint/fp-device.c
Date: 2025-12-06 02:24:24
Exec Total Coverage
Lines: 620 671 92.4%
Functions: 68 68 100.0%
Branches: 269 373 72.1%

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