--- /dev/null
+#include <stdlib.h>
+#include <gio/gio.h>
+#include <libsyscommon/libgdbus.h>
+
+#include "power-internal.h"
+#include "common.h"
+
+#define SLEEP_DBUS_SIGNAME "sleep"
+#define DBUS_METHOD_SYNC_CALL_TIMEOUT_MS 10000 /* 10 second */
+
+struct userdata {
+ void *data;
+ sleep_callback callback;
+};
+
+static int signal_subscribe_id = -1;
+
+static void signal_unsubscribed_callback(void *data)
+{
+ struct userdata *ud = (struct userdata *) data;
+
+ free(ud);
+}
+
+static void signal_callback(GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
+{
+ guint64 sleep_time_ms;
+ guint64 sleep_id;
+ struct userdata *ud = (struct userdata *) user_data;
+ int retval;
+
+ g_variant_get(parameters, "(tt)", &sleep_time_ms, &sleep_id);
+
+ if (!ud || !ud->callback)
+ return;
+
+ retval = ud->callback(sleep_time_ms, ud->data);
+ if (retval == DEVICE_SLEEP_READY) {
+ g_dbus_connection_call_sync(connection,
+ DEVICED_BUS_NAME,
+ DEVICED_PATH_POWER,
+ DEVICED_INTERFACE_POWER,
+ "ConfirmSleepWait",
+ g_variant_new("(i)", sleep_id),
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
+ NULL,
+ NULL);
+ }
+}
+
+int device_power_add_sleep_callback(sleep_callback cb, void *data)
+{
+ GDBusConnection *connection;
+ GVariant *retval;
+ GError *err = NULL;
+ struct userdata *ud;
+
+ if (signal_subscribe_id != -1)
+ return DEVICE_ERROR_ALREADY_IN_PROGRESS;
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+ if (!connection) {
+ _E("Failed to get dbus connection, %s", err->message);
+ g_clear_error(&err);
+ return DEVICE_ERROR_OPERATION_FAILED;
+ }
+
+ ud = malloc(sizeof(struct userdata));
+ if (!ud) {
+ _E("Failed to alloc user data");
+ return DEVICE_ERROR_OPERATION_FAILED;
+ }
+
+ retval = g_dbus_connection_call_sync(connection,
+ DEVICED_BUS_NAME,
+ DEVICED_PATH_POWER,
+ DEVICED_INTERFACE_POWER,
+ "AddSleepWait",
+ NULL,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
+ NULL,
+ &err);
+ if (!retval || err) {
+ _E("Failed to request AddSleepWait, %s", err->message);
+ g_error_free(err);
+ return DEVICE_ERROR_OPERATION_FAILED;
+ }
+
+ ud->data = data;
+ ud->callback = cb;
+
+ signal_subscribe_id = g_dbus_connection_signal_subscribe(connection,
+ DEVICED_BUS_NAME,
+ DEVICED_INTERFACE_POWER,
+ SLEEP_DBUS_SIGNAME,
+ DEVICED_PATH_POWER,
+ NULL,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ signal_callback,
+ ud,
+ signal_unsubscribed_callback);
+
+ return DEVICE_ERROR_NONE;
+}
+
+void device_power_remove_sleep_callback(void)
+{
+ GError *err = NULL;
+ GDBusConnection *connection;
+
+ if (signal_subscribe_id == -1)
+ return;
+
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+ if (!connection) {
+ _E("Failed to get dbus connection, %s", err->message);
+ g_clear_error(&err);
+ return;
+ }
+
+ g_dbus_connection_signal_unsubscribe(connection, signal_subscribe_id);
+ signal_subscribe_id = -1;
+
+ g_dbus_connection_call_sync(connection,
+ DEVICED_BUS_NAME,
+ DEVICED_PATH_POWER,
+ DEVICED_INTERFACE_POWER,
+ "RemoveSleepWait",
+ NULL,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ DBUS_METHOD_SYNC_CALL_TIMEOUT_MS,
+ NULL,
+ NULL);
+}