• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/extensions/api/notifications/notifications_api.h"
6 
7 #include "base/callback.h"
8 #include "base/guid.h"
9 #include "base/rand_util.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/time/time.h"
13 #include "chrome/browser/browser_process.h"
14 #include "chrome/browser/notifications/desktop_notification_service.h"
15 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
16 #include "chrome/browser/notifications/notification.h"
17 #include "chrome/browser/notifications/notification_ui_manager.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/common/chrome_version_info.h"
20 #include "chrome/common/extensions/api/notifications/notification_style.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/render_view_host.h"
23 #include "content/public/browser/web_contents.h"
24 #include "extensions/browser/event_router.h"
25 #include "extensions/common/extension.h"
26 #include "extensions/common/features/feature.h"
27 #include "third_party/skia/include/core/SkBitmap.h"
28 #include "ui/base/layout.h"
29 #include "ui/gfx/image/image.h"
30 #include "ui/gfx/image/image_skia.h"
31 #include "ui/gfx/image/image_skia_rep.h"
32 #include "ui/message_center/message_center_style.h"
33 #include "ui/message_center/notifier_settings.h"
34 #include "url/gurl.h"
35 
36 namespace extensions {
37 
38 namespace notifications = api::notifications;
39 
40 namespace {
41 
42 const char kMissingRequiredPropertiesForCreateNotification[] =
43     "Some of the required properties are missing: type, iconUrl, title and "
44     "message.";
45 const char kUnableToDecodeIconError[] =
46     "Unable to successfully use the provided image.";
47 const char kUnexpectedProgressValueForNonProgressType[] =
48     "The progress value should not be specified for non-progress notification";
49 const char kInvalidProgressValue[] =
50     "The progress value should range from 0 to 100";
51 const char kExtraListItemsProvided[] =
52     "List items provided for notification type != list";
53 const char kExtraImageProvided[] =
54     "Image resource provided for notification type != image";
55 
56 // Converts an object with width, height, and data in RGBA format into an
57 // gfx::Image (in ARGB format).
NotificationBitmapToGfxImage(float max_scale,const gfx::Size & target_size_dips,api::notifications::NotificationBitmap * notification_bitmap,gfx::Image * return_image)58 bool NotificationBitmapToGfxImage(
59     float max_scale,
60     const gfx::Size& target_size_dips,
61     api::notifications::NotificationBitmap* notification_bitmap,
62     gfx::Image* return_image) {
63   if (!notification_bitmap)
64     return false;
65 
66   const int max_device_pixel_width = target_size_dips.width() * max_scale;
67   const int max_device_pixel_height = target_size_dips.height() * max_scale;
68 
69   const int BYTES_PER_PIXEL = 4;
70 
71   const int width = notification_bitmap->width;
72   const int height = notification_bitmap->height;
73 
74   if (width < 0 || height < 0 || width > max_device_pixel_width ||
75       height > max_device_pixel_height)
76     return false;
77 
78   // Ensure we have rgba data.
79   std::string* rgba_data = notification_bitmap->data.get();
80   if (!rgba_data)
81     return false;
82 
83   const size_t rgba_data_length = rgba_data->length();
84   const size_t rgba_area = width * height;
85 
86   if (rgba_data_length != rgba_area * BYTES_PER_PIXEL)
87     return false;
88 
89   // Now configure the bitmap with the sanitized dimensions.
90   SkBitmap bitmap;
91   bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
92 
93   // Allocate the actual backing store.
94   if (!bitmap.allocPixels())
95     return false;
96 
97   // Ensure that our bitmap and our data now refer to the same number of pixels.
98   if (rgba_data_length != bitmap.getSafeSize())
99     return false;
100 
101   uint32_t* pixels = bitmap.getAddr32(0, 0);
102   const char* c_rgba_data = rgba_data->data();
103 
104   for (size_t t = 0; t < rgba_area; ++t) {
105     // |c_rgba_data| is RGBA, pixels is ARGB.
106     size_t rgba_index = t * BYTES_PER_PIXEL;
107     pixels[t] = SkPreMultiplyColor(
108         ((c_rgba_data[rgba_index + 3] & 0xFF) << 24) |
109         ((c_rgba_data[rgba_index + 0] & 0xFF) << 16) |
110         ((c_rgba_data[rgba_index + 1] & 0xFF) << 8) |
111         ((c_rgba_data[rgba_index + 2] & 0xFF) << 0));
112   }
113 
114   // TODO(dewittj): Handle HiDPI images with more than one scale factor
115   // representation.
116   gfx::ImageSkia skia(gfx::ImageSkiaRep(bitmap, 1.0f));
117   *return_image = gfx::Image(skia);
118   return true;
119 }
120 
121 // Given an extension id and another id, returns an id that is unique
122 // relative to other extensions.
CreateScopedIdentifier(const std::string & extension_id,const std::string & id)123 std::string CreateScopedIdentifier(const std::string& extension_id,
124                                    const std::string& id) {
125   return extension_id + "-" + id;
126 }
127 
128 // Removes the unique internal identifier to send the ID as the
129 // extension expects it.
StripScopeFromIdentifier(const std::string & extension_id,const std::string & id)130 std::string StripScopeFromIdentifier(const std::string& extension_id,
131                                      const std::string& id) {
132   size_t index_of_separator = extension_id.length() + 1;
133   DCHECK_LT(index_of_separator, id.length());
134 
135   return id.substr(index_of_separator);
136 }
137 
138 class NotificationsApiDelegate : public NotificationDelegate {
139  public:
NotificationsApiDelegate(ChromeAsyncExtensionFunction * api_function,Profile * profile,const std::string & extension_id,const std::string & id)140   NotificationsApiDelegate(ChromeAsyncExtensionFunction* api_function,
141                            Profile* profile,
142                            const std::string& extension_id,
143                            const std::string& id)
144       : api_function_(api_function),
145         profile_(profile),
146         extension_id_(extension_id),
147         id_(id),
148         scoped_id_(CreateScopedIdentifier(extension_id, id)),
149         process_id_(-1) {
150     DCHECK(api_function_.get());
151     if (api_function_->render_view_host())
152       process_id_ = api_function->render_view_host()->GetProcess()->GetID();
153   }
154 
Display()155   virtual void Display() OVERRIDE { }
156 
Error()157   virtual void Error() OVERRIDE {}
158 
Close(bool by_user)159   virtual void Close(bool by_user) OVERRIDE {
160     EventRouter::UserGestureState gesture =
161         by_user ? EventRouter::USER_GESTURE_ENABLED
162                 : EventRouter::USER_GESTURE_NOT_ENABLED;
163     scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
164     args->Append(new base::FundamentalValue(by_user));
165     SendEvent(notifications::OnClosed::kEventName, gesture, args.Pass());
166   }
167 
Click()168   virtual void Click() OVERRIDE {
169     scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
170     SendEvent(notifications::OnClicked::kEventName,
171               EventRouter::USER_GESTURE_ENABLED,
172               args.Pass());
173   }
174 
HasClickedListener()175   virtual bool HasClickedListener() OVERRIDE {
176     return EventRouter::Get(profile_)->HasEventListener(
177         notifications::OnClicked::kEventName);
178   }
179 
ButtonClick(int index)180   virtual void ButtonClick(int index) OVERRIDE {
181     scoped_ptr<base::ListValue> args(CreateBaseEventArgs());
182     args->Append(new base::FundamentalValue(index));
183     SendEvent(notifications::OnButtonClicked::kEventName,
184               EventRouter::USER_GESTURE_ENABLED,
185               args.Pass());
186   }
187 
id() const188   virtual std::string id() const OVERRIDE {
189     return scoped_id_;
190   }
191 
process_id() const192   virtual int process_id() const OVERRIDE {
193     return process_id_;
194   }
195 
GetWebContents() const196   virtual content::WebContents* GetWebContents() const OVERRIDE {
197     // We're holding a reference to api_function_, so we know it'll be valid
198     // until ReleaseRVH is called, and api_function_ (as a
199     // AsyncExtensionFunction) will zero out its copy of render_view_host
200     // when the RVH goes away.
201     if (!api_function_.get())
202       return NULL;
203     content::RenderViewHost* rvh = api_function_->render_view_host();
204     if (!rvh)
205       return NULL;
206     return content::WebContents::FromRenderViewHost(rvh);
207   }
208 
ReleaseRenderViewHost()209   virtual void ReleaseRenderViewHost() OVERRIDE {
210     api_function_ = NULL;
211   }
212 
213  private:
~NotificationsApiDelegate()214   virtual ~NotificationsApiDelegate() {}
215 
SendEvent(const std::string & name,EventRouter::UserGestureState user_gesture,scoped_ptr<base::ListValue> args)216   void SendEvent(const std::string& name,
217                  EventRouter::UserGestureState user_gesture,
218                  scoped_ptr<base::ListValue> args) {
219     scoped_ptr<Event> event(new Event(name, args.Pass()));
220     event->user_gesture = user_gesture;
221     EventRouter::Get(profile_)->DispatchEventToExtension(extension_id_,
222                                                          event.Pass());
223   }
224 
CreateBaseEventArgs()225   scoped_ptr<base::ListValue> CreateBaseEventArgs() {
226     scoped_ptr<base::ListValue> args(new base::ListValue());
227     args->Append(new base::StringValue(id_));
228     return args.Pass();
229   }
230 
231   scoped_refptr<ChromeAsyncExtensionFunction> api_function_;
232   Profile* profile_;
233   const std::string extension_id_;
234   const std::string id_;
235   const std::string scoped_id_;
236   int process_id_;
237 
238   DISALLOW_COPY_AND_ASSIGN(NotificationsApiDelegate);
239 };
240 
241 }  // namespace
242 
IsNotificationsApiAvailable()243 bool NotificationsApiFunction::IsNotificationsApiAvailable() {
244   // We need to check this explicitly rather than letting
245   // _permission_features.json enforce it, because we're sharing the
246   // chrome.notifications permissions namespace with WebKit notifications.
247   return GetExtension()->is_platform_app() || GetExtension()->is_extension();
248 }
249 
NotificationsApiFunction()250 NotificationsApiFunction::NotificationsApiFunction() {
251 }
252 
~NotificationsApiFunction()253 NotificationsApiFunction::~NotificationsApiFunction() {
254 }
255 
CreateNotification(const std::string & id,api::notifications::NotificationOptions * options)256 bool NotificationsApiFunction::CreateNotification(
257     const std::string& id,
258     api::notifications::NotificationOptions* options) {
259   // First, make sure the required fields exist: type, title, message,  icon.
260   // These fields are defined as optional in IDL such that they can be used as
261   // optional for notification updates. But for notification creations, they
262   // should be present.
263   if (options->type == api::notifications::TEMPLATE_TYPE_NONE ||
264       !options->icon_url || !options->title || !options->message) {
265     SetError(kMissingRequiredPropertiesForCreateNotification);
266     return false;
267   }
268 
269   NotificationBitmapSizes bitmap_sizes = GetNotificationBitmapSizes();
270 
271   float image_scale =
272       ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactors().back());
273 
274   // Extract required fields: type, title, message, and icon.
275   message_center::NotificationType type =
276       MapApiTemplateTypeToType(options->type);
277   const base::string16 title(base::UTF8ToUTF16(*options->title));
278   const base::string16 message(base::UTF8ToUTF16(*options->message));
279   gfx::Image icon;
280 
281   if (!NotificationBitmapToGfxImage(image_scale,
282                                     bitmap_sizes.icon_size,
283                                     options->icon_bitmap.get(),
284                                     &icon)) {
285     SetError(kUnableToDecodeIconError);
286     return false;
287   }
288 
289   // Then, handle any optional data that's been provided.
290   message_center::RichNotificationData optional_fields;
291   if (options->priority.get())
292     optional_fields.priority = *options->priority;
293 
294   if (options->event_time.get())
295     optional_fields.timestamp = base::Time::FromJsTime(*options->event_time);
296 
297   if (options->buttons.get()) {
298     // Currently we allow up to 2 buttons.
299     size_t number_of_buttons = options->buttons->size();
300     number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons;
301 
302     for (size_t i = 0; i < number_of_buttons; i++) {
303       message_center::ButtonInfo info(
304           base::UTF8ToUTF16((*options->buttons)[i]->title));
305       NotificationBitmapToGfxImage(image_scale,
306                                    bitmap_sizes.button_icon_size,
307                                    (*options->buttons)[i]->icon_bitmap.get(),
308                                    &info.icon);
309       optional_fields.buttons.push_back(info);
310     }
311   }
312 
313   if (options->context_message) {
314     optional_fields.context_message =
315         base::UTF8ToUTF16(*options->context_message);
316   }
317 
318   bool has_image = NotificationBitmapToGfxImage(image_scale,
319                                                 bitmap_sizes.image_size,
320                                                 options->image_bitmap.get(),
321                                                 &optional_fields.image);
322   // We should have an image if and only if the type is an image type.
323   if (has_image != (type == message_center::NOTIFICATION_TYPE_IMAGE)) {
324     SetError(kExtraImageProvided);
325     return false;
326   }
327 
328   // We should have list items if and only if the type is a multiple type.
329   bool has_list_items = options->items.get() && options->items->size() > 0;
330   if (has_list_items != (type == message_center::NOTIFICATION_TYPE_MULTIPLE)) {
331     SetError(kExtraListItemsProvided);
332     return false;
333   }
334 
335   if (options->progress.get() != NULL) {
336     // We should have progress if and only if the type is a progress type.
337     if (type != message_center::NOTIFICATION_TYPE_PROGRESS) {
338       SetError(kUnexpectedProgressValueForNonProgressType);
339       return false;
340     }
341     optional_fields.progress = *options->progress;
342     // Progress value should range from 0 to 100.
343     if (optional_fields.progress < 0 || optional_fields.progress > 100) {
344       SetError(kInvalidProgressValue);
345       return false;
346     }
347   }
348 
349   if (has_list_items) {
350     using api::notifications::NotificationItem;
351     std::vector<linked_ptr<NotificationItem> >::iterator i;
352     for (i = options->items->begin(); i != options->items->end(); ++i) {
353       message_center::NotificationItem item(
354           base::UTF8ToUTF16(i->get()->title),
355           base::UTF8ToUTF16(i->get()->message));
356       optional_fields.items.push_back(item);
357     }
358   }
359 
360   if (options->is_clickable.get())
361     optional_fields.clickable = *options->is_clickable;
362 
363   NotificationsApiDelegate* api_delegate(new NotificationsApiDelegate(
364       this, GetProfile(), extension_->id(), id));  // ownership is passed to
365                                                    // Notification
366   Notification notification(type,
367                             extension_->url(),
368                             title,
369                             message,
370                             icon,
371                             blink::WebTextDirectionDefault,
372                             message_center::NotifierId(
373                                 message_center::NotifierId::APPLICATION,
374                                 extension_->id()),
375                             base::UTF8ToUTF16(extension_->name()),
376                             base::UTF8ToUTF16(api_delegate->id()),
377                             optional_fields,
378                             api_delegate);
379 
380   g_browser_process->notification_ui_manager()->Add(notification, GetProfile());
381   return true;
382 }
383 
UpdateNotification(const std::string & id,api::notifications::NotificationOptions * options,Notification * notification)384 bool NotificationsApiFunction::UpdateNotification(
385     const std::string& id,
386     api::notifications::NotificationOptions* options,
387     Notification* notification) {
388   NotificationBitmapSizes bitmap_sizes = GetNotificationBitmapSizes();
389   float image_scale =
390       ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactors().back());
391 
392   // Update optional fields if provided.
393   if (options->type != api::notifications::TEMPLATE_TYPE_NONE)
394     notification->set_type(MapApiTemplateTypeToType(options->type));
395   if (options->title)
396     notification->set_title(base::UTF8ToUTF16(*options->title));
397   if (options->message)
398     notification->set_message(base::UTF8ToUTF16(*options->message));
399 
400   // TODO(dewittj): Return error if this fails.
401   if (options->icon_bitmap) {
402     gfx::Image icon;
403     NotificationBitmapToGfxImage(
404         image_scale, bitmap_sizes.icon_size, options->icon_bitmap.get(), &icon);
405     notification->set_icon(icon);
406   }
407 
408   if (options->priority)
409     notification->set_priority(*options->priority);
410 
411   if (options->event_time)
412     notification->set_timestamp(base::Time::FromJsTime(*options->event_time));
413 
414   if (options->buttons) {
415     // Currently we allow up to 2 buttons.
416     size_t number_of_buttons = options->buttons->size();
417     number_of_buttons = number_of_buttons > 2 ? 2 : number_of_buttons;
418 
419     std::vector<message_center::ButtonInfo> buttons;
420     for (size_t i = 0; i < number_of_buttons; i++) {
421       message_center::ButtonInfo button(
422           base::UTF8ToUTF16((*options->buttons)[i]->title));
423       NotificationBitmapToGfxImage(image_scale,
424                                    bitmap_sizes.button_icon_size,
425                                    (*options->buttons)[i]->icon_bitmap.get(),
426                                    &button.icon);
427       buttons.push_back(button);
428     }
429     notification->set_buttons(buttons);
430   }
431 
432   if (options->context_message) {
433     notification->set_context_message(
434         base::UTF8ToUTF16(*options->context_message));
435   }
436 
437   gfx::Image image;
438   bool has_image = NotificationBitmapToGfxImage(image_scale,
439                                                 bitmap_sizes.image_size,
440                                                 options->image_bitmap.get(),
441                                                 &image);
442   if (has_image) {
443     // We should have an image if and only if the type is an image type.
444     if (notification->type() != message_center::NOTIFICATION_TYPE_IMAGE) {
445       SetError(kExtraImageProvided);
446       return false;
447     }
448     notification->set_image(image);
449   }
450 
451   if (options->progress) {
452     // We should have progress if and only if the type is a progress type.
453     if (notification->type() != message_center::NOTIFICATION_TYPE_PROGRESS) {
454       SetError(kUnexpectedProgressValueForNonProgressType);
455       return false;
456     }
457     int progress = *options->progress;
458     // Progress value should range from 0 to 100.
459     if (progress < 0 || progress > 100) {
460       SetError(kInvalidProgressValue);
461       return false;
462     }
463     notification->set_progress(progress);
464   }
465 
466   if (options->items.get() && options->items->size() > 0) {
467     // We should have list items if and only if the type is a multiple type.
468     if (notification->type() != message_center::NOTIFICATION_TYPE_MULTIPLE) {
469       SetError(kExtraListItemsProvided);
470       return false;
471     }
472 
473     std::vector<message_center::NotificationItem> items;
474     using api::notifications::NotificationItem;
475     std::vector<linked_ptr<NotificationItem> >::iterator i;
476     for (i = options->items->begin(); i != options->items->end(); ++i) {
477       message_center::NotificationItem item(
478           base::UTF8ToUTF16(i->get()->title),
479           base::UTF8ToUTF16(i->get()->message));
480       items.push_back(item);
481     }
482     notification->set_items(items);
483   }
484 
485   // Then override if it's already set.
486   if (options->is_clickable.get())
487     notification->set_clickable(*options->is_clickable);
488 
489   g_browser_process->notification_ui_manager()->Update(*notification,
490                                                        GetProfile());
491   return true;
492 }
493 
AreExtensionNotificationsAllowed() const494 bool NotificationsApiFunction::AreExtensionNotificationsAllowed() const {
495   DesktopNotificationService* service =
496       DesktopNotificationServiceFactory::GetForProfile(GetProfile());
497   return service->IsNotifierEnabled(message_center::NotifierId(
498              message_center::NotifierId::APPLICATION, extension_->id()));
499 }
500 
IsNotificationsApiEnabled() const501 bool NotificationsApiFunction::IsNotificationsApiEnabled() const {
502   return CanRunWhileDisabled() || AreExtensionNotificationsAllowed();
503 }
504 
CanRunWhileDisabled() const505 bool NotificationsApiFunction::CanRunWhileDisabled() const {
506   return false;
507 }
508 
RunAsync()509 bool NotificationsApiFunction::RunAsync() {
510   if (IsNotificationsApiAvailable() && IsNotificationsApiEnabled()) {
511     return RunNotificationsApi();
512   } else {
513     SendResponse(false);
514     return true;
515   }
516 }
517 
518 message_center::NotificationType
MapApiTemplateTypeToType(api::notifications::TemplateType type)519 NotificationsApiFunction::MapApiTemplateTypeToType(
520     api::notifications::TemplateType type) {
521   switch (type) {
522     case api::notifications::TEMPLATE_TYPE_NONE:
523     case api::notifications::TEMPLATE_TYPE_BASIC:
524       return message_center::NOTIFICATION_TYPE_BASE_FORMAT;
525     case api::notifications::TEMPLATE_TYPE_IMAGE:
526       return message_center::NOTIFICATION_TYPE_IMAGE;
527     case api::notifications::TEMPLATE_TYPE_LIST:
528       return message_center::NOTIFICATION_TYPE_MULTIPLE;
529     case api::notifications::TEMPLATE_TYPE_PROGRESS:
530       return message_center::NOTIFICATION_TYPE_PROGRESS;
531     default:
532       // Gracefully handle newer application code that is running on an older
533       // runtime that doesn't recognize the requested template.
534       return message_center::NOTIFICATION_TYPE_BASE_FORMAT;
535   }
536 }
537 
NotificationsCreateFunction()538 NotificationsCreateFunction::NotificationsCreateFunction() {
539 }
540 
~NotificationsCreateFunction()541 NotificationsCreateFunction::~NotificationsCreateFunction() {
542 }
543 
RunNotificationsApi()544 bool NotificationsCreateFunction::RunNotificationsApi() {
545   params_ = api::notifications::Create::Params::Create(*args_);
546   EXTENSION_FUNCTION_VALIDATE(params_.get());
547 
548   const std::string extension_id(extension_->id());
549   std::string notification_id;
550   if (!params_->notification_id.empty()) {
551     // If the caller provided a notificationId, use that.
552     notification_id = params_->notification_id;
553   } else {
554     // Otherwise, use a randomly created GUID. In case that GenerateGUID returns
555     // the empty string, simply generate a random string.
556     notification_id = base::GenerateGUID();
557     if (notification_id.empty())
558       notification_id = base::RandBytesAsString(16);
559   }
560 
561   SetResult(new base::StringValue(notification_id));
562 
563   // TODO(dewittj): Add more human-readable error strings if this fails.
564   if (!CreateNotification(notification_id, &params_->options))
565     return false;
566 
567   SendResponse(true);
568 
569   return true;
570 }
571 
NotificationsUpdateFunction()572 NotificationsUpdateFunction::NotificationsUpdateFunction() {
573 }
574 
~NotificationsUpdateFunction()575 NotificationsUpdateFunction::~NotificationsUpdateFunction() {
576 }
577 
RunNotificationsApi()578 bool NotificationsUpdateFunction::RunNotificationsApi() {
579   params_ = api::notifications::Update::Params::Create(*args_);
580   EXTENSION_FUNCTION_VALIDATE(params_.get());
581 
582   // We are in update.  If the ID doesn't exist, succeed but call the callback
583   // with "false".
584   const Notification* matched_notification =
585       g_browser_process->notification_ui_manager()->FindById(
586           CreateScopedIdentifier(extension_->id(), params_->notification_id));
587   if (!matched_notification) {
588     SetResult(new base::FundamentalValue(false));
589     SendResponse(true);
590     return true;
591   }
592 
593   // Copy the existing notification to get a writable version of it.
594   Notification notification = *matched_notification;
595 
596   // If we have trouble updating the notification (could be improper use of API
597   // or some other reason), mark the function as failed, calling the callback
598   // with false.
599   // TODO(dewittj): Add more human-readable error strings if this fails.
600   bool could_update_notification = UpdateNotification(
601       params_->notification_id, &params_->options, &notification);
602   SetResult(new base::FundamentalValue(could_update_notification));
603   if (!could_update_notification)
604     return false;
605 
606   // No trouble, created the notification, send true to the callback and
607   // succeed.
608   SendResponse(true);
609   return true;
610 }
611 
NotificationsClearFunction()612 NotificationsClearFunction::NotificationsClearFunction() {
613 }
614 
~NotificationsClearFunction()615 NotificationsClearFunction::~NotificationsClearFunction() {
616 }
617 
RunNotificationsApi()618 bool NotificationsClearFunction::RunNotificationsApi() {
619   params_ = api::notifications::Clear::Params::Create(*args_);
620   EXTENSION_FUNCTION_VALIDATE(params_.get());
621 
622   bool cancel_result = g_browser_process->notification_ui_manager()->CancelById(
623       CreateScopedIdentifier(extension_->id(), params_->notification_id));
624 
625   SetResult(new base::FundamentalValue(cancel_result));
626   SendResponse(true);
627 
628   return true;
629 }
630 
NotificationsGetAllFunction()631 NotificationsGetAllFunction::NotificationsGetAllFunction() {}
632 
~NotificationsGetAllFunction()633 NotificationsGetAllFunction::~NotificationsGetAllFunction() {}
634 
RunNotificationsApi()635 bool NotificationsGetAllFunction::RunNotificationsApi() {
636   NotificationUIManager* notification_ui_manager =
637       g_browser_process->notification_ui_manager();
638   std::set<std::string> notification_ids =
639       notification_ui_manager->GetAllIdsByProfileAndSourceOrigin(
640           GetProfile(), extension_->url());
641 
642   scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
643 
644   for (std::set<std::string>::iterator iter = notification_ids.begin();
645        iter != notification_ids.end(); iter++) {
646     result->SetBooleanWithoutPathExpansion(
647         StripScopeFromIdentifier(extension_->id(), *iter), true);
648   }
649 
650   SetResult(result.release());
651   SendResponse(true);
652 
653   return true;
654 }
655 
656 NotificationsGetPermissionLevelFunction::
NotificationsGetPermissionLevelFunction()657 NotificationsGetPermissionLevelFunction() {}
658 
659 NotificationsGetPermissionLevelFunction::
~NotificationsGetPermissionLevelFunction()660 ~NotificationsGetPermissionLevelFunction() {}
661 
CanRunWhileDisabled() const662 bool NotificationsGetPermissionLevelFunction::CanRunWhileDisabled() const {
663   return true;
664 }
665 
RunNotificationsApi()666 bool NotificationsGetPermissionLevelFunction::RunNotificationsApi() {
667   api::notifications::PermissionLevel result =
668       AreExtensionNotificationsAllowed()
669           ? api::notifications::PERMISSION_LEVEL_GRANTED
670           : api::notifications::PERMISSION_LEVEL_DENIED;
671 
672   SetResult(new base::StringValue(api::notifications::ToString(result)));
673   SendResponse(true);
674 
675   return true;
676 }
677 
678 }  // namespace extensions
679