Add parser's handler: appwidget 23/34923/8
authorTomasz Iwanek <t.iwanek@samsung.com>
Tue, 3 Feb 2015 10:11:30 +0000 (11:11 +0100)
committerPawel Sikorski <p.sikorski@samsung.com>
Wed, 18 Feb 2015 13:45:52 +0000 (05:45 -0800)
Change-Id: I3d4009960593e319abc9034e5c6e27b34e064e25

src/widget-manifest-parser/CMakeLists.txt
src/widget-manifest-parser/manifest_handler.cc
src/widget-manifest-parser/manifest_handlers/appwidget_handler.cc [new file with mode: 0644]
src/widget-manifest-parser/manifest_handlers/appwidget_handler.h [new file with mode: 0644]

index c5a1b80..22e3c7b 100644 (file)
@@ -4,6 +4,7 @@ SET(SRCS
   application_manifest_constants.cc
   manifest.cc
   manifest_handler.cc
+  manifest_handlers/appwidget_handler.cc
   manifest_handlers/category_handler.cc
   manifest_handlers/ime_handler.cc
   manifest_handlers/metadata_handler.cc
index b0d76d0..eaba407 100644 (file)
 
 #include "widget-manifest-parser/application_manifest_constants.h"
 
-#include "widget-manifest-parser/manifest_handlers/permissions_handler.h"
+#include "widget-manifest-parser/manifest_handlers/appwidget_handler.h"
 #include "widget-manifest-parser/manifest_handlers/category_handler.h"
 #include "widget-manifest-parser/manifest_handlers/ime_handler.h"
 #include "widget-manifest-parser/manifest_handlers/metadata_handler.h"
 #include "widget-manifest-parser/manifest_handlers/navigation_handler.h"
+#include "widget-manifest-parser/manifest_handlers/permissions_handler.h"
 #include "widget-manifest-parser/manifest_handlers/setting_handler.h"
 #include "widget-manifest-parser/manifest_handlers/splash_screen_handler.h"
 #include "widget-manifest-parser/manifest_handlers/tizen_application_handler.h"
 #include "widget-manifest-parser/manifest_handlers/widget_handler.h"
 
-// TODO(t.iwanek): add following handlers
-// #include "widget-manifest-parser/manifest_handlers/tizen_appwidget_handler.h"
-
 namespace common_installer {
 namespace widget_manifest_parser {
 
@@ -112,7 +110,7 @@ ManifestHandlerRegistry::GetInstanceForWGT() {
   handlers.push_back(new MetaDataHandler);
   handlers.push_back(new NavigationHandler);
   handlers.push_back(new SplashScreenHandler);
-
+  handlers.push_back(new AppWidgetHandler);
 
   widget_registry_ = new ManifestHandlerRegistry(handlers);
   return widget_registry_;
diff --git a/src/widget-manifest-parser/manifest_handlers/appwidget_handler.cc b/src/widget-manifest-parser/manifest_handlers/appwidget_handler.cc
new file mode 100644 (file)
index 0000000..732e53d
--- /dev/null
@@ -0,0 +1,675 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE-xwalk file.
+
+#include "widget-manifest-parser/manifest_handlers/appwidget_handler.h"
+
+#include <cstdlib>
+#include <limits>
+#include <regex>
+#include <set>
+
+#include "utils/macros.h"
+#include "utils/values.h"
+#include "widget-manifest-parser/application_manifest_constants.h"
+#include "widget-manifest-parser/manifest_handlers/tizen_application_handler.h"
+
+namespace common_installer {
+namespace widget_manifest_parser {
+
+namespace keys = application_widget_keys;
+
+namespace {
+
+const char kErrMsgInvalidDictionary[] =
+    "Cannot get key value as a dictionary. Key name: ";
+const char kErrMsgInvalidList[] =
+    "Cannot get key value as a list. Key name: ";
+const char kErrMsgNoMandatoryKey[] =
+    "Cannot find mandatory key. Key name: ";
+const char kErrMsgInvalidKeyValue[] =
+    "Invalid key value. Key name: ";
+const char kErrMsgMultipleKeys[] =
+    "Too many keys found. Key name: ";
+const char kErrMsgNoNamespace[] =
+    "Element pointed by key has no namespace specified. Key name: ";
+const char kErrMsgInvalidNamespace[] =
+    "Invalid namespace of element pointed by key. Key name: ";
+const char kErrMsgAppWidgetInfoNotFound[] =
+    "Cannot access app-widget info object.";
+const char kErrMsgApplicationInfoNotFound[] =
+    "Cannot access application info object.";
+const char kErrMsgDuplicatedAppWidgetId[] =
+    "Duplicated value of an id attribute in app-widget element. The value: ";
+const char kErrMsgInvalidAppWidgetIdBeginning[] =
+    "Invalid beginning of an id attribute value in app-widget element."
+    " The value: ";
+const char kErrMsgInvalidAppWidgetIdFormat[] =
+    "Invalid format of an id attribute value in app-widget element."
+    " The value: ";
+const char kErrMsgUpdatePeriodOutOfDomain[] =
+    "Value of an update-period attribute in app-widget element out of domain."
+    " The value: ";
+const char kErrMsgNoLabel[] =
+    "No box-label element in app-widget element.";
+const char kErrMsgInvalidIconSrc[] =
+    "Invalid path in a src attribute of box-icon element. The value: ";
+const char kErrMsgInvalidContentSrc[] =
+    "Invalid path or url in a src attribute of box-content element."
+    " The value: ";
+const char kErrMsgInvalidContentSizePreview[] =
+    "Invalid path in a preview attribute of box-size element. The value: ";
+const char kErrMsgNoMandatoryContentSize1x1[] =
+    "No mandatory box-size element (1x1) in box-content element.";
+const char kErrMsgInvalidContentDropViewSrc[] =
+    "Invalid path or url in a src attribute of pd element. The value: ";
+const char kErrMsgContentDropViewHeightOutOfDomain[] =
+    "Value of a height attribute in box-content element out of domain."
+    " The value: ";
+
+const std::regex kStringRegex("[.][0-9a-zA-Z]+");
+
+// If the error parameter is specified, it is filled with the given message
+// otherwise it does nothing.
+void SetError(const std::string& message,
+    std::string* error) {
+  if (error)
+    *error = message;
+}
+
+// If the error parameter is specified, it is filled with concatenation
+// of message and arg parameters otherwise it does nothing.
+void SetError(const std::string& message,
+    const std::string& arg, std::string* error) {
+  if (error)
+    *error = message + arg;
+}
+
+// Retrieves a mandatory dictionary from specified manifest and specified key.
+// Returns true, if the ditionary is found or false otherwise. If the error
+// parameter is specified, it is also filled with proper message.
+bool GetMandatoryDictionary(const Manifest& manifest, const std::string& key,
+    const utils::DictionaryValue** dict, std::string* error) {
+  assert(dict);
+  if (!manifest.HasPath(key)) {
+    SetError(kErrMsgNoMandatoryKey, key, error);
+    return false;
+  }
+  if (!manifest.GetDictionary(key, dict) || !*dict) {
+    SetError(kErrMsgInvalidDictionary, key, error);
+    return false;
+  }
+  return true;
+}
+
+// Converts given text value to a value of specific type. Returns true
+// if convertion is successful or false otherwise.
+template <typename ValueType>
+bool ConvertValue(const std::string& /*str_value*/, ValueType* /*value*/) {
+  assert(false && "Use one of already defined template specializations"
+                  " or define a new one.");
+  return false;
+}
+
+// Converts given text value to a string value. Returns true
+// if convertion is successful or false otherwise.
+template <>
+bool ConvertValue(const std::string& str_value, std::string* value) {
+  assert(value);
+  *value = str_value;
+  return true;
+}
+
+// Converts given text value to a boolean value. Returns true
+// if convertion is successful or false otherwise.
+template <>
+bool ConvertValue(const std::string& str_value, bool* value) {
+  assert(value);
+  if (str_value == "true") {
+    *value = true;
+    return true;
+  }
+  if (str_value == "false") {
+    *value = false;
+    return true;
+  }
+  return false;
+}
+
+// Converts given text value to an integer value. Returns true
+// if convertion is successful or false otherwise.
+template <>
+bool ConvertValue(const std::string& str_value, int* value) {
+  assert(value);
+  char* end = nullptr;
+  *value = strtol(str_value.c_str(), &end, 10);
+  return end == &*str_value.end();
+}
+
+// Converts given text value to a floating point value. Returns true
+// if convertion is successful or false otherwise.
+template <>
+bool ConvertValue(const std::string& str_value, double* value) {
+  assert(value);
+  char* end = nullptr;
+  *value = strtod(str_value.c_str(), &end);
+  return end == &*str_value.end();
+}
+
+// Retrieves a mandatory value from specified dictionary and specified key.
+// Returns true, if the value is found or false otherwise. If the error
+// parameter is specified, it is also filled with proper message.
+template <typename ValueType>
+bool GetMandatoryValue(const utils::DictionaryValue& dict,
+    const std::string& key, ValueType* value, std::string* error) {
+  assert(value);
+  std::string tmp;
+  if (!dict.GetString(key, &tmp)) {
+    SetError(kErrMsgNoMandatoryKey, key, error);
+    return false;
+  }
+  bool result = ConvertValue(tmp, value);
+  if (!result)
+    SetError(kErrMsgInvalidKeyValue, key, error);
+  return result;
+}
+
+// Retrieves an optional value from specified dictionary and specified key.
+// If the value is found, the function returns true and fills value
+// parameter. If the value is not found, the function returns true and fills
+// value parameter with default value. If an error occurs, it returns false
+// and fills error parameter if it is set.
+template <typename ValueType>
+bool GetOptionalValue(const utils::DictionaryValue& dict,
+    const std::string& key, ValueType default_value, ValueType* value,
+    std::string* error) {
+  assert(value);
+  std::string tmp;
+  if (!dict.GetString(key, &tmp)) {
+    *value = default_value;
+    return true;
+  }
+  bool result = ConvertValue(tmp, value);
+  if (!result)
+    SetError(kErrMsgInvalidKeyValue, key, error);
+  return result;
+}
+
+// Helper function for ParseEach. Do not use directly.
+template <typename ParseSingleType, typename DataContainerType>
+bool ParseEachInternal(const utils::Value& value, const std::string& key,
+    ParseSingleType parse_single, DataContainerType* data_container,
+    std::string* error) {
+  assert(data_container);
+  const utils::DictionaryValue* inner_dict;
+  if (!value.GetAsDictionary(&inner_dict)) {
+    SetError(kErrMsgInvalidDictionary, key, error);
+    return false;
+  }
+  if (!parse_single(*inner_dict, key, data_container, error))
+    return false;
+  return true;
+}
+
+// Parsing helper function calling 'parse_single' for each dictionary contained
+// in 'dict' under a 'key'. This helper function takes two template arguments:
+//  - a function with following prototype:
+//    bool ParseSingleExample(const utils::Value& value, const std::string& key,
+//        DataContainerType* data_container, std::string* error);
+//  - a DataContainerType object where the above function stores data
+template <typename ParseSingleType, typename DataContainerType>
+bool ParseEach(const utils::DictionaryValue& dict, const std::string& key,
+    bool mandatory, ParseSingleType parse_single,
+    DataContainerType* data_container, std::string* error) {
+  assert(data_container);
+
+  const utils::Value* value = nullptr;
+  if (!dict.Get(key, &value) || !value) {
+    if (mandatory) {
+      SetError(kErrMsgNoMandatoryKey, key, error);
+      return false;
+    }
+    return true;
+  }
+
+  if (value->IsType(utils::Value::TYPE_DICTIONARY)) {
+    if (!ParseEachInternal(*value, key, parse_single, data_container, error))
+      return false;
+  } else if (value->IsType(utils::Value::TYPE_LIST)) {
+    const utils::ListValue* list;
+    if (!value->GetAsList(&list)) {
+      SetError(kErrMsgInvalidList, key, error);
+      return false;
+    }
+    for (const utils::Value* value : *list)
+      if (!ParseEachInternal(*value, key, parse_single, data_container, error))
+        return false;
+  }
+
+  return true;
+}
+
+// Verifies whether specified dictionary represents an element in specified
+// namespace. Returns true, if the namespace is set and equal to the specified
+// one or false otherwise. If the error parameter is specified, it is also
+// filled with proper message.
+bool VerifyElementNamespace(const utils::DictionaryValue& dict,
+    const std::string& key, const std::string& desired_namespace_value,
+    std::string* error) {
+  std::string namespace_value;
+  if (!GetMandatoryValue(dict, keys::kNamespaceKey,
+      &namespace_value, nullptr)) {
+    SetError(kErrMsgNoNamespace, key, error);
+    return false;
+  }
+  if (namespace_value != desired_namespace_value) {
+    SetError(kErrMsgInvalidNamespace, key, error);
+    return false;
+  }
+  return true;
+}
+
+// Parses box-label part
+bool ParseLabel(const utils::DictionaryValue& dict,
+    const std::string& key, AppWidget* app_widget, std::string* error) {
+  assert(app_widget);
+
+  if (!VerifyElementNamespace(dict, key, keys::kTizenNamespacePrefix, error))
+    return false;
+
+  std::string lang;
+  if (!GetOptionalValue(dict, keys::kTizenAppWidgetBoxLabelLangKey,
+      std::string(), &lang, error))
+    return false;
+
+  std::string text;
+  if (!GetMandatoryValue(dict, keys::kTizenAppWidgetBoxLabelTextKey,
+      &text, error))
+    return false;
+
+  if (lang.empty()) {
+    // Note: Tizen 2.2 WRT Core Spec does not determine how many times the value
+    // without lang attribute can appear in one app-widget, so overwrite.
+    app_widget->label.default_value = text;
+  } else {
+    // Note: Tizen 2.2 WRT Core Spec does not determine how many times the value
+    // with specific lang attribute can appear in one app-widget, so overwrite.
+    app_widget->label.lang_value_map[lang] = text;
+  }
+
+  return true;
+}
+
+// Parses box-icon part
+bool ParseIcon(const utils::DictionaryValue& dict,
+    const std::string& key, AppWidget* app_widget, std::string* error) {
+  assert(app_widget);
+
+  if (!VerifyElementNamespace(dict, key, keys::kTizenNamespacePrefix, error))
+    return false;
+
+  if (!app_widget->icon_src.empty()) {
+    SetError(kErrMsgMultipleKeys, key, error);
+    return false;
+  }
+  if (!GetMandatoryValue(dict, keys::kTizenAppWidgetBoxIconSrcKey,
+      &app_widget->icon_src, error))
+    return false;
+
+  return true;
+}
+
+// Converts size type from text to enum representation
+bool StringToSizeType(const std::string& str_type,
+    AppWidgetSizeType* enum_type) {
+  assert(enum_type);
+  if (str_type == "1x1") {
+    *enum_type = AppWidgetSizeType::k1x1;
+    return true;
+  }
+  if (str_type == "2x1") {
+    *enum_type = AppWidgetSizeType::k2x1;
+    return true;
+  }
+  if (str_type == "2x2") {
+    *enum_type = AppWidgetSizeType::k2x2;
+    return true;
+  }
+  return false;
+}
+
+// Parses box-size part
+bool ParseContentSizes(const utils::DictionaryValue& dict,
+    const std::string& key, AppWidget* app_widget, std::string* error) {
+  assert(app_widget);
+
+  if (!VerifyElementNamespace(dict, key, keys::kTizenNamespacePrefix, error))
+    return false;
+
+  AppWidgetSize size;
+
+  std::string str_type;
+  if (!GetMandatoryValue(dict, keys::kTizenAppWidgetBoxContentSizeTextKey,
+      &str_type, error))
+    return false;
+
+  AppWidgetSizeType type;
+  if (!StringToSizeType(str_type, &type)) {
+    SetError(kErrMsgInvalidKeyValue,
+        keys::kTizenAppWidgetBoxContentSizeTextKey, error);
+    return false;
+  }
+  size.type = type;
+
+  if (!GetOptionalValue(dict, keys::kTizenAppWidgetBoxContentSizePreviewKey,
+      std::string(), &size.preview, error))
+    return false;
+
+  if (!GetOptionalValue(dict,
+      keys::kTizenAppWidgetBoxContentSizeUseDecorationKey,
+      true, &size.use_decoration, error))
+    return false;
+
+  app_widget->content_size.push_back(size);
+
+  return true;
+}
+
+// Parses pd part
+bool ParseContentDropView(const utils::DictionaryValue& dict,
+    const std::string& key, AppWidget* app_widget, std::string* error) {
+  assert(app_widget);
+
+  if (!VerifyElementNamespace(dict, key, keys::kTizenNamespacePrefix, error))
+    return false;
+
+  if (!app_widget->content_drop_view.empty()) {
+    SetError(kErrMsgMultipleKeys, key, error);
+    return false;
+  }
+
+  AppWidgetDropView drop_view;
+
+  if (!GetMandatoryValue(dict, keys::kTizenAppWidgetBoxContentDropViewSrcKey,
+      &drop_view.src, error))
+    return false;
+
+  if (!GetMandatoryValue(dict,
+      keys::kTizenAppWidgetBoxContentDropViewWidthKey,
+      &drop_view.width, error))
+    return false;
+
+  if (!GetMandatoryValue(dict,
+      keys::kTizenAppWidgetBoxContentDropViewHeightKey,
+      &drop_view.height, error))
+    return false;
+
+  app_widget->content_drop_view.push_back(drop_view);
+
+  return true;
+}
+
+// Parses box-content part
+bool ParseContent(const utils::DictionaryValue& dict,
+    const std::string& key, AppWidget* app_widget, std::string* error) {
+  assert(app_widget);
+
+  if (!VerifyElementNamespace(dict, key, keys::kTizenNamespacePrefix, error))
+    return false;
+
+  if (!app_widget->content_src.empty()) {
+    SetError(kErrMsgMultipleKeys, key, error);
+    return false;
+  }
+  if (!GetMandatoryValue(dict, keys::kTizenAppWidgetBoxContentSrcKey,
+      &app_widget->content_src, error))
+    return false;
+
+  if (!GetOptionalValue(dict, keys::kTizenAppWidgetBoxContentMouseEventKey,
+      false, &app_widget->content_mouse_event, error))
+    return false;
+
+  if (!GetOptionalValue(dict, keys::kTizenAppWidgetBoxContentTouchEffectKey,
+      true, &app_widget->content_touch_effect, error))
+    return false;
+
+  if (!ParseEach(dict, keys::kTizenAppWidgetBoxContentSizeKey,
+      true, ParseContentSizes, app_widget, error))
+    return false;
+
+  if (!ParseEach(dict, keys::kTizenAppWidgetBoxContentDropViewKey,
+      false, ParseContentDropView, app_widget, error))
+    return false;
+
+  return true;
+}
+
+// Parses app-widget part
+bool ParseAppWidget(const utils::DictionaryValue& dict,
+    const std::string& key, AppWidgetVector* app_widgets,
+    std::string* error) {
+  assert(app_widgets);
+
+  if (!VerifyElementNamespace(dict, key, keys::kTizenNamespacePrefix, error))
+    return false;
+
+  AppWidget app_widget;
+
+  if (!GetMandatoryValue(dict, keys::kTizenAppWidgetIdKey,
+      &app_widget.id, error))
+    return false;
+
+  if (!GetMandatoryValue(dict, keys::kTizenAppWidgetPrimaryKey,
+      &app_widget.primary, error))
+    return false;
+
+  double update_period;
+  double no_update_period = std::numeric_limits<double>::min();
+  if (!GetOptionalValue(dict, keys::kTizenAppWidgetUpdatePeriodKey,
+      no_update_period, &update_period, error))
+    return false;
+  if (update_period != no_update_period)
+    app_widget.update_period.push_back(update_period);
+
+  if (!GetOptionalValue(dict, keys::kTizenAppWidgetAutoLaunchKey,
+      false, &app_widget.auto_launch, error))
+    return false;
+
+  if (!ParseEach(dict, keys::kTizenAppWidgetBoxLabelKey,
+      true, ParseLabel, &app_widget, error))
+    return false;
+
+  if (!ParseEach(dict, keys::kTizenAppWidgetBoxIconKey,
+      false, ParseIcon, &app_widget, error))
+    return false;
+
+  if (!ParseEach(dict, keys::kTizenAppWidgetBoxContentKey,
+      true, ParseContent, &app_widget, error))
+    return false;
+
+  app_widgets->push_back(app_widget);
+
+  return true;
+}
+
+// Validates all app-widget ids
+bool ValidateEachId(const AppWidgetVector& app_widgets,
+    const std::string& app_id, std::string* error) {
+  std::set<std::string> unique_values;
+
+  for (const AppWidget& app_widget : app_widgets) {
+    if (!unique_values.insert(app_widget.id).second) {
+      SetError(kErrMsgDuplicatedAppWidgetId, app_widget.id, error);
+      return false;
+    }
+
+    const size_t app_id_len = app_id.length();
+
+    if (app_widget.id.find(app_id) != 0) {
+      SetError(kErrMsgInvalidAppWidgetIdBeginning, app_widget.id, error);
+      return false;
+    }
+
+    if (!std::regex_match(app_widget.id.substr(app_id_len), kStringRegex)) {
+      SetError(kErrMsgInvalidAppWidgetIdFormat, app_widget.id, error);
+      return false;
+    }
+  }
+
+  return true;
+}
+
+// Tests if specified string represents valid remote url
+bool IsValidUrl(const std::string& value) {
+  // TODO(tweglarski): implement me (it's not crucial atm)
+  return true;
+}
+
+// Tests if specified string represents valid path
+bool IsValidPath(const std::string& value) {
+  // TODO(tweglarski): implement me (it's not crucial atm)
+  return true;
+}
+
+// Tests if specified string represents valid path or remote url
+bool IsValidPathOrUrl(const std::string& value) {
+  return IsValidPath(value) || IsValidUrl(value);
+}
+
+// Validates all content sizes in an app-widget
+bool ValidateContentSize(const AppWidgetSizeVector& content_size,
+    std::string* error) {
+  bool mandatory_1x1_found = false;
+
+  for (const AppWidgetSize& size : content_size) {
+    mandatory_1x1_found |= size.type == AppWidgetSizeType::k1x1;
+
+    if (!size.preview.empty() && !IsValidPath(size.preview)) {
+      SetError(kErrMsgInvalidContentSizePreview, size.preview, error);
+      return false;
+    }
+  }
+
+  if (!mandatory_1x1_found) {
+    SetError(kErrMsgNoMandatoryContentSize1x1, error);
+    return false;
+  }
+
+  return true;
+}
+
+}  // namespace
+
+AppWidgetInfo::AppWidgetInfo(const AppWidgetVector& app_widgets)
+    : app_widgets_(app_widgets) {
+}
+
+AppWidgetInfo::~AppWidgetInfo() {
+}
+
+AppWidgetHandler::AppWidgetHandler() {
+}
+
+AppWidgetHandler::~AppWidgetHandler() {
+}
+
+bool AppWidgetHandler::Parse(std::shared_ptr<ApplicationData> application,
+    std::string* error) {
+  const Manifest* manifest = application->GetManifest();
+  assert(manifest);
+
+  const utils::DictionaryValue* dict = nullptr;
+  if (!GetMandatoryDictionary(*manifest, keys::kTizenWidgetKey, &dict, error))
+    return false;
+
+  AppWidgetVector app_widgets;
+
+  if (!ParseEach(*dict, keys::kTizenAppWidgetKey,
+      false, ParseAppWidget, &app_widgets, error))
+    return false;
+
+  std::shared_ptr<AppWidgetInfo> info(new AppWidgetInfo(app_widgets));
+  application->SetManifestData(keys::kTizenAppWidgetFullKey, info);
+
+  return true;
+}
+
+bool AppWidgetHandler::Validate(
+    std::shared_ptr<const ApplicationData> application,
+    std::string* error) const {
+  const AppWidgetInfo* app_widget_info =
+      static_cast<const AppWidgetInfo*>(
+          application->GetManifestData(keys::kTizenAppWidgetFullKey));
+  const TizenApplicationInfo* app_info =
+      static_cast<const TizenApplicationInfo*>(
+          application->GetManifestData(keys::kTizenApplicationKey));
+
+  if (!app_widget_info) {
+    SetError(kErrMsgAppWidgetInfoNotFound, error);
+    return false;
+  }
+  if (!app_info) {
+    SetError(kErrMsgApplicationInfoNotFound, error);
+    return false;
+  }
+
+  const AppWidgetVector& app_widgets = app_widget_info->app_widgets();
+
+  if (!ValidateEachId(app_widgets, app_info->id(), error))
+    return false;
+
+  for (const AppWidget& app_widget : app_widgets) {
+    if (!app_widget.update_period.empty()
+        && app_widget.update_period.front() < 1800) {
+      SetError(kErrMsgUpdatePeriodOutOfDomain,
+          std::to_string(app_widget.update_period.front()), error);
+      return false;
+    }
+
+    if (app_widget.label.default_value.empty()
+        && app_widget.label.lang_value_map.empty()) {
+      SetError(kErrMsgNoLabel, error);
+      return false;
+    }
+
+    if (!app_widget.icon_src.empty()
+        && !IsValidPathOrUrl(app_widget.icon_src)) {
+      SetError(kErrMsgInvalidIconSrc, app_widget.icon_src, error);
+      return false;
+    }
+
+    if (!IsValidPathOrUrl(app_widget.content_src)) {
+      SetError(kErrMsgInvalidContentSrc, app_widget.content_src, error);
+      return false;
+    }
+
+    if (!ValidateContentSize(app_widget.content_size, error))
+      return false;
+
+    if (!app_widget.content_drop_view.empty()) {
+      const AppWidgetDropView& drop_view
+          = app_widget.content_drop_view.front();
+
+      if (!IsValidPathOrUrl(drop_view.src)) {
+        SetError(kErrMsgInvalidContentDropViewSrc, drop_view.src, error);
+        return false;
+      }
+
+      if (drop_view.height < 1 || drop_view.height > 380) {
+        SetError(kErrMsgContentDropViewHeightOutOfDomain,
+            std::to_string(drop_view.height), error);
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+std::vector<std::string> AppWidgetHandler::Keys() const {
+  return std::vector<std::string>(1, keys::kTizenAppWidgetFullKey);
+}
+
+}  // namespace widget_manifest_parser
+}  // namespace common_installer
diff --git a/src/widget-manifest-parser/manifest_handlers/appwidget_handler.h b/src/widget-manifest-parser/manifest_handlers/appwidget_handler.h
new file mode 100644 (file)
index 0000000..f55f35a
--- /dev/null
@@ -0,0 +1,135 @@
+// Copyright (c) 2014 Intel Corporation. All rights reserved.
+// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE-xwalk file.
+
+#ifndef WIDGET_MANIFEST_PARSER_MANIFEST_HANDLERS_APPWIDGET_HANDLER_H_
+#define WIDGET_MANIFEST_PARSER_MANIFEST_HANDLERS_APPWIDGET_HANDLER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "widget-manifest-parser/application_data.h"
+#include "widget-manifest-parser/manifest_handler.h"
+
+namespace common_installer {
+namespace widget_manifest_parser {
+
+typedef std::map<std::string, std::string> AppWidgetLabelLangValueMap;
+
+struct AppWidgetLabel {
+  // may be empty
+  std::string default_value;
+
+  // may be empty if default is set
+  AppWidgetLabelLangValueMap lang_value_map;
+};
+
+enum AppWidgetSizeType {
+  k1x1, k2x1, k2x2
+};
+
+struct AppWidgetSize {
+  // mandatory
+  AppWidgetSizeType type;
+
+  // optional, relative to web app directory
+  std::string preview;
+
+  // optional, default: true
+  bool use_decoration;
+};
+
+typedef std::vector<AppWidgetSize> AppWidgetSizeVector;
+
+struct AppWidgetDropView {
+  // mandatory, relative to web app directory or remote URL
+  std::string src;
+
+  // mandatory
+  int width;
+
+  // mandatory, <1, 380>
+  int height;
+};
+
+typedef std::vector<AppWidgetDropView> AppWidgetDropViewVector;
+
+struct AppWidget {
+  // mandatory, unique, must start with application id and end with label
+  // separated with dot, the label can contain only 0-9, a-z, A-Z
+  std::string id;
+
+  // mandatory, if 2 or more app widgets have the primary attribute set to true,
+  // the default icon and title of the parent web app can be used
+  bool primary;
+
+  // optional(0-1), min: 1800.0, default: no update
+  std::vector<double> update_period;
+
+  // optional, default: false
+  bool auto_launch;
+
+  // box label, multiple(1+)
+  AppWidgetLabel label;
+
+  // box icon, optional(0-1), src, mandatory, relative to web app directory
+  std::string icon_src;
+
+  // box content, mandatory(1) -[
+
+  // mandatory, relative to web app directory or remote URL
+  std::string content_src;
+
+  // optional, default: false
+  bool content_mouse_event;
+
+  // optional, default: true
+  bool content_touch_effect;
+
+  // box size, mandatory(1-3), 1x1 must exist
+  AppWidgetSizeVector content_size;
+
+  // drop view, optional(0-1)
+  AppWidgetDropViewVector content_drop_view;
+
+  // ]- box content
+};
+
+typedef std::vector<AppWidget> AppWidgetVector;
+
+class AppWidgetInfo : public ApplicationData::ManifestData {
+ public:
+  explicit AppWidgetInfo(const AppWidgetVector& app_widgets);
+  virtual ~AppWidgetInfo();
+
+  const AppWidgetVector& app_widgets() const {
+    return app_widgets_;
+  }
+
+ private:
+  // multiple(0+)
+  AppWidgetVector app_widgets_;
+};
+
+class AppWidgetHandler : public ManifestHandler {
+ public:
+  AppWidgetHandler();
+  virtual ~AppWidgetHandler();
+
+  bool Parse(std::shared_ptr<ApplicationData> application,
+             std::string* error) override;
+  bool Validate(std::shared_ptr<const ApplicationData> application,
+                std::string* error) const override;
+  std::vector<std::string> Keys() const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AppWidgetHandler);
+};
+
+}  // namespace widget_manifest_parser
+}  // namespace common_installer
+
+#endif  // WIDGET_MANIFEST_PARSER_MANIFEST_HANDLERS_APPWIDGET_HANDLER_H_