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