d9fef91fd7289727c8e915ffe25c091761002bb4
[apps/agl-service-homescreen.git] / src / homescreen.cpp
1 /*
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #ifndef _GNU_SOURCE
18 #define _GNU_SOURCE
19 #endif
20 #include <unistd.h>
21 #include <memory>
22 #include <algorithm>
23 #include <unordered_map>
24 #include <list>
25 #include <thread>
26 #include "hs-helper.h"
27 #include "hs-clientmanager.h"
28 #include "hs-appinfo.h"
29 #include "hs-config.h"
30 #include "hs-apprecover.h"
31 #include "hs-vuiadapter.h"
32
33
34 const char _error[] = "error";
35 const char _application_id[] = "application_id";
36 const char _display_message[] = "display_message";
37 const char _reply_message[] = "reply_message";
38 const char _keyData[] = "data";
39 const char _keyId[] = "id";
40
41 struct hs_handshake {
42     hs_handshake(int times, int sleep) : m_times(times), m_sleep(sleep) {}
43     int start(afb_api_t api);
44     void handshake_loop(afb_api_t api, int times, int sleeps);
45
46     enum HandshakeStatus {
47         Handshake_Idle = 0,
48         Handshake_Subscribing,
49         Handshake_Subscribe_Fail,
50         Handshake_WaitEvent,
51         Handshake_Over
52     };
53     static int hs_sts;
54
55 private:
56     const std::string sub_event = "windowmanager/handshake";
57     const int m_times;
58     const int m_sleep;
59 };
60
61 int hs_handshake::hs_sts = hs_handshake::Handshake_Idle;
62
63 /**
64  * handshake callback function
65  *
66  * #### Parameters
67  * - obj : reply json object
68  * - error : api_call error
69  * - info : api_call information
70  *
71  * #### Return
72  * None
73  *
74  */
75 void handshake_subscribe_callback(struct json_object *obj, const char *error, const char *info)
76 {
77     AFB_NOTICE("subscribe handshake reply: obj=%s, error=%s, info=%s", json_object_to_json_string(obj), error, info);
78     if(hs_handshake::hs_sts == hs_handshake::Handshake_Over) {
79         return;
80     }
81     if(error == nullptr) {
82         hs_handshake::hs_sts =  hs_handshake::Handshake_WaitEvent;
83     }
84     else {
85         hs_handshake::hs_sts =  hs_handshake::Handshake_Subscribe_Fail;
86     }
87 }
88
89 /**
90  * handshake event function
91  *
92  * #### Parameters
93  * - api : the api
94  * - event : received event name
95  * - object : received json object
96  *
97  * #### Return
98  * 0 : event can transfer to others
99  * 1 : event not transfer to others
100  */
101 int on_handshake_event(afb_api_t api, const char *event, struct json_object *object)
102 {
103     AFB_NOTICE("received handshake event from windowmanager.");
104     hs_handshake::hs_sts =  hs_handshake::Handshake_Over;
105     return 1;
106 }
107
108 /**
109  * start handshake function
110  *
111  * #### Parameters
112  * - api : the api
113  *
114  * #### Return
115  * 0 : handshake success
116  * other : handshake fail
117  * 
118  */
119 int hs_handshake::start(afb_api_t api)
120 {
121     AFB_NOTICE("start handshake with windowmanager.");
122     setEventHook(sub_event.c_str(), on_handshake_event);
123
124     std::thread th(&hs_handshake::handshake_loop, this, api, m_times, m_sleep);
125     th.detach();
126     return 0;
127 }
128
129 /**
130  * handshake loop
131  *
132  * #### Parameters
133  * - api : the api
134  *
135  * #### Return
136  * None
137  *
138  */
139 void hs_handshake::handshake_loop(afb_api_t api, int times, int sleeps)
140 {
141     int count = 0;
142     do {
143         // try to subscribe handshake event
144         if(hs_handshake::hs_sts == hs_handshake::Handshake_Idle
145         || hs_handshake::hs_sts == hs_handshake::Handshake_Subscribe_Fail) {
146             hs_handshake::hs_sts = Handshake_Subscribing;
147             HS_WmProxy wm_proxy;
148             wm_proxy.subscribe(api, HS_WmProxy::Event_Handshake, handshake_subscribe_callback);
149         }
150
151         // wait handshake event
152         if(hs_handshake::hs_sts == hs_handshake::Handshake_Over) {
153             break;
154         }
155
156         ++count;
157         usleep(sleeps*1000);
158     } while(count < times);
159     AFB_NOTICE("handshake over, m_times=%d, m_sleep=%d, count=%d.", times, sleeps, count);
160     HS_AppRecover::instance()->startRecovery(api);
161 }
162
163 struct hs_instance {
164     HS_ClientManager *client_manager;   // the connection session manager
165     HS_AppInfo *app_info;               // application info
166     HS_AppRecover *app_recover;         // application recover
167     HS_VuiAdapter * vui_adapter;        // vui function adapter
168
169     hs_instance() : client_manager(HS_ClientManager::instance()), app_info(HS_AppInfo::instance()), app_recover(HS_AppRecover::instance()), vui_adapter(HS_VuiAdapter::instance()) {}
170     int init(afb_api_t api);
171     void setEventHook(const char *event, const event_hook_func f);
172     void onEvent(afb_api_t api, const char *event, struct json_object *object);
173 private:
174     std::unordered_map<std::string, std::list<event_hook_func>> event_hook_list;
175 };
176
177 static struct hs_instance *g_hs_instance;
178
179 /**
180  * init function
181  *
182  * #### Parameters
183  * - api : the api serving the request
184  *
185  * #### Return
186  * 0 : init success
187  * 1 : init fail
188  *
189  */
190 int hs_instance::init(afb_api_t api)
191 {
192     if(client_manager == nullptr) {
193         AFB_ERROR("client_manager is nullptr.");
194         return -1;
195     }
196     client_manager->init();
197
198     if(app_info == nullptr) {
199         AFB_ERROR("app_info is nullptr.");
200         return -1;
201     }
202     app_info->init(api);
203
204     HS_Config hs_config;
205     if(hs_config.readConfig() < 0) {
206         AFB_ERROR("read config file failed.");
207         return -1;
208     }
209
210     if(app_recover == nullptr) {
211         AFB_ERROR("app_recover is nullptr.");
212         return -1;
213     }
214     app_recover->init(api);
215     app_recover->setRecoverMap(hs_config.getRecoverMap());
216
217     const struct handshake_info *h = hs_config.getHandshakeInfo();
218     struct hs_handshake handshake(h->times, h->sleep);
219     if(handshake.start(api) < 0) {
220         AFB_ERROR("handshake with windowmanager failed.");
221         return -1;
222     }
223
224     if(vui_adapter == nullptr) {
225         AFB_ERROR("vui_adapter is nullptr."); 
226     }
227     vui_adapter->init(api);
228
229     return 0;
230 }
231
232 /**
233  * set event hook
234  *
235  * #### Parameters
236  *  - event  : event name
237  *  - f : hook function
238  *
239  * #### Return
240  * Nothing
241  */
242 void hs_instance::setEventHook(const char *event, const event_hook_func f)
243 {
244     AFB_INFO("hook event %s", event);
245     if(event == nullptr || f == nullptr) {
246         AFB_WARNING("argument is null.");
247         return;
248     }
249
250     std::string ev(event);
251     auto it = event_hook_list.find(ev);
252     if(it != event_hook_list.end()) {
253         it->second.push_back(f);
254     }
255     else {
256         std::list<event_hook_func> l;
257         l.push_back(f);
258         event_hook_list[ev] = std::move(l);
259     }
260 }
261
262 /**
263  * onEvent function
264  *
265  * #### Parameters
266  *  - api : the api serving the request
267  *  - event  : event name
268  *  - object : event json object
269  *
270  * #### Return
271  * Nothing
272  */
273 void hs_instance::onEvent(afb_api_t api, const char *event, struct json_object *object)
274 {
275     std::string ev(event);
276     auto it = event_hook_list.find(ev);
277     if(it != event_hook_list.end()) {
278         for(auto &ref : it->second) {
279             if(ref(api, event, object))
280                 break;
281         }
282     }
283     else {
284         AFB_INFO("don't find hook event %s", event);
285     }
286 }
287
288 /**
289  * set event hook
290  *
291  * #### Parameters
292  *  - event  : event name
293  *  - f : hook function pointer
294  *
295  * #### Return
296  * Nothing
297  */
298 void setEventHook(const char *event, const event_hook_func f)
299 {
300     if(g_hs_instance == nullptr) {
301         AFB_ERROR("g_hs_instance is null.");
302         return;
303     }
304
305     g_hs_instance->setEventHook(event, f);
306 }
307
308 /*
309 ********** Method of HomeScreen Service (API) **********
310 */
311
312 static void pingSample(afb_req_t request)
313 {
314    static int pingcount = 0;
315    afb_req_success_f(request, json_object_new_int(pingcount), "Ping count = %d", pingcount);
316    AFB_DEBUG("Verbosity macro at level notice invoked at ping invocation count = %d", pingcount);
317    pingcount++;
318 }
319
320 /**
321  * tap_shortcut notify for homescreen
322  * When Shortcut area is tapped,  notify these applciations
323  *
324  * #### Parameters
325  * Request key
326  * - application_id   : application id
327  *
328  * #### Return
329  * None
330  *
331  */
332 static void tap_shortcut (afb_req_t request)
333 {
334     int ret = 0;
335     const char* value = afb_req_value(request, _application_id);
336     if (value) {
337         AFB_INFO("request appid = %s.", value);
338         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
339         if(ret == AFB_REQ_NOT_STARTED_APPLICATION) {
340             g_hs_instance->client_manager->setStartupAppid(std::string(value));
341             std::string id = g_hs_instance->app_info->getAppProperty(value, _keyId);
342             HS_AfmMainProxy afm_proxy;
343             afm_proxy.start(request->api, id);
344             ret = 0;
345         }
346     }
347     else {
348         ret = AFB_EVENT_BAD_REQUEST;
349     }
350
351     if (ret) {
352         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
353     }
354     else {
355         struct json_object *res = json_object_new_object();
356         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
357           _error,  ret);
358         afb_req_success(request, res, "afb_event_push event [tap_shortcut]");
359     }
360 }
361
362 /**
363  * HomeScreen OnScreen message
364  *
365  * #### Parameters
366  * Request key
367  * - display_message   : message for display
368  *
369  * #### Return
370  * None
371  *
372  */
373 static void on_screen_message (afb_req_t request)
374 {
375     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__);
376     if (ret) {
377         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
378     }
379     else {
380         struct json_object *res = json_object_new_object();
381         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
382           _error,  ret);
383         afb_req_success(request, res, "afb_event_push event [on_screen_message]");
384     }
385 }
386
387 /**
388  * HomeScreen OnScreen Reply
389  *
390  * #### Parameters
391  * Request key
392  * - reply_message   : message for reply
393  *
394  * #### Return
395  * None
396  *
397  */
398 static void on_screen_reply (afb_req_t request)
399 {
400     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__);
401     if (ret) {
402         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
403     }
404     else {
405         struct json_object *res = json_object_new_object();
406         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
407           _error,  ret);
408         afb_req_success(request, res, "afb_event_push event [on_screen_reply]");
409     }
410 }
411
412 /**
413  * Subscribe event
414  *
415  * #### Parameters
416  *  - event  : Event name. Event list is written in libhomescreen.cpp
417  *
418  * #### Return
419  * None
420  *
421  */
422 static void subscribe(afb_req_t request)
423 {
424     int ret = 0;
425     std::string req_appid = std::move(get_application_id(request));
426     if(!req_appid.empty()) {
427         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str());
428     }
429     else {
430         ret = AFB_EVENT_BAD_REQUEST;
431     }
432
433     if(ret) {
434         afb_req_fail_f(request, "afb_req_subscribe failed", "called %s.", __FUNCTION__);
435     }
436     else {
437         struct json_object *res = json_object_new_object();
438         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
439             _error, ret);
440         afb_req_success_f(request, res, "homescreen binder subscribe.");
441     }
442 }
443
444 /**
445  * Unsubscribe event
446  *
447  * #### Parameters
448  *  - event  : Event name. Event list is written in libhomescreen.cpp
449  *
450  * #### Return
451  * None
452  *
453  */
454 static void unsubscribe(afb_req_t request)
455 {
456     int ret = 0;
457     std::string req_appid = std::move(get_application_id(request));
458     if(!req_appid.empty()) {
459         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str());
460     }
461     else {
462         ret = AFB_EVENT_BAD_REQUEST;
463     }
464
465     if(ret) {
466         afb_req_fail_f(request, "afb_req_unsubscribe failed", "called %s.", __FUNCTION__);
467     }
468     else {
469         struct json_object *res = json_object_new_object();
470         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
471             _error, ret);
472         afb_req_success_f(request, res, "homescreen binder unsubscribe success.");
473     }
474 }
475
476 /**
477  * showWindow event
478  *
479  * #### Parameters
480  *  - request : the request
481  *
482  * #### Return
483  * None
484  *
485  */
486 static void showWindow(afb_req_t request)
487 {
488     int ret = 0;
489     const char* value = afb_req_value(request, _application_id);
490     if (value) {
491         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
492         if(ret == AFB_REQ_NOT_STARTED_APPLICATION) {
493             g_hs_instance->client_manager->setStartupAppid(std::string(value));
494             std::string id = g_hs_instance->app_info->getAppProperty(value, _keyId);
495             HS_AfmMainProxy afm_proxy;
496             afm_proxy.start(request->api, id);
497             ret = 0;
498         }
499     }
500     else {
501         ret = AFB_EVENT_BAD_REQUEST;
502     }
503
504     if (ret) {
505         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
506     }
507     else {
508         struct json_object *res = json_object_new_object();
509         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
510           _error,  ret);
511         afb_req_success(request, res, "afb_event_push event [showWindow]");
512     }
513 }
514
515 /**
516  * hideWindow event
517  *
518  * #### Parameters
519  *  - request : the request
520  *
521  * #### Return
522  * None
523  *
524  */
525 static void hideWindow(afb_req_t request)
526 {
527     int ret = 0;
528     const char* value = afb_req_value(request, _application_id);
529     if (value) {
530         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
531     }
532     else {
533         ret = AFB_EVENT_BAD_REQUEST;
534     }
535
536     if (ret) {
537         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
538     }
539     else {
540         struct json_object *res = json_object_new_object();
541         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
542           _error,  ret);
543         afb_req_success(request, res, "afb_event_push event [hideWindow]");
544     }
545 }
546
547 /**
548  * replyShowWindow event
549  *
550  * #### Parameters
551  *  - request : the request
552  *
553  * #### Return
554  *  None
555  *
556  */
557 static void replyShowWindow(afb_req_t request)
558 {
559     int ret = 0;
560     const char* value = afb_req_value(request, _application_id);
561     if (value) {
562         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
563     }
564     else {
565         ret = AFB_EVENT_BAD_REQUEST;
566     }
567
568     if (ret) {
569         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
570     }
571     else {
572         struct json_object *res = json_object_new_object();
573         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
574           _error,  ret);
575         afb_req_success(request, res, "afb_event_push event [replyShowWindow]");
576     }
577 }
578
579 /**
580  * showNotification event
581  *
582  * the contents to homescreen which display at top area.
583  *
584  * #### Parameters
585  *  - request : the request
586  *
587  * #### Return
588  * None
589  *
590  */
591 static void showNotification(afb_req_t request)
592 {
593     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, "homescreen");
594     if (ret) {
595         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
596     }
597     else {
598         struct json_object *res = json_object_new_object();
599         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
600           _error,  ret);
601         afb_req_success(request, res, "afb_event_push event [showNotification]");
602     }
603 }
604
605 /**
606  * showInformation event
607  *
608  * the contents to homescreen which display at bottom area.
609  *
610  * #### Parameters
611  *  - request : the request
612  *
613  * #### Return
614  * None
615  *
616  */
617 static void showInformation(afb_req_t request)
618 {
619     int ret = g_hs_instance->client_manager->handleRequest(request,  __FUNCTION__, "homescreen");
620     if (ret) {
621         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
622     }
623     else {
624         struct json_object *res = json_object_new_object();
625         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
626           _error,  ret);
627         afb_req_success(request, res, "afb_event_push event [showInformation]");
628     }
629 }
630
631 /**
632  * get runnables list
633  *
634  * #### Parameters
635  *  - request : the request
636  *
637  * #### Return
638  * None
639  *
640  */
641 static void getRunnables(afb_req_t request)
642 {
643     struct json_object* j_runnable = json_object_new_array();
644     g_hs_instance->app_info->getRunnables(&j_runnable);
645
646     /*create response json object*/
647     struct json_object *res = json_object_new_object();
648     hs_add_object_to_json_object_func(res, __FUNCTION__, 2, _error, 0);
649     json_object_object_add(res, _keyData, j_runnable);
650     afb_req_success_f(request, res, "homescreen binder unsubscribe success.");
651 }
652
653 /**
654  * registerShortcut event
655  *
656  * #### Parameters
657  *  - value  : the json contents to MenuBar.
658  *    {"application_id":"homescreen","parameter":{"shortcut_id":"dashboard@0.1","shortcut_name":"Dashboard","postion": 1}}
659  *
660  * #### Return
661  * None
662  *
663  */
664 static void registerShortcut(afb_req_t request)
665 {
666     int ret = 0;
667     const char* value = afb_req_value(request, _application_id);
668     if (value) {
669         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
670     }
671     else {
672         ret = AFB_EVENT_BAD_REQUEST;
673     }
674
675     if (ret) {
676         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
677     }
678     else {
679         struct json_object *res = json_object_new_object();
680         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
681           _error,  ret);
682         afb_req_success(request, res, "afb_event_push event [registerShortcut]");
683     }
684 }
685
686 /**
687  * updateShortcut event
688  *
689  * #### Parameters
690  *  - value  : homescreen shortcut json contents.
691  *    {"application_id":"launcher","parameter":{"shortcut":[{"shortcut_id":"hvac","shortcut_name":"HVAC"},...]}}
692  *
693  * #### Return
694  * None
695  *
696  */
697 static void updateShortcut(afb_req_t request)
698 {
699     int ret = 0;
700     const char* value = afb_req_value(request, _application_id);
701     if (value) {
702         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
703     }
704     else {
705         ret = AFB_EVENT_BAD_REQUEST;
706     }
707
708     if (ret) {
709         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
710     }
711     else {
712         struct json_object *res = json_object_new_object();
713         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
714           _error,  ret);
715         afb_req_success(request, res, "afb_event_push event [updateShortcut]");
716     }
717 }
718
719 /*
720  * array of the verbs exported to afb-daemon
721  */
722 static const afb_verb_t verbs[]= {
723     /* VERB'S NAME                 FUNCTION TO CALL                  */
724     { .verb="ping",              .callback=pingSample             },
725     { .verb="tap_shortcut",      .callback=tap_shortcut           },
726     { .verb="showWindow",        .callback=showWindow             },
727     { .verb="hideWindow",        .callback=hideWindow             },
728     { .verb="replyShowWindow",   .callback=replyShowWindow        },
729     { .verb="on_screen_message", .callback=on_screen_message      },
730     { .verb="on_screen_reply",   .callback=on_screen_reply        },
731     { .verb="subscribe",         .callback=subscribe              },
732     { .verb="unsubscribe",       .callback=unsubscribe            },
733     { .verb="showNotification",  .callback=showNotification       },
734     { .verb="showInformation",   .callback=showInformation        },
735     { .verb="getRunnables",      .callback=getRunnables           },
736     { .verb="registerShortcut",  .callback=registerShortcut       },
737     { .verb="updateShortcut",    .callback=updateShortcut         },
738     {NULL } /* marker for end of the array */
739 };
740
741 /**
742  * homescreen binding preinit function
743  *
744  * #### Parameters
745  *  - api : the api serving the request
746  *
747  * #### Return
748  * None
749  *
750  */
751 static int preinit(afb_api_t api)
752 {
753     AFB_DEBUG("binding preinit (was register)");
754     return 0;
755 }
756
757 /**
758  * homescreen binding init function
759  *
760  * #### Parameters
761  *  - api : the api serving the request
762  *
763  * #### Return
764  * None
765  *
766  */
767 static int init(afb_api_t api)
768 {
769     AFB_DEBUG("binding init");
770
771     if(g_hs_instance != nullptr) {
772         AFB_WARNING( "g_hs_instance isn't null.");
773         delete g_hs_instance->client_manager;
774         delete g_hs_instance->app_info;
775         delete g_hs_instance->app_recover;
776         delete g_hs_instance->vui_adapter;
777         delete g_hs_instance;
778         g_hs_instance = nullptr;
779     }
780     g_hs_instance = new hs_instance();
781     if(g_hs_instance == nullptr) {
782         AFB_ERROR( "new g_hs_instance failed.");
783         return -1;
784     }
785
786     return g_hs_instance->init(api);
787 }
788
789 /**
790  * homescreen binding event function
791  *
792  * #### Parameters
793  *  - api : the api serving the request
794  *  - event  : event name
795  *  - object : event json object
796  *
797  * #### Return
798  * None
799  *
800  */
801 static void onevent(afb_api_t api, const char *event, struct json_object *object)
802 {
803     AFB_INFO("on_event %s, object %s", event, json_object_to_json_string(object));
804     g_hs_instance->onEvent(api, event, object);
805 }
806
807 const afb_binding_t afbBindingExport = {
808     .api = "homescreen",
809     .specification = NULL,
810     .info = NULL,
811     .verbs = verbs,
812     .preinit = preinit,
813     .init = init,
814     .onevent = onevent
815 };