142007fb81cf939541ade41f1fb3facf03f53836
[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     HS_AppRecover *app_recover;
144
145     hs_instance() : client_manager(HS_ClientManager::instance()), app_info(HS_AppInfo::instance()), app_recover(HS_AppRecover::instance()) {}
146     int init(afb_api_t api);
147     void setEventHook(const char *event, const event_hook_func f);
148     void onEvent(afb_api_t api, const char *event, struct json_object *object);
149 private:
150     std::unordered_map<std::string, std::list<event_hook_func>> event_hook_list;
151 };
152
153 static struct hs_instance *g_hs_instance;
154
155 /**
156  * init function
157  *
158  * #### Parameters
159  * - api : the api serving the request
160  *
161  * #### Return
162  * 0 : init success
163  * 1 : init fail
164  *
165  */
166 int hs_instance::init(afb_api_t api)
167 {
168     if(client_manager == nullptr) {
169         AFB_ERROR("client_manager is nullptr.");
170         return -1;
171     }
172     client_manager->init();
173
174     if(app_info == nullptr) {
175         AFB_ERROR("app_info is nullptr.");
176         return -1;
177     }
178     app_info->init(api);
179
180     HS_Config hs_config;
181     if(hs_config.readConfig() < 0) {
182         AFB_ERROR("read config file failed.");
183         return -1;
184     }
185
186     const struct handshake_info *h = hs_config.getHandshakeInfo();
187     struct hs_handshake handshake(h->times, h->sleep);
188     if(handshake.start(api) < 0) {
189         AFB_ERROR("handshake with windowmanager failed.");
190         return -1;
191     }
192
193     if(app_recover == nullptr) {
194         AFB_ERROR("app_recover is nullptr.");
195         return -1;
196     }
197     app_recover->init(api);
198     app_recover->startRecovery(api, hs_config.getRecoverMap());
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             g_hs_instance->client_manager->setStartupAppid(std::string(value));
309             std::string id = g_hs_instance->app_info->getAppProperty(value, _keyId);
310             HS_AfmMainProxy afm_proxy;
311             afm_proxy.start(request->api, id);
312             ret = 0;
313         }
314     }
315     else {
316         ret = AFB_EVENT_BAD_REQUEST;
317     }
318
319     if (ret) {
320         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
321     }
322     else {
323         struct json_object *res = json_object_new_object();
324         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
325           _error,  ret);
326         afb_req_success(request, res, "afb_event_push event [tap_shortcut]");
327     }
328 }
329
330 /**
331  * HomeScreen OnScreen message
332  *
333  * #### Parameters
334  * Request key
335  * - display_message   : message for display
336  *
337  * #### Return
338  * None
339  *
340  */
341 static void on_screen_message (afb_req_t request)
342 {
343     AFB_DEBUG("called.");
344     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__);
345     if (ret) {
346         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
347     }
348     else {
349         struct json_object *res = json_object_new_object();
350         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
351           _error,  ret);
352         afb_req_success(request, res, "afb_event_push event [on_screen_message]");
353     }
354 }
355
356 /**
357  * HomeScreen OnScreen Reply
358  *
359  * #### Parameters
360  * Request key
361  * - reply_message   : message for reply
362  *
363  * #### Return
364  * None
365  *
366  */
367 static void on_screen_reply (afb_req_t request)
368 {
369     AFB_DEBUG("called.");
370     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__);
371     if (ret) {
372         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
373     }
374     else {
375         struct json_object *res = json_object_new_object();
376         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
377           _error,  ret);
378         afb_req_success(request, res, "afb_event_push event [on_screen_reply]");
379     }
380 }
381
382 /**
383  * Subscribe event
384  *
385  * #### Parameters
386  *  - event  : Event name. Event list is written in libhomescreen.cpp
387  *
388  * #### Return
389  * None
390  *
391  */
392 static void subscribe(afb_req_t request)
393 {
394     AFB_DEBUG("called.");
395     int ret = 0;
396     std::string req_appid = std::move(get_application_id(request));
397     if(!req_appid.empty()) {
398         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str());
399     }
400     else {
401         ret = AFB_EVENT_BAD_REQUEST;
402     }
403
404     if(ret) {
405         afb_req_fail_f(request, "afb_req_subscribe failed", "called %s.", __FUNCTION__);
406     }
407     else {
408         struct json_object *res = json_object_new_object();
409         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
410             _error, ret);
411         afb_req_success_f(request, res, "homescreen binder subscribe.");
412     }
413 }
414
415 /**
416  * Unsubscribe event
417  *
418  * #### Parameters
419  *  - event  : Event name. Event list is written in libhomescreen.cpp
420  *
421  * #### Return
422  * None
423  *
424  */
425 static void unsubscribe(afb_req_t request)
426 {
427     AFB_DEBUG("called.");
428     int ret = 0;
429     std::string req_appid = std::move(get_application_id(request));
430     if(!req_appid.empty()) {
431         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str());
432     }
433     else {
434         ret = AFB_EVENT_BAD_REQUEST;
435     }
436
437     if(ret) {
438         afb_req_fail_f(request, "afb_req_unsubscribe failed", "called %s.", __FUNCTION__);
439     }
440     else {
441         struct json_object *res = json_object_new_object();
442         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
443             _error, ret);
444         afb_req_success_f(request, res, "homescreen binder unsubscribe success.");
445     }
446 }
447
448 /**
449  * showWindow event
450  *
451  * #### Parameters
452  *  - request : the request
453  *
454  * #### Return
455  * None
456  *
457  */
458 static void showWindow(afb_req_t request)
459 {
460     AFB_DEBUG("called.");
461     int ret = 0;
462     const char* value = afb_req_value(request, _application_id);
463     if (value) {
464         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
465         if(ret == AFB_REQ_NOT_STARTED_APPLICATION) {
466             g_hs_instance->client_manager->setStartupAppid(std::string(value));
467             std::string id = g_hs_instance->app_info->getAppProperty(value, _keyId);
468             HS_AfmMainProxy afm_proxy;
469             afm_proxy.start(request->api, id);
470             ret = 0;
471         }
472     }
473     else {
474         ret = AFB_EVENT_BAD_REQUEST;
475     }
476
477     if (ret) {
478         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
479     }
480     else {
481         struct json_object *res = json_object_new_object();
482         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
483           _error,  ret);
484         afb_req_success(request, res, "afb_event_push event [showWindow]");
485     }
486 }
487
488 /**
489  * hideWindow event
490  *
491  * #### Parameters
492  *  - request : the request
493  *
494  * #### Return
495  * None
496  *
497  */
498 static void hideWindow(afb_req_t request)
499 {
500     AFB_DEBUG("called.");
501     int ret = 0;
502     const char* value = afb_req_value(request, _application_id);
503     if (value) {
504         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
505     }
506     else {
507         ret = AFB_EVENT_BAD_REQUEST;
508     }
509
510     if (ret) {
511         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
512     }
513     else {
514         struct json_object *res = json_object_new_object();
515         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
516           _error,  ret);
517         afb_req_success(request, res, "afb_event_push event [hideWindow]");
518     }
519 }
520
521 /**
522  * replyShowWindow event
523  *
524  * #### Parameters
525  *  - request : the request
526  *
527  * #### Return
528  *  None
529  *
530  */
531 static void replyShowWindow(afb_req_t request)
532 {
533     AFB_DEBUG("called.");
534     int ret = 0;
535     const char* value = afb_req_value(request, _application_id);
536     if (value) {
537         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
538     }
539     else {
540         ret = AFB_EVENT_BAD_REQUEST;
541     }
542
543     if (ret) {
544         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
545     }
546     else {
547         struct json_object *res = json_object_new_object();
548         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
549           _error,  ret);
550         afb_req_success(request, res, "afb_event_push event [replyShowWindow]");
551     }
552 }
553
554 /**
555  * showNotification event
556  *
557  * the contents to homescreen which display at top area.
558  *
559  * #### Parameters
560  *  - request : the request
561  *
562  * #### Return
563  * None
564  *
565  */
566 static void showNotification(afb_req_t request)
567 {
568     AFB_DEBUG("called.");
569     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, "homescreen");
570     if (ret) {
571         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
572     }
573     else {
574         struct json_object *res = json_object_new_object();
575         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
576           _error,  ret);
577         afb_req_success(request, res, "afb_event_push event [showNotification]");
578     }
579 }
580
581 /**
582  * showInformation event
583  *
584  * the contents to homescreen which display at bottom area.
585  *
586  * #### Parameters
587  *  - request : the request
588  *
589  * #### Return
590  * None
591  *
592  */
593 static void showInformation(afb_req_t request)
594 {
595     AFB_DEBUG("called.");
596     int ret = g_hs_instance->client_manager->handleRequest(request,  __FUNCTION__, "homescreen");
597     if (ret) {
598         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
599     }
600     else {
601         struct json_object *res = json_object_new_object();
602         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
603           _error,  ret);
604         afb_req_success(request, res, "afb_event_push event [showInformation]");
605     }
606 }
607
608 /**
609  * get runnables list
610  *
611  * #### Parameters
612  *  - request : the request
613  *
614  * #### Return
615  * None
616  *
617  */
618 static void getRunnables(afb_req_t request)
619 {
620     AFB_DEBUG("called.");
621     struct json_object* j_runnable = json_object_new_array();
622     g_hs_instance->app_info->getRunnables(&j_runnable);
623
624     /*create response json object*/
625     struct json_object *res = json_object_new_object();
626     hs_add_object_to_json_object_func(res, __FUNCTION__, 2, _error, 0);
627     json_object_object_add(res, _keyData, j_runnable);
628     afb_req_success_f(request, res, "homescreen binder unsubscribe success.");
629 }
630
631 /*
632  * array of the verbs exported to afb-daemon
633  */
634 static const afb_verb_t verbs[]= {
635     /* VERB'S NAME                 FUNCTION TO CALL                  */
636     { .verb="ping",              .callback=pingSample             },
637     { .verb="tap_shortcut",      .callback=tap_shortcut           },
638     { .verb="showWindow",        .callback=showWindow             },
639     { .verb="hideWindow",        .callback=hideWindow             },
640     { .verb="replyShowWindow",   .callback=replyShowWindow        },
641     { .verb="on_screen_message", .callback=on_screen_message      },
642     { .verb="on_screen_reply",   .callback=on_screen_reply        },
643     { .verb="subscribe",         .callback=subscribe              },
644     { .verb="unsubscribe",       .callback=unsubscribe            },
645     { .verb="showNotification",  .callback=showNotification       },
646     { .verb="showInformation",   .callback=showInformation        },
647     { .verb="getRunnables",      .callback=getRunnables           },
648     {NULL } /* marker for end of the array */
649 };
650
651 /**
652  * homescreen binding preinit function
653  *
654  * #### Parameters
655  *  - api : the api serving the request
656  *
657  * #### Return
658  * None
659  *
660  */
661 static int preinit(afb_api_t api)
662 {
663     AFB_DEBUG("binding preinit (was register)");
664     return 0;
665 }
666
667 /**
668  * homescreen binding init function
669  *
670  * #### Parameters
671  *  - api : the api serving the request
672  *
673  * #### Return
674  * None
675  *
676  */
677 static int init(afb_api_t api)
678 {
679     AFB_DEBUG("binding init");
680
681     if(g_hs_instance != nullptr) {
682         AFB_WARNING( "g_hs_instance isn't null.");
683         delete g_hs_instance->client_manager;
684         delete g_hs_instance->app_info;
685         delete g_hs_instance;
686         g_hs_instance = nullptr;
687     }
688     g_hs_instance = new hs_instance();
689     if(g_hs_instance == nullptr) {
690         AFB_ERROR( "Fatal Error: new g_hs_instance failed.");
691         return -1;
692     }
693
694     return g_hs_instance->init(api);
695 }
696
697 /**
698  * homescreen binding event function
699  *
700  * #### Parameters
701  *  - api : the api serving the request
702  *  - event  : event name
703  *  - object : event json object
704  *
705  * #### Return
706  * None
707  *
708  */
709 static void onevent(afb_api_t api, const char *event, struct json_object *object)
710 {
711     AFB_INFO("on_event %s", event);
712     g_hs_instance->onEvent(api, event, object);
713 }
714
715 const afb_binding_t afbBindingExport = {
716     .api = "homescreen",
717     .specification = NULL,
718     .info = NULL,
719     .verbs = verbs,
720     .preinit = preinit,
721     .init = init,
722     .onevent = onevent
723 };