diff options
author | Yuta Doi <yuta-d@witz-inc.co.jp> | 2018-04-27 19:01:36 +0900 |
---|---|---|
committer | Yuta Doi <yuta-d@witz-inc.co.jp> | 2018-04-27 19:01:36 +0900 |
commit | 55be85ed4bdfea6fc037d781b8cd8f58487718d1 (patch) | |
tree | 279a88e26c74aee58f11e2a5d20348569ce34667 /src/layout_manager | |
parent | d50188f726b15a0ae2777bf2d91ee88836feeac5 (diff) |
Add PolicyManager, related classes and some config files
- PolicyManager
Decide next layout by using occured event and current state
based on policy table.
This PolicyManger is reference and the OEMs can replace it.
- LayoutManager
Change the current layout to the layout
which decided by PolicyManager.
NOTE:
The functions of this class had been included in App class.
The part of function of this class remain there yet.
- LowCanClient
Receive the CAN signal from low level CAN service.
- app.db
Define the applications name and its role.
This file will be deleted
when the names and roles can be given by other module.
- layout.cb
Define the layouts and areas which are included by the layout.
- role.db
Define the roles of the applications.
Change-Id: I2f84bdf5e68355e022f516cee9a1db88efe58825
Signed-off-by: Yuta Doi <yuta-d@witz-inc.co.jp>
Diffstat (limited to 'src/layout_manager')
-rw-r--r-- | src/layout_manager/db/layout.db | 158 | ||||
-rw-r--r-- | src/layout_manager/layout.cpp | 570 | ||||
-rw-r--r-- | src/layout_manager/layout.hpp | 84 |
3 files changed, 812 insertions, 0 deletions
diff --git a/src/layout_manager/db/layout.db b/src/layout_manager/db/layout.db new file mode 100644 index 0000000..c7cefd8 --- /dev/null +++ b/src/layout_manager/db/layout.db @@ -0,0 +1,158 @@ +{ + "layouts": [ + { + "name": "pu", + "layer": "on_screen", + "areas": [ + { + "name": "pop_up", + "role": "incomming_call" + } + ] + }, + { + "name": "sa", + "layer": "on_screen", + "areas": [ + { + "name": "system_alert", + "role": "system_alert" + } + ] + }, + { + "name": "m1", + "layer": "apps", + "areas": [ + { + "name": "normal", + "role": "map" + } + ] + }, + { + "name": "m2", + "layer": "apps", + "areas": [ + { + "name": "split.main", + "role": "map" + }, + { + "name": "split.sub", + "category": "splitable" + } + ] + }, + { + "name": "mf", + "layer": "apps", + "areas": [ + { + "name": "full", + "role": "map" + } + ] + }, + { + "name": "s1", + "layer": "apps", + "areas": [ + { + "name": "normal", + "category": "splitable" + } + ] + }, + { + "name": "s2", + "layer": "apps", + "areas": [ + { + "name": "split.main", + "category": "splitable" + }, + { + "name": "split.sub", + "category": "splitable" + } + ] + }, + { + "name": "g", + "layer": "apps", + "areas": [ + { + "name": "normal", + "category": "general" + } + ] + }, + { + "name": "hs", + "layer": "homescreen", + "areas": [ + { + "name": "full", + "role": "homescreen" + } + ] + } + ], + "areas": [ + { + "name": "normal", + "rect": { + "x": 0, + "y": 218, + "w": 1080, + "h": 1488 + } + }, + { + "name": "split.main", + "rect": { + "x": 0, + "y": 218, + "w": 1080, + "h": 744 + } + }, + { + "name": "split.sub", + "rect": { + "x": 0, + "y": 962, + "w": 1080, + "h": 744 + } + }, + { + "name": "full", + "rect": { + "x": 0, + "y": 0, + "w": 1080, + "h": 1920 + } + }, + { + "name": "pop_up", + "rect": { + "x": 0, + "y": 640, + "w": 1080, + "h": 640 + } + }, + { + "name": "system_alert", + "rect": { + "x": 0, + "y": 640, + "w": 1080, + "h": 640 + } + } + ] +} diff --git a/src/layout_manager/layout.cpp b/src/layout_manager/layout.cpp new file mode 100644 index 0000000..dc73cbf --- /dev/null +++ b/src/layout_manager/layout.cpp @@ -0,0 +1,570 @@ +/* + * 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 "layout.hpp" +#include "json_helper.hpp" +#include "hmi-debug.h" + + +LayoutManager::LayoutManager() { + HMI_DEBUG("wm:lm", "Call"); +} + +int LayoutManager::initialize() { + HMI_DEBUG("wm:lm", "Call"); + + int ret = 0; + + // Load layout.db + ret = this->loadLayoutDb(); + if (0 > ret) { + HMI_ERROR("wm:lm", "Load layout.db Error!!"); + return ret; + } + + TypeLayouts layout; + TypeAreas area; + TypeRolCtg rol_ctg; + + rol_ctg["none"] = "none"; + area["none"] = rol_ctg; + layout["none"] = area; + + this->prv_layers_["on_screen"] = layout; + this->prv_layers_["apps"] = layout; + this->prv_layers_["homescreen"] = layout; + + this->crr_layers_["on_screen"] = layout; + this->crr_layers_["apps"] = layout; + this->crr_layers_["homescreen"] = layout; + + this->prv_layers_car_stop_["on_screen"] = layout; + this->prv_layers_car_stop_["apps"] = layout; + this->prv_layers_car_stop_["homescreen"] = layout; + + return ret; +} + +bool LayoutManager::updateLayout(json_object* obj, + const char* new_role, const char* category) { + HMI_DEBUG("wm:lm", "Call"); + + bool ret = false; + + // Check car state change + json_object* json_car; + if (!json_object_object_get_ex(obj, "car", &json_car)) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + + json_bool is_car_state_changed; + std::string car_state = ""; + is_car_state_changed = jh::getBoolFromJson(json_car, "is_changed"); + if (is_car_state_changed) { + // If car state is changed, get car state + car_state = jh::getStringFromJson(json_car, "state"); + } + + // Update layout of all layers + json_object* json_layers; + if (!json_object_object_get_ex(obj, "layers", &json_layers)) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + + int len = json_object_array_length(json_layers); + HMI_DEBUG("wm:lm", "json_layers len:%d", len); + HMI_DEBUG("wm:lm", "json_layers dump:%s", json_object_get_string(json_layers)); + + for (int i=0; i<len; i++) { + json_object* json_tmp = json_object_array_get_idx(json_layers, i); + + // Get layer name and json_object + const char* layer; + json_object* json_layer; + json_object_object_foreach(json_tmp, key, val) { + layer = key; + json_layer = val; + HMI_DEBUG("wm:lm", "Update %s layer state", layer); + } + + // Store previous state + this->prv_layers_[layer] = this->crr_layers_[layer]; + std::string prv_layout_name = this->prv_layers_[layer].begin()->first; + + // If car state is changed car_stop -> car_run, + // store current state for state of car stop + if ((is_car_state_changed) && ("car_run" == car_state)) { + HMI_DEBUG("wm:lm", "Store current state for state of car stop"); + this->prv_layers_car_stop_[layer] = this->crr_layers_[layer]; + } + + json_object* json_is_changed; + if (!json_object_object_get_ex(json_layer, "is_changed", &json_is_changed)) { + HMI_ERROR("wm:lm", "Not found key \"is_changed\""); + return false; + } + + // If layer state is changed + if (json_object_get_boolean(json_is_changed)) { + // Set layout changed flag + this->is_layout_changed_[layer] = true; + + json_object* json_state; + if (!json_object_object_get_ex(json_layer, "state", &json_state)) { + HMI_ERROR("wm:lm", "Not found key \"state\""); + return false; + } + + const char* crr_layout_name = json_object_get_string(json_state); + HMI_DEBUG("wm:lm", "crr state: %s", crr_layout_name); + + TypeLayouts crr_layout; + if ((is_car_state_changed) && ("car_stop" == car_state)) { + // If car state is changed car_run -> car_stop, + // restore state of car stop + HMI_DEBUG("wm:lm", "Restore state of car stop"); + crr_layout = this->prv_layers_car_stop_[layer]; + } + else if ("none" == std::string(crr_layout_name)) { + // If current layout is "none", + // current areas is set with "none" + TypeAreas area; + TypeRolCtg rol_ctg; + rol_ctg["none"] = "none"; + area["none"] = rol_ctg; + crr_layout["none"] = area; + } + else { + if (std::string(crr_layout_name) == prv_layout_name) { + // If previous layout is same with current, + // previous areas are copied to current + crr_layout[crr_layout_name] = this->prv_layers_[layer][crr_layout_name]; + } + else { + // If previous layout is NOT same with current, + // current areas is set with default value + crr_layout[crr_layout_name] = this->layout_define_[crr_layout_name]; + } + + if (is_car_state_changed) { + // Updating role is not necessary + // because new_role is not specified when car state is changed + } + else { + // Get new_area for new role + std::string new_area = this->getAreaName(this->layout_define_[crr_layout_name], + new_role, category); + + // Update role in new area + TypeRolCtg crr_role; + crr_role["role"] = std::string(new_role); + crr_layout[crr_layout_name][new_area] = crr_role; + } + } + + // Update layer state + this->crr_layers_[layer] = crr_layout; + + // Check + for (auto itr_layout = this->crr_layers_[layer].begin(); + itr_layout != this->crr_layers_[layer].end(); ++itr_layout) { + for (auto itr_area = itr_layout->second.begin(); + itr_area != itr_layout->second.end(); ++itr_area) { + for (auto itr_role = itr_area->second.begin(); + itr_role != itr_area->second.end(); ++itr_role) { + HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s", + itr_layout->first.c_str(), itr_area->first.c_str(), + itr_role->first.c_str(), itr_role->second.c_str()); + } + } + } + + ret = true; + } + else { + // Clear layout changed flag + this->is_layout_changed_[layer] = false; + } + } + return ret; +} + +// TODO: This API is for workaround, so this will be removed +void LayoutManager::updateArea(const char* layer, const char* role, const char* area) { + this->crr_layers_[layer].begin()->second[area]["role"] = std::string(role); +} + +LayoutManager::TypeLayers LayoutManager::getCurrentLayers() { + return this->crr_layers_; +} + +LayoutManager::TypeLayers LayoutManager::getPreviousLayers() { + return this->prv_layers_; +} + +compositor::rect LayoutManager::getAreaSize(const char* area) { + return this->area2size_[area]; +} + +std::string LayoutManager::getAreaName(TypeAreas areas, const char* role, const char* category) { + for (auto itr_area = areas.begin(); itr_area != areas.end(); ++itr_area) { + std::string area_name = itr_area->first; + TypeRolCtg rol_ctg = itr_area->second; + + if ("role" == rol_ctg.begin()->first) { + if (std::string(role) == rol_ctg.begin()->second) { + return area_name; + } + } + else if ("category" == rol_ctg.begin()->first) { + if (std::string(category) == rol_ctg.begin()->second) { + return area_name; + } + } + else { + return std::string("none"); + } + } + return std::string("none"); +} + + +bool LayoutManager::isLayoutChanged(const char* layer) { + return this->is_layout_changed_[layer]; +} + +extern const char* kDefaultLayoutDb; +int LayoutManager::loadLayoutDb() { + HMI_DEBUG("wm:lm", "Call"); + + // Get afm application installed dir + char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR"); + HMI_DEBUG("wm:lm", "afm_app_install_dir:%s", afm_app_install_dir); + + std::string file_name; + if (!afm_app_install_dir) { + HMI_ERROR("wm:lm", "AFM_APP_INSTALL_DIR is not defined"); + } + else { + file_name = std::string(afm_app_install_dir) + std::string("/etc/layout.db"); + } + + // Load layout.db + HMI_DEBUG("wm:lm", "file_name:%s", file_name.c_str()); + json_object* json_obj = json_object_from_file(file_name.c_str()); + if (nullptr == json_obj) { + HMI_ERROR("wm:lm", "Could not open layout.db, so use default role information"); + json_obj = json_tokener_parse(kDefaultLayoutDb); + } + HMI_DEBUG("wm:lm", "json_obj dump:%s", json_object_get_string(json_obj)); + + // Perse layouts + HMI_DEBUG("wm:lm", "Perse layouts"); + json_object* json_cfg; + if (!json_object_object_get_ex(json_obj, "layouts", &json_cfg)) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + + int len = json_object_array_length(json_cfg); + HMI_DEBUG("wm:lm", "json_cfg len:%d", len); + HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg)); + + const char* layout; + const char* role; + const char* category; + for (int i=0; i<len; i++) { + json_object* json_tmp = json_object_array_get_idx(json_cfg, i); + + layout = jh::getStringFromJson(json_tmp, "name"); + if (nullptr == layout) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + HMI_DEBUG("wm:lm", "> layout:%s", layout); + + json_object* json_area_array; + if (!json_object_object_get_ex(json_tmp, "areas", &json_area_array)) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + + int len_area = json_object_array_length(json_area_array); + HMI_DEBUG("wm:lm", "json_area_array len:%d", len_area); + HMI_DEBUG("wm:lm", "json_area_array dump:%s", json_object_get_string(json_area_array)); + + TypeAreas areas; + for (int j=0; j<len_area; j++) { + json_object* json_area = json_object_array_get_idx(json_area_array, j); + + const char* area = jh::getStringFromJson(json_area, "name"); + if (nullptr == area) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + HMI_DEBUG("wm:lm", ">> area:%s", area); + + TypeRolCtg rol_ctg_name; + role = jh::getStringFromJson(json_area, "role"); + if (nullptr == role) { + category = jh::getStringFromJson(json_area, "category"); + if (nullptr == category) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + rol_ctg_name["category"] = std::string(category); + HMI_DEBUG("wm:lm", ">>> category:%s", category); + } + else { + rol_ctg_name["role"] = std::string(role); + HMI_DEBUG("wm:lm", ">>> role:%s", role); + } + + areas[area] = rol_ctg_name; + } + + this->layout_define_[layout] = areas; + } + + // Check + for(auto itr_layout = this->layout_define_.begin(); + itr_layout != this->layout_define_.end(); ++itr_layout) { + for (auto itr_area = itr_layout->second.begin(); + itr_area != itr_layout->second.end(); ++itr_area) { + for (auto itr_role = itr_area->second.begin(); + itr_role != itr_area->second.end(); ++itr_role) { + HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s", + itr_layout->first.c_str(), itr_area->first.c_str(), + itr_role->first.c_str(), itr_role->second.c_str()); + } + } + } + + // Perse areas + HMI_DEBUG("wm:lm", "Perse areas"); + if (!json_object_object_get_ex(json_obj, "areas", &json_cfg)) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + + len = json_object_array_length(json_cfg); + HMI_DEBUG("wm:lm", "json_cfg len:%d", len); + HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg)); + + const char* area; + for (int i=0; i<len; i++) { + json_object* json_tmp = json_object_array_get_idx(json_cfg, i); + HMI_DEBUG("wm:lm", "> json_tmp dump:%s", json_object_get_string(json_tmp)); + + area = jh::getStringFromJson(json_tmp, "name"); + if (nullptr == area) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + HMI_DEBUG("wm:lm", "> area:%s", area); + + json_object* json_rect; + if (!json_object_object_get_ex(json_tmp, "rect", &json_rect)) { + HMI_ERROR("wm:lm", "Parse Error!!"); + return -1; + } + HMI_DEBUG("wm:lm", "> json_rect dump:%s", json_object_get_string(json_rect)); + + compositor::rect area_size; + area_size.x = jh::getIntFromJson(json_rect, "x"); + area_size.y = jh::getIntFromJson(json_rect, "y"); + area_size.w = jh::getIntFromJson(json_rect, "w"); + area_size.h = jh::getIntFromJson(json_rect, "h"); + + this->area2size_[area] = area_size; + } + + // Check + for(auto itr = this->area2size_.begin(); + itr != this->area2size_.end(); ++itr) { + HMI_DEBUG("wm:lm", "area:%s x:%d y:%d w:%d h:%d", + itr->first.c_str(), itr->second.x, itr->second.y, + itr->second.w, itr->second.h); + } + + // Release json_object + json_object_put(json_obj); + + return 0; +} + +const char* kDefaultLayoutDb = "{ \ + \"layouts\": [ \ + { \ + \"name\": \"pu\", \ + \"layer\": \"on_screen\", \ + \"areas\": [ \ + { \ + \"name\": \"pop_up\", \ + \"role\": \"incomming_call\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"sa\", \ + \"layer\": \"on_screen\", \ + \"areas\": [ \ + { \ + \"name\": \"system_alert\", \ + \"role\": \"system_alert\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"m1\", \ + \"layer\": \"apps\", \ + \"areas\": [ \ + { \ + \"name\": \"normal\", \ + \"role\": \"map\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"m2\", \ + \"layer\": \"apps\", \ + \"areas\": [ \ + { \ + \"name\": \"split.main\", \ + \"role\": \"map\" \ + }, \ + { \ + \"name\": \"split.sub\", \ + \"category\": \"hvac\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"mf\", \ + \"layer\": \"apps\", \ + \"areas\": [ \ + { \ + \"name\": \"full\", \ + \"role\": \"map\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"s1\", \ + \"layer\": \"apps\", \ + \"areas\": [ \ + { \ + \"name\": \"normal\", \ + \"category\": \"splitable\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"s2\", \ + \"layer\": \"apps\", \ + \"areas\": [ \ + { \ + \"name\": \"split.main\", \ + \"category\": \"splitable\" \ + }, \ + { \ + \"name\": \"split.sub\", \ + \"category\": \"splitable\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"g\", \ + \"layer\": \"apps\", \ + \"areas\": [ \ + { \ + \"name\": \"normal\", \ + \"category\": \"general\" \ + } \ + ] \ + }, \ + { \ + \"name\": \"hs\", \ + \"layer\": \"homescreen\", \ + \"areas\": [ \ + { \ + \"name\": \"full\", \ + \"role\": \"homescreen\" \ + } \ + ] \ + } \ + ], \ + \"areas\": [ \ + { \ + \"name\": \"normal\", \ + \"rect\": { \ + \"x\": 0, \ + \"y\": 218, \ + \"w\": 1080, \ + \"h\": 1488 \ + } \ + }, \ + { \ + \"name\": \"split.main\", \ + \"rect\": { \ + \"x\": 0, \ + \"y\": 218, \ + \"w\": 1080, \ + \"h\": 744 \ + } \ + }, \ + { \ + \"name\": \"split.sub\", \ + \"rect\": { \ + \"x\": 0, \ + \"y\": 962, \ + \"w\": 1080, \ + \"h\": 744 \ + } \ + }, \ + { \ + \"name\": \"full\", \ + \"rect\": { \ + \"x\": 0, \ + \"y\": 0, \ + \"w\": 1080, \ + \"h\": 1920 \ + } \ + }, \ + { \ + \"name\": \"pop_up\", \ + \"rect\": { \ + \"x\": 0, \ + \"y\": 640, \ + \"w\": 1080, \ + \"h\": 640 \ + } \ + }, \ + { \ + \"name\": \"system_alert\", \ + \"rect\": { \ + \"x\": 0, \ + \"y\": 640, \ + \"w\": 1080, \ + \"h\": 640 \ + } \ + } \ + ] \ +}"; diff --git a/src/layout_manager/layout.hpp b/src/layout_manager/layout.hpp new file mode 100644 index 0000000..bfa4a6c --- /dev/null +++ b/src/layout_manager/layout.hpp @@ -0,0 +1,84 @@ +/* + * 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 TMCAGLWM_LAYOUT_HPP +#define TMCAGLWM_LAYOUT_HPP + +#include <cstdint> +#include <string> +#include <map> +#include "result.hpp" +#include "wayland_ivi_wm.hpp" + +namespace wm { + +struct LayoutState { + int main{-1}; + int sub{-1}; + + bool operator==(const LayoutState &b) const { + return main == b.main && sub == b.sub; + } + + bool operator!=(const LayoutState &b) const { + return !(*this == b); + } +}; + +} // namespace wm + +class LayoutManager { +public: + explicit LayoutManager(); + ~LayoutManager() = default; + + typedef std::unordered_map<std::string, std::string> TypeRolCtg; + typedef std::unordered_map<std::string, TypeRolCtg> TypeAreas; + typedef std::unordered_map<std::string, TypeAreas> TypeLayouts; + typedef std::unordered_map<std::string, TypeLayouts> TypeLayers; + + int initialize(); + bool updateLayout(json_object* obj, const char* new_role, const char* new_area); + TypeLayers getCurrentLayers(); + TypeLayers getPreviousLayers(); + compositor::rect getAreaSize(const char* area); + bool isLayoutChanged(const char* layer); + + void updateArea(const char* layer, const char* role, const char* area); + +private: + // Disable copy and move + LayoutManager(LayoutManager const &) = delete; + LayoutManager &operator=(LayoutManager const &) = delete; + LayoutManager(LayoutManager &&) = delete; + LayoutManager &operator=(LayoutManager &&) = delete; + + TypeLayouts layout_define_; + std::unordered_map<std::string, compositor::rect> area2size_; + + TypeLayers crr_layers_, prv_layers_; + TypeLayers prv_layers_car_stop_; + + std::unordered_map<std::string, bool> is_layout_changed_; + + std::string getAreaName(TypeAreas area, const char* role, const char* category); + int loadLayoutDb(); + std::string role2App(std::string role, void* ptr); +}; + + + +#endif // TMCAGLWM_LAYOUT_HPP |