From ea459cc8988c3e664c3f9d56d3a9929775d8b57b Mon Sep 17 00:00:00 2001 From: wang_zhiqiang Date: Tue, 9 Oct 2018 10:31:06 +0800 Subject: [PATCH] emit event to one application changed agl-service-homescreen and libhomescreen to make agl-service-homescreen emit event to one application only. BUG-AGL: SPEC-1764 Change-Id: I87e4fc8fe900fdf9d7fde04852077c7174b8a3ba Signed-off-by: wang_zhiqiang --- src/CMakeLists.txt | 4 +- src/homescreen.cpp | 101 +++++++++++----------- src/hs-client.cpp | 180 ++++++++++++++++++++++++++++++++++++++ src/hs-client.h | 49 +++++++++++ src/hs-clientmanager.cpp | 219 +++++++++++++++++++++++++++++++++++++++++++++++ src/hs-clientmanager.h | 66 ++++++++++++++ src/hs-helper.h | 4 + 7 files changed, 572 insertions(+), 51 deletions(-) create mode 100644 src/hs-client.cpp create mode 100644 src/hs-client.h create mode 100644 src/hs-clientmanager.cpp create mode 100644 src/hs-clientmanager.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dbd7fbe..bf8b33f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,7 +24,9 @@ FIND_PACKAGE(Threads) pkg_check_modules(hs_binding_depends afb-daemon glib-2.0 gio-2.0 gio-unix-2.0 json-c) set(binding_hs_sources homescreen.cpp - hs-helper.cpp) + hs-helper.cpp + hs-clientmanager.cpp + hs-client.cpp) link_libraries(-Wl,--as-needed -Wl,--gc-sections -Wl,--no-undefined) include_directories(${PROJECT_SOURCE_DIR}/include) diff --git a/src/homescreen.cpp b/src/homescreen.cpp index 744535b..a3039c5 100644 --- a/src/homescreen.cpp +++ b/src/homescreen.cpp @@ -17,24 +17,20 @@ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif +#include +#include #include "hs-helper.h" #include "hmi-debug.h" +#include "hs-clientmanager.h" -#define COMMAND_EVENT_NUM 4 #define EVENT_SUBSCRIBE_ERROR_CODE 100 -/* To Do hash table is better */ -struct event{ - const char* name; - struct afb_event event; -}; - -static struct event event_list[COMMAND_EVENT_NUM]; +const char _error[] = "error"; +const char _application_name[] = "application_name"; +const char _display_message[] = "display_message"; +const char _reply_message[] = "reply_message"; -static const char _error[] = "error"; -static const char _application_name[] = "application_name"; -static const char _display_message[] = "display_message"; -static const char _reply_message[] = "reply_message"; +static HS_ClientManager* g_client_manager = HS_ClientManager::instance(); /* ********** Method of HomeScreen Service (API) ********** @@ -67,13 +63,20 @@ static void tap_shortcut (struct afb_req request) int ret = 0; const char* value = afb_req_value(request, _application_name); if (value) { - HMI_NOTICE("homescreen-service","request params = %s.", value); - - struct json_object* push_obj = json_object_new_object(); - hs_add_object_to_json_object_str( push_obj, 2, - _application_name, value); - afb_event_push(event_list[hs_search_event_name_index(__FUNCTION__)].event, push_obj); + // first step get appid from appname, next step change appname to appid + std::string appid(value); + std::transform(appid.begin(), appid.end(), appid.begin(), ::tolower); + HS_Client* client = g_client_manager->find(appid); + if(client != nullptr) { + if(client->tap_shortcut(value) != 0) { + afb_req_fail_f(request, "afb_event_push failed", "called %s.", __FUNCTION__); + return; + } + } + else { + // app is not started, do nothing + } } else { afb_req_fail_f(request, "failed", "called %s, Unknown palameter", __FUNCTION__); return; @@ -106,11 +109,12 @@ static void on_screen_message (struct afb_req request) if (value) { HMI_NOTICE("homescreen-service","request params = %s.", value); - - struct json_object* push_obj = json_object_new_object(); - hs_add_object_to_json_object_str( push_obj, 2, - _display_message, value); - afb_event_push(event_list[hs_search_event_name_index(__FUNCTION__)].event, push_obj); + for(auto m : g_client_manager->getAllClient()) { + if(m->on_screen_message(request, value) != 0) { + afb_req_fail_f(request, "afb_event_push failed", "called %s.", __FUNCTION__); + return; + } + } } else { afb_req_fail_f(request, "failed", "called %s, Unknown palameter", __FUNCTION__); return; @@ -143,11 +147,12 @@ static void on_screen_reply (struct afb_req request) if (value) { HMI_NOTICE("homescreen-service","request params = %s.", value); - - struct json_object* push_obj = json_object_new_object(); - hs_add_object_to_json_object_str( push_obj, 2, - _reply_message, value); - afb_event_push(event_list[hs_search_event_name_index(__FUNCTION__)].event, push_obj); + for(auto m : g_client_manager->getAllClient()) { + if(m->on_screen_reply(request, value) != 0) { + afb_req_fail_f(request, "afb_event_push failed", "called %s.", __FUNCTION__); + return; + } + } } else { afb_req_fail_f(request, "failed", "called %s, Unknown palameter", __FUNCTION__); return; @@ -176,18 +181,14 @@ static void subscribe(struct afb_req request) HMI_NOTICE("homescreen-service","value is %s", value); int ret = 0; if(value) { - int index = hs_search_event_name_index(value); - if(index < 0) - { - HMI_NOTICE("homescreen-service","dedicated event doesn't exist"); - ret = EVENT_SUBSCRIBE_ERROR_CODE; - } - else - { - afb_req_subscribe(request, event_list[index].event); + std::string appid(afb_req_get_application_id(request)); + std::transform(appid.begin(), appid.end(), appid.begin(), ::tolower); + if(g_client_manager->getClient(request, appid)->subscribe(request, value) != 0) { + afb_req_fail_f(request, "afb_req_subscribe failed", "called %s.", __FUNCTION__); + return; } } - else{ + else { HMI_NOTICE("homescreen-service","Please input event name"); ret = EVENT_SUBSCRIBE_ERROR_CODE; } @@ -214,15 +215,18 @@ static void unsubscribe(struct afb_req request) HMI_NOTICE("homescreen-service","value is %s", value); int ret = 0; if(value) { - int index = hs_search_event_name_index(value); - if(index < 0) - { - HMI_NOTICE("homescreen-service","dedicated event doesn't exist"); - ret = EVENT_SUBSCRIBE_ERROR_CODE; + std::string appid(afb_req_get_application_id(request)); + std::transform(appid.begin(), appid.end(), appid.begin(), ::tolower); + HS_Client* client = g_client_manager->find(appid); + if(client != nullptr) { + if(client->unsubscribe(request, value) != 0) { + afb_req_fail_f(request, "afb_req_unsubscribe failed", "called %s.", __FUNCTION__); + return; + } } - else - { - afb_req_unsubscribe(request, event_list[index].event); + else { + HMI_NOTICE("homescreen-service","not find app's client, unsubscribe failed"); + ret = EVENT_SUBSCRIBE_ERROR_CODE; } } else{ @@ -280,10 +284,7 @@ static int init() { HMI_NOTICE("homescreen-service","binding init"); - for(int i = 0; i < COMMAND_EVENT_NUM; ++i) { - event_list[i].name = evlist[i]; - event_list[i].event = afb_daemon_make_event(evlist[i]); - } + g_client_manager->init(); return 0; } diff --git a/src/hs-client.cpp b/src/hs-client.cpp new file mode 100644 index 0000000..807b068 --- /dev/null +++ b/src/hs-client.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2018 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hs-client.h" +#include "hs-helper.h" +#include "hmi-debug.h" + +static const char _type[] = "type"; + +/** + * HS_Client construction function + * + * #### Parameters + * - id: app's id + * + * #### Return + * None + * + */ +HS_Client::HS_Client(struct afb_req request, std::string id) : my_id(id) +{ + HMI_NOTICE("homescreen-service","called."); + my_event = afb_daemon_make_event(id.c_str()); +} + +/** + * HS_Client destruction function + * + * #### Parameters + * - null + * + * #### Return + * None + * + */ +HS_Client::~HS_Client() +{ + HMI_NOTICE("homescreen-service","called."); + afb_event_unref(my_event); +} + +/** + * push tap_shortcut event + * + * #### Parameters + * - appname: app's name. + * + * #### Return + * result + * + */ +int HS_Client::tap_shortcut(const char* appname) +{ + if(!checkEvent(__FUNCTION__)) + return 0; + + HMI_NOTICE("homescreen-service","%s application_name = %s.", __FUNCTION__, appname); + struct json_object* push_obj = json_object_new_object(); + hs_add_object_to_json_object_str( push_obj, 4, _application_name, appname, + _type, __FUNCTION__); + return afb_event_push(my_event, push_obj); +} + +/** + * push on_screen_message event + * + * #### Parameters + * - message: post message. + * + * #### Return + * result + * + */ +int HS_Client::on_screen_message(struct afb_req request, const char* message) +{ + if(!checkEvent(__FUNCTION__)) + return 0; + + HMI_NOTICE("homescreen-service","push %s event message [%s].", __FUNCTION__, message); + struct json_object* push_obj = json_object_new_object(); + hs_add_object_to_json_object_str( push_obj, 4, _display_message, message, + _type, __FUNCTION__); + return afb_event_push(my_event, push_obj); +} + +/** + * push on_screen_reply event + * + * #### Parameters + * - message: reply message. + * + * #### Return + * result + * + */ +int HS_Client::on_screen_reply(struct afb_req request, const char* message) +{ + if(!checkEvent(__FUNCTION__)) + return 0; + + HMI_NOTICE("homescreen-service","push %s event message [%s].", __FUNCTION__, message); + struct json_object* push_obj = json_object_new_object(); + hs_add_object_to_json_object_str( push_obj, 4, _reply_message, message, + _type, __FUNCTION__); + return afb_event_push(my_event, push_obj); +} + +/** + * subscribe event + * + * #### Parameters + * - event: homescreen event, tap_shortcut etc. + * + * #### Return + * result + * + */ +int HS_Client::subscribe(struct afb_req request, const char* event) +{ + int ret = 0; + auto ip = event_list.find(std::string(event)); + if(ip == event_list.end()) { + event_list[std::string(event)] = 0; + ret = afb_req_subscribe(request, my_event); + } + return ret; +} + +/** + * unsubscribe event + * + * #### Parameters + * - event: homescreen event, tap_shortcut etc. + * + * #### Return + * result + * + */ +int HS_Client::unsubscribe(struct afb_req request, const char* event) +{ + int ret = 0; + event_list.erase(std::string(event)); + if(event_list.empty()) { + ret = afb_req_unsubscribe(request, my_event); + } + return ret; +} + +/** + * check if client subscribe event + * + * #### Parameters + * - event: homescreen event, tap_shortcut etc. + * + * #### Return + * true: found + * false: not found + * + */ +bool HS_Client::checkEvent(const char* event) +{ + auto ip = event_list.find(std::string(event)); + if(ip == event_list.end()) + return false; + else + return true; +} diff --git a/src/hs-client.h b/src/hs-client.h new file mode 100644 index 0000000..035f3c4 --- /dev/null +++ b/src/hs-client.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HOMESCREEN_CLIENT_H +#define HOMESCREEN_CLIENT_H + +#include +#include +#include "hs-helper.h" + + +class HS_Client { +public: + HS_Client(struct afb_req request, const char* id) : HS_Client(request, std::string(id)){} + HS_Client(struct afb_req request, std::string id); + HS_Client(HS_Client&) = delete; + HS_Client &operator=(HS_Client&) = delete; + ~HS_Client(); + + int tap_shortcut(const char* appname); + int on_screen_message (struct afb_req request, const char* message); + int on_screen_reply (struct afb_req request, const char* message); + int subscribe(struct afb_req request, const char* event); + int unsubscribe(struct afb_req request, const char* event); + +private: + bool checkEvent(const char* event); + +private: + std::string my_id; + struct afb_event my_event; + std::unordered_map event_list; + +}; + +#endif // HOMESCREEN_CLIENT_H \ No newline at end of file diff --git a/src/hs-clientmanager.cpp b/src/hs-clientmanager.cpp new file mode 100644 index 0000000..3dea3a6 --- /dev/null +++ b/src/hs-clientmanager.cpp @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2018 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "hs-clientmanager.h" +#include "hmi-debug.h" + +HS_ClientManager* HS_ClientManager::me = nullptr; + +static void cbRemoveClientCtxt(void *data) +{ + HS_ClientManager::instance()->removeClientCtxt(data); +} + +/** + * HS_ClientManager construction function + * + * #### Parameters + * - Nothing + * + * #### Return + * None + * + */ +HS_ClientManager::HS_ClientManager() +{ +} + +/** + * get instance + * + * #### Parameters + * - Nothing + * + * #### Return + * HS_ClientManager instance pointer + * + */ +HS_ClientManager* HS_ClientManager::instance(void) +{ + if(me == nullptr) + me = new HS_ClientManager(); + + return me; +} + +/** + * HS_ClientManager init function + * + * #### Parameters + * - Nothing + * + * #### Return + * init result + * + */ +int HS_ClientManager::init(void) +{ + HMI_NOTICE("homescreen-service","called."); + // TODO : connect to windowmanger + // get applist from appfw +} + +/** + * find HS_Client in client_list + * + * #### Parameters + * - appid: app's id + * + * #### Return + * found HS_Client pointer + * + */ +HS_Client* HS_ClientManager::find(std::string appid) +{ + std::lock_guard lock(this->mtx); + HS_Client* p = nullptr; + auto ip = client_list.find(appid); + if(ip != client_list.end()) { + p = client_list[appid]; + } + return p; +} + +/** + * get HS_Client + * + * #### Parameters + * - appid: app's id + * + * #### Return + * found HS_Client pointer + * + */ +HS_Client* HS_ClientManager::getClient(afb_req req, std::string appid) +{ + std::lock_guard lock(this->mtx); + HS_Client* p = nullptr; + auto ip = client_list.find(appid); + if(ip != client_list.end()) { + p = client_list[appid]; + } + else { + appid2ctxt[appid] = createClientCtxt(req, appid); + p = addClient(req, appid); + } + return p; +} + +/** + * get HS_Client pointers set + * + * #### Parameters + * - Nothing + * + * #### Return + * HS_Client pointers set + * + */ +std::vector HS_ClientManager::getAllClient(void) +{ + std::lock_guard lock(this->mtx); + std::vector v; + for(auto a : client_list) + v.push_back(a.second); + return v; +} + +/** + * create client's afb_req_context + * + * #### Parameters + * - appid: app's id + * + * #### Return + * HS_ClientCtxt pointer + * + */ +HS_ClientCtxt* HS_ClientManager::createClientCtxt(afb_req req, std::string appid) +{ + HS_ClientCtxt *ctxt = (HS_ClientCtxt *)afb_req_context_get(req); + if (!ctxt) + { + HMI_NOTICE("homescreen-service", "create new session for %s", appid.c_str()); + HS_ClientCtxt *ctxt = new HS_ClientCtxt(appid.c_str()); + afb_req_session_set_LOA(req, 1); + afb_req_context_set(req, ctxt, cbRemoveClientCtxt); + } + return ctxt; +} + +/** + * add Client + * + * #### Parameters + * - ctxt: app's id + * + * #### Return + * HS_Client pointer + * + */ +HS_Client* HS_ClientManager::addClient(afb_req req, std::string appid) +{ + return (client_list[appid] = new HS_Client(req, appid)); +} + +/** + * remove Client + * + * #### Parameters + * - appid: app's id + * + * #### Return + * None + * + */ +void HS_ClientManager::removeClient(std::string appid) +{ + delete client_list[appid]; + client_list.erase(appid); +} + +/** + * remove Client from list + * + * #### Parameters + * - data: HS_ClientCtxt pointer + * + * #### Return + * None + * + */ +void HS_ClientManager::removeClientCtxt(void *data) +{ + HS_ClientCtxt *ctxt = (HS_ClientCtxt *)data; + if(ctxt == nullptr) + { + HMI_ERROR("homescreen-service", "data is nullptr"); + return; + } + + HMI_NOTICE("homescreen-service", "remove app %s", ctxt->id.c_str()); + std::lock_guard lock(this->mtx); + removeClient(ctxt->id); + delete appid2ctxt[ctxt->id]; + appid2ctxt.erase(ctxt->id); +} diff --git a/src/hs-clientmanager.h b/src/hs-clientmanager.h new file mode 100644 index 0000000..cb49088 --- /dev/null +++ b/src/hs-clientmanager.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018 TOYOTA MOTOR CORPORATION + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef HOMESCREEN_CLIENTMANAGER_H +#define HOMESCREEN_CLIENTMANAGER_H + +#include +#include +#include +#include +#include +#include "hs-helper.h" +#include "hs-client.h" + +typedef struct HS_ClientCtxt +{ + std::string id; + HS_ClientCtxt(const char *appid) + { + id = appid; + } +} HS_ClientCtxt; + + +class HS_ClientManager { +public: + HS_ClientManager(); + ~HS_ClientManager() = default; + HS_ClientManager(HS_ClientManager const &) = delete; + HS_ClientManager &operator=(HS_ClientManager const &) = delete; + HS_ClientManager(HS_ClientManager &&) = delete; + HS_ClientManager &operator=(HS_ClientManager &&) = delete; + + static HS_ClientManager* instance(void); + int init(void); + HS_Client* find(std::string appid); + HS_Client* getClient(afb_req req, std::string appid); + std::vector getAllClient(void); + void removeClientCtxt(void *data); + +private: + HS_ClientCtxt* createClientCtxt(afb_req req, std::string appid); + HS_Client* addClient(afb_req req, std::string appid); + void removeClient(std::string appid); + +private: + static HS_ClientManager* me; + std::unordered_map client_list; + std::unordered_map appid2ctxt; + std::mutex mtx; +}; + +#endif // HOMESCREEN_CLIENTMANAGER_H \ No newline at end of file diff --git a/src/hs-helper.h b/src/hs-helper.h index fe74303..6aba71e 100644 --- a/src/hs-helper.h +++ b/src/hs-helper.h @@ -30,6 +30,10 @@ typedef enum REQ_ERROR }REQ_ERROR; extern const char* evlist[]; +extern const char _error[]; +extern const char _application_name[]; +extern const char _display_message[]; +extern const char _reply_message[]; REQ_ERROR get_value_uint16(const struct afb_req request, const char *source, uint16_t *out_id); REQ_ERROR get_value_int16(const struct afb_req request, const char *source, int16_t *out_id); -- 2.16.6