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