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