add handshake loop
[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
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);
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);
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)
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(m_sleep*1000);
158     } while(count < m_times);
159     AFB_NOTICE("handshake over, count=%d.", 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;
167
168     hs_instance() : client_manager(HS_ClientManager::instance()), app_info(HS_AppInfo::instance()), app_recover(HS_AppRecover::instance()) {}
169     int init(afb_api_t api);
170     void setEventHook(const char *event, const event_hook_func f);
171     void onEvent(afb_api_t api, const char *event, struct json_object *object);
172 private:
173     std::unordered_map<std::string, std::list<event_hook_func>> event_hook_list;
174 };
175
176 static struct hs_instance *g_hs_instance;
177
178 /**
179  * init function
180  *
181  * #### Parameters
182  * - api : the api serving the request
183  *
184  * #### Return
185  * 0 : init success
186  * 1 : init fail
187  *
188  */
189 int hs_instance::init(afb_api_t api)
190 {
191     if(client_manager == nullptr) {
192         AFB_ERROR("client_manager is nullptr.");
193         return -1;
194     }
195     client_manager->init();
196
197     if(app_info == nullptr) {
198         AFB_ERROR("app_info is nullptr.");
199         return -1;
200     }
201     app_info->init(api);
202
203     HS_Config hs_config;
204     if(hs_config.readConfig() < 0) {
205         AFB_ERROR("read config file failed.");
206         return -1;
207     }
208
209     if(app_recover == nullptr) {
210         AFB_ERROR("app_recover is nullptr.");
211         return -1;
212     }
213     app_recover->init(api);
214     app_recover->setRecoverMap(hs_config.getRecoverMap());
215
216     const struct handshake_info *h = hs_config.getHandshakeInfo();
217     struct hs_handshake handshake(h->times, h->sleep);
218     if(handshake.start(api) < 0) {
219         AFB_ERROR("handshake with windowmanager failed.");
220         return -1;
221     }
222
223     return 0;
224 }
225
226 /**
227  * set event hook
228  *
229  * #### Parameters
230  *  - event  : event name
231  *  - f : hook function
232  *
233  * #### Return
234  * Nothing
235  */
236 void hs_instance::setEventHook(const char *event, const event_hook_func f)
237 {
238     if(event == nullptr || f == nullptr) {
239         AFB_WARNING("argument is null.");
240         return;
241     }
242
243     std::string ev(event);
244     auto it = event_hook_list.find(ev);
245     if(it != event_hook_list.end()) {
246         it->second.push_back(f);
247     }
248     else {
249         std::list<event_hook_func> l;
250         l.push_back(f);
251         event_hook_list[ev] = std::move(l);
252     }
253 }
254
255 /**
256  * onEvent function
257  *
258  * #### Parameters
259  *  - api : the api serving the request
260  *  - event  : event name
261  *  - object : event json object
262  *
263  * #### Return
264  * Nothing
265  */
266 void hs_instance::onEvent(afb_api_t api, const char *event, struct json_object *object)
267 {
268     std::string ev(event);
269     auto it = event_hook_list.find(ev);
270     if(it != event_hook_list.end()) {
271         for(auto &ref : it->second) {
272             if(ref(api, event, object))
273                 break;
274         }
275     }
276 }
277
278 /**
279  * set event hook
280  *
281  * #### Parameters
282  *  - event  : event name
283  *  - f : hook function pointer
284  *
285  * #### Return
286  * Nothing
287  */
288 void setEventHook(const char *event, const event_hook_func f)
289 {
290     if(g_hs_instance == nullptr) {
291         AFB_ERROR("g_hs_instance is null.");
292         return;
293     }
294
295     g_hs_instance->setEventHook(event, f);
296 }
297
298 /*
299 ********** Method of HomeScreen Service (API) **********
300 */
301
302 static void pingSample(afb_req_t request)
303 {
304    static int pingcount = 0;
305    afb_req_success_f(request, json_object_new_int(pingcount), "Ping count = %d", pingcount);
306    AFB_DEBUG("Verbosity macro at level notice invoked at ping invocation count = %d", pingcount);
307    pingcount++;
308 }
309
310 /**
311  * tap_shortcut notify for homescreen
312  * When Shortcut area is tapped,  notify these applciations
313  *
314  * #### Parameters
315  * Request key
316  * - application_id   : application id
317  *
318  * #### Return
319  * None
320  *
321  */
322 static void tap_shortcut (afb_req_t request)
323 {
324     AFB_DEBUG("called.");
325     int ret = 0;
326     const char* value = afb_req_value(request, _application_id);
327     if (value) {
328         AFB_INFO("request appid = %s.", value);
329         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
330         if(ret == AFB_REQ_NOT_STARTED_APPLICATION) {
331             g_hs_instance->client_manager->setStartupAppid(std::string(value));
332             std::string id = g_hs_instance->app_info->getAppProperty(value, _keyId);
333             HS_AfmMainProxy afm_proxy;
334             afm_proxy.start(request->api, id);
335             ret = 0;
336         }
337     }
338     else {
339         ret = AFB_EVENT_BAD_REQUEST;
340     }
341
342     if (ret) {
343         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
344     }
345     else {
346         struct json_object *res = json_object_new_object();
347         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
348           _error,  ret);
349         afb_req_success(request, res, "afb_event_push event [tap_shortcut]");
350     }
351 }
352
353 /**
354  * HomeScreen OnScreen message
355  *
356  * #### Parameters
357  * Request key
358  * - display_message   : message for display
359  *
360  * #### Return
361  * None
362  *
363  */
364 static void on_screen_message (afb_req_t request)
365 {
366     AFB_DEBUG("called.");
367     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__);
368     if (ret) {
369         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
370     }
371     else {
372         struct json_object *res = json_object_new_object();
373         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
374           _error,  ret);
375         afb_req_success(request, res, "afb_event_push event [on_screen_message]");
376     }
377 }
378
379 /**
380  * HomeScreen OnScreen Reply
381  *
382  * #### Parameters
383  * Request key
384  * - reply_message   : message for reply
385  *
386  * #### Return
387  * None
388  *
389  */
390 static void on_screen_reply (afb_req_t request)
391 {
392     AFB_DEBUG("called.");
393     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__);
394     if (ret) {
395         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
396     }
397     else {
398         struct json_object *res = json_object_new_object();
399         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
400           _error,  ret);
401         afb_req_success(request, res, "afb_event_push event [on_screen_reply]");
402     }
403 }
404
405 /**
406  * Subscribe event
407  *
408  * #### Parameters
409  *  - event  : Event name. Event list is written in libhomescreen.cpp
410  *
411  * #### Return
412  * None
413  *
414  */
415 static void subscribe(afb_req_t request)
416 {
417     AFB_DEBUG("called.");
418     int ret = 0;
419     std::string req_appid = std::move(get_application_id(request));
420     if(!req_appid.empty()) {
421         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str());
422     }
423     else {
424         ret = AFB_EVENT_BAD_REQUEST;
425     }
426
427     if(ret) {
428         afb_req_fail_f(request, "afb_req_subscribe failed", "called %s.", __FUNCTION__);
429     }
430     else {
431         struct json_object *res = json_object_new_object();
432         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
433             _error, ret);
434         afb_req_success_f(request, res, "homescreen binder subscribe.");
435     }
436 }
437
438 /**
439  * Unsubscribe event
440  *
441  * #### Parameters
442  *  - event  : Event name. Event list is written in libhomescreen.cpp
443  *
444  * #### Return
445  * None
446  *
447  */
448 static void unsubscribe(afb_req_t request)
449 {
450     AFB_DEBUG("called.");
451     int ret = 0;
452     std::string req_appid = std::move(get_application_id(request));
453     if(!req_appid.empty()) {
454         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str());
455     }
456     else {
457         ret = AFB_EVENT_BAD_REQUEST;
458     }
459
460     if(ret) {
461         afb_req_fail_f(request, "afb_req_unsubscribe failed", "called %s.", __FUNCTION__);
462     }
463     else {
464         struct json_object *res = json_object_new_object();
465         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
466             _error, ret);
467         afb_req_success_f(request, res, "homescreen binder unsubscribe success.");
468     }
469 }
470
471 /**
472  * showWindow event
473  *
474  * #### Parameters
475  *  - request : the request
476  *
477  * #### Return
478  * None
479  *
480  */
481 static void showWindow(afb_req_t request)
482 {
483     AFB_DEBUG("called.");
484     int ret = 0;
485     const char* value = afb_req_value(request, _application_id);
486     if (value) {
487         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
488         if(ret == AFB_REQ_NOT_STARTED_APPLICATION) {
489             g_hs_instance->client_manager->setStartupAppid(std::string(value));
490             std::string id = g_hs_instance->app_info->getAppProperty(value, _keyId);
491             HS_AfmMainProxy afm_proxy;
492             afm_proxy.start(request->api, id);
493             ret = 0;
494         }
495     }
496     else {
497         ret = AFB_EVENT_BAD_REQUEST;
498     }
499
500     if (ret) {
501         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
502     }
503     else {
504         struct json_object *res = json_object_new_object();
505         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
506           _error,  ret);
507         afb_req_success(request, res, "afb_event_push event [showWindow]");
508     }
509 }
510
511 /**
512  * hideWindow event
513  *
514  * #### Parameters
515  *  - request : the request
516  *
517  * #### Return
518  * None
519  *
520  */
521 static void hideWindow(afb_req_t request)
522 {
523     AFB_DEBUG("called.");
524     int ret = 0;
525     const char* value = afb_req_value(request, _application_id);
526     if (value) {
527         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
528     }
529     else {
530         ret = AFB_EVENT_BAD_REQUEST;
531     }
532
533     if (ret) {
534         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
535     }
536     else {
537         struct json_object *res = json_object_new_object();
538         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
539           _error,  ret);
540         afb_req_success(request, res, "afb_event_push event [hideWindow]");
541     }
542 }
543
544 /**
545  * replyShowWindow event
546  *
547  * #### Parameters
548  *  - request : the request
549  *
550  * #### Return
551  *  None
552  *
553  */
554 static void replyShowWindow(afb_req_t request)
555 {
556     AFB_DEBUG("called.");
557     int ret = 0;
558     const char* value = afb_req_value(request, _application_id);
559     if (value) {
560         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
561     }
562     else {
563         ret = AFB_EVENT_BAD_REQUEST;
564     }
565
566     if (ret) {
567         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
568     }
569     else {
570         struct json_object *res = json_object_new_object();
571         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
572           _error,  ret);
573         afb_req_success(request, res, "afb_event_push event [replyShowWindow]");
574     }
575 }
576
577 /**
578  * showNotification event
579  *
580  * the contents to homescreen which display at top area.
581  *
582  * #### Parameters
583  *  - request : the request
584  *
585  * #### Return
586  * None
587  *
588  */
589 static void showNotification(afb_req_t request)
590 {
591     AFB_DEBUG("called.");
592     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, "homescreen");
593     if (ret) {
594         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
595     }
596     else {
597         struct json_object *res = json_object_new_object();
598         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
599           _error,  ret);
600         afb_req_success(request, res, "afb_event_push event [showNotification]");
601     }
602 }
603
604 /**
605  * showInformation event
606  *
607  * the contents to homescreen which display at bottom area.
608  *
609  * #### Parameters
610  *  - request : the request
611  *
612  * #### Return
613  * None
614  *
615  */
616 static void showInformation(afb_req_t request)
617 {
618     AFB_DEBUG("called.");
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     AFB_DEBUG("called.");
644     struct json_object* j_runnable = json_object_new_array();
645     g_hs_instance->app_info->getRunnables(&j_runnable);
646
647     /*create response json object*/
648     struct json_object *res = json_object_new_object();
649     hs_add_object_to_json_object_func(res, __FUNCTION__, 2, _error, 0);
650     json_object_object_add(res, _keyData, j_runnable);
651     afb_req_success_f(request, res, "homescreen binder unsubscribe success.");
652 }
653
654 /**
655  * registerShortcut event
656  *
657  * #### Parameters
658  *  - value  : the json contents to MenuBar.
659  *    {"application_id":"homescreen","parameter":{"shortcut_id":"dashboard@0.1","shortcut_name":"Dashboard","postion": 1}}
660  *
661  * #### Return
662  * None
663  *
664  */
665 static void registerShortcut(afb_req_t request)
666 {
667     int ret = 0;
668     const char* value = afb_req_value(request, _application_id);
669     if (value) {
670         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
671     }
672     else {
673         ret = AFB_EVENT_BAD_REQUEST;
674     }
675
676     if (ret) {
677         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
678     }
679     else {
680         struct json_object *res = json_object_new_object();
681         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
682           _error,  ret);
683         afb_req_success(request, res, "afb_event_push event [registerShortcut]");
684     }
685 }
686
687 /**
688  * updateShortcut event
689  *
690  * #### Parameters
691  *  - value  : homescreen shortcut json contents.
692  *    {"application_id":"launcher","parameter":{"shortcut":[{"shortcut_id":"hvac","shortcut_name":"HVAC"},...]}}
693  *
694  * #### Return
695  * None
696  *
697  */
698 static void updateShortcut(afb_req_t request)
699 {
700     int ret = 0;
701     const char* value = afb_req_value(request, _application_id);
702     if (value) {
703         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
704     }
705     else {
706         ret = AFB_EVENT_BAD_REQUEST;
707     }
708
709     if (ret) {
710         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
711     }
712     else {
713         struct json_object *res = json_object_new_object();
714         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
715           _error,  ret);
716         afb_req_success(request, res, "afb_event_push event [updateShortcut]");
717     }
718 }
719
720 /*
721  * array of the verbs exported to afb-daemon
722  */
723 static const afb_verb_t verbs[]= {
724     /* VERB'S NAME                 FUNCTION TO CALL                  */
725     { .verb="ping",              .callback=pingSample             },
726     { .verb="tap_shortcut",      .callback=tap_shortcut           },
727     { .verb="showWindow",        .callback=showWindow             },
728     { .verb="hideWindow",        .callback=hideWindow             },
729     { .verb="replyShowWindow",   .callback=replyShowWindow        },
730     { .verb="on_screen_message", .callback=on_screen_message      },
731     { .verb="on_screen_reply",   .callback=on_screen_reply        },
732     { .verb="subscribe",         .callback=subscribe              },
733     { .verb="unsubscribe",       .callback=unsubscribe            },
734     { .verb="showNotification",  .callback=showNotification       },
735     { .verb="showInformation",   .callback=showInformation        },
736     { .verb="registerShortcut",  .callback=registerShortcut       },
737     { .verb="getRunnables",      .callback=getRunnables           },
738     { .verb="updateShortcut",    .callback=updateShortcut         },
739     {NULL } /* marker for end of the array */
740 };
741
742 /**
743  * homescreen binding preinit function
744  *
745  * #### Parameters
746  *  - api : the api serving the request
747  *
748  * #### Return
749  * None
750  *
751  */
752 static int preinit(afb_api_t api)
753 {
754     AFB_DEBUG("binding preinit (was register)");
755     return 0;
756 }
757
758 /**
759  * homescreen binding init function
760  *
761  * #### Parameters
762  *  - api : the api serving the request
763  *
764  * #### Return
765  * None
766  *
767  */
768 static int init(afb_api_t api)
769 {
770     AFB_DEBUG("binding init");
771
772     if(g_hs_instance != nullptr) {
773         AFB_WARNING( "g_hs_instance isn't null.");
774         delete g_hs_instance->client_manager;
775         delete g_hs_instance->app_info;
776         delete g_hs_instance->app_recover;
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( "Fatal 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", event);
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 };