GCC Code Coverage Report


Directory: ./
File: libfprint/fpi-image-device.c
Date: 2024-09-16 14:36:32
Exec Total Coverage
Lines: 225 276 81.5%
Functions: 15 16 93.8%
Branches: 103 176 58.5%

Line Branch Exec Source
1 /*
2 * FpImageDevice - An image based fingerprint reader device - Private APIs
3 * Copyright (C) 2019 Benjamin Berg <bberg@redhat.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #define FP_COMPONENT "image_device"
21 #include "fpi-log.h"
22
23 #include "fp-image-device-private.h"
24 #include "fp-image-device.h"
25
26 /**
27 * SECTION: fpi-image-device
28 * @title: Internal FpImageDevice
29 * @short_description: Internal image device functions
30 *
31 * Internal image device functions. See #FpImageDevice for public routines.
32 */
33
34 /* Manually redefine what G_DEFINE_* macro does */
35 static inline gpointer
36 946 fp_image_device_get_instance_private (FpImageDevice *self)
37 {
38 946 FpImageDeviceClass *img_class = g_type_class_peek_static (FP_TYPE_IMAGE_DEVICE);
39
40 946 return G_STRUCT_MEMBER_P (self,
41 g_type_class_get_instance_private_offset (img_class));
42 }
43
44 static void fp_image_device_change_state (FpImageDevice *self,
45 FpiImageDeviceState state);
46
47 /* Private shared functions */
48
49 void
50 34 fpi_image_device_activate (FpImageDevice *self)
51 {
52 34 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
53
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (self);
54
55
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 g_assert (!priv->active);
56
57 34 fp_dbg ("Activating image device");
58 34 fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_ACTIVATING);
59 34 cls->activate (self);
60 34 }
61
62 void
63 34 fpi_image_device_deactivate (FpImageDevice *self, gboolean cancelling)
64 {
65 34 FpDevice *device = FP_DEVICE (self);
66 34 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
67
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 FpImageDeviceClass *cls = FP_IMAGE_DEVICE_GET_CLASS (device);
68
69
2/4
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 34 times.
34 if (!priv->active || priv->state == FPI_IMAGE_DEVICE_STATE_DEACTIVATING)
70 {
71 /* XXX: We currently deactivate both from minutiae scan result
72 * and finger off report. */
73 fp_dbg ("Already deactivated, ignoring request.");
74 return;
75 }
76
3/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 28 times.
34 if (!cancelling && priv->state != FPI_IMAGE_DEVICE_STATE_IDLE)
77 g_warning ("Deactivating image device while it is not idle, this should not happen.");
78
79 34 fp_dbg ("Deactivating image device");
80 34 fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_DEACTIVATING);
81 34 cls->deactivate (self);
82 }
83
84 /* Static helper functions */
85
86 /* This should not be called directly to activate/deactivate the device! */
87 static void
88 334 fp_image_device_change_state (FpImageDevice *self, FpiImageDeviceState state)
89 {
90 334 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
91 668 g_autofree char *prev_state_str = NULL;
92 334 g_autofree char *state_str = NULL;
93 334 gboolean transition_is_valid = FALSE;
94 334 gint i;
95
96 334 struct
97 {
98 FpiImageDeviceState from;
99 FpiImageDeviceState to;
100 334 } valid_transitions[] = {
101 { FPI_IMAGE_DEVICE_STATE_INACTIVE, FPI_IMAGE_DEVICE_STATE_ACTIVATING },
102
103 { FPI_IMAGE_DEVICE_STATE_ACTIVATING, FPI_IMAGE_DEVICE_STATE_IDLE },
104 { FPI_IMAGE_DEVICE_STATE_ACTIVATING, FPI_IMAGE_DEVICE_STATE_INACTIVE },
105
106 { FPI_IMAGE_DEVICE_STATE_IDLE, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON },
107 { FPI_IMAGE_DEVICE_STATE_IDLE, FPI_IMAGE_DEVICE_STATE_CAPTURE }, /* raw mode -- currently not supported */
108 { FPI_IMAGE_DEVICE_STATE_IDLE, FPI_IMAGE_DEVICE_STATE_DEACTIVATING },
109
110 { FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON, FPI_IMAGE_DEVICE_STATE_CAPTURE },
111 { FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON, FPI_IMAGE_DEVICE_STATE_DEACTIVATING }, /* cancellation */
112
113 { FPI_IMAGE_DEVICE_STATE_CAPTURE, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF },
114 { FPI_IMAGE_DEVICE_STATE_CAPTURE, FPI_IMAGE_DEVICE_STATE_IDLE }, /* raw mode -- currently not supported */
115 { FPI_IMAGE_DEVICE_STATE_CAPTURE, FPI_IMAGE_DEVICE_STATE_DEACTIVATING }, /* cancellation */
116
117 { FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF, FPI_IMAGE_DEVICE_STATE_IDLE },
118 { FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF, FPI_IMAGE_DEVICE_STATE_DEACTIVATING }, /* cancellation */
119
120 { FPI_IMAGE_DEVICE_STATE_DEACTIVATING, FPI_IMAGE_DEVICE_STATE_INACTIVE },
121 };
122
123 334 prev_state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, priv->state);
124 334 state_str = g_enum_to_string (FPI_TYPE_IMAGE_DEVICE_STATE, state);
125 334 fp_dbg ("Image device internal state change from %s to %s",
126 prev_state_str, state_str);
127
128
1/2
✓ Branch 1 taken 2354 times.
✗ Branch 2 not taken.
2688 for (i = 0; i < G_N_ELEMENTS (valid_transitions); i++)
129 {
130
4/4
✓ Branch 0 taken 396 times.
✓ Branch 1 taken 1958 times.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 334 times.
2354 if (valid_transitions[i].from == priv->state && valid_transitions[i].to == state)
131 {
132 transition_is_valid = TRUE;
133 break;
134 }
135 }
136
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 334 times.
334 if (!transition_is_valid)
137 g_warning ("Internal state machine issue: transition from %s to %s should not happen!",
138 prev_state_str, state_str);
139
140 334 priv->state = state;
141 334 g_object_notify (G_OBJECT (self), "fpi-image-device-state");
142 334 g_signal_emit_by_name (self, "fpi-image-device-state-changed", priv->state);
143
144
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 280 times.
334 if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
145 {
146 54 fpi_device_report_finger_status_changes (FP_DEVICE (self),
147 FP_FINGER_STATUS_NEEDED,
148 FP_FINGER_STATUS_NONE);
149 }
150
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 232 times.
280 else if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
151 {
152 48 fpi_device_report_finger_status_changes (FP_DEVICE (self),
153 FP_FINGER_STATUS_NONE,
154 FP_FINGER_STATUS_NEEDED);
155 }
156 334 }
157
158 static void
159 45 fp_image_device_enroll_maybe_await_finger_on (FpImageDevice *self)
160 {
161 45 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
162
163 /* We wait for both the minutiae scan to complete and the finger to
164 * be removed before we switch to AWAIT_FINGER_ON. */
165
4/4
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 5 times.
45 if (priv->minutiae_scan_active || priv->finger_present)
166 return;
167
168 20 fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
169 }
170
171 static void
172 67 fp_image_device_maybe_complete_action (FpImageDevice *self, GError *error)
173 {
174 67 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
175 67 FpDevice *device = FP_DEVICE (self);
176 67 FpiDeviceAction action;
177
178
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 64 times.
67 if (error)
179 {
180 /* Keep the first error we encountered, but not if it is of type retry */
181
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
3 if (priv->action_error && !(priv->action_error->domain == FP_DEVICE_RETRY))
182 {
183 g_warning ("Will complete with first error, new error was: %s", error->message);
184 g_clear_error (&error);
185 }
186 else
187 {
188 3 g_clear_error (&priv->action_error);
189 3 priv->action_error = error;
190 }
191 }
192
193 /* Do not complete if the device is still active or a minutiae scan is pending. */
194
4/4
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 21 times.
67 if (priv->active || priv->minutiae_scan_active)
195 return;
196
197
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 3 times.
34 if (!priv->action_error)
198 31 g_cancellable_set_error_if_cancelled (fpi_device_get_cancellable (device), &priv->action_error);
199
200
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 30 times.
34 if (priv->action_error)
201 {
202 4 fpi_device_action_error (device, g_steal_pointer (&priv->action_error));
203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 g_clear_object (&priv->capture_image);
204 4 return;
205 }
206
207 /* We are done, report the result. */
208 30 action = fpi_device_get_current_action (FP_DEVICE (self));
209
210
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 25 times.
30 if (action == FPI_DEVICE_ACTION_ENROLL)
211 {
212 5 FpPrint *enroll_print;
213 5 fpi_device_get_enroll_data (device, &enroll_print);
214
215 5 fpi_device_enroll_complete (device, g_object_ref (enroll_print), NULL);
216 }
217
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 18 times.
25 else if (action == FPI_DEVICE_ACTION_VERIFY)
218 {
219 7 fpi_device_verify_complete (device, NULL);
220 }
221
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
18 else if (action == FPI_DEVICE_ACTION_IDENTIFY)
222 {
223 3 fpi_device_identify_complete (device, NULL);
224 }
225
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 else if (action == FPI_DEVICE_ACTION_CAPTURE)
226 {
227 15 fpi_device_capture_complete (device, g_steal_pointer (&priv->capture_image), NULL);
228 }
229 else
230 {
231 g_assert_not_reached ();
232 }
233 }
234
235 static void
236 48 fpi_image_device_minutiae_detected (GObject *source_object, GAsyncResult *res, gpointer user_data)
237 {
238 48 g_autoptr(FpImage) image = FP_IMAGE (source_object);
239
1/4
✓ Branch 1 taken 33 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
48 g_autoptr(FpPrint) print = NULL;
240 48 GError *error = NULL;
241 48 FpImageDevice *self = FP_IMAGE_DEVICE (user_data);
242 48 FpDevice *device = FP_DEVICE (self);
243 48 FpImageDevicePrivate *priv;
244 48 FpiDeviceAction action;
245
246 /* Note: We rely on the device to not disappear during an operation. */
247 48 priv = fp_image_device_get_instance_private (FP_IMAGE_DEVICE (device));
248 48 priv->minutiae_scan_active = FALSE;
249
250
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
48 if (!fp_image_detect_minutiae_finish (image, res, &error))
251 {
252 /* Cancel operation . */
253 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
254 {
255 fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
256 fpi_image_device_deactivate (self, TRUE);
257 return;
258 }
259
260 /* Replace error with a retry condition. */
261 g_warning ("Failed to detect minutiae: %s", error->message);
262 g_clear_pointer (&error, g_error_free);
263
264 error = fpi_device_retry_new_msg (FP_DEVICE_RETRY_GENERAL, "Minutiae detection failed, please retry");
265 }
266
267 48 action = fpi_device_get_current_action (device);
268
269
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 33 times.
48 if (action == FPI_DEVICE_ACTION_CAPTURE)
270 {
271 15 priv->capture_image = g_steal_pointer (&image);
272 15 fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
273 15 return;
274 }
275
276
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (!error)
277 {
278 33 print = fp_print_new (device);
279 33 fpi_print_set_type (print, FPI_PRINT_NBIS);
280
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
33 if (!fpi_print_add_from_image (print, image, &error))
281 {
282 g_clear_object (&print);
283
284 if (error->domain != FP_DEVICE_RETRY)
285 {
286 fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
287 /* We might not yet be deactivating, if we are enrolling. */
288 fpi_image_device_deactivate (self, TRUE);
289 return;
290 }
291 }
292 }
293
294
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 8 times.
33 if (action == FPI_DEVICE_ACTION_ENROLL)
295 {
296 25 FpPrint *enroll_print;
297 25 fpi_device_get_enroll_data (device, &enroll_print);
298
299
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 if (print)
300 {
301 25 fpi_print_add_print (enroll_print, print);
302 25 priv->enroll_stage += 1;
303 }
304
305 25 fpi_device_enroll_progress (device, priv->enroll_stage,
306 25 g_steal_pointer (&print), error);
307
308 /* Start another scan or deactivate. */
309
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 20 times.
25 if (priv->enroll_stage == fp_device_get_nr_enroll_stages (device))
310 {
311 5 fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
312 5 fpi_image_device_deactivate (self, FALSE);
313 }
314 else
315 {
316 20 fp_image_device_enroll_maybe_await_finger_on (FP_IMAGE_DEVICE (device));
317 }
318 }
319
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 else if (action == FPI_DEVICE_ACTION_VERIFY)
320 {
321 6 FpPrint *template;
322 6 FpiMatchResult result;
323
324 6 fpi_device_get_verify_data (device, &template);
325
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (print)
326 6 result = fpi_print_bz3_match (template, print, priv->bz3_threshold, &error);
327 else
328 result = FPI_MATCH_ERROR;
329
330
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 if (!error || error->domain == FP_DEVICE_RETRY)
331 6 fpi_device_verify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
332
333 6 fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
334 }
335
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 else if (action == FPI_DEVICE_ACTION_IDENTIFY)
336 {
337 2 gint i;
338 2 GPtrArray *templates;
339 2 FpPrint *result = NULL;
340
341 2 fpi_device_get_identify_data (device, &templates);
342
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
5 for (i = 0; !error && i < templates->len; i++)
343 {
344 3 FpPrint *template = g_ptr_array_index (templates, i);
345
346
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
3 if (fpi_print_bz3_match (template, print, priv->bz3_threshold, &error) == FPI_MATCH_SUCCESS)
347 {
348 result = template;
349 break;
350 }
351 }
352
353
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 if (!error || error->domain == FP_DEVICE_RETRY)
354 2 fpi_device_identify_report (device, result, g_steal_pointer (&print), g_steal_pointer (&error));
355
356 2 fp_image_device_maybe_complete_action (self, g_steal_pointer (&error));
357 }
358 else
359 {
360 /* XXX: This can be hit currently due to a race condition in the enroll code!
361 * In that case we scan a further image even though the minutiae for the previous
362 * one have not yet been detected.
363 * We need to keep track on the pending minutiae detection and the fact that
364 * it will finish eventually (or we may need to retry on error and activate the
365 * device again). */
366
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
33 g_assert_not_reached ();
367 }
368 }
369
370 /*********************************************************/
371 /* Private API */
372
373 /**
374 * fpi_image_device_set_bz3_threshold:
375 * @self: a #FpImageDevice imaging fingerprint device
376 * @bz3_threshold: BZ3 threshold to use
377 *
378 * Dynamically adjust the bz3 threshold. This is only needed for drivers
379 * that support devices with different properties. It should generally be
380 * called from the probe callback, but is acceptable to call from the open
381 * callback.
382 */
383 void
384 fpi_image_device_set_bz3_threshold (FpImageDevice *self,
385 gint bz3_threshold)
386 {
387 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
388
389 g_return_if_fail (FP_IS_IMAGE_DEVICE (self));
390 g_return_if_fail (bz3_threshold > 0);
391
392 priv->bz3_threshold = bz3_threshold;
393 }
394
395 /**
396 * fpi_image_device_report_finger_status:
397 * @self: a #FpImageDevice imaging fingerprint device
398 * @present: whether the finger is present on the sensor
399 *
400 * Reports from the driver whether the user's finger is on
401 * the sensor.
402 */
403 void
404 181 fpi_image_device_report_finger_status (FpImageDevice *self,
405 gboolean present)
406 {
407 181 FpDevice *device = FP_DEVICE (self);
408 181 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
409 181 FpiDeviceAction action;
410
411
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 87 times.
181 if (present)
412 {
413 94 fpi_device_report_finger_status_changes (device,
414 FP_FINGER_STATUS_PRESENT,
415 FP_FINGER_STATUS_NONE);
416 }
417 else
418 {
419 87 fpi_device_report_finger_status_changes (device,
420 FP_FINGER_STATUS_NONE,
421 FP_FINGER_STATUS_PRESENT);
422 }
423
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 181 times.
181 if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
425 {
426 /* Do we really want to always ignore such reports? We could
427 * also track the state in case the user had the finger on
428 * the device at initialisation time and the driver reports
429 * this early.
430 */
431 g_debug ("Ignoring finger presence report as the device is not active!");
432 return;
433 }
434
435 181 action = fpi_device_get_current_action (device);
436
437
1/2
✓ Branch 0 taken 181 times.
✗ Branch 1 not taken.
181 g_assert (action != FPI_DEVICE_ACTION_OPEN);
438
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 181 times.
181 g_assert (action != FPI_DEVICE_ACTION_CLOSE);
439
440
2/2
✓ Branch 0 taken 87 times.
✓ Branch 1 taken 94 times.
268 g_debug ("Image device reported finger status: %s", present ? "on" : "off");
441
442 181 priv->finger_present = present;
443
444
4/4
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 87 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 46 times.
181 if (present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON)
445 {
446 48 fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_CAPTURE);
447 }
448
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 39 times.
87 else if (!present && priv->state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF)
449 {
450 /* If we are in the non-enroll case, we always deactivate.
451 *
452 * In the enroll case, the decision can only be made after minutiae
453 * detection has finished.
454 */
455 48 fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_IDLE);
456
457
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 25 times.
48 if (action != FPI_DEVICE_ACTION_ENROLL)
458 23 fpi_image_device_deactivate (self, FALSE);
459 else
460 25 fp_image_device_enroll_maybe_await_finger_on (self);
461 }
462 }
463
464 /**
465 * fpi_image_device_image_captured:
466 * @self: a #FpImageDevice imaging fingerprint device
467 * @image: whether the finger is present on the sensor
468 *
469 * Reports an image capture. Only use this function if the image was
470 * captured successfully. If there was an issue where the user should
471 * retry, use fpi_image_device_retry_scan() to report the retry condition.
472 *
473 * In the event of a fatal error for the operation use
474 * fpi_image_device_session_error(). This will abort the entire operation
475 * including e.g. an enroll operation which captures multiple images during
476 * one session.
477 */
478 void
479 48 fpi_image_device_image_captured (FpImageDevice *self, FpImage *image)
480 {
481 48 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
482 48 FpiDeviceAction action;
483
484 48 action = fpi_device_get_current_action (FP_DEVICE (self));
485
486
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 g_return_if_fail (image != NULL);
487
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_CAPTURE);
488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
489 action == FPI_DEVICE_ACTION_VERIFY ||
490 action == FPI_DEVICE_ACTION_IDENTIFY ||
491 action == FPI_DEVICE_ACTION_CAPTURE);
492
493 48 g_debug ("Image device captured an image");
494
495 48 priv->minutiae_scan_active = TRUE;
496
497 /* XXX: We also detect minutiae in capture mode, we solely do this
498 * to normalize the image which will happen as a by-product. */
499 48 fp_image_detect_minutiae (image,
500 fpi_device_get_cancellable (FP_DEVICE (self)),
501 fpi_image_device_minutiae_detected,
502 self);
503
504 /* XXX: This is wrong if we add support for raw capture mode. */
505 48 fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
506 }
507
508 /**
509 * fpi_image_device_retry_scan:
510 * @self: a #FpImageDevice imaging fingerprint device
511 * @retry: The #FpDeviceRetry error code to report
512 *
513 * Reports a scan failure to the user. This may or may not abort the
514 * current session. It is the equivalent of fpi_image_device_image_captured()
515 * in the case of a retryable error condition (e.g. short swipe).
516 */
517 void
518 2 fpi_image_device_retry_scan (FpImageDevice *self, FpDeviceRetry retry)
519 {
520 2 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
521 2 FpiDeviceAction action;
522 2 GError *error;
523
524 2 action = fpi_device_get_current_action (FP_DEVICE (self));
525
526 /* We might be waiting for a finger at this point, so just accept
527 * all but INACTIVE */
528
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 g_return_if_fail (priv->state != FPI_IMAGE_DEVICE_STATE_INACTIVE);
529
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
530 action == FPI_DEVICE_ACTION_VERIFY ||
531 action == FPI_DEVICE_ACTION_IDENTIFY ||
532 action == FPI_DEVICE_ACTION_CAPTURE);
533
534 2 error = fpi_device_retry_new (retry);
535
536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (action == FPI_DEVICE_ACTION_ENROLL)
537 {
538 g_debug ("Reporting retry during enroll");
539 fpi_device_enroll_progress (FP_DEVICE (self), priv->enroll_stage, NULL, error);
540
541 fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_OFF);
542 }
543
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 else if (action == FPI_DEVICE_ACTION_VERIFY)
544 {
545 1 fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
546 1 fp_image_device_maybe_complete_action (self, NULL);
547 1 fpi_image_device_deactivate (self, TRUE);
548
549 }
550
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (action == FPI_DEVICE_ACTION_IDENTIFY)
551 {
552 1 fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
553 1 fp_image_device_maybe_complete_action (self, NULL);
554 1 fpi_image_device_deactivate (self, TRUE);
555 }
556 else
557 {
558 /* The capture case where there is no early reporting. */
559 g_debug ("Abort current operation due to retry (no early-reporting)");
560 fp_image_device_maybe_complete_action (self, error);
561 fpi_image_device_deactivate (self, TRUE);
562 }
563 }
564
565 /**
566 * fpi_image_device_session_error:
567 * @self: a #FpImageDevice imaging fingerprint device
568 * @error: (nullable) (transfer full): The #GError to report.
569 *
570 * Report an error while interacting with the device. This effectively
571 * aborts the current ongoing action. Note that doing so will result in
572 * the deactivation handler to be called and this function must not be
573 * used to report an error during deactivation.
574 */
575 void
576 3 fpi_image_device_session_error (FpImageDevice *self, GError *error)
577 {
578 3 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
579
580
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 g_return_if_fail (self);
581
582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!error)
583 {
584 g_warning ("Driver did not provide an error, generating a generic one");
585 error = g_error_new (FP_DEVICE_ERROR, FP_DEVICE_ERROR_GENERAL, "Driver reported session error without an error");
586 }
587
588
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!priv->active)
589 {
590 FpiDeviceAction action = fpi_device_get_current_action (FP_DEVICE (self));
591 g_warning ("Driver reported session error, but device is inactive.");
592
593 if (action != FPI_DEVICE_ACTION_NONE)
594 {
595 g_warning ("Translating to activation failure!");
596 fpi_image_device_activate_complete (self, error);
597 return;
598 }
599 }
600
1/4
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
3 else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) &&
601 fpi_device_action_is_cancelled (FP_DEVICE (self)))
602 {
603 /* Ignore cancellation errors here, as we will explicitly deactivate
604 * anyway (or, may already have done so at this point).
605 */
606 g_debug ("Driver reported a cancellation error, this is expected but not required. Ignoring.");
607 g_clear_error (&error);
608 return;
609 }
610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 else if (priv->state == FPI_IMAGE_DEVICE_STATE_INACTIVE)
611 {
612 g_warning ("Driver reported session error while deactivating already, ignoring. This indicates a driver bug.");
613 g_clear_error (&error);
614 return;
615 }
616
617
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (error->domain == FP_DEVICE_RETRY)
618 g_warning ("Driver should report retries using fpi_image_device_retry_scan!");
619
620 3 fp_image_device_maybe_complete_action (self, error);
621 3 fpi_image_device_deactivate (self, TRUE);
622 }
623
624 /**
625 * fpi_image_device_activate_complete:
626 * @self: a #FpImageDevice imaging fingerprint device
627 * @error: (nullable) (transfer full): The #GError or %NULL on success
628 *
629 * Reports completion of device activation.
630 */
631 void
632 34 fpi_image_device_activate_complete (FpImageDevice *self, GError *error)
633 {
634 34 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
635 34 FpiDeviceAction action;
636
637 34 action = fpi_device_get_current_action (FP_DEVICE (self));
638
639
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 g_return_if_fail (priv->active == FALSE);
640
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_ACTIVATING);
641
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 g_return_if_fail (action == FPI_DEVICE_ACTION_ENROLL ||
642 action == FPI_DEVICE_ACTION_VERIFY ||
643 action == FPI_DEVICE_ACTION_IDENTIFY ||
644 action == FPI_DEVICE_ACTION_CAPTURE);
645
646
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (error)
647 {
648 g_debug ("Image device activation failed");
649 fpi_device_action_error (FP_DEVICE (self), error);
650 return;
651 }
652
653 34 g_debug ("Image device activation completed");
654
655 34 priv->active = TRUE;
656
657 /* We always want to capture at this point, move to AWAIT_FINGER
658 * state. */
659 34 fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_IDLE);
660 34 fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON);
661 }
662
663 /**
664 * fpi_image_device_deactivate_complete:
665 * @self: a #FpImageDevice imaging fingerprint device
666 * @error: (nullable) (transfer full): The #GError or %NULL on success
667 *
668 * Reports completion of device deactivation.
669 */
670 void
671 34 fpi_image_device_deactivate_complete (FpImageDevice *self, GError *error)
672 {
673 34 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
674
675
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
34 g_return_if_fail (priv->active == TRUE);
676
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 g_return_if_fail (priv->state == FPI_IMAGE_DEVICE_STATE_DEACTIVATING);
677
678 34 g_debug ("Image device deactivation completed");
679
680 34 priv->active = FALSE;
681
682 /* Assume finger was removed. */
683 34 priv->finger_present = FALSE;
684
685 34 fp_image_device_change_state (self, FPI_IMAGE_DEVICE_STATE_INACTIVE);
686
687 34 fp_image_device_maybe_complete_action (self, error);
688 }
689
690 /**
691 * fpi_image_device_open_complete:
692 * @self: a #FpImageDevice imaging fingerprint device
693 * @error: (nullable) (transfer full): The #GError or %NULL on success
694 *
695 * Reports completion of open operation.
696 */
697 void
698 41 fpi_image_device_open_complete (FpImageDevice *self, GError *error)
699 {
700 41 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
701 41 FpiDeviceAction action;
702
703 41 action = fpi_device_get_current_action (FP_DEVICE (self));
704
705
1/2
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
41 g_return_if_fail (priv->active == FALSE);
706
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 g_return_if_fail (action == FPI_DEVICE_ACTION_OPEN);
707
708 41 g_debug ("Image device open completed");
709
710 41 priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
711 41 g_object_notify (G_OBJECT (self), "fpi-image-device-state");
712
713 41 fpi_device_report_finger_status (FP_DEVICE (self), FP_FINGER_STATUS_NONE);
714
715 41 fpi_device_open_complete (FP_DEVICE (self), error);
716 }
717
718 /**
719 * fpi_image_device_close_complete:
720 * @self: a #FpImageDevice imaging fingerprint device
721 * @error: (nullable) (transfer full): The #GError or %NULL on success
722 *
723 * Reports completion of close operation.
724 */
725 void
726 41 fpi_image_device_close_complete (FpImageDevice *self, GError *error)
727 {
728 41 FpImageDevicePrivate *priv = fp_image_device_get_instance_private (self);
729 41 FpiDeviceAction action;
730
731 41 action = fpi_device_get_current_action (FP_DEVICE (self));
732
733 41 g_debug ("Image device close completed");
734
735
1/2
✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
41 g_return_if_fail (priv->active == FALSE);
736
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 g_return_if_fail (action == FPI_DEVICE_ACTION_CLOSE);
737
738 41 priv->state = FPI_IMAGE_DEVICE_STATE_INACTIVE;
739 41 g_object_notify (G_OBJECT (self), "fpi-image-device-state");
740
741 41 fpi_device_close_complete (FP_DEVICE (self), error);
742 }
743