2 * Copyright (c) 2011 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
30 #include "shortcut_private.h"
31 #include "shortcut_db.h"
32 #include "shortcut_manager.h"
34 #define SHORTCUT_PKGNAME_LEN 512
35 #define SHORTCUT_IS_WIDGET_SIZE(size) (!!((size) & WIDGET_SIZE_DEFAULT))
37 #define PROVIDER_BUS_NAME "org.tizen.data_provider_service"
38 #define PROVIDER_OBJECT_PATH "/org/tizen/data_provider_service"
39 #define PROVIDER_SHORTCUT_INTERFACE_NAME "org.tizen.data_provider_shortcut_service"
41 #define DBUS_SERVICE_DBUS "org.freedesktop.DBus"
42 #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
43 #define DBUS_INTERFACE_DBUS "org.freedesktop.DBus"
45 static GDBusConnection *_gdbus_conn = NULL;
46 static int monitor_id = 0;
47 static int provider_monitor_id = 0;
49 static const GDBusErrorEntry dbus_error_entries[] = {
50 {SHORTCUT_ERROR_INVALID_PARAMETER, "org.freedesktop.Shortcut.Error.INVALID_PARAMETER"},
51 {SHORTCUT_ERROR_OUT_OF_MEMORY, "org.freedesktop.Shortcut.Error.OUT_OF_MEMORY"},
52 {SHORTCUT_ERROR_IO_ERROR, "org.freedesktop.Shortcut.Error.IO_ERROR"},
53 {SHORTCUT_ERROR_PERMISSION_DENIED, "org.freedesktop.Shortcut.Error.PERMISSION_DENIED"},
54 {SHORTCUT_ERROR_NOT_SUPPORTED, "org.freedesktop.Shortcut.Error.NOT_SUPPORTED"},
55 {SHORTCUT_ERROR_RESOURCE_BUSY, "org.freedesktop.Shortcut.Error.RESOURCE_BUSY"},
56 {SHORTCUT_ERROR_NO_SPACE, "org.freedesktop.Shortcut.Error.NO_SPACE"},
57 {SHORTCUT_ERROR_EXIST, "org.freedesktop.Shortcut.Error.EXIST"},
58 {SHORTCUT_ERROR_FAULT, "org.freedesktop.Shortcut.Error.FAULT"},
59 {SHORTCUT_ERROR_COMM, "org.freedesktop.Shortcut.Error.COMM"},
62 struct result_cb_item {
63 result_internal_cb_t result_internal_cb;
64 result_cb_t result_cb;
68 typedef struct _shortcut_cb_info {
69 int (*request_cb)(const char *appid, const char *name, int type, const char *content, const char *icon, pid_t pid, double period, int allow_duplicate, void *data);
73 static shortcut_cb_info _callback_info;
74 static int _dbus_init();
75 static char *_shortcut_get_pkgname_by_pid(void);
77 EXPORT_API GQuark shortcut_error_quark(void)
79 static volatile gsize quark_volatile = 0;
80 g_dbus_error_register_error_domain("shortcut-error-quark",
83 G_N_ELEMENTS(dbus_error_entries));
84 return (GQuark) quark_volatile;
87 static void _add_shortcut_notify(GVariant *parameters)
97 g_variant_get(parameters, "(i&s&si&s&si)", &sender_pid, &appid, &name, &type, &content, &icon, &allow_duplicate);
98 DbgPrint("_add_shortcut_notify sender_pid: %d ", sender_pid);
99 _callback_info.request_cb(appid, name, type, content, icon, sender_pid, -1.0f, allow_duplicate, _callback_info.data);
102 static void _add_shortcut_widget_notify(GVariant *parameters)
113 g_variant_get(parameters, "(i&s&si&s&sdi)", &sender_pid, &appid, &name, &type, &content, &icon, &period, &allow_duplicate);
114 _callback_info.request_cb(appid, name, type, content, icon, sender_pid, period, allow_duplicate, _callback_info.data);
117 static void _handle_shortcut_notify(GDBusConnection *connection,
118 const gchar *sender_name,
119 const gchar *object_path,
120 const gchar *interface_name,
121 const gchar *signal_name,
122 GVariant *parameters,
125 DbgPrint("signal_name: %s", signal_name);
126 if (g_strcmp0(signal_name, "add_shortcut_notify") == 0)
127 _add_shortcut_notify(parameters);
128 else if (g_strcmp0(signal_name, "add_shortcut_widget_notify") == 0)
129 _add_shortcut_widget_notify(parameters);
132 static int _dbus_init(void)
134 GError *error = NULL;
136 if (_gdbus_conn == NULL) {
137 _gdbus_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
139 if (_gdbus_conn == NULL) {
141 ErrPrint("Failed to get dbus [%s]", error->message);
144 return SHORTCUT_ERROR_IO_ERROR;
146 shortcut_error_quark();
149 return SHORTCUT_ERROR_NONE;
152 static int _dbus_signal_init()
154 int ret = SHORTCUT_ERROR_NONE;
157 if (monitor_id == 0) {
158 DbgPrint("get dbus connection success");
159 id = g_dbus_connection_signal_subscribe(
162 PROVIDER_SHORTCUT_INTERFACE_NAME, /* interface */
164 PROVIDER_OBJECT_PATH, /* path */
166 G_DBUS_SIGNAL_FLAGS_NONE,
167 _handle_shortcut_notify,
171 DbgPrint("subscribe id : %d", id);
173 ret = SHORTCUT_ERROR_IO_ERROR;
174 ErrPrint("Failed to _register_noti_dbus_interface");
183 static char *_shortcut_get_pkgname_by_pid(void)
185 char pkgname[SHORTCUT_PKGNAME_LEN + 1] = { 0, };
186 char buf[SHORTCUT_PKGNAME_LEN + 1] = { 0, };
193 ret = aul_app_get_pkgname_bypid(pid, pkgname, sizeof(pkgname));
195 snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid);
197 fd = open(buf, O_RDONLY);
201 ret = read(fd, pkgname, sizeof(pkgname) - 1);
210 * "ret" is not able to be larger than "sizeof(pkgname) - 1",
211 * if the system is not going wrong.
214 if (strlen(pkgname) <= 0)
218 dup_pkgname = strdup(pkgname);
220 ErrPrint("Heap: %d\n", errno);
226 * implement user request
228 static int _send_sync_shortcut(GVariant *body, GDBusMessage **reply, char *cmd)
232 int ret = SHORTCUT_ERROR_NONE;
234 msg = g_dbus_message_new_method_call(
236 PROVIDER_OBJECT_PATH,
237 PROVIDER_SHORTCUT_INTERFACE_NAME,
240 ErrPrint("Can't allocate new method call");
242 g_variant_unref(body);
243 return SHORTCUT_ERROR_OUT_OF_MEMORY;
247 g_dbus_message_set_body(msg, body);
249 *reply = g_dbus_connection_send_message_with_reply_sync(
252 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
261 ret = SHORTCUT_ERROR_COMM;
263 ErrPrint("No reply. cmd = %s, error = %s", cmd, err->message);
264 if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
265 ret = SHORTCUT_ERROR_PERMISSION_DENIED;
271 if (g_dbus_message_to_gerror(*reply, &err)) {
272 if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
273 ret = SHORTCUT_ERROR_PERMISSION_DENIED;
277 ErrPrint("_send_sync_shortcut error %s err code: %d", err->message, ret);
281 DbgPrint("_send_sync_shortcut done !!");
282 return SHORTCUT_ERROR_NONE;
285 static int _send_service_register()
287 GDBusMessage *reply = NULL;
290 result = _send_sync_shortcut(NULL, &reply, "shortcut_service_register");
291 ErrPrint("_send_service_register done");
295 static void _send_message_with_reply_sync_cb(GDBusConnection *connection,
299 int result = SHORTCUT_ERROR_NONE;
301 GDBusMessage *reply = NULL;
302 struct result_cb_item *cb_item = (struct result_cb_item *)user_data;
304 if (cb_item == NULL) {
305 ErrPrint("Failed to get a callback item");
309 reply = g_dbus_connection_send_message_with_reply_finish(
316 ErrPrint("No reply. error = %s", err->message);
319 result = SHORTCUT_ERROR_COMM;
321 } else if (g_dbus_message_to_gerror(reply, &err)) {
322 if (err->code == G_DBUS_ERROR_ACCESS_DENIED)
323 result = SHORTCUT_ERROR_PERMISSION_DENIED;
327 ErrPrint("_send_message_with_reply_sync_cb error %s err code: %d", err->message, result);
331 if (cb_item->result_internal_cb)
332 result = cb_item->result_internal_cb(result, getpid(), cb_item->data);
333 else if (cb_item->result_cb)
334 result = cb_item->result_cb(result, cb_item->data);
337 g_object_unref(reply);
342 static int _send_async_noti(GVariant *body, struct result_cb_item *cb_item, char *cmd)
345 msg = g_dbus_message_new_method_call(
347 PROVIDER_OBJECT_PATH,
348 PROVIDER_SHORTCUT_INTERFACE_NAME,
351 ErrPrint("Can't allocate new method call");
352 return SHORTCUT_ERROR_OUT_OF_MEMORY;
356 g_dbus_message_set_body(msg, body);
358 g_dbus_connection_send_message_with_reply(
361 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
365 (GAsyncReadyCallback)_send_message_with_reply_sync_cb,
370 DbgPrint("_send_async_noti done !!");
371 return SHORTCUT_ERROR_NONE;
374 static void _on_name_appeared(GDBusConnection *connection,
376 const gchar *name_owner,
379 DbgPrint("name appeared : %s", name);
380 _send_service_register();
383 static void _on_name_vanished(GDBusConnection *connection,
387 DbgPrint("name vanished : %s", name);
390 EAPI int shortcut_set_request_cb(shortcut_request_cb request_cb, void *data)
392 int ret = _dbus_init();
394 if (ret != SHORTCUT_ERROR_NONE) {
395 ErrPrint("Can't init dbus %d", ret);
399 ret = _dbus_signal_init();
400 if (ret != SHORTCUT_ERROR_NONE) {
401 ErrPrint("Can't init dbus_signal %d", ret);
405 ret = _send_service_register();
406 if (ret != SHORTCUT_ERROR_NONE) {
407 ErrPrint("Can't init ipc_monitor_register %d", ret);
411 if (request_cb == NULL)
412 return SHORTCUT_ERROR_INVALID_PARAMETER;
414 if (provider_monitor_id == 0) {
415 provider_monitor_id = g_bus_watch_name_on_connection(
418 G_BUS_NAME_WATCHER_FLAGS_NONE,
424 if (provider_monitor_id == 0) {
425 ErrPrint("watch on name fail");
426 return SHORTCUT_ERROR_IO_ERROR;
430 _callback_info.request_cb = request_cb;
431 _callback_info.data = data;
433 return SHORTCUT_ERROR_NONE;
436 EAPI int shortcut_add_to_home(const char *name, shortcut_type type, const char *uri,
437 const char *icon, int allow_duplicate, result_cb_t result_cb, void *data)
439 struct result_cb_item *item;
444 if (ADD_TO_HOME_IS_DYNAMICBOX(type)) {
445 ErrPrint("Invalid type used for adding a shortcut\n");
446 return SHORTCUT_ERROR_INVALID_PARAMETER;
450 if (ret != SHORTCUT_ERROR_NONE) {
451 ErrPrint("Can't init dbus %d", ret);
455 appid = _shortcut_get_pkgname_by_pid();
456 item = malloc(sizeof(struct result_cb_item));
461 ErrPrint("Heap: %d\n", errno);
462 return SHORTCUT_ERROR_OUT_OF_MEMORY;
465 item->result_cb = result_cb;
466 item->result_internal_cb = NULL;
478 body = g_variant_new("(ississi)", getpid(), appid, name, type, uri, icon, allow_duplicate);
479 ret = _send_async_noti(body, item, "add_shortcut");
480 if (ret != SHORTCUT_ERROR_NONE) {
488 g_variant_unref(body);
493 EAPI int shortcut_add_to_home_widget(const char *name, shortcut_widget_size_e size, const char *widget_id,
494 const char *icon, double period, int allow_duplicate, result_cb_t result_cb, void *data)
496 struct result_cb_item *item;
502 ErrPrint("AppID is null\n");
503 return SHORTCUT_ERROR_INVALID_PARAMETER;
506 if (!SHORTCUT_IS_WIDGET_SIZE(size)) {
507 ErrPrint("Invalid type used for adding a widget\n");
508 return SHORTCUT_ERROR_INVALID_PARAMETER;
512 if (ret != SHORTCUT_ERROR_NONE) {
513 ErrPrint("Can't init dbus %d", ret);
517 appid = _shortcut_get_pkgname_by_pid();
518 item = malloc(sizeof(struct result_cb_item));
523 ErrPrint("Heap: %d\n", errno);
524 return SHORTCUT_ERROR_OUT_OF_MEMORY;
527 item->result_cb = result_cb;
528 item->result_internal_cb = NULL;
531 body = g_variant_new("(ississdi)", getpid(), widget_id, name, size, NULL, icon, period, allow_duplicate);
532 ret = _send_async_noti(body, item, "add_shortcut_widget");
534 if (ret != SHORTCUT_ERROR_NONE) {
542 g_variant_unref(body);
547 EAPI int add_to_home_shortcut(const char *appid, const char *name, int type, const char *content,
548 const char *icon, int allow_duplicate, result_internal_cb_t result_cb, void *data)
551 return SHORTCUT_ERROR_NONE;
554 EAPI int add_to_home_dynamicbox(const char *appid, const char *name, int type, const char *content, const char *icon, double period, int allow_duplicate, result_internal_cb_t result_cb, void *data)
557 return SHORTCUT_ERROR_NONE;
561 EAPI int shortcut_get_list(const char *package_name, shortcut_list_cb list_cb, void *data)
563 GDBusMessage *reply = NULL;
567 GVariant *reply_body;
571 shortcut_info_s shortcut;
574 return SHORTCUT_ERROR_INVALID_PARAMETER;
576 result = _dbus_init();
577 if (result != SHORTCUT_ERROR_NONE) {
578 ErrPrint("Can't init dbus %d", result);
582 b = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
584 g_variant_builder_add(b, "{sv}", "package_name", g_variant_new_string(package_name));
585 body = g_variant_builder_end(b);
586 result = _send_sync_shortcut(g_variant_new("(v)", body), &reply, "get_list");
588 if (result == SHORTCUT_ERROR_NONE) {
589 reply_body = g_dbus_message_get_body(reply);
590 g_variant_get(reply_body, "(ia(v))", &count, &iter);
591 DbgPrint("shortcut count : %d", count);
592 while (g_variant_iter_loop(iter, "(v)", &iter_body)) {
593 g_variant_get(iter_body, "(&s&s&s&s&s)",
594 &shortcut.package_name, &shortcut.icon, &shortcut.name, &shortcut.extra_key, &shortcut.extra_data);
595 DbgPrint("call calback : %s", shortcut.package_name);
596 list_cb(shortcut.package_name, shortcut.icon, shortcut.name, shortcut.extra_key, shortcut.extra_data, data);
598 g_variant_iter_free(iter);
602 g_object_unref(reply);