replace vconf to dbus to listen homescreen launch signal
[platform/core/appfw/ui-gadget-1.git] / client / ug-client.c
1 /*
2  *  UI Gadget
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Jayoun Lee <airjany@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <appcore-efl.h>
24 #include <ui-gadget.h>
25
26 #include <dlog.h>
27 #include <aul.h>
28 #include <app.h>
29 #include <vconf.h>
30 #include <dbus/dbus.h>
31 #include <dbus/dbus-glib-lowlevel.h>
32
33 #include "ug-client.h"
34
35 #include <tzplatform_config.h>
36
37 #ifdef LOG_TAG
38 #undef LOG_TAG
39 #endif
40
41 #define PATH_UG_LAUNCHER tzplatform_mkpath(TZ_SYS_BIN,"ug-launcher")
42
43 #define LOG_TAG "UI_GADGET_CLIENT"
44
45 static int home_screen_pid = 0;
46 static DBusConnection *bus;
47 static int ug_dbus_signal_handler_initialized = 0;
48 static bool is_app_pause = false;
49
50 static void prt_usage(const char *cmd)
51 {
52         fprintf(stderr, "Usage: %s [-f] [-F] -n <UG NAME> [-d <Arguments>]\n",
53                 cmd);
54         fprintf(stderr, "   Options:\n");
55         fprintf(stderr, "            -d argument\n");
56         fprintf(stderr, "            -F Fullview mode (Default)\n");
57         fprintf(stderr, "            -f Frameview mode\n");
58         fprintf(stderr, "   Example:\n");
59         fprintf(stderr,
60                 "            %s -F -n helloUG-efl -d \"name,John Doe\" -d \"age,30\"\n",
61                 cmd);
62
63 }
64
65 static void win_del(void *data, Evas_Object *obj, void *event)
66 {
67         elm_exit();
68 }
69
70 static void main_quit_cb(void *data, Evas_Object *obj,
71                          const char *emission, const char *source)
72 {
73         elm_exit();
74 }
75
76 static int ug_send_rotate_event(int angle)
77 {
78         int ret = -1;
79         LOGD("ug_send_rotate_event angle : %d", angle);
80         switch(angle) {
81                 case 0 :
82                         ret = ug_send_event(UG_EVENT_ROTATE_PORTRAIT);
83                         break;
84                 case 90 :
85                         ret = ug_send_event(UG_EVENT_ROTATE_LANDSCAPE_UPSIDEDOWN);
86                         break;
87                 case 180 :
88                         ret = ug_send_event(UG_EVENT_ROTATE_PORTRAIT_UPSIDEDOWN);
89                         break;
90                 case 270 :
91                         ret = ug_send_event(UG_EVENT_ROTATE_LANDSCAPE);
92                         break;
93                 default :
94                         LOGW("wrong angle(%d) for send rotate event",angle);
95                         break;
96         }
97
98         return ret;
99 }
100
101 static void rotate(void *data, Evas_Object *obj, void *event)
102 {
103         int changed_angle = 0;
104         struct appdata *ad = data;
105
106         changed_angle = elm_win_rotation_get((const Evas_Object *)obj);
107         if(changed_angle == -1) {
108                 LOGE("elm_win_rotation_get error");
109                 return;
110         }
111
112         LOGD("rotate call back : changed angle(%d) / current angle(%d)",
113                 changed_angle, ad->rotate);
114
115         if(ad->rotate != changed_angle) {
116                 ug_send_rotate_event(changed_angle);
117         }
118
119         ad->rotate = changed_angle;
120
121         return;
122 }
123
124 void _ug_client_layout_cb(ui_gadget_h ug, enum ug_mode mode, void *priv)
125 {
126         struct appdata *ad;
127         Evas_Object *base;
128
129         if (!ug || !priv)
130                 return;
131
132         ad = priv;
133
134         base = ug_get_layout(ug);
135         if (!base) {
136                 LOGE("base layout is null");
137                 return;
138         }
139
140         switch (mode) {
141         case UG_MODE_FULLVIEW:
142                 evas_object_size_hint_weight_set(base, EVAS_HINT_EXPAND,
143                                                  EVAS_HINT_EXPAND);
144                 ug_disable_effect(ug);
145                 elm_object_content_set(ad->ly_main, base);
146                 evas_object_show(base);
147                 break;
148         case UG_MODE_FRAMEVIEW:
149                 elm_object_part_content_set(ad->ly_main, "content", base);
150                 break;
151         default:
152                 break;
153         }
154 }
155
156 void _ug_client_result_cb(ui_gadget_h ug, service_h reply, void *priv)
157 {
158         struct appdata *ad = NULL;
159         int ret;
160         char* value = NULL;
161         int result;
162
163         if (!ug || !priv)
164                 return;
165
166         ret = service_get_extra_data (reply, UG_SERVICE_DATA_RESULT, &value);
167         if((ret == SERVICE_ERROR_NONE) && (value)) {
168                 result = atoi(value);
169                 LOGD("reply result is %d", result);
170         } else {
171                 LOGW("get reply result error(%d) . result will be SERVICE_RESULT_SUCCEEDED", ret);
172                 result = SERVICE_RESULT_SUCCEEDED;
173         }
174
175         ad = priv;
176         if (!ad) {
177                 LOGE("appdata is null");
178                 return;
179         }
180
181         ret = service_reply_to_launch_request(reply, ad->request, (service_result_e)result);
182         if (ret != SERVICE_ERROR_NONE)
183                 LOGE("service_reply_to_launch_request failed, %d", ret);
184 }
185
186 void _ug_client_destroy_cb(ui_gadget_h ug, void *priv)
187 {
188         struct appdata *ad = NULL;
189
190         if (!ug)
191                 return;
192
193         ad = priv;
194         if (!ad) {
195                 LOGE("appdata is null. win lower is fail");
196         } else {
197                 LOGD("window lower");
198                 elm_win_lower(ad->win);
199         }
200
201         elm_exit();
202 }
203
204 void _ug_client_end_cb(ui_gadget_h ug, void *priv)
205 {
206         if (!ug)
207                 return;
208
209         LOGD("_ug_client_end_cb invoked");
210
211         elm_exit();
212 }
213
214 static void profile_changed_cb(void *data, Evas_Object * obj, void *event)
215 {
216         const char *profile = elm_config_profile_get();
217
218         LOGE("!!! profile_changed_cb(%s) !!!", profile);
219
220         if (strcmp(profile, "desktop") == 0)
221                 elm_win_indicator_mode_set(obj, ELM_WIN_INDICATOR_HIDE);
222 }
223
224 static Evas_Object *create_win(const char *name)
225 {
226         Ecore_Evas *ee;
227         Evas_Object *eo;
228         int w, h;
229
230         eo = elm_win_add(NULL, name, ELM_WIN_BASIC);
231         if (eo) {
232                 elm_win_title_set(eo, name);
233                 elm_win_conformant_set(eo, EINA_TRUE);
234                 evas_object_smart_callback_add(eo, "delete,request",
235                                                win_del, NULL);
236                 /* disable destktop mode
237                 evas_object_smart_callback_add(eo, "profile,changed", profile_changed_cb, NULL); */
238                 ee = ecore_evas_ecore_evas_get(evas_object_evas_get(eo));
239                 evas_output_size_get(ee, &w, &h);
240                 evas_object_resize(eo, w, h);
241
242                 elm_win_indicator_mode_set(eo,ELM_WIN_INDICATOR_SHOW);
243         }
244
245         return eo;
246 }
247
248 static Evas_Object *_ug_client_load_edj(Evas_Object *parent, const char *file,
249                              const char *group)
250 {
251         Evas_Object *eo;
252         int r;
253         eo = elm_layout_add(parent);
254         if (eo) {
255                 r = elm_layout_file_set(eo, file, group);
256                 if (!r) {
257                         evas_object_del(eo);
258                         return NULL;
259                 }
260                 evas_object_size_hint_weight_set(eo,
261                                                  EVAS_HINT_EXPAND,
262                                                  EVAS_HINT_EXPAND);
263         }
264         return eo;
265 }
266
267 static int low_memory(void *data)
268 {
269         return ug_send_event(UG_EVENT_LOW_MEMORY);
270 }
271
272 static int low_battery(void *data)
273 {
274         return ug_send_event(UG_EVENT_LOW_BATTERY);
275 }
276
277 static int lang_changed(void *data)
278 {
279         char* lang = NULL;
280
281         lang = vconf_get_str(VCONFKEY_LANGSET);
282         if(lang) {
283                 LOGD("lang : %s", lang);
284                 elm_language_set((const char*)lang);
285                 free(lang);
286         } else {
287                 LOGW("language get error");
288         }
289
290         return ug_send_event(UG_EVENT_LANG_CHANGE);
291 }
292
293 static int region_changed(void *data)
294 {
295         return ug_send_event(UG_EVENT_REGION_CHANGE);
296 }
297
298 static int app_create(void *data)
299 {
300         struct appdata *ad = data;
301         Evas_Object *win;
302         Evas_Object *ly;
303         Evas_Object *conform;
304         Evas_Object *bg;
305
306         /* create window */
307         win = create_win(PACKAGE);
308         if (win == NULL)
309                 return -1;
310         ad->win = win;
311
312         UG_INIT_EFL(ad->win, UG_OPT_INDICATOR_ENABLE);
313
314         bg = elm_bg_add(win);
315         evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
316         elm_win_resize_object_add(win, bg);
317         evas_object_show(bg);
318
319         conform = elm_conformant_add(win);
320         evas_object_size_hint_weight_set(conform, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
321         ad->conform = conform;
322
323         /* load edje */
324         ly = _ug_client_load_edj(conform, EDJ_FILE, GRP_MAIN);
325         if (ly == NULL)
326                 return -1;
327         elm_win_resize_object_add(win, conform);
328
329         evas_object_show(conform);
330         elm_object_content_set(conform, ly);
331         edje_object_signal_callback_add(elm_layout_edje_get(ly),
332                                         "EXIT", "*", main_quit_cb, NULL);
333         ad->ly_main = ly;
334         lang_changed(ad);
335
336         /* rotate notice */
337         int angle = -1;
338         angle = elm_win_rotation_get((const Evas_Object *)win);
339         LOGE("rotate : %d", angle);
340         if(angle != -1) {
341                 ug_send_rotate_event(angle);
342                 ad->rotate = angle;
343         } else {
344                 LOGE("elm win rotation get error");
345         }
346     /*
347         if(elm_win_wm_rotation_supported_get(win)) {
348                 int rots[4] = { 0, 90, 180, 270 };
349                 elm_win_wm_rotation_available_rotations_set(win, (const int*)&rots, 4);
350         } else {
351                 LOGW("wm rotation supported get error");
352         }
353     */
354         evas_object_smart_callback_add(win, "wm,rotation,changed", rotate, data);
355
356         appcore_set_event_callback(APPCORE_EVENT_LOW_MEMORY, low_memory, ad);
357         appcore_set_event_callback(APPCORE_EVENT_LOW_BATTERY, low_battery, ad);
358         appcore_set_event_callback(APPCORE_EVENT_LANG_CHANGE, lang_changed, ad);
359         appcore_set_event_callback(APPCORE_EVENT_REGION_CHANGE, region_changed, ad);
360
361         return 0;
362 }
363
364 static void _ug_client_home_screen_top_cb(void *data)
365 {
366         struct appdata *ad = data;
367
368         if((!ad->is_transient) && (home_screen_pid)) {
369                 LOGW("home key pressed. window is not transient. ug client will be terminated");
370                 elm_exit();
371         }
372         return;
373 }
374
375 static DBusHandlerResult
376 _ug_client_dbus_signal_filter(DBusConnection *conn, DBusMessage *message,
377                 void *user_data)
378 {
379         const char *sender;
380         const char *interface;
381         int home_pid_by_dbus;
382
383         DBusError error;
384
385         dbus_error_init(&error);
386
387         sender = dbus_message_get_sender(message);
388         if (sender == NULL)
389                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
390
391         if (dbus_bus_get_unix_user(conn, sender, &error) != 0) {
392                 LOGW("reject by security issue - no allowed sender\n");
393                 dbus_error_free(&error);
394                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
395         }
396
397         interface = dbus_message_get_interface(message);
398         if (interface == NULL) {
399                 LOGW("reject by security issue - no interface\n");
400                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
401         }
402
403         if (dbus_message_is_signal(
404                                 message, interface, "home_launch")) {
405
406                 LOGD("interface signal is home_launch");
407
408                 if (dbus_message_get_args(message, &error, DBUS_TYPE_UINT32,
409                                         &home_pid_by_dbus, DBUS_TYPE_INVALID) == FALSE) {
410                         LOGW("Failed to get data: %s", error.message);
411                         dbus_error_free(&error);
412                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
413                 }
414
415                 LOGD("pid : %d", home_pid_by_dbus);
416
417                 home_screen_pid = home_pid_by_dbus;
418
419                 if(is_app_pause) {
420                         LOGD("home_launch signal under app_pause.\
421                                         if home screen is top, app will be terminated");
422                         _ug_client_home_screen_top_cb(user_data);
423                 }
424         }
425
426         return DBUS_HANDLER_RESULT_HANDLED;
427 }
428
429 static int _ug_client_dbus_listen_signal(void *data)
430 {
431         DBusError error;
432         char rule[128];
433
434         if (ug_dbus_signal_handler_initialized)
435                 return 0;
436
437         dbus_threads_init_default();
438
439         dbus_error_init(&error);
440         bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
441         if (!bus) {
442                 LOGW("Failed to connect to the D-BUS daemon: %s", error.message);
443                 dbus_error_free(&error);
444                 return -1;
445         }
446         dbus_connection_setup_with_g_main(bus, NULL);
447
448         snprintf(rule, 128,
449                         "path='%s',type='signal',interface='%s'", "/aul/dbus_handler",
450                         "org.tizen.aul.signal");
451         /* listening to messages */
452         dbus_bus_add_match(bus, rule, &error);
453         if (dbus_error_is_set(&error)) {
454                 LOGW("Fail to rule set: %s", error.message);
455                 dbus_error_free(&error);
456                 return -1;
457         }
458
459         if (dbus_connection_add_filter(bus,
460                                 _ug_client_dbus_signal_filter, data, NULL) == FALSE) {
461                 LOGW("dbus conntaction add fileter fail");
462                 return -1;
463         }
464
465         LOGD("bus : %p / filter func pointer : %p", bus , _ug_client_dbus_signal_filter);
466
467         ug_dbus_signal_handler_initialized = 1;
468
469         return 0;
470 }
471
472 static void _ug_client_dbus_signal_handler_fini(void *data)
473 {
474         DBusError error;
475         char rule[128];
476
477         if (!ug_dbus_signal_handler_initialized)
478                 return;
479
480         if(!dbus_connection_get_is_connected(bus)) {
481                 LOGD("dbus connection(%p) is not connected", bus);
482                 goto func_out;
483         }
484
485         dbus_connection_remove_filter(bus, _ug_client_dbus_signal_filter, data);
486
487         dbus_error_init(&error);
488
489         snprintf(rule, 128,
490                         "path='%s',type='signal',interface='%s'", "/aul/dbus_handler",
491                         "org.tizen.aul.signal");
492         dbus_bus_remove_match(bus, rule, &error);
493         if (dbus_error_is_set(&error)) {
494                 LOGE("Fail to rule unset: %s", error.message);
495                 dbus_error_free(&error);
496                 goto func_out;
497         }
498
499         dbus_connection_close(bus);
500
501         LOGD("ug dbus signal finialized");
502
503 func_out :
504         ug_dbus_signal_handler_initialized = 0;
505         bus = NULL;
506
507         return;
508 }
509
510 static int app_terminate(void *data)
511 {
512         struct appdata *ad = data;
513
514         LOGD("app_terminate called");
515
516         _ug_client_dbus_signal_handler_fini(data);
517
518         evas_object_smart_callback_del(ad->win, "wm,rotation,changed", rotate);
519
520         ug_destroy_all();
521
522         if (ad->ly_main) {
523                 evas_object_del(ad->ly_main);
524                 ad->ly_main = NULL;
525         }
526
527         if (ad->win) {
528                 evas_object_del(ad->win);
529                 ad->win = NULL;
530         }
531
532         service_destroy(ad->request);
533
534         if (ad->name) {
535                 free(ad->name);
536         }
537
538         LOGD("app_terminate end");
539
540         return 0;
541 }
542
543 static int app_pause(void *data)
544 {
545         struct appdata *ad = data;
546
547         LOGD("app_pause called");
548
549         ug_pause();
550
551 #if ENABLE_TRANSIENT_SUB_MODE
552         if (!ad->is_transient) {
553                 LOGD("app_pause received. close ug service");
554                 elm_exit();
555         }
556 #endif
557         is_app_pause = true;
558
559         return 0;
560 }
561
562 static int app_resume(void *data)
563 {
564         ug_resume();
565         is_app_pause = true;
566         return 0;
567 }
568
569 static int svc_cb(void *data)
570 {
571         LOGD("svc_cb called");
572         return 0;
573 }
574
575 static int app_reset(bundle *b, void *data)
576 {
577         struct appdata *ad = data;
578         struct ug_cbs cbs = { 0, };
579         service_h service;
580         enum ug_mode mode = UG_MODE_FULLVIEW;
581         int ret;
582         Ecore_X_Window id2 = elm_win_xwindow_get(ad->win);
583
584         ret = appsvc_request_transient_app(b, id2, svc_cb, "svc test");
585
586         if (ret) {
587                 LOGD("fail to request transient app: return value(%d)", ret);
588                 if(_ug_client_dbus_listen_signal(data) < 0) {
589                         LOGW("home screen dbus register error");
590                 }
591         } else {
592                 /* check home screen raise */
593                 ad->is_transient = 1;
594         }
595
596         if (ad->win) {
597                 elm_win_activate(ad->win);
598                 evas_object_show(ad->win);
599         }
600
601         if (ad->data)   /* ug-launcher */
602                 service_create_event(ad->data, &service);
603         else
604                 service_create_event(b, &service);
605
606         if(service) {
607                 service_clone(&ad->request, service);
608                 service_destroy(service);
609         }
610
611         cbs.layout_cb = _ug_client_layout_cb;
612         cbs.destroy_cb = _ug_client_destroy_cb;
613         cbs.result_cb = _ug_client_result_cb;
614         cbs.end_cb = _ug_client_end_cb;
615         cbs.priv = ad;
616
617         mode = ad->is_frameview ? UG_MODE_FRAMEVIEW : UG_MODE_FULLVIEW;
618
619         ad->ug = ug_create(NULL, ad->name, mode, ad->request, &cbs);
620         if (ad->ug == NULL) {
621                 LOGE("ug_create fail: %s", ad->name);
622                 elm_exit();
623         }
624
625         return 0;
626 }
627
628 static int update_argument(const char *optarg, struct appdata *ad)
629 {
630         const char *key;
631         const char *val;
632         key = strtok((char *)optarg, ",");
633         if (!key)
634                 return -1;
635
636         val = optarg + strlen(key) + 1;
637
638         if (!ad->data)
639                 ad->data = bundle_create();
640         if (!ad->data)
641                 return -1;
642         bundle_add(ad->data, key, val);
643         return 0;
644 }
645
646 int main(int argc, char *argv[])
647 {
648         int opt;
649         struct appdata ad;
650         struct appcore_ops ops = {
651                 .create = app_create,
652                 .terminate = app_terminate,
653                 .pause = app_pause,
654                 .resume = app_resume,
655                 .reset = app_reset,
656         };
657         int cmdlen = 0;
658
659         memset(&ad, 0x0, sizeof(struct appdata));
660         ops.data = &ad;
661
662         cmdlen = strlen(argv[0]);
663         if (strncmp(argv[0], "ug-launcher", cmdlen) == 0
664                 || strncmp(argv[0], PATH_UG_LAUNCHER , cmdlen) == 0) {
665                 while ((opt = getopt(argc, argv, "n:d:")) != -1) {
666                         switch (opt) {
667                         case 'n':
668                                 if (optarg)
669                                         ad.name = strdup(optarg);
670                                 break;
671                         case 'f':
672                                 ad.is_frameview = 1;
673                                 break;
674                         case 'F':
675                                 ad.is_frameview = 0;
676                                 break;
677                         case 'd':
678                                 if (update_argument(optarg, &ad)) {
679                                         if (ad.data)
680                                                 bundle_free(ad.data);
681                                         prt_usage(argv[0]);
682                                         return -1;
683                                 }
684                                 break;
685                         default:
686                                 prt_usage(argv[0]);
687                                 return -1;
688                         }
689                 }
690
691                 if (!ad.name) {
692                         prt_usage(argv[0]);
693                         return -1;
694                 }
695                 argc = 1; // remove appsvc bundle
696         } else {        /* ug-client */
697                 char *name = NULL;
698                 name = strrchr(argv[0], '/');
699                 if (name == NULL)
700                         return -1;
701                 /* .../bin/{name} */
702                 ad.name = strdup(&name[1]);
703         }
704         return appcore_efl_main(PACKAGE, &argc, &argv, &ops);
705 }