set area in showWindow
[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 #include "hs-vuiadapter.h"
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;         // application recover
169     HS_VuiAdapter * vui_adapter;        // vui function adapter
170
171     hs_instance() : client_manager(HS_ClientManager::instance()), app_info(HS_AppInfo::instance()), app_recover(HS_AppRecover::instance()), vui_adapter(HS_VuiAdapter::instance()) {}
172     int init(afb_api_t api);
173     void setEventHook(const char *event, const event_hook_func f);
174     void onEvent(afb_api_t api, const char *event, struct json_object *object);
175 private:
176     std::unordered_map<std::string, std::list<event_hook_func>> event_hook_list;
177 };
178
179 static struct hs_instance *g_hs_instance;
180
181 /**
182  * init function
183  *
184  * #### Parameters
185  * - api : the api serving the request
186  *
187  * #### Return
188  * 0 : init success
189  * 1 : init fail
190  *
191  */
192 int hs_instance::init(afb_api_t api)
193 {
194     if(client_manager == nullptr) {
195         AFB_ERROR("client_manager is nullptr.");
196         return -1;
197     }
198     client_manager->init();
199
200     if(app_info == nullptr) {
201         AFB_ERROR("app_info is nullptr.");
202         return -1;
203     }
204     app_info->init(api);
205
206     HS_Config hs_config;
207     if(hs_config.readConfig() < 0) {
208         AFB_ERROR("read config file failed.");
209         return -1;
210     }
211
212     if(app_recover == nullptr) {
213         AFB_ERROR("app_recover is nullptr.");
214         return -1;
215     }
216     app_recover->init(api);
217     app_recover->setRecoverMap(hs_config.getRecoverMap());
218
219     const struct handshake_info *h = hs_config.getHandshakeInfo();
220     struct hs_handshake handshake(h->times, h->sleep);
221     if(handshake.start(api) < 0) {
222         AFB_ERROR("handshake with windowmanager failed.");
223         return -1;
224     }
225
226     if(vui_adapter == nullptr) {
227         AFB_ERROR("vui_adapter is nullptr."); 
228     }
229     vui_adapter->init(api);
230
231     return 0;
232 }
233
234 /**
235  * set event hook
236  *
237  * #### Parameters
238  *  - event  : event name
239  *  - f : hook function
240  *
241  * #### Return
242  * Nothing
243  */
244 void hs_instance::setEventHook(const char *event, const event_hook_func f)
245 {
246     AFB_INFO("hook event %s", event);
247     if(event == nullptr || f == nullptr) {
248         AFB_WARNING("argument is null.");
249         return;
250     }
251
252     std::string ev(event);
253     auto it = event_hook_list.find(ev);
254     if(it != event_hook_list.end()) {
255         it->second.push_back(f);
256     }
257     else {
258         std::list<event_hook_func> l;
259         l.push_back(f);
260         event_hook_list[ev] = std::move(l);
261     }
262 }
263
264 /**
265  * onEvent function
266  *
267  * #### Parameters
268  *  - api : the api serving the request
269  *  - event  : event name
270  *  - object : event json object
271  *
272  * #### Return
273  * Nothing
274  */
275 void hs_instance::onEvent(afb_api_t api, const char *event, struct json_object *object)
276 {
277     std::string ev(event);
278     auto it = event_hook_list.find(ev);
279     if(it != event_hook_list.end()) {
280         for(auto &ref : it->second) {
281             if(ref(api, event, object))
282                 break;
283         }
284     }
285     else {
286         AFB_INFO("don't find hook event %s", event);
287     }
288 }
289
290 /**
291  * set event hook
292  *
293  * #### Parameters
294  *  - event  : event name
295  *  - f : hook function pointer
296  *
297  * #### Return
298  * Nothing
299  */
300 void setEventHook(const char *event, const event_hook_func f)
301 {
302     if(g_hs_instance == nullptr) {
303         AFB_ERROR("g_hs_instance is null.");
304         return;
305     }
306
307     g_hs_instance->setEventHook(event, f);
308 }
309
310 /*
311 ********** Method of HomeScreen Service (API) **********
312 */
313
314 static void pingSample(afb_req_t request)
315 {
316    static int pingcount = 0;
317    afb_req_success_f(request, json_object_new_int(pingcount), "Ping count = %d", pingcount);
318    AFB_DEBUG("Verbosity macro at level notice invoked at ping invocation count = %d", pingcount);
319    pingcount++;
320 }
321
322 /**
323  * tap_shortcut notify for homescreen
324  * When Shortcut area is tapped,  notify these applciations
325  *
326  * #### Parameters
327  * Request key
328  * - application_id   : application id
329  *
330  * #### Return
331  * None
332  *
333  */
334 static void tap_shortcut (afb_req_t request)
335 {
336     int ret = 0;
337     struct json_object *param_obj, *area_obj;
338     const char* value = afb_req_value(request, _application_id);
339     if (value
340     && json_object_object_get_ex(afb_req_json(request), _parameter, &param_obj)
341     && json_object_object_get_ex(param_obj, _area, &area_obj)) {
342         AFB_INFO("request appid = %s.", value);
343         const char* area = json_object_get_string(area_obj);
344         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
345         if(ret == AFB_REQ_NOT_STARTED_APPLICATION) {
346             g_hs_instance->client_manager->setStartupAppidAndArea(make_pair(std::string(value), std::string(area)));
347             std::string id = g_hs_instance->app_info->getAppProperty(value, _keyId);
348             HS_AfmMainProxy afm_proxy;
349             afm_proxy.start(request->api, id);
350             ret = 0;
351         }
352     }
353     else {
354         ret = AFB_EVENT_BAD_REQUEST;
355     }
356
357     if (ret) {
358         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
359     }
360     else {
361         struct json_object *res = json_object_new_object();
362         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
363           _error,  ret);
364         afb_req_success(request, res, "afb_event_push event [tap_shortcut]");
365     }
366 }
367
368 /**
369  * HomeScreen OnScreen message
370  *
371  * #### Parameters
372  * Request key
373  * - display_message   : message for display
374  *
375  * #### Return
376  * None
377  *
378  */
379 static void on_screen_message (afb_req_t request)
380 {
381     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__);
382     if (ret) {
383         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
384     }
385     else {
386         struct json_object *res = json_object_new_object();
387         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
388           _error,  ret);
389         afb_req_success(request, res, "afb_event_push event [on_screen_message]");
390     }
391 }
392
393 /**
394  * HomeScreen OnScreen Reply
395  *
396  * #### Parameters
397  * Request key
398  * - reply_message   : message for reply
399  *
400  * #### Return
401  * None
402  *
403  */
404 static void on_screen_reply (afb_req_t request)
405 {
406     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__);
407     if (ret) {
408         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __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(request, res, "afb_event_push event [on_screen_reply]");
415     }
416 }
417
418 /**
419  * Subscribe 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 subscribe(afb_req_t request)
429 {
430     int ret = 0;
431     std::string req_appid = std::move(get_application_id(request));
432     if(!req_appid.empty()) {
433         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str());
434     }
435     else {
436         ret = AFB_EVENT_BAD_REQUEST;
437     }
438
439     if(ret) {
440         afb_req_fail_f(request, "afb_req_subscribe failed", "called %s.", __FUNCTION__);
441     }
442     else {
443         struct json_object *res = json_object_new_object();
444         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
445             _error, ret);
446         afb_req_success_f(request, res, "homescreen binder subscribe.");
447     }
448 }
449
450 /**
451  * Unsubscribe event
452  *
453  * #### Parameters
454  *  - event  : Event name. Event list is written in libhomescreen.cpp
455  *
456  * #### Return
457  * None
458  *
459  */
460 static void unsubscribe(afb_req_t request)
461 {
462     int ret = 0;
463     std::string req_appid = std::move(get_application_id(request));
464     if(!req_appid.empty()) {
465         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str());
466     }
467     else {
468         ret = AFB_EVENT_BAD_REQUEST;
469     }
470
471     if(ret) {
472         afb_req_fail_f(request, "afb_req_unsubscribe failed", "called %s.", __FUNCTION__);
473     }
474     else {
475         struct json_object *res = json_object_new_object();
476         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
477             _error, ret);
478         afb_req_success_f(request, res, "homescreen binder unsubscribe success.");
479     }
480 }
481
482 /**
483  * showWindow event
484  *
485  * #### Parameters
486  *  - request : the request
487  *
488  * #### Return
489  * None
490  *
491  */
492 static void showWindow(afb_req_t request)
493 {
494     int ret = 0;
495     struct json_object *param_obj, *area_obj;
496     const char* value = afb_req_value(request, _application_id);
497     if (value
498     && json_object_object_get_ex(afb_req_json(request), _parameter, &param_obj)
499     && json_object_object_get_ex(param_obj, _area, &area_obj)) {
500         const char* area = json_object_get_string(area_obj);
501         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
502         if(ret == AFB_REQ_NOT_STARTED_APPLICATION) {
503             g_hs_instance->client_manager->setStartupAppidAndArea(make_pair(std::string(value), std::string(area)));
504             std::string id = g_hs_instance->app_info->getAppProperty(value, _keyId);
505             HS_AfmMainProxy afm_proxy;
506             afm_proxy.start(request->api, id);
507             ret = 0;
508         }
509     }
510     else {
511         ret = AFB_EVENT_BAD_REQUEST;
512     }
513
514     if (ret) {
515         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
516     }
517     else {
518         struct json_object *res = json_object_new_object();
519         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
520           _error,  ret);
521         afb_req_success(request, res, "afb_event_push event [showWindow]");
522     }
523 }
524
525 /**
526  * hideWindow event
527  *
528  * #### Parameters
529  *  - request : the request
530  *
531  * #### Return
532  * None
533  *
534  */
535 static void hideWindow(afb_req_t request)
536 {
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 [hideWindow]");
554     }
555 }
556
557 /**
558  * replyShowWindow event
559  *
560  * #### Parameters
561  *  - request : the request
562  *
563  * #### Return
564  *  None
565  *
566  */
567 static void replyShowWindow(afb_req_t request)
568 {
569     int ret = 0;
570     const char* value = afb_req_value(request, _application_id);
571     if (value) {
572         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
573     }
574     else {
575         ret = AFB_EVENT_BAD_REQUEST;
576     }
577
578     if (ret) {
579         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
580     }
581     else {
582         struct json_object *res = json_object_new_object();
583         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
584           _error,  ret);
585         afb_req_success(request, res, "afb_event_push event [replyShowWindow]");
586     }
587 }
588
589 /**
590  * showNotification event
591  *
592  * the contents to homescreen which display at top area.
593  *
594  * #### Parameters
595  *  - request : the request
596  *
597  * #### Return
598  * None
599  *
600  */
601 static void showNotification(afb_req_t request)
602 {
603     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, "homescreen");
604     if (ret) {
605         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
606     }
607     else {
608         struct json_object *res = json_object_new_object();
609         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
610           _error,  ret);
611         afb_req_success(request, res, "afb_event_push event [showNotification]");
612     }
613 }
614
615 /**
616  * showInformation event
617  *
618  * the contents to homescreen which display at bottom area.
619  *
620  * #### Parameters
621  *  - request : the request
622  *
623  * #### Return
624  * None
625  *
626  */
627 static void showInformation(afb_req_t request)
628 {
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     struct json_object* j_runnable = json_object_new_array();
654     g_hs_instance->app_info->getRunnables(&j_runnable);
655
656     /*create response json object*/
657     struct json_object *res = json_object_new_object();
658     hs_add_object_to_json_object_func(res, __FUNCTION__, 2, _error, 0);
659     json_object_object_add(res, _keyData, j_runnable);
660     afb_req_success_f(request, res, "homescreen binder unsubscribe success.");
661 }
662
663 /**
664  * registerShortcut event
665  *
666  * #### Parameters
667  *  - value  : the json contents to MenuBar.
668  *    {"application_id":"homescreen","parameter":{"shortcut_id":"dashboard@0.1","shortcut_name":"Dashboard","postion": 1}}
669  *
670  * #### Return
671  * None
672  *
673  */
674 static void registerShortcut(afb_req_t request)
675 {
676     int ret = 0;
677     const char* value = afb_req_value(request, _application_id);
678     if (value) {
679         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
680     }
681     else {
682         ret = AFB_EVENT_BAD_REQUEST;
683     }
684
685     if (ret) {
686         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
687     }
688     else {
689         struct json_object *res = json_object_new_object();
690         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
691           _error,  ret);
692         afb_req_success(request, res, "afb_event_push event [registerShortcut]");
693     }
694 }
695
696 /**
697  * updateShortcut event
698  *
699  * #### Parameters
700  *  - value  : homescreen shortcut json contents.
701  *    {"application_id":"launcher","parameter":{"shortcut":[{"shortcut_id":"hvac","shortcut_name":"HVAC"},...]}}
702  *
703  * #### Return
704  * None
705  *
706  */
707 static void updateShortcut(afb_req_t request)
708 {
709     int ret = 0;
710     const char* value = afb_req_value(request, _application_id);
711     if (value) {
712         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
713     }
714     else {
715         ret = AFB_EVENT_BAD_REQUEST;
716     }
717
718     if (ret) {
719         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
720     }
721     else {
722         struct json_object *res = json_object_new_object();
723         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
724           _error,  ret);
725         afb_req_success(request, res, "afb_event_push event [updateShortcut]");
726     }
727 }
728
729 /*
730  * array of the verbs exported to afb-daemon
731  */
732 static const afb_verb_t verbs[]= {
733     /* VERB'S NAME                 FUNCTION TO CALL                  */
734     { .verb="ping",              .callback=pingSample             },
735     { .verb="tap_shortcut",      .callback=tap_shortcut           },
736     { .verb="showWindow",        .callback=showWindow             },
737     { .verb="hideWindow",        .callback=hideWindow             },
738     { .verb="replyShowWindow",   .callback=replyShowWindow        },
739     { .verb="on_screen_message", .callback=on_screen_message      },
740     { .verb="on_screen_reply",   .callback=on_screen_reply        },
741     { .verb="subscribe",         .callback=subscribe              },
742     { .verb="unsubscribe",       .callback=unsubscribe            },
743     { .verb="showNotification",  .callback=showNotification       },
744     { .verb="showInformation",   .callback=showInformation        },
745     { .verb="getRunnables",      .callback=getRunnables           },
746     { .verb="registerShortcut",  .callback=registerShortcut       },
747     { .verb="updateShortcut",    .callback=updateShortcut         },
748     {NULL } /* marker for end of the array */
749 };
750
751 /**
752  * homescreen binding preinit function
753  *
754  * #### Parameters
755  *  - api : the api serving the request
756  *
757  * #### Return
758  * None
759  *
760  */
761 static int preinit(afb_api_t api)
762 {
763     AFB_DEBUG("binding preinit (was register)");
764     return 0;
765 }
766
767 /**
768  * homescreen binding init function
769  *
770  * #### Parameters
771  *  - api : the api serving the request
772  *
773  * #### Return
774  * None
775  *
776  */
777 static int init(afb_api_t api)
778 {
779     AFB_DEBUG("binding init");
780
781     if(g_hs_instance != nullptr) {
782         AFB_WARNING( "g_hs_instance isn't null.");
783         delete g_hs_instance->client_manager;
784         delete g_hs_instance->app_info;
785         delete g_hs_instance->app_recover;
786         delete g_hs_instance->vui_adapter;
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( "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, object %s", event, json_object_to_json_string(object));
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 };