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