/* * 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->prv_layers_["restriction"] = layout; this->crr_layers_["on_screen"] = layout; this->crr_layers_["apps"] = layout; this->crr_layers_["homescreen"] = layout; this->crr_layers_["restriction"] = layout; this->prv_layers_car_stop_["on_screen"] = layout; this->prv_layers_car_stop_["apps"] = layout; this->prv_layers_car_stop_["homescreen"] = layout; this->prv_layers_car_stop_["restriction"] = 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"); } // Check restriction mode change json_object* json_restriction_mode; if (!json_object_object_get_ex(obj, "restriction_mode", &json_restriction_mode)) { HMI_ERROR("wm:lm", "Parse Error!!"); return -1; } json_bool is_restriction_mode_changed; std::string restriction_mode = ""; is_restriction_mode_changed = jh::getBoolFromJson(json_restriction_mode, "is_changed"); if (is_restriction_mode_changed) { // If restriction mode is changed, get restriction mode restriction_mode = jh::getStringFromJson(json_restriction_mode, "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 1 // If restriction mode is changed off -> on, // store current state for state of restriction mode off if ((is_restriction_mode_changed) && ("restriction_mode_on" == restriction_mode)) { HMI_DEBUG("wm:lm", "Store current state for state of restriction mode off"); this->prv_layers_car_stop_[layer] = this->crr_layers_[layer]; } #else // 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]; } #endif 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 1 if ((is_restriction_mode_changed) && ("restriction_mode_off" == restriction_mode)) { // If restriction mode is changed on -> off, // restore state of restriction mode off HMI_DEBUG("wm:lm", "Restriction mode is changed on -> off, so restore state of restriction mode off"); crr_layout = this->prv_layers_car_stop_[layer]; #else 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", "Car state is changed car_run -> car_stop, so restore state of car stop"); crr_layout = this->prv_layers_car_stop_[layer]; #endif } else if ("none" == std::string(crr_layout_name)) { // If current layout is "none", // current areas is set with "none" HMI_DEBUG("wm:lm", "Current layout is \"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 HMI_DEBUG("wm:lm", "Previous layout is same with 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 HMI_DEBUG("wm:lm", "Previous layout is NOT same with current"); crr_layout[crr_layout_name] = this->layout_define_[crr_layout_name]; } // Update role in new area #if 1 if (is_restriction_mode_changed) { // Updating role is not necessary // because new_role is not specified // when restriction mode is changed HMI_DEBUG("wm:lm", "Updating role is not necessary because new_role is not specified when restriction mode is changed"); #else if (is_car_state_changed) { // Updating role is not necessary // because new_role is not specified // when car state is changed HMI_DEBUG("wm:lm", "Updating role is not necessary because new_role is not specified when car state is changed"); #endif } else { HMI_DEBUG("wm:lm", "Get new_area for new role"); // Get new_area for new role std::string new_area = this->getAreaName(this->layout_define_[crr_layout_name], new_role, category); if ("none" == new_area) { HMI_DEBUG("wm:lm", "It is not necessary to update role of areas in this layer, because new_role is not specified for this layer"); } else { // Update role in new area // because new_role is specified for this layer 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 json_object* json_obj; int ret = jh::inputJsonFilie(file_name.c_str(), &json_obj); if (0 > ret) { HMI_DEBUG("wm:lm", "Could not open layout.db, so use default layout 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 \ } \ } \ ] \ }";