Add PolicyManager, related classes and some config files
authorYuta Doi <yuta-d@witz-inc.co.jp>
Fri, 27 Apr 2018 10:01:36 +0000 (19:01 +0900)
committerYuta Doi <yuta-d@witz-inc.co.jp>
Fri, 27 Apr 2018 10:01:36 +0000 (19:01 +0900)
- PolicyManager
    Decide next layout by using occured event and current state
    based on policy table.
    This PolicyManger is reference and the OEMs can replace it.

- LayoutManager
    Change the current layout to the layout
    which decided by PolicyManager.

    NOTE:
    The functions of this class had been included in App class.
    The part of function of this class remain there yet.

- LowCanClient
    Receive the CAN signal from low level CAN service.

- app.db
    Define the applications name and its role.
    This file will be deleted
    when the names and roles can be given by other module.

- layout.cb
    Define the layouts and areas which are included by the layout.

- role.db
    Define the roles of the applications.

Change-Id: I2f84bdf5e68355e022f516cee9a1db88efe58825
Signed-off-by: Yuta Doi <yuta-d@witz-inc.co.jp>
24 files changed:
CMakeLists.txt
layers.json
package/root/config.xml
src/CMakeLists.txt
src/app.cpp
src/app.hpp
src/db/app.db [new file with mode: 0644]
src/json_helper.cpp
src/json_helper.hpp
src/layout.cpp [deleted file]
src/layout.hpp [deleted file]
src/layout_manager/db/layout.db [new file with mode: 0644]
src/layout_manager/layout.cpp [new file with mode: 0644]
src/layout_manager/layout.hpp [new file with mode: 0644]
src/low_can_client.cpp [new file with mode: 0644]
src/low_can_client.hpp [new file with mode: 0644]
src/main.cpp
src/policy_manager/CMakeLists.txt [new file with mode: 0644]
src/policy_manager/db/role.db [new file with mode: 0644]
src/policy_manager/policy_manager.cpp [new file with mode: 0644]
src/policy_manager/policy_manager.hpp [new file with mode: 0644]
src/policy_manager/zipc/category.db [new file with mode: 0644]
src/policy_manager/zipc/dummy_stm.c [new file with mode: 0644]
src/policy_manager/zipc/dummy_stm.h [new file with mode: 0644]

