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 car state change
73 json_object* json_car;
74 if (!json_object_object_get_ex(obj, "car", &json_car)) {
75 HMI_ERROR("wm:lm", "Parse Error!!");
79 json_bool is_car_state_changed;
80 std::string car_state = "";
81 is_car_state_changed = jh::getBoolFromJson(json_car, "is_changed");
82 if (is_car_state_changed) {
83 // If car state is changed, get car state
84 car_state = jh::getStringFromJson(json_car, "state");
87 // Check restriction mode change
88 json_object* json_restriction_mode;
89 if (!json_object_object_get_ex(obj, "restriction_mode", &json_restriction_mode)) {
90 HMI_ERROR("wm:lm", "Parse Error!!");
94 json_bool is_restriction_mode_changed;
95 std::string restriction_mode = "";
96 is_restriction_mode_changed = jh::getBoolFromJson(json_restriction_mode, "is_changed");
97 if (is_restriction_mode_changed) {
98 // If restriction mode is changed, get restriction mode
99 restriction_mode = jh::getStringFromJson(json_restriction_mode, "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;
130 // If restriction mode is changed off -> on,
131 // store current state for state of restriction mode off
132 if ((is_restriction_mode_changed) && ("restriction_mode_on" == restriction_mode)) {
133 HMI_DEBUG("wm:lm", "Store current state for state of restriction mode off");
134 this->prv_layers_car_stop_[layer] = this->crr_layers_[layer];
137 // If car state is changed car_stop -> car_run,
138 // store current state for state of car stop
139 if ((is_car_state_changed) && ("car_run" == car_state)) {
140 HMI_DEBUG("wm:lm", "Store current state for state of car stop");
141 this->prv_layers_car_stop_[layer] = this->crr_layers_[layer];
145 json_object* json_is_changed;
146 if (!json_object_object_get_ex(json_layer, "is_changed", &json_is_changed)) {
147 HMI_ERROR("wm:lm", "Not found key \"is_changed\"");
151 // If layer state is changed
152 if (json_object_get_boolean(json_is_changed)) {
153 // Set layout changed flag
154 this->is_layout_changed_[layer] = true;
156 json_object* json_state;
157 if (!json_object_object_get_ex(json_layer, "state", &json_state)) {
158 HMI_ERROR("wm:lm", "Not found key \"state\"");
162 const char* crr_layout_name = json_object_get_string(json_state);
163 HMI_DEBUG("wm:lm", "crr state: %s", crr_layout_name);
165 TypeLayouts crr_layout;
167 if ((is_restriction_mode_changed) && ("restriction_mode_off" == restriction_mode)) {
168 // If restriction mode is changed on -> off,
169 // restore state of restriction mode off
170 HMI_DEBUG("wm:lm", "Restriction mode is changed on -> off, so restore state of restriction mode off");
171 crr_layout = this->prv_layers_car_stop_[layer];
173 if ((is_car_state_changed) && ("car_stop" == car_state)) {
174 // If car state is changed car_run -> car_stop,
175 // restore state of car stop
176 HMI_DEBUG("wm:lm", "Car state is changed car_run -> car_stop, so restore state of car stop");
177 crr_layout = this->prv_layers_car_stop_[layer];
180 else if ("none" == std::string(crr_layout_name)) {
181 // If current layout is "none",
182 // current areas is set with "none"
183 HMI_DEBUG("wm:lm", "Current layout is \"none\"");
186 rol_ctg["none"] = "none";
187 area["none"] = rol_ctg;
188 crr_layout["none"] = area;
191 if (std::string(crr_layout_name) == prv_layout_name) {
192 // If previous layout is same with current,
193 // previous areas are copied to current
194 HMI_DEBUG("wm:lm", "Previous layout is same with current");
195 crr_layout[crr_layout_name] = this->prv_layers_[layer][crr_layout_name];
198 // If previous layout is NOT same with current,
199 // current areas is set with default value
200 HMI_DEBUG("wm:lm", "Previous layout is NOT same with current");
201 crr_layout[crr_layout_name] = this->layout_define_[crr_layout_name];
204 // Update role in new area
206 if (is_restriction_mode_changed) {
207 // Updating role is not necessary
208 // because new_role is not specified
209 // when restriction mode is changed
210 HMI_DEBUG("wm:lm", "Updating role is not necessary because new_role is not specified when restriction mode is changed");
212 if (is_car_state_changed) {
213 // Updating role is not necessary
214 // because new_role is not specified
215 // when car state is changed
216 HMI_DEBUG("wm:lm", "Updating role is not necessary because new_role is not specified when car state is changed");
220 HMI_DEBUG("wm:lm", "Get new_area for new role");
221 // Get new_area for new role
222 std::string new_area = this->getAreaName(this->layout_define_[crr_layout_name],
225 if ("none" == new_area) {
226 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");
229 // Update role in new area
230 // because new_role is specified for this layer
232 crr_role["role"] = std::string(new_role);
233 crr_layout[crr_layout_name][new_area] = crr_role;
238 // Update layer state
239 this->crr_layers_[layer] = crr_layout;
242 for (auto itr_layout = this->crr_layers_[layer].begin();
243 itr_layout != this->crr_layers_[layer].end(); ++itr_layout) {
244 for (auto itr_area = itr_layout->second.begin();
245 itr_area != itr_layout->second.end(); ++itr_area) {
246 for (auto itr_role = itr_area->second.begin();
247 itr_role != itr_area->second.end(); ++itr_role) {
248 HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s",
249 itr_layout->first.c_str(), itr_area->first.c_str(),
250 itr_role->first.c_str(), itr_role->second.c_str());
258 // Clear layout changed flag
259 this->is_layout_changed_[layer] = false;
265 // TODO: This API is for workaround, so this will be removed
266 void LayoutManager::updateArea(const char* layer, const char* role, const char* area) {
267 this->crr_layers_[layer].begin()->second[area]["role"] = std::string(role);
270 LayoutManager::TypeLayers LayoutManager::getCurrentLayers() {
271 return this->crr_layers_;
274 LayoutManager::TypeLayers LayoutManager::getPreviousLayers() {
275 return this->prv_layers_;
278 compositor::rect LayoutManager::getAreaSize(const char* area) {
279 return this->area2size_[area];
282 std::string LayoutManager::getAreaName(TypeAreas areas, const char* role, const char* category) {
283 for (auto itr_area = areas.begin(); itr_area != areas.end(); ++itr_area) {
284 std::string area_name = itr_area->first;
285 TypeRolCtg rol_ctg = itr_area->second;
287 if ("role" == rol_ctg.begin()->first) {
288 if (std::string(role) == rol_ctg.begin()->second) {
292 else if ("category" == rol_ctg.begin()->first) {
293 if (std::string(category) == rol_ctg.begin()->second) {
298 return std::string("none");
301 return std::string("none");
305 bool LayoutManager::isLayoutChanged(const char* layer) {
306 return this->is_layout_changed_[layer];
310 extern const char* kDefaultLayoutDb;
311 int LayoutManager::loadLayoutDb() {
312 HMI_DEBUG("wm:lm", "Call");
314 // Get afm application installed dir
315 char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
316 HMI_DEBUG("wm:lm", "afm_app_install_dir:%s", afm_app_install_dir);
318 std::string file_name;
319 if (!afm_app_install_dir) {
320 HMI_ERROR("wm:lm", "AFM_APP_INSTALL_DIR is not defined");
323 file_name = std::string(afm_app_install_dir) + std::string("/etc/layout.db");
327 json_object* json_obj;
328 int ret = jh::inputJsonFilie(file_name.c_str(), &json_obj);
330 HMI_DEBUG("wm:lm", "Could not open layout.db, so use default layout information");
331 json_obj = json_tokener_parse(kDefaultLayoutDb);
333 HMI_DEBUG("wm:lm", "json_obj dump:%s", json_object_get_string(json_obj));
336 HMI_DEBUG("wm:lm", "Perse layouts");
337 json_object* json_cfg;
338 if (!json_object_object_get_ex(json_obj, "layouts", &json_cfg)) {
339 HMI_ERROR("wm:lm", "Parse Error!!");
343 int len = json_object_array_length(json_cfg);
344 HMI_DEBUG("wm:lm", "json_cfg len:%d", len);
345 HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg));
349 const char* category;
350 for (int i=0; i<len; i++) {
351 json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
353 layout = jh::getStringFromJson(json_tmp, "name");
354 if (nullptr == layout) {
355 HMI_ERROR("wm:lm", "Parse Error!!");
358 HMI_DEBUG("wm:lm", "> layout:%s", layout);
360 json_object* json_area_array;
361 if (!json_object_object_get_ex(json_tmp, "areas", &json_area_array)) {
362 HMI_ERROR("wm:lm", "Parse Error!!");
366 int len_area = json_object_array_length(json_area_array);
367 HMI_DEBUG("wm:lm", "json_area_array len:%d", len_area);
368 HMI_DEBUG("wm:lm", "json_area_array dump:%s", json_object_get_string(json_area_array));
371 for (int j=0; j<len_area; j++) {
372 json_object* json_area = json_object_array_get_idx(json_area_array, j);
374 const char* area = jh::getStringFromJson(json_area, "name");
375 if (nullptr == area) {
376 HMI_ERROR("wm:lm", "Parse Error!!");
379 HMI_DEBUG("wm:lm", ">> area:%s", area);
381 TypeRolCtg rol_ctg_name;
382 role = jh::getStringFromJson(json_area, "role");
383 if (nullptr == role) {
384 category = jh::getStringFromJson(json_area, "category");
385 if (nullptr == category) {
386 HMI_ERROR("wm:lm", "Parse Error!!");
389 rol_ctg_name["category"] = std::string(category);
390 HMI_DEBUG("wm:lm", ">>> category:%s", category);
393 rol_ctg_name["role"] = std::string(role);
394 HMI_DEBUG("wm:lm", ">>> role:%s", role);
397 areas[area] = rol_ctg_name;
400 this->layout_define_[layout] = areas;
404 for(auto itr_layout = this->layout_define_.begin();
405 itr_layout != this->layout_define_.end(); ++itr_layout) {
406 for (auto itr_area = itr_layout->second.begin();
407 itr_area != itr_layout->second.end(); ++itr_area) {
408 for (auto itr_role = itr_area->second.begin();
409 itr_role != itr_area->second.end(); ++itr_role) {
410 HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s",
411 itr_layout->first.c_str(), itr_area->first.c_str(),
412 itr_role->first.c_str(), itr_role->second.c_str());
418 HMI_DEBUG("wm:lm", "Perse areas");
419 if (!json_object_object_get_ex(json_obj, "areas", &json_cfg)) {
420 HMI_ERROR("wm:lm", "Parse Error!!");
424 len = json_object_array_length(json_cfg);
425 HMI_DEBUG("wm:lm", "json_cfg len:%d", len);
426 HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg));
429 for (int i=0; i<len; i++) {
430 json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
431 HMI_DEBUG("wm:lm", "> json_tmp dump:%s", json_object_get_string(json_tmp));
433 area = jh::getStringFromJson(json_tmp, "name");
434 if (nullptr == area) {
435 HMI_ERROR("wm:lm", "Parse Error!!");
438 HMI_DEBUG("wm:lm", "> area:%s", area);
440 json_object* json_rect;
441 if (!json_object_object_get_ex(json_tmp, "rect", &json_rect)) {
442 HMI_ERROR("wm:lm", "Parse Error!!");
445 HMI_DEBUG("wm:lm", "> json_rect dump:%s", json_object_get_string(json_rect));
447 compositor::rect area_size;
448 area_size.x = jh::getIntFromJson(json_rect, "x");
449 area_size.y = jh::getIntFromJson(json_rect, "y");
450 area_size.w = jh::getIntFromJson(json_rect, "w");
451 area_size.h = jh::getIntFromJson(json_rect, "h");
453 this->area2size_[area] = area_size;
457 for(auto itr = this->area2size_.begin();
458 itr != this->area2size_.end(); ++itr) {
459 HMI_DEBUG("wm:lm", "area:%s x:%d y:%d w:%d h:%d",
460 itr->first.c_str(), itr->second.x, itr->second.y,
461 itr->second.w, itr->second.h);
464 // Release json_object
465 json_object_put(json_obj);
470 const char* kDefaultLayoutDb = "{ \
474 \"layer\": \"on_screen\", \
477 \"name\": \"pop_up\", \
478 \"role\": \"incomming_call\" \
484 \"layer\": \"on_screen\", \
487 \"name\": \"system_alert\", \
488 \"role\": \"system_alert\" \
494 \"layer\": \"apps\", \
497 \"name\": \"normal\", \
504 \"layer\": \"apps\", \
507 \"name\": \"split.main\", \
511 \"name\": \"split.sub\", \
512 \"category\": \"hvac\" \
518 \"layer\": \"apps\", \
521 \"name\": \"full\", \
528 \"layer\": \"apps\", \
531 \"name\": \"normal\", \
532 \"category\": \"splitable\" \
538 \"layer\": \"apps\", \
541 \"name\": \"split.main\", \
542 \"category\": \"splitable\" \
545 \"name\": \"split.sub\", \
546 \"category\": \"splitable\" \
552 \"layer\": \"apps\", \
555 \"name\": \"normal\", \
556 \"category\": \"general\" \
562 \"layer\": \"homescreen\", \
565 \"name\": \"full\", \
566 \"role\": \"homescreen\" \
573 \"name\": \"normal\", \
582 \"name\": \"split.main\", \
591 \"name\": \"split.sub\", \
600 \"name\": \"full\", \
609 \"name\": \"pop_up\", \
618 \"name\": \"system_alert\", \