diff options
-rw-r--r-- | include/hmi-debug.h | 47 | ||||
-rw-r--r-- | src/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/app.hpp | 2 | ||||
-rw-r--r-- | src/applist.cpp | 526 | ||||
-rw-r--r-- | src/applist.hpp | 81 | ||||
-rw-r--r-- | src/request.cpp | 44 | ||||
-rw-r--r-- | src/request.hpp | 72 | ||||
-rw-r--r-- | src/wm_client.cpp | 222 | ||||
-rw-r--r-- | src/wm_client.hpp | 76 | ||||
-rw-r--r-- | src/wm_error.cpp | 46 | ||||
-rw-r--r-- | src/wm_error.hpp | 41 |
11 files changed, 1160 insertions, 3 deletions
diff --git a/include/hmi-debug.h b/include/hmi-debug.h index a1d3079..697ac80 100644 --- a/include/hmi-debug.h +++ b/include/hmi-debug.h @@ -41,6 +41,14 @@ enum LOG_LEVEL{ #define HMI_INFO(prefix, args,...) _HMI_LOG(LOG_LEVEL_INFO, __FILENAME__, __FUNCTION__,__LINE__, prefix, args,##__VA_ARGS__) #define HMI_DEBUG(prefix, args,...) _HMI_LOG(LOG_LEVEL_DEBUG, __FILENAME__, __FUNCTION__,__LINE__, prefix, args,##__VA_ARGS__) +#define HMI_SEQ_ERROR(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_ERROR, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) +#define HMI_SEQ_WARNING(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_WARNING, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) +#define HMI_SEQ_NOTICE(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_NOTICE, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) +#define HMI_SEQ_INFO(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_INFO, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) +#define HMI_SEQ_DEBUG(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_DEBUG, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__) + +#define DUMP(args, ...) _DUMP(LOG_LEVEL_DEBUG, args, ##__VA_ARGS__) + static char ERROR_FLAG[6][20] = {"NONE", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"}; static void _HMI_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, const char* prefix, const char* log, ...) @@ -67,4 +75,43 @@ static void _HMI_LOG(enum LOG_LEVEL level, const char* file, const char* func, c free(message); } +static void _HMI_SEQ_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, unsigned seq_num, const char* log, ...){ + const int log_level = (getenv("USE_HMI_DEBUG") == NULL) ? LOG_LEVEL_ERROR:atoi(getenv("USE_HMI_DEBUG")); + if(log_level < level) + { + return; + } + + char *message; + struct timespec tp; + unsigned int time; + + clock_gettime(CLOCK_REALTIME, &tp); + time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000); + + va_list args; + va_start(args, log); + if (log == NULL || vasprintf(&message, log, args) < 0) + message = NULL; + fprintf(stderr, "[%10.3f] [wm %s] [%s, %s(), Line:%d] >>> req %d: %s \n", time / 1000.0, ERROR_FLAG[level], file, func, line, seq_num, message); + va_end(args); + free(message); +} + +static void _DUMP(enum LOG_LEVEL level, const char *log, ...) +{ + const int log_level = (getenv("USE_HMI_DEBUG") == NULL) ? LOG_LEVEL_ERROR : atoi(getenv("USE_HMI_DEBUG")); + if (log_level < level) + { + return; + } + char *message; + va_list args; + va_start(args, log); + if (log == NULL || vasprintf(&message, log, args) < 0) + message = NULL; + fprintf(stderr, "%s \n", message); + va_end(args); + free(message); +} #endif //__HMI_DEBUG_H__
\ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f727500..db3f9cd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,7 +33,11 @@ add_library(${TARGETS_WM} MODULE ${IVI_CON_PROTO} json_helper.cpp app.cpp - layers.cpp) + layers.cpp + wm_client.cpp + wm_error.cpp + applist.cpp + request.cpp) target_include_directories(${TARGETS_WM} PRIVATE diff --git a/src/app.hpp b/src/app.hpp index ab4e809..4dce828 100644 --- a/src/app.hpp +++ b/src/app.hpp @@ -69,7 +69,6 @@ struct id_allocator // Surfaces that where requested but not yet created std::unordered_map<unsigned, std::string> id2name; - // std::unordered_set<unsigned> pending_surfaces; std::unordered_map<std::string, unsigned> name2id; id_allocator(id_allocator const &) = delete; @@ -82,7 +81,6 @@ struct id_allocator { unsigned sid = this->next++; this->id2name[sid] = name; - // this->pending_surfaces.insert({sid}); this->name2id[name] = sid; HMI_DEBUG("wm", "allocated new id %u with name %s", sid, name.c_str()); return sid; diff --git a/src/applist.cpp b/src/applist.cpp new file mode 100644 index 0000000..a5ae9f0 --- /dev/null +++ b/src/applist.cpp @@ -0,0 +1,526 @@ +/* + * Copyright (c) 2017 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 <iostream> +#include <algorithm> +#include "applist.hpp" +#include "../include/hmi-debug.h" + +using std::shared_ptr; +using std::string; +using std::vector; + +namespace wm +{ + +const static int kReserveClientSize = 100; +const static int kReserveReqSize = 10; + +/** + * AppList Constructor. + * + * Reserve the container size to avoid re-allocating memory. + * + * @note Size should be changed according to the system. + * If the number of applications becomes over the size, re-allocating memory will happen. + */ +AppList::AppList() + : req_list(), + app2client(), + current_req(1) +{ + this->app2client.reserve(kReserveClientSize); + this->req_list.reserve(kReserveReqSize); +} + +AppList::~AppList() {} + +// =================== Client Date container API =================== + +/** + * Add Client to the list + * + * Add Client to the list. + * The Client means application which has role, layer, surface + * This function should be called once for the app. + * Caller should take care not to be called more than once. + * + * @param string[in] Application id. This will be the key to withdraw the information. + * @param unsigned[in] Layer ID in which the application is + * @param unsigned[in] surface ID which the application has + * @param string[in] Role which means what behavior the application will do. + * @return None + * @attention This function should be called once for the app + * Caller should take care not to be called more than once. + */ +void AppList::addClient(const std::string &appid, unsigned layer, unsigned surface, const std::string &role) +{ + std::lock_guard<std::mutex> lock(this->mtx); + shared_ptr<WMClient> client = std::make_shared<WMClient>(appid, layer, surface, role); + this->app2client[appid] = client; + this->clientDump(); +} + +/** + * Remove WMClient from the list + * + * @param string[in] Application id. This will be the key to withdraw the information. + */ +void AppList::removeClient(const string &appid) +{ + std::lock_guard<std::mutex> lock(this->mtx); + this->app2client.erase(appid); + HMI_INFO("wm", "Remove client %s", appid.c_str()); +} + +/** + * Check this class stores the appid. + * + * @param string[in] Application id. This will be the key to withdraw the information. + * @return true if the class has the requested key(appid) + */ +bool AppList::contains(const string &appid) const +{ + auto result = this->app2client.find(appid); + return (this->app2client.end() != result) ? true : false; +} + +/** + * Remove surface from client + * + * @param unsigned[in] surface id. + * @return None + */ +void AppList::removeSurface(unsigned surface){ + // This function may be very slow + std::lock_guard<std::mutex> lock(this->mtx); + bool ret = false; + for (auto &x : this->app2client) + { + ret = x.second->removeSurfaceIfExist(surface); + if(ret){ + HMI_DEBUG("wm", "remove surface %d from Client %s finish", + surface, x.second->appID().c_str()); + break; + } + } + +} + +/** + * Get WMClient object. + * + * After get the WMClient object, caller can call the client method. + * Before call this function, caller must call "contains" + * to check the key is contained, otherwise, you have to take care of std::out_of_range. + * + * @param string[in] application id(key) + * @return WMClient object + * @attention Must call cantains to check appid is stored before this function. + */ +shared_ptr<WMClient> AppList::lookUpClient(const string &appid) +{ + return this->app2client.at(appid); +} + +/** + * Count Client. + * + * Returns the number of client stored in the list. + * + * @param None + * @return The number of client + */ +int AppList::countClient() const +{ + return this->app2client.size(); +} + +/** + * Get AppID with surface and role. + * + * Returns AppID if found. + * + * @param unsigned[in] surfaceID + * @param string[in] role + * @param bool[in,out] AppID is found or not + * @return AppID + * @attention If AppID is not found, param found will be false. + */ +string AppList::getAppID(unsigned surface, const string& role, bool* found) const +{ + *found = false; + for (const auto &x : this->app2client) + { + if(x.second->surfaceID(role) == surface){ + *found = true; + return x.second->appID(); + } + } + return string(""); +} + +// =================== Request Date container API =================== + +/** + * Get current request number + * + * Request number is the numeric ID to designate the request. + * But returned request number from this function doesn't mean the request exists. + * This number is used as key to withdraw the WMRequest object. + * + * @param None + * @return current request number. + * @note request number is more than 0. + */ +unsigned AppList::currentRequestNumber() const +{ + return this->current_req; +} + +/** + * Get request number + * + * Request number is the numeric ID to designate the request. + * But returned request number from this function doesn't mean the request exists. + * This number is used as key to withdraw the WMRequest object. + * + * @param None + * @return request number. + * @attention If returned value is 0, no request exists. + */ +unsigned AppList::getRequestNumber(const string &appid) const +{ + for (const auto &x : this->req_list) + { + // Since app will not request twice and more, comparing appid is enough? + if ((x.trigger.appid == appid)) + { + return x.req_num; + } + } + return 0; +} + +/** + * Add Request + * + * Request number is the numeric ID to designate the request. + * But returned request number from this function doesn't mean the request exists. + * This number is used as key to withdraw the WMRequest object. + * + * @param WMRequest[in] WMRequest object caller creates + * @return Request number + * @attention If the request number is different with curent request number, + * it means the previous request is not finished. + */ +unsigned AppList::addRequest(WMRequest req) +{ + std::lock_guard<std::mutex> lock(this->mtx); + if (this->req_list.size() == 0) + { + req.req_num = current_req; + } + else + { + HMI_SEQ_INFO(this->current_req, "add: %d", this->req_list.back().req_num + 1); + req.req_num = this->req_list.back().req_num + 1; + } + this->req_list.push_back(req); + return req.req_num; +} + +/** + * Get trigger which the application requests + * + * WMTrigger contains which application requests what role and where to put(area) and task. + * This is used for input event to Window Policy Manager(state machine). + * + * @param unsigned[in] request number + * @param bool[in,out] Check request number of the parameter is valid. + * @return WMTrigger which associates with the request number + * @attention If the request number is not valid, parameter "found" is false + * and return value will be meaningless value. + * Caller can check the request parameter is valid. + */ +struct WMTrigger AppList::getRequest(unsigned req_num, bool *found) +{ + *found = false; + for (const auto &x : this->req_list) + { + if (req_num == x.req_num) + { + *found = true; + return x.trigger; + } + } + HMI_SEQ_ERROR(req_num, "Couldn't get request : %d", req_num); + return WMTrigger{"", "", "", Task::TASK_INVALID}; +} + +/** + * Get actions which the application requests + * + * WMAciton contains the information of state transition. + * In other words, it contains actions of Window Manager, + * which role should be put to the area. + * + * @param unsigned[in] request number + * @param bool[in,out] Check request number of the parameter is valid. + * @return WMTrigger which associates with the request number + * @attention If the request number is not valid, parameter "found" is false + * and return value will be no reference pointer. + * Caller must check the request parameter is valid. + */ +const vector<struct WMAction> &AppList::getActions(unsigned req_num, bool* found) +{ + *found = false; + for (auto &x : this->req_list) + { + if (req_num == x.req_num) + { + *found = true; + return x.sync_draw_req; + } + } + HMI_SEQ_ERROR(req_num, "Couldn't get action with the request : %d", req_num); +} + +/** + * Set actions to the request. + * + * Add actions to the request. + * This function can be called many times, and actions increase. + * This function is used for decision of actions of Window Manager + * according to the result of Window Policy Manager. + * + * @param unsigned[in] request number + * @param WMAction[in] Action of Window Manager. + * @return WMError If request number is not valid, FAIL will be returned. + */ +WMError AppList::setAction(unsigned req_num, const struct WMAction &action) +{ + std::lock_guard<std::mutex> lock(this->mtx); + WMError result = WMError::FAIL; + for (auto &x : this->req_list) + { + if (req_num != x.req_num) + { + continue; + } + x.sync_draw_req.push_back(action); + result = WMError::SUCCESS; + break; + } + return result; +} + +/** + * Note: + * @note This function set action with parameters. + * If visible is true, it means app should be visible, so enddraw_finished parameter should be false. + * otherwise (visible is false) app should be invisible. Then enddraw_finished param is set to true. + * This function doesn't support actions for focus yet. + */ +/** + * Set actions to the request. + * + * This function is overload function. + * The feature is same as other one. + * + * @param unsigned[in] request number + * @param string[in] application id + * @param string[in] role + * @param string[in] area + * @param Task[in] the role should be visible or not. + * @return WMError If request number is not valid, FAIL will be returned. + * @attention This function set action with parameters, then caller doesn't need to create WMAction object. + * If visible is true, it means app should be visible, so enddraw_finished parameter will be false. + * otherwise (visible is false) app should be invisible. Then enddraw_finished param is set to true. + * This function doesn't support actions for focus yet. + */ +WMError AppList::setAction(unsigned req_num, const string &appid, const string &role, const string &area, TaskVisible visible) +{ + std::lock_guard<std::mutex> lock(this->mtx); + WMError result = WMError::FAIL; + for (auto &x : req_list) + { + if (req_num != x.req_num) + { + continue; + } + // If visible task is not invisible, redraw is required -> true + bool edraw_f = (visible != TaskVisible::INVISIBLE) ? false : true; + WMAction action{appid, role, area, visible, edraw_f}; + + x.sync_draw_req.push_back(action); + result = WMError::SUCCESS; + break; + } + return result; +} + +/** + * Set end_draw_finished param is true + * + * This function checks + * - req_num is equal to current request number + * - appid and role are equeal to the appid and role stored in action list + * If it is valid, set the action is finished. + * + * @param unsigned[in] request number + * @param string[in] application id + * @param string[in] role + * @return If the parameters are not valid in action list, returns false + */ +bool AppList::setEndDrawFinished(unsigned req_num, const string &appid, const string &role) +{ + std::lock_guard<std::mutex> lock(this->mtx); + bool result = false; + for (auto &x : req_list) + { + if (req_num < x.req_num) + { + break; + } + if (req_num == x.req_num) + { + for (auto &y : x.sync_draw_req) + { + if (y.appid == appid && y.role == role) + { + HMI_SEQ_INFO(req_num, "Role %s finish redraw", y.role.c_str()); + y.end_draw_finished = true; + result = true; + } + } + } + } + this->reqDump(); + return result; +} + +/** + * Check all actions of the requested sequence is finished + * + * @param unsigned[in] request_number + * @return true if all action is set. + */ +bool AppList::endDrawFullfilled(unsigned req_num) +{ + bool result = false; + for (const auto &x : req_list) + { + if (req_num < x.req_num) + { + break; + } + if (req_num == x.req_num) + { + result = true; + for (const auto &y : x.sync_draw_req) + { + result &= y.end_draw_finished; + if (!result) + { + break; + } + } + } + } + return result; +} + +/** + * Finish the request, then remove it. + * + * @param unsigned[in] request_number + * @return None + * @note Please call next after this function to receive or process next request. + */ +void AppList::removeRequest(unsigned req_num) +{ + std::lock_guard<std::mutex> lock(this->mtx); + this->req_list.erase(remove_if(this->req_list.begin(), this->req_list.end(), + [req_num](WMRequest x) { + return x.req_num == req_num; + })); +} + +/** + * Move the current request to next + * + * @param None + * @return None + */ +void AppList::next() +{ + std::lock_guard<std::mutex> lock(this->mtx); + ++this->current_req; + if (0 == this->current_req) + { + this->current_req = 1; + } +} + +/** + * Check the request exists is in request list + * + * @param None + * @return true if WMRequest exists in the request list + */ +bool AppList::haveRequest() const +{ + return !this->req_list.empty(); +} + +void AppList::clientDump() +{ + DUMP("======= client dump ====="); + for (const auto &x : this->app2client) + { + const auto &y = x.second; + y->dumpInfo(); + } + DUMP("======= client dump end====="); +} + +void AppList::reqDump() +{ + DUMP("======= req dump ====="); + DUMP("current request : %d", current_req); + for (const auto &x : req_list) + { + DUMP("requested : %d", x.req_num); + DUMP("Trigger : (APPID :%s, ROLE :%s, AREA :%s, TASK: %d)", + x.trigger.appid.c_str(), + x.trigger.role.c_str(), + x.trigger.area.c_str(), + x.trigger.task); + + for (const auto &y : x.sync_draw_req) + { + DUMP( + "Action : (APPID :%s, ROLE :%s, AREA :%s, VISIBLE : %s, END_DRAW_FINISHED: %d)", + y.appid.c_str(), + y.role.c_str(), + y.area.c_str(), + (y.visible == TaskVisible::INVISIBLE) ? "invisible" : "visible", + y.end_draw_finished); + } + } + DUMP("======= req dump end ====="); +} +} // namespace wm diff --git a/src/applist.hpp b/src/applist.hpp new file mode 100644 index 0000000..a794b53 --- /dev/null +++ b/src/applist.hpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2017 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 ALLOCATE_LIST_HPP +#define ALLOCATE_LIST_HPP +#include <vector> +#include <string> +#include <map> +#include <memory> +#include <mutex> +#include "wm_client.hpp" +#include "request.hpp" +#include "wm_error.hpp" + +namespace wm +{ + +/* using std::experimental::nullopt; +using std::experimental::optional; */ + +class AppList +{ + public: + AppList(); + virtual ~AppList(); + AppList(const AppList &obj) = delete; + + // Client Database Interface + /* TODO: consider, which is better WMClient as parameter or not + If the WMClient should be more flexible, I think this param should be WMClient class + */ + void addClient(const std::string &appid, unsigned layer, + unsigned surface,const std::string &role); + void removeClient(const std::string &appid); + bool contains(const std::string &appid) const; + int countClient() const; + std::shared_ptr<WMClient> lookUpClient(const std::string &appid); + void removeSurface(unsigned surface); + std::string getAppID(unsigned surface, const std::string &role, bool *found) const; + + // Request Interface + unsigned currentRequestNumber() const; + unsigned getRequestNumber(const std::string &appid) const; + unsigned addRequest(WMRequest req); + WMError setAction(unsigned req_num, const struct WMAction &action); + WMError setAction(unsigned req_num, const std::string &appid, + const std::string &role, const std::string &area, TaskVisible visible); + bool setEndDrawFinished(unsigned req_num, const std::string &appid, const std::string &role); + bool endDrawFullfilled(unsigned req_num); + void removeRequest(unsigned req_num); + void next(); + bool haveRequest() const; + + struct WMTrigger getRequest(unsigned req_num, bool* found); + const std::vector<struct WMAction> &getActions(unsigned req_num, bool* found); + + void clientDump(); + void reqDump(); + + private: + std::vector<WMRequest> req_list; + std::unordered_map<std::string, std::shared_ptr<WMClient>> app2client; + unsigned current_req; + std::mutex mtx; +}; + +} // namespace wm +#endif // ALLOCATE_LIST_HPP
\ No newline at end of file diff --git a/src/request.cpp b/src/request.cpp new file mode 100644 index 0000000..069f8ff --- /dev/null +++ b/src/request.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017 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 "request.hpp" + +namespace wm +{ + +using std::string; + +WMRequest::WMRequest() {} + +WMRequest::WMRequest(string appid, string role, string area, Task task) + : req_num(0), + trigger{appid, role, area, task}, + sync_draw_req(0) +{ +} + +WMRequest::~WMRequest() +{ +} + +WMRequest::WMRequest(const WMRequest &obj) +{ + this->req_num = obj.req_num; + this->trigger = obj.trigger; + this->sync_draw_req = obj.sync_draw_req; +} + +} // namespace wm
\ No newline at end of file diff --git a/src/request.hpp b/src/request.hpp new file mode 100644 index 0000000..6b2bda1 --- /dev/null +++ b/src/request.hpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017 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 WMREQUEST_HPP +#define WMREQUEST_HPP + +#include <string> +#include <vector> + +namespace wm +{ + +enum Task +{ + TASK_ALLOCATE, + TASK_RELEASE, + TASK_INVALID +}; + +enum TaskVisible +{ + VISIBLE, + INVISIBLE, + NO_CHANGE +}; + +struct WMTrigger +{ + std::string appid; + std::string role; + std::string area; + Task task; +}; + +struct WMAction +{ + std::string appid; + std::string role; + std::string area; + TaskVisible visible; + bool end_draw_finished; +}; + +struct WMRequest +{ + WMRequest(); + explicit WMRequest(std::string appid, std::string role, + std::string area, Task task); + virtual ~WMRequest(); + WMRequest(const WMRequest &obj); + + unsigned req_num; + struct WMTrigger trigger; + std::vector<struct WMAction> sync_draw_req; +}; + +} // namespace wm + +#endif //WMREQUEST_HPP
\ No newline at end of file diff --git a/src/wm_client.cpp b/src/wm_client.cpp new file mode 100644 index 0000000..a9ed547 --- /dev/null +++ b/src/wm_client.cpp @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2017 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 <json-c/json.h> +#include "wm_client.hpp" +#include "hmi-debug.h" + +#define INVALID_SURFACE_ID 0 + +using std::string; +using std::vector; + +namespace wm +{ + +static const vector<string> kWMEvents = { + // Private event for applications + "syncDraw", "flushDraw", "visible", "invisible", "active", "inactive", "error"}; +static const vector<string> kErrorDescription = { + "unknown-error"}; + +static const char kKeyDrawingName[] = "drawing_name"; +static const char kKeyrole[] = "role"; +static const char kKeyError[] = "error"; +static const char kKeyErrorDesc[] = "kErrorDescription"; + +WMClient::WMClient(const string &appid, unsigned layer, unsigned surface, const string &role) + : id(appid), layer(layer), + role2surface(0) +{ + role2surface[role] = surface; + for (auto x : kWMEvents) + { +#if GTEST_ENABLED + string ev = x; +#else + afb_event ev = afb_daemon_make_event(x.c_str()); +#endif + event2list[x] = ev; + } +} + +WMClient::WMClient(const string &appid, const string &role) + : id(appid), + layer(0), + role2surface(0), + event2list(0) +{ + role2surface[role] = INVALID_SURFACE_ID; + for (auto x : kWMEvents) + { +#if GTEST_ENABLED + string ev = x; +#else + afb_event ev = afb_daemon_make_event(x.c_str()); +#endif + event2list[x] = ev; + } +} + +WMClient::~WMClient() +{ +} + +string WMClient::appID() const +{ + return this->id; +} + +unsigned WMClient::surfaceID(const string &role) const +{ + if (0 == this->role2surface.count(role)) + { + return INVALID_SURFACE_ID; + } + return this->role2surface.at(role); +} + +std::string WMClient::role(unsigned surface) const +{ + for(const auto& x : this->role2surface) + { + if(x.second == surface) + { + return x.first; + } + } + return std::string(""); +} + +unsigned WMClient::layerID() const +{ + return this->layer; +} + +/** + * Set layerID the client belongs to + * + * This function set layerID the client belongs to. + * But this function may not used because the layer should be fixed at constructor. + * So this function will be used to change layer by some reasons. + * + * @param unsigned[in] layerID + * @return None + * @attention WMClient can't have multiple layer + */ +void WMClient::registerLayer(unsigned layer) +{ + this->layer = layer; +} + +/** + * Add the pair of role and surface to the client + * + * This function set the pair of role and surface to the client. + * This function is used for the client which has multi surfaces. + * If the model and relationship for role and surface(layer) + * is changed, this function will be changed + * Current Window Manager doesn't use this function. + * + * @param string[in] role + * @param unsigned[in] surface + * @return true + */ +bool WMClient::addSurface(const string &role, unsigned surface) +{ + HMI_DEBUG("wm", "Add role %s with surface %d", role.c_str(), surface); + if (0 != this->role2surface.count(role)) + { + HMI_NOTICE("wm", "override surfaceID %d with %d", this->role2surface[role], surface); + } + this->role2surface[role] = surface; + return true; +} + +bool WMClient::removeSurfaceIfExist(unsigned surface) +{ + bool ret = false; + for (auto &x : this->role2surface) + { + if (surface == x.second) + { + HMI_INFO("wm", "Remove surface from client %s: role %s, surface: %d", + this->id.c_str(), x.first.c_str(), x.second); + this->role2surface.erase(x.first); + ret = true; + break; + } + } + return ret; +} + +bool WMClient::removeRole(const string &role) +{ + bool ret = false; + if (this->role2surface.count(role) != 0) + { + this->role2surface.erase(role); + ret = true; + } + return ret; +} + +#ifndef GTEST_ENABLED +bool WMClient::subscribe(afb_req req, const string &evname) +{ + if(evname != kKeyError){ + HMI_DEBUG("wm", "error is only enabeled for now"); + return false; + } + int ret = afb_req_subscribe(req, this->event2list[evname]); + if (ret) + { + HMI_DEBUG("wm", "Failed to subscribe %s", evname.c_str()); + return false; + } + return true; +} + +void WMClient::emitError(WM_CLIENT_ERROR_EVENT ev) +{ + if (!afb_event_is_valid(this->event2list[kKeyError])){ + HMI_ERROR("wm", "event err is not valid"); + return; + } + json_object *j = json_object_new_object(); + json_object_object_add(j, kKeyError, json_object_new_int(ev)); + json_object_object_add(j, kKeyErrorDesc, json_object_new_string(kErrorDescription[ev].c_str())); + HMI_DEBUG("wm", "error: %d, description:%s", ev, kErrorDescription[ev].c_str()); + + int ret = afb_event_push(this->event2list[kKeyError], j); + if (ret != 0) + { + HMI_DEBUG("wm", "afb_event_push failed: %m"); + } +} +#endif + +void WMClient::dumpInfo() +{ + DUMP("APPID : %s", id.c_str()); + DUMP(" LAYER : %d", layer); + for (const auto &x : this->role2surface) + { + DUMP(" ROLE : %s , SURFACE : %d", x.first.c_str(), x.second); + } +} + +} // namespace wm
\ No newline at end of file diff --git a/src/wm_client.hpp b/src/wm_client.hpp new file mode 100644 index 0000000..0d6faeb --- /dev/null +++ b/src/wm_client.hpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017 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 WINDOWMANAGER_CLIENT_HPP +#define WINDOWMANAGER_CLIENT_HPP + +#include <vector> +#include <string> +#include <unordered_map> + +extern "C" +{ +#define AFB_BINDING_VERSION 2 +#include <afb/afb-binding.h> +} + +namespace wm +{ + +enum WM_CLIENT_ERROR_EVENT +{ + UNKNOWN_ERROR +}; + +class WMClient +{ + public: + WMClient(); + WMClient(const std::string &appid, unsigned layer, + unsigned surface, const std::string &role); + WMClient(const std::string &appid, const std::string &role); + virtual ~WMClient(); + + std::string appID() const; + unsigned surfaceID(const std::string &role) const; + unsigned layerID() const; + std::string role(unsigned surface) const; + void registerLayer(unsigned layer); + bool addSurface(const std::string& role, unsigned surface); + bool removeSurfaceIfExist(unsigned surface); + bool removeRole(const std::string& role); + +#ifndef GTEST_ENABLED + bool subscribe(afb_req req, const std::string &event_name); + void emitError(WM_CLIENT_ERROR_EVENT ev); +#endif + + void dumpInfo(); + + private: + std::string id; + unsigned layer; + std::unordered_map<std::string, unsigned> role2surface; +#if GTEST_ENABLED + // This is for unit test. afb_make_event occurs sig11 if call not in afb-binding + std::unordered_map<std::string, std::string> event2list; +#else + std::unordered_map<std::string, struct afb_event> event2list; +#endif +}; +} // namespace wm + +#endif
\ No newline at end of file diff --git a/src/wm_error.cpp b/src/wm_error.cpp new file mode 100644 index 0000000..694a7d0 --- /dev/null +++ b/src/wm_error.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017 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 "wm_error.hpp" + +namespace wm { + +const char *errorDescription(WMError enum_error_number) +{ + switch (enum_error_number){ + case SUCCESS: + return "Success"; + case FAIL: + return "Request failed"; + case REQ_REJECTED: + return "Request is rejected, due to the policy rejection of the request."; + case REQ_DROPPED: + return "Request is dropped, because the high priority request is done"; + case NOT_REGISTERED: + return "Not registered"; + case TIMEOUT_EXPIRED: + return "Request is dropped, due to time out expiring"; + case LAYOUT_CHANGE_FAIL: + return "Layout change fails, due to some reasons"; + case NO_ENTRY: + return "No element"; + case NO_LAYOUT_CHANGE: + return "No layout change(deactivate only)"; + default: + return "Unknown error number. Window manager bug."; + } +} + +}
\ No newline at end of file diff --git a/src/wm_error.hpp b/src/wm_error.hpp new file mode 100644 index 0000000..c4c61b4 --- /dev/null +++ b/src/wm_error.hpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017 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 WINDOW_MANAGER_ERROR +#define WINDOW_MANAGER_ERROR + +namespace wm { + +typedef enum WINDOWMANAGER_ERROR +{ + SUCCESS = 0, + FAIL, + REQ_REJECTED, + REQ_DROPPED, + TIMEOUT_EXPIRED, + NOT_REGISTERED, + LAYOUT_CHANGE_FAIL, + NO_ENTRY, + NO_LAYOUT_CHANGE, + UNKNOWN, + ERR_MAX = UNKNOWN +} +WMError; + +const char *errorDescription(WMError enum_error_number); + +} +#endif // WINDOW_MANAGER_ERROR
\ No newline at end of file |