index 4ed6d6d..4762e0d 100644 (file)
@@ -79,4 +79,7 @@ set(SANITIZER_MODE "none" CACHE STRING "Build using a specific sanitizer (e.g. '
 
 set(LINK_LIBCXX OFF CACHE BOOL "Link against LLVMs libc++")
 
+set(PLUGIN_PM policy_manager)
+add_subdirectory(src/${PLUGIN_PM})
+
 add_subdirectory(src)
index cf7ed34..1d2390d 100644 (file)
@@ -22,7 +22,7 @@
          "comment": "Single layer map for the HomeScreen"
       },
       {
-         "role": "Music|Video|WebBrowser|MediaPlayer|Radio|Phone|Navigation|HVAC|Settings|Dashboard|POI|Mixer|Fallback",
+         "role": "Music|Video|WebBrowser|MediaPlayer|Radio|Phone|Navigation|HVAC|Settings|Dashboard|POI|Mixer|Splitable1|Splitable2|Fallback",
          "name": "apps",
          "layer_id": 1001,
          "area": { "type": "rect", "rect": { "x": 0, "y": 218, "width": -1, "height": -433 } },
index 6392dc3..d375905 100644 (file)
@@ -14,6 +14,7 @@
      <param name="windowmanager" value="ws" />
   </feature>     
   <feature name="urn:AGL:widget:required-api">
+    <param name="low-can" value="ws" />
     <param name="lib/windowmanager-service.so" value="local" />
   </feature>
 </widget>
index cc3efc3..a632b9c 100644 (file)
@@ -25,14 +25,17 @@ set(CMAKE_SHARED_MODULE_PREFIX "")
 
 set(TARGETS_WM windowmanager-service)
 
+# Set use STM name
+set(USE_STM_NAME zipc)
+
 add_library(${TARGETS_WM} MODULE
    main.cpp
    wayland_ivi_wm.cpp
    wayland_ivi_wm.hpp
    util.cpp
    util.hpp
-   layout.cpp
-   layout.hpp
+   layout_manager/layout.cpp
+   layout_manager/layout.hpp
    ${IVI_CON_PROTO}
    json_helper.cpp
    json_helper.hpp
@@ -43,20 +46,28 @@ add_library(${TARGETS_WM} MODULE
    controller_hooks.hpp
    config.cpp
    config.hpp
-   policy.hpp)
+   low_can_client.cpp
+   low_can_client.hpp
+)
 
 target_include_directories(${TARGETS_WM}
     PRIVATE
         ${AFB_INCLUDE_DIRS}
         ${SD_INCLUDE_DIRS}
         ../include
-        ../src)
+        ../src
+        ../src/layout_manager
+        ../src/${PLUGIN_PM}
+        ../src/${PLUGIN_PM}/${USE_STM_NAME}
+)
 
 target_link_libraries(${TARGETS_WM}
     PRIVATE
         ${AFB_LIBRARIES}
         ${WLC_LIBRARIES}
-        ${SD_LIBRARIES})
+        ${SD_LIBRARIES}
+       ${PLUGIN_PM}
+)
 
 target_compile_definitions(${TARGETS_WM}
     PRIVATE
@@ -116,6 +127,9 @@ add_custom_command(TARGET ${TARGETS_WM} POST_BUILD
    COMMAND cp -rf ${PROJECT_BINARY_DIR}/src/${TARGETS_WM}.so ${PROJECT_BINARY_DIR}/package/root/lib
    COMMAND mkdir -p ${PROJECT_BINARY_DIR}/package/root/etc
    COMMAND cp -f ${PROJECT_SOURCE_DIR}/layers.json ${PROJECT_BINARY_DIR}/package/root/etc
+   COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/layout_manager/db/layout.db ${PROJECT_BINARY_DIR}/package/root/etc
+   COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/${PLUGIN_PM}/db/role.db ${PROJECT_BINARY_DIR}/package/root/etc
+   COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/db/app.db ${PROJECT_BINARY_DIR}/package/root/etc
 )
 
 add_custom_target(package DEPENDS ${PROJECT_BINARY_DIR}/package/root
index 937da6a..20f5b56 100644 (file)
@@ -34,6 +34,7 @@
 #include <json.hpp>
 #include <regex>
 #include <thread>
+#include <string>
 
 
 namespace wm {
@@ -130,6 +131,17 @@ int App::init() {
       return -1;
    }
 
+#if 1 // @@@@@
+   // Load app.db
+   this->loadAppDb();
+#endif
+
+   // Initialize PolicyManager
+   this->pm_.initialize();
+
+   // Initialize LayoutManager
+   this->lm_.initialize();
+
    // Make afb event
    for (int i=Event_Val_Min; i<=Event_Val_Max; i++) {
       map_afb_event[kListEventName[i]] = afb_daemon_make_event(kListEventName[i]);
@@ -245,328 +257,177 @@ int App::init_layers() {
    return 0;
 }
 
-void App::surface_set_layout(int surface_id, optional<int> sub_surface_id) {
-   if (!this->controller->surface_exists(surface_id)) {
-      HMI_ERROR("wm", "Surface %d does not exist", surface_id);
-      return;
-   }
-
-   auto o_layer_id = this->layers.get_layer_id(surface_id);
-
-   if (!o_layer_id) {
-      HMI_ERROR("wm", "Surface %d is not associated with any layer!", surface_id);
-      return;
-   }
-
-   uint32_t layer_id = *o_layer_id;
-
-   auto const &layer = this->layers.get_layer(layer_id);
-   auto rect = layer.value().rect;
-   auto &s = this->controller->surfaces[surface_id];
-
-   int x = rect.x;
-   int y = rect.y;
-   int w = rect.w;
-   int h = rect.h;
-
-   // less-than-0 values refer to MAX + 1 - $VALUE
-   // e.g. MAX is either screen width or height
-   if (w < 0) {
-      w = this->controller->output_size.w + 1 + w;
-   }
-   if (h < 0) {
-      h = this->controller->output_size.h + 1 + h;
-   }
-
-   if (sub_surface_id) {
-      if (o_layer_id != this->layers.get_layer_id(*sub_surface_id)) {
-         HMI_ERROR("wm",
-            "surface_set_layout: layers of surfaces (%d and %d) don't match!",
-            surface_id, *sub_surface_id);
-         return;
-      }
-
-      int x_off = 0;
-      int y_off = 0;
-
-      // split along major axis
-      if (w > h) {
-         w /= 2;
-         x_off = w;
-      } else {
-         h /= 2;
-         y_off = h;
-      }
-
-      auto &ss = this->controller->surfaces[*sub_surface_id];
-
-      HMI_DEBUG("wm", "surface_set_layout for sub surface %u on layer %u",
-               *sub_surface_id, layer_id);
-
-      // set destination to the display rectangle
-      ss->set_destination_rectangle(x + x_off, y + y_off, w, h);
-
-      this->area_info[*sub_surface_id].x = x;
-      this->area_info[*sub_surface_id].y = y;
-      this->area_info[*sub_surface_id].w = w;
-      this->area_info[*sub_surface_id].h = h;
-   }
-
-   HMI_DEBUG("wm", "surface_set_layout for surface %u on layer %u", surface_id,
-            layer_id);
-
-   // set destination to the display rectangle
-   s->set_destination_rectangle(x, y, w, h);
-
-   // update area information
-   this->area_info[surface_id].x = x;
-   this->area_info[surface_id].y = y;
-   this->area_info[surface_id].w = w;
-   this->area_info[surface_id].h = h;
-
-   HMI_DEBUG("wm", "Surface %u now on layer %u with rect { %d, %d, %d, %d }",
-            surface_id, layer_id, x, y, w, h);
-}
-
 void App::layout_commit() {
    this->controller->commit_changes();
    this->display->flush();
 }
 
-void App::api_activate_surface(char const *drawing_name, char const *drawing_area, const reply_func &reply) {
-   ST();
-
-   auto const &surface_id = this->lookup_id(drawing_name);
-
-   if (!surface_id) {
-       reply("Surface does not exist");
-       return;
-   }
-
-   if (!this->controller->surface_exists(*surface_id)) {
-      reply("Surface does not exist in controller!");
-      return;
-   }
-
-   auto layer_id = this->layers.get_layer_id(*surface_id);
-
-   if (!layer_id) {
-      reply("Surface is not on any layer!");
-      return;
-   }
-
-   auto o_state = *this->layers.get_layout_state(*surface_id);
-
-   if (o_state == nullptr) {
-      reply("Could not find layer for surface");
-      return;
-   }
-
-   HMI_DEBUG("wm", "surface %d is detected", *surface_id);
-   reply(nullptr);
-
-   struct LayoutState &state = *o_state;
-
-   // disable layers that are above our current layer
-   for (auto const &l : this->layers.mapping) {
-      if (l.second.layer_id <= *layer_id) {
-         continue;
-      }
-
-      bool flush = false;
-      if (l.second.state.main != -1) {
-         this->deactivate(l.second.state.main);
-         l.second.state.main = -1;
-         flush = true;
-      }
-
-      if (l.second.state.sub != -1) {
-         this->deactivate(l.second.state.sub);
-         l.second.state.sub = -1;
-         flush = true;
-      }
-
-      if (flush) {
-         this->layout_commit();
-      }
-   }
-
-   auto layer = this->layers.get_layer(*layer_id);
-
-   if (state.main == -1) {
-      this->try_layout(
-         state, LayoutState{*surface_id}, [&] (LayoutState const &nl) {
-            HMI_DEBUG("wm", "Layout: %s", kNameLayoutNormal);
-            this->surface_set_layout(*surface_id);
-            state = nl;
-
-            // Commit for configuraton
-            this->layout_commit();
-
-            std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull);
-            compositor::rect area_rect = this->area_info[*surface_id];
-            this->emit_syncdraw(drawing_name, str_area.c_str(),
-                                area_rect.x, area_rect.y, area_rect.w, area_rect.h);
-            this->enqueue_flushdraw(state.main);
-         });
-   } else {
-      if (0 == strcmp(drawing_name, "HomeScreen")) {
-         this->try_layout(
-            state, LayoutState{*surface_id}, [&] (LayoutState const &nl) {
-               HMI_DEBUG("wm", "Layout: %s", kNameLayoutNormal);
-               std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull);
-               compositor::rect area_rect = this->area_info[*surface_id];
-               this->emit_syncdraw(drawing_name, str_area.c_str(),
-                                   area_rect.x, area_rect.y, area_rect.w, area_rect.h);
-               this->enqueue_flushdraw(state.main);
-            });
-      } else {
-         bool can_split = this->can_split(state, *surface_id);
-
-         if (can_split) {
-            this->try_layout(
-               state,
-               LayoutState{state.main, *surface_id},
-               [&] (LayoutState const &nl) {
-                  HMI_DEBUG("wm", "Layout: %s", kNameLayoutSplit);
-                  std::string main =
-                     std::move(*this->lookup_name(state.main));
-
-                  this->surface_set_layout(state.main, surface_id);
-                  if (state.sub != *surface_id) {
-                      if (state.sub != -1) {
-                         this->deactivate(state.sub);
-                      }
-                  }
-                  state = nl;
-
-                  // Commit for configuration and visibility(0)
-                  this->layout_commit();
-
-                  std::string str_area_main = std::string(kNameLayoutSplit) + "." + std::string(kNameAreaMain);
-                  std::string str_area_sub = std::string(kNameLayoutSplit) + "." + std::string(kNameAreaSub);
-                  compositor::rect area_rect_main = this->area_info[state.main];
-                  compositor::rect area_rect_sub = this->area_info[*surface_id];
-                  this->emit_syncdraw(main.c_str(), str_area_main.c_str(),
-                                      area_rect_main.x, area_rect_main.y,
-                                      area_rect_main.w, area_rect_main.h);
-                  this->emit_syncdraw(drawing_name, str_area_sub.c_str(),
-                                      area_rect_sub.x, area_rect_sub.y,
-                                      area_rect_sub.w, area_rect_sub.h);
-                  this->enqueue_flushdraw(state.main);
-                  this->enqueue_flushdraw(state.sub);
-               });
-         } else {
-            this->try_layout(
-               state, LayoutState{*surface_id}, [&] (LayoutState const &nl) {
-                  HMI_DEBUG("wm", "Layout: %s", kNameLayoutNormal);
-
-                  this->surface_set_layout(*surface_id);
-                  if (state.main != *surface_id) {
-                      this->deactivate(state.main);
-                  }
-                  if (state.sub != -1) {
-                      if (state.sub != *surface_id) {
-                         this->deactivate(state.sub);
-                      }
-                  }
-                  state = nl;
-
-                  // Commit for configuraton and visibility(0)
-                  this->layout_commit();
-
-                  std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull);
-                  compositor::rect area_rect = this->area_info[*surface_id];
-                  this->emit_syncdraw(drawing_name, str_area.c_str(),
-                                      area_rect.x, area_rect.y, area_rect.w, area_rect.h);
-                  this->enqueue_flushdraw(state.main);
-               });
-         }
-      }
-   }
-}
-
-void App::api_deactivate_surface(char const *drawing_name, const reply_func &reply) {
-   ST();
-   auto const &surface_id = this->lookup_id(drawing_name);
-
-   if (!surface_id) {
-      reply ("Surface does not exist");
-      return;
-   }
-
-   if (*surface_id == this->layers.main_surface) {
-      reply("Cannot deactivate main_surface");
-      return;
-   }
-
-   auto o_state = *this->layers.get_layout_state(*surface_id);
-
-   if (o_state == nullptr) {
-      reply("Could not find layer for surface");
-      return;
-   }
-
-   struct LayoutState &state = *o_state;
-
-   if (state.main == -1) {
-      reply("No surface active");
-      return;
-   }
-
-   // Check against main_surface, main_surface_name is the configuration item.
-   if (*surface_id == this->layers.main_surface) {
-      HMI_DEBUG("wm", "Refusing to deactivate main_surface %d", *surface_id);
-      reply(nullptr);
-      return;
-   }
-   if((state.main == *surface_id) && (state.sub == *surface_id)){
-       reply("Surface is not active");
-       return;
-   }
-   reply(nullptr);
-
-   if (state.main == *surface_id) {
-      if (state.sub != -1) {
-         this->try_layout(
-            state, LayoutState{state.sub, -1}, [&] (LayoutState const &nl) {
-               std::string sub = std::move(*this->lookup_name(state.sub));
-
-               this->deactivate(*surface_id);
-               this->surface_set_layout(state.sub);
-               state = nl;
-
-               this->layout_commit();
-               std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull);
-               compositor::rect area_rect = this->area_info[state.sub];
-               this->emit_syncdraw(sub.c_str(), str_area.c_str(),
-                                   area_rect.x, area_rect.y, area_rect.w, area_rect.h);
-               this->enqueue_flushdraw(state.sub);
-            });
-      } else {
-         this->try_layout(state, LayoutState{-1, -1}, [&] (LayoutState const &nl) {
-            this->deactivate(*surface_id);
-            state = nl;
-            this->layout_commit();
-         });
-      }
-   } else if (state.sub == *surface_id) {
-      this->try_layout(
-         state, LayoutState{state.main, -1}, [&] (LayoutState const &nl) {
-            std::string main = std::move(*this->lookup_name(state.main));
-
-            this->deactivate(*surface_id);
-            this->surface_set_layout(state.main);
-            state = nl;
-
-            this->layout_commit();
-            std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull);
-            compositor::rect area_rect = this->area_info[state.main];
-            this->emit_syncdraw(main.c_str(), str_area.c_str(),
-                                area_rect.x, area_rect.y, area_rect.w, area_rect.h);
-            this->enqueue_flushdraw(state.main);
-         });
-   }
+void App::allocateWindowResource(char const *event, char const *drawing_name,
+                                 char const *drawing_area, char const *role,
+                                 const reply_func &reply) {
+    const char* new_role = nullptr;
+    const char* new_area = nullptr;
+
+    if (0 == strcmp("activate", event)) {
+        // TODO:
+        // This process will be removed
+        // because the applications will specify role instead of drawing_name
+        {
+            if ((nullptr == role) || (0 == strcmp("", role))) {
+                HMI_DEBUG("wm", "Role is not specified, so get by using app name");
+                new_role = this->app2role_[drawing_name].c_str();
+            }
+            else {
+                new_role = role;
+            }
+            HMI_DEBUG("wm", "drawing_name:%s, new_role: %s", drawing_name, new_role);
+        }
+
+        // TODO:
+        // This process will be removed
+        // because the area "normal.full" and "normalfull" will be prohibited
+        {
+            if (nullptr == drawing_area) {
+                new_area = "normal";
+            }
+            else if (0 == strcmp("normal.full", drawing_area)) {
+                new_area = "normal";
+            }
+            else if (0 == strcmp("homescreen", new_role)) {
+                // Now homescreen specifies "normalfull"
+                new_area = "full";
+            }
+            else {
+                new_area = "normal";
+            }
+            HMI_DEBUG("wm", "drawing_area:%s, new_area: %s", drawing_area, new_area);
+        }
+    }
+    else if (0 == strcmp("deactivate", event)) {
+        // TODO:
+        // This process will be removed
+        // because the applications will specify role instead of drawing_name
+        {
+            if ((nullptr == role) || (0 == strcmp("", role))) {
+                HMI_DEBUG("wm", "Role is not specified, so get by using app name");
+                new_role = this->app2role_[drawing_name].c_str();
+            }
+            else {
+                new_role = role;
+            }
+            HMI_DEBUG("wm", "drawing_name:%s, new_role: %s", drawing_name, new_role);
+        }
+        new_area = "";
+    }
+
+    // TODO:
+    // Check role
+
+    // TODO:
+    // If event is "activate" and area is not specifid,
+    // get default value by using role
+
+    // Check Policy
+    json_object* json_in = json_object_new_object();
+    json_object* json_out = json_object_new_object();
+    json_object_object_add(json_in, "event", json_object_new_string(event));
+
+    if (nullptr != new_role) {
+        json_object_object_add(json_in, "role", json_object_new_string(new_role));
+    }
+    if (nullptr != new_area) {
+        json_object_object_add(json_in, "area", json_object_new_string(new_area));
+    }
+
+    int ret = this->pm_.checkPolicy(json_in, &json_out);
+    if (0 > ret) {
+        reply("Error checkPolicy()");
+        return;
+    }
+    else {
+        HMI_DEBUG("wm", "result: %s", json_object_get_string(json_out));
+    }
+
+    // Release json_object
+    json_object_put(json_in);
+
+    // Cat state
+    json_object* json_car;
+    if (!json_object_object_get_ex(json_out, "car", &json_car)) {
+        reply("Not found key \"car\"");
+        return;
+    }
+
+    json_bool is_changed;
+    is_changed = jh::getBoolFromJson(json_car, "is_changed");
+    if (is_changed) {
+        // Update car state
+        std::string car_state = jh::getStringFromJson(json_car, "state");
+        HMI_DEBUG("wm", "car_state: %s", car_state.c_str());
+
+        // Emit car event
+        if ("car_stop" == car_state) {
+            this->emitCarStop();
+        }
+        else if ("car_run" == car_state) {
+            this->emitCarRun();
+        }
+        else {
+            reply("Unknown car state");
+            return;
+        }
+    }
+
+    // Lamp state
+    json_object* json_lamp;
+    if (!json_object_object_get_ex(json_out, "lamp", &json_lamp)) {
+        reply("Not found key \"lamp\"");
+        return;
+    }
+
+    is_changed = jh::getBoolFromJson(json_lamp, "is_changed");
+    if (is_changed) {
+        // Update car state
+        std::string lamp_state = jh::getStringFromJson(json_lamp, "state");
+        HMI_DEBUG("wm", "lamp_state: %s", lamp_state.c_str());
+
+        // Emit lamp event
+        if ("lamp_off" == lamp_state) {
+            this->emitHeadlampOff();
+        }
+        else if ("lamp_on" == lamp_state) {
+            this->emitHeadlampOn();
+        }
+        else {
+            reply("Unknown lamp state");
+            return;
+        }
+    }
+
+    // Get category
+    const char* category = nullptr;
+    std::string str_category;
+    if (nullptr != new_role) {
+        str_category = this->pm_.roleToCategory(new_role);
+        category = str_category.c_str();
+        HMI_DEBUG("wm", "role:%s category:%s", new_role, category);
+    }
+
+    // Update layout
+    if (this->lm_.updateLayout(json_out, new_role, category)) {
+        HMI_DEBUG("wm", "Layer is changed!!");
+
+        // Allocate surface
+        this->allocateSurface();
+    }
+    else {
+        HMI_DEBUG("wm", "All layer is NOT changed!!");
+    }
+
+    // Release json_object
+    json_object_put(json_out);
+
+    return;
 }
 
 void App::enqueue_flushdraw(int surface_id) {
@@ -603,6 +464,15 @@ void App::api_enddraw(char const *drawing_name) {
 
 void App::api_ping() { this->dispatch_pending_events(); }
 
+void App::send_event(char const *evname){
+   HMI_DEBUG("wm", "%s: %s", __func__, evname);
+
+   int ret = afb_event_push(this->map_afb_event[evname], nullptr);
+   if (ret != 0) {
+      HMI_DEBUG("wm", "afb_event_push failed: %m");
+   }
+}
+
 void App::send_event(char const *evname, char const *label){
    HMI_DEBUG("wm", "%s: %s(%s)", __func__, evname, label);
 
@@ -671,7 +541,9 @@ void App::surface_removed(uint32_t surface_id) {
    } else {
       auto drawing_name = this->lookup_name(surface_id);
       if (drawing_name) {
-         this->api_deactivate_surface(drawing_name->c_str(), [](const char*){});
+         this->allocateWindowResource("deactivate", drawing_name->c_str(),
+                                      nullptr, nullptr,
+                                      [](const char*){});
       }
    }
 
@@ -705,6 +577,26 @@ void App::emit_invisible(char const *label) {
 
 void App::emit_visible(char const *label) { return emit_visible(label, true); }
 
+void App::emitHeadlampOff() {
+    // Send HeadlampOff event for all application
+    this->send_event(kListEventName[Event_HeadlampOff]);
+}
+
+void App::emitHeadlampOn() {
+    // Send HeadlampOn event for all application
+    this->send_event(kListEventName[Event_HeadlampOn]);
+}
+
+void App::emitCarStop() {
+    // Send CarStop event for all application
+    this->send_event(kListEventName[Event_CarStop]);
+}
+
+void App::emitCarRun() {
+    // Send CarRun event for all application
+    this->send_event(kListEventName[Event_CarRun]);
+}
+
 result<int> App::api_request_surface(char const *drawing_name) {
    auto lid = this->layers.get_layer_id(std::string(drawing_name));
    if (!lid) {
@@ -731,6 +623,20 @@ result<int> App::api_request_surface(char const *drawing_name) {
          HMI_DEBUG("wm", "Set main_surface id to %u", id);
       }
 
+#if 0 // @@@@@
+      // TODO:
+      // This process will be implemented in SystemManager
+      {
+          // Generate app id
+          auto id = int(this->app_id_alloc_.generate_id(drawing_name));
+          this->appname2appid_[drawing_name] = id;
+      }
+#endif
+
+      // Set map of (role, surface_id)
+      std::string role = this->app2role_[std::string(drawing_name)];
+      this->role2surfaceid_[role] = id;
+
       return Ok<int>(id);
    }
 
@@ -910,56 +816,24 @@ void App::deactivate(int id) {
    }
 }
 
-void App::deactivate_main_surface() {
-   this->layers.main_surface = -1;
-   this->api_deactivate_surface(this->layers.main_surface_name.c_str(), [](const char*){});
-}
-
-bool App::can_split(struct LayoutState const &state, int new_id) {
-   if (state.main != -1 && state.main != new_id) {
-      auto new_id_layer = this->layers.get_layer_id(new_id).value();
-      auto current_id_layer = this->layers.get_layer_id(state.main).value();
-
-      // surfaces are on separate layers, don't bother.
-      if (new_id_layer != current_id_layer) {
-         return false;
-      }
-
-      std::string const &new_id_str = this->lookup_name(new_id).value();
-      std::string const &cur_id_str = this->lookup_name(state.main).value();
-
-      auto const &layer = this->layers.get_layer(new_id_layer);
-
-      HMI_DEBUG("wm", "layer info name: %s", layer->name.c_str());
-
-      if (layer->layouts.empty()) {
-         return false;
-      }
-
-      for (auto i = layer->layouts.cbegin(); i != layer->layouts.cend(); i++) {
-         HMI_DEBUG("wm", "%d main_match '%s'", new_id_layer, i->main_match.c_str());
-         auto rem = std::regex(i->main_match);
-         if (std::regex_match(cur_id_str, rem)) {
-            // build the second one only if the first already matched
-            HMI_DEBUG("wm", "%d sub_match '%s'", new_id_layer, i->sub_match.c_str());
-            auto res = std::regex(i->sub_match);
-            if (std::regex_match(new_id_str, res)) {
-               HMI_DEBUG("wm", "layout matched!");
-               return true;
-            }
-         }
-      }
-   }
+void App::deactivate(std::string role) {
+    std::string app = this->roleToApp(role);
+    auto const &id = this->lookup_id(app.c_str());
+    if (!id) {
+      HMI_ERROR("wm", "Surface does not exist");
+      return;
+    }
+    HMI_DEBUG("wm", "Deactivate role:%s (app:%s)",
+              role.c_str(), app.c_str());
 
-   return false;
+    this->deactivate(*id);
 }
 
-void App::try_layout(struct LayoutState & /*state*/,
-                     struct LayoutState const &new_layout,
-                     std::function<void(LayoutState const &nl)> apply) {
-   if (this->policy.layout_is_valid(new_layout)) {
-      apply(new_layout);
-   }
+void App::deactivate_main_surface() {
+   this->layers.main_surface = -1;
+   this->allocateWindowResource("deactivate", this->layers.main_surface_name.c_str(),
+                                nullptr, nullptr,
+                                [](const char*){});
 }
 
 /**
@@ -982,4 +856,302 @@ void controller_hooks::surface_destination_rectangle(uint32_t /*surface_id*/,
                                                      uint32_t /*w*/,
                                                      uint32_t /*h*/) {}
 
+int App::allocateSurface() {
+    HMI_DEBUG("wm", "Call");
+
+    // Get current/previous layers
+    LayoutManager::TypeLayers crr_layers = this->lm_.getCurrentLayers();
+    LayoutManager::TypeLayers prv_layers = this->lm_.getPreviousLayers();
+
+    // Update resource of all layers
+    for (auto itr_layers = crr_layers.begin();
+         itr_layers != crr_layers.end(); ++itr_layers) {
+        // Get layer
+        std::string layer = itr_layers->first;
+        HMI_DEBUG("wm", "Update resource in %s layer", layer.c_str());
+
+        // If layout is changed, update resouce
+        if (this->lm_.isLayoutChanged(layer.c_str())) {
+            // Get current/previous layout
+            LayoutManager::TypeLayouts crr_layout = itr_layers->second;
+            LayoutManager::TypeLayouts prv_layout = prv_layers[layer];
+
+            // Get current/previous layout name
+            std::string crr_layout_name = crr_layout.begin()->first;
+            std::string prv_layout_name = prv_layout.begin()->first;
+            HMI_DEBUG("wm", "layout name crr:%s prv:%s",
+                      crr_layout_name.c_str(), prv_layout_name.c_str());
+
+            // Get current/previous ares
+            LayoutManager::TypeAreas crr_areas = crr_layout[crr_layout_name];
+            LayoutManager::TypeAreas prv_areas = prv_layout[prv_layout_name];
+
+            // Create previous displayed role list
+            std::string prv_area_name;
+            std::vector<std::string> prv_role_list;
+            for (auto itr_areas = prv_areas.begin();
+                 itr_areas != prv_areas.end(); ++itr_areas) {
+                prv_area_name = itr_areas->first;
+                prv_role_list.push_back(prv_areas[prv_area_name]["role"]);
+                HMI_DEBUG("wm", "previous displayed role:%s",
+                          prv_areas[prv_area_name]["role"].c_str());
+            }
+
+            // Allocate surface for each area
+            std::string crr_area_name;
+            std::string crr_role_name;
+            LayoutManager::TypeRolCtg crr_rol_ctg;
+            for (auto itr_areas = crr_areas.begin();
+                 itr_areas != crr_areas.end(); ++itr_areas) {
+                crr_area_name = itr_areas->first;
+                crr_rol_ctg = itr_areas->second;
+
+                // Get role of current area
+                if ("category" == crr_rol_ctg.begin()->first) {
+                    // If current area have category
+                    // Get category name
+                    std::string crr_ctg = crr_rol_ctg.begin()->second;
+
+                    // Serch relevant role fron previous displayed role list
+                    for (auto itr_role = prv_role_list.begin();
+                         itr_role != prv_role_list.end(); ++itr_role) {
+                        std::string prv_ctg = this->pm_.roleToCategory((*itr_role).c_str());
+                        if (crr_ctg == prv_ctg) {
+                            // First discovered role is set to current role
+                            crr_role_name = *itr_role;
+
+                            // Delete used role for other areas
+                            // which have same category
+                            prv_role_list.erase(itr_role);
+
+                            break;
+                        }
+                    }
+                }
+                else {
+                    crr_role_name = itr_areas->second["role"];
+                }
+                HMI_DEBUG("wm", "Allocate surface for area:%s role:%s",
+                          crr_area_name.c_str(), crr_role_name.c_str());
+
+                // Deactivate non-displayed role
+                std::string prv_role_name;
+                if (crr_layout_name == prv_layout_name) {
+                    HMI_DEBUG("wm", "Current layout is same with previous");
+
+                    // Deactivate previous role in same area
+                    // if it is different with current
+                    prv_role_name = prv_areas[crr_area_name]["role"];
+                    if (crr_role_name != prv_role_name) {
+                        this->deactivate(prv_role_name);
+                    }
+                }
+                else {
+                    HMI_DEBUG("wm", "Current layout is different with previous");
+
+                    if ("none" != prv_layout_name) {
+                        // Deactivate previous role in all area in previous layout
+                        // if it is different with current role
+                        for(auto itr = prv_areas.begin(); itr != prv_areas.end(); ++itr) {
+                            prv_role_name = itr->second["role"].c_str();
+                            if (crr_role_name != prv_role_name) {
+                                this->deactivate(prv_role_name);
+                            }
+                        }
+                    }
+                }
+
+                // Set surface for displayed role
+                if ("none" != crr_layout_name) {
+                    // If current layout is not "none",
+                    // set surface for current role
+                    this->setSurfaceSize(crr_role_name.c_str(), crr_area_name.c_str());
+
+                    // TODO:
+                    // This API is workaround.
+                    // Resource manager should manage each resource infomations
+                    // according to architecture document.
+                    this->lm_.updateArea(layer.c_str(), crr_role_name.c_str(), crr_area_name.c_str());
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+void App::setSurfaceSize(const char* role, const char* area) {
+    HMI_DEBUG("wm", "role:%s area:%s", role, area);
+
+    // Get size of current area
+    compositor::rect size = this->lm_.getAreaSize(area);
+
+    // Set destination to the display rectangle
+    int surface_id = this->role2surfaceid_[role];
+    auto &s = this->controller->surfaces[surface_id];
+    s->set_destination_rectangle(size.x, size.y, size.w, size.h);
+    this->layout_commit();
+
+    // Update area information
+    this->area_info[surface_id].x = size.x;
+    this->area_info[surface_id].y = size.y;
+    this->area_info[surface_id].w = size.w;
+    this->area_info[surface_id].h = size.h;
+    HMI_DEBUG("wm", "Surface rect { %d, %d, %d, %d }",
+              size.x, size.y, size.w, size.h);
+
+    // Emit syncDraw event
+    const char* app = this->roleToApp(role).c_str();
+    this->emit_syncdraw(app, area,
+                        size.x, size.y, size.w, size.h);
+
+    // Enqueue flushDraw event
+    this->enqueue_flushdraw(surface_id);
+}
+
+std::string App::roleToApp(std::string role) {
+    HMI_DEBUG("wm", "Call");
+
+    for (auto itr = this->app2role_.begin();
+         itr != this->app2role_.end(); itr++) {
+        if (role == itr->second) {
+            return itr->first;
+        }
+    }
+    return std::string("none");
+}
+
+extern const char* kDefaultAppDb;
+int App::loadAppDb() {
+    HMI_DEBUG("wm", "Call");
+
+    // Get afm application installed dir
+    char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
+    HMI_DEBUG("wm", "afm_app_install_dir:%s", afm_app_install_dir);
+
+    std::string file_name;
+    if (!afm_app_install_dir) {
+        HMI_ERROR("wm", "AFM_APP_INSTALL_DIR is not defined");
+    }
+    else {
+        file_name = std::string(afm_app_install_dir) + std::string("/etc/app.db");
+    }
+
+    // Load app.db
+    HMI_DEBUG("wm", "file_name:%s", file_name.c_str());
+    json_object* json_obj = json_object_from_file(file_name.c_str());
+    if (nullptr == json_obj) {
+        HMI_ERROR("wm", "Could not open app.db, so use default role information");
+        json_obj = json_tokener_parse(kDefaultAppDb);
+    }
+    HMI_DEBUG("wm", "json_obj dump:%s", json_object_get_string(json_obj));
+
+    // Perse apps
+    HMI_DEBUG("wm", "Perse apps");
+    json_object* json_cfg;
+    if (!json_object_object_get_ex(json_obj, "apps", &json_cfg)) {
+        HMI_ERROR("wm", "Parse Error!!");
+        return -1;
+    }
+
+    int len = json_object_array_length(json_cfg);
+    HMI_DEBUG("wm", "json_cfg len:%d", len);
+    HMI_DEBUG("wm", "json_cfg dump:%s", json_object_get_string(json_cfg));
+
+    for (int i=0; i<len; i++) {
+        json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
+        HMI_DEBUG("wm", "> json_tmp dump:%s", json_object_get_string(json_tmp));
+
+        const char* app = jh::getStringFromJson(json_tmp, "name");
+        if (nullptr == app) {
+            HMI_ERROR("wm", "Parse Error!!");
+            return -1;
+        }
+        HMI_DEBUG("wm", "> app:%s", app);
+
+        const char* role = jh::getStringFromJson(json_tmp, "role");
+        if (nullptr == role) {
+            HMI_ERROR("wm", "Parse Error!!");
+            return -1;
+        }
+        HMI_DEBUG("wm", "> role:%s", role);
+
+        this->app2role_[app] = std::string(role);
+    }
+
+    // Check
+    for(auto itr = this->app2role_.begin();
+      itr != this->app2role_.end(); ++itr) {
+        HMI_DEBUG("wm", "app:%s role:%s",
+                  itr->first.c_str(), itr->second.c_str());
+    }
+
+    // Release json_object
+    json_object_put(json_obj);
+
+    return 0;
+}
+
+
+const char* kDefaultAppDb = "{ \
+    \"apps\": [ \
+        { \
+            \"name\": \"HomeScreen\", \
+            \"role\": \"homescreen\" \
+        }, \
+        { \
+            \"name\": \"Music\", \
+            \"role\": \"music\" \
+        }, \
+        { \
+            \"name\": \"MediaPlayer\", \
+            \"role\": \"music\" \
+        }, \
+        { \
+            \"name\": \"Video\", \
+            \"role\": \"video\" \
+        }, \
+        { \
+            \"name\": \"VideoPlayer\", \
+            \"role\": \"video\" \
+        }, \
+        { \
+            \"name\": \"WebBrowser\", \
+            \"role\": \"browser\" \
+        }, \
+        { \
+            \"name\": \"Radio\", \
+            \"role\": \"radio\" \
+        }, \
+        { \
+            \"name\": \"Phone\", \
+            \"role\": \"phone\" \
+        }, \
+        { \
+            \"name\": \"Navigation\", \
+            \"role\": \"map\" \
+        }, \
+        { \
+            \"name\": \"HVAC\", \
+            \"role\": \"hvac\" \
+        }, \
+        { \
+            \"name\": \"Settings\", \
+            \"role\": \"settings\" \
+        }, \
+        { \
+            \"name\": \"Dashboard\", \
+            \"role\": \"dashboard\" \
+        }, \
+        { \
+            \"name\": \"POI\", \
+            \"role\": \"poi\" \
+        }, \
+        { \
+            \"name\": \"Mixer\", \
+            \"role\": \"mixer\" \
+        } \
+    ] \
+}";
+
+
 }  // namespace wm
index d1393c0..9ab1280 100644 (file)
@@ -31,6 +31,7 @@
 #include "policy.hpp"
 #include "result.hpp"
 #include "wayland_ivi_wm.hpp"
+#include "policy_manager.hpp"
 #include "hmi-debug.h"
 
 namespace wl {
@@ -144,7 +145,13 @@ struct App {
       Event_SyncDraw,
       Event_FlushDraw,
 
-      Event_Val_Max = Event_FlushDraw,
+      Event_HeadlampOff,
+      Event_HeadlampOn,
+
+      Event_CarStop,
+      Event_CarRun,
+
+      Event_Val_Max = Event_CarRun,
    };
 
    const std::vector<const char *> kListEventName{
@@ -153,7 +160,11 @@ struct App {
      "visible",
      "invisible",
      "syncdraw",
-     "flushdraw"
+     "flushdraw",
+     "headlamp_off",
+     "headlamp_on",
+     "car_stop",
+     "car_run",
    };
 
    struct controller_hooks chooks;
@@ -203,12 +214,14 @@ struct App {
 
    result<int> api_request_surface(char const *drawing_name);
    char const *api_request_surface(char const *drawing_name, char const *ivi_id);
-   void api_activate_surface(char const *drawing_name, char const *drawing_area, const reply_func &reply);
-   void api_deactivate_surface(char const *drawing_name, const reply_func &reply);
+   void allocateWindowResource(char const *event, char const *drawing_name,
+                               char const *role, char const *drawing_area,
+                               const reply_func &reply);
    void api_enddraw(char const *drawing_name);
    result<json_object *> api_get_display_info();
    result<json_object *> api_get_area_info(char const *drawing_name);
    void api_ping();
+   void send_event(char const *evname);
    void send_event(char const *evname, char const *label);
    void send_event(char const *evname, char const *label, char const *area, int x, int y, int w, int h);
 
@@ -217,6 +230,23 @@ struct App {
    void surface_removed(uint32_t surface_id);
 
 private:
+#if 1 // @@@@@
+   PolicyManager pm_;
+   LayoutManager lm_;
+   std::unordered_map<std::string, int> role2surfaceid_;
+   std::unordered_map<std::string, std::string> app2role_;
+   std::unordered_map<int, int> appid2role_;
+
+   int allocateSurface();
+   void setSurfaceSize(const char* role, const char* area);
+   std::string roleToApp(std::string role);
+   int loadAppDb();
+
+#if 0
+   struct id_allocator app_id_alloc_;
+   std::unordered_map<std::string, int> appname2appid_;
+#endif
+#endif
    optional<int> lookup_id(char const *name);
    optional<std::string> lookup_name(int id);
 
@@ -227,7 +257,6 @@ private:
 
    int init_layers();
 
-   void surface_set_layout(int surface_id, optional<int> sub_surface_id = nullopt);
    void layout_commit();
 
    // TMC WM Events to clients
@@ -238,15 +267,16 @@ private:
    void emit_visible(char const *label, bool is_visible);
    void emit_invisible(char const *label);
    void emit_visible(char const *label);
+   void emitHeadlampOff();
+   void emitHeadlampOn();
+   void emitCarStop();
+   void emitCarRun();
 
    void activate(int id);
    void deactivate(int id);
+   void deactivate(std::string role);
    void deactivate_main_surface();
 
-   bool can_split(struct LayoutState const &state, int new_id);
-   void try_layout(struct LayoutState &state,
-                   struct LayoutState const &new_layout,
-                   std::function<void(LayoutState const &nl)> apply);
 };
 
 }  // namespace wm
diff --git a/src/db/app.db b/src/db/app.db
new file mode 100644 (file)
index 0000000..32155ac
--- /dev/null
@@ -0,0 +1,68 @@
+{
+    "apps": [
+        {
+            "name": "HomeScreen",
+            "role": "homescreen"
+        },
+        {
+            "name": "Music",
+            "role": "music"
+        },
+        {
+            "name": "MediaPlayer",
+            "role": "music"
+        },
+        {
+            "name": "Video",
+            "role": "video"
+        },
+        {
+            "name": "VideoPlayer",
+            "role": "video"
+        },
+        {
+            "name": "WebBrowser",
+            "role": "browser"
+        },
+        {
+            "name": "Radio",
+            "role": "radio"
+        },
+        {
+            "name": "Phone",
+            "role": "phone"
+        },
+        {
+            "name": "Navigation",
+            "role": "map"
+        },
+        {
+            "name": "HVAC",
+            "role": "hvac"
+        },
+        {
+            "name": "Settings",
+            "role": "settings"
+        },
+        {
+            "name": "Dashboard",
+            "role": "dashboard"
+        },
+        {
+            "name": "POI",
+            "role": "poi"
+        },
+        {
+            "name": "Mixer",
+            "role": "mixer"
+        },
+        {
+            "name": "Splitable1",
+            "role": "splitable1"
+        },
+        {
+            "name": "Splitable2",
+            "role": "splitable2"
+        }
+    ]
+}
\ No newline at end of file
index 193a187..ac3d2b0 100644 (file)
  * limitations under the License.
  */
 
-#include "json_helper.hpp"
 
+#include <json-c/json.h>
 #include <json.h>
+#include "json_helper.hpp"
+#include "hmi-debug.h"
+
 
 json_object *to_json(compositor::surface_properties const &s) {
    // auto j = json::object({
@@ -100,3 +103,52 @@ json_object *to_json(std::vector<uint32_t> const &v) {
    }
    return a;
 }
+
+namespace jh {
+
+const char* getStringFromJson(json_object* obj, const char* key) {
+    if ((nullptr == obj) || (nullptr == key)) {
+        HMI_ERROR("wm:jh", "Argument is nullptr!!!");
+        return nullptr;
+    }
+
+    json_object* tmp;
+    if (!json_object_object_get_ex(obj, key, &tmp)) {
+        HMI_DEBUG("wm:jh", "Not found key \"%s\"", key);
+        return nullptr;
+    }
+
+    return json_object_get_string(tmp);
+}
+
+int getIntFromJson(json_object* obj, const char* key) {
+    if ((nullptr == obj) || (nullptr == key)) {
+        HMI_ERROR("wm", "Argument is nullptr!!!");
+        return 0;
+    }
+
+    json_object* tmp;
+    if (!json_object_object_get_ex(obj, key, &tmp)) {
+        HMI_DEBUG("wm", "Not found key \"%s\"", key);
+        return 0;
+    }
+
+    return json_object_get_int(tmp);
+}
+
+json_bool getBoolFromJson(json_object* obj, const char* key) {
+    if ((nullptr == obj) || (nullptr == key)) {
+        HMI_ERROR("wm", "Argument is nullptr!!!");
+        return 0;
+    }
+
+    json_object* tmp;
+    if (!json_object_object_get_ex(obj, key, &tmp)) {
+        HMI_DEBUG("wm", "Not found key \"%s\"", key);
+        return 0;
+    }
+
+    return json_object_get_boolean(tmp);
+}
+
+} // namespace jh
index 78e03f7..c2087cf 100644 (file)
 
 #include "result.hpp"
 #include "wayland_ivi_wm.hpp"
+#include <json-c/json.h>
 #include <json.hpp>
 
+
 struct json_object;
 
 json_object *to_json(compositor::screen const *s);
 json_object *to_json(compositor::controller::props_map const &s);
 json_object *to_json(std::vector<uint32_t> const &v);
 
+namespace jh {
+const char* getStringFromJson(json_object* obj, const char* key);
+int getIntFromJson(json_object* obj, const char* key);
+json_bool getBoolFromJson(json_object* obj, const char* key);
+} // namespace jh
 #endif  // TMCAGLWM_JSON_HELPER_HPP
diff --git a/src/layout.cpp b/src/layout.cpp
deleted file mode 100644 (file)
index fbf2baa..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "layout.hpp"
diff --git a/src/layout.hpp b/src/layout.hpp
deleted file mode 100644 (file)
index d5fd00c..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TMCAGLWM_LAYOUT_HPP
-#define TMCAGLWM_LAYOUT_HPP
-
-#include <cstdint>
-#include <string>
-
-#include "result.hpp"
-
-namespace wm {
-
-struct LayoutState {
-   int main{-1};
-   int sub{-1};
-
-   bool operator==(const LayoutState &b) const {
-      return main == b.main && sub == b.sub;
-   }
-
-   bool operator!=(const LayoutState &b) const {
-      return !(*this == b);
-   }
-};
-
-}  // namespace wm
-
-#endif  // TMCAGLWM_LAYOUT_HPP
diff --git a/src/layout_manager/db/layout.db b/src/layout_manager/db/layout.db
new file mode 100644 (file)
index 0000000..c7cefd8
--- /dev/null
@@ -0,0 +1,158 @@
+{
+    "layouts": [
+        {
+            "name": "pu",
+            "layer": "on_screen",
+            "areas": [
+                {
+                    "name": "pop_up",
+                    "role": "incomming_call"
+                }
+            ]
+        },
+        {
+            "name": "sa",
+            "layer": "on_screen",
+            "areas": [
+                {
+                    "name": "system_alert",
+                    "role": "system_alert"
+                }
+            ]
+        },
+        {
+            "name": "m1",
+            "layer": "apps",
+            "areas": [
+                {
+                    "name": "normal",
+                    "role": "map"
+                }
+            ]
+        },
+        {
+            "name": "m2",
+            "layer": "apps",
+            "areas": [
+                {
+                    "name": "split.main",
+                    "role": "map"
+                },
+                {
+                    "name": "split.sub",
+                    "category": "splitable"
+                }
+            ]
+        },
+        {
+            "name": "mf",
+            "layer": "apps",
+            "areas": [
+                {
+                    "name": "full",
+                    "role": "map"
+                }
+            ]
+        },
+        {
+            "name": "s1",
+            "layer": "apps",
+            "areas": [
+                {
+                    "name": "normal",
+                    "category": "splitable"
+                }
+            ]
+        },
+        {
+            "name": "s2",
+            "layer": "apps",
+            "areas": [
+                {
+                    "name": "split.main",
+                    "category": "splitable"
+                },
+                {
+                    "name": "split.sub",
+                    "category": "splitable"
+                }
+            ]
+        },
+        {
+            "name": "g",
+            "layer": "apps",
+            "areas": [
+                {
+                    "name": "normal",
+                    "category": "general"
+                }
+            ]
+        },
+        {
+            "name": "hs",
+            "layer": "homescreen",
+            "areas": [
+                {
+                    "name": "full",
+                    "role": "homescreen"
+                }
+            ]
+        }
+    ],
+    "areas": [
+        {
+            "name": "normal",
+            "rect": {
+                "x": 0,
+                "y": 218,
+                "w": 1080,
+                "h": 1488
+            }
+        },
+        {
+            "name": "split.main",
+            "rect": {
+                "x": 0,
+                "y": 218,
+                "w": 1080,
+                "h": 744
+            }
+        },
+        {
+            "name": "split.sub",
+            "rect": {
+                "x": 0,
+                "y": 962,
+                "w": 1080,
+                "h": 744
+            }
+        },
+        {
+            "name": "full",
+            "rect": {
+                "x": 0,
+                "y": 0,
+                "w": 1080,
+                "h": 1920
+            }
+        },
+        {
+            "name": "pop_up",
+            "rect": {
+                "x": 0,
+                "y": 640,
+                "w": 1080,
+                "h": 640
+            }
+        },
+        {
+            "name": "system_alert",
+            "rect": {
+                "x": 0,
+                "y": 640,
+                "w": 1080,
+                "h": 640
+            }
+        }
+    ]
+}
diff --git a/src/layout_manager/layout.cpp b/src/layout_manager/layout.cpp
new file mode 100644 (file)
index 0000000..dc73cbf
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <json-c/json.h>
+#include "layout.hpp"
+#include "json_helper.hpp"
+#include "hmi-debug.h"
+
+
+LayoutManager::LayoutManager() {
+    HMI_DEBUG("wm:lm", "Call");
+}
+
+int LayoutManager::initialize() {
+    HMI_DEBUG("wm:lm", "Call");
+
+    int ret = 0;
+
+    // Load layout.db
+    ret = this->loadLayoutDb();
+    if (0 > ret) {
+        HMI_ERROR("wm:lm", "Load layout.db Error!!");
+        return ret;
+    }
+
+    TypeLayouts layout;
+    TypeAreas area;
+    TypeRolCtg rol_ctg;
+
+    rol_ctg["none"] = "none";
+    area["none"]    = rol_ctg;
+    layout["none"]  = area;
+
+    this->prv_layers_["on_screen"]  = layout;
+    this->prv_layers_["apps"]       = layout;
+    this->prv_layers_["homescreen"] = layout;
+
+    this->crr_layers_["on_screen"]  = layout;
+    this->crr_layers_["apps"]       = layout;
+    this->crr_layers_["homescreen"] = layout;
+
+    this->prv_layers_car_stop_["on_screen"]  = layout;
+    this->prv_layers_car_stop_["apps"]       = layout;
+    this->prv_layers_car_stop_["homescreen"] = layout;
+
+    return ret;
+}
+
+bool LayoutManager::updateLayout(json_object* obj,
+                                     const char* new_role, const char* category) {
+    HMI_DEBUG("wm:lm", "Call");
+
+    bool ret = false;
+
+    // Check car state change
+    json_object* json_car;
+    if (!json_object_object_get_ex(obj, "car", &json_car)) {
+        HMI_ERROR("wm:lm", "Parse Error!!");
+        return -1;
+    }
+
+    json_bool is_car_state_changed;
+    std::string car_state = "";
+    is_car_state_changed = jh::getBoolFromJson(json_car, "is_changed");
+    if (is_car_state_changed) {
+        // If car state is changed, get car state
+        car_state = jh::getStringFromJson(json_car, "state");
+    }
+
+    // Update layout of all layers
+    json_object* json_layers;
+    if (!json_object_object_get_ex(obj, "layers", &json_layers)) {
+        HMI_ERROR("wm:lm", "Parse Error!!");
+        return -1;
+    }
+
+    int len = json_object_array_length(json_layers);
+    HMI_DEBUG("wm:lm", "json_layers len:%d", len);
+    HMI_DEBUG("wm:lm", "json_layers dump:%s", json_object_get_string(json_layers));
+
+    for (int i=0; i<len; i++) {
+        json_object* json_tmp = json_object_array_get_idx(json_layers, i);
+
+        // Get layer name and json_object
+        const char* layer;
+        json_object* json_layer;
+        json_object_object_foreach(json_tmp, key, val) {
+            layer = key;
+            json_layer = val;
+            HMI_DEBUG("wm:lm", "Update %s layer state", layer);
+        }
+
+        // Store previous state
+        this->prv_layers_[layer] = this->crr_layers_[layer];
+        std::string prv_layout_name = this->prv_layers_[layer].begin()->first;
+
+        // If car state is changed car_stop -> car_run,
+        // store current state for state of car stop
+        if ((is_car_state_changed) && ("car_run" == car_state)) {
+            HMI_DEBUG("wm:lm", "Store current state for state of car stop");
+            this->prv_layers_car_stop_[layer] = this->crr_layers_[layer];
+        }
+
+        json_object* json_is_changed;
+        if (!json_object_object_get_ex(json_layer, "is_changed", &json_is_changed)) {
+            HMI_ERROR("wm:lm", "Not found key \"is_changed\"");
+           return false;
+        }
+
+        // If layer state is changed
+        if (json_object_get_boolean(json_is_changed)) {
+            // Set layout changed flag
+            this->is_layout_changed_[layer] = true;
+
+            json_object* json_state;
+            if (!json_object_object_get_ex(json_layer, "state", &json_state)) {
+                HMI_ERROR("wm:lm", "Not found key \"state\"");
+                return false;
+            }
+
+            const char* crr_layout_name = json_object_get_string(json_state);
+            HMI_DEBUG("wm:lm", "crr state: %s", crr_layout_name);
+
+            TypeLayouts crr_layout;
+            if ((is_car_state_changed) && ("car_stop" == car_state)) {
+                // If car state is changed car_run -> car_stop,
+                // restore state of car stop
+                HMI_DEBUG("wm:lm", "Restore state of car stop");
+                crr_layout = this->prv_layers_car_stop_[layer];
+            }
+            else if ("none" == std::string(crr_layout_name)) {
+              // If current layout is "none",
+              // current areas is set with "none"
+              TypeAreas area;
+              TypeRolCtg rol_ctg;
+              rol_ctg["none"] = "none";
+              area["none"] = rol_ctg;
+              crr_layout["none"] = area;
+            }
+            else {
+                if (std::string(crr_layout_name) == prv_layout_name) {
+                    // If previous layout is same with current,
+                    // previous areas are copied to current
+                    crr_layout[crr_layout_name] = this->prv_layers_[layer][crr_layout_name];
+                }
+                else {
+                    // If previous layout is NOT same with current,
+                    // current areas is set with default value
+                    crr_layout[crr_layout_name] = this->layout_define_[crr_layout_name];
+                }
+
+                if (is_car_state_changed) {
+                    // Updating role is not necessary
+                    // because new_role is not specified when car state is changed
+                }
+                else {
+                    // Get new_area for new role
+                    std::string new_area = this->getAreaName(this->layout_define_[crr_layout_name],
+                                                             new_role, category);
+
+                    // Update role in new area
+                    TypeRolCtg crr_role;
+                    crr_role["role"] = std::string(new_role);
+                    crr_layout[crr_layout_name][new_area] = crr_role;
+                }
+            }
+
+            // Update layer state
+            this->crr_layers_[layer] = crr_layout;
+
+            // Check
+            for (auto itr_layout = this->crr_layers_[layer].begin();
+                 itr_layout != this->crr_layers_[layer].end(); ++itr_layout) {
+              for (auto itr_area = itr_layout->second.begin();
+                   itr_area != itr_layout->second.end(); ++itr_area) {
+                for (auto itr_role = itr_area->second.begin();
+                     itr_role != itr_area->second.end(); ++itr_role) {
+                  HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s",
+                            itr_layout->first.c_str(), itr_area->first.c_str(),
+                            itr_role->first.c_str(), itr_role->second.c_str());
+                }
+              }
+            }
+
+            ret = true;
+        }
+        else {
+            // Clear layout changed flag
+            this->is_layout_changed_[layer] = false;
+        }
+    }
+    return ret;
+}
+
+// TODO: This API is for workaround, so this will be removed
+void LayoutManager::updateArea(const char* layer, const char* role, const char* area) {
+    this->crr_layers_[layer].begin()->second[area]["role"] = std::string(role);
+}
+
+LayoutManager::TypeLayers LayoutManager::getCurrentLayers() {
+    return this->crr_layers_;
+}
+
+LayoutManager::TypeLayers LayoutManager::getPreviousLayers() {
+    return this->prv_layers_;
+}
+
+compositor::rect LayoutManager::getAreaSize(const char* area) {
+    return this->area2size_[area];
+}
+
+std::string LayoutManager::getAreaName(TypeAreas areas, const char* role, const char* category) {
+    for (auto itr_area = areas.begin(); itr_area != areas.end(); ++itr_area) {
+        std::string area_name = itr_area->first;
+        TypeRolCtg rol_ctg = itr_area->second;
+
+        if ("role" == rol_ctg.begin()->first) {
+            if (std::string(role) == rol_ctg.begin()->second) {
+                return area_name;
+            }
+        }
+        else if ("category" == rol_ctg.begin()->first) {
+            if (std::string(category) == rol_ctg.begin()->second) {
+                return area_name;
+            }
+        }
+        else {
+            return std::string("none");
+        }
+    }
+    return std::string("none");
+}
+
+
+bool LayoutManager::isLayoutChanged(const char* layer) {
+    return this->is_layout_changed_[layer];
+}
+
+extern const char* kDefaultLayoutDb;
+int LayoutManager::loadLayoutDb() {
+    HMI_DEBUG("wm:lm", "Call");
+
+    // Get afm application installed dir
+    char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
+    HMI_DEBUG("wm:lm", "afm_app_install_dir:%s", afm_app_install_dir);
+
+    std::string file_name;
+    if (!afm_app_install_dir) {
+        HMI_ERROR("wm:lm", "AFM_APP_INSTALL_DIR is not defined");
+    }
+    else {
+        file_name = std::string(afm_app_install_dir) + std::string("/etc/layout.db");
+    }
+
+    // Load layout.db
+    HMI_DEBUG("wm:lm", "file_name:%s", file_name.c_str());
+    json_object* json_obj = json_object_from_file(file_name.c_str());
+    if (nullptr == json_obj) {
+        HMI_ERROR("wm:lm", "Could not open layout.db, so use default role information");
+        json_obj = json_tokener_parse(kDefaultLayoutDb);
+    }
+    HMI_DEBUG("wm:lm", "json_obj dump:%s", json_object_get_string(json_obj));
+
+    // Perse layouts
+    HMI_DEBUG("wm:lm", "Perse layouts");
+    json_object* json_cfg;
+    if (!json_object_object_get_ex(json_obj, "layouts", &json_cfg)) {
+        HMI_ERROR("wm:lm", "Parse Error!!");
+        return -1;
+    }
+
+    int len = json_object_array_length(json_cfg);
+    HMI_DEBUG("wm:lm", "json_cfg len:%d", len);
+    HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg));
+
+    const char* layout;
+    const char* role;
+    const char* category;
+    for (int i=0; i<len; i++) {
+        json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
+
+        layout = jh::getStringFromJson(json_tmp, "name");
+        if (nullptr == layout) {
+            HMI_ERROR("wm:lm", "Parse Error!!");
+            return -1;
+        }
+        HMI_DEBUG("wm:lm", "> layout:%s", layout);
+
+        json_object* json_area_array;
+        if (!json_object_object_get_ex(json_tmp, "areas", &json_area_array)) {
+          HMI_ERROR("wm:lm", "Parse Error!!");
+          return -1;
+        }
+
+        int len_area = json_object_array_length(json_area_array);
+        HMI_DEBUG("wm:lm", "json_area_array len:%d", len_area);
+        HMI_DEBUG("wm:lm", "json_area_array dump:%s", json_object_get_string(json_area_array));
+
+        TypeAreas areas;
+        for (int j=0; j<len_area; j++) {
+            json_object* json_area = json_object_array_get_idx(json_area_array, j);
+
+            const char* area = jh::getStringFromJson(json_area, "name");
+            if (nullptr == area) {
+              HMI_ERROR("wm:lm", "Parse Error!!");
+              return -1;
+            }
+            HMI_DEBUG("wm:lm", ">> area:%s", area);
+
+            TypeRolCtg rol_ctg_name;
+            role = jh::getStringFromJson(json_area, "role");
+            if (nullptr == role) {
+                category = jh::getStringFromJson(json_area, "category");
+                if (nullptr == category) {
+                  HMI_ERROR("wm:lm", "Parse Error!!");
+                  return -1;
+                }
+                rol_ctg_name["category"] = std::string(category);
+                HMI_DEBUG("wm:lm", ">>> category:%s", category);
+            }
+            else {
+                rol_ctg_name["role"] = std::string(role);
+                HMI_DEBUG("wm:lm", ">>> role:%s", role);
+            }
+
+            areas[area] = rol_ctg_name;
+        }
+
+        this->layout_define_[layout] = areas;
+    }
+
+    // Check
+    for(auto itr_layout = this->layout_define_.begin();
+      itr_layout != this->layout_define_.end(); ++itr_layout) {
+        for (auto itr_area = itr_layout->second.begin();
+          itr_area != itr_layout->second.end(); ++itr_area) {
+            for (auto itr_role = itr_area->second.begin();
+              itr_role != itr_area->second.end(); ++itr_role) {
+                HMI_DEBUG("wm:lm", "layout:%s, area:%s, rol_ctg:%s, name:%s",
+                          itr_layout->first.c_str(), itr_area->first.c_str(),
+                          itr_role->first.c_str(), itr_role->second.c_str());
+            }
+        }
+    }
+
+    // Perse areas
+    HMI_DEBUG("wm:lm", "Perse areas");
+    if (!json_object_object_get_ex(json_obj, "areas", &json_cfg)) {
+        HMI_ERROR("wm:lm", "Parse Error!!");
+        return -1;
+    }
+
+    len = json_object_array_length(json_cfg);
+    HMI_DEBUG("wm:lm", "json_cfg len:%d", len);
+    HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg));
+
+    const char* area;
+    for (int i=0; i<len; i++) {
+        json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
+        HMI_DEBUG("wm:lm", "> json_tmp dump:%s", json_object_get_string(json_tmp));
+
+        area = jh::getStringFromJson(json_tmp, "name");
+        if (nullptr == area) {
+            HMI_ERROR("wm:lm", "Parse Error!!");
+            return -1;
+        }
+        HMI_DEBUG("wm:lm", "> area:%s", area);
+
+        json_object* json_rect;
+        if (!json_object_object_get_ex(json_tmp, "rect", &json_rect)) {
+          HMI_ERROR("wm:lm", "Parse Error!!");
+          return -1;
+        }
+        HMI_DEBUG("wm:lm", "> json_rect dump:%s", json_object_get_string(json_rect));
+
+        compositor::rect area_size;
+        area_size.x = jh::getIntFromJson(json_rect, "x");
+        area_size.y = jh::getIntFromJson(json_rect, "y");
+        area_size.w = jh::getIntFromJson(json_rect, "w");
+        area_size.h = jh::getIntFromJson(json_rect, "h");
+
+        this->area2size_[area] = area_size;
+    }
+
+    // Check
+    for(auto itr = this->area2size_.begin();
+      itr != this->area2size_.end(); ++itr) {
+        HMI_DEBUG("wm:lm", "area:%s x:%d y:%d w:%d h:%d",
+                  itr->first.c_str(), itr->second.x, itr->second.y,
+                  itr->second.w, itr->second.h);
+    }
+
+    // Release json_object
+    json_object_put(json_obj);
+
+    return 0;
+}
+
+const char* kDefaultLayoutDb = "{ \
+    \"layouts\": [ \
+        { \
+            \"name\": \"pu\", \
+            \"layer\": \"on_screen\", \
+            \"areas\": [ \
+                { \
+                    \"name\": \"pop_up\", \
+                    \"role\": \"incomming_call\" \
+                } \
+            ] \
+        }, \
+        { \
+            \"name\": \"sa\", \
+            \"layer\": \"on_screen\", \
+            \"areas\": [ \
+                { \
+                    \"name\": \"system_alert\", \
+                    \"role\": \"system_alert\" \
+                } \
+            ] \
+        }, \
+        { \
+            \"name\": \"m1\", \
+            \"layer\": \"apps\", \
+            \"areas\": [ \
+                { \
+                    \"name\": \"normal\", \
+                    \"role\": \"map\" \
+                } \
+            ] \
+        }, \
+        { \
+            \"name\": \"m2\", \
+            \"layer\": \"apps\", \
+            \"areas\": [ \
+                { \
+                    \"name\": \"split.main\", \
+                    \"role\": \"map\" \
+                }, \
+                { \
+                    \"name\": \"split.sub\", \
+                    \"category\": \"hvac\" \
+                } \
+            ] \
+        }, \
+        { \
+            \"name\": \"mf\", \
+            \"layer\": \"apps\", \
+            \"areas\": [ \
+                { \
+                    \"name\": \"full\", \
+                    \"role\": \"map\" \
+                } \
+            ] \
+        }, \
+        { \
+            \"name\": \"s1\", \
+            \"layer\": \"apps\", \
+            \"areas\": [ \
+                { \
+                    \"name\": \"normal\", \
+                    \"category\": \"splitable\" \
+                } \
+            ] \
+        }, \
+        { \
+            \"name\": \"s2\", \
+            \"layer\": \"apps\", \
+            \"areas\": [ \
+                { \
+                    \"name\": \"split.main\", \
+                    \"category\": \"splitable\" \
+                }, \
+                { \
+                    \"name\": \"split.sub\", \
+                    \"category\": \"splitable\" \
+                } \
+            ] \
+        }, \
+        { \
+            \"name\": \"g\", \
+            \"layer\": \"apps\", \
+            \"areas\": [ \
+                { \
+                    \"name\": \"normal\", \
+                    \"category\": \"general\" \
+                } \
+            ] \
+        }, \
+        { \
+            \"name\": \"hs\", \
+            \"layer\": \"homescreen\", \
+            \"areas\": [ \
+                { \
+                    \"name\": \"full\", \
+                    \"role\": \"homescreen\" \
+                } \
+            ] \
+        } \
+    ], \
+    \"areas\": [ \
+        { \
+            \"name\": \"normal\", \
+            \"rect\": { \
+                \"x\": 0, \
+                \"y\": 218, \
+                \"w\": 1080, \
+                \"h\": 1488 \
+            } \
+        }, \
+        { \
+            \"name\": \"split.main\", \
+            \"rect\": { \
+                \"x\": 0, \
+                \"y\": 218, \
+                \"w\": 1080, \
+                \"h\": 744 \
+            } \
+        }, \
+        { \
+            \"name\": \"split.sub\", \
+            \"rect\": { \
+                \"x\": 0, \
+                \"y\": 962, \
+                \"w\": 1080, \
+                \"h\": 744 \
+            } \
+        }, \
+        { \
+            \"name\": \"full\", \
+            \"rect\": { \
+                \"x\": 0, \
+                \"y\": 0, \
+                \"w\": 1080, \
+                \"h\": 1920 \
+            } \
+        }, \
+        { \
+            \"name\": \"pop_up\", \
+            \"rect\": { \
+                \"x\": 0, \
+                \"y\": 640, \
+                \"w\": 1080, \
+                \"h\": 640 \
+            } \
+        }, \
+        { \
+            \"name\": \"system_alert\", \
+            \"rect\": { \
+                \"x\": 0, \
+                \"y\": 640, \
+                \"w\": 1080, \
+                \"h\": 640 \
+            } \
+        } \
+    ] \
+}";
diff --git a/src/layout_manager/layout.hpp b/src/layout_manager/layout.hpp
new file mode 100644 (file)
index 0000000..bfa4a6c
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TMCAGLWM_LAYOUT_HPP
+#define TMCAGLWM_LAYOUT_HPP
+
+#include <cstdint>
+#include <string>
+#include <map>
+#include "result.hpp"
+#include "wayland_ivi_wm.hpp"
+
+namespace wm {
+
+struct LayoutState {
+   int main{-1};
+   int sub{-1};
+
+   bool operator==(const LayoutState &b) const {
+      return main == b.main && sub == b.sub;
+   }
+
+   bool operator!=(const LayoutState &b) const {
+      return !(*this == b);
+   }
+};
+
+}  // namespace wm
+
+class LayoutManager {
+public:
+    explicit LayoutManager();
+    ~LayoutManager() = default;
+
+    typedef std::unordered_map<std::string, std::string> TypeRolCtg;
+    typedef std::unordered_map<std::string, TypeRolCtg>  TypeAreas;
+    typedef std::unordered_map<std::string, TypeAreas>   TypeLayouts;
+    typedef std::unordered_map<std::string, TypeLayouts> TypeLayers;
+
+    int initialize();
+    bool updateLayout(json_object* obj, const char* new_role, const char* new_area);
+    TypeLayers getCurrentLayers();
+    TypeLayers getPreviousLayers();
+    compositor::rect getAreaSize(const char* area);
+    bool isLayoutChanged(const char* layer);
+
+    void updateArea(const char* layer, const char* role, const char* area);
+
+private:
+    // Disable copy and move
+    LayoutManager(LayoutManager const &) = delete;
+    LayoutManager &operator=(LayoutManager const &) = delete;
+    LayoutManager(LayoutManager &&) = delete;
+    LayoutManager &operator=(LayoutManager &&) = delete;
+
+    TypeLayouts layout_define_;
+    std::unordered_map<std::string, compositor::rect> area2size_;
+
+    TypeLayers  crr_layers_, prv_layers_;
+    TypeLayers  prv_layers_car_stop_;
+
+    std::unordered_map<std::string, bool> is_layout_changed_;
+
+    std::string getAreaName(TypeAreas area, const char* role, const char* category);
+    int loadLayoutDb();
+    std::string role2App(std::string role, void* ptr);
+};
+
+
+
+#endif  // TMCAGLWM_LAYOUT_HPP
diff --git a/src/low_can_client.cpp b/src/low_can_client.cpp
new file mode 100644 (file)
index 0000000..23a39e2
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2018 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include "json_helper.hpp"
+#include "low_can_client.hpp"
+#include "hmi-debug.h"
+
+extern "C" {
+#include <afb/afb-binding.h>
+}
+
+
+namespace wm {
+
+LowCanClient::LowCanClient() :
+  vehicle_speed_(0),
+  trans_gear_pos_(0),
+  park_brake_status_(TRUE),
+  headlamp_status_(FALSE),
+  prv_car_state_("car_stop"),
+  crr_car_state_("car_stop"),
+  prv_lamp_state_("lamp_off"),
+  crr_lamp_state_("lamp_off"),
+  is_changed_car_state_(false),
+  is_changed_lamp_state_(false)
+{
+    HMI_DEBUG("wm:lcc", "Call");
+}
+
+void LowCanClient::initialize() {
+    HMI_DEBUG("wm:lcc", "Call");
+
+    int ret;
+
+    // Require API "low-can"
+    ret = afb_daemon_require_api_v2("low-can", 1);
+    if (0 > ret) {
+        HMI_INFO("wm:lcc", "Requirement API \"low-can\" failed");
+        return;
+    }
+
+    // Subscribe low-level-can
+    // low-can subscribe { "event": "vehicle.speed" }
+    // low-can subscribe { "event": "transmission_gear_position" }
+    // low-can subscribe { "event": "headlamp_status" }
+    // low-can subscribe { "event": "parking_brake_status" }
+    for (int i=0; i<this->kNumEvent_; i++) {
+        json_object *json_obj = json_object_new_object();
+        json_object_object_add(json_obj, "event", json_object_new_string(this->kEventName_[i]));
+        HMI_DEBUG("wm:lcc", "subscribe message:%s", json_object_get_string(json_obj));
+
+        json_object *json_result = json_object_new_object();
+        ret = afb_service_call_sync("low-can", "subscribe", json_obj, &json_result);
+        if (0 > ret) {
+            HMI_INFO("wm:lcc", "Could not subscribe to \"low-can\" :%d", ret);
+            return;
+        }
+        HMI_DEBUG("wm:lcc", "subscribe result:%s", json_object_get_string(json_result));
+    }
+
+    return;
+}
+
+void LowCanClient::analyzeCanSignal(struct json_object *object) {
+    HMI_DEBUG("wm:lcc", "object:%s", json_object_get_string(object));
+
+    const char* name = jh::getStringFromJson(object, "name");
+    HMI_DEBUG("wm:lcc", "CAN signal name:%s", name);
+
+    if (strstr(name, "vehicle.speed")) {
+        HMI_DEBUG("wm:lcc", "Receive vehicle speed");
+        // Update vehicle speed
+        int speed = jh::getIntFromJson(object, "value");
+        if (this->vehicle_speed_ != speed) {
+            this->vehicle_speed_ = speed;
+            HMI_DEBUG("wm:lcc", "Update vehicle speed:%d", this->vehicle_speed_);
+        }
+    }
+    else if (strstr(name, "transmission_gear_position")) {
+        HMI_DEBUG("wm:lcc", "Receive transmission gear position");
+        // Update transmission gear position
+        int gear_pos = jh::getIntFromJson(object, "value");
+        if (this->trans_gear_pos_ != gear_pos) {
+            this->trans_gear_pos_ = gear_pos;
+            HMI_DEBUG("wm:lcc", "Update transmission gear position:%d", this->trans_gear_pos_);
+        }
+    }
+    else if (strstr(name, "parking_brake_status")) {
+        HMI_DEBUG("wm:lcc", "Receive parking brake status");
+        // Update parking gear status
+        json_bool park_brake = jh::getBoolFromJson(object, "value");
+        if (this->park_brake_status_ != park_brake) {
+            this->park_brake_status_ = park_brake;
+            HMI_DEBUG("wm:lcc", "Update parking brake status:%d", this->park_brake_status_);
+        }
+    }
+    else if (strstr(name, "headlamp_status")) {
+        HMI_DEBUG("wm:lcc", "Receive headlamp status");
+        // Update headlamp status
+        json_bool headlamp = jh::getBoolFromJson(object, "value");
+        if (this->headlamp_status_ != headlamp) {
+            this->headlamp_status_ = headlamp;
+            HMI_DEBUG("wm:lcc", "Update headlamp status:%d", this->headlamp_status_);
+        }
+    }
+
+    // Update car state
+    if ((0 == this->vehicle_speed_) || (true == this->park_brake_status_)) {
+        this->crr_car_state_ = "car_stop";
+    }
+    else {
+        this->crr_car_state_ = "car_run";
+    }
+    HMI_DEBUG("wm:lcc", "Current car state:%s", this->crr_car_state_.c_str());
+
+    // Update lamp state
+    if (true == this->headlamp_status_) {
+        this->crr_lamp_state_ = "lamp_on";
+    }
+    else {
+        this->crr_lamp_state_ = "lamp_off";
+    }
+    HMI_DEBUG("wm:lcc", "Current lamp state:%s", this->crr_lamp_state_.c_str());
+
+    // If car state is changed,
+    // backup current state for previous state and set flag
+    if (this->prv_car_state_ != this->crr_car_state_) {
+        HMI_DEBUG("wm:lcc", "Car state is changed: %s -> %s",
+                  this->prv_car_state_.c_str(), this->crr_car_state_.c_str());
+        this->prv_car_state_ = this->crr_car_state_;
+        this->is_changed_car_state_ = true;
+    }
+
+    // If lamp state is changed,
+    // backup current state for previous state and set flag
+    if (this->prv_lamp_state_ != this->crr_lamp_state_) {
+        HMI_DEBUG("wm:lcc", "Lamp state is changed: %s -> %s",
+                  this->prv_lamp_state_.c_str(), this->crr_lamp_state_.c_str());
+        this->prv_lamp_state_ = this->crr_lamp_state_;
+        this->is_changed_lamp_state_ = true;
+    }
+}
+
+bool LowCanClient::isChangedCarState() {
+    HMI_DEBUG("wm:lcc", "Call");
+
+    // Return changed flag
+    return this->is_changed_car_state_;
+}
+
+bool LowCanClient::isChangedLampState() {
+    HMI_DEBUG("wm:lcc", "Call");
+
+    // Return changed flag
+    return this->is_changed_lamp_state_;
+}
+
+const char* LowCanClient::getCurrentCarState() {
+    HMI_DEBUG("wm:lcc", "Call");
+
+    // Clear changed flag
+    this->is_changed_car_state_ = false;
+
+    // Return current car state
+    return this->crr_car_state_.c_str();
+}
+
+const char* LowCanClient::getCurrentLampState() {
+    HMI_DEBUG("wm:lcc", "Call");
+
+    // Clear changed flag
+    this->is_changed_lamp_state_ = false;
+
+    // Return current lamp state
+    return this->crr_lamp_state_.c_str();
+}
+
+
+} // namespace wm
diff --git a/src/low_can_client.hpp b/src/low_can_client.hpp
new file mode 100644 (file)
index 0000000..5119c23
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TMCAGLWM_LOW_CAN_CLIENT_HPP
+#define TMCAGLWM_LOW_CAN_CLIENT_HPP
+
+
+#include <vector>
+#include <json-c/json.h>
+
+
+namespace wm {
+
+class LowCanClient {
+
+public:
+    explicit LowCanClient();
+    ~LowCanClient() = default;
+
+    void initialize();
+    void analyzeCanSignal(struct json_object *object);
+    bool isChangedCarState();
+    bool isChangedLampState();
+    const char* getCurrentCarState();
+    const char* getCurrentLampState();
+
+private:
+    // Disable copy and move
+    LowCanClient(LowCanClient const &) = delete;
+    LowCanClient &operator=(LowCanClient const &) = delete;
+    LowCanClient(LowCanClient &&) = delete;
+    LowCanClient &operator=(LowCanClient &&) = delete;
+
+    const int kNumEvent_ = 4;
+    const std::vector<const char*> kEventName_{
+        "vehicle.speed",
+        "transmission_gear_position",
+        "headlamp_status",
+        "parking_brake_status"
+    };
+
+    int vehicle_speed_;
+    int trans_gear_pos_;
+    json_bool park_brake_status_;
+    json_bool headlamp_status_;
+
+    std::string prv_car_state_;
+    std::string crr_car_state_;
+    std::string prv_lamp_state_;
+    std::string crr_lamp_state_;
+
+    bool is_changed_car_state_;
+    bool is_changed_lamp_state_;
+};
+
+} // namespace wm
+
+
+#endif  // TMCAGLWM_LOW_CAN_CLIENT_HPP
index 2f813a3..067a006 100644 (file)
@@ -24,6 +24,7 @@
 #include "json_helper.hpp"
 #include "util.hpp"
 #include "wayland_ivi_wm.hpp"
+#include "low_can_client.hpp"
 
 extern "C" {
 #include <afb/afb-binding.h>
@@ -39,9 +40,10 @@ typedef struct wmClientCtxt{
 
 struct afb_instance {
    std::unique_ptr<wl::display> display;
+   wm::LowCanClient lcc_;
    wm::App app;
 
-   afb_instance() : display{new wl::display}, app{this->display.get()} {}
+   afb_instance() : display{new wl::display}, lcc_{}, app{this->display.get()} {}
 
    int init();
 };
@@ -50,6 +52,10 @@ struct afb_instance *g_afb_instance;
 std::mutex binding_m;
 
 int afb_instance::init() {
+   // Initialize LowCanClient class
+   this->lcc_.initialize();
+
+   // Initialize App class
    return this->app.init();
 }
 
@@ -298,8 +304,14 @@ void windowmanager_activatesurface(afb_req req) noexcept {
        return;
    }
 
-   g_afb_instance->app.api_activate_surface(a_drawing_name, a_drawing_area,
-      [&req](const char* errmsg){
+   const char* a_role = afb_req_value(req, "role");
+   if(!a_role){
+       a_role = "";
+   }
+
+   g_afb_instance->app.allocateWindowResource("activate", a_drawing_name,
+                                              a_drawing_area, a_role,
+                                              [&req](const char* errmsg){
       if (errmsg != nullptr) {
          HMI_ERROR("wm", errmsg);
          afb_req_fail(req, "failed", errmsg);
@@ -332,8 +344,14 @@ void windowmanager_deactivatesurface(afb_req req) noexcept {
        return;
    }
 
-   g_afb_instance->app.api_deactivate_surface(a_drawing_name,
-      [&req](const char* errmsg){
+   const char* a_role = afb_req_value(req, "role");
+   if(!a_role){
+       a_role = "";
+   }
+
+   g_afb_instance->app.allocateWindowResource("deactivate", a_drawing_name,
+                                              nullptr, a_role,
+                                              [&req](const char* errmsg){
       if (errmsg != nullptr) {
          HMI_ERROR("wm", errmsg);
          afb_req_fail(req, "failed", errmsg);
@@ -452,6 +470,12 @@ void windowmanager_wm_subscribe(afb_req req) noexcept {
       return;
    }
    int event_type = json_object_get_int(j);
+   if ((wm::App::Event_Val_Min > event_type)
+       || (wm::App::Event_Val_Max < event_type)) {
+      afb_req_fail(req, "failed", "Invalid EventType");
+      return;
+   }
+
    const char *event_name = g_afb_instance->app.kListEventName[event_type];
    struct afb_event event = g_afb_instance->app.map_afb_event[event_name];
    int ret = afb_req_subscribe(req, event);
@@ -635,5 +659,48 @@ const struct afb_verb_v2 windowmanager_verbs[] = {
    {}
 };
 
+void on_event(const char *event, struct json_object *object){
+    HMI_DEBUG("wm", "event:%s", event);
+
+    // If receive low can signal
+    if (strstr(event, "low-can")) {
+        // Analyze low can signal
+        g_afb_instance->lcc_.analyzeCanSignal(object);
+
+        if (g_afb_instance->lcc_.isChangedCarState()) {
+            // If car state is changed
+            HMI_DEBUG("wm", "Car state is changed");
+
+            // Get car state
+            const char* car_state = g_afb_instance->lcc_.getCurrentCarState();
+
+            // Allocate window resource
+            g_afb_instance->app.allocateWindowResource(car_state, nullptr,
+                                                       nullptr, nullptr,
+                                                       [](const char* errmsg){
+                if (errmsg != nullptr) {
+                    HMI_ERROR("wm", errmsg);
+                }
+            });
+        }
+        else if (g_afb_instance->lcc_.isChangedLampState()) {
+            // If lamp state is changed
+            HMI_DEBUG("wm", "Lamp state is changed");
+
+            // Get lamp state
+            const char* lamp_state = g_afb_instance->lcc_.getCurrentLampState();
+
+            // Allocate window resource
+            g_afb_instance->app.allocateWindowResource(lamp_state, nullptr,
+                                                       nullptr, nullptr,
+                                                       [](const char* errmsg){
+                if (errmsg != nullptr) {
+                    HMI_ERROR("wm", errmsg);
+                }
+            });
+        }
+    }
+}
+
 extern "C" const struct afb_binding_v2 afbBindingV2 = {
-   "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, nullptr, 0};
+   "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, on_event, 0};
diff --git a/src/policy_manager/CMakeLists.txt b/src/policy_manager/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ca31e5f
--- /dev/null
@@ -0,0 +1,65 @@
+#
+# Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include(FindPkgConfig)
+
+# We do not want a prefix for our module
+set(CMAKE_SHARED_MODULE_PREFIX "")
+
+set(TARGETS_PM lib${PLUGIN_PM})
+
+# Set use STM name
+set(USE_STM_NAME zipc)
+
+add_library(${TARGETS_PM} MODULE
+   policy_manager.cpp
+   policy_manager.hpp
+   ${USE_STM_NAME}/dummy_stm.c
+)
+
+target_include_directories(${TARGETS_PM}
+    PRIVATE
+        ../../include
+        ../
+        ./
+        ./${USE_STM_NAME}
+)
+
+target_compile_definitions(${TARGETS_PM}
+    PRIVATE
+        _GNU_SOURCE
+)
+
+target_compile_options(${TARGETS_PM}
+    PRIVATE
+        -Wall -Wextra -Wno-unused-parameter -Wno-comment)
+
+set_target_properties(${TARGETS_PM}
+    PROPERTIES
+        CXX_EXTENSIONS OFF
+        CXX_STANDARD 14
+        CXX_STANDARD_REQUIRED ON
+
+        C_EXTENSIONS OFF
+        C_STANDARD 99
+        C_STANDARD_REQUIRED ON
+)
+
+install(
+   TARGETS ${TARGET_PM}
+   DESTINATION ${CMAKE_INSTALL_LIBDIR}
+   COMPONENT "runtime"
+)
diff --git a/src/policy_manager/db/role.db b/src/policy_manager/db/role.db
new file mode 100644 (file)
index 0000000..2807fde
--- /dev/null
@@ -0,0 +1,44 @@
+{
+    "roles":[
+    {
+        "category": "homescreen",
+        "role": "homescreen",
+        "area": "full",
+    },
+    {
+        "category": "map",
+        "role": "map",
+        "area": "full | normal | split.main",
+    },
+    {
+        "category": "general",
+        "role": "poi | music | video | browser | sdl | settings | mixer | radio | hvac | dashboard | debug",
+        "area": "normal",
+    },
+    {
+        "category": "phone",
+        "role": "phone",
+        "area": "normal",
+    },
+    {
+        "category": "splitable",
+        "role": "splitable1 | splitable2",
+        "area": "normal | split.main | split.sub",
+    },
+    {
+        "category": "popup",
+        "role": "popup",
+        "area": "on_screen",
+    },
+    {
+        "category": "system_alert",
+        "role": "system_alert",
+        "area": "on_screen",
+    },
+    {
+        "category": "tbt",
+        "role": "tbt",
+        "area": "hud",
+    }
+    ]
+}
\ No newline at end of file
diff --git a/src/policy_manager/policy_manager.cpp b/src/policy_manager/policy_manager.cpp
new file mode 100644 (file)
index 0000000..61d1d7c
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * Copyright (c) 2018 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <fstream>
+#include <sstream>
+#include <istream>
+#include <json-c/json.h>
+#include "policy_manager.hpp"
+#include "dummy_stm.h"
+#include "hmi-debug.h"
+
+
+namespace {
+
+static const char* kEventName[] = {
+    "activate",
+    "deactivate",
+    "car_stop",
+    "car_run",
+    "timer_expired",
+    "lamp_off",
+    "lamp_on"
+};
+
+static const int kEventNo[] = {
+    STM_EVT_NO_ACTIVATE,
+    STM_EVT_NO_DEACTIVATE,
+    STM_EVT_NO_CAR_STOP,
+    STM_EVT_NO_CAR_RUN,
+    STM_EVT_NO_TIMER_EXPIRED,
+    STM_EVT_NO_LAMP_OFF,
+    STM_EVT_NO_LAMP_ON
+};
+
+static const char* kCategoryName[] = {
+    "homescreen",
+    "map",
+    "general",
+    "splitable",
+    "popup",
+    "system_alert"
+};
+
+static const int kCategoryNo[] = {
+    STM_CTG_NO_HOMESCREEN,
+    STM_CTG_NO_MAP,
+    STM_CTG_NO_GENERAL,
+    STM_CTG_NO_SPLITABLE,
+    STM_CTG_NO_POPUP,
+    STM_CTG_NO_SYSTEM_ALERT
+};
+
+static const char* kAreaName[] = {
+    "full",
+    "normal",
+    "split.main",
+    "split.sub",
+    "onscreen"
+};
+
+static const int kAreaNo[] = {
+    STM_ARA_NO_FULL,
+    STM_ARA_NO_NORMAL,
+    STM_ARA_NO_SPLIT_MAIN,
+    STM_ARA_NO_SPLIT_SUB,
+    STM_ARA_NO_ON_SCREEN
+};
+
+// String for state
+const char* gStmCarStateNo2Name[] = {
+    "car_stop",
+    "car_run"
+};
+
+const char* gStmLampStateNo2Name[] = {
+    "lamp_off",
+    "lamp_on"
+};
+
+const char* gStmLayoutNo2Name[] = {
+    "none",
+    "pu",
+    "sa",
+    "m1",
+    "m2",
+    "mf",
+    "s1",
+    "s2",
+    "g",
+    "hs",
+};
+
+} // namespace
+
+PolicyManager::PolicyManager() :
+  eventname2no_(),
+  categoryname2no_(),
+  areaname2no_(),
+  role2category_(),
+  category2role_(),
+  role2defaultarea_(),
+  current_state_()
+{
+    HMI_DEBUG("wm:pm", "Call");
+}
+
+int PolicyManager::initialize() {
+    HMI_DEBUG("wm:pm", "Call");
+
+    int ret = 0;
+
+    // Create convert map
+    for (unsigned int i=0; i<(sizeof(kEventNo)/sizeof(int)); i++) {
+        HMI_DEBUG("wm:pm", "event name:%s no:%d", kEventName[i], kEventNo[i]);
+        this->eventname2no_[kEventName[i]] = kEventNo[i];
+    }
+
+    for (unsigned int i=0; i<(sizeof(kCategoryNo)/sizeof(int)); i++) {
+        HMI_DEBUG("wm:pm", "category name:%s no:%d", kCategoryName[i], kCategoryNo[i]);
+        this->categoryname2no_[kCategoryName[i]] = kCategoryNo[i];
+    }
+
+    for (unsigned int i=0; i<(sizeof(kAreaNo)/sizeof(int)); i++) {
+        HMI_DEBUG("wm:pm", "area name:%s no:%d", kAreaName[i], kAreaNo[i]);
+        this->areaname2no_[kAreaName[i]] = kAreaNo[i];
+    }
+
+    // Load role.db
+    ret = loadRoleDb();
+    if (0 > ret) {
+        HMI_ERROR("wm:pm", "Load role.db Error!!");
+        return ret;
+    }
+
+    // TODO:
+    // Initialize StateTransitioner
+    // stmInitialize();
+
+    return ret;
+}
+
+int PolicyManager::checkPolicy(json_object* json_in, json_object** json_out) {
+    HMI_DEBUG("wm:pm", "Call");
+
+    // Check arguments
+    if ((nullptr == json_in) || (nullptr == json_out)) {
+        HMI_ERROR("wm:pm", "Argument is NULL!!");
+        return -1;
+    }
+
+    // Get event from json_object
+    const char* event = getStringFromJson(json_in, "event");
+    int event_no = 0;
+    if (nullptr != event) {
+        // Convert name to number
+        event_no = this->eventname2no_[event];
+        HMI_DEBUG("wm:pm", "event(%s:%d)", event, event_no);
+    }
+
+    // Get role from json_object
+    const char* role = getStringFromJson(json_in, "role");
+    int category_no = 0;
+    if (nullptr != role) {
+        HMI_DEBUG("wm:pm", "role(%s)", role);
+
+        // Convert role to category
+        const char* category = this->role2category_[role].c_str();
+        if (0 == strcmp("", category)) {
+            HMI_ERROR("wm:pm", "Error!!");
+            return -1;
+        }
+        HMI_DEBUG("wm:pm", "category(%s)", category);
+
+        // Convert name to number
+        category_no = categoryname2no_[category];
+        HMI_DEBUG("wm:pm", "role(%s), category(%s:%d)", role, category, category_no);
+    }
+
+    // Get areat from json_object
+    const char* area = getStringFromJson(json_in, "area");
+    int area_no = 0;
+    if (nullptr != area) {
+        // Convert name to number
+        area_no = areaname2no_[area];
+        HMI_DEBUG("wm:pm", "area(%s:%d)", area, area_no);
+    }
+
+    // Transition state
+    HMI_DEBUG("wm:pm", "set event:0x%x", (event_no | category_no | area_no));
+    int ret = stmTransitionState((event_no | category_no | area_no),
+                                       &(this->current_state_));
+    if (0 > ret) {
+        HMI_ERROR("wm:pm", "Error!!");
+        return -1;
+    }
+
+    // Create result
+    // {
+    //     "car": {
+    //         "is_changed": <bool>,
+    //         "state": <const char*>
+    //     },
+    HMI_DEBUG("wm", "@@@@@ car state (is_changed:%d state:%d:%s)",
+              this->current_state_.car.is_changed,
+              this->current_state_.car.state,
+              gStmCarStateNo2Name[this->current_state_.car.state]);
+    this->addStateToJson("car",
+                         this->current_state_.car.is_changed,
+                         gStmCarStateNo2Name[this->current_state_.car.state],
+                         json_out);
+
+    //     "lamp": {
+    //         "is_changed": <bool>,
+    //         "state": <const char*>
+    //     },
+    HMI_DEBUG("wm", "@@@@@ lamp state (is_changed:%d state:%d:%s)",
+              this->current_state_.lamp.is_changed,
+              this->current_state_.lamp.state,
+              gStmLampStateNo2Name[this->current_state_.lamp.state]);
+    this->addStateToJson("lamp",
+                         this->current_state_.lamp.is_changed,
+                         gStmLampStateNo2Name[this->current_state_.lamp.state],
+                         json_out);
+
+    //     "layers": [
+    //         {
+    //             "on_screen": {
+    //                 "is_changed": <bool>,
+    //                 "state": <const char*>
+    //             }
+    //         },
+    json_object* json_layer = json_object_new_array();
+    json_object* json_tmp = json_object_new_object();
+    this->addStateToJson("on_screen",
+                         this->current_state_.layer.on_screen.is_changed,
+                         gStmLayoutNo2Name[this->current_state_.layer.on_screen.state],
+                         &json_tmp);
+    json_object_array_add(json_layer, json_tmp);
+
+    //         {
+    //             "apps": {
+    //                 "is_changed": <bool>,
+    //                 "state": <const char*>
+    //             }
+    //         },
+    json_tmp = json_object_new_object();
+    this->addStateToJson("apps",
+                         this->current_state_.layer.apps.is_changed,
+                         gStmLayoutNo2Name[this->current_state_.layer.apps.state],
+                         &json_tmp);
+    json_object_array_add(json_layer, json_tmp);
+
+    //         {
+    //             "homescreen": {
+    //                 "is_changed": <bool>,
+    //                 "state": <const char*>
+    //             }
+    //         },
+    //     ]
+    // }
+    json_tmp = json_object_new_object();
+    this->addStateToJson("homescreen",
+                         this->current_state_.layer.homescreen.is_changed,
+                         gStmLayoutNo2Name[this->current_state_.layer.homescreen.state],
+                         &json_tmp);
+    json_object_array_add(json_layer, json_tmp);
+
+    // Add json array of layer
+    json_object_object_add(*json_out, "layers", json_layer);
+
+    HMI_DEBUG("wm:pm", "json_out.dump:%s", json_object_get_string(*json_out));
+
+    return 0;
+}
+
+std::string PolicyManager::roleToCategory(const char* role) {
+    return this->role2category_[role];
+}
+
+extern const char* kDefaultRoleDb;
+int PolicyManager::loadRoleDb() {
+    HMI_DEBUG("wm:pm", "Call");
+
+    std::string file_name;
+
+    // Get afm application installed dir
+    char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
+    HMI_DEBUG("wm:pm", "afm_app_install_dir:%s", afm_app_install_dir);
+
+    if (!afm_app_install_dir) {
+        HMI_ERROR("wm:pm", "AFM_APP_INSTALL_DIR is not defined");
+    }
+    else {
+        file_name = std::string(afm_app_install_dir) + std::string("/etc/role.db");
+    }
+
+    // Load role.db
+    HMI_DEBUG("wm:pm", "file_name:%s", file_name.c_str());
+    json_object* json_obj = json_object_from_file(file_name.c_str());
+    if (nullptr == json_obj) {
+        HMI_ERROR("wm:pm", "Could not open role.db, so use default role information");
+        json_obj = json_tokener_parse(kDefaultRoleDb);
+    }
+    HMI_DEBUG("wm:pm", "json_obj dump:%s", json_object_get_string(json_obj));
+
+    json_object* json_roles;
+    if (!json_object_object_get_ex(json_obj, "roles", &json_roles)) {
+        HMI_ERROR("wm:pm", "Parse Error!!");
+        return -1;
+    }
+
+    int len = json_object_array_length(json_roles);
+    HMI_DEBUG("wm:pm", "json_cfg len:%d", len);
+    HMI_DEBUG("wm:pm", "json_cfg dump:%s", json_object_get_string(json_roles));
+
+    json_object* json_tmp;
+    const char* category;
+    const char* roles;
+    const char* areas;
+    for (int i=0; i<len; i++) {
+        json_tmp = json_object_array_get_idx(json_roles, i);
+
+        category = this->getStringFromJson(json_tmp, "category");
+        roles =  this->getStringFromJson(json_tmp, "role");
+        areas =  this->getStringFromJson(json_tmp, "area");
+
+        if ((nullptr == category) || (nullptr == roles) || (nullptr == areas)) {
+            HMI_ERROR("wm:pm", "Parse Error!!");
+            return -1;
+        }
+
+        // Parse roles by '|'
+        std::vector<std::string> vct_roles;
+        vct_roles = this->parseString(std::string(roles), '|');
+
+        // Parse areas by '|'
+        std::vector<std::string> vct_areas;
+        vct_areas = this->parseString(std::string(areas), '|');
+
+        // Set role, category, default area
+        for (auto itr = vct_roles.begin(); itr != vct_roles.end(); ++itr) {
+            // Delete space from role and area name
+            std::string role = this->deleteSpace(*itr);
+            std::string area = this->deleteSpace(vct_areas[0]);
+
+            this->role2category_[role] = std::string(category);
+            this->role2defaultarea_[role] = area;
+        }
+
+        this->category2role_[std::string(category)] = std::string(roles);
+    }
+
+    // Check
+    HMI_DEBUG("wm:pm", "Check role2category_");
+    for (auto& x:this->role2category_){
+        HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
+    }
+
+    HMI_DEBUG("wm:pm", "Check role2defaultarea_");
+    for (auto& x:this->role2defaultarea_){
+        HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
+    }
+
+    HMI_DEBUG("wm:pm", "Check category2role_");
+    for (auto& x:this->category2role_){
+        HMI_DEBUG("wm:pm", "key:%s, val:%s", x.first.c_str(), x.second.c_str());
+    }
+
+    return 0;
+}
+
+const char* PolicyManager::getStringFromJson(json_object* obj, const char* key) {
+    if ((nullptr == obj) || (nullptr == key)) {
+        HMI_ERROR("wm:pm", "Argument is nullptr!!!");
+        return nullptr;
+    }
+
+    json_object* tmp;
+    if (!json_object_object_get_ex(obj, key, &tmp)) {
+        HMI_DEBUG("wm:pm", "Not found key \"%s\"", key);
+        return nullptr;
+    }
+
+    return json_object_get_string(tmp);
+}
+
+int PolicyManager::getIntFromJson(json_object* obj, const char* key) {
+    if ((nullptr == obj) || (nullptr == key)) {
+        HMI_ERROR("wm:pm", "Argument is nullptr!!!");
+        return 0;
+    }
+
+    json_object* tmp;
+    if (!json_object_object_get_ex(obj, key, &tmp)) {
+        HMI_DEBUG("wm:pm", "Not found key \"%s\"", key);
+        return 0;
+    }
+
+    return json_object_get_int(tmp);
+}
+
+void PolicyManager::addStateToJson(
+  const char* key, int is_changed, const char* state, json_object** json_out) {
+    if ((nullptr == key) || (nullptr == state) || (nullptr == json_out)) {
+        HMI_ERROR("wm:pm", "Argument is nullptr!!!");
+        return;
+    }
+
+    json_object* json_obj = json_object_new_object();
+    json_object_object_add(json_obj, "is_changed", json_object_new_boolean(is_changed));
+    if (is_changed) {
+        HMI_DEBUG("wm:pm", "%s: state changed (%s)", key, state);
+        json_object_object_add(json_obj, "state", json_object_new_string(state));
+    }
+    json_object_object_add(*json_out, key, json_obj);
+}
+
+std::vector<std::string> PolicyManager::parseString(std::string str, char delimiter) {
+    // Parse string by delimiter
+    std::vector<std::string> vct;
+    std::stringstream ss{str};
+    std::string buf;
+    while (std::getline(ss, buf, delimiter)) {
+      if (!buf.empty()) {
+        vct.push_back(buf);
+      }
+    }
+    return vct;
+}
+
+std::string PolicyManager::deleteSpace(std::string str) {
+    std::string ret = str;
+    size_t pos;
+    while ((pos = ret.find_first_of(" ")) != std::string::npos) {
+      ret.erase(pos, 1);
+    }
+    return ret;
+}
+
+const char* kDefaultRoleDb = "{ \
+    \"roles\":[ \
+    { \
+        \"category\": \"homescreen\", \
+        \"role\": \"homescreen\", \
+        \"area\": \"full\", \
+    }, \
+    { \
+        \"category\": \"map\", \
+        \"role\": \"map\", \
+        \"area\": \"full | normal | split.main\", \
+    }, \
+    { \
+        \"category\": \"general\", \
+        \"role\": \"poi | music | video | browser | sdl | settings | mixer | radio | hvac | dashboard | debug\", \
+        \"area\": \"normal\", \
+    }, \
+    { \
+        \"category\": \"phone\", \
+        \"role\": \"phone\", \
+        \"area\": \"normal\", \
+    }, \
+    { \
+        \"category\": \"splitable\", \
+        \"role\": \"splitable1 | splitable2\", \
+        \"area\": \"normal | split.main | split.sub\", \
+    }, \
+    { \
+        \"category\": \"popup\", \
+        \"role\": \"popup\", \
+        \"area\": \"on_screen\", \
+    }, \
+    { \
+        \"category\": \"system_alert\", \
+        \"role\": \"system_alert\", \
+        \"area\": \"on_screen\", \
+    }, \
+    { \
+        \"category\": \"tbt\", \
+        \"role\": \"tbt\", \
+        \"area\": \"hud\", \
+    } \
+    ] \
+}";
diff --git a/src/policy_manager/policy_manager.hpp b/src/policy_manager/policy_manager.hpp
new file mode 100644 (file)
index 0000000..500120c
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TMCAGLWM_POLICY_MANAGER_HPP
+#define TMCAGLWM_POLICY_MANAGER_HPP
+
+
+#include <unordered_map>
+#include <vector>
+
+//namespace stm {
+extern "C" {
+#include "dummy_stm.h"
+}
+//} // namespace stm
+
+class PolicyManager {
+
+public:
+    explicit PolicyManager();
+    ~PolicyManager() = default;
+
+    int initialize();
+    int checkPolicy(json_object* json_in, json_object** json_out);
+    std::string roleToCategory(const char* role);
+private:
+    // Disable copy and move
+    PolicyManager(PolicyManager const &) = delete;
+    PolicyManager &operator=(PolicyManager const &) = delete;
+    PolicyManager(PolicyManager &&) = delete;
+    PolicyManager &operator=(PolicyManager &&) = delete;
+
+    // Convert map
+    std::unordered_map<std::string, int> eventname2no_;
+    std::unordered_map<std::string, int> categoryname2no_;
+    std::unordered_map<std::string, int> areaname2no_;
+
+    std::unordered_map<std::string, std::string> role2category_;
+    std::unordered_map<std::string, std::string> category2role_;
+    std::unordered_map<std::string, std::string> role2defaultarea_;
+
+    stm_state_t current_state_;
+
+    // Load role.db
+    int loadRoleDb();
+
+    const char* getStringFromJson(json_object* obj, const char* key);
+    int getIntFromJson(json_object* obj, const char* key);
+    void addStateToJson(const char* key, int is_changed, const char* state, json_object** json_out);
+    std::vector<std::string> parseString(std::string str, char delimiter);
+    std::string deleteSpace(std::string str);
+};
+
+#endif  // TMCAGLWM_POLICY_MANAGER_HPP
diff --git a/src/policy_manager/zipc/category.db b/src/policy_manager/zipc/category.db
new file mode 100644 (file)
index 0000000..4867260
--- /dev/null
@@ -0,0 +1,32 @@
+{
+    "categories":[
+    {
+        "name": "homescreen",
+        "role": "homescreen"
+    },
+    {
+        "name": "map",
+        "role": "map"
+    },
+    {
+        "name": "general",
+        "role": "poi | music | radio | video | browser | sdl | phone | settings | mixer | hvac | dashboard | fallback"
+    },
+    {
+        "name": "pop_up",
+        "role": "incoming_call"
+    },
+    {
+        "name": "system_alert",
+        "role": "system_alert"
+    },
+    {
+        "name": "tbt",
+        "role": "tbt"
+    },
+    {
+        "name": "splitable",
+        "role": "test_splitable1 | test_splitable2"
+    }
+    ]
+}
diff --git a/src/policy_manager/zipc/dummy_stm.c b/src/policy_manager/zipc/dummy_stm.c
new file mode 100644 (file)
index 0000000..3c9cba2
--- /dev/null
@@ -0,0 +1,212 @@
+
+#include <string.h>
+#include "dummy_stm.h"
+
+stm_state_t g_crr_state = {0};
+stm_state_t g_prv_state = {0};
+int g_prv_apps_state_car_stop = 0;
+
+int stmTransitionState(int event, stm_state_t* state) {
+    int event_no, category_no, area_no;
+    int apps_state, car_state, lamp_state;
+
+    event_no    = event & STM_MSK_EVT_NO;
+    category_no = event & STM_MSK_CTG_NO;
+    area_no     = event & STM_MSK_ARA_NO;
+
+    // Backup previous state
+    g_prv_state = g_crr_state;
+
+    // Get previous state
+    apps_state = g_prv_state.layer.apps.state;
+    car_state  = g_prv_state.car.state;
+    lamp_state = g_prv_state.lamp.state;
+
+    // Clear current state
+    memset(&g_crr_state, 0, sizeof(g_crr_state));
+
+    switch (event_no) {
+    case STM_EVT_NO_ACTIVATE:
+        switch (category_no) {
+        case STM_CTG_NO_HOMESCREEN:
+            // Apps layer
+            g_crr_state.layer.apps.state = gStmLayoutNoNone;
+            g_crr_state.layer.apps.is_changed = STM_TRUE;
+
+            // Homescreen layer
+            g_crr_state.layer.homescreen.state = gStmLayoutNoHs;
+            g_crr_state.layer.homescreen.is_changed = STM_TRUE;
+            break;
+        case STM_CTG_NO_MAP:
+            switch (area_no) {
+            case STM_ARA_NO_FULL:
+                // Apps layer
+                switch (apps_state) {
+                case gStmLayoutNoMf:
+                    // nop
+                    break;
+                default:
+                    g_crr_state.layer.apps.state = gStmLayoutNoMf;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                    break;
+                }
+                break;
+            case STM_ARA_NO_NORMAL:
+                // Apps layer
+                switch (apps_state) {
+                case gStmLayoutNoM1:
+                    // nop
+                    break;
+                case gStmLayoutNoS1:
+                    g_crr_state.layer.apps.state = gStmLayoutNoM2;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                    break;
+                default:
+                    g_crr_state.layer.apps.state = gStmLayoutNoM1;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                }
+                break;
+            case STM_ARA_NO_SPLIT_MAIN:
+                // Apps layer
+                switch (apps_state) {
+                case gStmLayoutNoS1:
+                case gStmLayoutNoS2:
+                    g_crr_state.layer.apps.state = gStmLayoutNoS2;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                    break;
+                default:
+                    // nop
+                    break;
+                }
+                break;
+            }
+            break;
+        case STM_CTG_NO_GENERAL:
+            switch (area_no) {
+            case STM_ARA_NO_NORMAL:
+                // Apps layer
+                switch (apps_state) {
+                case gStmLayoutNoMf:
+                    // nop
+                    break;
+                default:
+                    g_crr_state.layer.apps.state = gStmLayoutNoG;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                    break;
+                }
+                break;
+            default:
+                // nop
+                break;
+            }
+            break;
+        case STM_CTG_NO_SPLITABLE:
+            switch (area_no) {
+            case STM_ARA_NO_NORMAL:
+                // Apps layer
+                switch (apps_state) {
+                case gStmLayoutNoMf:
+                    // nop
+                    break;
+                case gStmLayoutNoS1:
+                    g_crr_state.layer.apps.state = gStmLayoutNoS2;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                    break;
+                default:
+                    g_crr_state.layer.apps.state = gStmLayoutNoS1;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                    break;
+                }
+                break;
+            case STM_ARA_NO_SPLIT_MAIN:
+                // Apps layer
+                switch (apps_state) {
+                case gStmLayoutNoS1:
+                    g_crr_state.layer.apps.state = gStmLayoutNoS2;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                    break;
+                case gStmLayoutNoS2:
+                    g_crr_state.layer.apps.state = gStmLayoutNoS2;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                    break;
+                default:
+                    // nop
+                    break;
+                }
+                break;
+            case STM_ARA_NO_SPLIT_SUB:
+                // Apps layer
+                switch (apps_state) {
+                case gStmLayoutNoM1:
+                    g_crr_state.layer.apps.state = gStmLayoutNoM2;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                    break;
+                case gStmLayoutNoM2:
+                    g_crr_state.layer.apps.state = gStmLayoutNoM2;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                    break;
+                case gStmLayoutNoS1:
+                    g_crr_state.layer.apps.state = gStmLayoutNoS2;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                    break;
+                case gStmLayoutNoS2:
+                    g_crr_state.layer.apps.state = gStmLayoutNoS2;
+                    g_crr_state.layer.apps.is_changed = STM_TRUE;
+                    break;
+                default:
+                    // nop
+                    break;
+                }
+                break;
+            default:
+                // nop
+                break;
+            }
+            break;
+        default:
+          // nop
+          break;
+        }
+        break;
+    case STM_EVT_NO_CAR_STOP:
+        if (gStmCarStateNoStop != car_state) {
+            g_crr_state.layer.apps.state = g_prv_apps_state_car_stop;
+            g_crr_state.layer.apps.is_changed = STM_TRUE;
+
+            g_crr_state.car.state = gStmCarStateNoStop;
+            g_crr_state.car.is_changed = STM_TRUE;
+        }
+        break;
+    case STM_EVT_NO_CAR_RUN:
+        if (gStmCarStateNoRun != car_state) {
+            g_prv_apps_state_car_stop = apps_state;
+            g_crr_state.layer.apps.state = gStmLayoutNoM1;
+            g_crr_state.layer.apps.is_changed = STM_TRUE;
+
+            g_crr_state.car.state = gStmCarStateNoRun;
+            g_crr_state.car.is_changed = STM_TRUE;
+        }
+        break;
+    case STM_EVT_NO_LAMP_OFF:
+        if (gStmLampStateNoOff != lamp_state) {
+            g_crr_state.lamp.state = gStmLampStateNoOff;
+            g_crr_state.lamp.is_changed = STM_TRUE;
+        }
+        break;
+    case STM_EVT_NO_LAMP_ON:
+        if (gStmLampStateNoOn != lamp_state) {
+            g_crr_state.lamp.state = gStmLampStateNoOn;
+            g_crr_state.lamp.is_changed = STM_TRUE;
+        }
+        break;
+    default:
+        // nop
+        break;
+    }
+
+    // Copy current state for return
+    memcpy(state, &g_crr_state, sizeof(g_crr_state));
+
+    return 0;
+}
+
diff --git a/src/policy_manager/zipc/dummy_stm.h b/src/policy_manager/zipc/dummy_stm.h
new file mode 100644 (file)
index 0000000..18af99b
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2018 TOYOTA MOTOR CORPORATION
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TMCAGLWM_DUMMY_STM_HPP
+#define TMCAGLWM_DUMMY_STM_HPP
+
+// TODO: This file should be existed in STM
+
+//
+#define STM_TRUE 1
+#define STM_FALSE 0
+
+// Event number
+#define STM_EVT_NO_ACTIVATE      0x01
+#define STM_EVT_NO_DEACTIVATE    0x02
+#define STM_EVT_NO_CAR_STOP      0x03
+#define STM_EVT_NO_CAR_RUN       0x04
+#define STM_EVT_NO_TIMER_EXPIRED 0x05
+#define STM_EVT_NO_LAMP_OFF      0x06
+#define STM_EVT_NO_LAMP_ON       0x07
+
+// Category number
+#define STM_CTG_NO_HOMESCREEN   0x0100
+#define STM_CTG_NO_MAP          0x0200
+#define STM_CTG_NO_GENERAL      0x0300
+#define STM_CTG_NO_SPLITABLE    0x0400
+#define STM_CTG_NO_POPUP        0x0500
+#define STM_CTG_NO_SYSTEM_ALERT 0x0600
+
+// Area number
+#define STM_ARA_NO_FULL       0x010000
+#define STM_ARA_NO_NORMAL     0x020000
+#define STM_ARA_NO_SPLIT_MAIN 0x030000
+#define STM_ARA_NO_SPLIT_SUB  0x040000
+#define STM_ARA_NO_ON_SCREEN  0x050000
+
+// Mask
+#define STM_MSK_EVT_NO 0x0000FF
+#define STM_MSK_CTG_NO 0x00FF00
+#define STM_MSK_ARA_NO 0xFF0000
+
+// Enum for state
+enum stm_car_state_ {
+    gStmCarStateNoStop = 0,
+    gStmCarStateNoRun
+};
+
+enum stm_lamp_state_ {
+    gStmLampStateNoOff = 0,
+    gStmLampStateNoOn
+};
+
+enum stm_layout_ {
+    gStmLayoutNoNone = 0,
+    gStmLayoutNoPu,
+    gStmLayoutNoSa,
+    gStmLayoutNoM1,
+    gStmLayoutNoM2,
+    gStmLayoutNoMf,
+    gStmLayoutNoS1,
+    gStmLayoutNoS2,
+    gStmLayoutNoG,
+    gStmLayoutNoHs
+};
+
+
+#if 0
+// String for state
+const char* gStmCarStateNo2Name[] {
+    "car_stop",
+    "car_run"
+};
+
+const char* gStmLampStateNo2Name[] {
+    "lamp_off",
+    "lamp_on"
+};
+
+const char* gStmLayoutNo2Name[] {
+    "none",
+    "pu",
+    "sa",
+    "m1",
+    "m2",
+    "mf",
+    "s1",
+    "s2",
+    "g",
+    "hs",
+};
+#endif
+
+typedef struct stm_base_state_ {
+    int is_changed;
+    int state;
+} stm_base_state;
+
+typedef struct stm_layer_state_ {
+    stm_base_state on_screen;
+    stm_base_state apps;
+    stm_base_state homescreen;
+} stm_layer_state;
+
+// Struct for state
+typedef struct {
+    stm_base_state car;
+    stm_base_state lamp;
+    stm_layer_state layer;
+} stm_state_t;
+
+int stmTransitionState(int event_no, stm_state_t* state);
+
+
+#endif  // TMCAGLWM_DUMMY_STM_HPP