diff --git a/libfprint/drivers/virtual-device-private.h b/libfprint/drivers/virtual-device-private.h index 08d6736..d0d8077 100644 --- a/libfprint/drivers/virtual-device-private.h +++ b/libfprint/drivers/virtual-device-private.h @@ -78,6 +78,7 @@ struct _FpDeviceVirtualDevice GHashTable *prints_storage; guint wait_command_id; + guint sleep_timeout_id; guint enroll_stages_passed; }; diff --git a/libfprint/drivers/virtual-device.c b/libfprint/drivers/virtual-device.c index e462a2b..61e98df 100644 --- a/libfprint/drivers/virtual-device.c +++ b/libfprint/drivers/virtual-device.c @@ -40,6 +40,7 @@ G_DEFINE_TYPE (FpDeviceVirtualDevice, fpi_device_virtual_device, FP_TYPE_DEVICE) #define ERROR_CMD_PREFIX "ERROR " #define RETRY_CMD_PREFIX "RETRY " #define FINGER_CMD_PREFIX "FINGER " +#define SLEEP_CMD_PREFIX "SLEEP " #define SET_ENROLL_STAGES_PREFIX "SET_ENROLL_STAGES " #define SET_SCAN_TYPE_PREFIX "SET_SCAN_TYPE " @@ -70,10 +71,26 @@ maybe_continue_current_action (FpDeviceVirtualDevice *self) } } +static gboolean +sleep_timeout_cb (gpointer data) +{ + FpDeviceVirtualDevice *self = data; + + self->sleep_timeout_id = 0; + + if (g_cancellable_is_cancelled (self->cancellable)) + return FALSE; + + g_debug ("Sleeping completed"); + maybe_continue_current_action (self); + + return FALSE; +} + char * process_cmds (FpDeviceVirtualDevice * self, - gboolean scan, - GError * *error) + gboolean scan, + GError **error) { while (self->pending_commands->len > 0) { @@ -101,6 +118,16 @@ process_cmds (FpDeviceVirtualDevice * self, g_ptr_array_remove_index (self->pending_commands, 0); continue; } + else if (g_str_has_prefix (cmd, SLEEP_CMD_PREFIX)) + { + guint64 sleep_ms = g_ascii_strtoull (cmd + strlen (SLEEP_CMD_PREFIX), NULL, 10); + + g_debug ("Sleeping %lums", sleep_ms); + self->sleep_timeout_id = g_timeout_add (sleep_ms, sleep_timeout_cb, self); + g_ptr_array_remove_index (self->pending_commands, 0); + + return NULL; + } /* If we are not scanning, then we have to stop here. */ if (!scan) @@ -300,6 +327,9 @@ gboolean should_wait_for_command (FpDeviceVirtualDevice *self, GError *error) { + if (!error && self->sleep_timeout_id) + return TRUE; + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) return FALSE; @@ -433,6 +463,7 @@ dev_deinit (FpDevice *dev) FpDeviceVirtualDevice *self = FP_DEVICE_VIRTUAL_DEVICE (dev); g_clear_handle_id (&self->wait_command_id, g_source_remove); + g_clear_handle_id (&self->sleep_timeout_id, g_source_remove); g_cancellable_cancel (self->cancellable); g_clear_object (&self->cancellable); g_clear_object (&self->listener); diff --git a/tests/virtual-device.py b/tests/virtual-device.py index 919c724..323b23a 100644 --- a/tests/virtual-device.py +++ b/tests/virtual-device.py @@ -96,7 +96,7 @@ class VirtualDevice(unittest.TestCase): def send_command(self, command, *args): self.assertIn(command, ['INSERT', 'REMOVE', 'SCAN', 'ERROR', 'RETRY', - 'FINGER', 'UNPLUG', 'SET_ENROLL_STAGES', 'SET_SCAN_TYPE']) + 'FINGER', 'UNPLUG', 'SLEEP', 'SET_ENROLL_STAGES', 'SET_SCAN_TYPE']) with Connection(self.sockaddr) as con: params = ' '.join(str(p) for p in args) @@ -439,6 +439,24 @@ class VirtualDevice(unittest.TestCase): with self.assertRaisesRegex(GLib.GError, 'device has been removed from the system'): self.dev.close_sync() + def test_device_sleep(self): + enrolled = self.enroll_print('testprint', FPrint.Finger.LEFT_LITTLE) + + timeout_reached = False + def on_timeout(): + nonlocal timeout_reached + timeout_reached = True + + self.send_command('SLEEP', 1500) + GLib.timeout_add(300, on_timeout) + + self.start_verify(enrolled, identify=self.dev.supports_identify()) + while not timeout_reached: + ctx.iteration(False) + + self.assertFalse(self._verify_completed) + self.cancel_verify() + class VirtualDeviceStorage(VirtualDevice): def tearDown(self):