Add restriction and software keyboard layers
[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", "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 extern const char* kDefaultLayoutDb;
257 int LayoutManager::loadLayoutDb() {
258     HMI_DEBUG("wm:lm", "Call");
259
260     // Get afm application installed dir
261     char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
262     HMI_DEBUG("wm:lm", "afm_app_install_dir:%s", afm_app_install_dir);
263
264     std::string file_name;
265     if (!afm_app_install_dir) {
266         HMI_ERROR("wm:lm", "AFM_APP_INSTALL_DIR is not defined");
267     }
268     else {
269         file_name = std::string(afm_app_install_dir) + std::string("/etc/layout.db");
270     }
271
272     // Load layout.db
273     HMI_DEBUG("wm:lm", "file_name:%s", file_name.c_str());
274     json_object* json_obj = json_object_from_file(file_name.c_str());
275     if (nullptr == json_obj) {
276         HMI_ERROR("wm:lm", "Could not open layout.db, so use default role information");
277         json_obj = json_tokener_parse(kDefaultLayoutDb);
278     }
279     HMI_DEBUG("wm:lm", "json_obj dump:%s", json_object_get_string(json_obj));
280
281     // Perse layouts
282     HMI_DEBUG("wm:lm", "Perse layouts");
283     json_object* json_cfg;
284     if (!json_object_object_get_ex(json_obj, "layouts", &json_cfg)) {
285         HMI_ERROR("wm:lm", "Parse Error!!");
286         return -1;
287     }
288
289     int len = json_object_array_length(json_cfg);
290     HMI_DEBUG("wm:lm", "json_cfg len:%d", len);
291     HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg));
292
293     const char* layout;
294     const char* role;
295     const char* category;
296     for (int i=0; i<len; i++) {
297         json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
298
299         layout = jh::getStringFromJson(json_tmp, "name");
300         if (nullptr == layout) {
301             HMI_ERROR("wm:lm", "Parse Error!!");
302             return -1;
303         }
304         HMI_DEBUG("wm:lm", "> layout:%s", layout);
305
306         json_object* json_area_array;
307         if (!json_object_object_get_ex(json_tmp, "areas", &json_area_array)) {
308           HMI_ERROR("wm:lm", "Parse Error!!");
309           return -1;
310         }
311
312         int len_area = json_object_array_length(json_area_array);
313         HMI_DEBUG("wm:lm", "json_area_array len:%d", len_area);
314         HMI_DEBUG("wm:lm", "json_area_array dump:%s", json_object_get_string(json_area_array));
315
316         TypeAreas areas;
317         for (int j=0; j<len_area; j++) {
318             json_object* json_area = json_object_array_get_idx(json_area_array, j);
319
320             const char* area = jh::getStringFromJson(json_area, "name");
321             if (nullptr == area) {
322               HMI_ERROR("wm:lm", "Parse Error!!");
323               return -1;
324             }
325             HMI_DEBUG("wm:lm", ">> area:%s", area);
326
327             TypeRolCtg rol_ctg_name;
328             role = jh::getStringFromJson(json_area, "role");
329             if (nullptr == role) {
330                 category = jh::getStringFromJson(json_area, "category");
331                 if (nullptr == category) {
332                   HMI_ERROR("wm:lm", "Parse Error!!");
333                   return -1;
334                 }
335                 rol_ctg_name["category"] = std::string(category);
336                 HMI_DEBUG("wm:lm", ">>> category:%s", category);
337             }
338             else {
339                 rol_ctg_name["role"] = std::string(role);
340                 HMI_DEBUG("wm:lm", ">>> role:%s", role);
341             }
342
343             areas[area] = rol_ctg_name;
344         }
345
346         this->layout_define_[layout] = areas;
347     }
348
349     // Check
350     for(auto itr_layout = this->layout_define_.begin();
351       itr_layout != this->layout_define_.end(); ++itr_layout) {
352         for (auto itr_area = itr_layout->second.begin();
353           itr_area != itr_layout->second.end(); ++itr_area) {
354             for (auto itr_role = itr_area->second.begin();
355               itr_role != itr_area->second.end(); ++itr_role) {
356                 HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s",
357                           itr_layout->first.c_str(), itr_area->first.c_str(),
358                           itr_role->first.c_str(), itr_role->second.c_str());
359             }
360         }
361     }
362
363     // Perse areas
364     HMI_DEBUG("wm:lm", "Perse areas");
365     if (!json_object_object_get_ex(json_obj, "areas", &json_cfg)) {
366         HMI_ERROR("wm:lm", "Parse Error!!");
367         return -1;
368     }
369
370     len = json_object_array_length(json_cfg);
371     HMI_DEBUG("wm:lm", "json_cfg len:%d", len);
372     HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg));
373
374     const char* area;
375     for (int i=0; i<len; i++) {
376         json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
377         HMI_DEBUG("wm:lm", "> json_tmp dump:%s", json_object_get_string(json_tmp));
378
379         area = jh::getStringFromJson(json_tmp, "name");
380         if (nullptr == area) {
381             HMI_ERROR("wm:lm", "Parse Error!!");
382             return -1;
383         }
384         HMI_DEBUG("wm:lm", "> area:%s", area);
385
386         json_object* json_rect;
387         if (!json_object_object_get_ex(json_tmp, "rect", &json_rect)) {
388           HMI_ERROR("wm:lm", "Parse Error!!");
389           return -1;
390         }
391         HMI_DEBUG("wm:lm", "> json_rect dump:%s", json_object_get_string(json_rect));
392
393         compositor::rect area_size;
394         area_size.x = jh::getIntFromJson(json_rect, "x");
395         area_size.y = jh::getIntFromJson(json_rect, "y");
396         area_size.w = jh::getIntFromJson(json_rect, "w");
397         area_size.h = jh::getIntFromJson(json_rect, "h");
398
399         this->area2size_[area] = area_size;
400     }
401
402     // Check
403     for(auto itr = this->area2size_.begin();
404       itr != this->area2size_.end(); ++itr) {
405         HMI_DEBUG("wm:lm", "area:%s x:%d y:%d w:%d h:%d",
406                   itr->first.c_str(), itr->second.x, itr->second.y,
407                   itr->second.w, itr->second.h);
408     }
409
410     // Release json_object
411     json_object_put(json_obj);
412
413     return 0;
414 }
415
416 const char* kDefaultLayoutDb = "{ \
417     \"layouts\": [ \
418         { \
419             \"name\": \"pu\", \
420             \"layer\": \"on_screen\", \
421             \"areas\": [ \
422                 { \
423                     \"name\": \"pop_up\", \
424                     \"role\": \"incomming_call\" \
425                 } \
426             ] \
427         }, \
428         { \
429             \"name\": \"sa\", \
430             \"layer\": \"on_screen\", \
431             \"areas\": [ \
432                 { \
433                     \"name\": \"system_alert\", \
434                     \"role\": \"system_alert\" \
435                 } \
436             ] \
437         }, \
438         { \
439             \"name\": \"m1\", \
440             \"layer\": \"apps\", \
441             \"areas\": [ \
442                 { \
443                     \"name\": \"normal\", \
444                     \"role\": \"map\" \
445                 } \
446             ] \
447         }, \
448         { \
449             \"name\": \"m2\", \
450             \"layer\": \"apps\", \
451             \"areas\": [ \
452                 { \
453                     \"name\": \"split.main\", \
454                     \"role\": \"map\" \
455                 }, \
456                 { \
457                     \"name\": \"split.sub\", \
458                     \"category\": \"hvac\" \
459                 } \
460             ] \
461         }, \
462         { \
463             \"name\": \"mf\", \
464             \"layer\": \"apps\", \
465             \"areas\": [ \
466                 { \
467                     \"name\": \"full\", \
468                     \"role\": \"map\" \
469                 } \
470             ] \
471         }, \
472         { \
473             \"name\": \"s1\", \
474             \"layer\": \"apps\", \
475             \"areas\": [ \
476                 { \
477                     \"name\": \"normal\", \
478                     \"category\": \"splitable\" \
479                 } \
480             ] \
481         }, \
482         { \
483             \"name\": \"s2\", \
484             \"layer\": \"apps\", \
485             \"areas\": [ \
486                 { \
487                     \"name\": \"split.main\", \
488                     \"category\": \"splitable\" \
489                 }, \
490                 { \
491                     \"name\": \"split.sub\", \
492                     \"category\": \"splitable\" \
493                 } \
494             ] \
495         }, \
496         { \
497             \"name\": \"g\", \
498             \"layer\": \"apps\", \
499             \"areas\": [ \
500                 { \
501                     \"name\": \"normal\", \
502                     \"category\": \"general\" \
503                 } \
504             ] \
505         }, \
506         { \
507             \"name\": \"hs\", \
508             \"layer\": \"homescreen\", \
509             \"areas\": [ \
510                 { \
511                     \"name\": \"full\", \
512                     \"role\": \"homescreen\" \
513                 } \
514             ] \
515         } \
516     ], \
517     \"areas\": [ \
518         { \
519             \"name\": \"normal\", \
520             \"rect\": { \
521                 \"x\": 0, \
522                 \"y\": 218, \
523                 \"w\": 1080, \
524                 \"h\": 1488 \
525             } \
526         }, \
527         { \
528             \"name\": \"split.main\", \
529             \"rect\": { \
530                 \"x\": 0, \
531                 \"y\": 218, \
532                 \"w\": 1080, \
533                 \"h\": 744 \
534             } \
535         }, \
536         { \
537             \"name\": \"split.sub\", \
538             \"rect\": { \
539                 \"x\": 0, \
540                 \"y\": 962, \
541                 \"w\": 1080, \
542                 \"h\": 744 \
543             } \
544         }, \
545         { \
546             \"name\": \"full\", \
547             \"rect\": { \
548                 \"x\": 0, \
549                 \"y\": 0, \
550                 \"w\": 1080, \
551                 \"h\": 1920 \
552             } \
553         }, \
554         { \
555             \"name\": \"pop_up\", \
556             \"rect\": { \
557                 \"x\": 0, \
558                 \"y\": 640, \
559                 \"w\": 1080, \
560                 \"h\": 640 \
561             } \
562         }, \
563         { \
564             \"name\": \"system_alert\", \
565             \"rect\": { \
566                 \"x\": 0, \
567                 \"y\": 640, \
568                 \"w\": 1080, \
569                 \"h\": 640 \
570             } \
571         } \
572     ] \
573 }";