Migrate hmi-debug into util
[apps/agl-service-windowmanager.git] / src / window_manager.cpp
1 /*
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <fstream>
18 #include <regex>
19
20 #include "window_manager.hpp"
21 #include "json_helper.hpp"
22 #include "applist.hpp"
23
24 extern "C"
25 {
26 #include <systemd/sd-event.h>
27 }
28
29 namespace wm
30 {
31
32 static const uint64_t kTimeOut = 3ULL; /* 3s */
33
34 /* DrawingArea name used by "{layout}.{area}" */
35 const char kNameLayoutNormal[] = "normal";
36 const char kNameLayoutSplit[]  = "split";
37 const char kNameAreaFull[]     = "full";
38 const char kNameAreaMain[]     = "main";
39 const char kNameAreaSub[]      = "sub";
40
41 /* Key for json obejct */
42 const char kKeyDrawingName[] = "drawing_name";
43 const char kKeyDrawingArea[] = "drawing_area";
44 const char kKeyDrawingRect[] = "drawing_rect";
45 const char kKeyX[]           = "x";
46 const char kKeyY[]           = "y";
47 const char kKeyWidth[]       = "width";
48 const char kKeyHeight[]      = "height";
49 const char kKeyWidthPixel[]  = "width_pixel";
50 const char kKeyHeightPixel[] = "height_pixel";
51 const char kKeyWidthMm[]     = "width_mm";
52 const char kKeyHeightMm[]    = "height_mm";
53 const char kKeyScale[]       = "scale";
54 const char kKeyIds[]         = "ids";
55
56 static sd_event_source *g_timer_ev_src = nullptr;
57 static AppList g_app_list;
58 static WindowManager *g_context;
59
60 namespace
61 {
62
63 using nlohmann::json;
64
65 result<json> file_to_json(char const *filename)
66 {
67     json j;
68     std::ifstream i(filename);
69     if (i.fail())
70     {
71         HMI_DEBUG("Could not open config file, so use default layer information");
72         j = default_layers_json;
73     }
74     else
75     {
76         i >> j;
77     }
78
79     return Ok(j);
80 }
81
82 struct result<layer_map> load_layer_map(char const *filename)
83 {
84     HMI_DEBUG("loading IDs from %s", filename);
85
86     auto j = file_to_json(filename);
87     if (j.is_err())
88     {
89         return Err<layer_map>(j.unwrap_err());
90     }
91     json jids = j.unwrap();
92
93     return to_layer_map(jids);
94 }
95
96 static int processTimerHandler(sd_event_source *s, uint64_t usec, void *userdata)
97 {
98     HMI_NOTICE("Time out occurs because the client replys endDraw slow, so revert the request");
99     reinterpret_cast<wm::WindowManager *>(userdata)->timerHandler();
100     return 0;
101 }
102
103 static void onStateTransitioned(std::vector<WMAction> actions)
104 {
105     g_context->startTransitionWrapper(actions);
106 }
107
108 static void onError()
109 {
110     g_context->processError(WMError::LAYOUT_CHANGE_FAIL);
111 }
112 } // namespace
113
114 /**
115  * WindowManager Impl
116  */
117 WindowManager::WindowManager(wl::display *d)
118     : chooks{this},
119       display{d},
120       controller{},
121       outputs(),
122       layers(),
123       id_alloc{},
124       pending_events(false)
125 {
126     char const *path_layers_json = getenv("AFM_APP_INSTALL_DIR");
127     std::string path;
128     if (!path_layers_json)
129     {
130         HMI_ERROR("AFM_APP_INSTALL_DIR is not defined");
131         path = std::string(path_layers_json);
132     }
133     else
134     {
135         path = std::string(path_layers_json) + std::string("/etc/layers.json");
136     }
137
138     try
139     {
140         {
141             auto l = load_layer_map(path.c_str());
142             if (l.is_ok())
143             {
144                 this->layers = l.unwrap();
145             }
146             else
147             {
148                 HMI_ERROR("%s", l.err().value());
149             }
150         }
151     }
152     catch (std::exception &e)
153     {
154         HMI_ERROR("Loading of configuration failed: %s", e.what());
155     }
156 }
157
158 int WindowManager::init()
159 {
160     if (!this->display->ok())
161     {
162         return -1;
163     }
164
165     if (this->layers.mapping.empty())
166     {
167         HMI_ERROR("No surface -> layer mapping loaded");
168         return -1;
169     }
170
171     // TODO: application requests by old role,
172     //       so create role map (old, new)
173     // Load old_role.db
174     this->loadOldRoleDb();
175
176     // Store my context for calling callback from PolicyManager
177     g_context = this;
178
179     // Initialize PMWrapper
180     this->pmw.initialize();
181
182     // Register callback to PolicyManager
183     this->pmw.registerCallback(onStateTransitioned, onError);
184
185     // Make afb event
186     for (int i = Event_Val_Min; i <= Event_Val_Max; i++)
187     {
188         map_afb_event[kListEventName[i]] = afb_daemon_make_event(kListEventName[i]);
189     }
190
191     this->display->add_global_handler(
192         "wl_output", [this](wl_registry *r, uint32_t name, uint32_t v) {
193             this->outputs.emplace_back(std::make_unique<wl::output>(r, name, v));
194         });
195
196     this->display->add_global_handler(
197         "ivi_wm", [this](wl_registry *r, uint32_t name, uint32_t v) {
198             this->controller =
199                 std::make_unique<struct compositor::controller>(r, name, v);
200
201             // Init controller hooks
202             this->controller->chooks = &this->chooks;
203
204             // This protocol needs the output, so lets just add our mapping here...
205             this->controller->add_proxy_to_id_mapping(
206                 this->outputs.front()->proxy.get(),
207                 wl_proxy_get_id(reinterpret_cast<struct wl_proxy *>(
208                     this->outputs.front()->proxy.get())));
209
210             // Create screen
211             this->controller->create_screen(this->outputs.front()->proxy.get());
212
213             // Set display to controller
214             this->controller->display = this->display;
215         });
216
217     // First level objects
218     this->display->roundtrip();
219     // Second level objects
220     this->display->roundtrip();
221     // Third level objects
222     this->display->roundtrip();
223
224     return init_layers();
225 }
226
227 int WindowManager::dispatch_pending_events()
228 {
229     if (this->pop_pending_events())
230     {
231         this->display->dispatch_pending();
232         return 0;
233     }
234     return -1;
235 }
236
237 void WindowManager::set_pending_events()
238 {
239     this->pending_events.store(true, std::memory_order_release);
240 }
241
242 result<int> WindowManager::api_request_surface(char const *appid, char const *drawing_name)
243 {
244     // TODO: application requests by old role,
245     //       so convert role old to new
246     const char *role = this->convertRoleOldToNew(drawing_name);
247
248     auto lid = this->layers.get_layer_id(std::string(role));
249     if (!lid)
250     {
251         /**
252        * register drawing_name as fallback and make it displayed.
253        */
254         lid = this->layers.get_layer_id(std::string("fallback"));
255         HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role);
256         if (!lid)
257         {
258             return Err<int>("Drawing name does not match any role, fallback is disabled");
259         }
260     }
261
262     auto rname = this->lookup_id(role);
263     if (!rname)
264     {
265         // name does not exist yet, allocate surface id...
266         auto id = int(this->id_alloc.generate_id(role));
267         this->layers.add_surface(id, *lid);
268
269         // set the main_surface[_name] here and now
270         if (!this->layers.main_surface_name.empty() &&
271             this->layers.main_surface_name == drawing_name)
272         {
273             this->layers.main_surface = id;
274             HMI_DEBUG("Set main_surface id to %u", id);
275         }
276
277         // add client into the db
278         std::string appid_str(appid);
279         g_app_list.addClient(appid_str, *lid, id, std::string(role));
280
281         // Set role map of (new, old)
282         this->rolenew2old[role] = std::string(drawing_name);
283
284         return Ok<int>(id);
285     }
286
287     // Check currently registered drawing names if it is already there.
288     return Err<int>("Surface already present");
289 }
290
291 char const *WindowManager::api_request_surface(char const *appid, char const *drawing_name,
292                                      char const *ivi_id)
293 {
294     // TODO: application requests by old role,
295     //       so convert role old to new
296     const char *role = this->convertRoleOldToNew(drawing_name);
297
298     auto lid = this->layers.get_layer_id(std::string(role));
299     unsigned sid = std::stol(ivi_id);
300
301     if (!lid)
302     {
303         /**
304        * register drawing_name as fallback and make it displayed.
305        */
306         lid = this->layers.get_layer_id(std::string("fallback"));
307         HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role);
308         if (!lid)
309         {
310             return "Drawing name does not match any role, fallback is disabled";
311         }
312     }
313
314     auto rname = this->lookup_id(role);
315
316     if (rname)
317     {
318         return "Surface already present";
319     }
320
321     // register pair drawing_name and ivi_id
322     this->id_alloc.register_name_id(role, sid);
323     this->layers.add_surface(sid, *lid);
324
325     // this surface is already created
326     HMI_DEBUG("surface_id is %u, layer_id is %u", sid, *lid);
327
328     this->controller->layers[*lid]->add_surface(sid);
329     this->layout_commit();
330
331     // add client into the db
332     std::string appid_str(appid);
333     g_app_list.addClient(appid_str, *lid, sid, std::string(role));
334
335     // Set role map of (new, old)
336     this->rolenew2old[role] = std::string(drawing_name);
337
338     return nullptr;
339 }
340
341 void WindowManager::api_activate_surface(char const *appid, char const *drawing_name,
342                                char const *drawing_area, const reply_func &reply)
343 {
344     // TODO: application requests by old role,
345     //       so convert role old to new
346     const char *c_role = this->convertRoleOldToNew(drawing_name);
347
348     std::string id = appid;
349     std::string role = c_role;
350     std::string area = drawing_area;
351     Task task = Task::TASK_ALLOCATE;
352     unsigned req_num = 0;
353     WMError ret = WMError::UNKNOWN;
354
355     ret = this->setRequest(id, role, area, task, &req_num);
356
357     if(ret != WMError::SUCCESS)
358     {
359         HMI_ERROR(errorDescription(ret));
360         reply("Failed to set request");
361         return;
362     }
363
364     reply(nullptr);
365     if (req_num != g_app_list.currentRequestNumber())
366     {
367         // Add request, then invoked after the previous task is finished
368         HMI_SEQ_DEBUG(req_num, "request is accepted");
369         return;
370     }
371
372     /*
373      * Do allocate tasks
374      */
375     ret = this->doTransition(req_num);
376
377     if (ret != WMError::SUCCESS)
378     {
379         //this->emit_error()
380         HMI_SEQ_ERROR(req_num, errorDescription(ret));
381         g_app_list.removeRequest(req_num);
382         this->processNextRequest();
383     }
384 }
385
386 void WindowManager::api_deactivate_surface(char const *appid, char const *drawing_name,
387                                  const reply_func &reply)
388 {
389     // TODO: application requests by old role,
390     //       so convert role old to new
391     const char *c_role = this->convertRoleOldToNew(drawing_name);
392
393     /*
394     * Check Phase
395     */
396     std::string id = appid;
397     std::string role = c_role;
398     std::string area = ""; //drawing_area;
399     Task task = Task::TASK_RELEASE;
400     unsigned req_num = 0;
401     WMError ret = WMError::UNKNOWN;
402
403     ret = this->setRequest(id, role, area, task, &req_num);
404
405     if (ret != WMError::SUCCESS)
406     {
407         HMI_ERROR(errorDescription(ret));
408         reply("Failed to set request");
409         return;
410     }
411
412     reply(nullptr);
413     if (req_num != g_app_list.currentRequestNumber())
414     {
415         // Add request, then invoked after the previous task is finished
416         HMI_SEQ_DEBUG(req_num, "request is accepted");
417         return;
418     }
419
420     /*
421     * Do allocate tasks
422     */
423     ret = this->doTransition(req_num);
424
425     if (ret != WMError::SUCCESS)
426     {
427         //this->emit_error()
428         HMI_SEQ_ERROR(req_num, errorDescription(ret));
429         g_app_list.removeRequest(req_num);
430         this->processNextRequest();
431     }
432 }
433
434 void WindowManager::api_enddraw(char const *appid, char const *drawing_name)
435 {
436     // TODO: application requests by old role,
437     //       so convert role old to new
438     const char *c_role = this->convertRoleOldToNew(drawing_name);
439
440     std::string id = appid;
441     std::string role = c_role;
442     unsigned current_req = g_app_list.currentRequestNumber();
443     bool result = g_app_list.setEndDrawFinished(current_req, id, role);
444
445     if (!result)
446     {
447         HMI_ERROR("%s is not in transition state", id.c_str());
448         return;
449     }
450
451     if (g_app_list.endDrawFullfilled(current_req))
452     {
453         // do task for endDraw
454         this->stopTimer();
455         WMError ret = this->doEndDraw(current_req);
456
457         if(ret != WMError::SUCCESS)
458         {
459             //this->emit_error();
460
461             // Undo state of PolicyManager
462             this->pmw.undoState();
463         }
464         this->emitScreenUpdated(current_req);
465         HMI_SEQ_INFO(current_req, "Finish request status: %s", errorDescription(ret));
466
467         g_app_list.removeRequest(current_req);
468
469         this->processNextRequest();
470     }
471     else
472     {
473         HMI_SEQ_INFO(current_req, "Wait other App call endDraw");
474         return;
475     }
476 }
477
478 result<json_object *> WindowManager::api_get_display_info()
479 {
480     if (!this->display->ok())
481     {
482         return Err<json_object *>("Wayland compositor is not available");
483     }
484
485     // Set display info
486     compositor::size o_size = this->controller->output_size;
487     compositor::size p_size = this->controller->physical_size;
488
489     json_object *object = json_object_new_object();
490     json_object_object_add(object, kKeyWidthPixel, json_object_new_int(o_size.w));
491     json_object_object_add(object, kKeyHeightPixel, json_object_new_int(o_size.h));
492     json_object_object_add(object, kKeyWidthMm, json_object_new_int(p_size.w));
493     json_object_object_add(object, kKeyHeightMm, json_object_new_int(p_size.h));
494     json_object_object_add(object, kKeyScale, json_object_new_double(this->controller->scale));
495
496     return Ok<json_object *>(object);
497 }
498
499 result<json_object *> WindowManager::api_get_area_info(char const *drawing_name)
500 {
501     HMI_DEBUG("called");
502
503     // TODO: application requests by old role,
504     //       so convert role old to new
505     const char *role = this->convertRoleOldToNew(drawing_name);
506
507     // Check drawing name, surface/layer id
508     auto const &surface_id = this->lookup_id(role);
509     if (!surface_id)
510     {
511         return Err<json_object *>("Surface does not exist");
512     }
513
514     if (!this->controller->surface_exists(*surface_id))
515     {
516         return Err<json_object *>("Surface does not exist in controller!");
517     }
518
519     auto layer_id = this->layers.get_layer_id(*surface_id);
520     if (!layer_id)
521     {
522         return Err<json_object *>("Surface is not on any layer!");
523     }
524
525     // Set area rectangle
526     compositor::rect area_info = this->area_info[*surface_id];
527     json_object *object = json_object_new_object();
528     json_object_object_add(object, kKeyX, json_object_new_int(area_info.x));
529     json_object_object_add(object, kKeyY, json_object_new_int(area_info.y));
530     json_object_object_add(object, kKeyWidth, json_object_new_int(area_info.w));
531     json_object_object_add(object, kKeyHeight, json_object_new_int(area_info.h));
532
533     return Ok<json_object *>(object);
534 }
535
536 void WindowManager::api_ping() { this->dispatch_pending_events(); }
537
538 void WindowManager::send_event(char const *evname, char const *label)
539 {
540     HMI_DEBUG("%s: %s(%s)", __func__, evname, label);
541
542     json_object *j = json_object_new_object();
543     json_object_object_add(j, kKeyDrawingName, json_object_new_string(label));
544
545     int ret = afb_event_push(this->map_afb_event[evname], j);
546     if (ret != 0)
547     {
548         HMI_DEBUG("afb_event_push failed: %m");
549     }
550 }
551
552 void WindowManager::send_event(char const *evname, char const *label, char const *area,
553                      int x, int y, int w, int h)
554 {
555     HMI_DEBUG("%s: %s(%s, %s) x:%d y:%d w:%d h:%d",
556               __func__, evname, label, area, x, y, w, h);
557
558     json_object *j_rect = json_object_new_object();
559     json_object_object_add(j_rect, kKeyX, json_object_new_int(x));
560     json_object_object_add(j_rect, kKeyY, json_object_new_int(y));
561     json_object_object_add(j_rect, kKeyWidth, json_object_new_int(w));
562     json_object_object_add(j_rect, kKeyHeight, json_object_new_int(h));
563
564     json_object *j = json_object_new_object();
565     json_object_object_add(j, kKeyDrawingName, json_object_new_string(label));
566     json_object_object_add(j, kKeyDrawingArea, json_object_new_string(area));
567     json_object_object_add(j, kKeyDrawingRect, j_rect);
568
569     int ret = afb_event_push(this->map_afb_event[evname], j);
570     if (ret != 0)
571     {
572         HMI_DEBUG("afb_event_push failed: %m");
573     }
574 }
575
576 /**
577  * proxied events
578  */
579 void WindowManager::surface_created(uint32_t surface_id)
580 {
581     this->controller->get_surface_properties(surface_id, IVI_WM_PARAM_SIZE);
582
583     auto layer_id = this->layers.get_layer_id(surface_id);
584     if (!layer_id)
585     {
586         HMI_DEBUG("Newly created surfce %d is not associated with any layer!",
587                   surface_id);
588         return;
589     }
590
591     HMI_DEBUG("surface_id is %u, layer_id is %u", surface_id, *layer_id);
592
593     this->controller->layers[*layer_id]->add_surface(surface_id);
594     this->layout_commit();
595 }
596
597 void WindowManager::surface_removed(uint32_t surface_id)
598 {
599     HMI_DEBUG("Delete surface_id %u", surface_id);
600     this->id_alloc.remove_id(surface_id);
601     this->layers.remove_surface(surface_id);
602     g_app_list.removeSurface(surface_id);
603 }
604
605 void WindowManager::removeClient(const std::string &appid)
606 {
607     HMI_DEBUG("Remove clinet %s from list", appid.c_str());
608     g_app_list.removeClient(appid);
609 }
610
611 void WindowManager::exceptionProcessForTransition()
612 {
613     unsigned req_num = g_app_list.currentRequestNumber();
614     HMI_SEQ_NOTICE(req_num, "Process exception handling for request. Remove current request %d", req_num);
615     g_app_list.removeRequest(req_num);
616     HMI_SEQ_NOTICE(g_app_list.currentRequestNumber(), "Process next request if exists");
617     this->processNextRequest();
618 }
619
620 void WindowManager::timerHandler()
621 {
622     unsigned req_num = g_app_list.currentRequestNumber();
623     HMI_SEQ_DEBUG(req_num, "Timer expired remove Request");
624     g_app_list.reqDump();
625     g_app_list.removeRequest(req_num);
626     this->processNextRequest();
627 }
628
629 void WindowManager::startTransitionWrapper(std::vector<WMAction> &actions)
630 {
631     WMError ret;
632     unsigned req_num = g_app_list.currentRequestNumber();
633
634     if (actions.empty())
635     {
636         if (g_app_list.haveRequest())
637         {
638             HMI_SEQ_DEBUG(req_num, "There is no WMAction for this request");
639             goto proc_remove_request;
640         }
641         else
642         {
643             HMI_SEQ_DEBUG(req_num, "There is no request");
644             return;
645         }
646     }
647
648     for (auto &act : actions)
649     {
650         if ("" != act.role)
651         {
652             bool found;
653             auto const &surface_id = this->lookup_id(act.role.c_str());
654             if(surface_id == nullopt)
655             {
656                 goto proc_remove_request;
657             }
658             std::string appid = g_app_list.getAppID(*surface_id, act.role, &found);
659             if (!found)
660             {
661                 if (TaskVisible::INVISIBLE == act.visible)
662                 {
663                     // App is killed, so do not set this action
664                     continue;
665                 }
666                 else
667                 {
668                     HMI_SEQ_ERROR(req_num, "appid which is visible is not found");
669                     ret = WMError::FAIL;
670                     goto error;
671                 }
672             }
673             act.appid = appid;
674         }
675
676         ret = g_app_list.setAction(req_num, act);
677         if (ret != WMError::SUCCESS)
678         {
679             HMI_SEQ_ERROR(req_num, "Setting action is failed");
680             goto error;
681         }
682     }
683
684     HMI_SEQ_DEBUG(req_num, "Start transition.");
685     ret = this->startTransition(req_num);
686     if (ret != WMError::SUCCESS)
687     {
688         if (ret == WMError::NO_LAYOUT_CHANGE)
689         {
690             goto proc_remove_request;
691         }
692         else
693         {
694             HMI_SEQ_ERROR(req_num, "Transition state is failed");
695             goto error;
696         }
697     }
698
699     return;
700
701 error:
702     //this->emit_error()
703     HMI_SEQ_ERROR(req_num, errorDescription(ret));
704     this->pmw.undoState();
705
706 proc_remove_request:
707     g_app_list.removeRequest(req_num);
708     this->processNextRequest();
709 }
710
711 void WindowManager::processError(WMError error)
712 {
713     unsigned req_num = g_app_list.currentRequestNumber();
714
715     //this->emit_error()
716     HMI_SEQ_ERROR(req_num, errorDescription(error));
717     g_app_list.removeRequest(req_num);
718     this->processNextRequest();
719 }
720
721 /*
722  ******* Private Functions *******
723  */
724
725 bool WindowManager::pop_pending_events()
726 {
727     bool x{true};
728     return this->pending_events.compare_exchange_strong(
729         x, false, std::memory_order_consume);
730 }
731
732 optional<int> WindowManager::lookup_id(char const *name)
733 {
734     return this->id_alloc.lookup(std::string(name));
735 }
736 optional<std::string> WindowManager::lookup_name(int id)
737 {
738     return this->id_alloc.lookup(id);
739 }
740
741 /**
742  * init_layers()
743  */
744 int WindowManager::init_layers()
745 {
746     if (!this->controller)
747     {
748         HMI_ERROR("ivi_controller global not available");
749         return -1;
750     }
751
752     if (this->outputs.empty())
753     {
754         HMI_ERROR("no output was set up!");
755         return -1;
756     }
757
758     auto &c = this->controller;
759
760     auto &o = this->outputs.front();
761     auto &s = c->screens.begin()->second;
762     auto &layers = c->layers;
763
764     // Write output dimensions to ivi controller...
765     c->output_size = compositor::size{uint32_t(o->width), uint32_t(o->height)};
766     c->physical_size = compositor::size{uint32_t(o->physical_width),
767                                         uint32_t(o->physical_height)};
768
769
770     HMI_DEBUG("SCALING: screen (%dx%d), physical (%dx%d)",
771               o->width, o->height, o->physical_width, o->physical_height);
772
773     this->layers.loadAreaDb();
774
775     const compositor::rect css_bg = this->layers.getAreaSize("fullscreen");
776     rectangle dp_bg(o->width, o->height);
777
778     dp_bg.set_aspect(static_cast<double>(css_bg.w) / css_bg.h);
779     dp_bg.fit(o->width, o->height);
780     dp_bg.center(o->width, o->height);
781     HMI_DEBUG("SCALING: CSS BG(%dx%d) -> DDP %dx%d,(%dx%d)",
782               css_bg.w, css_bg.h, dp_bg.left(), dp_bg.top(), dp_bg.width(), dp_bg.height());
783
784     // Clear scene
785     layers.clear();
786
787     // Clear screen
788     s->clear();
789
790     // Quick and dirty setup of layers
791     for (auto const &i : this->layers.mapping)
792     {
793         c->layer_create(i.second.layer_id, dp_bg.width(), dp_bg.height());
794         auto &l = layers[i.second.layer_id];
795         l->set_destination_rectangle(dp_bg.left(), dp_bg.top(), dp_bg.width(), dp_bg.height());
796         l->set_visibility(1);
797         HMI_DEBUG("Setting up layer %s (%d) for surface role match \"%s\"",
798                   i.second.name.c_str(), i.second.layer_id, i.second.role.c_str());
799     }
800
801     // Add layers to screen
802     s->set_render_order(this->layers.layers);
803
804     this->layout_commit();
805
806     c->scale = static_cast<double>(dp_bg.height()) / css_bg.h;
807     this->layers.setupArea(c->scale);
808
809     return 0;
810 }
811
812 void WindowManager::surface_set_layout(int surface_id, const std::string& area)
813 {
814     if (!this->controller->surface_exists(surface_id))
815     {
816         HMI_ERROR("Surface %d does not exist", surface_id);
817         return;
818     }
819
820     auto o_layer_id = this->layers.get_layer_id(surface_id);
821
822     if (!o_layer_id)
823     {
824         HMI_ERROR("Surface %d is not associated with any layer!", surface_id);
825         return;
826     }
827
828     uint32_t layer_id = *o_layer_id;
829
830     auto const &layer = this->layers.get_layer(layer_id);
831     auto rect = this->layers.getAreaSize(area);
832     HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "%s : x:%d y:%d w:%d h:%d", area.c_str(),
833                     rect.x, rect.y, rect.w, rect.h);
834     auto &s = this->controller->surfaces[surface_id];
835
836     int x = rect.x;
837     int y = rect.y;
838     int w = rect.w;
839     int h = rect.h;
840
841     HMI_DEBUG("surface_set_layout for surface %u on layer %u", surface_id,
842               layer_id);
843
844     // set destination to the display rectangle
845     s->set_destination_rectangle(x, y, w, h);
846
847     // update area information
848     this->area_info[surface_id].x = x;
849     this->area_info[surface_id].y = y;
850     this->area_info[surface_id].w = w;
851     this->area_info[surface_id].h = h;
852
853     HMI_DEBUG("Surface %u now on layer %u with rect { %d, %d, %d, %d }",
854               surface_id, layer_id, x, y, w, h);
855 }
856
857 void WindowManager::layout_commit()
858 {
859     this->controller->commit_changes();
860     this->display->flush();
861 }
862
863 void WindowManager::emit_activated(char const *label)
864 {
865     this->send_event(kListEventName[Event_Active], label);
866 }
867
868 void WindowManager::emit_deactivated(char const *label)
869 {
870     this->send_event(kListEventName[Event_Inactive], label);
871 }
872
873 void WindowManager::emit_syncdraw(char const *label, char const *area, int x, int y, int w, int h)
874 {
875     this->send_event(kListEventName[Event_SyncDraw], label, area, x, y, w, h);
876 }
877
878 void WindowManager::emit_syncdraw(const std::string &role, const std::string &area)
879 {
880     compositor::rect rect = this->layers.getAreaSize(area);
881     this->send_event(kListEventName[Event_SyncDraw],
882         role.c_str(), area.c_str(), rect.x, rect.y, rect.w, rect.h);
883 }
884
885 void WindowManager::emit_flushdraw(char const *label)
886 {
887     this->send_event(kListEventName[Event_FlushDraw], label);
888 }
889
890 void WindowManager::emit_visible(char const *label, bool is_visible)
891 {
892     this->send_event(is_visible ? kListEventName[Event_Visible] : kListEventName[Event_Invisible], label);
893 }
894
895 void WindowManager::emit_invisible(char const *label)
896 {
897     return emit_visible(label, false);
898 }
899
900 void WindowManager::emit_visible(char const *label) { return emit_visible(label, true); }
901
902 void WindowManager::activate(int id)
903 {
904     auto ip = this->controller->sprops.find(id);
905     if (ip != this->controller->sprops.end())
906     {
907         this->controller->surfaces[id]->set_visibility(1);
908         char const *label =
909             this->lookup_name(id).value_or("unknown-name").c_str();
910
911          // FOR CES DEMO >>>
912         if ((0 == strcmp(label, "radio")) ||
913             (0 == strcmp(label, "music")) ||
914             (0 == strcmp(label, "video")) ||
915             (0 == strcmp(label, "map")))
916         {
917             for (auto i = surface_bg.begin(); i != surface_bg.end(); ++i)
918             {
919                 if (id == *i)
920                 {
921                     // Remove id
922                     this->surface_bg.erase(i);
923
924                     // Remove from BG layer (999)
925                     HMI_DEBUG("Remove %s(%d) from BG layer", label, id);
926                     this->controller->layers[999]->remove_surface(id);
927
928                     // Add to FG layer (1001)
929                     HMI_DEBUG("Add %s(%d) to FG layer", label, id);
930                     this->controller->layers[1001]->add_surface(id);
931
932                     for (int j : this->surface_bg)
933                     {
934                         HMI_DEBUG("Stored id:%d", j);
935                     }
936                     break;
937                 }
938             }
939         }
940         // <<< FOR CES DEMO
941
942         this->layout_commit();
943
944         // TODO: application requests by old role,
945         //       so convert role new to old for emitting event
946         const char* old_role = this->rolenew2old[label].c_str();
947
948         this->emit_visible(old_role);
949         this->emit_activated(old_role);
950     }
951 }
952
953 void WindowManager::deactivate(int id)
954 {
955     auto ip = this->controller->sprops.find(id);
956     if (ip != this->controller->sprops.end())
957     {
958         char const *label =
959             this->lookup_name(id).value_or("unknown-name").c_str();
960
961         // FOR CES DEMO >>>
962         if ((0 == strcmp(label, "radio")) ||
963             (0 == strcmp(label, "music")) ||
964             (0 == strcmp(label, "video")) ||
965             (0 == strcmp(label, "map")))
966         {
967
968             // Store id
969             this->surface_bg.push_back(id);
970
971             // Remove from FG layer (1001)
972             HMI_DEBUG("Remove %s(%d) from FG layer", label, id);
973             this->controller->layers[1001]->remove_surface(id);
974
975             // Add to BG layer (999)
976             HMI_DEBUG("Add %s(%d) to BG layer", label, id);
977             this->controller->layers[999]->add_surface(id);
978
979             for (int j : surface_bg)
980             {
981                 HMI_DEBUG("Stored id:%d", j);
982             }
983         }
984         else
985         {
986             this->controller->surfaces[id]->set_visibility(0);
987         }
988         // <<< FOR CES DEMO
989
990         this->layout_commit();
991
992         // TODO: application requests by old role,
993         //       so convert role new to old for emitting event
994         const char* old_role = this->rolenew2old[label].c_str();
995
996         this->emit_deactivated(old_role);
997         this->emit_invisible(old_role);
998     }
999 }
1000
1001 WMError WindowManager::setRequest(const std::string& appid, const std::string &role, const std::string &area,
1002                             Task task, unsigned* req_num)
1003 {
1004     if (!g_app_list.contains(appid))
1005     {
1006         return WMError::NOT_REGISTERED;
1007     }
1008
1009     auto client = g_app_list.lookUpClient(appid);
1010
1011     /*
1012      * Queueing Phase
1013      */
1014     unsigned current = g_app_list.currentRequestNumber();
1015     unsigned requested_num = g_app_list.getRequestNumber(appid);
1016     if (requested_num != 0)
1017     {
1018         HMI_SEQ_INFO(requested_num,
1019             "%s %s %s request is already queued", appid.c_str(), role.c_str(), area.c_str());
1020         return REQ_REJECTED;
1021     }
1022
1023     WMRequest req = WMRequest(appid, role, area, task);
1024     unsigned new_req = g_app_list.addRequest(req);
1025     *req_num = new_req;
1026     g_app_list.reqDump();
1027
1028     HMI_SEQ_DEBUG(current, "%s start sequence with %s, %s", appid.c_str(), role.c_str(), area.c_str());
1029
1030     return WMError::SUCCESS;
1031 }
1032
1033 WMError WindowManager::doTransition(unsigned req_num)
1034 {
1035     HMI_SEQ_DEBUG(req_num, "check policy");
1036     WMError ret = this->checkPolicy(req_num);
1037     return ret;
1038 }
1039
1040 WMError WindowManager::checkPolicy(unsigned req_num)
1041 {
1042     /*
1043     * Check Policy
1044     */
1045     // get current trigger
1046     bool found = false;
1047     WMError ret = WMError::LAYOUT_CHANGE_FAIL;
1048     auto trigger = g_app_list.getRequest(req_num, &found);
1049     if (!found)
1050     {
1051         ret = WMError::NO_ENTRY;
1052         return ret;
1053     }
1054     std::string req_area = trigger.area;
1055
1056     if (trigger.task == Task::TASK_ALLOCATE)
1057     {
1058         const char *msg = this->check_surface_exist(trigger.role.c_str());
1059
1060         if (msg)
1061         {
1062             HMI_SEQ_ERROR(req_num, msg);
1063             return ret;
1064         }
1065     }
1066
1067     // Input event data to PolicyManager
1068     if (0 > this->pmw.setInputEventData(trigger.task, trigger.role, trigger.area))
1069     {
1070         HMI_SEQ_ERROR(req_num, "Failed to set input event data to PolicyManager");
1071         return ret;
1072     }
1073
1074     // Execute state transition of PolicyManager
1075     if (0 > this->pmw.executeStateTransition())
1076     {
1077         HMI_SEQ_ERROR(req_num, "Failed to execute state transition of PolicyManager");
1078         return ret;
1079     }
1080
1081     ret = WMError::SUCCESS;
1082
1083     g_app_list.reqDump();
1084
1085     return ret;
1086 }
1087
1088 WMError WindowManager::startTransition(unsigned req_num)
1089 {
1090     bool sync_draw_happen = false;
1091     bool found = false;
1092     WMError ret = WMError::SUCCESS;
1093     auto actions = g_app_list.getActions(req_num, &found);
1094     if (!found)
1095     {
1096         ret = WMError::NO_ENTRY;
1097         HMI_SEQ_ERROR(req_num,
1098             "Window Manager bug :%s : Action is not set", errorDescription(ret));
1099         return ret;
1100     }
1101
1102     for (const auto &action : actions)
1103     {
1104         if (action.visible == TaskVisible::VISIBLE)
1105         {
1106             sync_draw_happen = true;
1107
1108             // TODO: application requests by old role,
1109             //       so convert role new to old for emitting event
1110             std::string old_role = this->rolenew2old[action.role];
1111
1112             this->emit_syncdraw(old_role, action.area);
1113             /* TODO: emit event for app not subscriber
1114             if(g_app_list.contains(y.appid))
1115                 g_app_list.lookUpClient(y.appid)->emit_syncdraw(y.role, y.area); */
1116         }
1117     }
1118
1119     if (sync_draw_happen)
1120     {
1121         this->setTimer();
1122     }
1123     else
1124     {
1125         // deactivate only, no syncDraw
1126         // Make it deactivate here
1127         for (const auto &x : actions)
1128         {
1129             if (g_app_list.contains(x.appid))
1130             {
1131                 auto client = g_app_list.lookUpClient(x.appid);
1132                 this->deactivate(client->surfaceID(x.role));
1133             }
1134         }
1135         ret = WMError::NO_LAYOUT_CHANGE;
1136     }
1137     return ret;
1138 }
1139
1140 WMError WindowManager::doEndDraw(unsigned req_num)
1141 {
1142     // get actions
1143     bool found;
1144     auto actions = g_app_list.getActions(req_num, &found);
1145     WMError ret = WMError::SUCCESS;
1146     if (!found)
1147     {
1148         ret = WMError::NO_ENTRY;
1149         return ret;
1150     }
1151
1152     HMI_SEQ_INFO(req_num, "do endDraw");
1153
1154     // layout change and make it visible
1155     for (const auto &act : actions)
1156     {
1157         if(act.visible != TaskVisible::NO_CHANGE)
1158         {
1159             // layout change
1160             if(!g_app_list.contains(act.appid)){
1161                 ret = WMError::NOT_REGISTERED;
1162             }
1163             ret = this->layoutChange(act);
1164             if(ret != WMError::SUCCESS)
1165             {
1166                 HMI_SEQ_WARNING(req_num,
1167                     "Failed to manipulate surfaces while state change : %s", errorDescription(ret));
1168                 return ret;
1169             }
1170             ret = this->visibilityChange(act);
1171             if (ret != WMError::SUCCESS)
1172             {
1173                 HMI_SEQ_WARNING(req_num,
1174                     "Failed to manipulate surfaces while state change : %s", errorDescription(ret));
1175                 return ret;
1176             }
1177             HMI_SEQ_DEBUG(req_num, "visible %s", act.role.c_str());
1178             //this->lm_enddraw(act.role.c_str());
1179         }
1180     }
1181     this->layout_commit();
1182
1183     HMI_SEQ_INFO(req_num, "emit flushDraw");
1184
1185     for(const auto &act_flush : actions)
1186     {
1187         if(act_flush.visible == TaskVisible::VISIBLE)
1188         {
1189             // TODO: application requests by old role,
1190             //       so convert role new to old for emitting event
1191             std::string old_role = this->rolenew2old[act_flush.role];
1192
1193             this->emit_flushdraw(old_role.c_str());
1194         }
1195     }
1196
1197     return ret;
1198 }
1199
1200 WMError WindowManager::layoutChange(const WMAction &action)
1201 {
1202     if (action.visible == TaskVisible::INVISIBLE)
1203     {
1204         // Visibility is not change -> no redraw is required
1205         return WMError::SUCCESS;
1206     }
1207     auto client = g_app_list.lookUpClient(action.appid);
1208     unsigned surface = client->surfaceID(action.role);
1209     if (surface == 0)
1210     {
1211         HMI_SEQ_ERROR(g_app_list.currentRequestNumber(),
1212                       "client doesn't have surface with role(%s)", action.role.c_str());
1213         return WMError::NOT_REGISTERED;
1214     }
1215     // Layout Manager
1216     WMError ret = this->setSurfaceSize(surface, action.area);
1217     return ret;
1218 }
1219
1220 WMError WindowManager::visibilityChange(const WMAction &action)
1221 {
1222     HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "Change visibility");
1223     if(!g_app_list.contains(action.appid)){
1224         return WMError::NOT_REGISTERED;
1225     }
1226     auto client = g_app_list.lookUpClient(action.appid);
1227     unsigned surface = client->surfaceID(action.role);
1228     if(surface == 0)
1229     {
1230         HMI_SEQ_ERROR(g_app_list.currentRequestNumber(),
1231                       "client doesn't have surface with role(%s)", action.role.c_str());
1232         return WMError::NOT_REGISTERED;
1233     }
1234
1235     if (action.visible != TaskVisible::INVISIBLE)
1236     {
1237         this->activate(surface); // Layout Manager task
1238     }
1239     else
1240     {
1241         this->deactivate(surface); // Layout Manager task
1242     }
1243     return WMError::SUCCESS;
1244 }
1245
1246 WMError WindowManager::setSurfaceSize(unsigned surface, const std::string &area)
1247 {
1248     this->surface_set_layout(surface, area);
1249
1250     return WMError::SUCCESS;
1251 }
1252
1253 void WindowManager::emitScreenUpdated(unsigned req_num)
1254 {
1255     // Get visible apps
1256     HMI_SEQ_DEBUG(req_num, "emit screen updated");
1257     bool found = false;
1258     auto actions = g_app_list.getActions(req_num, &found);
1259
1260     // create json object
1261     json_object *j = json_object_new_object();
1262     json_object *jarray = json_object_new_array();
1263
1264     for(const auto& action: actions)
1265     {
1266         if(action.visible != TaskVisible::INVISIBLE)
1267         {
1268             json_object_array_add(jarray, json_object_new_string(action.appid.c_str()));
1269         }
1270     }
1271     json_object_object_add(j, kKeyIds, jarray);
1272     HMI_SEQ_INFO(req_num, "Visible app: %s", json_object_get_string(j));
1273
1274     int ret = afb_event_push(
1275         this->map_afb_event[kListEventName[Event_ScreenUpdated]], j);
1276     if (ret != 0)
1277     {
1278         HMI_DEBUG("afb_event_push failed: %m");
1279     }
1280 }
1281
1282 void WindowManager::setTimer()
1283 {
1284     struct timespec ts;
1285     if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0) {
1286         HMI_ERROR("Could't set time (clock_gettime() returns with error");
1287         return;
1288     }
1289
1290     HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "Timer set activate");
1291     if (g_timer_ev_src == nullptr)
1292     {
1293         // firsttime set into sd_event
1294         int ret = sd_event_add_time(afb_daemon_get_event_loop(), &g_timer_ev_src,
1295             CLOCK_BOOTTIME, (uint64_t)(ts.tv_sec + kTimeOut) * 1000000ULL, 1, processTimerHandler, this);
1296         if (ret < 0)
1297         {
1298             HMI_ERROR("Could't set timer");
1299         }
1300     }
1301     else
1302     {
1303         // update timer limitation after second time
1304         sd_event_source_set_time(g_timer_ev_src, (uint64_t)(ts.tv_sec + kTimeOut) * 1000000ULL);
1305         sd_event_source_set_enabled(g_timer_ev_src, SD_EVENT_ONESHOT);
1306     }
1307 }
1308
1309 void WindowManager::stopTimer()
1310 {
1311     unsigned req_num = g_app_list.currentRequestNumber();
1312     HMI_SEQ_DEBUG(req_num, "Timer stop");
1313     int rc = sd_event_source_set_enabled(g_timer_ev_src, SD_EVENT_OFF);
1314     if (rc < 0)
1315     {
1316         HMI_SEQ_ERROR(req_num, "Timer stop failed");
1317     }
1318 }
1319
1320 void WindowManager::processNextRequest()
1321 {
1322     g_app_list.next();
1323     g_app_list.reqDump();
1324     unsigned req_num = g_app_list.currentRequestNumber();
1325     if (g_app_list.haveRequest())
1326     {
1327         HMI_SEQ_DEBUG(req_num, "Process next request");
1328         WMError rc = doTransition(req_num);
1329         if (rc != WMError::SUCCESS)
1330         {
1331             HMI_SEQ_ERROR(req_num, errorDescription(rc));
1332         }
1333     }
1334     else
1335     {
1336         HMI_SEQ_DEBUG(req_num, "Nothing Request. Waiting Request");
1337     }
1338 }
1339
1340 const char* WindowManager::convertRoleOldToNew(char const *old_role)
1341 {
1342     const char *new_role = nullptr;
1343
1344     for (auto const &on : this->roleold2new)
1345     {
1346         std::regex regex = std::regex(on.first);
1347         if (std::regex_match(old_role, regex))
1348         {
1349             // role is old. So convert to new.
1350             new_role = on.second.c_str();
1351             break;
1352         }
1353     }
1354
1355     if (nullptr == new_role)
1356     {
1357         // role is new or fallback.
1358         new_role = old_role;
1359     }
1360
1361     HMI_DEBUG("old:%s -> new:%s", old_role, new_role);
1362
1363     return new_role;
1364 }
1365
1366 int WindowManager::loadOldRoleDb()
1367 {
1368     // Get afm application installed dir
1369     char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
1370     HMI_DEBUG("afm_app_install_dir:%s", afm_app_install_dir);
1371
1372     std::string file_name;
1373     if (!afm_app_install_dir)
1374     {
1375         HMI_ERROR("AFM_APP_INSTALL_DIR is not defined");
1376     }
1377     else
1378     {
1379         file_name = std::string(afm_app_install_dir) + std::string("/etc/old_roles.db");
1380     }
1381
1382     // Load old_role.db
1383     json_object* json_obj;
1384     int ret = jh::inputJsonFilie(file_name.c_str(), &json_obj);
1385     if (0 > ret)
1386     {
1387         HMI_ERROR("Could not open old_role.db, so use default old_role information");
1388         json_obj = json_tokener_parse(kDefaultOldRoleDb);
1389     }
1390     HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
1391
1392     // Perse apps
1393     json_object* json_cfg;
1394     if (!json_object_object_get_ex(json_obj, "old_roles", &json_cfg))
1395     {
1396         HMI_ERROR("Parse Error!!");
1397         return -1;
1398     }
1399
1400     int len = json_object_array_length(json_cfg);
1401     HMI_DEBUG("json_cfg len:%d", len);
1402     HMI_DEBUG("json_cfg dump:%s", json_object_get_string(json_cfg));
1403
1404     for (int i=0; i<len; i++)
1405     {
1406         json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
1407
1408         const char* old_role = jh::getStringFromJson(json_tmp, "name");
1409         if (nullptr == old_role)
1410         {
1411             HMI_ERROR("Parse Error!!");
1412             return -1;
1413         }
1414
1415         const char* new_role = jh::getStringFromJson(json_tmp, "new");
1416         if (nullptr == new_role)
1417         {
1418             HMI_ERROR("Parse Error!!");
1419             return -1;
1420         }
1421
1422         this->roleold2new[old_role] = std::string(new_role);
1423     }
1424
1425     // Check
1426     for(auto itr = this->roleold2new.begin();
1427       itr != this->roleold2new.end(); ++itr)
1428     {
1429         HMI_DEBUG(">>> role old:%s new:%s",
1430                   itr->first.c_str(), itr->second.c_str());
1431     }
1432
1433     // Release json_object
1434     json_object_put(json_obj);
1435
1436     return 0;
1437 }
1438
1439 const char *WindowManager::check_surface_exist(const char *drawing_name)
1440 {
1441     auto const &surface_id = this->lookup_id(drawing_name);
1442     if (!surface_id)
1443     {
1444         return "Surface does not exist";
1445     }
1446
1447     if (!this->controller->surface_exists(*surface_id))
1448     {
1449         return "Surface does not exist in controller!";
1450     }
1451
1452     auto layer_id = this->layers.get_layer_id(*surface_id);
1453
1454     if (!layer_id)
1455     {
1456         return "Surface is not on any layer!";
1457     }
1458
1459     HMI_DEBUG("surface %d is detected", *surface_id);
1460     return nullptr;
1461 }
1462
1463 const char* WindowManager::kDefaultOldRoleDb = "{ \
1464     \"old_roles\": [ \
1465         { \
1466             \"name\": \"HomeScreen\", \
1467             \"new\": \"homescreen\" \
1468         }, \
1469         { \
1470             \"name\": \"Music\", \
1471             \"new\": \"music\" \
1472         }, \
1473         { \
1474             \"name\": \"MediaPlayer\", \
1475             \"new\": \"music\" \
1476         }, \
1477         { \
1478             \"name\": \"Video\", \
1479             \"new\": \"video\" \
1480         }, \
1481         { \
1482             \"name\": \"VideoPlayer\", \
1483             \"new\": \"video\" \
1484         }, \
1485         { \
1486             \"name\": \"WebBrowser\", \
1487             \"new\": \"browser\" \
1488         }, \
1489         { \
1490             \"name\": \"Radio\", \
1491             \"new\": \"radio\" \
1492         }, \
1493         { \
1494             \"name\": \"Phone\", \
1495             \"new\": \"phone\" \
1496         }, \
1497         { \
1498             \"name\": \"Navigation\", \
1499             \"new\": \"map\" \
1500         }, \
1501         { \
1502             \"name\": \"HVAC\", \
1503             \"new\": \"hvac\" \
1504         }, \
1505         { \
1506             \"name\": \"Settings\", \
1507             \"new\": \"settings\" \
1508         }, \
1509         { \
1510             \"name\": \"Dashboard\", \
1511             \"new\": \"dashboard\" \
1512         }, \
1513         { \
1514             \"name\": \"POI\", \
1515             \"new\": \"poi\" \
1516         }, \
1517         { \
1518             \"name\": \"Mixer\", \
1519             \"new\": \"mixer\" \
1520         }, \
1521         { \
1522             \"name\": \"Restriction\", \
1523             \"new\": \"restriction\" \
1524         }, \
1525         { \
1526             \"name\": \"^OnScreen.*\", \
1527             \"new\": \"on_screen\" \
1528         } \
1529     ] \
1530 }";
1531
1532 /**
1533  * controller_hooks
1534  */
1535 void controller_hooks::surface_created(uint32_t surface_id)
1536 {
1537     this->wmgr->surface_created(surface_id);
1538 }
1539
1540 void controller_hooks::surface_removed(uint32_t surface_id)
1541 {
1542     this->wmgr->surface_removed(surface_id);
1543 }
1544
1545 void controller_hooks::surface_visibility(uint32_t /*surface_id*/,
1546                                           uint32_t /*v*/) {}
1547
1548 void controller_hooks::surface_destination_rectangle(uint32_t /*surface_id*/,
1549                                                      uint32_t /*x*/,
1550                                                      uint32_t /*y*/,
1551                                                      uint32_t /*w*/,
1552                                                      uint32_t /*h*/) {}
1553
1554 } // namespace wm