Bug Fix: When restriction app gets invisible event, other app also gets it
[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     // Update layout of all layers
88     json_object* json_layers;
89     if (!json_object_object_get_ex(obj, "layers", &json_layers)) {
90         HMI_ERROR("wm:lm", "Parse Error!!");
91         return -1;
92     }
93
94     int len = json_object_array_length(json_layers);
95     HMI_DEBUG("wm:lm", "json_layers len:%d", len);
96     HMI_DEBUG("wm:lm", "json_layers dump:%s", json_object_get_string(json_layers));
97
98     for (int i=0; i<len; i++) {
99         json_object* json_tmp = json_object_array_get_idx(json_layers, i);
100
101         // Get layer name and json_object
102         const char* layer;
103         json_object* json_layer;
104         json_object_object_foreach(json_tmp, key, val) {
105             layer = key;
106             json_layer = val;
107             HMI_DEBUG("wm:lm", "Try to update %s layer state", layer);
108         }
109
110         // Store previous state
111         this->prv_layers_[layer] = this->crr_layers_[layer];
112         std::string prv_layout_name = this->prv_layers_[layer].begin()->first;
113
114         // If car state is changed car_stop -> car_run,
115         // store current state for state of car stop
116         if ((is_car_state_changed) && ("car_run" == car_state)) {
117             HMI_DEBUG("wm:lm", "Store current state for state of car stop");
118             this->prv_layers_car_stop_[layer] = this->crr_layers_[layer];
119         }
120
121         json_object* json_is_changed;
122         if (!json_object_object_get_ex(json_layer, "is_changed", &json_is_changed)) {
123             HMI_ERROR("wm:lm", "Not found key \"is_changed\"");
124            return false;
125         }
126
127         // If layer state is changed
128         if (json_object_get_boolean(json_is_changed)) {
129             // Set layout changed flag
130             this->is_layout_changed_[layer] = true;
131
132             json_object* json_state;
133             if (!json_object_object_get_ex(json_layer, "state", &json_state)) {
134                 HMI_ERROR("wm:lm", "Not found key \"state\"");
135                 return false;
136             }
137
138             const char* crr_layout_name = json_object_get_string(json_state);
139             HMI_DEBUG("wm:lm", "crr state: %s", crr_layout_name);
140
141             TypeLayouts crr_layout;
142             if ((is_car_state_changed) && ("car_stop" == car_state)) {
143                 // If car state is changed car_run -> car_stop,
144                 // restore state of car stop
145                 HMI_DEBUG("wm:lm", "Car state is changed car_run -> car_stop, so restore state of car stop");
146                 crr_layout = this->prv_layers_car_stop_[layer];
147             }
148             else if ("none" == std::string(crr_layout_name)) {
149                 // If current layout is "none",
150                 // current areas is set with "none"
151                 HMI_DEBUG("wm:lm", "Current layout is \"none\"");
152                 TypeAreas area;
153                 TypeRolCtg rol_ctg;
154                 rol_ctg["none"] = "none";
155                 area["none"] = rol_ctg;
156                 crr_layout["none"] = area;
157             }
158             else {
159                 if (std::string(crr_layout_name) == prv_layout_name) {
160                     // If previous layout is same with current,
161                     // previous areas are copied to current
162                     HMI_DEBUG("wm:lm", "Previous layout is same with current");
163                     crr_layout[crr_layout_name] = this->prv_layers_[layer][crr_layout_name];
164                 }
165                 else {
166                     // If previous layout is NOT same with current,
167                     // current areas is set with default value
168                     HMI_DEBUG("wm:lm", "Previous layout is NOT same with current");
169                     crr_layout[crr_layout_name] = this->layout_define_[crr_layout_name];
170                 }
171
172                 // Update role in new area
173                 if (is_car_state_changed) {
174                     // Updating role is not necessary
175                     // because new_role is not specified
176                     // when car state is changed
177                     HMI_DEBUG("wm:lm", "Updating role is not necessary because new_role is not specified when car state is changed");
178                 }
179                 else {
180                     HMI_DEBUG("wm:lm", "Get new_area for new role");
181                     // Get new_area for new role
182                     std::string new_area = this->getAreaName(this->layout_define_[crr_layout_name],
183                                                              new_role, category);
184
185                     if ("none" == new_area) {
186                         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");
187                     }
188                     else {
189                         // Update role in new area
190                         // because new_role is specified for this layer
191                         TypeRolCtg crr_role;
192                         crr_role["role"] = std::string(new_role);
193                         crr_layout[crr_layout_name][new_area] = crr_role;
194                     }
195                 }
196             }
197
198             // Update layer state
199             this->crr_layers_[layer] = crr_layout;
200
201             // Check
202             for (auto itr_layout = this->crr_layers_[layer].begin();
203                  itr_layout != this->crr_layers_[layer].end(); ++itr_layout) {
204               for (auto itr_area = itr_layout->second.begin();
205                    itr_area != itr_layout->second.end(); ++itr_area) {
206                 for (auto itr_role = itr_area->second.begin();
207                      itr_role != itr_area->second.end(); ++itr_role) {
208                   HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s",
209                             itr_layout->first.c_str(), itr_area->first.c_str(),
210                             itr_role->first.c_str(), itr_role->second.c_str());
211                 }
212               }
213             }
214
215             ret = true;
216         }
217         else {
218             // Clear layout changed flag
219             this->is_layout_changed_[layer] = false;
220         }
221     }
222     return ret;
223 }
224
225 // TODO: This API is for workaround, so this will be removed
226 void LayoutManager::updateArea(const char* layer, const char* role, const char* area) {
227     this->crr_layers_[layer].begin()->second[area]["role"] = std::string(role);
228 }
229
230 LayoutManager::TypeLayers LayoutManager::getCurrentLayers() {
231     return this->crr_layers_;
232 }
233
234 LayoutManager::TypeLayers LayoutManager::getPreviousLayers() {
235     return this->prv_layers_;
236 }
237
238 compositor::rect LayoutManager::getAreaSize(const char* area) {
239     return this->area2size_[area];
240 }
241
242 std::string LayoutManager::getAreaName(TypeAreas areas, const char* role, const char* category) {
243     for (auto itr_area = areas.begin(); itr_area != areas.end(); ++itr_area) {
244         std::string area_name = itr_area->first;
245         TypeRolCtg rol_ctg = itr_area->second;
246
247         if ("role" == rol_ctg.begin()->first) {
248             if (std::string(role) == rol_ctg.begin()->second) {
249                 return area_name;
250             }
251         }
252         else if ("category" == rol_ctg.begin()->first) {
253             if (std::string(category) == rol_ctg.begin()->second) {
254                 return area_name;
255             }
256         }
257         else {
258             return std::string("none");
259         }
260     }
261     return std::string("none");
262 }
263
264
265 bool LayoutManager::isLayoutChanged(const char* layer) {
266     return this->is_layout_changed_[layer];
267 }
268
269
270 extern const char* kDefaultLayoutDb;
271 int LayoutManager::loadLayoutDb() {
272     HMI_DEBUG("wm:lm", "Call");
273
274     // Get afm application installed dir
275     char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
276     HMI_DEBUG("wm:lm", "afm_app_install_dir:%s", afm_app_install_dir);
277
278     std::string file_name;
279     if (!afm_app_install_dir) {
280         HMI_ERROR("wm:lm", "AFM_APP_INSTALL_DIR is not defined");
281     }
282     else {
283         file_name = std::string(afm_app_install_dir) + std::string("/etc/layout.db");
284     }
285
286     // Load layout.db
287     json_object* json_obj;
288     int ret = jh::inputJsonFilie(file_name.c_str(), &json_obj);
289     if (0 > ret) {
290         HMI_DEBUG("wm:lm", "Could not open layout.db, so use default layout information");
291         json_obj = json_tokener_parse(kDefaultLayoutDb);
292     }
293     HMI_DEBUG("wm:lm", "json_obj dump:%s", json_object_get_string(json_obj));
294
295     // Perse layouts
296     HMI_DEBUG("wm:lm", "Perse layouts");
297     json_object* json_cfg;
298     if (!json_object_object_get_ex(json_obj, "layouts", &json_cfg)) {
299         HMI_ERROR("wm:lm", "Parse Error!!");
300         return -1;
301     }
302
303     int len = json_object_array_length(json_cfg);
304     HMI_DEBUG("wm:lm", "json_cfg len:%d", len);
305     HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg));
306
307     const char* layout;
308     const char* role;
309     const char* category;
310     for (int i=0; i<len; i++) {
311         json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
312
313         layout = jh::getStringFromJson(json_tmp, "name");
314         if (nullptr == layout) {
315             HMI_ERROR("wm:lm", "Parse Error!!");
316             return -1;
317         }
318         HMI_DEBUG("wm:lm", "> layout:%s", layout);
319
320         json_object* json_area_array;
321         if (!json_object_object_get_ex(json_tmp, "areas", &json_area_array)) {
322           HMI_ERROR("wm:lm", "Parse Error!!");
323           return -1;
324         }
325
326         int len_area = json_object_array_length(json_area_array);
327         HMI_DEBUG("wm:lm", "json_area_array len:%d", len_area);
328         HMI_DEBUG("wm:lm", "json_area_array dump:%s", json_object_get_string(json_area_array));
329
330         TypeAreas areas;
331         for (int j=0; j<len_area; j++) {
332             json_object* json_area = json_object_array_get_idx(json_area_array, j);
333
334             const char* area = jh::getStringFromJson(json_area, "name");
335             if (nullptr == area) {
336               HMI_ERROR("wm:lm", "Parse Error!!");
337               return -1;
338             }
339             HMI_DEBUG("wm:lm", ">> area:%s", area);
340
341             TypeRolCtg rol_ctg_name;
342             role = jh::getStringFromJson(json_area, "role");
343             if (nullptr == role) {
344                 category = jh::getStringFromJson(json_area, "category");
345                 if (nullptr == category) {
346                   HMI_ERROR("wm:lm", "Parse Error!!");
347                   return -1;
348                 }
349                 rol_ctg_name["category"] = std::string(category);
350                 HMI_DEBUG("wm:lm", ">>> category:%s", category);
351             }
352             else {
353                 rol_ctg_name["role"] = std::string(role);
354                 HMI_DEBUG("wm:lm", ">>> role:%s", role);
355             }
356
357             areas[area] = rol_ctg_name;
358         }
359
360         this->layout_define_[layout] = areas;
361     }
362
363     // Check
364     for(auto itr_layout = this->layout_define_.begin();
365       itr_layout != this->layout_define_.end(); ++itr_layout) {
366         for (auto itr_area = itr_layout->second.begin();
367           itr_area != itr_layout->second.end(); ++itr_area) {
368             for (auto itr_role = itr_area->second.begin();
369               itr_role != itr_area->second.end(); ++itr_role) {
370                 HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s",
371                           itr_layout->first.c_str(), itr_area->first.c_str(),
372                           itr_role->first.c_str(), itr_role->second.c_str());
373             }
374         }
375     }
376
377     // Perse areas
378     HMI_DEBUG("wm:lm", "Perse areas");
379     if (!json_object_object_get_ex(json_obj, "areas", &json_cfg)) {
380         HMI_ERROR("wm:lm", "Parse Error!!");
381         return -1;
382     }
383
384     len = json_object_array_length(json_cfg);
385     HMI_DEBUG("wm:lm", "json_cfg len:%d", len);
386     HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg));
387
388     const char* area;
389     for (int i=0; i<len; i++) {
390         json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
391         HMI_DEBUG("wm:lm", "> json_tmp dump:%s", json_object_get_string(json_tmp));
392
393         area = jh::getStringFromJson(json_tmp, "name");
394         if (nullptr == area) {
395             HMI_ERROR("wm:lm", "Parse Error!!");
396             return -1;
397         }
398         HMI_DEBUG("wm:lm", "> area:%s", area);
399
400         json_object* json_rect;
401         if (!json_object_object_get_ex(json_tmp, "rect", &json_rect)) {
402           HMI_ERROR("wm:lm", "Parse Error!!");
403           return -1;
404         }
405         HMI_DEBUG("wm:lm", "> json_rect dump:%s", json_object_get_string(json_rect));
406
407         compositor::rect area_size;
408         area_size.x = jh::getIntFromJson(json_rect, "x");
409         area_size.y = jh::getIntFromJson(json_rect, "y");
410         area_size.w = jh::getIntFromJson(json_rect, "w");
411         area_size.h = jh::getIntFromJson(json_rect, "h");
412
413         this->area2size_[area] = area_size;
414     }
415
416     // Check
417     for(auto itr = this->area2size_.begin();
418       itr != this->area2size_.end(); ++itr) {
419         HMI_DEBUG("wm:lm", "area:%s x:%d y:%d w:%d h:%d",
420                   itr->first.c_str(), itr->second.x, itr->second.y,
421                   itr->second.w, itr->second.h);
422     }
423
424     // Release json_object
425     json_object_put(json_obj);
426
427     return 0;
428 }
429
430 const char* kDefaultLayoutDb = "{ \
431     \"layouts\": [ \
432         { \
433             \"name\": \"pu\", \
434             \"layer\": \"on_screen\", \
435             \"areas\": [ \
436                 { \
437                     \"name\": \"pop_up\", \
438                     \"role\": \"incomming_call\" \
439                 } \
440             ] \
441         }, \
442         { \
443             \"name\": \"sa\", \
444             \"layer\": \"on_screen\", \
445             \"areas\": [ \
446                 { \
447                     \"name\": \"system_alert\", \
448                     \"role\": \"system_alert\" \
449                 } \
450             ] \
451         }, \
452         { \
453             \"name\": \"m1\", \
454             \"layer\": \"apps\", \
455             \"areas\": [ \
456                 { \
457                     \"name\": \"normal\", \
458                     \"role\": \"map\" \
459                 } \
460             ] \
461         }, \
462         { \
463             \"name\": \"m2\", \
464             \"layer\": \"apps\", \
465             \"areas\": [ \
466                 { \
467                     \"name\": \"split.main\", \
468                     \"role\": \"map\" \
469                 }, \
470                 { \
471                     \"name\": \"split.sub\", \
472                     \"category\": \"hvac\" \
473                 } \
474             ] \
475         }, \
476         { \
477             \"name\": \"mf\", \
478             \"layer\": \"apps\", \
479             \"areas\": [ \
480                 { \
481                     \"name\": \"full\", \
482                     \"role\": \"map\" \
483                 } \
484             ] \
485         }, \
486         { \
487             \"name\": \"s1\", \
488             \"layer\": \"apps\", \
489             \"areas\": [ \
490                 { \
491                     \"name\": \"normal\", \
492                     \"category\": \"splitable\" \
493                 } \
494             ] \
495         }, \
496         { \
497             \"name\": \"s2\", \
498             \"layer\": \"apps\", \
499             \"areas\": [ \
500                 { \
501                     \"name\": \"split.main\", \
502                     \"category\": \"splitable\" \
503                 }, \
504                 { \
505                     \"name\": \"split.sub\", \
506                     \"category\": \"splitable\" \
507                 } \
508             ] \
509         }, \
510         { \
511             \"name\": \"g\", \
512             \"layer\": \"apps\", \
513             \"areas\": [ \
514                 { \
515                     \"name\": \"normal\", \
516                     \"category\": \"general\" \
517                 } \
518             ] \
519         }, \
520         { \
521             \"name\": \"hs\", \
522             \"layer\": \"homescreen\", \
523             \"areas\": [ \
524                 { \
525                     \"name\": \"full\", \
526                     \"role\": \"homescreen\" \
527                 } \
528             ] \
529         } \
530     ], \
531     \"areas\": [ \
532         { \
533             \"name\": \"normal\", \
534             \"rect\": { \
535                 \"x\": 0, \
536                 \"y\": 218, \
537                 \"w\": 1080, \
538                 \"h\": 1488 \
539             } \
540         }, \
541         { \
542             \"name\": \"split.main\", \
543             \"rect\": { \
544                 \"x\": 0, \
545                 \"y\": 218, \
546                 \"w\": 1080, \
547                 \"h\": 744 \
548             } \
549         }, \
550         { \
551             \"name\": \"split.sub\", \
552             \"rect\": { \
553                 \"x\": 0, \
554                 \"y\": 962, \
555                 \"w\": 1080, \
556                 \"h\": 744 \
557             } \
558         }, \
559         { \
560             \"name\": \"full\", \
561             \"rect\": { \
562                 \"x\": 0, \
563                 \"y\": 0, \
564                 \"w\": 1080, \
565                 \"h\": 1920 \
566             } \
567         }, \
568         { \
569             \"name\": \"pop_up\", \
570             \"rect\": { \
571                 \"x\": 0, \
572                 \"y\": 640, \
573                 \"w\": 1080, \
574                 \"h\": 640 \
575             } \
576         }, \
577         { \
578             \"name\": \"system_alert\", \
579             \"rect\": { \
580                 \"x\": 0, \
581                 \"y\": 640, \
582                 \"w\": 1080, \
583                 \"h\": 640 \
584             } \
585         } \
586     ] \
587 }";