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