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