0af8398366d94b855c6cb7c3345dc84c687a29ad
[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 1
334                 if (crr_state.restriction_mode.is_changed) {
335                     // Updating role is not necessary
336                     // because new_role is not specified
337                     // when restriction mode is changed
338                     HMI_DEBUG("wm:lm", "Updating role is not necessary because new_role is not specified when restriction mode is changed");
339 #else
340                 if (crr_state.car.is_changed) {
341                     // Updating role is not necessary
342                     // because new_role is not specified
343                     // when car state is changed
344                     HMI_DEBUG("wm:lm", "Updating role is not necessary because new_role is not specified when car state is changed");
345 #endif
346                 }
347                 else {
348
349                     std::map<std::string, std::vector<pm::AreaState>> ctg_list;
350                     for (int ctg_no=stm::gStmCategoryNoMin;
351                          ctg_no<=stm::gStmCategoryNoMax; ctg_no++) {
352                         const char* ctg = stm::gStmCategoryName[ctg_no];
353                         HMI_DEBUG("wm:pm", "ctg:%s", ctg);
354
355                         // Create area list of previous app
356                         std::vector<pm::AreaState> area_list;
357                         for (pm::AreaState area_state : prv_layout_state.area_list) {
358                             if (std::string(ctg) == area_state.category) {
359                                 // If there is the category which is same with new category in previous layout,
360                                 // push it to area list
361                                 HMI_DEBUG("wm:pm", "push area_state to prv list");
362                                 area_list.push_back(area_state);
363                             }
364                         }
365
366                         int prv_ctg_num = prv_layout_state.category_num[ctg];
367                         int crr_ctg_num = crr_layout_state.category_num[ctg];
368                         HMI_DEBUG("wm:pm", "crr_ctg_num:%d prv_ctg_num:%d", crr_ctg_num, prv_ctg_num);
369
370                         // Remove state of area which is used no longer from area list
371                         if (crr_ctg_num < prv_ctg_num) {
372                             HMI_DEBUG("wm:pm", "crr_ctg_num < prv_ctg_num");
373                             if (0 == strcmp(ctg, category.c_str())) {
374                                 for (auto i = area_list.begin(); i != area_list.end(); ++i) {
375                                     if ((role == i->role) && (area == i->name)) {
376                                         HMI_DEBUG("wm:pm", "store removed role:%s", i->role.c_str());
377                                         crr_layout_state.last_invisibled_role[category] = i->role;
378
379                                         HMI_DEBUG("wm:pm", "remove area state which have same role with requested role");
380                                         area_list.erase(i);
381
382                                         prv_ctg_num--;
383
384                                         if (crr_ctg_num == prv_ctg_num) {
385                                             break;
386                                         }
387                                     }
388                                 }
389                             }
390                             else {
391                                 HMI_DEBUG("wm:pm", "store removed role:%s", area_list.begin()->role.c_str());
392                                 crr_layout_state.last_invisibled_role[ctg] = area_list.begin()->role;
393
394                                 HMI_DEBUG("wm:pm", "remove the oldest area data");
395                                 area_list.erase(area_list.begin());
396                             }
397                         }
398                         else if (crr_ctg_num >= prv_ctg_num) {
399                             HMI_DEBUG("wm:pm", "crr_ctg_num >= prv_ctg_num");
400                             if (0 == strcmp(ctg, category.c_str())) {
401                                 HMI_DEBUG("wm:pm", "category of requested role is same");
402                                 if ((crr_ctg_num == prv_ctg_num) && (0 != prv_ctg_num)) {
403                                     HMI_DEBUG("wm:pm", "store removed role:%s", area_list.begin()->role.c_str());
404                                     crr_layout_state.last_invisibled_role[ctg] = area_list.begin()->role;
405
406                                     HMI_DEBUG("wm:pm", "remove the oldest area data for adding requested role");
407                                     area_list.erase(area_list.begin());
408                                 }
409                             }
410                         }
411
412                         // Check
413                         for (pm::AreaState area_state : area_list) {
414                             HMI_DEBUG("wm:pm", "area_list name:%s category:%s role:%s",
415                                       area_state.name.c_str(),
416                                       area_state.category.c_str(),
417                                       area_state.role.c_str());
418                         }
419
420                         ctg_list[ctg] = area_list;
421                     }
422
423                     if (event == "activate") {
424                         HMI_DEBUG("wm:pm", "event is activate");
425                         // First, update area for requested role
426                         bool request_for_this_layer = false;
427                         bool updated = false;
428                         for (pm::AreaState &as : crr_layout_state.area_list) {
429                             if (as.category == category) {
430                                 request_for_this_layer = true;
431                                 if (as.name == area) {
432                                     HMI_DEBUG("wm:pm", "update area for requested category:%s role:%s area:%s", category.c_str(), role.c_str(), area.c_str());
433                                     as.role = role;
434                                     updated = true;
435                                     break;
436                                 }
437                             }
438                         }
439
440                         // If NOT updated: there is not requested area in new layout, 
441                         // requested role is used later.
442                         if (request_for_this_layer && (!updated)) {
443                             HMI_DEBUG("wm:pm", "requested role is used later category:%s role:%s area:%s", category.c_str(), role.c_str(), area.c_str());
444                             pm::AreaState area_state;
445                             area_state.name = area;
446                             area_state.category = category;
447                             area_state.role = role;
448                             ctg_list[category].push_back(area_state);
449                         }
450                     }
451
452                     // Update areas
453                     for (pm::AreaState &as : crr_layout_state.area_list) {
454                         if (as.role != role) {  // This conditional expression is useful in only when requested activate event
455                             HMI_DEBUG("wm:pm", "update areas for category:%s", as.category.c_str());
456                             if (0 != ctg_list[as.category].size()) {
457                                 HMI_DEBUG("wm:pm", "update role to %s by using area list this category",
458                                           ctg_list[as.category].begin()->role);
459                                 as.role = ctg_list[as.category].begin()->role;
460                                 ctg_list[as.category].erase(ctg_list[as.category].begin());
461                             }
462                             else {
463                                 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]);
464                                 as.role = crr_layout_state.last_invisibled_role[as.category];
465                                 crr_layout_state.last_invisibled_role.erase(as.category);
466                             }
467                         }
468                     }
469                 }
470             }
471             // Update current layout of this layer
472             pm::g_crr_layers[layer_name].layout_state = crr_layout_state;
473         }
474     }
475
476     // Check
477     for (auto itr : pm::g_crr_layers) {
478         pm::LayerState ls = itr.second;
479         HMI_DEBUG("wm:pm", ">>> LAYER:%s",ls.name.c_str());
480         HMI_DEBUG("wm:pm", ">>> >>> LAYOUT:%s", ls.layout_state.name.c_str());
481
482         for (pm::AreaState as : ls.layout_state.area_list) {
483             HMI_DEBUG("wm:pm", ">>> >>> >>> AREA:%s", as.name.c_str());
484             HMI_DEBUG("wm:pm", ">>> >>> >>> >>> CTG:%s", as.category.c_str());
485             HMI_DEBUG("wm:pm", ">>> >>> >>> >>> ROLE:%s", as.role.c_str());
486         }
487     }
488 #endif // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
489
490     json_object* json_out = json_object_new_object();
491
492     // Create result
493     // {
494     //     "parking_brake": {
495     //         "is_changed": <bool>,
496     //         "state": <const char*>
497     //     },
498     addStateToJson("parking_brake",
499                    crr_state.parking_brake.is_changed,
500                    stm::gStmParkingBrakeStateNo2Name[crr_state.parking_brake.state],
501                    &json_out);
502
503     //     "accel_pedal": {
504     //         "is_changed": <bool>,
505     //         "state": <const char*>
506     //     },
507     addStateToJson("accel_pedal",
508                    crr_state.accel_pedal.is_changed,
509                    stm::gStmAccelPedalStateNo2Name[crr_state.accel_pedal.state],
510                    &json_out);
511
512     //     "lightstatus_brake": {
513     //         "is_changed": <bool>,
514     //         "state": <const char*>
515     //     },
516     addStateToJson("lightstatus_brake",
517                    crr_state.lightstatus_brake.is_changed,
518                    stm::gStmLightstatusBrakeStateNo2Name[crr_state.lightstatus_brake.state],
519                    &json_out);
520
521     //     "car": {
522     //         "is_changed": <bool>,
523     //         "state": <const char*>
524     //     },
525     addStateToJson("car",
526                    crr_state.car.is_changed,
527                    stm::gStmCarStateNo2Name[crr_state.car.state],
528                    &json_out);
529
530     //     "lamp": {
531     //         "is_changed": <bool>,
532     //         "state": <const char*>
533     //     },
534     addStateToJson("lamp",
535                    crr_state.lamp.is_changed,
536                    stm::gStmLampStateNo2Name[crr_state.lamp.state],
537                    &json_out);
538
539     //     "restriction_mode": {
540     //         "is_changed": <bool>,
541     //         "state": <const char*>
542     //     },
543     addStateToJson("restriction_mode",
544                    crr_state.restriction_mode.is_changed,
545                    stm::gStmRestrictionModeStateNo2Name[crr_state.restriction_mode.state],
546                    &json_out);
547
548     //     "layers": [
549     json_object* json_layer = json_object_new_array();
550     json_object* json_tmp;
551
552     //         {
553     //             "homescreen": {
554     //                 "is_changed": <bool>,
555     //                 "state": <const char*>
556     //             }
557     //         },
558     //     ]
559     // }
560     json_tmp = json_object_new_object();
561     addStateToJson("homescreen",
562                    crr_state.layer[stm::gStmLayerNoHomescreen].is_changed,
563                    stm::gStmLayoutNo2Name[crr_state.layer[stm::gStmLayerNoHomescreen].state],
564                    &json_tmp);
565     json_object_array_add(json_layer, json_tmp);
566
567     //         {
568     //             "apps": {
569     //                 "is_changed": <bool>,
570     //                 "state": <const char*>
571     //             }
572     //         },
573     json_tmp = json_object_new_object();
574     addStateToJson("apps",
575                    crr_state.layer[stm::gStmLayerNoApps].is_changed,
576                    stm::gStmLayoutNo2Name[crr_state.layer[stm::gStmLayerNoApps].state],
577                    &json_tmp);
578     json_object_array_add(json_layer, json_tmp);
579
580     //         {
581     //             "restriction": {
582     //                 "is_changed": <bool>,
583     //                 "state": <const char*>
584     //             }
585     //         },
586     json_tmp = json_object_new_object();
587     addStateToJson("restriction",
588                    crr_state.layer[stm::gStmLayerNoRestriction].is_changed,
589                    stm::gStmLayoutNo2Name[crr_state.layer[stm::gStmLayerNoRestriction].state],
590                    &json_tmp);
591     json_object_array_add(json_layer, json_tmp);
592
593     //         {
594     //             "on_screen": {
595     //                 "is_changed": <bool>,
596     //                 "state": <const char*>
597     //             }
598     //         },
599     json_tmp = json_object_new_object();
600     addStateToJson("on_screen",
601                    crr_state.layer[stm::gStmLayerNoOnScreen].is_changed,
602                    stm::gStmLayoutNo2Name[crr_state.layer[stm::gStmLayerNoOnScreen].state],
603                    &json_tmp);
604     json_object_array_add(json_layer, json_tmp);
605
606     // Add json array of layer
607     json_object_object_add(json_out, "layers", json_layer);
608
609     // Notify state is changed
610     if (nullptr != pm::callback.onStateTransitioned) {
611         pm::callback.onStateTransitioned(json_out);
612     }
613
614     if (crr_state.car.is_changed) {
615         if (stm::gStmCarStateNoRun == crr_state.car.state) {
616             // Set delay event(restriction mode on)
617             checkPolicyEntry(STM_EVT_NO_RESTRICTION_MODE_ON, 3000, nullptr);
618         }
619         else if (stm::gStmCarStateNoStop == crr_state.car.state) {
620             // Set event(restriction mode off)
621             checkPolicyEntry(STM_EVT_NO_RESTRICTION_MODE_OFF, 0, nullptr);
622
623             // Stop timer for restriction on event
624             if (pm::event_source_list.find(STM_EVT_NO_RESTRICTION_MODE_ON)
625               != pm::event_source_list.end()) {
626                 HMI_DEBUG("wm:pm", "Stop timer for restriction on");
627                 sd_event_source *event_source
628                     = pm::event_source_list[STM_EVT_NO_RESTRICTION_MODE_ON];
629                 int ret = sd_event_source_set_enabled(event_source, SD_EVENT_OFF);
630                 if (0 > ret) {
631                     HMI_ERROR("wm:pm", "Failed to stop timer");
632                 }
633             }
634         }
635     }
636
637     // Release json_object
638     json_object_put(json_out);
639
640     // Release data
641     delete (int*)data;
642
643     // Destroy sd_event_source object
644     sd_event_source_unref(source);
645
646     // Remove event source from list
647     if (pm::event_source_list.find(event_data) != pm::event_source_list.end()) {
648         pm::event_source_list.erase(event_data);
649     }
650
651     HMI_DEBUG("wm:pm", ">>>>>>>>>> FINISH CHECK POLICY");
652     return 0;
653 }
654
655 static int timerEvent(sd_event_source *source, uint64_t usec, void *data) {
656     int ret = checkPolicy(source, data);
657     return ret;
658 };
659
660 static int checkPolicyEntry(int event, uint64_t delay_ms, const char* role)
661 {
662     HMI_DEBUG("wm:pm", "Call");
663     HMI_DEBUG("wm:pm", "event:0x%x", event);
664
665     // Store event info
666     if (nullptr == role) {
667         pm::g_event_info_list[event] = std::string("");
668     }
669     else {
670         pm::g_event_info_list[event] = std::string(role);
671     }
672
673     if (0 == delay_ms) {
674         int ret = sd_event_add_defer(pm::event_loop, NULL,
675                                      &checkPolicy, new int(event));
676         if (0 > ret) {
677             HMI_ERROR("wm:pm", "Faild to sd_event_add_defer: errno:%d", ret);
678             pm::g_event_info_list.erase(event);
679             return -1;
680         }
681     }
682     else {
683         // Get current time
684         struct timespec time_spec;
685         clock_gettime(CLOCK_MONOTONIC, &time_spec);
686
687         // Calculate timer fired time
688         uint64_t usec = (time_spec.tv_sec * 1000000)
689             + (time_spec.tv_nsec / 1000)
690             + (delay_ms * 1000);
691
692         // Set timer
693         struct sd_event_source* event_source;
694         int ret = sd_event_add_time(pm::event_loop, &event_source, CLOCK_MONOTONIC, usec, 1,
695                                     &timerEvent, new int(event));
696         if (0 > ret) {
697             HMI_ERROR("wm:pm", "Faild to sd_event_add_time: errno:%d", ret);
698             pm::g_event_info_list.erase(event);
699             return -1;
700         }
701
702         // Store event source
703         pm::event_source_list[event] = event_source;
704     }
705
706     return 0;
707 }
708
709 void PolicyManager::registerCallback(CallbackTable callback) {
710     pm::callback.onStateTransitioned = callback.onStateTransitioned;
711     pm::callback.onError             = callback.onError;
712 }
713
714 int PolicyManager::inputEvent(json_object* json_in) {
715     HMI_DEBUG("wm:pm", "Call");
716
717     // Check arguments
718     if (nullptr == json_in) {
719         HMI_ERROR("wm:pm", "Argument is NULL!!");
720         return -1;
721     }
722
723     // Get event from json_object
724     const char* event = this->getStringFromJson(json_in, "event");
725     int event_no = 0;
726     if (nullptr != event) {
727         // Convert name to number
728         event_no = this->eventname2no_[event];
729         HMI_DEBUG("wm:pm", "event(%s:%d)", event, event_no);
730     }
731
732     // Get role from json_object
733     const char* role = this->getStringFromJson(json_in, "role");
734     int category_no = 0;
735     if (nullptr != role) {
736         HMI_DEBUG("wm:pm", "role(%s)", role);
737
738         // Convert role to category
739         const char* category = this->role2category_[role].c_str();
740         if (0 == strcmp("", category)) {
741             HMI_ERROR("wm:pm", "Error!!");
742             return -1;
743         }
744         HMI_DEBUG("wm:pm", "category(%s)", category);
745
746         // Convert name to number
747         category_no = categoryname2no_[category];
748         HMI_DEBUG("wm:pm", "role(%s), category(%s:%d)", role, category, category_no);
749     }
750
751     // Get areat from json_object
752     const char* area = this->getStringFromJson(json_in, "area");
753     int area_no = 0;
754     if (nullptr != area) {
755         // Convert name to number
756         area_no = areaname2no_[area];
757         HMI_DEBUG("wm:pm", "area(%s:%d)", area, area_no);
758     }
759
760     // Check policy
761     checkPolicyEntry((event_no | category_no | area_no), 0, role);
762
763     return 0;
764 }
765
766 std::string PolicyManager::roleToCategory(const char* role) {
767     return this->role2category_[role];
768 }
769
770 extern const char* kDefaultRoleDb;
771 int PolicyManager::loadRoleDb() {
772     HMI_DEBUG("wm:pm", "Call");
773
774     std::string file_name;
775
776     // Get afm application installed dir
777     char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
778     HMI_DEBUG("wm:pm", "afm_app_install_dir:%s", afm_app_install_dir);
779
780     if (!afm_app_install_dir) {
781         HMI_ERROR("wm:pm", "AFM_APP_INSTALL_DIR is not defined");
782     }
783     else {
784         file_name = std::string(afm_app_install_dir) + std::string("/etc/role.db");
785     }
786
787     // Load role.db
788     json_object* json_obj;
789     int ret = this->inputJsonFilie(file_name.c_str(), &json_obj);
790     if (0 > ret) {
791         HMI_ERROR("wm:pm", "Could not open role.db, so use default role information");
792         json_obj = json_tokener_parse(kDefaultRoleDb);
793     }
794     HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj));
795
796     json_object* json_roles;
797     if (!json_object_object_get_ex(json_obj, "roles", &json_roles)) {
798         HMI_ERROR("wm:pm", "Parse Error!!");
799         return -1;
800     }
801
802     int len = json_object_array_length(json_roles);
803     HMI_DEBUG("wm:pm", "json_cfg len:%d", len);
804     HMI_DEBUG("wm:pm", "json_cfg dump:%s", json_object_get_string(json_roles));
805
806     json_object* json_tmp;
807     const char* category;
808     const char* roles;
809     const char* areas;
810     for (int i=0; i<len; i++) {
811         json_tmp = json_object_array_get_idx(json_roles, i);
812
813         category = this->getStringFromJson(json_tmp, "category");
814         roles =  this->getStringFromJson(json_tmp, "role");
815         areas =  this->getStringFromJson(json_tmp, "area");
816
817         if ((nullptr == category) || (nullptr == roles) || (nullptr == areas)) {
818             HMI_ERROR("wm:pm", "Parse Error!!");
819             return -1;
820         }
821
822         // Parse roles by '|'
823         std::vector<std::string> vct_roles;
824         vct_roles = this->parseString(std::string(roles), '|');
825
826         // Parse areas by '|'
827         std::vector<std::string> vct_areas;
828         vct_areas = this->parseString(std::string(areas), '|');
829
830         // Set role, category, default area
831         for (auto itr = vct_roles.begin(); itr != vct_roles.end(); ++itr) {
832             // Delete space from role and area name
833             std::string role = this->deleteSpace(*itr);
834             std::string area = this->deleteSpace(vct_areas[0]);
835
836             this->role2category_[role] = std::string(category);
837             this->role2defaultarea_[role] = area;
838         }
839
840         this->category2role_[std::string(category)] = std::string(roles);
841     }
842
843     // Check
844     HMI_DEBUG("wm:pm", "Check role2category_");
845     for (auto& x:this->role2category_){
846         HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
847     }
848
849     HMI_DEBUG("wm:pm", "Check role2defaultarea_");
850     for (auto& x:this->role2defaultarea_){
851         HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
852     }
853
854     HMI_DEBUG("wm:pm", "Check category2role_");
855     for (auto& x:this->category2role_){
856         HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
857     }
858
859     return 0;
860 }
861
862 extern const char* kDefaultLayoutDb;
863 int PolicyManager::loadLayoutDb() {
864     HMI_DEBUG("wm:lm", "Call");
865
866     // Get afm application installed dir
867     char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
868     HMI_DEBUG("wm:pm", "afm_app_install_dir:%s", afm_app_install_dir);
869
870     std::string file_name;
871     if (!afm_app_install_dir) {
872         HMI_ERROR("wm:pm", "AFM_APP_INSTALL_DIR is not defined");
873     }
874     else {
875         file_name = std::string(afm_app_install_dir) + std::string("/etc/layout.db");
876     }
877
878     // Load layout.db
879     json_object* json_obj;
880     int ret = this->inputJsonFilie(file_name.c_str(), &json_obj);
881     if (0 > ret) {
882         HMI_DEBUG("wm:pm", "Could not open layout.db, so use default layout information");
883         json_obj = json_tokener_parse(kDefaultLayoutDb);
884     }
885     HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj));
886
887     // Perse layouts
888     HMI_DEBUG("wm:pm", "Perse layouts");
889     json_object* json_cfg;
890     if (!json_object_object_get_ex(json_obj, "layouts", &json_cfg)) {
891         HMI_ERROR("wm:pm", "Parse Error!!");
892         return -1;
893     }
894
895     int len = json_object_array_length(json_cfg);
896     HMI_DEBUG("wm:pm", "json_cfg len:%d", len);
897     HMI_DEBUG("wm:pm", "json_cfg dump:%s", json_object_get_string(json_cfg));
898
899     const char* layout;
900     const char* role;
901     const char* category;
902     for (int i=0; i<len; i++) {
903         json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
904
905         layout = this->getStringFromJson(json_tmp, "name");
906         if (nullptr == layout) {
907             HMI_ERROR("wm:pm", "Parse Error!!");
908             return -1;
909         }
910         HMI_DEBUG("wm:pm", "> layout:%s", layout);
911
912         json_object* json_area_array;
913         if (!json_object_object_get_ex(json_tmp, "areas", &json_area_array)) {
914           HMI_ERROR("wm:pm", "Parse Error!!");
915           return -1;
916         }
917
918         int len_area = json_object_array_length(json_area_array);
919         HMI_DEBUG("wm:pm", "json_area_array len:%d", len_area);
920         HMI_DEBUG("wm:pm", "json_area_array dump:%s", json_object_get_string(json_area_array));
921
922         pm::LayoutState layout_state;
923         pm::AreaState area_state;
924         std::map<std::string, int> category_num;
925         for (int ctg_no = stm::gStmCategoryNoMin;
926              ctg_no <= stm::gStmCategoryNoMax; ctg_no++) {
927             const char* ctg_name = stm::gStmCategoryName[ctg_no];
928             category_num[ctg_name] = 0;
929         }
930
931         for (int j=0; j<len_area; j++) {
932             json_object* json_area = json_object_array_get_idx(json_area_array, j);
933
934             // Get area name
935             const char* area = this->getStringFromJson(json_area, "name");
936             if (nullptr == area) {
937               HMI_ERROR("wm:pm", "Parse Error!!");
938               return -1;
939             }
940             area_state.name = std::string(area);
941             HMI_DEBUG("wm:pm", ">> area:%s", area);
942
943             // Get app attribute of the area
944             category = this->getStringFromJson(json_area, "category");
945             if (nullptr == category) {
946                 HMI_ERROR("wm:pm", "Parse Error!!");
947                 return -1;
948             }
949             area_state.category = std::string(category);
950             category_num[category]++;
951             HMI_DEBUG("wm:pm", ">>> category:%s", category);
952
953             role = this->getStringFromJson(json_area, "role");
954             if (nullptr != role) {
955                 // Role is NOT essential here
956                 area_state.role = std::string(role);
957                 HMI_DEBUG("wm:pm", ">>> role:%s", role);
958             }
959
960             layout_state.area_list.push_back(area_state);
961
962         }
963
964         layout_state.name = layout;
965         layout_state.category_num = category_num;
966         pm::g_default_layouts[layout] = layout_state;
967     }
968
969     // initialize for none layout
970     pm::LayoutState none_layout_state;
971     memset(&none_layout_state, 0, sizeof(none_layout_state));
972     none_layout_state.name                 = "none";
973     pm::g_default_layouts["none"] = none_layout_state;
974
975     // Check
976     for(auto itr_layout = pm::g_default_layouts.begin();
977       itr_layout != pm::g_default_layouts.end(); ++itr_layout) {
978         HMI_DEBUG("wm:pm", ">>> layout:%s", itr_layout->first.c_str());
979
980         for (auto itr_area = itr_layout->second.area_list.begin();
981           itr_area != itr_layout->second.area_list.end(); ++itr_area) {
982             HMI_DEBUG("wm:pm", ">>> >>> area    :%s", itr_area->name.c_str());
983             HMI_DEBUG("wm:pm", ">>> >>> category:%s", itr_area->category.c_str());
984             HMI_DEBUG("wm:pm", ">>> >>> role    :%s", itr_area->role.c_str());
985 #if 0
986             for (auto itr_role = itr_area->second.begin();
987               itr_role != itr_area->second.end(); ++itr_role) {
988                 HMI_DEBUG("wm:pm", ">>> >>> >>> attribute:%s, name:%s",
989                           itr_role->first.c_str(), itr_role->second.c_str());
990             }
991 #endif
992         }
993     }
994
995     // Release json_object
996     json_object_put(json_obj);
997
998     return 0;
999 }
1000
1001 // TODO:
1002 // This function will be removed because json_helper has same function.
1003 // json_helper should be library.
1004 const char* PolicyManager::getStringFromJson(json_object* obj, const char* key) {
1005     if ((nullptr == obj) || (nullptr == key)) {
1006         HMI_ERROR("wm:pm", "Argument is nullptr!!!");
1007         return nullptr;
1008     }
1009
1010     json_object* tmp;
1011     if (!json_object_object_get_ex(obj, key, &tmp)) {
1012         HMI_DEBUG("wm:pm", "Not found key \"%s\"", key);
1013         return nullptr;
1014     }
1015
1016     return json_object_get_string(tmp);
1017 }
1018
1019 // TODO:
1020 // This function will be removed because json_helper has same function.
1021 // json_helper should be library.
1022 int PolicyManager::inputJsonFilie(const char* file, json_object** obj) {
1023     const int input_size = 128;
1024     int ret = -1;
1025
1026     if ((nullptr == file) || (nullptr == obj)) {
1027         HMI_ERROR("wm:jh", "Argument is nullptr!!!");
1028         return ret;
1029     }
1030
1031     HMI_DEBUG("wm:jh", "Input file: %s", file);
1032
1033     // Open json file
1034     FILE *fp = fopen(file, "rb");
1035     if (nullptr == fp) {
1036         HMI_ERROR("wm:jh", "Could not open file");
1037         return ret;
1038     }
1039
1040     // Parse file data
1041     struct json_tokener *tokener = json_tokener_new();
1042     enum json_tokener_error json_error;
1043     char buffer[input_size];
1044     int block_cnt = 1;
1045     while (1) {
1046         size_t len = fread(buffer, sizeof(char), input_size, fp);
1047         *obj = json_tokener_parse_ex(tokener, buffer, len);
1048         if (nullptr != *obj) {
1049             HMI_DEBUG("wm:jh", "File input is success");
1050             ret = 0;
1051             break;
1052         }
1053
1054         json_error = json_tokener_get_error(tokener);
1055         if ((json_tokener_continue != json_error)
1056             || (input_size > len)) {
1057             HMI_ERROR("wm:jh", "Failed to parse file (byte:%d err:%s)",
1058                       (input_size * block_cnt), json_tokener_error_desc(json_error));
1059             HMI_ERROR("wm:jh", "\n%s", buffer);
1060             *obj = nullptr;
1061             break;
1062         }
1063         block_cnt++;
1064     }
1065
1066     // Close json file
1067     fclose(fp);
1068
1069     // Free json_tokener
1070     json_tokener_free(tokener);
1071
1072     return ret;
1073 }
1074
1075 std::vector<std::string> PolicyManager::parseString(std::string str, char delimiter) {
1076     // Parse string by delimiter
1077     std::vector<std::string> vct;
1078     std::stringstream ss{str};
1079     std::string buf;
1080     while (std::getline(ss, buf, delimiter)) {
1081       if (!buf.empty()) {
1082         vct.push_back(buf);
1083       }
1084     }
1085     return vct;
1086 }
1087
1088 std::string PolicyManager::deleteSpace(std::string str) {
1089     std::string ret = str;
1090     size_t pos;
1091     while ((pos = ret.find_first_of(" ")) != std::string::npos) {
1092       ret.erase(pos, 1);
1093     }
1094     return ret;
1095 }
1096
1097 const char* kDefaultRoleDb = "{ \
1098     \"roles\":[ \
1099     { \
1100         \"category\": \"homescreen\", \
1101         \"role\": \"homescreen\", \
1102         \"area\": \"full\", \
1103     }, \
1104     { \
1105         \"category\": \"map\", \
1106         \"role\": \"map\", \
1107         \"area\": \"full | normal | split.main\", \
1108     }, \
1109     { \
1110         \"category\": \"general\", \
1111         \"role\": \"poi | music | video | browser | sdl | settings | mixer | radio | hvac | dashboard | debug\", \
1112         \"area\": \"normal\", \
1113     }, \
1114     { \
1115         \"category\": \"phone\", \
1116         \"role\": \"phone\", \
1117         \"area\": \"normal\", \
1118     }, \
1119     { \
1120         \"category\": \"splitable\", \
1121         \"role\": \"splitable1 | splitable2\", \
1122         \"area\": \"normal | split.main | split.sub\", \
1123     }, \
1124     { \
1125         \"category\": \"popup\", \
1126         \"role\": \"popup\", \
1127         \"area\": \"on_screen\", \
1128     }, \
1129     { \
1130         \"category\": \"system_alert\", \
1131         \"role\": \"system_alert\", \
1132         \"area\": \"on_screen\", \
1133     }, \
1134     { \
1135         \"category\": \"tbt\", \
1136         \"role\": \"tbt\", \
1137         \"area\": \"hud\", \
1138     } \
1139     ] \
1140 }";
1141
1142
1143 const char* kDefaultLayoutDb = "{ \
1144     \"layouts\": [ \
1145         { \
1146             \"name\": \"pu\", \
1147             \"layer\": \"on_screen\", \
1148             \"areas\": [ \
1149                 { \
1150                     \"name\": \"pop_up\", \
1151                     \"role\": \"incomming_call\" \
1152                 } \
1153             ] \
1154         }, \
1155         { \
1156             \"name\": \"sa\", \
1157             \"layer\": \"on_screen\", \
1158             \"areas\": [ \
1159                 { \
1160                     \"name\": \"system_alert\", \
1161                     \"role\": \"system_alert\" \
1162                 } \
1163             ] \
1164         }, \
1165         { \
1166             \"name\": \"m1\", \
1167             \"layer\": \"apps\", \
1168             \"areas\": [ \
1169                 { \
1170                     \"name\": \"normal\", \
1171                     \"role\": \"map\" \
1172                 } \
1173             ] \
1174         }, \
1175         { \
1176             \"name\": \"m2\", \
1177             \"layer\": \"apps\", \
1178             \"areas\": [ \
1179                 { \
1180                     \"name\": \"split.main\", \
1181                     \"role\": \"map\" \
1182                 }, \
1183                 { \
1184                     \"name\": \"split.sub\", \
1185                     \"category\": \"hvac\" \
1186                 } \
1187             ] \
1188         }, \
1189         { \
1190             \"name\": \"mf\", \
1191             \"layer\": \"apps\", \
1192             \"areas\": [ \
1193                 { \
1194                     \"name\": \"full\", \
1195                     \"role\": \"map\" \
1196                 } \
1197             ] \
1198         }, \
1199         { \
1200             \"name\": \"s1\", \
1201             \"layer\": \"apps\", \
1202             \"areas\": [ \
1203                 { \
1204                     \"name\": \"normal\", \
1205                     \"category\": \"splitable\" \
1206                 } \
1207             ] \
1208         }, \
1209         { \
1210             \"name\": \"s2\", \
1211             \"layer\": \"apps\", \
1212             \"areas\": [ \
1213                 { \
1214                     \"name\": \"split.main\", \
1215                     \"category\": \"splitable\" \
1216                 }, \
1217                 { \
1218                     \"name\": \"split.sub\", \
1219                     \"category\": \"splitable\" \
1220                 } \
1221             ] \
1222         }, \
1223         { \
1224             \"name\": \"g\", \
1225             \"layer\": \"apps\", \
1226             \"areas\": [ \
1227                 { \
1228                     \"name\": \"normal\", \
1229                     \"category\": \"general\" \
1230                 } \
1231             ] \
1232         }, \
1233         { \
1234             \"name\": \"hs\", \
1235             \"layer\": \"homescreen\", \
1236             \"areas\": [ \
1237                 { \
1238                     \"name\": \"full\", \
1239                     \"role\": \"homescreen\" \
1240                 } \
1241             ] \
1242         } \
1243     ], \
1244     \"areas\": [ \
1245         { \
1246             \"name\": \"normal\", \
1247             \"rect\": { \
1248                 \"x\": 0, \
1249                 \"y\": 218, \
1250                 \"w\": 1080, \
1251                 \"h\": 1488 \
1252             } \
1253         }, \
1254         { \
1255             \"name\": \"split.main\", \
1256             \"rect\": { \
1257                 \"x\": 0, \
1258                 \"y\": 218, \
1259                 \"w\": 1080, \
1260                 \"h\": 744 \
1261             } \
1262         }, \
1263         { \
1264             \"name\": \"split.sub\", \
1265             \"rect\": { \
1266                 \"x\": 0, \
1267                 \"y\": 962, \
1268                 \"w\": 1080, \
1269                 \"h\": 744 \
1270             } \
1271         }, \
1272         { \
1273             \"name\": \"full\", \
1274             \"rect\": { \
1275                 \"x\": 0, \
1276                 \"y\": 0, \
1277                 \"w\": 1080, \
1278                 \"h\": 1920 \
1279             } \
1280         }, \
1281         { \
1282             \"name\": \"pop_up\", \
1283             \"rect\": { \
1284                 \"x\": 0, \
1285                 \"y\": 640, \
1286                 \"w\": 1080, \
1287                 \"h\": 640 \
1288             } \
1289         }, \
1290         { \
1291             \"name\": \"system_alert\", \
1292             \"rect\": { \
1293                 \"x\": 0, \
1294                 \"y\": 640, \
1295                 \"w\": 1080, \
1296                 \"h\": 640 \
1297             } \
1298         } \
1299     ] \
1300 }";