Skip to content
Snippets Groups Projects
Commit 4c970cb5 authored by Guillaume Desmottes's avatar Guillaume Desmottes
Browse files

service: add TrpServiceTurnByTurnNotification


API meant to be used by the navigation system to send turn-by-turn
notifications to the guidance UI.

Signed-off-by: default avatarGuillaume Desmottes <guillaume.desmottes@collabora.co.uk>
Reviewed-by: default avatarEmmanuel Gil Peyrot <emmanuel.peyrot@collabora.com>
Differential Revision: https://phabricator.apertis.org/D4698
parent fa2d0e43
No related branches found
No related tags found
No related merge requests found
......@@ -203,6 +203,7 @@ traprain_serviceincludedir = $(includedir)/traprain-service-@TRP_API_VERSION@
traprain_service_headers = \
traprain-service/navigation-guidance-progress.h \
traprain-service/navigation.h \
traprain-service/turn-by-turn-notification.h \
$(NULL)
traprain_service_private_headers =\
......@@ -218,6 +219,7 @@ traprain_service_sources = \
traprain-service/navigation-guidance-progress.c \
traprain-service/navigation.c \
traprain-service/route.c \
traprain-service/turn-by-turn-notification.c \
$(NULL)
traprain_service_libtraprain_service_internal_la_SOURCES = \
......@@ -777,6 +779,7 @@ tests_test_guidance_turn_by_turn_LDFLAGS = \
tests_test_guidance_turn_by_turn_LDADD = \
$(TRAPRAIN_LIBS) \
$(top_builddir)/traprain-guidance/libtraprain-guidance-internal.la \
$(top_builddir)/traprain-service/libtraprain-service-internal.la \
$(NULL)
EXTRA_DIST += tests/services/org.apertis.Navigation1.service.in
......
......@@ -12,6 +12,7 @@
#include <glib.h>
#include "traprain-guidance/turn-by-turn-service.h"
#include "traprain-service/turn-by-turn-notification.h"
#include "dbus/org.apertis.NavigationGuidance1.TurnByTurn.h"
......@@ -163,6 +164,36 @@ test_service_invalidated (Test *test,
g_assert_error (test->error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER);
}
static void
send_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
TrpServiceTurnByTurnNotification *notif = TRP_SERVICE_TURN_BY_TURN_NOTIFICATION (source);
Test *test = user_data;
g_clear_error (&test->error);
test->result = trp_service_turn_by_turn_notification_send_finish (notif, result, &test->error);
g_main_loop_quit (test->loop);
}
/* Create a notification and try sending it despite no service running */
static void
test_client_create_notification (Test *test,
gconstpointer unused)
{
g_autoptr (TrpServiceTurnByTurnNotification) notif = NULL;
notif = trp_service_turn_by_turn_notification_new (test->conn, "my summary", "my body", "my icon");
g_assert (TRP_SERVICE_IS_TURN_BY_TURN_NOTIFICATION (notif));
trp_service_turn_by_turn_notification_send_async (notif, -1, send_cb, test);
g_main_loop_run (test->loop);
g_assert (!test->result);
g_assert_error (test->error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN);
}
int
main (int argc,
char **argv)
......@@ -173,6 +204,8 @@ main (int argc,
setup, test_service_init, teardown);
g_test_add ("/guidance/turn-by-turn/service/invalidated", Test, NULL,
setup, test_service_invalidated, teardown);
g_test_add ("/guidance/turn-by-turn/client/create-notification", Test, NULL,
setup, test_client_create_notification, teardown);
return g_test_run ();
}
/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */
/*
* Copyright © 2016 Collabora Ltd.
*
* SPDX-License-Identifier: MPL-2.0
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "config.h"
#include "turn-by-turn-notification.h"
#define TBT_BUS_NAME "org.apertis.NavigationGuidance1.TurnByTurn"
#define TBT_PATH "/org/apertis/NavigationGuidance1/TurnByTurn"
#define TBT_IFACE "org.apertis.NavigationGuidance1.TurnByTurn"
/**
* SECTION: traprain-service/turn-by-turn-notification.h
* @title: TrpServiceTurnByTurnNotification
* @short_description: turn-by-turn navigation notification to be sent
*
* #TrpServiceTurnByTurnNotification are meant to be used by the navigation
* system to send turn-by-turn guidance notification popups to the UI
* responsible of displaying those.
*
* Once created using trp_service_turn_by_turn_notification_new(), the
* notification is sent for display using
* trp_service_turn_by_turn_notification_send_async().
*
* Previously sent notifications can be updated by updating their settings and
* re-calling trp_service_turn_by_turn_notification_send_async() on the same
* #TrpServiceTurnByTurnNotification object.
*
* trp_service_turn_by_turn_notification_close_async() can be used to stop
* displaying a notification before its expiration time is reached.
*
* Since: UNRELEASED
*/
/**
* TrpServiceTurnByTurnNotification:
*
* #TrpServiceTurnByTurnNotification is an object representing a guidance
* turn-by-turn notification to send to the guidance UI.
*
* Since: UNRELEASED
*/
struct _TrpServiceTurnByTurnNotification
{
GObject parent;
GDBusConnection *conn; /* owned */
gchar *summary;
gchar *body;
gchar *icon;
guint id; /* Notification ID returned by Notify() */
GCancellable *cancellable; /* owned */
};
typedef enum {
PROP_CONNECTION = 1,
PROP_SUMMARY,
PROP_BODY,
PROP_ICON,
/*< private >*/
PROP_LAST = PROP_ICON
} TrpServiceTurnByTurnNotificationProperty;
static GParamSpec *properties[PROP_LAST + 1];
G_DEFINE_TYPE (TrpServiceTurnByTurnNotification, trp_service_turn_by_turn_notification, G_TYPE_OBJECT)
static void
trp_service_turn_by_turn_notification_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
TrpServiceTurnByTurnNotification *self = TRP_SERVICE_TURN_BY_TURN_NOTIFICATION (object);
switch ((TrpServiceTurnByTurnNotificationProperty) prop_id)
{
case PROP_CONNECTION:
g_value_set_object (value, self->conn);
break;
case PROP_SUMMARY:
g_value_set_string (value, self->summary);
break;
case PROP_BODY:
g_value_set_string (value, self->body);
break;
case PROP_ICON:
g_value_set_string (value, self->icon);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
trp_service_turn_by_turn_notification_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
TrpServiceTurnByTurnNotification *self = TRP_SERVICE_TURN_BY_TURN_NOTIFICATION (object);
switch ((TrpServiceTurnByTurnNotificationProperty) prop_id)
{
case PROP_CONNECTION:
g_assert (self->conn == NULL); /* construct only */
self->conn = g_value_dup_object (value);
break;
case PROP_SUMMARY:
g_free (self->summary);
self->summary = g_value_dup_string (value);
break;
case PROP_BODY:
g_free (self->body);
self->body = g_value_dup_string (value);
break;
case PROP_ICON:
g_free (self->icon);
self->icon = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
trp_service_turn_by_turn_notification_dispose (GObject *object)
{
TrpServiceTurnByTurnNotification *self = (TrpServiceTurnByTurnNotification *) object;
g_cancellable_cancel (self->cancellable);
g_clear_object (&self->cancellable);
g_clear_object (&self->conn);
g_clear_pointer (&self->summary, g_free);
g_clear_pointer (&self->body, g_free);
g_clear_pointer (&self->icon, g_free);
G_OBJECT_CLASS (trp_service_turn_by_turn_notification_parent_class)
->dispose (object);
}
static void
trp_service_turn_by_turn_notification_class_init (TrpServiceTurnByTurnNotificationClass *klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
object_class->get_property = trp_service_turn_by_turn_notification_get_property;
object_class->set_property = trp_service_turn_by_turn_notification_set_property;
object_class->dispose = trp_service_turn_by_turn_notification_dispose;
/**
* TrpServiceTurnByTurnNotification:connection:
*
* The #GDBusConnection used to send the notification
*
* Since: UNRELEASED
*/
properties[PROP_CONNECTION] = g_param_spec_object (
"connection", "Connection", "GDBusConnection", G_TYPE_DBUS_CONNECTION,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
/**
* TrpServiceTurnByTurnNotification:summary:
*
* The summary text of the notification describing briefly the
* next action the driver has to take.
* Something like "Turn right in 100 meters" for example.
*
* Since: UNRELEASED
*/
properties[PROP_SUMMARY] = g_param_spec_string (
"summary", "Summary", "Summary", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
/**
* TrpServiceTurnByTurnNotification:body:
*
* The body text of the notification, or %NULL,
* giving more details about the turn-by-turn
* notification.
* Something like "Take right on Goat Street".
*
* Since: UNRELEASED
*/
properties[PROP_BODY] = g_param_spec_string (
"body", "Body", "Body", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
/**
* TrpServiceTurnByTurnNotification:icon:
*
* The icon name of the notification, or %NULL.
* This can be used to display, for example, an arrow pointing to
* the direction where the driver has to turn.
*
* Since: UNRELEASED
*/
properties[PROP_ICON] = g_param_spec_string (
"icon", "Icon", "Icon name", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (object_class, G_N_ELEMENTS (properties), properties);
}
static void
trp_service_turn_by_turn_notification_init (TrpServiceTurnByTurnNotification *self)
{
self->cancellable = g_cancellable_new ();
}
/**
* trp_service_turn_by_turn_notification_new:
* @conn: the #GDBusConnection to use to communicate with the guidance UI
* @summary: the summary text briefly describing the notification
* @body: (nullable): the detailed body text of the notification, or %NULL
* @icon: (nullable): the icon name to display with the notificiation, or %NULL
*
* Create a new turn-by-turn guidance notification. Once it's ready to be
* displayed by the guidance UI call
* trp_service_turn_by_turn_notification_send_async() on it.
*
* Returns: (transfer full): a new #TrpServiceTurnByTurnNotification
* Since: UNRELEASED
*/
TrpServiceTurnByTurnNotification *
trp_service_turn_by_turn_notification_new (GDBusConnection *conn,
const gchar *summary,
const gchar *body,
const gchar *icon)
{
g_return_val_if_fail (G_IS_DBUS_CONNECTION (conn), NULL);
g_return_val_if_fail (summary != NULL, NULL);
return g_object_new (TRP_SERVICE_TYPE_TURN_BY_TURN_NOTIFICATION,
"connection", conn,
"summary", summary,
"body", body,
"icon", icon,
NULL);
}
/**
* trp_service_turn_by_turn_notification_set_summary:
* @self: a #TrpServiceTurnByTurnNotification
* @summary: the new summary text
*
* Update the #TrpServiceTurnByTurnNotification:summary: property of @self.
*
* If the notification is already being displayed by the guidance UI it won't
* be updated until trp_service_turn_by_turn_notification_send_async() is
* re-called on @self.
*
* Since: UNRELEASED
*/
void
trp_service_turn_by_turn_notification_set_summary (TrpServiceTurnByTurnNotification *self,
const gchar *summary)
{
g_return_if_fail (TRP_SERVICE_IS_TURN_BY_TURN_NOTIFICATION (self));
g_return_if_fail (summary != NULL);
if (g_strcmp0 (self->summary, summary) == 0)
return;
g_free (self->summary);
self->summary = g_strdup (summary);
g_object_notify (G_OBJECT (self), "summary");
}
/**
* trp_service_turn_by_turn_notification_set_body:
* @self: a #TrpServiceTurnByTurnNotification
* @body: (nullable): the new body text, or %NULL
*
* Update the #TrpServiceTurnByTurnNotification:body: property of @self.
*
* If the notification is already being displayed by the guidance UI it won't
* be updated until trp_service_turn_by_turn_notification_send_async() is
* re-called on @self.
*
* Since: UNRELEASED
*/
void
trp_service_turn_by_turn_notification_set_body (TrpServiceTurnByTurnNotification *self,
const gchar *body)
{
g_return_if_fail (TRP_SERVICE_IS_TURN_BY_TURN_NOTIFICATION (self));
if (g_strcmp0 (self->body, body) == 0)
return;
g_clear_pointer (&self->body, g_free);
self->body = g_strdup (body);
g_object_notify (G_OBJECT (self), "body");
}
/**
* trp_service_turn_by_turn_notification_set_icon:
* @self: a #TrpServiceTurnByTurnNotification
* @icon: (nullable): the new icon name, or %NULL
*
* Update the #TrpServiceTurnByTurnNotification:icon: property of @self.
*
* If the notification is already being displayed by the guidance UI it won't
* be updated until trp_service_turn_by_turn_notification_send_async() is
* re-called on @self.
*
* Since: UNRELEASED
*/
void
trp_service_turn_by_turn_notification_set_icon (TrpServiceTurnByTurnNotification *self,
const gchar *icon)
{
g_return_if_fail (TRP_SERVICE_IS_TURN_BY_TURN_NOTIFICATION (self));
if (g_strcmp0 (self->icon, icon) == 0)
return;
g_clear_pointer (&self->icon, g_free);
self->icon = g_strdup (icon);
g_object_notify (G_OBJECT (self), "icon");
}
static GVariant *
create_notify_variant (TrpServiceTurnByTurnNotification *self,
gint expire_timeout)
{
/* We don't support any Hints at the moment so just pass an empty dict */
return g_variant_new ("(usss@a{sv}i)", self->id, self->icon ? self->icon : "",
self->summary, self->body ? self->body : "",
g_variant_new ("a{sv}", NULL), expire_timeout);
}
static void
notify_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr (GVariant) reply = NULL;
g_autoptr (GError) error = NULL;
g_autoptr (GTask) task = user_data;
TrpServiceTurnByTurnNotification *self = g_task_get_source_object (task);
reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
if (reply == NULL)
{
g_task_return_error (task, g_steal_pointer (&error));
return;
}
/* Save the returned ID so we'll re-use it if this notification is
* updated */
g_variant_get (reply, "(u)", &self->id);
g_task_return_boolean (task, TRUE);
}
/**
* trp_service_turn_by_turn_notification_send_async:
* @self: a #TrpServiceTurnByTurnNotification
* @expire_timeout: the timeout time in milliseconds since the display of the notification at which the notification should automatically close. If -1, the notification's expiration time is dependent on the notification server's settings, and may vary for the type of notification. If 0, never expire.
* @callback: callback to call when the request is satisfied.
* @user_data: the data to pass to @callback function.
*
* Send @self to the guidance UI to be displayed.
*
* When the operation is finished, @callback will be called.
* You can then call trp_service_turn_by_turn_notification_send_finish()
* to get the result of the operation.
*
* Since: UNRELEASED
*/
void
trp_service_turn_by_turn_notification_send_async (TrpServiceTurnByTurnNotification *self,
gint expire_timeout,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr (GTask) task = NULL;
g_return_if_fail (TRP_SERVICE_IS_TURN_BY_TURN_NOTIFICATION (self));
task = g_task_new (self, self->cancellable, callback, user_data);
g_task_set_source_tag (task, trp_service_turn_by_turn_notification_send_async);
/* There is no need to prepare and keep around a proxy object as we are
* just calling methods so use the g_dbus_connection_call() object directly. */
g_dbus_connection_call (self->conn, TBT_BUS_NAME, TBT_PATH, TBT_IFACE,
"Notify", create_notify_variant (self, expire_timeout), NULL,
G_DBUS_CALL_FLAGS_NONE, -1, self->cancellable,
notify_cb, g_steal_pointer (&task));
}
/**
* trp_service_turn_by_turn_notification_send_finish:
* @self: a #TrpServiceTurnByTurnNotification
* @result: a #GAsyncResult
* @error: a #GError, or %NULL
*
* Finishes an operation started with trp_service_turn_by_turn_notification_send_async().
*
* Returns: %TRUE if the operation succeeded, %FALSE otherwise
* Since: UNRELEASED
*/
gboolean
trp_service_turn_by_turn_notification_send_finish (TrpServiceTurnByTurnNotification *self,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
return g_task_propagate_boolean (G_TASK (result), error);
}
static void
close_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
g_autoptr (GVariant) reply = NULL;
g_autoptr (GError) error = NULL;
g_autoptr (GTask) task = user_data;
reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
if (reply == NULL)
{
g_task_return_error (task, g_steal_pointer (&error));
return;
}
g_task_return_boolean (task, TRUE);
}
/**
* trp_service_turn_by_turn_notification_close_async:
* @self: a #TrpServiceTurnByTurnNotification
* @callback: callback to call when the request is satisfied.
* @user_data: the data to pass to @callback function.
*
* Ask the guidance UI to stop displaying @self.
*
* You shouldn't call this function until at least one one sending operation
* (started using trp_service_turn_by_turn_notification_send_async()) has been completed.
*
* When the operation is finished, @callback will be called.
* You can then call trp_service_turn_by_turn_notification_close_finish()
* to get the result of the operation.
*
* Since: UNRELEASED
*/
void
trp_service_turn_by_turn_notification_close_async (TrpServiceTurnByTurnNotification *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_autoptr (GTask) task = NULL;
g_return_if_fail (TRP_SERVICE_IS_TURN_BY_TURN_NOTIFICATION (self));
task = g_task_new (self, self->cancellable, callback, user_data);
g_task_set_source_tag (task, trp_service_turn_by_turn_notification_close_async);
if (self->id == 0)
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
"Notification hasn't been send to server for displaying");
return;
}
g_dbus_connection_call (self->conn, TBT_BUS_NAME, TBT_PATH, TBT_IFACE,
"CloseNotification", g_variant_new ("(u)", self->id), NULL,
G_DBUS_CALL_FLAGS_NONE, -1, self->cancellable,
close_cb, g_steal_pointer (&task));
}
/**
* trp_service_turn_by_turn_notification_close_finish:
* @self: a #TrpServiceTurnByTurnNotification
* @result: a #GAsyncResult
* @error: a #GError, or %NULL
*
* Finishes an operation started with trp_service_turn_by_turn_notification_close_async().
*
* Returns: %TRUE if the operation succeeded, %FALSE otherwise
* Since: UNRELEASED
*/
gboolean
trp_service_turn_by_turn_notification_close_finish (TrpServiceTurnByTurnNotification *self,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
return g_task_propagate_boolean (G_TASK (result), error);
}
/* vim:set et sw=2 cin cino=t0,f0,(0,{s,>2s,n-s,^-s,e2s: */
/*
* Copyright © 2016 Collabora Ltd.
*
* SPDX-License-Identifier: MPL-2.0
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef __TRAPRAIN_SERVICE_TURN_BY_TURN_NOTIFICATION_H__
#define __TRAPRAIN_SERVICE_TURN_BY_TURN_NOTIFICATION_H__
#include <gio/gio.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define TRP_SERVICE_TYPE_TURN_BY_TURN_NOTIFICATION (trp_service_turn_by_turn_notification_get_type ())
G_DECLARE_FINAL_TYPE (TrpServiceTurnByTurnNotification, trp_service_turn_by_turn_notification, TRP_SERVICE, TURN_BY_TURN_NOTIFICATION, GObject)
TrpServiceTurnByTurnNotification *trp_service_turn_by_turn_notification_new (GDBusConnection *conn,
const gchar *summary,
const gchar *body,
const gchar *icon);
void trp_service_turn_by_turn_notification_set_summary (TrpServiceTurnByTurnNotification *self,
const gchar *summary);
void trp_service_turn_by_turn_notification_set_body (TrpServiceTurnByTurnNotification *self,
const gchar *body);
void trp_service_turn_by_turn_notification_set_icon (TrpServiceTurnByTurnNotification *self,
const gchar *icon);
void trp_service_turn_by_turn_notification_send_async (TrpServiceTurnByTurnNotification *self,
gint expire_timeout,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean trp_service_turn_by_turn_notification_send_finish (TrpServiceTurnByTurnNotification *self,
GAsyncResult *result,
GError **error);
void trp_service_turn_by_turn_notification_close_async (TrpServiceTurnByTurnNotification *self,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean trp_service_turn_by_turn_notification_close_finish (TrpServiceTurnByTurnNotification *self,
GAsyncResult *result,
GError **error);
G_END_DECLS
#endif /* __TRAPRAIN_SERVICE_TURN_BY_TURN_NOTIFICATION_H__ */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment