2 * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
3 * Copyright (c) 2018,2019 TOYOTA MOTOR CORPORATION
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 #include <sys/socket.h>
31 #include <libhomescreen.hpp>
32 #include "hmi-debug.h"
36 static bool has_verb(const string& verb);
37 static const char API[] = "homescreen";
38 static const char ApplicationId[] = "application_id";
40 const std::vector<std::string> LibHomeScreen::api_list {
41 std::string("ping"), // debug do not use
42 std::string("tap_shortcut"), // HomeScreen Application only
43 std::string("on_screen_message"),
44 std::string("on_screen_reply"),
45 std::string("subscribe"),
46 std::string("unsubscribe"),
47 std::string("showWindow"),
48 std::string("hideWindow"),
49 std::string("replyShowWindow"),
50 std::string("showNotification"),
51 std::string("showInformation"),
52 std::string("getRunnables")
55 const std::vector<std::string> LibHomeScreen::event_list {
56 // std::string("tap_shortcut"),
57 std::string("showWindow"),
58 std::string("on_screen_message"),
59 std::string("on_screen_reply"),
60 std::string("hideWindow"),
61 std::string("replyShowWindow"),
62 std::string("showNotification"),
63 std::string("showInformation"),
64 std::string("application-list-changed"),
73 static void _on_hangup_static(void *closure, struct afb_wsj1 *wsj)
75 static_cast<LibHomeScreen*>(closure)->on_hangup(NULL,wsj);
78 static void _on_call_static(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
80 /* LibHomeScreen is not called from other process */
83 static void _on_event_static(void* closure, const char* event, struct afb_wsj1_msg *msg)
85 static_cast<LibHomeScreen*>(closure)->on_event(NULL,event,msg);
88 static void _on_reply_static(void *closure, struct afb_wsj1_msg *msg)
90 static_cast<LibHomeScreen*>(closure)->on_reply(NULL,msg);
94 static void event_loop_run(struct sd_event* loop){
103 LibHomeScreen::LibHomeScreen()
110 LibHomeScreen::~LibHomeScreen()
112 if(sp_websock != NULL)
114 afb_wsj1_unref(sp_websock);
118 sd_event_exit(mploop, 0);
123 * This function is initializer
126 * - hostname [in] : This argument should be specified to the hostname to be used for websocket
127 * - port [in] : This argument should be specified to the port number to be used for websocket
128 * - token [in] : This argument should be specified to the token to be used for websocket
134 * Use this constructor
137 int LibHomeScreen::init(const char *hostname, const int port, const char *token)
140 if(port < 0 || token == nullptr || token[0] == 0)
142 HMI_ERROR("libhomescreen","port and token should be > 0, Initial port and token uses.");
145 ret = initialize_websocket(hostname, port, token);
149 HMI_ERROR("libhomescreen","Failed to initialize websocket");
152 HMI_DEBUG("libhomescreen","Initialized");
159 * This function is initializer
162 * - port [in] : This argument should be specified to the port number to be used for websocket
163 * - token [in] : This argument should be specified to the token to be used for websocket
169 * Use this constructor
172 int LibHomeScreen::init(const int port, const string& token)
174 return init(nullptr, port, token.c_str());
178 * This function register callback function for reply/event message from home screen
181 * - event_cb [in] : This argument should be specified to the callback for subscribed event
182 * - reply_cb [in] : This argument should be specified to the reply callback for call function
188 * Event callback is invoked by home screen for event you subscribed.
189 * If you would like to get event, please call subscribe function before/after this function
191 void LibHomeScreen::registerCallback(
192 void (*event_cb)(const std::string& event, struct json_object* event_contents),
193 void (*reply_cb)(struct json_object* reply_contents),
194 void (*hangup_cb)(void))
198 onHangup = hangup_cb;
201 int LibHomeScreen::initialize_websocket()
207 int ret = sd_event_new(&mploop);
210 HMI_ERROR("libhomescreen","Failed to create event loop");
215 // enforce context to avoid initialization/goto error
216 std::thread th(event_loop_run, mploop);
220 /* Initialize interface from websocket */
221 minterface.on_hangup = _on_hangup_static;
222 minterface.on_call = _on_call_static;
223 minterface.on_event = _on_event_static;
225 sp_websock = afb_ws_client_connect_wsj1(mploop, muri.c_str(), &minterface, this);
226 if(sp_websock == NULL)
228 HMI_ERROR("libhomescreen","Failed to create websocket connection");
232 /* creates the evsrc */
233 //ret = sd_event_add_io(mploop,&mevent_src, sp_websock->fd, EPOLLIN, event_callback, NULL);
240 int LibHomeScreen::initialize_websocket(const char *hostname, const int port, const char *token)
242 if (hostname == nullptr)
243 hostname = "localhost";
244 muri = std::string("ws://") + hostname + ":" + to_string(port) + "/api?token=" + token; /*To be modified*/
246 return initialize_websocket();
251 * Sending ShortCut Icon tapped event
253 * When HomeScreen shortcut area is tapped, sending a event
256 * - application_id [in] : Tapped application id (label)
259 * - Returns 0 on success or -1 in case of error.
261 int LibHomeScreen::tapShortcut(const char* application_id)
263 struct json_object* obj = json_object_new_object();
264 struct json_object* val = json_object_new_string("normal");
265 json_object_object_add(obj, "area", val);
267 return showWindow(application_id, obj);
271 * Sending onScreen message event
273 * Sending OnScreen message event to HomeScreen from applications
276 * - display_message [in] : message for display
279 * - Returns 0 on success or -1 in case of error.
281 int LibHomeScreen::onScreenMessage(const char* display_message)
288 struct json_object* j_obj = json_object_new_object();
289 struct json_object* val = json_object_new_string(display_message);
290 json_object_object_add(j_obj, "display_message", val);
291 return this->call("on_screen_message", j_obj);
295 * Sending onScreen reply event
297 * Sending OnScreen reply event to applications from HomeScreen
300 * - reply_message [in] : message for reply
303 * - Returns 0 on success or -1 in case of error.
305 int LibHomeScreen::onScreenReply(const char* reply_message)
312 struct json_object* j_obj = json_object_new_object();
313 struct json_object* val = json_object_new_string(reply_message);
314 json_object_object_add(j_obj, "reply_message", val);
315 return this->call("on_screen_reply", j_obj);
319 * Setting Event Handler
321 * Setting event handler for Homescreen
324 * - et [in] : event name
325 * - f [in] : event handler
331 * Don't release json_object by json_object_put in handler_func.
332 * The resource is released by libafbwsc library.
334 void LibHomeScreen::set_event_handler(enum EventType et, handler_func f)
336 if (et > Event_Min && et < Event_Max) {
338 case Event_ShowWindow:
339 this->subscribe(LibHomeScreen::event_list[0]);
341 case Event_OnScreenMessage:
342 this->subscribe(LibHomeScreen::event_list[1]);
344 case Event_OnScreenReply:
345 this->subscribe(LibHomeScreen::event_list[2]);
347 case Event_HideWindow:
348 this->subscribe(LibHomeScreen::event_list[3]);
350 case Event_ReplyShowWindow:
351 this->subscribe(LibHomeScreen::event_list[4]);
353 case Event_ShowNotification:
354 this->subscribe(LibHomeScreen::event_list[5]);
356 case Event_ShowInformation:
357 this->subscribe(LibHomeScreen::event_list[6]);
359 case Event_AppListChanged:
360 this->subscribe(LibHomeScreen::event_list[7]);
364 this->handlers[et] = std::move(f);
369 * This function calls the API of HomeScreen via WebSocket
372 * - verb [in] : This argument should be specified to the API name (e.g. "tap_shortcut")
373 * - arg [in] : This argument should be specified to the argument of API. And this argument expects JSON object
376 * - Returns 0 on success or -1 in case of error.
379 * To call HomeScreen's APIs, the application should set its function name, arguments to JSON format.
382 int LibHomeScreen::call(const string& verb, struct json_object* arg)
391 HMI_ERROR("libhomescreen","verb doesn't exit");
394 ret = afb_wsj1_call_j(sp_websock, API, verb.c_str(), arg, _on_reply_static, this);
396 HMI_ERROR("libhomescreen","Failed to call verb:%s",verb.c_str());
402 * This function calls the API of HomeScreen via WebSocket
403 * This function is overload function of "call"
406 * - verb [in] : This argument should be specified to the API name (e.g. "tap_shortcut")
407 * - arg [in] : This argument should be specified to the argument of API. And this argument expects JSON object
410 * - Returns 0 on success or -1 in case of error.
413 * To call HomeScreen's APIs, the application should set its function name, arguments to JSON format.
416 int LibHomeScreen::call(const char* verb, struct json_object* arg)
423 if (!has_verb(string(verb)))
425 HMI_ERROR("libhomescreen","verb doesn't exit");
428 ret = afb_wsj1_call_j(sp_websock, API, verb, arg, _on_reply_static, this);
430 HMI_ERROR("libhomescreen","Failed to call verb:%s",verb);
436 * Register callback function for each event
439 * - event_name [in] : This argument should be specified to the event name
442 * - Returns 0 on success or -1 in case of error.
445 * This function enables to get an event to your callback function.
448 int LibHomeScreen::subscribe(const string& event_name)
454 struct json_object* j_obj = json_object_new_object();
455 json_object_object_add(j_obj, "event", json_object_new_string(event_name.c_str()));
457 int ret = afb_wsj1_call_j(sp_websock, API, "subscribe", j_obj, _on_reply_static, this);
459 HMI_ERROR("libhomescreen","Failed to call verb");
465 * Unregister callback function for each event
468 * - event_name [in] : This argument should be specified to the event name
471 * - Returns 0 on success or -1 in case of error.
474 * This function disables to get an event to your callback function.
477 int LibHomeScreen::unsubscribe(const string& event_name)
483 struct json_object* j_obj = json_object_new_object();
484 json_object_object_add(j_obj, "event", json_object_new_string(event_name.c_str()));
486 int ret = afb_wsj1_call_j(sp_websock, API, "unsubscribe", j_obj, _on_reply_static, this);
488 HMI_ERROR("libhomescreen","Failed to call verb");
494 * Sending show window event
496 * Call HomeScreen Service's showWindow verb to request display id's screen.
499 * - application_id [in] : This argument should be specified to the application's id.
500 * - json [in] : This argument should be specified to the json parameters.
503 * - Returns 0 on success or -1 in case of error.
506 int LibHomeScreen::showWindow(const char* application_id, json_object* json)
513 struct json_object* j_obj = json_object_new_object();
514 struct json_object* val = json_object_new_string(application_id);
515 json_object_object_add(j_obj, ApplicationId, val);
517 if (json == nullptr) {
518 struct json_object* j_json = json_object_new_object();
519 struct json_object* value = json_object_new_string("normal");
520 json_object_object_add(j_json, "area", value);
521 json_object_object_add(j_obj, "parameter", j_json);
524 json_object_object_add(j_obj, "parameter", json);
527 return this->call("showWindow", j_obj);
531 * Sending hide window event
533 * Call HomeScreen Service's hideWindow verb to release id's screen.
536 * - application_id [in] : This argument should be specified to the application's id.
539 * - Returns 0 on success or -1 in case of error.
542 int LibHomeScreen::hideWindow(const char* application_id)
549 struct json_object* j_obj = json_object_new_object();
550 struct json_object* val = json_object_new_string(application_id);
551 json_object_object_add(j_obj, ApplicationId, val);
553 return this->call("hideWindow", j_obj);
557 * Sending reply onscreen message event
559 * Call HomeScreen Service's replyShowWindow verb to reply onscreen message.
562 * - application_id [in] : This argument should be specified to the onscreen reply to applilcation id.
563 * - json [in] : This argument should be specified to the json parameters.
566 * - Returns 0 on success or -1 in case of error.
569 int LibHomeScreen::replyShowWindow(const char* application_id, json_object* json)
576 if (json == nullptr) {
577 HMI_WARNING("libhomescreen", "replyShowWindow`s parameter is null");
581 struct json_object* j_obj = json_object_new_object();
582 struct json_object* val = json_object_new_string(application_id);
583 json_object_object_add(j_obj, ApplicationId, val);
584 json_object_object_add(j_obj, "parameter", json);
586 return this->call("replyShowWindow", j_obj);
590 * Sending show notification event
592 * Call HomeScreen Service's notification verb to show notification on Status Bar.
595 * - json [in] : This argument should be specified to the json parameters.
598 * - Returns 0 on success or -1 in case of error.
601 int LibHomeScreen::showNotification(json_object* json)
608 return this->call("showNotification", json);
612 * Sending show information event
614 * Call HomeScreen Service's information verb to show notification on Information Bar.
617 * - json [in] : This argument should be specified to the json parameters.
620 * - Returns 0 on success or -1 in case of error.
623 int LibHomeScreen::showInformation(json_object* json)
630 return this->call("showInformation", json);
636 * Call HomeScreen Service's getRunnables verb to get runnalbes list.
642 * - Returns 0 on success or -1 in case of error.
645 int LibHomeScreen::getRunnables(void)
647 return this->call("getRunnables", nullptr);
651 /************* Callback Function *************/
653 void LibHomeScreen::on_hangup(void *closure, struct afb_wsj1 *wsj)
655 HMI_DEBUG("libhomescreen","called");
656 if(onHangup != nullptr)
662 void LibHomeScreen::on_call(void *closure, const char *api, const char *verb, struct afb_wsj1_msg *msg)
667 * event is like "homescreen/hvac"
668 * msg is like {"event":"homescreen\/hvac","data":{"type":"tap_shortcut"},"jtype":"afb-event"}
670 event name : struct json_object obj = json_object_object_get(msg,"event")
672 void LibHomeScreen::on_event(void *closure, const char *event, struct afb_wsj1_msg *msg)
674 HMI_DEBUG("libhomescreen","event: (%s) msg: (%s).", event, afb_wsj1_msg_object_s(msg));
676 if (strstr(event, API) == NULL) {
680 struct json_object* ev_contents = afb_wsj1_msg_object_j(msg);
681 struct json_object *json_data;
682 if(!json_object_object_get_ex(ev_contents, "data", &json_data)) {
683 HMI_ERROR("libhomescreen", "got ev_contents error.");
687 if(onEvent != nullptr)
689 const string ev(event);
690 onEvent(ev, ev_contents);
693 const char* event_type = nullptr;
694 struct json_object *json_event_type;
695 if(json_object_object_get_ex(json_data, "type", &json_event_type)) {
696 event_type = json_object_get_string(json_event_type);
699 HMI_WARNING("libhomescreen","event_type is null.");
703 if (strcasecmp(event_type, LibHomeScreen::event_list[0].c_str()) == 0) {
704 auto i = this->handlers.find(Event_ShowWindow);
705 if ( i != this->handlers.end() ) {
706 i->second(json_data);
709 else if (strcasecmp(event_type, LibHomeScreen::event_list[1].c_str()) == 0) {
710 auto i = this->handlers.find(Event_OnScreenMessage);
711 if ( i != this->handlers.end() ) {
712 i->second(json_data);
715 else if (strcasecmp(event_type, LibHomeScreen::event_list[2].c_str()) == 0) {
716 auto i = this->handlers.find(Event_OnScreenReply);
717 if ( i != this->handlers.end() ) {
718 i->second(json_data);
721 else if (strcasecmp(event_type, LibHomeScreen::event_list[3].c_str()) == 0) {
722 auto i = this->handlers.find(Event_HideWindow);
723 if ( i != this->handlers.end() ) {
724 i->second(json_data);
727 else if (strcasecmp(event_type, LibHomeScreen::event_list[4].c_str()) == 0) {
728 auto i = this->handlers.find(Event_ReplyShowWindow);
729 if ( i != this->handlers.end() ) {
730 i->second(json_data);
733 else if (strcasecmp(event_type, LibHomeScreen::event_list[5].c_str()) == 0) {
734 auto i = this->handlers.find(Event_ShowNotification);
735 if ( i != this->handlers.end() ) {
736 i->second(json_data);
739 else if (strcasecmp(event_type, LibHomeScreen::event_list[6].c_str()) == 0) {
740 auto i = this->handlers.find(Event_ShowInformation);
741 if ( i != this->handlers.end() ) {
742 i->second(json_data);
745 else if (strcasecmp(event_type, LibHomeScreen::event_list[7].c_str()) == 0) {
746 auto i = this->handlers.find(Event_AppListChanged);
747 if ( i != this->handlers.end() ) {
748 i->second(json_data);
754 * msg is like ({"response":{"verb":"subscribe","error":0},"jtype":"afb-reply","request":{"status":"success","info":"homescreen binder subscribe event name [on_screen_message]"}})
755 * msg is like ({"response":{"verb":"tap_shortcut","error":0},"jtype":"afb-reply","request":{"status":"success","info":"afb_event_push event [tap_shortcut]"}})
757 void LibHomeScreen::on_reply(void *closure, struct afb_wsj1_msg *msg)
759 HMI_DEBUG("libhomescreen","msg: (%s)", afb_wsj1_msg_object_s(msg));
760 if(onReply != nullptr)
762 struct json_object* reply = afb_wsj1_msg_object_j(msg);
767 static bool has_verb(const string& verb)
769 HMI_DEBUG("libhomescreen","verb is %s", verb.c_str());
770 if(find(LibHomeScreen::api_list.begin(), LibHomeScreen::api_list.end(), verb) != LibHomeScreen::api_list.end())