GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 79.2% 210 / 0 / 265
Functions: 93.8% 15 / 0 / 16
Branches: 57.4% 101 / 0 / 176

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