diff --git a/libfprint/fp-device-private.h b/libfprint/fp-device-private.h index 5bf5954..c32cdf7 100644 --- a/libfprint/fp-device-private.h +++ b/libfprint/fp-device-private.h @@ -49,7 +49,8 @@ typedef struct GSource *current_task_idle_return_source; /* State for tasks */ - gboolean wait_for_finger; + gboolean wait_for_finger; + FpFingerStatusFlags finger_status; } FpDevicePrivate; diff --git a/libfprint/fp-device.c b/libfprint/fp-device.c index 1e61447..c6fb7e3 100644 --- a/libfprint/fp-device.c +++ b/libfprint/fp-device.c @@ -46,6 +46,7 @@ enum { PROP_OPEN, PROP_NR_ENROLL_STAGES, PROP_SCAN_TYPE, + PROP_FINGER_STATUS, PROP_FPI_ENVIRON, PROP_FPI_USB_DEVICE, PROP_FPI_DRIVER_DATA, @@ -181,6 +182,10 @@ fp_device_get_property (GObject *object, g_value_set_enum (value, priv->scan_type); break; + case PROP_FINGER_STATUS: + g_value_set_enum (value, priv->finger_status); + break; + case PROP_DRIVER: g_value_set_static_string (value, FP_DEVICE_GET_CLASS (priv)->id); break; @@ -310,6 +315,13 @@ fp_device_class_init (FpDeviceClass *klass) FP_TYPE_SCAN_TYPE, FP_SCAN_TYPE_SWIPE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + properties[PROP_FINGER_STATUS] = + g_param_spec_flags ("finger-status", + "FingerStatus", + "The status of the finger", + FP_TYPE_FINGER_STATUS_FLAGS, FP_FINGER_STATUS_NONE, + G_PARAM_STATIC_STRINGS | G_PARAM_READABLE); + properties[PROP_DRIVER] = g_param_spec_string ("driver", "Driver", @@ -469,6 +481,26 @@ fp_device_get_scan_type (FpDevice *device) return priv->scan_type; } +/** + * fp_device_get_finger_status: + * @device: A #FpDevice + * + * Retrieves the finger status flags for the device. + * This can be used by the UI to present the relevant feedback, although it + * is not guaranteed to be a relevant value when not performing any action. + * + * Returns: The current #FpFingerStatusFlags + */ +FpFingerStatusFlags +fp_device_get_finger_status (FpDevice *device) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + + g_return_val_if_fail (FP_IS_DEVICE (device), FP_SCAN_TYPE_SWIPE); + + return priv->finger_status; +} + /** * fp_device_get_nr_enroll_stages: * @device: A #FpDevice diff --git a/libfprint/fp-device.h b/libfprint/fp-device.h index 0be64ec..e1cb8a2 100644 --- a/libfprint/fp-device.h +++ b/libfprint/fp-device.h @@ -170,6 +170,7 @@ const gchar *fp_device_get_device_id (FpDevice *device); const gchar *fp_device_get_name (FpDevice *device); gboolean fp_device_is_open (FpDevice *device); FpScanType fp_device_get_scan_type (FpDevice *device); +FpFingerStatusFlags fp_device_get_finger_status (FpDevice *device); gint fp_device_get_nr_enroll_stages (FpDevice *device); gboolean fp_device_supports_identify (FpDevice *device); diff --git a/libfprint/fp-print.h b/libfprint/fp-print.h index 3408e73..39cf87c 100644 --- a/libfprint/fp-print.h +++ b/libfprint/fp-print.h @@ -66,6 +66,18 @@ typedef enum { FP_FINGER_LAST = FP_FINGER_RIGHT_LITTLE, } FpFinger; +/** + * FpFingerStatusFlags: + * @FP_FINGER_STATUS_NONE: Sensor has not the finger on it, nor requires it + * @FP_FINGER_STATUS_NEEDED: Sensor waits for the finger + * @FP_FINGER_STATUS_PRESENT: Sensor has the finger on it + */ +typedef enum { + FP_FINGER_STATUS_NONE = 0, + FP_FINGER_STATUS_NEEDED = 1 << 0, + FP_FINGER_STATUS_PRESENT = 1 << 1, +} FpFingerStatusFlags; + FpPrint *fp_print_new (FpDevice *device); FpPrint *fp_print_new_from_data (guchar *data, diff --git a/libfprint/fpi-device.c b/libfprint/fpi-device.c index e62ab19..d94ae67 100644 --- a/libfprint/fpi-device.c +++ b/libfprint/fpi-device.c @@ -1394,3 +1394,59 @@ fpi_device_identify_report (FpDevice *device, if (call_cb && data->match_cb) data->match_cb (device, data->match, data->print, data->match_data, data->error); } + +/** + * fpi_device_report_finger_status: + * @device: The #FpDevice + * @finger_status: The current #FpFingerStatusFlags to report + * + * Report the finger status for the @device. + * This can be used by UI to give a feedback + * + * Returns: %TRUE if changed + */ +gboolean +fpi_device_report_finger_status (FpDevice *device, + FpFingerStatusFlags finger_status) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + g_autofree char *status_string = NULL; + + if (priv->finger_status == finger_status) + return FALSE; + + status_string = g_flags_to_string (FP_TYPE_FINGER_STATUS_FLAGS, finger_status); + fp_dbg ("Device reported finger status change: %s", status_string); + + priv->finger_status = finger_status; + g_object_notify (G_OBJECT (device), "finger-status"); + + return TRUE; +} + +/** + * fpi_device_report_finger_status_changes: + * @device: The #FpDevice + * @added_status: The #FpFingerStatusFlags to add + * @added_status: The #FpFingerStatusFlags to remove + * + * Report the finger status for the @device adding the @added_status flags + * and removing the @removed_status flags. + * + * This can be used by UI to give a feedback + * + * Returns: %TRUE if changed + */ +gboolean +fpi_device_report_finger_status_changes (FpDevice *device, + FpFingerStatusFlags added_status, + FpFingerStatusFlags removed_status) +{ + FpDevicePrivate *priv = fp_device_get_instance_private (device); + FpFingerStatusFlags finger_status = priv->finger_status; + + finger_status |= added_status; + finger_status &= ~removed_status; + + return fpi_device_report_finger_status (device, finger_status); +} diff --git a/libfprint/fpi-device.h b/libfprint/fpi-device.h index 94cdb35..2bab022 100644 --- a/libfprint/fpi-device.h +++ b/libfprint/fpi-device.h @@ -255,4 +255,10 @@ void fpi_device_identify_report (FpDevice *device, FpPrint *print, GError *error); +gboolean fpi_device_report_finger_status (FpDevice *device, + FpFingerStatusFlags finger_status); +gboolean fpi_device_report_finger_status_changes (FpDevice *device, + FpFingerStatusFlags added_status, + FpFingerStatusFlags removed_status); + G_END_DECLS diff --git a/tests/test-fp-device.c b/tests/test-fp-device.c index a279b46..e3eb662 100644 --- a/tests/test-fp-device.c +++ b/tests/test-fp-device.c @@ -178,6 +178,15 @@ test_device_get_scan_type (void) g_assert_cmpint (fp_device_get_scan_type (tctx->device), ==, FP_SCAN_TYPE_SWIPE); } +static void +test_device_get_finger_status (void) +{ + g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_imgdev (); + + fp_device_open_sync (tctx->device, NULL, NULL); + g_assert_cmpint (fp_device_get_finger_status (tctx->device), ==, FP_FINGER_STATUS_NONE); +} + static void test_device_get_nr_enroll_stages (void) { @@ -229,6 +238,7 @@ main (int argc, char *argv[]) g_test_add_func ("/device/sync/get_device_id", test_device_get_device_id); g_test_add_func ("/device/sync/get_name", test_device_get_name); g_test_add_func ("/device/sync/get_scan_type", test_device_get_scan_type); + g_test_add_func ("/device/sync/get_finger_status", test_device_get_finger_status); g_test_add_func ("/device/sync/get_nr_enroll_stages", test_device_get_nr_enroll_stages); g_test_add_func ("/device/sync/supports_identify", test_device_supports_identify); g_test_add_func ("/device/sync/supports_capture", test_device_supports_capture); diff --git a/tests/test-fpi-device.c b/tests/test-fpi-device.c index d415258..2b6b256 100644 --- a/tests/test-fpi-device.c +++ b/tests/test-fpi-device.c @@ -200,6 +200,147 @@ test_driver_set_scan_type_swipe (void) g_assert_cmpstr (pspec->name, ==, "scan-type"); } +static void +test_driver_finger_status_inactive (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + + g_signal_connect (device, "notify::finger-status", G_CALLBACK (on_device_notify), NULL); + + g_assert_false (fpi_device_report_finger_status (device, FP_FINGER_STATUS_NONE)); + g_assert_cmpuint (fp_device_get_finger_status (device), ==, FP_FINGER_STATUS_NONE); + g_assert (fake_dev->last_called_function != on_device_notify); + g_assert_null (g_steal_pointer (&fake_dev->user_data)); +} + +static void +test_driver_finger_status_needed (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + g_autoptr(GParamSpec) pspec = NULL; + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + + g_signal_connect (device, "notify::finger-status", G_CALLBACK (on_device_notify), NULL); + + g_assert_true (fpi_device_report_finger_status (device, FP_FINGER_STATUS_NEEDED)); + g_assert_cmpuint (fp_device_get_finger_status (device), ==, FP_FINGER_STATUS_NEEDED); + + g_assert (fake_dev->last_called_function == on_device_notify); + pspec = g_steal_pointer (&fake_dev->user_data); + g_assert_cmpstr (pspec->name, ==, "finger-status"); + + fake_dev->last_called_function = NULL; + g_assert_false (fpi_device_report_finger_status (device, FP_FINGER_STATUS_NEEDED)); + g_assert_null (fake_dev->last_called_function); + g_assert_null (g_steal_pointer (&fake_dev->user_data)); +} + +static void +test_driver_finger_status_present (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + g_autoptr(GParamSpec) pspec = NULL; + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + + g_signal_connect (device, "notify::finger-status", G_CALLBACK (on_device_notify), NULL); + + g_assert_true (fpi_device_report_finger_status (device, FP_FINGER_STATUS_PRESENT)); + g_assert_cmpuint (fp_device_get_finger_status (device), ==, FP_FINGER_STATUS_PRESENT); + + g_assert (fake_dev->last_called_function == on_device_notify); + pspec = g_steal_pointer (&fake_dev->user_data); + g_assert_cmpstr (pspec->name, ==, "finger-status"); + + fake_dev->last_called_function = NULL; + g_assert_false (fpi_device_report_finger_status (device, FP_FINGER_STATUS_PRESENT)); + g_assert_null (fake_dev->last_called_function); + g_assert_null (g_steal_pointer (&fake_dev->user_data)); +} + +static void +driver_finger_status_changes_check (FpDevice *device, gboolean add) +{ + FpiDeviceFake *fake_dev = FPI_DEVICE_FAKE (device); + + g_autoptr(GFlagsClass) status_class = g_type_class_ref (FP_TYPE_FINGER_STATUS_FLAGS); + guint expected_status; + guint initial_value; + guint i; + gulong signal_id; + + if (add) + initial_value = FP_FINGER_STATUS_NONE; + else + initial_value = status_class->mask; + + g_assert_cmpuint (fp_device_get_finger_status (device), ==, initial_value); + + signal_id = g_signal_connect (device, "notify::finger-status", + G_CALLBACK (on_device_notify), NULL); + + for (i = 0, expected_status = initial_value; i < status_class->n_values; ++i) + { + g_autoptr(GParamSpec) pspec = NULL; + FpFingerStatusFlags finger_status = status_class->values[i].value; + FpFingerStatusFlags added_status = add ? finger_status : FP_FINGER_STATUS_NONE; + FpFingerStatusFlags removed_status = add ? FP_FINGER_STATUS_NONE : finger_status; + gboolean ret; + + fake_dev->last_called_function = NULL; + ret = fpi_device_report_finger_status_changes (device, + added_status, + removed_status); + if (finger_status != FP_FINGER_STATUS_NONE) + g_assert_true (ret); + else + g_assert_false (ret); + + expected_status |= added_status; + expected_status &= ~removed_status; + + g_assert_cmpuint (fp_device_get_finger_status (device), ==, expected_status); + + if (finger_status != FP_FINGER_STATUS_NONE) + { + g_assert (fake_dev->last_called_function == on_device_notify); + pspec = g_steal_pointer (&fake_dev->user_data); + g_assert_cmpstr (pspec->name, ==, "finger-status"); + } + + fake_dev->last_called_function = NULL; + g_assert_false (fpi_device_report_finger_status_changes (device, + added_status, + removed_status)); + g_assert_null (fake_dev->last_called_function); + g_assert_null (g_steal_pointer (&fake_dev->user_data)); + } + + if (add) + g_assert_cmpuint (fp_device_get_finger_status (device), ==, status_class->mask); + else + g_assert_cmpuint (fp_device_get_finger_status (device), ==, FP_FINGER_STATUS_NONE); + + fake_dev->last_called_function = NULL; + g_assert_false (fpi_device_report_finger_status_changes (device, + FP_FINGER_STATUS_NONE, + FP_FINGER_STATUS_NONE)); + + g_assert_null (fake_dev->last_called_function); + g_assert_null (g_steal_pointer (&fake_dev->user_data)); + + g_signal_handler_disconnect (device, signal_id); +} + +static void +test_driver_finger_status_changes (void) +{ + g_autoptr(FpDevice) device = g_object_new (FPI_TYPE_DEVICE_FAKE, NULL); + + driver_finger_status_changes_check (device, TRUE); + driver_finger_status_changes_check (device, FALSE); +} + static void test_driver_get_nr_enroll_stages (void) { @@ -2207,6 +2348,10 @@ main (int argc, char *argv[]) g_test_add_func ("/driver/get_scan_type/swipe", test_driver_get_scan_type_swipe); g_test_add_func ("/driver/set_scan_type/press", test_driver_set_scan_type_press); g_test_add_func ("/driver/set_scan_type/swipe", test_driver_set_scan_type_swipe); + g_test_add_func ("/driver/finger_status/inactive", test_driver_finger_status_inactive); + g_test_add_func ("/driver/finger_status/waiting", test_driver_finger_status_needed); + g_test_add_func ("/driver/finger_status/present", test_driver_finger_status_present); + g_test_add_func ("/driver/finger_status/changes", test_driver_finger_status_changes); g_test_add_func ("/driver/get_nr_enroll_stages", test_driver_get_nr_enroll_stages); g_test_add_func ("/driver/set_nr_enroll_stages", test_driver_set_nr_enroll_stages); g_test_add_func ("/driver/supports_identify", test_driver_supports_identify);