• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/notifications/desktop_notification_service.h"
6 
7 #include "base/metrics/histogram.h"
8 #include "base/threading/thread.h"
9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/content_settings/content_settings_provider.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
13 #include "chrome/browser/notifications/notification.h"
14 #include "chrome/browser/notifications/notification_object_proxy.h"
15 #include "chrome/browser/notifications/notification_ui_manager.h"
16 #include "chrome/browser/notifications/notifications_prefs_cache.h"
17 #include "chrome/browser/prefs/pref_service.h"
18 #include "chrome/browser/prefs/scoped_user_pref_update.h"
19 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
21 #include "chrome/browser/ui/browser_list.h"
22 #include "chrome/common/pref_names.h"
23 #include "chrome/common/url_constants.h"
24 #include "content/browser/browser_child_process_host.h"
25 #include "content/browser/browser_thread.h"
26 #include "content/browser/renderer_host/render_process_host.h"
27 #include "content/browser/renderer_host/render_view_host.h"
28 #include "content/browser/site_instance.h"
29 #include "content/browser/tab_contents/tab_contents.h"
30 #include "content/browser/worker_host/worker_process_host.h"
31 #include "content/common/desktop_notification_messages.h"
32 #include "content/common/notification_service.h"
33 #include "content/common/notification_type.h"
34 #include "grit/browser_resources.h"
35 #include "grit/chromium_strings.h"
36 #include "grit/generated_resources.h"
37 #include "grit/theme_resources.h"
38 #include "net/base/escape.h"
39 #include "third_party/WebKit/Source/WebKit/chromium/public/WebNotificationPresenter.h"
40 #include "ui/base/l10n/l10n_util.h"
41 #include "ui/base/resource/resource_bundle.h"
42 
43 using WebKit::WebNotificationPresenter;
44 using WebKit::WebTextDirection;
45 
46 const ContentSetting kDefaultSetting = CONTENT_SETTING_ASK;
47 
48 namespace {
49 
50 typedef content_settings::ProviderInterface::Rules Rules;
51 
GetOriginsWithSettingFromContentSettingsRules(const Rules & content_setting_rules,ContentSetting setting,std::vector<GURL> * origins)52 void GetOriginsWithSettingFromContentSettingsRules(
53     const Rules& content_setting_rules,
54     ContentSetting setting,
55     std::vector<GURL>* origins) {
56   origins->clear();
57 
58   for (Rules::const_iterator rule = content_setting_rules.begin();
59        rule != content_setting_rules.end();
60        ++rule) {
61     if (setting == rule->content_setting) {
62       std::string url_str = rule->requesting_url_pattern.AsString();
63       if (!rule->requesting_url_pattern.IsValid()) {
64         // TODO(markusheintz): This will be removed in one of the next
65         // refactoring steps as this entire function will disapear.
66         LOG(DFATAL) << "Ignoring invalid content settings pattern: "
67                     << url_str;
68       } else if (url_str.find(ContentSettingsPattern::kDomainWildcard) == 0) {
69         // TODO(markusheintz): This must be changed once the UI code is
70         // refactored and content_settings patterns are fully supported for
71         // notifications settings.
72         LOG(DFATAL) << "Ignoring unsupported content settings pattern: "
73                     << url_str << ". Content settings patterns other than "
74                     << "hostnames (e.g. wildcard patterns) are not supported "
75                     << "for notification content settings yet.";
76       } else {
77         origins->push_back(
78             content_settings::NotificationProvider::ToGURL(
79                 rule->requesting_url_pattern));
80       }
81     }
82   }
83 }
84 
85 }  // namespace
86 
87 // NotificationPermissionInfoBarDelegate --------------------------------------
88 
89 // The delegate for the infobar shown when an origin requests notification
90 // permissions.
91 class NotificationPermissionInfoBarDelegate : public ConfirmInfoBarDelegate {
92  public:
93   NotificationPermissionInfoBarDelegate(TabContents* contents,
94                                         const GURL& origin,
95                                         const string16& display_name,
96                                         int process_id,
97                                         int route_id,
98                                         int callback_context);
99 
100  private:
101   virtual ~NotificationPermissionInfoBarDelegate();
102 
103   // ConfirmInfoBarDelegate:
104   virtual void InfoBarClosed();
105   virtual SkBitmap* GetIcon() const;
106   virtual Type GetInfoBarType() const;
107   virtual string16 GetMessageText() const;
108   virtual string16 GetButtonLabel(InfoBarButton button) const;
109   virtual bool Accept();
110   virtual bool Cancel();
111 
112   // The origin we are asking for permissions on.
113   GURL origin_;
114 
115   // The display name for the origin to be displayed.  Will be different from
116   // origin_ for extensions.
117   string16 display_name_;
118 
119   // The Profile that we restore sessions from.
120   Profile* profile_;
121 
122   // The callback information that tells us how to respond to javascript via
123   // the correct RenderView.
124   int process_id_;
125   int route_id_;
126   int callback_context_;
127 
128   // Whether the user clicked one of the buttons.
129   bool action_taken_;
130 
131   DISALLOW_COPY_AND_ASSIGN(NotificationPermissionInfoBarDelegate);
132 };
133 
NotificationPermissionInfoBarDelegate(TabContents * contents,const GURL & origin,const string16 & display_name,int process_id,int route_id,int callback_context)134 NotificationPermissionInfoBarDelegate::NotificationPermissionInfoBarDelegate(
135     TabContents* contents,
136     const GURL& origin,
137     const string16& display_name,
138     int process_id,
139     int route_id,
140     int callback_context)
141     : ConfirmInfoBarDelegate(contents),
142       origin_(origin),
143       display_name_(display_name),
144       profile_(contents->profile()),
145       process_id_(process_id),
146       route_id_(route_id),
147       callback_context_(callback_context),
148       action_taken_(false) {
149 }
150 
151 NotificationPermissionInfoBarDelegate::
~NotificationPermissionInfoBarDelegate()152     ~NotificationPermissionInfoBarDelegate() {
153 }
154 
InfoBarClosed()155 void NotificationPermissionInfoBarDelegate::InfoBarClosed() {
156   if (!action_taken_)
157     UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Ignored", 1);
158 
159   RenderViewHost* host = RenderViewHost::FromID(process_id_, route_id_);
160   if (host) {
161     host->Send(new DesktopNotificationMsg_PermissionRequestDone(
162         route_id_, callback_context_));
163   }
164 
165   delete this;
166 }
167 
GetIcon() const168 SkBitmap* NotificationPermissionInfoBarDelegate::GetIcon() const {
169   return ResourceBundle::GetSharedInstance().GetBitmapNamed(
170      IDR_PRODUCT_ICON_32);
171 }
172 
173 InfoBarDelegate::Type
GetInfoBarType() const174     NotificationPermissionInfoBarDelegate::GetInfoBarType() const {
175   return PAGE_ACTION_TYPE;
176 }
177 
GetMessageText() const178 string16 NotificationPermissionInfoBarDelegate::GetMessageText() const {
179   return l10n_util::GetStringFUTF16(IDS_NOTIFICATION_PERMISSIONS,
180                                     display_name_);
181 }
182 
GetButtonLabel(InfoBarButton button) const183 string16 NotificationPermissionInfoBarDelegate::GetButtonLabel(
184     InfoBarButton button) const {
185   return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
186       IDS_NOTIFICATION_PERMISSION_YES : IDS_NOTIFICATION_PERMISSION_NO);
187 }
188 
Accept()189 bool NotificationPermissionInfoBarDelegate::Accept() {
190   UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Allowed", 1);
191   DesktopNotificationServiceFactory::GetForProfile(profile_)->
192       GrantPermission(origin_);
193   action_taken_ = true;
194   return true;
195 }
196 
Cancel()197 bool NotificationPermissionInfoBarDelegate::Cancel() {
198   UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Denied", 1);
199   DesktopNotificationServiceFactory::GetForProfile(profile_)->
200       DenyPermission(origin_);
201   action_taken_ = true;
202   return true;
203 }
204 
205 
206 // DesktopNotificationService -------------------------------------------------
207 
208 // static
CreateDataUrl(const GURL & icon_url,const string16 & title,const string16 & body,WebTextDirection dir)209 string16 DesktopNotificationService::CreateDataUrl(
210     const GURL& icon_url, const string16& title, const string16& body,
211     WebTextDirection dir) {
212   int resource;
213   std::vector<std::string> subst;
214   if (icon_url.is_valid()) {
215     resource = IDR_NOTIFICATION_ICON_HTML;
216     subst.push_back(icon_url.spec());
217     subst.push_back(EscapeForHTML(UTF16ToUTF8(title)));
218     subst.push_back(EscapeForHTML(UTF16ToUTF8(body)));
219     // icon float position
220     subst.push_back(dir == WebKit::WebTextDirectionRightToLeft ?
221                     "right" : "left");
222   } else if (title.empty() || body.empty()) {
223     resource = IDR_NOTIFICATION_1LINE_HTML;
224     string16 line = title.empty() ? body : title;
225     // Strings are div names in the template file.
226     string16 line_name = title.empty() ? ASCIIToUTF16("description")
227                                        : ASCIIToUTF16("title");
228     subst.push_back(EscapeForHTML(UTF16ToUTF8(line_name)));
229     subst.push_back(EscapeForHTML(UTF16ToUTF8(line)));
230   } else {
231     resource = IDR_NOTIFICATION_2LINE_HTML;
232     subst.push_back(EscapeForHTML(UTF16ToUTF8(title)));
233     subst.push_back(EscapeForHTML(UTF16ToUTF8(body)));
234   }
235   // body text direction
236   subst.push_back(dir == WebKit::WebTextDirectionRightToLeft ?
237                   "rtl" : "ltr");
238 
239   return CreateDataUrl(resource, subst);
240 }
241 
242 // static
CreateDataUrl(int resource,const std::vector<std::string> & subst)243 string16 DesktopNotificationService::CreateDataUrl(
244     int resource, const std::vector<std::string>& subst) {
245   const base::StringPiece template_html(
246       ResourceBundle::GetSharedInstance().GetRawDataResource(
247           resource));
248 
249   if (template_html.empty()) {
250     NOTREACHED() << "unable to load template. ID: " << resource;
251     return string16();
252   }
253 
254   std::string data = ReplaceStringPlaceholders(template_html, subst, NULL);
255   return UTF8ToUTF16("data:text/html;charset=utf-8," +
256                       EscapeQueryParamValue(data, false));
257 }
258 
DesktopNotificationService(Profile * profile,NotificationUIManager * ui_manager)259 DesktopNotificationService::DesktopNotificationService(Profile* profile,
260     NotificationUIManager* ui_manager)
261     : profile_(profile),
262       ui_manager_(ui_manager) {
263   prefs_registrar_.Init(profile_->GetPrefs());
264   InitPrefs();
265   StartObserving();
266 }
267 
~DesktopNotificationService()268 DesktopNotificationService::~DesktopNotificationService() {
269   StopObserving();
270 }
271 
RegisterUserPrefs(PrefService * user_prefs)272 void DesktopNotificationService::RegisterUserPrefs(PrefService* user_prefs) {
273   content_settings::NotificationProvider::RegisterUserPrefs(user_prefs);
274 }
275 
276 // Initialize the cache with the allowed and denied origins, or
277 // create the preferences if they don't exist yet.
InitPrefs()278 void DesktopNotificationService::InitPrefs() {
279   provider_.reset(new content_settings::NotificationProvider(profile_));
280 
281   std::vector<GURL> allowed_origins;
282   std::vector<GURL> denied_origins;
283   ContentSetting default_content_setting = CONTENT_SETTING_DEFAULT;
284 
285   if (!profile_->IsOffTheRecord()) {
286     default_content_setting =
287         profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
288             CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
289     allowed_origins = GetAllowedOrigins();
290     denied_origins = GetBlockedOrigins();
291   }
292 
293   prefs_cache_ = new NotificationsPrefsCache();
294   prefs_cache_->SetCacheDefaultContentSetting(default_content_setting);
295   prefs_cache_->SetCacheAllowedOrigins(allowed_origins);
296   prefs_cache_->SetCacheDeniedOrigins(denied_origins);
297   prefs_cache_->set_is_initialized(true);
298 }
299 
StartObserving()300 void DesktopNotificationService::StartObserving() {
301   if (!profile_->IsOffTheRecord()) {
302     prefs_registrar_.Add(prefs::kDesktopNotificationAllowedOrigins, this);
303     prefs_registrar_.Add(prefs::kDesktopNotificationDeniedOrigins, this);
304     notification_registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
305                                 NotificationService::AllSources());
306     notification_registrar_.Add(
307         this,
308         NotificationType::CONTENT_SETTINGS_CHANGED,
309         // TODO(markusheintz): Remember to change to HostContentSettingsMap.
310         NotificationService::AllSources());
311   }
312   notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED,
313                               Source<Profile>(profile_));
314 }
315 
StopObserving()316 void DesktopNotificationService::StopObserving() {
317   if (!profile_->IsOffTheRecord()) {
318     prefs_registrar_.RemoveAll();
319   }
320   notification_registrar_.RemoveAll();
321 }
322 
GrantPermission(const GURL & origin)323 void DesktopNotificationService::GrantPermission(const GURL& origin) {
324   ContentSettingsPattern pattern =
325       content_settings::NotificationProvider::ToContentSettingsPattern(origin);
326   provider_->SetContentSetting(
327       pattern,
328       pattern,
329       CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
330       NO_RESOURCE_IDENTIFIER,
331       CONTENT_SETTING_ALLOW);
332 
333   // Schedule a cache update on the IO thread.
334   BrowserThread::PostTask(
335       BrowserThread::IO, FROM_HERE,
336       NewRunnableMethod(
337           prefs_cache_.get(),
338           &NotificationsPrefsCache::CacheAllowedOrigin,
339           origin));
340 }
341 
DenyPermission(const GURL & origin)342 void DesktopNotificationService::DenyPermission(const GURL& origin) {
343   // Update content settings
344   ContentSettingsPattern pattern =
345       content_settings::NotificationProvider::ToContentSettingsPattern(origin);
346   provider_->SetContentSetting(
347       pattern,
348       pattern,
349       CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
350       NO_RESOURCE_IDENTIFIER,
351       CONTENT_SETTING_BLOCK);
352 
353   // Schedule a cache update on the IO thread.
354   BrowserThread::PostTask(
355       BrowserThread::IO, FROM_HERE,
356       NewRunnableMethod(
357           prefs_cache_.get(),
358           &NotificationsPrefsCache::CacheDeniedOrigin,
359           origin));
360 }
361 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)362 void DesktopNotificationService::Observe(NotificationType type,
363                                          const NotificationSource& source,
364                                          const NotificationDetails& details) {
365   if (NotificationType::PREF_CHANGED == type) {
366     const std::string& name = *Details<std::string>(details).ptr();
367     OnPrefsChanged(name);
368   } else if (NotificationType::CONTENT_SETTINGS_CHANGED == type) {
369     // TODO(markusheintz): Check if content settings type default was changed;
370     const ContentSetting default_content_setting =
371         profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
372             CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
373     // Schedule a cache update on the IO thread.
374     BrowserThread::PostTask(
375         BrowserThread::IO, FROM_HERE,
376         NewRunnableMethod(
377             prefs_cache_.get(),
378             &NotificationsPrefsCache::SetCacheDefaultContentSetting,
379             default_content_setting));
380   } else if (NotificationType::EXTENSION_UNLOADED == type) {
381     // Remove all notifications currently shown or queued by the extension
382     // which was unloaded.
383     const Extension* extension =
384         Details<UnloadedExtensionInfo>(details)->extension;
385     if (extension)
386       ui_manager_->CancelAllBySourceOrigin(extension->url());
387   } else if (NotificationType::PROFILE_DESTROYED == type) {
388     StopObserving();
389   }
390 }
391 
OnPrefsChanged(const std::string & pref_name)392 void DesktopNotificationService::OnPrefsChanged(const std::string& pref_name) {
393   if (pref_name == prefs::kDesktopNotificationAllowedOrigins) {
394     // Schedule a cache update on the IO thread.
395     std::vector<GURL> allowed_origins(GetAllowedOrigins());
396     BrowserThread::PostTask(
397         BrowserThread::IO, FROM_HERE,
398         NewRunnableMethod(
399             prefs_cache_.get(),
400             &NotificationsPrefsCache::SetCacheAllowedOrigins,
401             allowed_origins));
402   } else if (pref_name == prefs::kDesktopNotificationDeniedOrigins) {
403     // Schedule a cache update on the IO thread.
404     std::vector<GURL> denied_origins(GetBlockedOrigins());
405     BrowserThread::PostTask(
406         BrowserThread::IO, FROM_HERE,
407         NewRunnableMethod(
408             prefs_cache_.get(),
409             &NotificationsPrefsCache::SetCacheDeniedOrigins,
410             denied_origins));
411   } else {
412     NOTREACHED();
413   }
414 }
415 
GetDefaultContentSetting()416 ContentSetting DesktopNotificationService::GetDefaultContentSetting() {
417   return profile_->GetHostContentSettingsMap()->GetDefaultContentSetting(
418       CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
419 }
420 
SetDefaultContentSetting(ContentSetting setting)421 void DesktopNotificationService::SetDefaultContentSetting(
422     ContentSetting setting) {
423   profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
424       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, setting);
425 }
426 
IsDefaultContentSettingManaged() const427 bool DesktopNotificationService::IsDefaultContentSettingManaged() const {
428   return profile_->GetHostContentSettingsMap()->IsDefaultContentSettingManaged(
429       CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
430 }
431 
ResetToDefaultContentSetting()432 void DesktopNotificationService::ResetToDefaultContentSetting() {
433   profile_->GetHostContentSettingsMap()->SetDefaultContentSetting(
434       CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_DEFAULT);
435 }
436 
GetAllowedOrigins()437 std::vector<GURL> DesktopNotificationService::GetAllowedOrigins() {
438   content_settings::ProviderInterface::Rules content_setting_rules;
439   provider_->GetAllContentSettingsRules(
440       CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
441       NO_RESOURCE_IDENTIFIER,
442       &content_setting_rules);
443   std::vector<GURL> allowed_origins;
444 
445   GetOriginsWithSettingFromContentSettingsRules(
446       content_setting_rules, CONTENT_SETTING_ALLOW, &allowed_origins);
447 
448   return allowed_origins;
449 }
450 
GetBlockedOrigins()451 std::vector<GURL> DesktopNotificationService::GetBlockedOrigins() {
452   content_settings::ProviderInterface::Rules content_settings_rules;
453   provider_->GetAllContentSettingsRules(
454       CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
455       NO_RESOURCE_IDENTIFIER,
456       &content_settings_rules);
457   std::vector<GURL> denied_origins;
458 
459   GetOriginsWithSettingFromContentSettingsRules(
460       content_settings_rules, CONTENT_SETTING_BLOCK, &denied_origins);
461 
462   return denied_origins;
463 }
464 
ResetAllowedOrigin(const GURL & origin)465 void DesktopNotificationService::ResetAllowedOrigin(const GURL& origin) {
466   ContentSettingsPattern pattern =
467       ContentSettingsPattern::FromURLNoWildcard(origin);
468   provider_->SetContentSetting(
469       pattern,
470       pattern,
471       CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
472       NO_RESOURCE_IDENTIFIER,
473       CONTENT_SETTING_DEFAULT);
474 }
475 
ResetBlockedOrigin(const GURL & origin)476 void DesktopNotificationService::ResetBlockedOrigin(const GURL& origin) {
477   ContentSettingsPattern pattern =
478       ContentSettingsPattern::FromURLNoWildcard(origin);
479   provider_->SetContentSetting(
480       pattern,
481       pattern,
482       CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
483       NO_RESOURCE_IDENTIFIER,
484       CONTENT_SETTING_DEFAULT);
485 }
486 
ResetAllOrigins()487 void DesktopNotificationService::ResetAllOrigins() {
488   provider_->ClearAllContentSettingsRules(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
489 }
490 
GetContentSetting(const GURL & origin)491 ContentSetting DesktopNotificationService::GetContentSetting(
492     const GURL& origin) {
493   ContentSetting provided_setting = provider_->GetContentSetting(
494       origin,
495       origin,
496       CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
497       NO_RESOURCE_IDENTIFIER);
498   if (CONTENT_SETTING_DEFAULT == provided_setting)
499     return GetDefaultContentSetting();
500   return provided_setting;
501 }
502 
RequestPermission(const GURL & origin,int process_id,int route_id,int callback_context,TabContents * tab)503 void DesktopNotificationService::RequestPermission(
504     const GURL& origin, int process_id, int route_id, int callback_context,
505     TabContents* tab) {
506   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
507   if (!tab) {
508     Browser* browser = BrowserList::GetLastActive();
509     if (browser)
510       tab = browser->GetSelectedTabContents();
511   }
512 
513   if (!tab)
514     return;
515 
516   // If |origin| hasn't been seen before and the default content setting for
517   // notifications is "ask", show an infobar.
518   // The cache can only answer queries on the IO thread once it's initialized,
519   // so don't ask the cache.
520   ContentSetting setting = GetContentSetting(origin);
521   if (setting == CONTENT_SETTING_ASK) {
522     // Show an info bar requesting permission.
523     tab->AddInfoBar(new NotificationPermissionInfoBarDelegate(
524                         tab, origin, DisplayNameForOrigin(origin), process_id,
525                         route_id, callback_context));
526   } else {
527     // Notify renderer immediately.
528     RenderViewHost* host = RenderViewHost::FromID(process_id, route_id);
529     if (host) {
530       host->Send(new DesktopNotificationMsg_PermissionRequestDone(
531           route_id, callback_context));
532     }
533   }
534 }
535 
ShowNotification(const Notification & notification)536 void DesktopNotificationService::ShowNotification(
537     const Notification& notification) {
538   ui_manager_->Add(notification, profile_);
539 }
540 
CancelDesktopNotification(int process_id,int route_id,int notification_id)541 bool DesktopNotificationService::CancelDesktopNotification(
542     int process_id, int route_id, int notification_id) {
543   scoped_refptr<NotificationObjectProxy> proxy(
544       new NotificationObjectProxy(process_id, route_id, notification_id,
545                                   false));
546   return ui_manager_->CancelById(proxy->id());
547 }
548 
549 
ShowDesktopNotification(const DesktopNotificationHostMsg_Show_Params & params,int process_id,int route_id,DesktopNotificationSource source)550 bool DesktopNotificationService::ShowDesktopNotification(
551     const DesktopNotificationHostMsg_Show_Params& params,
552     int process_id, int route_id, DesktopNotificationSource source) {
553   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
554   const GURL& origin = params.origin;
555   NotificationObjectProxy* proxy =
556       new NotificationObjectProxy(process_id, route_id,
557                                   params.notification_id,
558                                   source == WorkerNotification);
559   GURL contents;
560   if (params.is_html) {
561     contents = params.contents_url;
562   } else {
563     // "upconvert" the string parameters to a data: URL.
564     contents = GURL(
565         CreateDataUrl(params.icon_url, params.title, params.body,
566                       params.direction));
567   }
568   Notification notification(
569       origin, contents, DisplayNameForOrigin(origin),
570       params.replace_id, proxy);
571   ShowNotification(notification);
572   return true;
573 }
574 
DisplayNameForOrigin(const GURL & origin)575 string16 DesktopNotificationService::DisplayNameForOrigin(
576     const GURL& origin) {
577   // If the source is an extension, lookup the display name.
578   if (origin.SchemeIs(chrome::kExtensionScheme)) {
579     ExtensionService* ext_service = profile_->GetExtensionService();
580     if (ext_service) {
581       const Extension* extension = ext_service->GetExtensionByURL(origin);
582       if (extension)
583         return UTF8ToUTF16(extension->name());
584     }
585   }
586   return UTF8ToUTF16(origin.host());
587 }
588 
NotifySettingsChange()589 void DesktopNotificationService::NotifySettingsChange() {
590   NotificationService::current()->Notify(
591       NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
592       Source<DesktopNotificationService>(this),
593       NotificationService::NoDetails());
594 }
595