homescreen/hs-proxy: Guard against empty appids
[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
21 #include "homescreen.h"
22
23 const char _error[] = "error";
24 const char _application_id[] = "application_id";
25 const char _display_message[] = "display_message";
26 const char _reply_message[] = "reply_message";
27 const char _keyData[] = "data";
28 const char _keyId[] = "id";
29
30 /**
31  * init function
32  *
33  * #### Parameters
34  * - api : the api serving the request
35  *
36  * #### Return
37  * 0 : init success
38  * 1 : init fail
39  *
40  */
41 int hs_instance::init(afb_api_t api)
42 {
43     if(client_manager == nullptr) {
44         AFB_ERROR("client_manager is nullptr.");
45         return -1;
46     }
47     client_manager->init();
48
49     if(app_info == nullptr) {
50         AFB_ERROR("app_info is nullptr.");
51         return -1;
52     }
53     app_info->init(api);
54
55     return 0;
56 }
57
58 /**
59  * set event hook
60  *
61  * #### Parameters
62  *  - event  : event name
63  *  - f : hook function
64  *
65  * #### Return
66  * Nothing
67  */
68 void hs_instance::setEventHook(const char *event, const event_hook_func f)
69 {
70     if(event == nullptr || f == nullptr) {
71         AFB_WARNING("argument is null.");
72         return;
73     }
74
75     std::string ev(event);
76     auto it = event_hook_list.find(ev);
77     if(it != event_hook_list.end()) {
78         it->second.push_back(f);
79     }
80     else {
81         std::list<event_hook_func> l;
82         l.push_back(f);
83         event_hook_list[ev] = std::move(l);
84     }
85 }
86
87 /**
88  * onEvent function
89  *
90  * #### Parameters
91  *  - api : the api serving the request
92  *  - event  : event name
93  *  - object : event json object
94  *
95  * #### Return
96  * Nothing
97  */
98 void hs_instance::onEvent(afb_api_t api, const char *event, struct json_object *object)
99 {
100     std::string ev(event);
101     auto it = event_hook_list.find(ev);
102     if(it != event_hook_list.end()) {
103         for(auto &ref : it->second) {
104             if(ref(api, event, object))
105                 break;
106         }
107     }
108 }
109
110 static struct hs_instance *g_hs_instance;
111
112 /**
113  * set event hook
114  *
115  * #### Parameters
116  *  - event  : event name
117  *  - f : hook function pointer
118  *
119  * #### Return
120  * Nothing
121  */
122 void setEventHook(const char *event, const event_hook_func f)
123 {
124     if(g_hs_instance == nullptr) {
125         AFB_ERROR("g_hs_instance is null.");
126         return;
127     }
128
129     g_hs_instance->setEventHook(event, f);
130 }
131
132 /*
133 ********** Method of HomeScreen Service (API) **********
134 */
135
136 static void pingSample(afb_req_t request)
137 {
138    static int pingcount = 0;
139    afb_req_success_f(request, json_object_new_int(pingcount), "Ping count = %d", pingcount);
140    AFB_DEBUG("Verbosity macro at level notice invoked at ping invocation count = %d", pingcount);
141    pingcount++;
142 }
143
144 /**
145  * tap_shortcut notify for homescreen
146  * When Shortcut area is tapped,  notify these applciations
147  *
148  * #### Parameters
149  * Request key
150  * - application_id   : application id
151  *
152  * #### Return
153  * None
154  *
155  */
156 static void tap_shortcut (afb_req_t request)
157 {
158     int ret = 0;
159     const char* value = afb_req_value(request, _application_id);
160     if (value) {
161         AFB_INFO("request appid = %s.", value);
162         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
163         if(ret == AFB_REQ_NOT_STARTED_APPLICATION) {
164             std::string id = g_hs_instance->app_info->getAppProperty(value, _keyId);
165             if (!id.empty()) {
166                     HS_AfmMainProxy afm_proxy;
167                     afm_proxy.start(g_hs_instance, request, id);
168                     ret = 0;
169             } else {
170                     ret = AFB_EVENT_BAD_REQUEST;
171             }
172         }
173     }
174     else {
175         ret = AFB_EVENT_BAD_REQUEST;
176     }
177
178     if (ret) {
179         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
180     }
181     else {
182         struct json_object *res = json_object_new_object();
183         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
184           _error,  ret);
185         afb_req_success(request, res, "afb_event_push event [tap_shortcut]");
186     }
187 }
188
189 /**
190  * HomeScreen OnScreen message
191  *
192  * #### Parameters
193  * Request key
194  * - display_message   : message for display
195  *
196  * #### Return
197  * None
198  *
199  */
200 static void on_screen_message (afb_req_t request)
201 {
202     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__);
203     if (ret) {
204         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
205     }
206     else {
207         struct json_object *res = json_object_new_object();
208         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
209           _error,  ret);
210         afb_req_success(request, res, "afb_event_push event [on_screen_message]");
211     }
212 }
213
214 /**
215  * HomeScreen OnScreen Reply
216  *
217  * #### Parameters
218  * Request key
219  * - reply_message   : message for reply
220  *
221  * #### Return
222  * None
223  *
224  */
225 static void on_screen_reply (afb_req_t request)
226 {
227     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__);
228     if (ret) {
229         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
230     }
231     else {
232         struct json_object *res = json_object_new_object();
233         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
234           _error,  ret);
235         afb_req_success(request, res, "afb_event_push event [on_screen_reply]");
236     }
237 }
238
239 /**
240  * Subscribe event
241  *
242  * #### Parameters
243  *  - event  : Event name. Event list is written in libhomescreen.cpp
244  *
245  * #### Return
246  * None
247  *
248  */
249 static void subscribe(afb_req_t request)
250 {
251     int ret = 0;
252     std::string req_appid = std::move(get_application_id(request));
253     if(!req_appid.empty()) {
254         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str());
255     }
256     else {
257         ret = AFB_EVENT_BAD_REQUEST;
258     }
259
260     if(ret) {
261         afb_req_fail_f(request, "afb_req_subscribe failed", "called %s.", __FUNCTION__);
262     }
263     else {
264         struct json_object *res = json_object_new_object();
265         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
266             _error, ret);
267         afb_req_success_f(request, res, "homescreen binder subscribe.");
268     }
269 }
270
271 /**
272  * Unsubscribe event
273  *
274  * #### Parameters
275  *  - event  : Event name. Event list is written in libhomescreen.cpp
276  *
277  * #### Return
278  * None
279  *
280  */
281 static void unsubscribe(afb_req_t request)
282 {
283     int ret = 0;
284     std::string req_appid = std::move(get_application_id(request));
285     if(!req_appid.empty()) {
286         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str());
287     }
288     else {
289         ret = AFB_EVENT_BAD_REQUEST;
290     }
291
292     if(ret) {
293         afb_req_fail_f(request, "afb_req_unsubscribe failed", "called %s.", __FUNCTION__);
294     }
295     else {
296         struct json_object *res = json_object_new_object();
297         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
298             _error, ret);
299         afb_req_success_f(request, res, "homescreen binder unsubscribe success.");
300     }
301 }
302
303 /**
304  * showWindow event
305  *
306  * #### Parameters
307  *  - request : the request
308  *
309  * #### Return
310  * None
311  *
312  */
313 static void showWindow(afb_req_t request)
314 {
315     int ret = 0;
316     const char* value = afb_req_value(request, _application_id);
317     if (value) {
318         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
319         if(ret == AFB_REQ_NOT_STARTED_APPLICATION) {
320             std::string id = g_hs_instance->app_info->getAppProperty(value, _keyId);
321             if (!id.empty()) {
322                     HS_AfmMainProxy afm_proxy;
323                     afm_proxy.start(g_hs_instance, request, id);
324                     ret = 0;
325             } else {
326                     ret = AFB_EVENT_BAD_REQUEST;
327             }
328         }
329     }
330     else {
331         ret = AFB_EVENT_BAD_REQUEST;
332     }
333
334     if (ret) {
335         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
336     }
337     else {
338         struct json_object *res = json_object_new_object();
339         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
340           _error,  ret);
341         afb_req_success(request, res, "afb_event_push event [showWindow]");
342     }
343 }
344
345 /**
346  * hideWindow event
347  *
348  * #### Parameters
349  *  - request : the request
350  *
351  * #### Return
352  * None
353  *
354  */
355 static void hideWindow(afb_req_t request)
356 {
357     int ret = 0;
358     const char* value = afb_req_value(request, _application_id);
359     if (value) {
360         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
361     }
362     else {
363         ret = AFB_EVENT_BAD_REQUEST;
364     }
365
366     if (ret) {
367         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
368     }
369     else {
370         struct json_object *res = json_object_new_object();
371         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
372           _error,  ret);
373         afb_req_success(request, res, "afb_event_push event [hideWindow]");
374     }
375 }
376
377 /**
378  * replyShowWindow event
379  *
380  * #### Parameters
381  *  - request : the request
382  *
383  * #### Return
384  *  None
385  *
386  */
387 static void replyShowWindow(afb_req_t request)
388 {
389     int ret = 0;
390     const char* value = afb_req_value(request, _application_id);
391     if (value) {
392         ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value);
393     }
394     else {
395         ret = AFB_EVENT_BAD_REQUEST;
396     }
397
398     if (ret) {
399         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
400     }
401     else {
402         struct json_object *res = json_object_new_object();
403         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
404           _error,  ret);
405         afb_req_success(request, res, "afb_event_push event [replyShowWindow]");
406     }
407 }
408
409 /**
410  * showNotification event
411  *
412  * the contents to homescreen which display at top area.
413  *
414  * #### Parameters
415  *  - request : the request
416  *
417  * #### Return
418  * None
419  *
420  */
421 static void showNotification(afb_req_t request)
422 {
423     int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, "homescreen");
424     if (ret) {
425         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
426     }
427     else {
428         struct json_object *res = json_object_new_object();
429         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
430           _error,  ret);
431         afb_req_success(request, res, "afb_event_push event [showNotification]");
432     }
433 }
434
435 /**
436  * showInformation event
437  *
438  * the contents to homescreen which display at bottom area.
439  *
440  * #### Parameters
441  *  - request : the request
442  *
443  * #### Return
444  * None
445  *
446  */
447 static void showInformation(afb_req_t request)
448 {
449     int ret = g_hs_instance->client_manager->handleRequest(request,  __FUNCTION__, "homescreen");
450     if (ret) {
451         afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__);
452     }
453     else {
454         struct json_object *res = json_object_new_object();
455         hs_add_object_to_json_object_func(res, __FUNCTION__, 2,
456           _error,  ret);
457         afb_req_success(request, res, "afb_event_push event [showInformation]");
458     }
459 }
460
461 /**
462  * get runnables list
463  *
464  * #### Parameters
465  *  - request : the request
466  *
467  * #### Return
468  * None
469  *
470  */
471 static void getRunnables(afb_req_t request)
472 {
473     struct json_object* j_runnable = json_object_new_array();
474     g_hs_instance->app_info->getRunnables(&j_runnable);
475
476     /*create response json object*/
477     struct json_object *res = json_object_new_object();
478     hs_add_object_to_json_object_func(res, __FUNCTION__, 2, _error, 0);
479     json_object_object_add(res, _keyData, j_runnable);
480     afb_req_success_f(request, res, "homescreen binder unsubscribe success.");
481 }
482
483 /*
484  * array of the verbs exported to afb-daemon
485  */
486 static const afb_verb_t verbs[]= {
487     /* VERB'S NAME                 FUNCTION TO CALL                  */
488     { .verb="ping",              .callback=pingSample             },
489     { .verb="tap_shortcut",      .callback=tap_shortcut           },
490     { .verb="showWindow",        .callback=showWindow             },
491     { .verb="hideWindow",        .callback=hideWindow             },
492     { .verb="replyShowWindow",   .callback=replyShowWindow        },
493     { .verb="on_screen_message", .callback=on_screen_message      },
494     { .verb="on_screen_reply",   .callback=on_screen_reply        },
495     { .verb="subscribe",         .callback=subscribe              },
496     { .verb="unsubscribe",       .callback=unsubscribe            },
497     { .verb="showNotification",  .callback=showNotification       },
498     { .verb="showInformation",   .callback=showInformation        },
499     { .verb="getRunnables",      .callback=getRunnables           },
500     {NULL } /* marker for end of the array */
501 };
502
503 /**
504  * homescreen binding preinit function
505  *
506  * #### Parameters
507  *  - api : the api serving the request
508  *
509  * #### Return
510  * None
511  *
512  */
513 static int preinit(afb_api_t api)
514 {
515    (void)  api;
516    AFB_DEBUG("binding preinit (was register)");
517    return 0;
518 }
519
520 /**
521  * homescreen binding init function
522  *
523  * #### Parameters
524  *  - api : the api serving the request
525  *
526  * #### Return
527  * None
528  *
529  */
530 static int init(afb_api_t api)
531 {
532     AFB_DEBUG("binding init");
533
534     if(g_hs_instance != nullptr) {
535         AFB_WARNING( "g_hs_instance isn't null.");
536         delete g_hs_instance->client_manager;
537         delete g_hs_instance->app_info;
538         delete g_hs_instance;
539         g_hs_instance = nullptr;
540     }
541     g_hs_instance = new hs_instance();
542     if(g_hs_instance == nullptr) {
543         return -1;
544     }
545
546     return g_hs_instance->init(api);
547 }
548
549 /**
550  * homescreen binding event function
551  *
552  * #### Parameters
553  *  - api : the api serving the request
554  *  - event  : event name
555  *  - object : event json object
556  *
557  * #### Return
558  * None
559  *
560  */
561 static void onevent(afb_api_t api, const char *event, struct json_object *object)
562 {
563     AFB_INFO("on_event %s", event);
564     g_hs_instance->onEvent(api, event, object);
565 }
566
567 const afb_binding_t afbBindingExport = {
568     .api = "homescreen",
569     .specification = NULL,
570     .info = NULL,
571     .verbs = verbs,
572     .preinit = preinit,
573     .init = init,
574     .onevent = onevent
575 };