Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / api / notifications / notifications_api.cc
index 56203e1..631dbf4 100644 (file)
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/event_names.h"
-#include "chrome/browser/extensions/event_router.h"
-#include "chrome/browser/extensions/extension_system.h"
 #include "chrome/browser/notifications/desktop_notification_service.h"
 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
 #include "chrome/browser/notifications/notification.h"
+#include "chrome/browser/notifications/notification_conversion_helper.h"
 #include "chrome/browser/notifications/notification_ui_manager.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_version_info.h"
-#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/api/notifications/notification_style.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/event_router.h"
+#include "extensions/common/extension.h"
 #include "extensions/common/features/feature.h"
 #include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/layout.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_rep.h"
 #include "ui/message_center/message_center_style.h"
-#include "ui/message_center/message_center_util.h"
 #include "ui/message_center/notifier_settings.h"
 #include "url/gurl.h"
 
@@ -41,72 +43,16 @@ namespace {
 const char kMissingRequiredPropertiesForCreateNotification[] =
     "Some of the required properties are missing: type, iconUrl, title and "
     "message.";
+const char kUnableToDecodeIconError[] =
+    "Unable to successfully use the provided image.";
 const char kUnexpectedProgressValueForNonProgressType[] =
     "The progress value should not be specified for non-progress notification";
 const char kInvalidProgressValue[] =
     "The progress value should range from 0 to 100";
-
-// Converts an object with width, height, and data in RGBA format into an
-// gfx::Image (in ARGB format).
-bool NotificationBitmapToGfxImage(
-    api::notifications::NotificationBitmap* notification_bitmap,
-    gfx::Image* return_image) {
-  if (!notification_bitmap)
-    return false;
-
-  // Ensure a sane set of dimensions.
-  const int max_width = message_center::kNotificationPreferredImageSize;
-  const int max_height =
-      message_center::kNotificationPreferredImageRatio * max_width;
-  const int BYTES_PER_PIXEL = 4;
-
-  const int width = notification_bitmap->width;
-  const int height = notification_bitmap->height;
-
-  if (width < 0 || height < 0 || width > max_width || height > max_height)
-    return false;
-
-  // Ensure we have rgba data.
-  std::string* rgba_data = notification_bitmap->data.get();
-  if (!rgba_data)
-    return false;
-
-  const size_t rgba_data_length = rgba_data->length();
-  const size_t rgba_area = width * height;
-
-  if (rgba_data_length != rgba_area * BYTES_PER_PIXEL)
-    return false;
-
-  // Now configure the bitmap with the sanitized dimensions.
-  SkBitmap bitmap;
-  bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
-
-  // Allocate the actual backing store.
-  if (!bitmap.allocPixels())
-    return false;
-
-  // Ensure that our bitmap and our data now refer to the same number of pixels.
-  if (rgba_data_length != bitmap.getSafeSize())
-    return false;
-
-  uint32_t* pixels = bitmap.getAddr32(0, 0);
-  const char* c_rgba_data = rgba_data->data();
-
-  for (size_t t = 0; t < rgba_area; ++t) {
-    // |c_rgba_data| is RGBA, pixels is ARGB.
-    size_t rgba_index = t * BYTES_PER_PIXEL;
-    pixels[t] = SkPreMultiplyColor(
-        ((c_rgba_data[rgba_index + 3] & 0xFF) << 24) |
-        ((c_rgba_data[rgba_index + 0] & 0xFF) << 16) |
-        ((c_rgba_data[rgba_index + 1] & 0xFF) << 8) |
-        ((c_rgba_data[rgba_index + 2] & 0xFF) << 0));
-  }
-
-  // TODO(dewittj): Handle HiDPI images.
-  gfx::ImageSkia skia(gfx::ImageSkiaRep(bitmap, 1.0f));
-  *return_image = gfx::Image(skia);
-  return true;
-}
+const char kExtraListItemsProvided[] =
+    "List items provided for notification type != list";
+const char kExtraImageProvided[] =
+    "Image resource provided for notification type != image";
 
 // Given an extension id and another id, returns an id that is unique
 // relative to other extensions.
@@ -127,7 +73,7 @@ std::string StripScopeFromIdentifier(const std::string& extension_id,
 
 class NotificationsApiDelegate : public NotificationDelegate {
  public:
-  NotificationsApiDelegate(ApiFunction* api_function,
+  NotificationsApiDelegate(ChromeAsyncExtensionFunction* api_function,
                            Profile* profile,
                            const std::string& extension_id,
                            const std::string& id)
@@ -135,58 +81,58 @@ class NotificationsApiDelegate : public NotificationDelegate {
         profile_(profile),
         extension_id_(extension_id),
         id_(id),
-        scoped_id_(CreateScopedIdentifier(extension_id, id)),
-        process_id_(-1) {
+        scoped_id_(CreateScopedIdentifier(extension_id, id)) {
     DCHECK(api_function_.get());
-    if (api_function_->render_view_host())
-      process_id_ = api_function->render_view_host()->GetProcess()->GetID();
   }
 
   virtual void Display() OVERRIDE { }
 
-  virtual void Error() OVERRIDE {
-    scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
-    SendEvent(event_names::kOnNotificationError, args.Pass());
-  }
+  virtual void Error() OVERRIDE {}
 
   virtual void Close(bool by_user) OVERRIDE {
+    EventRouter::UserGestureState gesture =
+        by_user ? EventRouter::USER_GESTURE_ENABLED
+                : EventRouter::USER_GESTURE_NOT_ENABLED;
     scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
     args->Append(new base::FundamentalValue(by_user));
-    SendEvent(notifications::OnClosed::kEventName, args.Pass());
+    SendEvent(notifications::OnClosed::kEventName, gesture, args.Pass());
   }
 
   virtual void Click() OVERRIDE {
     scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
-    SendEvent(notifications::OnClicked::kEventName, args.Pass());
+    SendEvent(notifications::OnClicked::kEventName,
+              EventRouter::USER_GESTURE_ENABLED,
+              args.Pass());
   }
 
   virtual bool HasClickedListener() OVERRIDE {
-    return ExtensionSystem::Get(profile_)->event_router()->HasEventListener(
+    return EventRouter::Get(profile_)->HasEventListener(
         notifications::OnClicked::kEventName);
   }
 
   virtual void ButtonClick(int index) OVERRIDE {
     scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
     args->Append(new base::FundamentalValue(index));
-    SendEvent(notifications::OnButtonClicked::kEventName, args.Pass());
+    SendEvent(notifications::OnButtonClicked::kEventName,
+              EventRouter::USER_GESTURE_ENABLED,
+              args.Pass());
   }
 
   virtual std::string id() const OVERRIDE {
     return scoped_id_;
   }
 
-  virtual int process_id() const OVERRIDE {
-    return process_id_;
-  }
-
-  virtual content::RenderViewHost* GetRenderViewHost() const OVERRIDE {
+  virtual content::WebContents* GetWebContents() const OVERRIDE {
     // We're holding a reference to api_function_, so we know it'll be valid
     // until ReleaseRVH is called, and api_function_ (as a
-    // UIThreadExtensionFunction) will zero out its copy of render_view_host
+    // AsyncExtensionFunction) will zero out its copy of render_view_host
     // when the RVH goes away.
     if (!api_function_.get())
       return NULL;
-    return api_function_->render_view_host();
+    content::RenderViewHost* rvh = api_function_->render_view_host();
+    if (!rvh)
+      return NULL;
+    return content::WebContents::FromRenderViewHost(rvh);
   }
 
   virtual void ReleaseRenderViewHost() OVERRIDE {
@@ -196,10 +142,13 @@ class NotificationsApiDelegate : public NotificationDelegate {
  private:
   virtual ~NotificationsApiDelegate() {}
 
-  void SendEvent(const std::string& name, scoped_ptr<base::ListValue> args) {
+  void SendEvent(const std::string& name,
+                 EventRouter::UserGestureState user_gesture,
+                 scoped_ptr<base::ListValue> args) {
     scoped_ptr<Event> event(new Event(name, args.Pass()));
-    ExtensionSystem::Get(profile_)->event_router()->DispatchEventToExtension(
-        extension_id_, event.Pass());
+    event->user_gesture = user_gesture;
+    EventRouter::Get(profile_)->DispatchEventToExtension(extension_id_,
+                                                         event.Pass());
   }
 
   scoped_ptr<base::ListValue> CreateBaseEventArgs() {
@@ -208,12 +157,11 @@ class NotificationsApiDelegate : public NotificationDelegate {
     return args.Pass();
   }
 
-  scoped_refptr<ApiFunction> api_function_;
+  scoped_refptr<ChromeAsyncExtensionFunction> api_function_;
   Profile* profile_;
   const std::string extension_id_;
   const std::string id_;
   const std::string scoped_id_;
-  int process_id_;
 
   DISALLOW_COPY_AND_ASSIGN(NotificationsApiDelegate);
 };
@@ -224,7 +172,7 @@ bool NotificationsApiFunction::IsNotificationsApiAvailable() {
   // We need to check this explicitly rather than letting
   // _permission_features.json enforce it, because we're sharing the
   // chrome.notifications permissions namespace with WebKit notifications.
-  return GetExtension()->is_platform_app() || GetExtension()->is_extension();
+  return extension()->is_platform_app() || extension()->is_extension();
 }
 
 NotificationsApiFunction::NotificationsApiFunction() {
@@ -236,7 +184,7 @@ NotificationsApiFunction::~NotificationsApiFunction() {
 bool NotificationsApiFunction::CreateNotification(
     const std::string& id,
     api::notifications::NotificationOptions* options) {
-  // First, make sure the required fields exist: type, title, message,  icon.
+  // First, make sure the required fields exist: type, title, message, icon.
   // These fields are defined as optional in IDL such that they can be used as
   // optional for notification updates. But for notification creations, they
   // should be present.
@@ -246,80 +194,108 @@ bool NotificationsApiFunction::CreateNotification(
     return false;
   }
 
+  NotificationBitmapSizes bitmap_sizes = GetNotificationBitmapSizes();
+
+  float image_scale =
+      ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactors().back());
+
   // Extract required fields: type, title, message, and icon.
   message_center::NotificationType type =
       MapApiTemplateTypeToType(options->type);
-  const string16 title(UTF8ToUTF16(*options->title));
-  const string16 message(UTF8ToUTF16(*options->message));
+  const base::string16 title(base::UTF8ToUTF16(*options->title));
+  const base::string16 message(base::UTF8ToUTF16(*options->message));
   gfx::Image icon;
 
-  // TODO(dewittj): Return error if this fails.
-  NotificationBitmapToGfxImage(options->icon_bitmap.get(), &icon);
+  if (!NotificationConversionHelper::NotificationBitmapToGfxImage(
+          image_scale,
+          bitmap_sizes.icon_size,
+          options->icon_bitmap.get(),
+          &icon)) {
+    SetError(kUnableToDecodeIconError);
+    return false;
+  }
 
   // Then, handle any optional data that's been provided.
   message_center::RichNotificationData optional_fields;
-  if (message_center::IsRichNotificationEnabled()) {
-    if (options->priority.get())
-      optional_fields.priority = *options->priority;
-
-    if (options->event_time.get())
-      optional_fields.timestamp = base::Time::FromJsTime(*options->event_time);
-
-    if (options->buttons.get()) {
-      // Currently we allow up to 2 buttons.
-      size_t number_of_buttons = options->buttons->size();
-      number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons;
-
-      for (size_t i = 0; i < number_of_buttons; i++) {
-        message_center::ButtonInfo info(
-            UTF8ToUTF16((*options->buttons)[i]->title));
-        NotificationBitmapToGfxImage((*options->buttons)[i]->icon_bitmap.get(),
-                                     &info.icon);
-        optional_fields.buttons.push_back(info);
-      }
+  if (options->app_icon_mask_url.get()) {
+    if (!NotificationConversionHelper::NotificationBitmapToGfxImage(
+            image_scale,
+            bitmap_sizes.app_icon_mask_size,
+            options->app_icon_mask_bitmap.get(),
+            &optional_fields.small_image)) {
+      SetError(kUnableToDecodeIconError);
+      return false;
     }
+  }
 
-    if (options->expanded_message.get()) {
-      optional_fields.expanded_message =
-          UTF8ToUTF16(*options->expanded_message);
+  if (options->priority.get())
+    optional_fields.priority = *options->priority;
+
+  if (options->event_time.get())
+    optional_fields.timestamp = base::Time::FromJsTime(*options->event_time);
+
+  if (options->buttons.get()) {
+    // Currently we allow up to 2 buttons.
+    size_t number_of_buttons = options->buttons->size();
+    number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons;
+
+    for (size_t i = 0; i < number_of_buttons; i++) {
+      message_center::ButtonInfo info(
+          base::UTF8ToUTF16((*options->buttons)[i]->title));
+      NotificationConversionHelper::NotificationBitmapToGfxImage(
+          image_scale,
+          bitmap_sizes.button_icon_size,
+          (*options->buttons)[i]->icon_bitmap.get(),
+          &info.icon);
+      optional_fields.buttons.push_back(info);
     }
+  }
 
-    if (options->context_message)
-      optional_fields.context_message = UTF8ToUTF16(*options->context_message);
+  if (options->context_message) {
+    optional_fields.context_message =
+        base::UTF8ToUTF16(*options->context_message);
+  }
 
-    bool has_image = NotificationBitmapToGfxImage(options->image_bitmap.get(),
-                                                  &optional_fields.image);
-    // We should have an image if and only if the type is an image type.
-    if (has_image != (type == message_center::NOTIFICATION_TYPE_IMAGE))
-      return false;
+  bool has_image = NotificationConversionHelper::NotificationBitmapToGfxImage(
+      image_scale,
+      bitmap_sizes.image_size,
+      options->image_bitmap.get(),
+      &optional_fields.image);
+  // We should have an image if and only if the type is an image type.
+  if (has_image != (type == message_center::NOTIFICATION_TYPE_IMAGE)) {
+    SetError(kExtraImageProvided);
+    return false;
+  }
 
-    // We should have list items if and only if the type is a multiple type.
-    bool has_list_items = options->items.get() && options->items->size() > 0;
-    if (has_list_items != (type == message_center::NOTIFICATION_TYPE_MULTIPLE))
-      return false;
+  // We should have list items if and only if the type is a multiple type.
+  bool has_list_items = options->items.get() && options->items->size() > 0;
+  if (has_list_items != (type == message_center::NOTIFICATION_TYPE_MULTIPLE)) {
+    SetError(kExtraListItemsProvided);
+    return false;
+  }
 
-    if (options->progress.get() != NULL) {
-      // We should have progress if and only if the type is a progress type.
-      if (type != message_center::NOTIFICATION_TYPE_PROGRESS) {
-        SetError(kUnexpectedProgressValueForNonProgressType);
-        return false;
-      }
-      optional_fields.progress = *options->progress;
-      // Progress value should range from 0 to 100.
-      if (optional_fields.progress < 0 || optional_fields.progress > 100) {
-        SetError(kInvalidProgressValue);
-        return false;
-      }
+  if (options->progress.get() != NULL) {
+    // We should have progress if and only if the type is a progress type.
+    if (type != message_center::NOTIFICATION_TYPE_PROGRESS) {
+      SetError(kUnexpectedProgressValueForNonProgressType);
+      return false;
+    }
+    optional_fields.progress = *options->progress;
+    // Progress value should range from 0 to 100.
+    if (optional_fields.progress < 0 || optional_fields.progress > 100) {
+      SetError(kInvalidProgressValue);
+      return false;
     }
+  }
 
-    if (has_list_items) {
-      using api::notifications::NotificationItem;
-      std::vector<linked_ptr<NotificationItem> >::iterator i;
-      for (i = options->items->begin(); i != options->items->end(); ++i) {
-        message_center::NotificationItem item(UTF8ToUTF16(i->get()->title),
-                                              UTF8ToUTF16(i->get()->message));
-        optional_fields.items.push_back(item);
-      }
+  if (has_list_items) {
+    using api::notifications::NotificationItem;
+    std::vector<linked_ptr<NotificationItem> >::iterator i;
+    for (i = options->items->begin(); i != options->items->end(); ++i) {
+      message_center::NotificationItem item(
+          base::UTF8ToUTF16(i->get()->title),
+          base::UTF8ToUTF16(i->get()->message));
+      optional_fields.items.push_back(item);
     }
   }
 
@@ -334,12 +310,12 @@ bool NotificationsApiFunction::CreateNotification(
                             title,
                             message,
                             icon,
-                            WebKit::WebTextDirectionDefault,
+                            blink::WebTextDirectionDefault,
                             message_center::NotifierId(
                                 message_center::NotifierId::APPLICATION,
                                 extension_->id()),
-                            UTF8ToUTF16(extension_->name()),
-                            UTF8ToUTF16(api_delegate->id()),
+                            base::UTF8ToUTF16(extension_->name()),
+                            base::UTF8ToUTF16(api_delegate->id()),
                             optional_fields,
                             api_delegate);
 
@@ -351,89 +327,112 @@ bool NotificationsApiFunction::UpdateNotification(
     const std::string& id,
     api::notifications::NotificationOptions* options,
     Notification* notification) {
+  NotificationBitmapSizes bitmap_sizes = GetNotificationBitmapSizes();
+  float image_scale =
+      ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactors().back());
+
   // Update optional fields if provided.
   if (options->type != api::notifications::TEMPLATE_TYPE_NONE)
     notification->set_type(MapApiTemplateTypeToType(options->type));
   if (options->title)
-    notification->set_title(UTF8ToUTF16(*options->title));
+    notification->set_title(base::UTF8ToUTF16(*options->title));
   if (options->message)
-    notification->set_message(UTF8ToUTF16(*options->message));
+    notification->set_message(base::UTF8ToUTF16(*options->message));
 
   // TODO(dewittj): Return error if this fails.
   if (options->icon_bitmap) {
     gfx::Image icon;
-    NotificationBitmapToGfxImage(options->icon_bitmap.get(), &icon);
+    NotificationConversionHelper::NotificationBitmapToGfxImage(
+        image_scale, bitmap_sizes.icon_size, options->icon_bitmap.get(), &icon);
     notification->set_icon(icon);
   }
 
-  message_center::RichNotificationData optional_fields;
-  if (message_center::IsRichNotificationEnabled()) {
-    if (options->priority)
-      notification->set_priority(*options->priority);
-
-    if (options->event_time)
-      notification->set_timestamp(base::Time::FromJsTime(*options->event_time));
-
-    if (options->buttons) {
-      // Currently we allow up to 2 buttons.
-      size_t number_of_buttons = options->buttons->size();
-      number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons;
-
-      for (size_t i = 0; i < number_of_buttons; i++) {
-        message_center::ButtonInfo info(
-            UTF8ToUTF16((*options->buttons)[i]->title));
-        NotificationBitmapToGfxImage((*options->buttons)[i]->icon_bitmap.get(),
-                                     &info.icon);
-        optional_fields.buttons.push_back(info);
-      }
+  gfx::Image app_icon_mask;
+  if (NotificationConversionHelper::NotificationBitmapToGfxImage(
+          image_scale,
+          bitmap_sizes.app_icon_mask_size,
+          options->app_icon_mask_bitmap.get(),
+          &app_icon_mask)) {
+    notification->set_small_image(app_icon_mask);
+  }
+
+  if (options->priority)
+    notification->set_priority(*options->priority);
+
+  if (options->event_time)
+    notification->set_timestamp(base::Time::FromJsTime(*options->event_time));
+
+  if (options->buttons) {
+    // Currently we allow up to 2 buttons.
+    size_t number_of_buttons = options->buttons->size();
+    number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons;
+
+    std::vector<message_center::ButtonInfo> buttons;
+    for (size_t i = 0; i < number_of_buttons; i++) {
+      message_center::ButtonInfo button(
+          base::UTF8ToUTF16((*options->buttons)[i]->title));
+      NotificationConversionHelper::NotificationBitmapToGfxImage(
+          image_scale,
+          bitmap_sizes.button_icon_size,
+          (*options->buttons)[i]->icon_bitmap.get(),
+          &button.icon);
+      buttons.push_back(button);
     }
+    notification->set_buttons(buttons);
+  }
 
-    if (options->context_message)
-      notification->set_context_message(UTF8ToUTF16(*options->context_message));
+  if (options->context_message) {
+    notification->set_context_message(
+        base::UTF8ToUTF16(*options->context_message));
+  }
 
-    if (options->expanded_message) {
-      notification->set_expanded_message(
-          UTF8ToUTF16(*options->expanded_message));
+  gfx::Image image;
+  bool has_image = NotificationConversionHelper::NotificationBitmapToGfxImage(
+      image_scale,
+      bitmap_sizes.image_size,
+      options->image_bitmap.get(),
+      &image);
+  if (has_image) {
+    // We should have an image if and only if the type is an image type.
+    if (notification->type() != message_center::NOTIFICATION_TYPE_IMAGE) {
+      SetError(kExtraImageProvided);
+      return false;
     }
+    notification->set_image(image);
+  }
 
-    gfx::Image image;
-    if (NotificationBitmapToGfxImage(options->image_bitmap.get(), &image)) {
-      // We should have an image if and only if the type is an image type.
-      if (notification->type() != message_center::NOTIFICATION_TYPE_IMAGE)
-        return false;
-      notification->set_image(image);
+  if (options->progress) {
+    // We should have progress if and only if the type is a progress type.
+    if (notification->type() != message_center::NOTIFICATION_TYPE_PROGRESS) {
+      SetError(kUnexpectedProgressValueForNonProgressType);
+      return false;
+    }
+    int progress = *options->progress;
+    // Progress value should range from 0 to 100.
+    if (progress < 0 || progress > 100) {
+      SetError(kInvalidProgressValue);
+      return false;
     }
+    notification->set_progress(progress);
+  }
 
-    if (options->progress) {
-      // We should have progress if and only if the type is a progress type.
-      if (notification->type() != message_center::NOTIFICATION_TYPE_PROGRESS) {
-        SetError(kUnexpectedProgressValueForNonProgressType);
-        return false;
-      }
-      int progress = *options->progress;
-      // Progress value should range from 0 to 100.
-      if (progress < 0 || progress > 100) {
-        SetError(kInvalidProgressValue);
-        return false;
-      }
-      notification->set_progress(progress);
+  if (options->items.get() && options->items->size() > 0) {
+    // We should have list items if and only if the type is a multiple type.
+    if (notification->type() != message_center::NOTIFICATION_TYPE_MULTIPLE) {
+      SetError(kExtraListItemsProvided);
+      return false;
     }
 
-    if (options->items.get() && options->items->size() > 0) {
-      // We should have list items if and only if the type is a multiple type.
-      if (notification->type() != message_center::NOTIFICATION_TYPE_MULTIPLE)
-        return false;
-
-      std::vector< message_center::NotificationItem> items;
-      using api::notifications::NotificationItem;
-      std::vector<linked_ptr<NotificationItem> >::iterator i;
-      for (i = options->items->begin(); i != options->items->end(); ++i) {
-        message_center::NotificationItem item(UTF8ToUTF16(i->get()->title),
-                                              UTF8ToUTF16(i->get()->message));
-        items.push_back(item);
-      }
-      notification->set_items(items);
+    std::vector<message_center::NotificationItem> items;
+    using api::notifications::NotificationItem;
+    std::vector<linked_ptr<NotificationItem> >::iterator i;
+    for (i = options->items->begin(); i != options->items->end(); ++i) {
+      message_center::NotificationItem item(
+          base::UTF8ToUTF16(i->get()->title),
+          base::UTF8ToUTF16(i->get()->message));
+      items.push_back(item);
     }
+    notification->set_items(items);
   }
 
   // Then override if it's already set.
@@ -460,7 +459,7 @@ bool NotificationsApiFunction::CanRunWhileDisabled() const {
   return false;
 }
 
-bool NotificationsApiFunction::RunImpl() {
+bool NotificationsApiFunction::RunAsync() {
   if (IsNotificationsApiAvailable() && IsNotificationsApiEnabled()) {
     return RunNotificationsApi();
   } else {