Add new roles and remove unnecessary role definition
[apps/agl-service-windowmanager.git] / src / layout_manager / layout.cpp
1 /*
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17
18 #include <json-c/json.h>
19 #include "layout.hpp"
20 #include "json_helper.hpp"
21 #include "hmi-debug.h"
22
23
24 LayoutManager::LayoutManager() {
25     HMI_DEBUG("wm:lm", "Call");
26 }
27
28 int LayoutManager::initialize() {
29     HMI_DEBUG("wm:lm", "Call");
30
31     int ret = 0;
32
33     // Load layout.db
34     ret = this->loadLayoutDb();
35     if (0 > ret) {
36         HMI_ERROR("wm:lm", "Load layout.db Error!!");
37         return ret;
38     }
39
40     TypeLayouts layout;
41     TypeAreas area;
42     TypeRolCtg rol_ctg;
43
44     rol_ctg["none"] = "none";
45     area["none"]    = rol_ctg;
46     layout["none"]  = area;
47
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;
52
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;
57
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;
62
63     return ret;
64 }
65
66 bool LayoutManager::updateLayout(json_object* obj,
67                                      const char* new_role, const char* category) {
68     HMI_DEBUG("wm:lm", "Call");
69
70     bool ret = false;
71
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!!");
76         return -1;
77     }
78
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");
85     }
86
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!!");
91         return -1;
92     }
93
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");
100     }
101
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!!");
106         return -1;
107     }
108
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));
112
113     for (int i=0; i<len; i++) {
114         json_object* json_tmp = json_object_array_get_idx(json_layers, i);
115
116         // Get layer name and json_object
117         const char* layer;
118         json_object* json_layer;
119         json_object_object_foreach(json_tmp, key, val) {
120             layer = key;
121             json_layer = val;
122             HMI_DEBUG("wm:lm", "Try to update %s layer state", layer);
123         }
124
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;
128
129 #if 1
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];
135         }
136 #else
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];
142         }
143 #endif
144
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\"");
148            return false;
149         }
150
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;
155
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\"");
159                 return false;
160             }
161
162             const char* crr_layout_name = json_object_get_string(json_state);
163             HMI_DEBUG("wm:lm", "crr state: %s", crr_layout_name);
164
165             TypeLayouts crr_layout;
166 #if 1
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];
172 #else
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];
178 #endif
179             }
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\"");
184                 TypeAreas area;
185                 TypeRolCtg rol_ctg;
186                 rol_ctg["none"] = "none";
187                 area["none"] = rol_ctg;
188                 crr_layout["none"] = area;
189             }
190             else {
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];
196                 }
197                 else {
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];
202                 }
203
204                 // Update role in new area
205 #if 1
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");
211 #else
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");
217 #endif
218                 }
219                 else {
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],
223                                                              new_role, category);
224
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");
227                     }
228                     else {
229                         // Update role in new area
230                         // because new_role is specified for this layer
231                         TypeRolCtg crr_role;
232                         crr_role["role"] = std::string(new_role);
233                         crr_layout[crr_layout_name][new_area] = crr_role;
234                     }
235                 }
236             }
237
238             // Update layer state
239             this->crr_layers_[layer] = crr_layout;
240
241             // Check
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());
251                 }
252               }
253             }
254
255             ret = true;
256         }
257         else {
258             // Clear layout changed flag
259             this->is_layout_changed_[layer] = false;
260         }
261     }
262     return ret;
263 }
264
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);
268 }
269
270 LayoutManager::TypeLayers LayoutManager::getCurrentLayers() {
271     return this->crr_layers_;
272 }
273
274 LayoutManager::TypeLayers LayoutManager::getPreviousLayers() {
275     return this->prv_layers_;
276 }
277
278 compositor::rect LayoutManager::getAreaSize(const char* area) {
279     return this->area2size_[area];
280 }
281
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;
286
287         if ("role" == rol_ctg.begin()->first) {
288             if (std::string(role) == rol_ctg.begin()->second) {
289                 return area_name;
290             }
291         }
292         else if ("category" == rol_ctg.begin()->first) {
293             if (std::string(category) == rol_ctg.begin()->second) {
294                 return area_name;
295             }
296         }
297         else {
298             return std::string("none");
299         }
300     }
301     return std::string("none");
302 }
303
304
305 bool LayoutManager::isLayoutChanged(const char* layer) {
306     return this->is_layout_changed_[layer];
307 }
308
309
310 extern const char* kDefaultLayoutDb;
311 int LayoutManager::loadLayoutDb() {
312     HMI_DEBUG("wm:lm", "Call");
313
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);
317
318     std::string file_name;
319     if (!afm_app_install_dir) {
320         HMI_ERROR("wm:lm", "AFM_APP_INSTALL_DIR is not defined");
321     }
322     else {
323         file_name = std::string(afm_app_install_dir) + std::string("/etc/layout.db");
324     }
325
326     // Load layout.db
327     json_object* json_obj;
328     int ret = jh::inputJsonFilie(file_name.c_str(), &json_obj);
329     if (0 > ret) {
330         HMI_DEBUG("wm:lm", "Could not open layout.db, so use default layout information");
331         json_obj = json_tokener_parse(kDefaultLayoutDb);
332     }
333     HMI_DEBUG("wm:lm", "json_obj dump:%s", json_object_get_string(json_obj));
334
335     // Perse layouts
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!!");
340         return -1;
341     }
342
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));
346
347     const char* layout;
348     const char* role;
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);
352
353         layout = jh::getStringFromJson(json_tmp, "name");
354         if (nullptr == layout) {
355             HMI_ERROR("wm:lm", "Parse Error!!");
356             return -1;
357         }
358         HMI_DEBUG("wm:lm", "> layout:%s", layout);
359
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!!");
363           return -1;
364         }
365
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));
369
370         TypeAreas areas;
371         for (int j=0; j<len_area; j++) {
372             json_object* json_area = json_object_array_get_idx(json_area_array, j);
373
374             const char* area = jh::getStringFromJson(json_area, "name");
375             if (nullptr == area) {
376               HMI_ERROR("wm:lm", "Parse Error!!");
377               return -1;
378             }
379             HMI_DEBUG("wm:lm", ">> area:%s", area);
380
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!!");
387                   return -1;
388                 }
389                 rol_ctg_name["category"] = std::string(category);
390                 HMI_DEBUG("wm:lm", ">>> category:%s", category);
391             }
392             else {
393                 rol_ctg_name["role"] = std::string(role);
394                 HMI_DEBUG("wm:lm", ">>> role:%s", role);
395             }
396
397             areas[area] = rol_ctg_name;
398         }
399
400         this->layout_define_[layout] = areas;
401     }
402
403     // Check
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());
413             }
414         }
415     }
416
417     // Perse areas
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!!");
421         return -1;
422     }
423
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));
427
428     const char* area;
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));
432
433         area = jh::getStringFromJson(json_tmp, "name");
434         if (nullptr == area) {
435             HMI_ERROR("wm:lm", "Parse Error!!");
436             return -1;
437         }
438         HMI_DEBUG("wm:lm", "> area:%s", area);
439
440         json_object* json_rect;
441         if (!json_object_object_get_ex(json_tmp, "rect", &json_rect)) {
442           HMI_ERROR("wm:lm", "Parse Error!!");
443           return -1;
444         }
445         HMI_DEBUG("wm:lm", "> json_rect dump:%s", json_object_get_string(json_rect));
446
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");
452
453         this->area2size_[area] = area_size;
454     }
455
456     // Check
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);
462     }
463
464     // Release json_object
465     json_object_put(json_obj);
466
467     return 0;
468 }
469
470 const char* kDefaultLayoutDb = "{ \
471     \"layouts\": [ \
472         { \
473             \"name\": \"pu\", \
474             \"layer\": \"on_screen\", \
475             \"areas\": [ \
476                 { \
477                     \"name\": \"pop_up\", \
478                     \"role\": \"incomming_call\" \
479                 } \
480             ] \
481         }, \
482         { \
483             \"name\": \"sa\", \
484             \"layer\": \"on_screen\", \
485             \"areas\": [ \
486                 { \
487                     \"name\": \"system_alert\", \
488                     \"role\": \"system_alert\" \
489                 } \
490             ] \
491         }, \
492         { \
493             \"name\": \"m1\", \
494             \"layer\": \"apps\", \
495             \"areas\": [ \
496                 { \
497                     \"name\": \"normal\", \
498                     \"role\": \"map\" \
499                 } \
500             ] \
501         }, \
502         { \
503             \"name\": \"m2\", \
504             \"layer\": \"apps\", \
505             \"areas\": [ \
506                 { \
507                     \"name\": \"split.main\", \
508                     \"role\": \"map\" \
509                 }, \
510                 { \
511                     \"name\": \"split.sub\", \
512                     \"category\": \"hvac\" \
513                 } \
514             ] \
515         }, \
516         { \
517             \"name\": \"mf\", \
518             \"layer\": \"apps\", \
519             \"areas\": [ \
520                 { \
521                     \"name\": \"full\", \
522                     \"role\": \"map\" \
523                 } \
524             ] \
525         }, \
526         { \
527             \"name\": \"s1\", \
528             \"layer\": \"apps\", \
529             \"areas\": [ \
530                 { \
531                     \"name\": \"normal\", \
532                     \"category\": \"splitable\" \
533                 } \
534             ] \
535         }, \
536         { \
537             \"name\": \"s2\", \
538             \"layer\": \"apps\", \
539             \"areas\": [ \
540                 { \
541                     \"name\": \"split.main\", \
542                     \"category\": \"splitable\" \
543                 }, \
544                 { \
545                     \"name\": \"split.sub\", \
546                     \"category\": \"splitable\" \
547                 } \
548             ] \
549         }, \
550         { \
551             \"name\": \"g\", \
552             \"layer\": \"apps\", \
553             \"areas\": [ \
554                 { \
555                     \"name\": \"normal\", \
556                     \"category\": \"general\" \
557                 } \
558             ] \
559         }, \
560         { \
561             \"name\": \"hs\", \
562             \"layer\": \"homescreen\", \
563             \"areas\": [ \
564                 { \
565                     \"name\": \"full\", \
566                     \"role\": \"homescreen\" \
567                 } \
568             ] \
569         } \
570     ], \
571     \"areas\": [ \
572         { \
573             \"name\": \"normal\", \
574             \"rect\": { \
575                 \"x\": 0, \
576                 \"y\": 218, \
577                 \"w\": 1080, \
578                 \"h\": 1488 \
579             } \
580         }, \
581         { \
582             \"name\": \"split.main\", \
583             \"rect\": { \
584                 \"x\": 0, \
585                 \"y\": 218, \
586                 \"w\": 1080, \
587                 \"h\": 744 \
588             } \
589         }, \
590         { \
591             \"name\": \"split.sub\", \
592             \"rect\": { \
593                 \"x\": 0, \
594                 \"y\": 962, \
595                 \"w\": 1080, \
596                 \"h\": 744 \
597             } \
598         }, \
599         { \
600             \"name\": \"full\", \
601             \"rect\": { \
602                 \"x\": 0, \
603                 \"y\": 0, \
604                 \"w\": 1080, \
605                 \"h\": 1920 \
606             } \
607         }, \
608         { \
609             \"name\": \"pop_up\", \
610             \"rect\": { \
611                 \"x\": 0, \
612                 \"y\": 640, \
613                 \"w\": 1080, \
614                 \"h\": 640 \
615             } \
616         }, \
617         { \
618             \"name\": \"system_alert\", \
619             \"rect\": { \
620                 \"x\": 0, \
621                 \"y\": 640, \
622                 \"w\": 1080, \
623                 \"h\": 640 \
624             } \
625         } \
626     ] \
627 }";