2 * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <json-c/json.h>
20 #include "json_helper.hpp"
21 #include "hmi-debug.h"
24 LayoutManager::LayoutManager() {
25 HMI_DEBUG("wm:lm", "Call");
28 int LayoutManager::initialize() {
29 HMI_DEBUG("wm:lm", "Call");
34 ret = this->loadLayoutDb();
36 HMI_ERROR("wm:lm", "Load layout.db Error!!");
44 rol_ctg["none"] = "none";
45 area["none"] = rol_ctg;
46 layout["none"] = area;
48 this->prv_layers_["on_screen"] = layout;
49 this->prv_layers_["apps"] = layout;
50 this->prv_layers_["homescreen"] = layout;
51 this->prv_layers_["restriction"] = layout;
53 this->crr_layers_["on_screen"] = layout;
54 this->crr_layers_["apps"] = layout;
55 this->crr_layers_["homescreen"] = layout;
56 this->crr_layers_["restriction"] = layout;
58 this->prv_layers_car_stop_["on_screen"] = layout;
59 this->prv_layers_car_stop_["apps"] = layout;
60 this->prv_layers_car_stop_["homescreen"] = layout;
61 this->prv_layers_car_stop_["restriction"] = layout;
66 bool LayoutManager::updateLayout(json_object* obj,
67 const char* new_role, const char* category) {
68 HMI_DEBUG("wm:lm", "Call");
72 // Check accelerator pedal state change
73 json_object* json_accel_pedal;
74 if (!json_object_object_get_ex(obj, "accel_pedal", &json_accel_pedal)) {
75 HMI_ERROR("wm:lm", "Parse Error!!");
79 json_bool is_accel_pedal_state_changed;
80 std::string accel_pedal_state = "";
81 is_accel_pedal_state_changed = jh::getBoolFromJson(json_accel_pedal, "is_changed");
82 if (is_accel_pedal_state_changed) {
83 // If car state is changed, get car state
84 accel_pedal_state = jh::getStringFromJson(json_accel_pedal, "state");
87 // Check car state change
88 json_object* json_car;
89 if (!json_object_object_get_ex(obj, "car", &json_car)) {
90 HMI_ERROR("wm:lm", "Parse Error!!");
94 json_bool is_car_state_changed;
95 std::string car_state = "";
96 is_car_state_changed = jh::getBoolFromJson(json_car, "is_changed");
97 if (is_car_state_changed) {
98 // If car state is changed, get car state
99 car_state = jh::getStringFromJson(json_car, "state");
102 // Update layout of all layers
103 json_object* json_layers;
104 if (!json_object_object_get_ex(obj, "layers", &json_layers)) {
105 HMI_ERROR("wm:lm", "Parse Error!!");
109 int len = json_object_array_length(json_layers);
110 HMI_DEBUG("wm:lm", "json_layers len:%d", len);
111 HMI_DEBUG("wm:lm", "json_layers dump:%s", json_object_get_string(json_layers));
113 for (int i=0; i<len; i++) {
114 json_object* json_tmp = json_object_array_get_idx(json_layers, i);
116 // Get layer name and json_object
118 json_object* json_layer;
119 json_object_object_foreach(json_tmp, key, val) {
122 HMI_DEBUG("wm:lm", "Try to update %s layer state", layer);
125 // Store previous state
126 this->prv_layers_[layer] = this->crr_layers_[layer];
127 std::string prv_layout_name = this->prv_layers_[layer].begin()->first;
129 // If car state is changed car_stop -> car_run,
130 // OR accel pedal state is changed accel_pedal_off -> accel_pedal_on,
131 // store current state for state of car stop
132 if (((is_car_state_changed) && ("car_run" == car_state))
133 || ((is_accel_pedal_state_changed)
134 && ("accel_pedal_on" == accel_pedal_state))) {
135 HMI_DEBUG("wm:lm", "Store current state for state of car stop");
136 this->prv_layers_car_stop_[layer] = this->crr_layers_[layer];
139 json_object* json_is_changed;
140 if (!json_object_object_get_ex(json_layer, "is_changed", &json_is_changed)) {
141 HMI_ERROR("wm:lm", "Not found key \"is_changed\"");
145 // If layer state is changed
146 if (json_object_get_boolean(json_is_changed)) {
147 // Set layout changed flag
148 this->is_layout_changed_[layer] = true;
150 json_object* json_state;
151 if (!json_object_object_get_ex(json_layer, "state", &json_state)) {
152 HMI_ERROR("wm:lm", "Not found key \"state\"");
156 const char* crr_layout_name = json_object_get_string(json_state);
157 HMI_DEBUG("wm:lm", "crr state: %s", crr_layout_name);
159 TypeLayouts crr_layout;
160 if (((is_car_state_changed) && ("car_stop" == car_state))
161 || ((is_accel_pedal_state_changed)
162 && ("accel_pedal_off" == accel_pedal_state))) {
163 // If car state is changed car_run -> car_stop,
164 // OR accel pedal state is changed accel_pedal_on -> accel_pedal_off,
165 // restore state of car stop
166 HMI_DEBUG("wm:lm", "Restore state of car stop");
167 crr_layout = this->prv_layers_car_stop_[layer];
169 else if ("none" == std::string(crr_layout_name)) {
170 // If current layout is "none",
171 // current areas is set with "none"
174 rol_ctg["none"] = "none";
175 area["none"] = rol_ctg;
176 crr_layout["none"] = area;
179 if (std::string(crr_layout_name) == prv_layout_name) {
180 // If previous layout is same with current,
181 // previous areas are copied to current
182 crr_layout[crr_layout_name] = this->prv_layers_[layer][crr_layout_name];
185 // If previous layout is NOT same with current,
186 // current areas is set with default value
187 crr_layout[crr_layout_name] = this->layout_define_[crr_layout_name];
190 // Update role in new area
191 if (is_car_state_changed || is_accel_pedal_state_changed) {
192 // Updating role is not necessary
193 // because new_role is not specified
194 // when car or accel pedal state is changed
197 // Get new_area for new role
198 std::string new_area = this->getAreaName(this->layout_define_[crr_layout_name],
202 crr_role["role"] = std::string(new_role);
203 crr_layout[crr_layout_name][new_area] = crr_role;
207 // Update layer state
208 this->crr_layers_[layer] = crr_layout;
211 for (auto itr_layout = this->crr_layers_[layer].begin();
212 itr_layout != this->crr_layers_[layer].end(); ++itr_layout) {
213 for (auto itr_area = itr_layout->second.begin();
214 itr_area != itr_layout->second.end(); ++itr_area) {
215 for (auto itr_role = itr_area->second.begin();
216 itr_role != itr_area->second.end(); ++itr_role) {
217 HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s",
218 itr_layout->first.c_str(), itr_area->first.c_str(),
219 itr_role->first.c_str(), itr_role->second.c_str());
227 // Clear layout changed flag
228 this->is_layout_changed_[layer] = false;
234 // TODO: This API is for workaround, so this will be removed
235 void LayoutManager::updateArea(const char* layer, const char* role, const char* area) {
236 this->crr_layers_[layer].begin()->second[area]["role"] = std::string(role);
239 LayoutManager::TypeLayers LayoutManager::getCurrentLayers() {
240 return this->crr_layers_;
243 LayoutManager::TypeLayers LayoutManager::getPreviousLayers() {
244 return this->prv_layers_;
247 compositor::rect LayoutManager::getAreaSize(const char* area) {
248 return this->area2size_[area];
251 std::string LayoutManager::getAreaName(TypeAreas areas, const char* role, const char* category) {
252 for (auto itr_area = areas.begin(); itr_area != areas.end(); ++itr_area) {
253 std::string area_name = itr_area->first;
254 TypeRolCtg rol_ctg = itr_area->second;
256 if ("role" == rol_ctg.begin()->first) {
257 if (std::string(role) == rol_ctg.begin()->second) {
261 else if ("category" == rol_ctg.begin()->first) {
262 if (std::string(category) == rol_ctg.begin()->second) {
267 return std::string("none");
270 return std::string("none");
274 bool LayoutManager::isLayoutChanged(const char* layer) {
275 return this->is_layout_changed_[layer];
279 extern const char* kDefaultLayoutDb;
280 int LayoutManager::loadLayoutDb() {
281 HMI_DEBUG("wm:lm", "Call");
283 // Get afm application installed dir
284 char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
285 HMI_DEBUG("wm:lm", "afm_app_install_dir:%s", afm_app_install_dir);
287 std::string file_name;
288 if (!afm_app_install_dir) {
289 HMI_ERROR("wm:lm", "AFM_APP_INSTALL_DIR is not defined");
292 file_name = std::string(afm_app_install_dir) + std::string("/etc/layout.db");
296 json_object* json_obj;
297 int ret = jh::inputJsonFilie(file_name.c_str(), &json_obj);
299 HMI_DEBUG("wm:lm", "Could not open layout.db, so use default layout information");
300 json_obj = json_tokener_parse(kDefaultLayoutDb);
302 HMI_DEBUG("wm:lm", "json_obj dump:%s", json_object_get_string(json_obj));
305 HMI_DEBUG("wm:lm", "Perse layouts");
306 json_object* json_cfg;
307 if (!json_object_object_get_ex(json_obj, "layouts", &json_cfg)) {
308 HMI_ERROR("wm:lm", "Parse Error!!");
312 int len = json_object_array_length(json_cfg);
313 HMI_DEBUG("wm:lm", "json_cfg len:%d", len);
314 HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg));
318 const char* category;
319 for (int i=0; i<len; i++) {
320 json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
322 layout = jh::getStringFromJson(json_tmp, "name");
323 if (nullptr == layout) {
324 HMI_ERROR("wm:lm", "Parse Error!!");
327 HMI_DEBUG("wm:lm", "> layout:%s", layout);
329 json_object* json_area_array;
330 if (!json_object_object_get_ex(json_tmp, "areas", &json_area_array)) {
331 HMI_ERROR("wm:lm", "Parse Error!!");
335 int len_area = json_object_array_length(json_area_array);
336 HMI_DEBUG("wm:lm", "json_area_array len:%d", len_area);
337 HMI_DEBUG("wm:lm", "json_area_array dump:%s", json_object_get_string(json_area_array));
340 for (int j=0; j<len_area; j++) {
341 json_object* json_area = json_object_array_get_idx(json_area_array, j);
343 const char* area = jh::getStringFromJson(json_area, "name");
344 if (nullptr == area) {
345 HMI_ERROR("wm:lm", "Parse Error!!");
348 HMI_DEBUG("wm:lm", ">> area:%s", area);
350 TypeRolCtg rol_ctg_name;
351 role = jh::getStringFromJson(json_area, "role");
352 if (nullptr == role) {
353 category = jh::getStringFromJson(json_area, "category");
354 if (nullptr == category) {
355 HMI_ERROR("wm:lm", "Parse Error!!");
358 rol_ctg_name["category"] = std::string(category);
359 HMI_DEBUG("wm:lm", ">>> category:%s", category);
362 rol_ctg_name["role"] = std::string(role);
363 HMI_DEBUG("wm:lm", ">>> role:%s", role);
366 areas[area] = rol_ctg_name;
369 this->layout_define_[layout] = areas;
373 for(auto itr_layout = this->layout_define_.begin();
374 itr_layout != this->layout_define_.end(); ++itr_layout) {
375 for (auto itr_area = itr_layout->second.begin();
376 itr_area != itr_layout->second.end(); ++itr_area) {
377 for (auto itr_role = itr_area->second.begin();
378 itr_role != itr_area->second.end(); ++itr_role) {
379 HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s",
380 itr_layout->first.c_str(), itr_area->first.c_str(),
381 itr_role->first.c_str(), itr_role->second.c_str());
387 HMI_DEBUG("wm:lm", "Perse areas");
388 if (!json_object_object_get_ex(json_obj, "areas", &json_cfg)) {
389 HMI_ERROR("wm:lm", "Parse Error!!");
393 len = json_object_array_length(json_cfg);
394 HMI_DEBUG("wm:lm", "json_cfg len:%d", len);
395 HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg));
398 for (int i=0; i<len; i++) {
399 json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
400 HMI_DEBUG("wm:lm", "> json_tmp dump:%s", json_object_get_string(json_tmp));
402 area = jh::getStringFromJson(json_tmp, "name");
403 if (nullptr == area) {
404 HMI_ERROR("wm:lm", "Parse Error!!");
407 HMI_DEBUG("wm:lm", "> area:%s", area);
409 json_object* json_rect;
410 if (!json_object_object_get_ex(json_tmp, "rect", &json_rect)) {
411 HMI_ERROR("wm:lm", "Parse Error!!");
414 HMI_DEBUG("wm:lm", "> json_rect dump:%s", json_object_get_string(json_rect));
416 compositor::rect area_size;
417 area_size.x = jh::getIntFromJson(json_rect, "x");
418 area_size.y = jh::getIntFromJson(json_rect, "y");
419 area_size.w = jh::getIntFromJson(json_rect, "w");
420 area_size.h = jh::getIntFromJson(json_rect, "h");
422 this->area2size_[area] = area_size;
426 for(auto itr = this->area2size_.begin();
427 itr != this->area2size_.end(); ++itr) {
428 HMI_DEBUG("wm:lm", "area:%s x:%d y:%d w:%d h:%d",
429 itr->first.c_str(), itr->second.x, itr->second.y,
430 itr->second.w, itr->second.h);
433 // Release json_object
434 json_object_put(json_obj);
439 const char* kDefaultLayoutDb = "{ \
443 \"layer\": \"on_screen\", \
446 \"name\": \"pop_up\", \
447 \"role\": \"incomming_call\" \
453 \"layer\": \"on_screen\", \
456 \"name\": \"system_alert\", \
457 \"role\": \"system_alert\" \
463 \"layer\": \"apps\", \
466 \"name\": \"normal\", \
473 \"layer\": \"apps\", \
476 \"name\": \"split.main\", \
480 \"name\": \"split.sub\", \
481 \"category\": \"hvac\" \
487 \"layer\": \"apps\", \
490 \"name\": \"full\", \
497 \"layer\": \"apps\", \
500 \"name\": \"normal\", \
501 \"category\": \"splitable\" \
507 \"layer\": \"apps\", \
510 \"name\": \"split.main\", \
511 \"category\": \"splitable\" \
514 \"name\": \"split.sub\", \
515 \"category\": \"splitable\" \
521 \"layer\": \"apps\", \
524 \"name\": \"normal\", \
525 \"category\": \"general\" \
531 \"layer\": \"homescreen\", \
534 \"name\": \"full\", \
535 \"role\": \"homescreen\" \
542 \"name\": \"normal\", \
551 \"name\": \"split.main\", \
560 \"name\": \"split.sub\", \
569 \"name\": \"full\", \
578 \"name\": \"pop_up\", \
587 \"name\": \"system_alert\", \