diff options
author | wang_zhiqiang <wang_zhiqiang@dl.cn.nexty-ele.com> | 2019-02-20 13:52:59 +0800 |
---|---|---|
committer | wang_zhiqiang <wang_zhiqiang@dl.cn.nexty-ele.com> | 2019-03-25 19:42:35 +0800 |
commit | 211769e800f3a57de55b3774de82af55d2a0160a (patch) | |
tree | 07325ab1aeacb9a0c349e1927812e8080ff8744c | |
parent | 25299ef60fa4df5f590ff364cff004e90376a4bf (diff) |
Start app and get runnables list by homescreen
1.start application in showWindow.
2.add "getRunnables" verb.
3.handle "application-list-changed" event from afm-main and add "application-list-changed" event.
Bug-AGL: SPEC-2188
Change-Id: I619b97424d20af373a945ff502a8133339916923
Signed-off-by: wang_zhiqiang <wang_zhiqiang@dl.cn.nexty-ele.com>
-rw-r--r-- | package/root/config.xml | 7 | ||||
-rw-r--r-- | src/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/homescreen.cpp | 115 | ||||
-rw-r--r-- | src/hs-appinfo.cpp | 492 | ||||
-rw-r--r-- | src/hs-appinfo.h | 89 | ||||
-rw-r--r-- | src/hs-client.cpp | 28 | ||||
-rw-r--r-- | src/hs-client.h | 1 | ||||
-rw-r--r-- | src/hs-clientmanager.cpp | 38 | ||||
-rw-r--r-- | src/hs-clientmanager.h | 1 | ||||
-rw-r--r-- | src/hs-helper.cpp | 1 | ||||
-rw-r--r-- | src/hs-helper.h | 3 | ||||
-rw-r--r-- | src/hs-proxy.cpp | 135 | ||||
-rw-r--r-- | src/hs-proxy.h | 34 |
13 files changed, 931 insertions, 17 deletions
diff --git a/package/root/config.xml b/package/root/config.xml index 6ada42b..65c5d24 100644 --- a/package/root/config.xml +++ b/package/root/config.xml @@ -10,10 +10,17 @@ <param name="urn:AGL:permission::public:hidden" value="required" /> <param name="urn:AGL:permission::system:run-by-default" value="required" /> <param name="http://tizen.org/privilege/internal/dbus" value="required" /> + <param name="urn:AGL:permission:afm:system:widget" value="required" /> + <param name="urn:AGL:permission:afm:system:runner" value="required" /> + <param name="urn:AGL:permission:afm:system:widget:start" value="required" /> </feature> <feature name="urn:AGL:widget:provided-api"> <param name="homescreen" value="ws" /> </feature> + <feature name="urn:AGL:widget:required-api"> + <param name="afm-main" value="ws" /> + <param name="windowmanager" value="ws" /> + </feature> <feature name="urn:AGL:widget:required-binding"> <param name="lib/homescreen-service.so" value="local" /> </feature> diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3687345..98dc27c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,7 +26,9 @@ set(binding_hs_sources homescreen.cpp hs-helper.cpp hs-clientmanager.cpp - hs-client.cpp) + hs-client.cpp + hs-proxy.cpp + hs-appinfo.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 e921feb..10cc9bc 100644 --- a/src/homescreen.cpp +++ b/src/homescreen.cpp @@ -22,14 +22,53 @@ #include "hs-helper.h" #include "hmi-debug.h" #include "hs-clientmanager.h" +#include "hs-appinfo.h" const char _error[] = "error"; const char _application_id[] = "application_id"; const char _display_message[] = "display_message"; const char _reply_message[] = "reply_message"; +const char _keyData[] = "data"; +const char _keyId[] = "id"; -static HS_ClientManager* g_client_manager = HS_ClientManager::instance(); +struct hs_instance { + HS_ClientManager *client_manager; // the connection session manager + HS_AppInfo *app_info; // application info + + hs_instance() : client_manager(HS_ClientManager::instance()), app_info(HS_AppInfo::instance()) {} + int init(afb_api_t api); +}; + +/** + * init function + * + * #### Parameters + * - api : the api serving the request + * + * #### Return + * 0 : init success + * 1 : init fail + * + */ +int hs_instance::init(afb_api_t api) +{ + if(client_manager == nullptr) { + HMI_ERROR("homescreen-service","FATAL ERROR: client_manager is nullptr."); + return -1; + } + client_manager->init(); + + if(app_info == nullptr) { + HMI_ERROR("homescreen-service","FATAL ERROR: app_info is nullptr."); + return -1; + } + app_info->init(api); + + return 0; +} + +static struct hs_instance *g_hs_instance; /* ********** Method of HomeScreen Service (API) ********** @@ -62,7 +101,13 @@ static void tap_shortcut (afb_req_t request) const char* value = afb_req_value(request, _application_id); if (value) { HMI_NOTICE("homescreen-service","request appid = %s.", value); - ret = g_client_manager->handleRequest(request, __FUNCTION__, value); + ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value); + if(ret == AFB_REQ_NOT_STARTED_APPLICATION) { + std::string id = g_hs_instance->app_info->getAppProperty(value, _keyId); + HS_AfmMainProxy afm_proxy; + afm_proxy.start(request, id); + ret = 0; + } } else { ret = AFB_EVENT_BAD_REQUEST; @@ -93,7 +138,7 @@ static void tap_shortcut (afb_req_t request) static void on_screen_message (afb_req_t request) { HMI_NOTICE("homescreen-service","called."); - int ret = g_client_manager->handleRequest(request, __FUNCTION__); + int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__); if (ret) { afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__); } @@ -119,7 +164,7 @@ static void on_screen_message (afb_req_t request) static void on_screen_reply (afb_req_t request) { HMI_NOTICE("homescreen-service","called."); - int ret = g_client_manager->handleRequest(request, __FUNCTION__); + int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__); if (ret) { afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__); } @@ -147,7 +192,7 @@ static void subscribe(afb_req_t request) int ret = 0; std::string req_appid = std::move(get_application_id(request)); if(!req_appid.empty()) { - ret = g_client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str()); + ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str()); } else { ret = AFB_EVENT_BAD_REQUEST; @@ -180,7 +225,7 @@ static void unsubscribe(afb_req_t request) int ret = 0; std::string req_appid = std::move(get_application_id(request)); if(!req_appid.empty()) { - ret = g_client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str()); + ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, req_appid.c_str()); } else { ret = AFB_EVENT_BAD_REQUEST; @@ -213,7 +258,13 @@ static void showWindow(afb_req_t request) int ret = 0; const char* value = afb_req_value(request, _application_id); if (value) { - ret = g_client_manager->handleRequest(request, __FUNCTION__, value); + ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value); + if(ret == AFB_REQ_NOT_STARTED_APPLICATION) { + std::string id = g_hs_instance->app_info->getAppProperty(value, _keyId); + HS_AfmMainProxy afm_proxy; + afm_proxy.start(request, id); + ret = 0; + } } else { ret = AFB_EVENT_BAD_REQUEST; @@ -246,7 +297,7 @@ static void hideWindow(afb_req_t request) int ret = 0; const char* value = afb_req_value(request, _application_id); if (value) { - ret = g_client_manager->handleRequest(request, __FUNCTION__, value); + ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value); } else { ret = AFB_EVENT_BAD_REQUEST; @@ -279,7 +330,7 @@ static void replyShowWindow(afb_req_t request) int ret = 0; const char* value = afb_req_value(request, _application_id); if (value) { - ret = g_client_manager->handleRequest(request, __FUNCTION__, value); + ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, value); } else { ret = AFB_EVENT_BAD_REQUEST; @@ -311,7 +362,7 @@ static void replyShowWindow(afb_req_t request) static void showNotification(afb_req_t request) { HMI_NOTICE("homescreen-service","called."); - int ret = g_client_manager->handleRequest(request, __FUNCTION__, "homescreen"); + int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, "homescreen"); if (ret) { afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__); } @@ -338,7 +389,7 @@ static void showNotification(afb_req_t request) static void showInformation(afb_req_t request) { HMI_NOTICE("homescreen-service","called."); - int ret = g_client_manager->handleRequest(request, __FUNCTION__, "homescreen"); + int ret = g_hs_instance->client_manager->handleRequest(request, __FUNCTION__, "homescreen"); if (ret) { afb_req_fail_f(request, "failed", "called %s, Unknown parameter", __FUNCTION__); } @@ -350,6 +401,29 @@ static void showInformation(afb_req_t request) } } +/** + * get runnables list + * + * #### Parameters + * - request : the request + * + * #### Return + * None + * + */ +static void getRunnables(afb_req_t request) +{ + HMI_NOTICE("homescreen-service","called."); + struct json_object* j_runnable = json_object_new_array(); + g_hs_instance->app_info->getRunnables(&j_runnable); + + /*create response json object*/ + struct json_object *res = json_object_new_object(); + hs_add_object_to_json_object_func(res, __FUNCTION__, 2, _error, 0); + json_object_object_add(res, _keyData, j_runnable); + afb_req_success_f(request, res, "homescreen binder unsubscribe success."); +} + /* * array of the verbs exported to afb-daemon */ @@ -366,6 +440,7 @@ static const afb_verb_t verbs[]= { { .verb="unsubscribe", .callback=unsubscribe }, { .verb="showNotification", .callback=showNotification }, { .verb="showInformation", .callback=showInformation }, + { .verb="getRunnables", .callback=getRunnables }, {NULL } /* marker for end of the array */ }; @@ -399,9 +474,20 @@ static int init(afb_api_t api) { HMI_NOTICE("homescreen-service","binding init"); - g_client_manager->init(); + if(g_hs_instance != nullptr) { + HMI_WARNING("homescreen-service", "g_hs_instance isn't null."); + delete g_hs_instance->client_manager; + delete g_hs_instance->app_info; + delete g_hs_instance; + g_hs_instance = nullptr; + } + g_hs_instance = new hs_instance(); + if(g_hs_instance == nullptr) { + HMI_ERROR("homescreen-service", "Fatal Error: new g_hs_instance failed."); + return -1; + } - return 0; + return g_hs_instance->init(api); } /** @@ -418,7 +504,8 @@ static int init(afb_api_t api) */ static void onevent(afb_api_t api, const char *event, struct json_object *object) { - HMI_NOTICE("homescreen-service","on_event %s", event); + HMI_NOTICE("homescreen-service","on_event %s", event); + g_hs_instance->app_info->onEvent(api, event, object); } const afb_binding_t afbBindingExport = { diff --git a/src/hs-appinfo.cpp b/src/hs-appinfo.cpp new file mode 100644 index 0000000..e1c1990 --- /dev/null +++ b/src/hs-appinfo.cpp @@ -0,0 +1,492 @@ +/* + * Copyright (c) 2019 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 <unistd.h> +#include "hs-appinfo.h" +#include "hmi-debug.h" +#include "hs-clientmanager.h" + +#define RETRY_CNT 10 + +const char _keyName[] = "name"; +const char _keyVersion[] = "version"; +const char _keyInstall[] = "install"; +const char _keyUninstall[] = "uninstall"; +const char _keyOperation[] = "operation"; +const char _keyRunnables[] = "runnables"; +const char _keyStart[] = "start"; +const char _keyApplistChanged[] = "application-list-changed"; + +HS_AppInfo* HS_AppInfo::me = nullptr; + +/** + * get application property function + * + * #### Parameters + * - key : retrieve keyword + * + * #### Return + * retrieved property + * + */ +std::string AppDetail::getProperty(std::string key) const +{ + struct json_object *j_obj; + struct json_object *j_detail = json_tokener_parse(this->detail.c_str()); + if(json_object_object_get_ex(j_detail, key.c_str(), &j_obj) == 0) { + HMI_ERROR("homescreen-service","can't find key=%s.", key.c_str()); + return std::string(); + } + return std::string(json_object_get_string(j_obj)); +} + +/** + * HS_AppInfo destruction function + * + * #### Parameters + * - Nothing + * + * #### Return + * None + * + */ +HS_AppInfo::~HS_AppInfo() +{ + if(afmmain) + delete afmmain; +} + +/** + * get instance + * + * #### Parameters + * - Nothing + * + * #### Return + * HS_AppInfo instance pointer + * + */ +HS_AppInfo* HS_AppInfo::instance(void) +{ + if(me == nullptr) + me = new HS_AppInfo(); + + return me; +} + +/** + * HS_AppInfo initialize function + * + * #### Parameters + * - api : the api serving the request + * + * #### Return + * 0 : init success + * 1 : init fail + * + */ +int HS_AppInfo::init(afb_api_t api) +{ + afmmain = new HS_AfmMainProxy(); + if(afmmain == nullptr) { + HMI_ERROR("homescreen-service","Fatal Error:new HS_AfmMainProxy failed"); + return -1; + } + + struct json_object* j_runnable = nullptr; + int retry = 0; + do { + if(afmmain->runnables(api, &j_runnable) == 0) { + createAppDetailList(j_runnable); + json_object_put(j_runnable); + break; + } + + ++retry; + if(retry == RETRY_CNT) { + HMI_ERROR("homescreen-service","get runnables list failed"); + json_object_put(j_runnable); + return -1; + } + HMI_NOTICE("homescreen-service","retry to get runnables list %d", retry); + usleep(100000); // 100ms + } while(1); + + return 0; +} + +/** + * onEvent function + * + * #### Parameters + * - api : the api serving the request + * - event : event name + * - object : event json object + * + * #### Return + * None + * + */ +void HS_AppInfo::onEvent(afb_api_t api, const char *event, struct json_object *object) +{ + auto ip = concerned_event_list.find(std::string(event)); + if(ip != concerned_event_list.end()) { + HMI_NOTICE("homescreen-service","[%s] event received.", event); + (this->*(ip->second))(api, object); + } +} + +/** + * create application detail list function + * + * #### Parameters + * - object : the detail of all applications + * + * #### Return + * None + * + */ +void HS_AppInfo::createAppDetailList(struct json_object *object) +{ + HMI_NOTICE("homescreen-service","applist:%s", json_object_to_json_string(object)); + + if(json_object_get_type(object) == json_type_array) { + int array_len = json_object_array_length(object); + for (int i = 0; i < array_len; ++i) { + struct json_object *obj = json_object_array_get_idx(object, i); + addAppDetail(obj); + } + } + else { + HMI_ERROR("homescreen-service","Apps information input error."); + } +} + +/** + * update application detail function + * + * #### Parameters + * - object : the detail of all applications + * + * #### Return + * None + * + */ +void HS_AppInfo::updateAppDetailList(afb_api_t api, struct json_object *object) +{ + HMI_NOTICE("homescreen-service","update:%s", json_object_to_json_string(object)); + if(json_object_get_type(object) != json_type_object) { + HMI_ERROR("homescreen-service","input detail object error."); + return; + } + + struct json_object *obj_oper, *obj_data; + if(json_object_object_get_ex(object, _keyOperation, &obj_oper) == 0 + || json_object_object_get_ex(object, _keyData, &obj_data) == 0) { + HMI_ERROR("homescreen-service","can't find key=%s, %s.", _keyOperation, _keyData); + return; + } + + std::string id = json_object_get_string(obj_data); + std::string appid = id2appid(id); + if(isPeripheryApp(appid.c_str())) { + HMI_NOTICE("homescreen-service", "install/uninstall application is periphery."); + return; + } + + std::string oper = json_object_get_string(obj_oper); + if(oper == _keyInstall) { + struct json_object* j_runnable = nullptr; + int ret = afmmain->runnables(api, &j_runnable); + if(!ret) { + struct json_object *j_found = retrieveRunnables(j_runnable, id); + if(j_found == nullptr) { + HMI_NOTICE("homescreen-service", "installed application isn't runnables."); + json_object_put(j_runnable); + return; + } + addAppDetail(j_found); + pushAppListChangedEvent(_keyInstall, j_found); + } + else { + HMI_ERROR("homescreen-service","get runnalbes failed."); + } + json_object_put(j_runnable); + } + else if(oper == _keyUninstall) { + std::string appid_checked = checkAppId(appid); + if(appid_checked.empty()) { + HMI_NOTICE("homescreen-service","uninstalled application isn't in runnables list, appid=%s.", appid.c_str()); + return; + } + pushAppListChangedEvent(_keyUninstall, obj_data); + removeAppDetail(appid); + } + else { + HMI_ERROR("homescreen-service","operation error."); + } +} + +/** + * parse application detail function + * + * #### Parameters + * - object : [IN] the detail of application + * - info : [OUT] parsed application detail + * + * #### Return + * the appid of application liked "dashboard" + * + */ +std::string HS_AppInfo::parseAppDetail(struct json_object *object, AppDetail &info) const +{ + struct json_object *name, *id; + if(json_object_object_get_ex(object, _keyName, &name) == 0 + || json_object_object_get_ex(object, _keyId, &id) == 0) { + HMI_ERROR("homescreen-service","can't find key=%s, %s.", _keyName, _keyId); + return std::string(); + } + std::string appid = id2appid(json_object_get_string(id)); + bool periphery = isPeripheryApp(appid.c_str()); + + info = { json_object_get_string(name), + json_object_get_string(id), + json_object_to_json_string(object), + periphery + }; + return appid; +} + +/** + * add application detail to list function + * + * #### Parameters + * - object : application detail + * + * #### Return + * None + * + */ +void HS_AppInfo::addAppDetail(struct json_object *object) +{ + AppDetail info; + std::string appid = parseAppDetail(object, info); + if(appid.empty()) { + HMI_ERROR("homescreen-service","application id error"); + return; + } + + std::lock_guard<std::mutex> lock(this->mtx); + appid2name[appid] = info.name; + name2appid[info.name] = appid; + app_detail_list[appid] = std::move(info); +} + +/** + * remove application detail from list function + * + * #### Parameters + * - appid : application id + * + * #### Return + * None + * + */ +void HS_AppInfo::removeAppDetail(std::string appid) +{ + std::lock_guard<std::mutex> lock(this->mtx); + auto it = app_detail_list.find(appid); + if(it != app_detail_list.end()) { + appid2name.erase(appid); + name2appid.erase(it->second.name); + app_detail_list.erase(it); + } + else { + HMI_WARNING("homescreen-service","erase application(%s) wasn't in applist.", appid.c_str()); + } +} + +/** + * push app_list_changed event function + * + * #### Parameters + * - oper: install/uninstall + * - object: event data + * + * #### Return + * None + * + */ +void HS_AppInfo::pushAppListChangedEvent(const char *oper, struct json_object *object) +{ + HMI_NOTICE("homescreen-service","called."); + struct json_object *push_obj = json_object_new_object(); + json_object_object_add(push_obj, _keyOperation, json_object_new_string(oper)); + json_object_object_add(push_obj, _keyData, object); + + HS_ClientManager::instance()->pushEvent(_keyApplistChanged, push_obj); +} + +/** + * retrieve runnables function + * + * #### Parameters + * - obj_runnables: runnables array + * - id: application id + * + * #### Return + * found application detail + * + */ +struct json_object* HS_AppInfo::retrieveRunnables(struct json_object *obj_runnables, std::string id) +{ + struct json_object *j_found = nullptr; + if(json_object_get_type(obj_runnables) == json_type_array) { + int array_len = json_object_array_length(obj_runnables); + for (int i = 0; i < array_len; ++i) { + struct json_object *obj = json_object_array_get_idx(obj_runnables, i); + struct json_object *j_id; + if(json_object_object_get_ex(obj, _keyId, &j_id) == 0) { + HMI_WARNING("homescreen-service","can't find id."); + continue; + } + if(id == json_object_get_string(j_id)) { + j_found = obj; + break; + } + } + } + else { + HMI_ERROR("homescreen-service","Apps information input error."); + } + return j_found; +} + +/** + * convert id to appid function + * + * #### Parameters + * - id : the id of application liked "dashboard@0.1" + * + * #### Return + * the appid of application liked "dashboard" + * + */ +std::string HS_AppInfo::id2appid(const std::string &id) const +{ + std::string appid; + std::size_t pos = id.find("@"); + if(pos != std::string::npos) { + appid = id.substr(0,pos); + } + else { + HMI_ERROR("homescreen-service","input id error."); + } + return appid; +} + +/** + * get runnables list + * + * #### Parameters + * - object : runnables list,json array + * + * #### Return + * None + * + */ +void HS_AppInfo::getRunnables(struct json_object **object) +{ + if(json_object_get_type(*object) != json_type_array) { + HMI_ERROR("homescreen-service","json type error."); + return; + } + + std::lock_guard<std::mutex> lock(this->mtx); + for(auto it : app_detail_list) { + if(!it.second.periphery) + json_object_array_add(*object, json_tokener_parse(it.second.detail.c_str())); + } +} + +/** + * check appid function + * + * #### Parameters + * - appid : appid liked "dashboard" + * + * #### Return + * success : the correct appid + * fail : empty string + * + */ +std::string HS_AppInfo::checkAppId(const std::string &appid) +{ + std::lock_guard<std::mutex> lock(this->mtx); + auto it_appid = appid2name.find(appid); + if(it_appid != appid2name.end()) + return it_appid->first; + + auto it_name = name2appid.find(appid); + if(it_name != name2appid.end()) + return it_name->second; + + return std::string(); +} + +/** + * check if application is a runnable periphery application function + * + * #### Parameters + * - appid : appid liked "launcher" + * + * #### Return + * true : periphery + * false : not periphery + * + */ +bool HS_AppInfo::isPeripheryApp(const char *appid) const +{ + bool ret = false; + for(auto m : periphery_app_list) { + if(strcasecmp(appid, m) == 0) { + ret = true; + break; + } + } + return ret; +} + +/** + * get application specific property + * + * #### Parameters + * - appid : appid liked "launcher" + * - key : the keyword + * + * #### Return + * application property + * + */ +std::string HS_AppInfo::getAppProperty(const std::string appid, std::string key) const +{ + std::string value = ""; + auto it = app_detail_list.find(appid); + if(it != app_detail_list.end()) { + value = it->second.getProperty(key); + } + return value; +}
\ No newline at end of file diff --git a/src/hs-appinfo.h b/src/hs-appinfo.h new file mode 100644 index 0000000..7747f52 --- /dev/null +++ b/src/hs-appinfo.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019 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_APPINFO_H +#define HOMESCREEN_APPINFO_H + +#include <string> +#include <mutex> +#include <memory> +#include <vector> +#include <functional> +#include <unordered_map> +#include "hs-helper.h" +#include "hs-proxy.h" + + +struct AppDetail { + std::string name; + std::string id; + std::string detail; // detail json_object string + bool periphery; + + std::string getProperty(std::string key) const; +}; + +class HS_AppInfo { +public: + HS_AppInfo() = default; + ~HS_AppInfo(); + HS_AppInfo(HS_AppInfo const &) = delete; + HS_AppInfo &operator=(HS_AppInfo const &) = delete; + HS_AppInfo(HS_AppInfo &&) = delete; + HS_AppInfo &operator=(HS_AppInfo &&) = delete; + + static HS_AppInfo* instance(void); + int init(afb_api_t api); + void onEvent(afb_api_t api, const char *event, struct json_object *object); + + void getRunnables(struct json_object **object); + std::string getAppProperty(const std::string appid, std::string key) const; + std::string checkAppId(const std::string &appid); + +private: + void updateAppDetailList(afb_api_t api, struct json_object *object); + void createAppDetailList(struct json_object *object); + std::string parseAppDetail(struct json_object *object, AppDetail &info) const; + void addAppDetail(struct json_object *object); + void removeAppDetail(std::string appid); + struct json_object* retrieveRunnables(struct json_object *obj_runnables, std::string id); + void pushAppListChangedEvent(const char *oper, struct json_object *object); + std::string id2appid(const std::string &id) const; + bool isPeripheryApp(const char *appid) const; + + // applications can't display on launcher + const std::vector<const char*> periphery_app_list { + "launcher", + "homescreen", + "onscreenapp", + "restriction" + }; + + typedef void (HS_AppInfo::*func_handler)(afb_api_t, struct json_object*); + const std::unordered_map<std::string, func_handler> concerned_event_list { + {"afm-main/application-list-changed", &HS_AppInfo::updateAppDetailList} + }; + +private: + static HS_AppInfo* me; + HS_AfmMainProxy* afmmain = nullptr; + std::unordered_map<std::string, std::string> appid2name; + std::unordered_map<std::string, std::string> name2appid; + std::unordered_map<std::string, AppDetail> app_detail_list; + std::mutex mtx; +}; + +#endif // HOMESCREEN_APPINFO_H
\ No newline at end of file diff --git a/src/hs-client.cpp b/src/hs-client.cpp index e0d4bf0..c927442 100644 --- a/src/hs-client.cpp +++ b/src/hs-client.cpp @@ -465,9 +465,35 @@ int HS_Client::handleRequest(afb_req_t request, const char *verb) int ret = AFB_EVENT_BAD_REQUEST; auto ip = func_list.find(std::string(verb)); - if(ip != func_list.end()) { + if(ip != func_list.end() && ip->second != nullptr) { HMI_NOTICE("homescreen-service","[%s]verb found", verb); ret = (this->*(ip->second))(request); } return ret; +} + +/** + * push event + * + * #### Parameters + * - event : the event want to push + * - param : the parameter contents of event + * + * #### Return + * 0 : success + * others : fail + * + */ +int HS_Client::pushEvent(const char *event, struct json_object *param) +{ + if(!checkEvent(event)) + return 0; + + HMI_NOTICE("homescreen-service","called, event=%s.",event); + struct json_object* push_obj = json_object_new_object(); + hs_add_object_to_json_object_str( push_obj, 4, _application_id, my_id.c_str(), _type, event); + if(param != nullptr) + json_object_object_add(push_obj, _parameter, param); + afb_event_push(my_event, push_obj); + return 0; }
\ No newline at end of file diff --git a/src/hs-client.h b/src/hs-client.h index ac4d004..cbf2f33 100644 --- a/src/hs-client.h +++ b/src/hs-client.h @@ -32,6 +32,7 @@ public: ~HS_Client(); int handleRequest(afb_req_t request, const char *verb); + int pushEvent(const char *event, struct json_object *param); private: int tap_shortcut(afb_req_t request); diff --git a/src/hs-clientmanager.cpp b/src/hs-clientmanager.cpp index 7d658e4..8735c2e 100644 --- a/src/hs-clientmanager.cpp +++ b/src/hs-clientmanager.cpp @@ -189,9 +189,45 @@ int HS_ClientManager::handleRequest(afb_req_t request, const char *verb, const c } else { HMI_NOTICE("homescreen-service","not exist session"); - ret = AFB_EVENT_BAD_REQUEST; + ret = AFB_REQ_NOT_STARTED_APPLICATION; } } } return ret; +} + +/** + * push event + * + * #### Parameters + * - event : the event want to push + * - param : the parameter contents of event + * - appid : the destination application's id + * + * #### Return + * 0 : success + * others : fail + * + */ +int HS_ClientManager::pushEvent(const char *event, struct json_object *param, std::string appid) +{ + if(event == nullptr) { + HMI_ERROR("homescreen-service","event name is null."); + return -1; + } + + std::lock_guard<std::mutex> lock(this->mtx); + if(appid.empty()) { // broadcast event to clients who subscribed this event + for(auto m : client_list) { + m.second->pushEvent(event, param); + } + } + else { // push event to specific client + auto ip = client_list.find(appid); + if(ip != client_list.end()) { + ip->second->pushEvent(event, param); + } + } + + return 0; }
\ No newline at end of file diff --git a/src/hs-clientmanager.h b/src/hs-clientmanager.h index d485ea8..efc36de 100644 --- a/src/hs-clientmanager.h +++ b/src/hs-clientmanager.h @@ -46,6 +46,7 @@ public: static HS_ClientManager* instance(void); int init(void); int handleRequest(afb_req_t request, const char *verb, const char *appid = nullptr); + int pushEvent(const char *event, struct json_object *param, std::string appid = ""); void removeClientCtxt(void *data); // don't use, internal only private: diff --git a/src/hs-helper.cpp b/src/hs-helper.cpp index d0f5713..50a3ae1 100644 --- a/src/hs-helper.cpp +++ b/src/hs-helper.cpp @@ -28,6 +28,7 @@ const char* evlist[] = { "replyShowWindow", "showNotification", "showInformation", + "application-list-changed", "reserved" }; diff --git a/src/hs-helper.h b/src/hs-helper.h index 95ecb66..cc6fb89 100644 --- a/src/hs-helper.h +++ b/src/hs-helper.h @@ -27,6 +27,7 @@ #define AFB_REQ_SHOWNOTIFICATION_ERROR 103 #define AFB_REQ_SHOWINFORMATION_ERROR 104 #define AFB_REQ_GETAPPLICATIONID_ERROR 105 +#define AFB_REQ_NOT_STARTED_APPLICATION 106 typedef enum REQ_ERROR { @@ -41,6 +42,8 @@ extern const char _error[]; extern const char _application_id[]; extern const char _display_message[]; extern const char _reply_message[]; +extern const char _keyData[]; +extern const char _keyId[]; REQ_ERROR get_value_uint16(const afb_req_t request, const char *source, uint16_t *out_id); REQ_ERROR get_value_int16(const afb_req_t request, const char *source, int16_t *out_id); diff --git a/src/hs-proxy.cpp b/src/hs-proxy.cpp new file mode 100644 index 0000000..0f5e78c --- /dev/null +++ b/src/hs-proxy.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2019 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-proxy.h" +#include "hmi-debug.h" + +const char _afm_main[] = "afm-main"; + + +/** + * the callback function + * + * #### Parameters + * - closure : the user defined closure pointer 'closure' + * - object : a JSON object returned (can be NULL) + * - error : a string not NULL in case of error but NULL on success + * - info : a string handling some info (can be NULL) + * - api : the api + * + * #### Return + * None + * + */ +static void api_callback(void *closure, struct json_object *object, const char *error, const char *info, afb_api_t api) +{ + HMI_DEBUG("homescreen-service","asynchronous call, error=%s, info=%s, object=%s.", error, info, json_object_get_string(object)); +} + +/** + * call api asynchronous + * + * #### Parameters + * - api : the api serving the request + * - service : the api name of service + * - verb : the verb of service + * - args : parameter + * + * #### Return + * None + * + */ +static void api_call(afb_api_t api, const char *service, const char *verb, struct json_object *args) +{ + HMI_DEBUG("homescreen-service","service=%s verb=%s, args=%s.", service, verb, json_object_get_string(args)); + afb_api_call(api, service, verb, args, api_callback, nullptr); +} + +/** + * call api synchronous + * + * #### Parameters + * - api : the api serving the request + * - service : the api name of service + * - verb : the verb of afm-main + * - args : parameter + * - object : return the details of application + * + * #### Return + * 0 : success + * 1 : fail + * + */ +static int api_call_sync(afb_api_t api, const char *service, const char *verb, struct json_object *args, struct json_object **object) +{ + char *error = nullptr, *info = nullptr; + int ret = afb_api_call_sync(api, service, verb, args, object, &error, &info); + HMI_DEBUG("homescreen-service","synchronous call, error=%s, info=%s.", error, info); + return ret; +} + +/** + * get runnables application list + * + * #### Parameters + * - api : the api serving the request + * - object : return the details of appid + * + * #### Return + * 0 : success + * 1 : fail + * + */ +int HS_AfmMainProxy::runnables(afb_api_t api, struct json_object **object) +{ + return api_call_sync(api, _afm_main, __FUNCTION__, nullptr, object); +} + +/** + * get details of application + * + * #### Parameters + * - api : the api serving the request + * - id : the id to get details,liked "dashboard@0.1" + * - object : return the details of application + * + * #### Return + * 0 : success + * 1 : fail + * + */ +int HS_AfmMainProxy::detail(afb_api_t api, const std::string &id, struct json_object **object) +{ + struct json_object *args = json_object_new_string(id.c_str()); + return api_call_sync(api, _afm_main, __FUNCTION__, args, object); +} + +/** + * start application + * + * #### Parameters + * - request : the request + * - id : the application id liked "dashboard@0.1" + * + * #### Return + * None + * + */ +void HS_AfmMainProxy::start(afb_req_t request, const std::string &id) +{ + struct json_object *args = json_object_new_string(id.c_str()); + api_call(request->api, _afm_main, __FUNCTION__, args); +}
\ No newline at end of file diff --git a/src/hs-proxy.h b/src/hs-proxy.h new file mode 100644 index 0000000..8741e49 --- /dev/null +++ b/src/hs-proxy.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 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_PROXY_H +#define HOMESCREEN_PROXY_H + +#include <string> +#include <json-c/json.h> +#include <functional> +#include "hs-helper.h" + +struct HS_AfmMainProxy { + // synchronous call, call result in object + int runnables(afb_api_t api, struct json_object **object); + int detail(afb_api_t api, const std::string &id, struct json_object **object); + + // asynchronous call, reply in callback function + void start(afb_req_t request, const std::string &id); +}; + +#endif // HOMESCREEN_PROXY_H
\ No newline at end of file |