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