Update managing layout information
[apps/agl-service-windowmanager.git] / src / policy_manager / policy_manager.cpp
1 /*
2  * Copyright (c) 2018 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 <fstream>
19 #include <sstream>
20 #include <istream>
21 #include <thread>
22 #include <map>
23 #include <systemd/sd-event.h>
24 #include <json-c/json.h>
25 #include "policy_manager.hpp"
26 #include "hmi-debug.h"
27
28 namespace stm {
29 extern "C" {
30 #include "dummy_stm.h"
31 }
32 } // namespace stm
33
34
35 namespace pm {
36 typedef struct AreaState {
37     std::string name;
38     std::string category;
39     std::string role;
40 } AreaState;
41
42 typedef struct LayoutState {
43     std::string name;
44     std::map<std::string, int> category_num;
45 //    int category_num[stm::gStmCategoryNoNum];
46     std::vector<AreaState> area_list;
47     std::map<std::string, std::string> last_invisibled_role;
48 } LayoutState;
49
50 typedef struct LayerState {
51     std::string name;
52     LayoutState layout_state;
53 } LayerState;
54
55 struct sd_event* event_loop;
56 std::map<int, struct sd_event_source*> event_source_list;
57 std::map<int, std::string> g_event_info_list;
58 PolicyManager::CallbackTable callback;
59
60 std::unordered_map<std::string, LayerState> g_prv_layers;
61 std::unordered_map<std::string, LayerState> g_crr_layers;
62 std::unordered_map<std::string, LayerState> g_prv_layers_car_stop;
63 std::unordered_map<std::string, LayoutState> g_default_layouts;
64 }  // namespace pm
65
66
67 PolicyManager::PolicyManager() :
68   eventname2no_(),
69   categoryname2no_(),
70   areaname2no_(),
71   role2category_(),
72   category2role_(),
73   role2defaultarea_()
74 {
75     HMI_DEBUG("wm:pm", "Call");
76 }
77
78 int PolicyManager::initialize() {
79     HMI_DEBUG("wm:pm", "Call");
80
81     int ret = 0;
82
83     // Create convert map
84     for (unsigned int i=0; i<STM_NUM_EVT; i++) {
85         HMI_DEBUG("wm:pm", "event name:%s no:%d", stm::gStmEventName[i], stm::gStmEventNo[i]);
86         this->eventname2no_[stm::gStmEventName[i]] = stm::gStmEventNo[i];
87     }
88
89     for (int i = stm::gStmCategoryNoMin; i <= stm::gStmCategoryNoMax; i++) {
90         HMI_DEBUG("wm:pm", "category name:%s no:%d", stm::gStmCategoryName[i], stm::gStmCategoryNo[i]);
91         this->categoryname2no_[stm::gStmCategoryName[i]] = stm::gStmCategoryNo[i];
92     }
93
94     for (unsigned int i=0; i<STM_NUM_ARA; i++) {
95         HMI_DEBUG("wm:pm", "area name:%s no:%d", stm::gStmAreaName[i], stm::gStmAreaNo[i]);
96         this->areaname2no_[stm::gStmAreaName[i]] = stm::gStmAreaNo[i];
97     }
98
99     // Load role.db
100     ret = this->loadRoleDb();
101     if (0 > ret) {
102         HMI_ERROR("wm:pm", "Load role.db Error!!");
103         return ret;
104     }
105
106     // Load layout.db
107     ret = this->loadLayoutDb();
108     if (0 > ret) {
109         HMI_ERROR("wm:pm", "Load layout.db Error!!");
110         return ret;
111     }
112
113     // Initialize current/previous state of layers
114     pm::AreaState init_area;
115     pm::LayoutState init_layout;
116     init_area.name     = "none";
117     init_area.category = "none";
118     init_area.role     = "none";
119     init_layout.area_list.push_back(init_area);
120
121     for (int i = stm::gStmLayerNoMin; i <= stm::gStmLayerNoMax; i++) {
122         const char* layer_name = stm::gStmLayerName[i];
123         pm::g_crr_layers[layer_name].name          = layer_name;
124         pm::g_crr_layers[layer_name].layout_state  = init_layout;
125     }
126
127     pm::g_prv_layers = pm::g_crr_layers;
128
129     // Initialize StateTransitioner
130     stm::stmInitialize();
131
132     // Initialize sd_event loop
133     ret = this->initializeSdEventLoop();
134     if (0 > ret) {
135         HMI_ERROR("wm:pm", "Failed to initializeSdEventLoop!!");
136         return ret;
137     }
138
139     return ret;
140 }
141
142 int PolicyManager::initializeSdEventLoop() {
143     // Get default event loop object
144     int ret = sd_event_new(&(pm::event_loop));
145     if (0 > ret) {
146         HMI_ERROR("wm:pm", "Faild to sd_event_default: errno:%d", ret);
147         return -1;
148     }
149
150     // Create thread for sd_event and detach
151     std::thread sd_event_loop([this]() {
152         while (1) {
153             sd_event_run(pm::event_loop, 1000);
154         }
155     });
156     sd_event_loop.detach();
157
158     return 0;
159 }
160
161 static void addStateToJson(
162   const char* key, int is_changed, const char* state, json_object** json_out) {
163     if ((nullptr == key) || (nullptr == state) || (nullptr == json_out)) {
164         HMI_ERROR("wm:pm", "Argument is nullptr!!!");
165         return;
166     }
167
168     json_object* json_obj = json_object_new_object();
169     json_object_object_add(json_obj, "is_changed", json_object_new_boolean(is_changed));
170     if (is_changed) {
171         HMI_DEBUG("wm:pm", "%s: state changed (%s)", key, state);
172         json_object_object_add(json_obj, "state", json_object_new_string(state));
173     }
174     json_object_object_add(*json_out, key, json_obj);
175 }
176
177 static int checkPolicyEntry(int event, uint64_t delay_ms, const char* role);
178 static int checkPolicy(sd_event_source *source, void *data) {
179     HMI_DEBUG("wm:pm", "Call");
180     HMI_DEBUG("wm:pm", ">>>>>>>>>> START CHECK POLICY");
181
182     int event_data = *((int*)data);
183
184     int event_no, category_no, area_no;
185     event_no    = (event_data & STM_MSK_EVT_NO) - 1;
186     category_no = ((event_data & STM_MSK_CTG_NO) >> 8) - 1;
187     area_no     = ((event_data & STM_MSK_ARA_NO) >> 16) - 1;
188     HMI_DEBUG("wm:pm", ">>>>>>>>>> event:%s category:%s area:%s",
189               stm::gStmEventName[event_no],
190               stm::gStmCategoryName[category_no],
191               stm::gStmAreaName[area_no]);
192
193     // Transition state
194     stm::stm_state_t crr_state;
195     int ret = stm::stmTransitionState(event_data, &crr_state);
196     if (0 > ret) {
197         HMI_ERROR("wm:pm", "Error!!");
198         return -1;
199     }
200
201     HMI_DEBUG("wm:pm", "parking brake state     (is_changed:%d state:%d:%s)",
202               crr_state.parking_brake.is_changed,
203               crr_state.parking_brake.state,
204               stm::gStmParkingBrakeStateNo2Name[crr_state.parking_brake.state]);
205     HMI_DEBUG("wm:pm", "accelerator pedal state (is_changed:%d state:%d:%s)",
206               crr_state.accel_pedal.is_changed,
207               crr_state.accel_pedal.state,
208               stm::gStmAccelPedalStateNo2Name[crr_state.accel_pedal.state]);
209     HMI_DEBUG("wm:pm", "lightstatus brake state (is_changed:%d state:%d:%s)",
210               crr_state.lightstatus_brake.is_changed,
211               crr_state.lightstatus_brake.state,
212               stm::gStmLightstatusBrakeStateNo2Name[crr_state.lightstatus_brake.state]);
213     HMI_DEBUG("wm:pm", "car state               (is_changed:%d state:%d:%s)",
214               crr_state.car.is_changed,
215               crr_state.car.state,
216               stm::gStmCarStateNo2Name[crr_state.car.state]);
217     HMI_DEBUG("wm:pm", "lamp state              (is_changed:%d state:%d:%s)",
218               crr_state.lamp.is_changed,
219               crr_state.lamp.state,
220               stm::gStmLampStateNo2Name[crr_state.lamp.state]);
221     HMI_DEBUG("wm:pm", "restriction mode state  (is_changed:%d state:%d:%s)",
222               crr_state.restriction_mode.is_changed,
223               crr_state.restriction_mode.state,
224               stm::gStmRestrictionModeStateNo2Name[crr_state.restriction_mode.state]);
225     HMI_DEBUG("wm:pm", "homescreen state        (is_changed:%d state:%d:%s)",
226               crr_state.layer[stm::gStmLayerNoHomescreen].is_changed,
227               crr_state.layer[stm::gStmLayerNoHomescreen].state,
228               stm::gStmLayoutNo2Name[crr_state.layer[stm::gStmLayerNoHomescreen].state]);
229     HMI_DEBUG("wm:pm", "apps state              (is_changed:%d state:%d:%s)",
230               crr_state.layer[stm::gStmLayerNoApps].is_changed,
231               crr_state.layer[stm::gStmLayerNoApps].state,
232               stm::gStmLayoutNo2Name[crr_state.layer[stm::gStmLayerNoApps].state]);
233     HMI_DEBUG("wm:pm", "restriction state       (is_changed:%d state:%d:%s)",
234               crr_state.layer[stm::gStmLayerNoRestriction].is_changed,
235               crr_state.layer[stm::gStmLayerNoRestriction].state,
236               stm::gStmLayoutNo2Name[crr_state.layer[stm::gStmLayerNoRestriction].state]);
237     HMI_DEBUG("wm:pm", "on_screen state         (is_changed:%d state:%d:%s)",
238               crr_state.layer[stm::gStmLayerNoOnScreen].is_changed,
239               crr_state.layer[stm::gStmLayerNoOnScreen].state,
240               stm::gStmLayoutNo2Name[crr_state.layer[stm::gStmLayerNoOnScreen].state]);
241
242 #if 1 // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
243     // Store previous layers
244     pm::g_prv_layers = pm::g_crr_layers;
245
246     std::string role = pm::g_event_info_list[event_data];
247     std::string event = std::string(stm::gStmEventName[event_no]);
248     std::string category = std::string(stm::gStmCategoryName[category_no]);
249     std::string area = std::string(stm::gStmAreaName[area_no]);
250
251     // Update layers
252     for (int layer_no = stm::gStmLayerNoMin;
253          layer_no <= stm::gStmLayerNoMax; layer_no++) {
254         const char* layer_name = stm::gStmLayerName[layer_no];
255         HMI_DEBUG("wm:pm", "LAYER:%s", layer_name);
256
257 #if 1
258         // If restriction mode is changed off -> on,
259         // store current state for state of restriction mode off
260         if ((crr_state.restriction_mode.is_changed)
261             && (stm::gStmRestrictionModeStateNoOn == crr_state.restriction_mode.state)) {
262             HMI_DEBUG("wm:lm", "Store current state for state of restriction mode off");
263             pm::g_prv_layers_car_stop[layer_name] = pm::g_crr_layers[layer_name];
264         }
265 #else
266         // If car state is changed car_stop -> car_run,
267         // store current state for state of car stop
268         if ((crr_state.car.is_changed)
269             && (stm::gStmCarStateNoRun == crr_state.car.state)) {
270             HMI_DEBUG("wm:lm", "Store current state for state of car stop");
271             pm::g_prv_layers_car_stop[layer_name] = pm::g_crr_layers[layer_name];
272         }
273 #endif
274
275
276         // This layer is changed?
277         if (crr_state.layer[layer_no].is_changed) {
278             // Get previous layout name of this layer
279             pm::LayoutState prv_layout_state =  pm::g_prv_layers[layer_name].layout_state;
280             std::string prv_layout_name = prv_layout_state.name;
281
282             // Get current layout name of this layer
283             int crr_layout_state_no =  crr_state.layer[layer_no].state;
284             std::string crr_layout_name = std::string(stm::gStmLayoutNo2Name[crr_layout_state_no]);
285
286             pm::LayoutState crr_layout_state;
287 #if 1
288             if ((crr_state.restriction_mode.is_changed)
289                 && (stm::gStmRestrictionModeStateNoOff == crr_state.restriction_mode.state)) {
290                 // If restriction mode is changed on -> off,
291                 // restore state of restriction mode off
292                 HMI_DEBUG("wm:lm", "Restriction mode is changed on -> off, so restore state of restriction mode off");
293                 crr_layout_state = pm::g_prv_layers_car_stop[layer_name].layout_state;
294 #else
295             if ((crr_state.car.is_changed)
296                 && (stm::gStmCarStateNoStop == crr_state.car.state)) {
297                 // If car state is changed car_run -> car_stop,
298                 // restore state of car stop
299                 HMI_DEBUG("wm:lm", "Car state is changed car_run -> car_stop, so restore state of car stop");
300                 crr_layout_state = pm::g_prv_layers_car_stop[layer_name].layout_state;
301 #endif
302             }
303 #if 0
304             else if ("none" == crr_layout_name) {
305                 // If current layout is "none",
306                 // current areas is set with "none"
307                 HMI_DEBUG("wm:pm", "Current layout is \"none\"");
308                 pm::AreaState crr_area_state;
309                 crr_area_state.name     = "none";
310                 crr_area_state.category = "none";
311                 crr_area_state.role     = "none";
312                 crr_layout_state.name = "none";
313                 crr_layout_state.area_list.push_back(crr_area_state);
314             }
315 #endif
316             else {
317                 // Copy previous layout state for current
318                 crr_layout_state = prv_layout_state;
319
320                 if (prv_layout_name == crr_layout_name) {
321                     HMI_DEBUG("wm:lm", "Previous layout is same with current");
322                 }
323                 else {
324                     // If previous layout is NOT same with current,
325                     // current areas is set with default value
326                     HMI_DEBUG("wm:lm", "Previous layout is NOT same with current");
327                     crr_layout_state.name         = pm::g_default_layouts[crr_layout_name].name;
328                     crr_layout_state.category_num = pm::g_default_layouts[crr_layout_name].category_num;
329                     crr_layout_state.area_list    = pm::g_default_layouts[crr_layout_name].area_list;
330                 }
331
332                 // Update role in new area
333 #if 0
334 #if 1
335                 if (crr_state.restriction_mode.is_changed) {
336                     // Updating role is not necessary
337                     // because new_role is not specified
338                     // when restriction mode is changed
339                     HMI_DEBUG("wm:lm", "Updating role is not necessary because new_role is not specified when restriction mode is changed");
340 #else
341                 if (crr_state.car.is_changed) {
342                     // Updating role is not necessary
343                     // because new_role is not specified
344                     // when car state is changed
345                     HMI_DEBUG("wm:lm", "Updating role is not necessary because new_role is not specified when car state is changed");
346 #endif
347                 }
348                 else {
349 #endif
350                     std::map<std::string, std::vector<pm::AreaState>> ctg_list;
351                     for (int ctg_no=stm::gStmCategoryNoMin;
352                          ctg_no<=stm::gStmCategoryNoMax; ctg_no++) {
353                         const char* ctg = stm::gStmCategoryName[ctg_no];
354                         HMI_DEBUG("wm:pm", "ctg:%s", ctg);
355
356                         // Create area list of previous app
357                         std::vector<pm::AreaState> area_list;
358                         for (pm::AreaState area_state : prv_layout_state.area_list) {
359                             if (std::string(ctg) == area_state.category) {
360                                 // If there is the category which is same with new category in previous layout,
361                                 // push it to area list
362                                 HMI_DEBUG("wm:pm", "push area_state to prv list category:%s role:%s",
363                                     area_state.category.c_str(), area_state.role.c_str());
364                                 area_list.push_back(area_state);
365                             }
366                         }
367
368                         int prv_ctg_num = prv_layout_state.category_num[ctg];
369                         int crr_ctg_num = crr_layout_state.category_num[ctg];
370                         HMI_DEBUG("wm:pm", "crr_ctg_num:%d prv_ctg_num:%d", crr_ctg_num, prv_ctg_num);
371
372                         // Remove state of area which is used no longer from area list
373                         if (crr_ctg_num < prv_ctg_num) {
374                             HMI_DEBUG("wm:pm", "crr_ctg_num < prv_ctg_num");
375                             if (0 == strcmp(ctg, category.c_str())) {
376                                 for (auto i = area_list.begin(); i != area_list.end(); ++i) {
377                                     if ((role == i->role) && (area == i->name)) {
378                                         HMI_DEBUG("wm:pm", "store removed role:%s", i->role.c_str());
379                                         crr_layout_state.last_invisibled_role[category] = i->role;
380
381                                         HMI_DEBUG("wm:pm", "remove area state which have same role with requested role");
382                                         area_list.erase(i);
383
384                                         prv_ctg_num--;
385
386                                         if (crr_ctg_num == prv_ctg_num) {
387                                             break;
388                                         }
389                                     }
390                                 }
391                             }
392                             else {
393                                 HMI_DEBUG("wm:pm", "store removed role:%s", area_list.begin()->role.c_str());
394                                 crr_layout_state.last_invisibled_role[ctg] = area_list.begin()->role;
395
396                                 HMI_DEBUG("wm:pm", "remove the oldest area data");
397                                 area_list.erase(area_list.begin());
398                             }
399                         }
400                         else if (crr_ctg_num >= prv_ctg_num) {
401                             HMI_DEBUG("wm:pm", "crr_ctg_num >= prv_ctg_num");
402                             if (0 == strcmp(ctg, category.c_str())) {
403                                 HMI_DEBUG("wm:pm", "category of requested role is same");
404                                 if ((crr_ctg_num == prv_ctg_num) && (0 != prv_ctg_num)) {
405                                     HMI_DEBUG("wm:pm", "store removed role:%s", area_list.begin()->role.c_str());
406                                     crr_layout_state.last_invisibled_role[ctg] = area_list.begin()->role;
407
408                                     HMI_DEBUG("wm:pm", "remove the oldest area data for adding requested role");
409                                     area_list.erase(area_list.begin());
410                                 }
411                             }
412                         }
413
414                         // Check
415                         for (pm::AreaState area_state : area_list) {
416                             HMI_DEBUG("wm:pm", "area_list name:%s category:%s role:%s",
417                                       area_state.name.c_str(),
418                                       area_state.category.c_str(),
419                                       area_state.role.c_str());
420                         }
421
422                         ctg_list[ctg] = area_list;
423                     }
424
425                     if (event == "activate") {
426                         HMI_DEBUG("wm:pm", "event is activate");
427                         // First, update area for requested role
428                         bool request_for_this_layer = false;
429                         bool updated = false;
430                         for (pm::AreaState &as : crr_layout_state.area_list) {
431                             if (as.category == category) {
432                                 request_for_this_layer = true;
433                                 if (as.name == area) {
434                                     HMI_DEBUG("wm:pm", "update area for requested category:%s role:%s area:%s", category.c_str(), role.c_str(), area.c_str());
435                                     as.role = role;
436                                     updated = true;
437                                     break;
438                                 }
439                             }
440                         }
441
442                         // If NOT updated: there is not requested area in new layout, 
443                         // requested role is used later.
444                         if (request_for_this_layer && (!updated)) {
445                             HMI_DEBUG("wm:pm", "requested role is used later category:%s role:%s area:%s", category.c_str(), role.c_str(), area.c_str());
446                             pm::AreaState area_state;
447                             area_state.name = area;
448                             area_state.category = category;
449                             area_state.role = role;
450                             ctg_list[category].push_back(area_state);
451                         }
452                     }
453
454                     // Update areas
455                     for (pm::AreaState &as : crr_layout_state.area_list) {
456                         HMI_DEBUG("wm:pm", "current area info area:%s category:%s role:%s",
457                                   as.name.c_str(), as.category.c_str(), as.role.c_str());
458                         if ((as.role != role) || ("" == as.role)) {
459                             HMI_DEBUG("wm:pm", "update areas for category:%s", as.category.c_str());
460                             if (0 != ctg_list[as.category].size()) {
461                                 HMI_DEBUG("wm:pm", "update role to %s by using area list this category",
462                                           ctg_list[as.category].begin()->role);
463                                 as.role = ctg_list[as.category].begin()->role;
464                                 ctg_list[as.category].erase(ctg_list[as.category].begin());
465                             }
466                             else {
467                                 HMI_DEBUG("wm:pm", "there is no area list for this category, so update area by last invisibled role:", crr_layout_state.last_invisibled_role[as.category]);
468                                 as.role = crr_layout_state.last_invisibled_role[as.category];
469                                 crr_layout_state.last_invisibled_role.erase(as.category);
470                             }
471                         }
472                     }
473 #if 0
474                 }
475 #endif
476             }
477             // Update current layout of this layer
478             pm::g_crr_layers[layer_name].layout_state = crr_layout_state;
479         }
480     }
481
482     // Check
483     for (auto itr : pm::g_crr_layers) {
484         pm::LayerState ls = itr.second;
485         HMI_DEBUG("wm:pm", ">>> LAYER:%s",ls.name.c_str());
486         HMI_DEBUG("wm:pm", ">>> >>> LAYOUT:%s", ls.layout_state.name.c_str());
487
488         for (pm::AreaState as : ls.layout_state.area_list) {
489             HMI_DEBUG("wm:pm", ">>> >>> >>> AREA:%s", as.name.c_str());
490             HMI_DEBUG("wm:pm", ">>> >>> >>> >>> CTG:%s", as.category.c_str());
491             HMI_DEBUG("wm:pm", ">>> >>> >>> >>> ROLE:%s", as.role.c_str());
492         }
493     }
494 #endif // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
495
496     json_object* json_out = json_object_new_object();
497
498     // Create result
499     // {
500     //     "parking_brake": {
501     //         "is_changed": <bool>,
502     //         "state": <const char*>
503     //     },
504     addStateToJson("parking_brake",
505                    crr_state.parking_brake.is_changed,
506                    stm::gStmParkingBrakeStateNo2Name[crr_state.parking_brake.state],
507                    &json_out);
508
509     //     "accel_pedal": {
510     //         "is_changed": <bool>,
511     //         "state": <const char*>
512     //     },
513     addStateToJson("accel_pedal",
514                    crr_state.accel_pedal.is_changed,
515                    stm::gStmAccelPedalStateNo2Name[crr_state.accel_pedal.state],
516                    &json_out);
517
518     //     "lightstatus_brake": {
519     //         "is_changed": <bool>,
520     //         "state": <const char*>
521     //     },
522     addStateToJson("lightstatus_brake",
523                    crr_state.lightstatus_brake.is_changed,
524                    stm::gStmLightstatusBrakeStateNo2Name[crr_state.lightstatus_brake.state],
525                    &json_out);
526
527     //     "car": {
528     //         "is_changed": <bool>,
529     //         "state": <const char*>
530     //     },
531     addStateToJson("car",
532                    crr_state.car.is_changed,
533                    stm::gStmCarStateNo2Name[crr_state.car.state],
534                    &json_out);
535
536     //     "lamp": {
537     //         "is_changed": <bool>,
538     //         "state": <const char*>
539     //     },
540     addStateToJson("lamp",
541                    crr_state.lamp.is_changed,
542                    stm::gStmLampStateNo2Name[crr_state.lamp.state],
543                    &json_out);
544
545     //     "restriction_mode": {
546     //         "is_changed": <bool>,
547     //         "state": <const char*>
548     //     },
549     addStateToJson("restriction_mode",
550                    crr_state.restriction_mode.is_changed,
551                    stm::gStmRestrictionModeStateNo2Name[crr_state.restriction_mode.state],
552                    &json_out);
553
554     //     "layers": [
555     json_object* json_layer = json_object_new_array();
556     json_object* json_tmp;
557
558     //         {
559     //             "homescreen": {
560     //                 "is_changed": <bool>,
561     //                 "state": <const char*>
562     //             }
563     //         },
564     //     ]
565     // }
566     json_tmp = json_object_new_object();
567     addStateToJson("homescreen",
568                    crr_state.layer[stm::gStmLayerNoHomescreen].is_changed,
569 #if 1
570                    pm::g_crr_layers["homescreen"].layout_state.name.c_str(),
571 #else
572                    stm::gStmLayoutNo2Name[crr_state.layer[stm::gStmLayerNoHomescreen].state],
573 #endif
574                    &json_tmp);
575     json_object_array_add(json_layer, json_tmp);
576
577     //         {
578     //             "apps": {
579     //                 "is_changed": <bool>,
580     //                 "state": <const char*>
581     //             }
582     //         },
583     json_tmp = json_object_new_object();
584     addStateToJson("apps",
585                    crr_state.layer[stm::gStmLayerNoApps].is_changed,
586 #if 1
587                    pm::g_crr_layers["apps"].layout_state.name.c_str(),
588 #else
589                    stm::gStmLayoutNo2Name[crr_state.layer[stm::gStmLayerNoApps].state],
590 #endif
591                    &json_tmp);
592     json_object_array_add(json_layer, json_tmp);
593
594     //         {
595     //             "restriction": {
596     //                 "is_changed": <bool>,
597     //                 "state": <const char*>
598     //             }
599     //         },
600     json_tmp = json_object_new_object();
601     addStateToJson("restriction",
602                    crr_state.layer[stm::gStmLayerNoRestriction].is_changed,
603 #if 1
604                    pm::g_crr_layers["restriction"].layout_state.name.c_str(),
605 #else
606                    stm::gStmLayoutNo2Name[crr_state.layer[stm::gStmLayerNoRestriction].state],
607 #endif
608                    &json_tmp);
609     json_object_array_add(json_layer, json_tmp);
610
611     //         {
612     //             "on_screen": {
613     //                 "is_changed": <bool>,
614     //                 "state": <const char*>
615     //             }
616     //         },
617     json_tmp = json_object_new_object();
618     addStateToJson("on_screen",
619                    crr_state.layer[stm::gStmLayerNoOnScreen].is_changed,
620 #if 1
621                    pm::g_crr_layers["on_screen"].layout_state.name.c_str(),
622 #else
623                    stm::gStmLayoutNo2Name[crr_state.layer[stm::gStmLayerNoOnScreen].state],
624 #endif
625                    &json_tmp);
626     json_object_array_add(json_layer, json_tmp);
627
628     // Add json array of layer
629     json_object_object_add(json_out, "layers", json_layer);
630
631     // Notify state is changed
632     if (nullptr != pm::callback.onStateTransitioned) {
633         pm::callback.onStateTransitioned(json_out);
634     }
635
636     if (crr_state.car.is_changed) {
637         if (stm::gStmCarStateNoRun == crr_state.car.state) {
638             // Set delay event(restriction mode on)
639             checkPolicyEntry(STM_EVT_NO_RESTRICTION_MODE_ON, 3000, nullptr);
640         }
641         else if (stm::gStmCarStateNoStop == crr_state.car.state) {
642             // Set event(restriction mode off)
643             checkPolicyEntry(STM_EVT_NO_RESTRICTION_MODE_OFF, 0, nullptr);
644
645             // Stop timer for restriction on event
646             if (pm::event_source_list.find(STM_EVT_NO_RESTRICTION_MODE_ON)
647               != pm::event_source_list.end()) {
648                 HMI_DEBUG("wm:pm", "Stop timer for restriction on");
649                 sd_event_source *event_source
650                     = pm::event_source_list[STM_EVT_NO_RESTRICTION_MODE_ON];
651                 int ret = sd_event_source_set_enabled(event_source, SD_EVENT_OFF);
652                 if (0 > ret) {
653                     HMI_ERROR("wm:pm", "Failed to stop timer");
654                 }
655             }
656         }
657     }
658
659     // Release json_object
660     json_object_put(json_out);
661
662     // Release data
663     delete (int*)data;
664
665     // Destroy sd_event_source object
666     sd_event_source_unref(source);
667
668     // Remove event source from list
669     if (pm::event_source_list.find(event_data) != pm::event_source_list.end()) {
670         pm::event_source_list.erase(event_data);
671     }
672
673     HMI_DEBUG("wm:pm", ">>>>>>>>>> FINISH CHECK POLICY");
674     return 0;
675 }
676
677 static int timerEvent(sd_event_source *source, uint64_t usec, void *data) {
678     int ret = checkPolicy(source, data);
679     return ret;
680 };
681
682 static int checkPolicyEntry(int event, uint64_t delay_ms, const char* role)
683 {
684     HMI_DEBUG("wm:pm", "Call");
685     HMI_DEBUG("wm:pm", "event:0x%x", event);
686
687     // Store event info
688     if (nullptr == role) {
689         pm::g_event_info_list[event] = std::string("");
690     }
691     else {
692         pm::g_event_info_list[event] = std::string(role);
693     }
694
695     if (0 == delay_ms) {
696         int ret = sd_event_add_defer(pm::event_loop, NULL,
697                                      &checkPolicy, new int(event));
698         if (0 > ret) {
699             HMI_ERROR("wm:pm", "Faild to sd_event_add_defer: errno:%d", ret);
700             pm::g_event_info_list.erase(event);
701             return -1;
702         }
703     }
704     else {
705         // Get current time
706         struct timespec time_spec;
707         clock_gettime(CLOCK_MONOTONIC, &time_spec);
708
709         // Calculate timer fired time
710         uint64_t usec = (time_spec.tv_sec * 1000000)
711             + (time_spec.tv_nsec / 1000)
712             + (delay_ms * 1000);
713
714         // Set timer
715         struct sd_event_source* event_source;
716         int ret = sd_event_add_time(pm::event_loop, &event_source, CLOCK_MONOTONIC, usec, 1,
717                                     &timerEvent, new int(event));
718         if (0 > ret) {
719             HMI_ERROR("wm:pm", "Faild to sd_event_add_time: errno:%d", ret);
720             pm::g_event_info_list.erase(event);
721             return -1;
722         }
723
724         // Store event source
725         pm::event_source_list[event] = event_source;
726     }
727
728     return 0;
729 }
730
731 void PolicyManager::registerCallback(CallbackTable callback) {
732     pm::callback.onStateTransitioned = callback.onStateTransitioned;
733     pm::callback.onError             = callback.onError;
734 }
735
736 int PolicyManager::inputEvent(json_object* json_in) {
737     HMI_DEBUG("wm:pm", "Call");
738
739     // Check arguments
740     if (nullptr == json_in) {
741         HMI_ERROR("wm:pm", "Argument is NULL!!");
742         return -1;
743     }
744
745     // Get event from json_object
746     const char* event = this->getStringFromJson(json_in, "event");
747     int event_no = 0;
748     if (nullptr != event) {
749         // Convert name to number
750         event_no = this->eventname2no_[event];
751         HMI_DEBUG("wm:pm", "event(%s:%d)", event, event_no);
752     }
753
754     // Get role from json_object
755     const char* role = this->getStringFromJson(json_in, "role");
756     int category_no = 0;
757     if (nullptr != role) {
758         HMI_DEBUG("wm:pm", "role(%s)", role);
759
760         // Convert role to category
761         const char* category = this->role2category_[role].c_str();
762         if (0 == strcmp("", category)) {
763             HMI_ERROR("wm:pm", "Error!!");
764             return -1;
765         }
766         HMI_DEBUG("wm:pm", "category(%s)", category);
767
768         // Convert name to number
769         category_no = categoryname2no_[category];
770         HMI_DEBUG("wm:pm", "role(%s), category(%s:%d)", role, category, category_no);
771     }
772
773     // Get areat from json_object
774     const char* area = this->getStringFromJson(json_in, "area");
775     int area_no = 0;
776     if (nullptr != area) {
777         // Convert name to number
778         area_no = areaname2no_[area];
779         HMI_DEBUG("wm:pm", "area(%s:%d)", area, area_no);
780     }
781
782     // Check policy
783     checkPolicyEntry((event_no | category_no | area_no), 0, role);
784
785     return 0;
786 }
787
788 std::string PolicyManager::roleToCategory(const char* role) {
789     return this->role2category_[role];
790 }
791
792 extern const char* kDefaultRoleDb;
793 int PolicyManager::loadRoleDb() {
794     HMI_DEBUG("wm:pm", "Call");
795
796     std::string file_name;
797
798     // Get afm application installed dir
799     char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
800     HMI_DEBUG("wm:pm", "afm_app_install_dir:%s", afm_app_install_dir);
801
802     if (!afm_app_install_dir) {
803         HMI_ERROR("wm:pm", "AFM_APP_INSTALL_DIR is not defined");
804     }
805     else {
806         file_name = std::string(afm_app_install_dir) + std::string("/etc/role.db");
807     }
808
809     // Load role.db
810     json_object* json_obj;
811     int ret = this->inputJsonFilie(file_name.c_str(), &json_obj);
812     if (0 > ret) {
813         HMI_ERROR("wm:pm", "Could not open role.db, so use default role information");
814         json_obj = json_tokener_parse(kDefaultRoleDb);
815     }
816     HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj));
817
818     json_object* json_roles;
819     if (!json_object_object_get_ex(json_obj, "roles", &json_roles)) {
820         HMI_ERROR("wm:pm", "Parse Error!!");
821         return -1;
822     }
823
824     int len = json_object_array_length(json_roles);
825     HMI_DEBUG("wm:pm", "json_cfg len:%d", len);
826     HMI_DEBUG("wm:pm", "json_cfg dump:%s", json_object_get_string(json_roles));
827
828     json_object* json_tmp;
829     const char* category;
830     const char* roles;
831     const char* areas;
832     for (int i=0; i<len; i++) {
833         json_tmp = json_object_array_get_idx(json_roles, i);
834
835         category = this->getStringFromJson(json_tmp, "category");
836         roles =  this->getStringFromJson(json_tmp, "role");
837         areas =  this->getStringFromJson(json_tmp, "area");
838
839         if ((nullptr == category) || (nullptr == roles) || (nullptr == areas)) {
840             HMI_ERROR("wm:pm", "Parse Error!!");
841             return -1;
842         }
843
844         // Parse roles by '|'
845         std::vector<std::string> vct_roles;
846         vct_roles = this->parseString(std::string(roles), '|');
847
848         // Parse areas by '|'
849         std::vector<std::string> vct_areas;
850         vct_areas = this->parseString(std::string(areas), '|');
851
852         // Set role, category, default area
853         for (auto itr = vct_roles.begin(); itr != vct_roles.end(); ++itr) {
854             // Delete space from role and area name
855             std::string role = this->deleteSpace(*itr);
856             std::string area = this->deleteSpace(vct_areas[0]);
857
858             this->role2category_[role] = std::string(category);
859             this->role2defaultarea_[role] = area;
860         }
861
862         this->category2role_[std::string(category)] = std::string(roles);
863     }
864
865     // Check
866     HMI_DEBUG("wm:pm", "Check role2category_");
867     for (auto& x:this->role2category_){
868         HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
869     }
870
871     HMI_DEBUG("wm:pm", "Check role2defaultarea_");
872     for (auto& x:this->role2defaultarea_){
873         HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
874     }
875
876     HMI_DEBUG("wm:pm", "Check category2role_");
877     for (auto& x:this->category2role_){
878         HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
879     }
880
881     return 0;
882 }
883
884 extern const char* kDefaultLayoutDb;
885 int PolicyManager::loadLayoutDb() {
886     HMI_DEBUG("wm:lm", "Call");
887
888     // Get afm application installed dir
889     char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
890     HMI_DEBUG("wm:pm", "afm_app_install_dir:%s", afm_app_install_dir);
891
892     std::string file_name;
893     if (!afm_app_install_dir) {
894         HMI_ERROR("wm:pm", "AFM_APP_INSTALL_DIR is not defined");
895     }
896     else {
897         file_name = std::string(afm_app_install_dir) + std::string("/etc/layout.db");
898     }
899
900     // Load layout.db
901     json_object* json_obj;
902     int ret = this->inputJsonFilie(file_name.c_str(), &json_obj);
903     if (0 > ret) {
904         HMI_DEBUG("wm:pm", "Could not open layout.db, so use default layout information");
905         json_obj = json_tokener_parse(kDefaultLayoutDb);
906     }
907     HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj));
908
909     // Perse layouts
910     HMI_DEBUG("wm:pm", "Perse layouts");
911     json_object* json_cfg;
912     if (!json_object_object_get_ex(json_obj, "layouts", &json_cfg)) {
913         HMI_ERROR("wm:pm", "Parse Error!!");
914         return -1;
915     }
916
917     int len = json_object_array_length(json_cfg);
918     HMI_DEBUG("wm:pm", "json_cfg len:%d", len);
919     HMI_DEBUG("wm:pm", "json_cfg dump:%s", json_object_get_string(json_cfg));
920
921     const char* layout;
922     const char* role;
923     const char* category;
924     for (int i=0; i<len; i++) {
925         json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
926
927         layout = this->getStringFromJson(json_tmp, "name");
928         if (nullptr == layout) {
929             HMI_ERROR("wm:pm", "Parse Error!!");
930             return -1;
931         }
932         HMI_DEBUG("wm:pm", "> layout:%s", layout);
933
934         json_object* json_area_array;
935         if (!json_object_object_get_ex(json_tmp, "areas", &json_area_array)) {
936           HMI_ERROR("wm:pm", "Parse Error!!");
937           return -1;
938         }
939
940         int len_area = json_object_array_length(json_area_array);
941         HMI_DEBUG("wm:pm", "json_area_array len:%d", len_area);
942         HMI_DEBUG("wm:pm", "json_area_array dump:%s", json_object_get_string(json_area_array));
943
944         pm::LayoutState layout_state;
945         pm::AreaState area_state;
946         std::map<std::string, int> category_num;
947         for (int ctg_no = stm::gStmCategoryNoMin;
948              ctg_no <= stm::gStmCategoryNoMax; ctg_no++) {
949             const char* ctg_name = stm::gStmCategoryName[ctg_no];
950             category_num[ctg_name] = 0;
951         }
952
953         for (int j=0; j<len_area; j++) {
954             json_object* json_area = json_object_array_get_idx(json_area_array, j);
955
956             // Get area name
957             const char* area = this->getStringFromJson(json_area, "name");
958             if (nullptr == area) {
959               HMI_ERROR("wm:pm", "Parse Error!!");
960               return -1;
961             }
962             area_state.name = std::string(area);
963             HMI_DEBUG("wm:pm", ">> area:%s", area);
964
965             // Get app attribute of the area
966             category = this->getStringFromJson(json_area, "category");
967             if (nullptr == category) {
968                 HMI_ERROR("wm:pm", "Parse Error!!");
969                 return -1;
970             }
971             area_state.category = std::string(category);
972             category_num[category]++;
973             HMI_DEBUG("wm:pm", ">>> category:%s", category);
974
975             role = this->getStringFromJson(json_area, "role");
976             if (nullptr != role) {
977                 // Role is NOT essential here
978                 area_state.role = std::string(role);
979                 HMI_DEBUG("wm:pm", ">>> role:%s", role);
980             }
981
982             layout_state.area_list.push_back(area_state);
983
984         }
985
986         layout_state.name = layout;
987         layout_state.category_num = category_num;
988         pm::g_default_layouts[layout] = layout_state;
989     }
990
991     // initialize for none layout
992     pm::LayoutState none_layout_state;
993     memset(&none_layout_state, 0, sizeof(none_layout_state));
994     none_layout_state.name                 = "none";
995     pm::g_default_layouts["none"] = none_layout_state;
996
997     // Check
998     for(auto itr_layout = pm::g_default_layouts.begin();
999       itr_layout != pm::g_default_layouts.end(); ++itr_layout) {
1000         HMI_DEBUG("wm:pm", ">>> layout:%s", itr_layout->first.c_str());
1001
1002         for (auto itr_area = itr_layout->second.area_list.begin();
1003           itr_area != itr_layout->second.area_list.end(); ++itr_area) {
1004             HMI_DEBUG("wm:pm", ">>> >>> area    :%s", itr_area->name.c_str());
1005             HMI_DEBUG("wm:pm", ">>> >>> category:%s", itr_area->category.c_str());
1006             HMI_DEBUG("wm:pm", ">>> >>> role    :%s", itr_area->role.c_str());
1007 #if 0
1008             for (auto itr_role = itr_area->second.begin();
1009               itr_role != itr_area->second.end(); ++itr_role) {
1010                 HMI_DEBUG("wm:pm", ">>> >>> >>> attribute:%s, name:%s",
1011                           itr_role->first.c_str(), itr_role->second.c_str());
1012             }
1013 #endif
1014         }
1015     }
1016
1017     // Release json_object
1018     json_object_put(json_obj);
1019
1020     return 0;
1021 }
1022
1023 // TODO:
1024 // This function will be removed because json_helper has same function.
1025 // json_helper should be library.
1026 const char* PolicyManager::getStringFromJson(json_object* obj, const char* key) {
1027     if ((nullptr == obj) || (nullptr == key)) {
1028         HMI_ERROR("wm:pm", "Argument is nullptr!!!");
1029         return nullptr;
1030     }
1031
1032     json_object* tmp;
1033     if (!json_object_object_get_ex(obj, key, &tmp)) {
1034         HMI_DEBUG("wm:pm", "Not found key \"%s\"", key);
1035         return nullptr;
1036     }
1037
1038     return json_object_get_string(tmp);
1039 }
1040
1041 // TODO:
1042 // This function will be removed because json_helper has same function.
1043 // json_helper should be library.
1044 int PolicyManager::inputJsonFilie(const char* file, json_object** obj) {
1045     const int input_size = 128;
1046     int ret = -1;
1047
1048     if ((nullptr == file) || (nullptr == obj)) {
1049         HMI_ERROR("wm:jh", "Argument is nullptr!!!");
1050         return ret;
1051     }
1052
1053     HMI_DEBUG("wm:jh", "Input file: %s", file);
1054
1055     // Open json file
1056     FILE *fp = fopen(file, "rb");
1057     if (nullptr == fp) {
1058         HMI_ERROR("wm:jh", "Could not open file");
1059         return ret;
1060     }
1061
1062     // Parse file data
1063     struct json_tokener *tokener = json_tokener_new();
1064     enum json_tokener_error json_error;
1065     char buffer[input_size];
1066     int block_cnt = 1;
1067     while (1) {
1068         size_t len = fread(buffer, sizeof(char), input_size, fp);
1069         *obj = json_tokener_parse_ex(tokener, buffer, len);
1070         if (nullptr != *obj) {
1071             HMI_DEBUG("wm:jh", "File input is success");
1072             ret = 0;
1073             break;
1074         }
1075
1076         json_error = json_tokener_get_error(tokener);
1077         if ((json_tokener_continue != json_error)
1078             || (input_size > len)) {
1079             HMI_ERROR("wm:jh", "Failed to parse file (byte:%d err:%s)",
1080                       (input_size * block_cnt), json_tokener_error_desc(json_error));
1081             HMI_ERROR("wm:jh", "\n%s", buffer);
1082             *obj = nullptr;
1083             break;
1084         }
1085         block_cnt++;
1086     }
1087
1088     // Close json file
1089     fclose(fp);
1090
1091     // Free json_tokener
1092     json_tokener_free(tokener);
1093
1094     return ret;
1095 }
1096
1097 std::vector<std::string> PolicyManager::parseString(std::string str, char delimiter) {
1098     // Parse string by delimiter
1099     std::vector<std::string> vct;
1100     std::stringstream ss{str};
1101     std::string buf;
1102     while (std::getline(ss, buf, delimiter)) {
1103       if (!buf.empty()) {
1104         vct.push_back(buf);
1105       }
1106     }
1107     return vct;
1108 }
1109
1110 std::string PolicyManager::deleteSpace(std::string str) {
1111     std::string ret = str;
1112     size_t pos;
1113     while ((pos = ret.find_first_of(" ")) != std::string::npos) {
1114       ret.erase(pos, 1);
1115     }
1116     return ret;
1117 }
1118
1119 const char* kDefaultRoleDb = "{ \
1120     \"roles\":[ \
1121     { \
1122         \"category\": \"homescreen\", \
1123         \"role\": \"homescreen\", \
1124         \"area\": \"full\", \
1125     }, \
1126     { \
1127         \"category\": \"map\", \
1128         \"role\": \"map\", \
1129         \"area\": \"full | normal | split.main\", \
1130     }, \
1131     { \
1132         \"category\": \"general\", \
1133         \"role\": \"poi | music | video | browser | sdl | settings | mixer | radio | hvac | dashboard | debug\", \
1134         \"area\": \"normal\", \
1135     }, \
1136     { \
1137         \"category\": \"phone\", \
1138         \"role\": \"phone\", \
1139         \"area\": \"normal\", \
1140     }, \
1141     { \
1142         \"category\": \"splitable\", \
1143         \"role\": \"splitable1 | splitable2\", \
1144         \"area\": \"normal | split.main | split.sub\", \
1145     }, \
1146     { \
1147         \"category\": \"popup\", \
1148         \"role\": \"popup\", \
1149         \"area\": \"on_screen\", \
1150     }, \
1151     { \
1152         \"category\": \"system_alert\", \
1153         \"role\": \"system_alert\", \
1154         \"area\": \"on_screen\", \
1155     }, \
1156     { \
1157         \"category\": \"tbt\", \
1158         \"role\": \"tbt\", \
1159         \"area\": \"hud\", \
1160     } \
1161     ] \
1162 }";
1163
1164
1165 const char* kDefaultLayoutDb = "{ \
1166     \"layouts\": [ \
1167         { \
1168             \"name\": \"pu\", \
1169             \"layer\": \"on_screen\", \
1170             \"areas\": [ \
1171                 { \
1172                     \"name\": \"pop_up\", \
1173                     \"role\": \"incomming_call\" \
1174                 } \
1175             ] \
1176         }, \
1177         { \
1178             \"name\": \"sa\", \
1179             \"layer\": \"on_screen\", \
1180             \"areas\": [ \
1181                 { \
1182                     \"name\": \"system_alert\", \
1183                     \"role\": \"system_alert\" \
1184                 } \
1185             ] \
1186         }, \
1187         { \
1188             \"name\": \"m1\", \
1189             \"layer\": \"apps\", \
1190             \"areas\": [ \
1191                 { \
1192                     \"name\": \"normal\", \
1193                     \"role\": \"map\" \
1194                 } \
1195             ] \
1196         }, \
1197         { \
1198             \"name\": \"m2\", \
1199             \"layer\": \"apps\", \
1200             \"areas\": [ \
1201                 { \
1202                     \"name\": \"split.main\", \
1203                     \"role\": \"map\" \
1204                 }, \
1205                 { \
1206                     \"name\": \"split.sub\", \
1207                     \"category\": \"hvac\" \
1208                 } \
1209             ] \
1210         }, \
1211         { \
1212             \"name\": \"mf\", \
1213             \"layer\": \"apps\", \
1214             \"areas\": [ \
1215                 { \
1216                     \"name\": \"full\", \
1217                     \"role\": \"map\" \
1218                 } \
1219             ] \
1220         }, \
1221         { \
1222             \"name\": \"s1\", \
1223             \"layer\": \"apps\", \
1224             \"areas\": [ \
1225                 { \
1226                     \"name\": \"normal\", \
1227                     \"category\": \"splitable\" \
1228                 } \
1229             ] \
1230         }, \
1231         { \
1232             \"name\": \"s2\", \
1233             \"layer\": \"apps\", \
1234             \"areas\": [ \
1235                 { \
1236                     \"name\": \"split.main\", \
1237                     \"category\": \"splitable\" \
1238                 }, \
1239                 { \
1240                     \"name\": \"split.sub\", \
1241                     \"category\": \"splitable\" \
1242                 } \
1243             ] \
1244         }, \
1245         { \
1246             \"name\": \"g\", \
1247             \"layer\": \"apps\", \
1248             \"areas\": [ \
1249                 { \
1250                     \"name\": \"normal\", \
1251                     \"category\": \"general\" \
1252                 } \
1253             ] \
1254         }, \
1255         { \
1256             \"name\": \"hs\", \
1257             \"layer\": \"homescreen\", \
1258             \"areas\": [ \
1259                 { \
1260                     \"name\": \"full\", \
1261                     \"role\": \"homescreen\" \
1262                 } \
1263             ] \
1264         } \
1265     ], \
1266     \"areas\": [ \
1267         { \
1268             \"name\": \"normal\", \
1269             \"rect\": { \
1270                 \"x\": 0, \
1271                 \"y\": 218, \
1272                 \"w\": 1080, \
1273                 \"h\": 1488 \
1274             } \
1275         }, \
1276         { \
1277             \"name\": \"split.main\", \
1278             \"rect\": { \
1279                 \"x\": 0, \
1280                 \"y\": 218, \
1281                 \"w\": 1080, \
1282                 \"h\": 744 \
1283             } \
1284         }, \
1285         { \
1286             \"name\": \"split.sub\", \
1287             \"rect\": { \
1288                 \"x\": 0, \
1289                 \"y\": 962, \
1290                 \"w\": 1080, \
1291                 \"h\": 744 \
1292             } \
1293         }, \
1294         { \
1295             \"name\": \"full\", \
1296             \"rect\": { \
1297                 \"x\": 0, \
1298                 \"y\": 0, \
1299                 \"w\": 1080, \
1300                 \"h\": 1920 \
1301             } \
1302         }, \
1303         { \
1304             \"name\": \"pop_up\", \
1305             \"rect\": { \
1306                 \"x\": 0, \
1307                 \"y\": 640, \
1308                 \"w\": 1080, \
1309                 \"h\": 640 \
1310             } \
1311         }, \
1312         { \
1313             \"name\": \"system_alert\", \
1314             \"rect\": { \
1315                 \"x\": 0, \
1316                 \"y\": 640, \
1317                 \"w\": 1080, \
1318                 \"h\": 640 \
1319             } \
1320         } \
1321     ] \
1322 }";