From 55be85ed4bdfea6fc037d781b8cd8f58487718d1 Mon Sep 17 00:00:00 2001 From: Yuta Doi Date: Fri, 27 Apr 2018 19:01:36 +0900 Subject: 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 --- src/layout_manager/layout.cpp | 570 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 570 insertions(+) create mode 100644 src/layout_manager/layout.cpp (limited to 'src/layout_manager/layout.cpp') 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 +#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; iprv_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 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> 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 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 \ + } \ + } \ + ] \ +}"; -- cgit 1.2.3-korg