diff options
author | johnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-12 05:44:26 +0000 |
---|---|---|
committer | johnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-12 05:44:26 +0000 |
commit | 4bb33630869981809c47c36c3c18813d6b005d34 (patch) | |
tree | 505252dfeac2de2d02a89d1f7e69ffcdf4affcf5 /chrome | |
parent | a93244407e205a8619d620ce91bafbdf88eab195 (diff) | |
download | chromium_src-4bb33630869981809c47c36c3c18813d6b005d34.zip chromium_src-4bb33630869981809c47c36c3c18813d6b005d34.tar.gz chromium_src-4bb33630869981809c47c36c3c18813d6b005d34.tar.bz2 |
Browser side support (sans UI) for desktop notifications.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/194108
Review URL: http://codereview.chromium.org/271052
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@28696 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
28 files changed, 1124 insertions, 5 deletions
diff --git a/chrome/app/chromium_strings.grd b/chrome/app/chromium_strings.grd index 05cdf36..da38b89 100644 --- a/chrome/app/chromium_strings.grd +++ b/chrome/app/chromium_strings.grd @@ -362,6 +362,9 @@ be available for now. --> <message name="IDS_DEFAULT_BROWSER_INFOBAR_SHORT_TEXT" desc="More compact text to show in the default browser query infobar."> Chromium isn't your default browser. </message> + <message name="IDS_NOTIFICATION_PERMISSIONS" desc="Text requesting permission for desktop notifications."> + Allow <ph name="site">$1<ex>mail.google.com</ex></ph> to show desktop notifications? + </message> <if expr="os == 'darwin'"> <message name="IDS_SHORT_PRODUCT_NAME" desc="The application's short name, used for the Mac's application menu, activity monitor, etc. This should be less than 16 characters. Example: Chrome, not Google Chrome."> Chromium diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 0ec8bbe..8015426 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -5333,6 +5333,20 @@ Keep your key file in a safe place. You will need it to create new versions of y Your login details are out of date. Click to re-enter your password. </message> + <!-- Desktop notifications -->
+ <message name="IDS_NOTIFICATION_BALLOON_DISMISS_LABEL" desc="Text on the button which dismisses the balloon.">
+ Dismiss
+ </message>
+ <message name="IDS_NOTIFICATION_BALLOON_SOURCE_LABEL" desc="Text which labels the balloon with the source origin.">
+ from <ph name="SOURCE_ORIGIN">$1</ph>
+ </message>
+ <message name="IDS_NOTIFICATION_PERMISSION_YES" desc="The label of the 'allow' button on the notification permission infobar.">
+ Allow
+ </message>
+ <message name="IDS_NOTIFICATION_PERMISSION_NO" desc="The label of the 'deny' button on the notification permission infobar.">
+ Deny
+ </message>
+ <!-- Mac Menubar Menus --> <if expr="os == 'darwin'"> <!-- Menubar Menu Titles --> diff --git a/chrome/browser/automation/automation_profile_impl.h b/chrome/browser/automation/automation_profile_impl.h index dc57f9b..c464f73 100644 --- a/chrome/browser/automation/automation_profile_impl.h +++ b/chrome/browser/automation/automation_profile_impl.h @@ -168,6 +168,9 @@ class AutomationProfileImpl : public Profile { virtual BookmarkModel* GetBookmarkModel() { return original_profile_->GetBookmarkModel(); } + virtual DesktopNotificationService* GetDesktopNotificationService() { + return original_profile_->GetDesktopNotificationService(); + } #ifdef CHROME_PERSONALIZATION virtual ProfileSyncService* GetProfileSyncService() { diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd index fc6d70f..5fba870 100644 --- a/chrome/browser/browser_resources.grd +++ b/chrome/browser/browser_resources.grd @@ -52,6 +52,7 @@ without changes to the corresponding grd file. ek --> <include name="IDR_BLACKLIST_HTML" file="resources\privacy_blacklist_block.html" flattenhtml="true" type="BINDATA" /> <include name="IDR_BLACKLIST_IMAGE" file="resources\privacy_blacklist_block.png" type="BINDATA" /> <include name="IDR_DEFAULT_EXTENSION_ICON_128" file="resources\default_extension_icon_128.png" type="BINDATA" /> + <include name="IDR_NOTIFICATION_HTML" file="resources\notification.html" type="BINDATA" /> </includes> </release> </grit> diff --git a/chrome/browser/notifications/balloons.h b/chrome/browser/notifications/balloons.h new file mode 100644 index 0000000..6191d53 --- /dev/null +++ b/chrome/browser/notifications/balloons.h @@ -0,0 +1,200 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Handles the visible notification (or balloons). + +#ifndef CHROME_BROWSER_NOTIFICATIONS_BALLOONS_H_ +#define CHROME_BROWSER_NOTIFICATIONS_BALLOONS_H_ + +#include <deque> +#include <vector> + +#include "base/basictypes.h" +#include "base/gfx/point.h" +#include "base/gfx/rect.h" +#include "base/gfx/size.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/notifications/notification.h" + +class Balloon; +class BalloonView; +class Profile; +class SiteInstance; + +class BalloonCloseListener { + public: + virtual ~BalloonCloseListener() { } + + // Called when a balloon is closed. + virtual void OnBalloonClosed(Balloon* source) = 0; +}; + +class BalloonSpaceChangeListener { + public: + virtual ~BalloonSpaceChangeListener() { } + + // Called when there is more or less space for balloons due to + // monitor size changes or balloons disappearing. + virtual void OnBalloonSpaceChanged() = 0; +}; + +class BalloonCollectionInterface { + public: + virtual ~BalloonCollectionInterface() {} + + // Adds a new balloon for the specified notification. + virtual void Add(const Notification& notification, + Profile* profile, + SiteInstance* site_instance) = 0; + + // Is there room to add another notification? + virtual bool HasSpace() const = 0; +}; + +typedef std::deque<Balloon*> Balloons; + +// Represents a Notification on the screen. +class Balloon { + public: + Balloon(const Notification& notification, + Profile* profile, + SiteInstance* site_instance, + BalloonCloseListener* listener); + ~Balloon(); + + const Notification& notification() const { + return notification_; + } + + Profile* profile() const { + return profile_; + } + + SiteInstance* site_instance() const { + return site_instance_; + } + + void SetPosition(const gfx::Point& upper_left, bool reposition); + void SetSize(const gfx::Size& size); + void Show(); + void Close(); + + const gfx::Point& position() const; + const gfx::Size& size() const; + + private: + Profile* profile_; + SiteInstance* site_instance_; + Notification notification_; + BalloonCloseListener* close_listener_; + scoped_ptr<BalloonView> balloon_view_; + gfx::Point position_; + gfx::Size size_; + DISALLOW_COPY_AND_ASSIGN(Balloon); +}; + +class BalloonCollection : public BalloonCollectionInterface, + public BalloonCloseListener { + public: + explicit BalloonCollection(); + + BalloonSpaceChangeListener* space_change_listener() { return listener_; } + void set_space_change_listener(BalloonSpaceChangeListener* listener) { + listener_ = listener; + } + + // BalloonCollectionInterface overrides + virtual void Add(const Notification& notification, + Profile* profile, + SiteInstance* site_instance); + virtual void ShowAll(); + virtual void HideAll(); + virtual bool HasSpace() const; + + // BalloonCloseListener interface + virtual void OnBalloonClosed(Balloon* source); + + protected: + // Overridable by unit tests. + virtual Balloon* MakeBalloon(const Notification& notification, + Profile* profile, + SiteInstance* site_instance) { + return new Balloon(notification, profile, site_instance, this); + } + + private: + // The number of balloons being displayed. + int count() const { return balloons_.size(); } + + // Calculates layout values for the balloons including + // the scaling, the max/min sizes, and the upper left corner of each. + class Layout { + public: + Layout(); + + // Refresh the work area and balloon placement. + void OnDisplaySettingsChanged(); + + int min_balloon_width() const; + int max_balloon_width() const; + int min_balloon_height() const; + int max_balloon_height() const; + + // Returns both the total length available and the maximum + // allowed per balloon. + // + // The length may be a height or length depending on the way that + // balloons are laid out. + const void GetMaxLengths(int* max_balloon_length, int* total_length) const; + + // Scale the size to count in the system font factor. + int ScaleSize(int size) const; + + // Refresh the cached values for work area and drawing metrics. + // This is done automatically first time and the application should + // call this method to re-acquire metrics after any + // resolution or settings change. + // + // Return true if and only if a metric changed. + bool RefreshSystemMetrics(); + + // Returns the starting value for NextUpperLeftPosition. + gfx::Point GetStartPosition() const; + + // Compute the position for the next balloon. + // Modifies origin. + // Returns the position of the upper left coordinate for the given + // balloon. + gfx::Point NextPosition(const gfx::Size& balloon_size, + gfx::Point* origin) const; + + private: + enum Placement { + HORIZONTALLY_FROM_BOTTOM_LEFT, + HORIZONTALLY_FROM_BOTTOM_RIGHT, + VERTICALLY_FROM_TOP_RIGHT, + VERTICALLY_FROM_BOTTOM_RIGHT + }; + + // Minimum and maximum size of balloon + static const int kBalloonMinWidth = 300; + static const int kBalloonMaxWidth = 300; + static const int kBalloonMinHeight = 90; + static const int kBalloonMaxHeight = 120; + + static Placement placement_; + gfx::Rect work_area_; + double font_scale_factor_; + DISALLOW_COPY_AND_ASSIGN(Layout); + }; + + // Non-owned pointer to an object listening for space changes. + BalloonSpaceChangeListener* listener_; + + Balloons balloons_; + Layout layout_; + DISALLOW_COPY_AND_ASSIGN(BalloonCollection); +}; + +#endif // CHROME_BROWSER_NOTIFICATIONS_BALLOONS_H_ diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc new file mode 100644 index 0000000..0df73d7 --- /dev/null +++ b/chrome/browser/notifications/desktop_notification_service.cc @@ -0,0 +1,234 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/notifications/desktop_notification_service.h" + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "base/thread.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/notifications/notification.h" +#include "chrome/browser/notifications/notification_object_proxy.h" +#include "chrome/browser/notifications/notifications_prefs_cache.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/renderer_host/render_process_host.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/browser/renderer_host/site_instance.h" +#include "chrome/browser/tab_contents/infobar_delegate.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/browser/worker_host/worker_process_host.h" +#include "chrome/common/child_process_host.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/pref_service.h" +#include "chrome/common/render_messages.h" +#include "webkit/api/public/WebNotificationPresenter.h" +#include "grit/chromium_strings.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" + +using WebKit::WebNotificationPresenter; + +// A task object which calls the renderer to inform the web page that the +// permission request has completed. +class NotificationPermissionCallbackTask : public Task { + public: + NotificationPermissionCallbackTask(int process_id, int route_id, + int request_id) + : process_id_(process_id), + route_id_(route_id), + request_id_(request_id) { + } + + virtual void Run() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + RenderViewHost* host = RenderViewHost::FromID(process_id_, route_id_); + if (host) + host->Send(new ViewMsg_PermissionRequestDone(route_id_, request_id_)); + } + + private: + int process_id_; + int route_id_; + int request_id_; +}; + +// The delegate for the infobar shown when an origin requests notification +// permissions. +class NotificationPermissionInfoBarDelegate : public ConfirmInfoBarDelegate { + public: + NotificationPermissionInfoBarDelegate(TabContents* contents, + const GURL& origin, + int callback_context) + : ConfirmInfoBarDelegate(contents), + origin_(origin), + profile_(contents->profile()), + process_id_(contents->process()->id()), + route_id_(contents->render_view_host()->routing_id()), + callback_context_(callback_context), + action_taken_(false) { + } + + // Overridden from ConfirmInfoBarDelegate: + virtual void InfoBarClosed() { + if (!action_taken_) + UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Ignored", 1); + + base::Thread* io_thread = g_browser_process->io_thread(); + if (io_thread && io_thread->message_loop()) { + io_thread->message_loop()->PostTask(FROM_HERE, + new NotificationPermissionCallbackTask(process_id_, route_id_, + callback_context_)); + } + + delete this; + } + + virtual std::wstring GetMessageText() const { + return l10n_util::GetStringF(IDS_NOTIFICATION_PERMISSIONS, + UTF8ToWide(origin_.spec())); + } + + virtual SkBitmap* GetIcon() const { + return ResourceBundle::GetSharedInstance().GetBitmapNamed( + IDR_PRODUCT_ICON_32); + } + + virtual int GetButtons() const { + return BUTTON_OK | BUTTON_CANCEL | BUTTON_OK_DEFAULT; + } + + virtual std::wstring GetButtonLabel(InfoBarButton button) const { + return button == BUTTON_OK ? + l10n_util::GetString(IDS_NOTIFICATION_PERMISSION_YES) : + l10n_util::GetString(IDS_NOTIFICATION_PERMISSION_NO); + } + + virtual bool Accept() { + UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Allowed", 1); + profile_->GetDesktopNotificationService()->GrantPermission(origin_); + action_taken_ = true; + return true; + } + + virtual bool Cancel() { + UMA_HISTOGRAM_COUNTS("NotificationPermissionRequest.Denied", 1); + profile_->GetDesktopNotificationService()->DenyPermission(origin_); + action_taken_ = true; + return true; + } + + private: + // The origin we are asking for permissions on. + GURL origin_; + + // The Profile that we restore sessions from. + Profile* profile_; + + // The callback information that tells us how to respond to javascript via + // the correct RenderView. + int process_id_; + int route_id_; + int callback_context_; + + // Whether the user clicked one of the buttons. + bool action_taken_; + + DISALLOW_COPY_AND_ASSIGN(NotificationPermissionInfoBarDelegate); +}; + +DesktopNotificationService::DesktopNotificationService(Profile* profile, + NotificationUIManager* ui_manager) + : profile_(profile), + ui_manager_(ui_manager) { + InitPrefs(); +} + +DesktopNotificationService::~DesktopNotificationService() { +} + +// Initialize the cache with the allowed and denied origins, or +// create the preferences if they don't exist yet. +void DesktopNotificationService::InitPrefs() { + PrefService* prefs = profile_->GetPrefs(); + ListValue* allowed_sites = NULL; + ListValue* denied_sites = NULL; + + if (prefs->FindPreference(prefs::kDesktopNotificationAllowedOrigins)) + allowed_sites = + prefs->GetMutableList(prefs::kDesktopNotificationAllowedOrigins); + else + prefs->RegisterListPref(prefs::kDesktopNotificationAllowedOrigins); + + if (prefs->FindPreference(prefs::kDesktopNotificationDeniedOrigins)) + denied_sites = + prefs->GetMutableList(prefs::kDesktopNotificationDeniedOrigins); + else + prefs->RegisterListPref(prefs::kDesktopNotificationDeniedOrigins); + + prefs_cache_ = new NotificationsPrefsCache(allowed_sites, denied_sites); +} + +void DesktopNotificationService::GrantPermission(const GURL& origin) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + PrefService* prefs = profile_->GetPrefs(); + ListValue* allowed_sites = + prefs->GetMutableList(prefs::kDesktopNotificationAllowedOrigins); + ListValue* denied_sites = + prefs->GetMutableList(prefs::kDesktopNotificationDeniedOrigins); + // Remove from the black-list and add to the white-list. + StringValue* value = new StringValue(origin.spec()); + denied_sites->Remove(*value); + allowed_sites->Append(value); + prefs->ScheduleSavePersistentPrefs(); + + // Schedule a cache update on the IO thread. + base::Thread* io_thread = g_browser_process->io_thread(); + if (io_thread && io_thread->message_loop()) { + io_thread->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(prefs_cache_.get(), + &NotificationsPrefsCache::CacheAllowedOrigin, + origin)); + } +} + +void DesktopNotificationService::DenyPermission(const GURL& origin) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + PrefService* prefs = profile_->GetPrefs(); + ListValue* allowed_sites = + prefs->GetMutableList(prefs::kDesktopNotificationAllowedOrigins); + ListValue* denied_sites = + prefs->GetMutableList(prefs::kDesktopNotificationDeniedOrigins); + StringValue* value = new StringValue(origin.spec()); + // Remove from the white-list and add to the black-list. + allowed_sites->Remove(*value); + denied_sites->Append(value); + prefs->ScheduleSavePersistentPrefs(); + + // Schedule a cache update on the IO thread. + base::Thread* io_thread = g_browser_process->io_thread(); + if (io_thread && io_thread->message_loop()) { + io_thread->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(prefs_cache_.get(), + &NotificationsPrefsCache::CacheDeniedOrigin, + origin)); + } +} + +void DesktopNotificationService::RequestPermission( + const GURL& origin, int callback_context) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + // Show an info bar requesting permission. + Browser* browser = BrowserList::GetLastActive(); + if (!browser) { + // Reached during ui tests. + return; + } + TabContents* tab = browser->GetSelectedTabContents(); + if (!tab) + return; + tab->AddInfoBar(new NotificationPermissionInfoBarDelegate(tab, origin, + callback_context)); +} diff --git a/chrome/browser/notifications/desktop_notification_service.h b/chrome/browser/notifications/desktop_notification_service.h new file mode 100644 index 0000000..38e0b27 --- /dev/null +++ b/chrome/browser/notifications/desktop_notification_service.h @@ -0,0 +1,78 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_NOTIFICATIONS_DESKTOP_NOTIFICATION_SERVICE_H +#define CHROME_BROWSER_NOTIFICATIONS_DESKTOP_NOTIFICATION_SERVICE_H + +#include <set> + +#include "base/basictypes.h" +#include "chrome/browser/notifications/notification.h" +#include "googleurl/src/gurl.h" + +class NotificationUIManager; +class NotificationsPrefsCache; +class PrefService; +class Profile; +class Task; + +// The DesktopNotificationService is an object, owned by the Profile, +// which provides the creation of desktop "toasts" to web pages and workers. +class DesktopNotificationService { + public: + enum NotificationSource { + PageNotification, + WorkerNotification + }; + + DesktopNotificationService(Profile* profile, + NotificationUIManager* ui_manager); + ~DesktopNotificationService(); + + // Requests permission (using an info-bar) for a given origin. + // |callback_context| contains an opaque value to pass back to the + // requesting process when the info-bar finishes. + void RequestPermission(const GURL& origin, int callback_context); + + // Takes a notification object and shows it in the UI. + void ShowNotification(const Notification& notification); + + // Two ShowNotification methods: getting content either from remote + // URL or as local parameters. These are called on the UI thread + // in response to IPCs from a child process running script. |origin| + // is the origin of the script. |source| indicates whether the + // script is in a worker or page. |notification_id| is an opaque + // value to be passed back to the process when events occur on + // this notification. + bool ShowDesktopNotification(const GURL& origin, const GURL& url, + int process_id, int route_id, NotificationSource source, + int notification_id); + bool ShowDesktopNotificationText(const GURL& origin, const GURL& icon, + const string16& title, const string16& text, int process_id, + int route_id, NotificationSource source, int notification_id); + + // Methods to setup and modify permission preferences. + void GrantPermission(const GURL& origin); + void DenyPermission(const GURL& origin); + + NotificationsPrefsCache* prefs_cache() { return prefs_cache_; } + + private: + void InitPrefs(); + + // The profile which owns this object. + Profile* profile_; + + // A cache of preferences which is accessible only on the IO thread + // to service synchronous IPCs. + scoped_refptr<NotificationsPrefsCache> prefs_cache_; + + // Non-owned pointer to the notification manager which manages the + // UI for desktop toasts. + NotificationUIManager* ui_manager_; + + DISALLOW_COPY_AND_ASSIGN(DesktopNotificationService); +}; + +#endif // #ifndef CHROME_BROWSER_NOTIFICATIONS_DESKTOP_NOTIFICATION_SERVICE_H diff --git a/chrome/browser/notifications/desktop_notification_service_linux.cc b/chrome/browser/notifications/desktop_notification_service_linux.cc new file mode 100644 index 0000000..15148ce --- /dev/null +++ b/chrome/browser/notifications/desktop_notification_service_linux.cc @@ -0,0 +1,30 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/notifications/desktop_notification_service.h" + +bool DesktopNotificationService::ShowDesktopNotification( + const GURL& url, + const GURL&, + int process_id, + int route_id, + NotificationSource source, + int notification_id) { + // TODO(johnnyg): http://crbug.com/23954 Linux support coming soon. + return false; +} + +bool DesktopNotificationService::ShowDesktopNotificationText( + const GURL& origin, + const GURL& url, + const string16& title, + const string16& text, + int process_id, + int route_id, + NotificationSource source, + int notification_id) { + // TODO(johnnyg): http://crbug.com/23066 Linux support coming soon. + // Coming soon. + return false; +} diff --git a/chrome/browser/notifications/desktop_notification_service_mac.mm b/chrome/browser/notifications/desktop_notification_service_mac.mm new file mode 100644 index 0000000..42473c4 --- /dev/null +++ b/chrome/browser/notifications/desktop_notification_service_mac.mm @@ -0,0 +1,30 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/notifications/desktop_notification_service.h" + +bool DesktopNotificationService::ShowDesktopNotification( + const GURL& url, + const GURL&, + int process_id, + int route_id, + NotificationSource source, + int notification_id) { + // TODO(johnnyg): http://crbug.com/23066 Mac support coming soon. + return false; +} + +bool DesktopNotificationService::ShowDesktopNotificationText( + const GURL& origin, + const GURL& url, + const string16& title, + const string16& text, + int process_id, + int route_id, + NotificationSource source, + int notification_id) { + // TODO(johnnyg): http://crbug.com/23066 Integration with Growl will go here + // Coming soon. + return false; +} diff --git a/chrome/browser/notifications/desktop_notification_service_win.cc b/chrome/browser/notifications/desktop_notification_service_win.cc new file mode 100644 index 0000000..41e3e29 --- /dev/null +++ b/chrome/browser/notifications/desktop_notification_service_win.cc @@ -0,0 +1,97 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/notifications/desktop_notification_service.h" + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" +#include "base/string_piece.h" +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/browser/browser_list.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/notifications/notification_object_proxy.h" +#include "chrome/browser/renderer_host/render_process_host.h" +#include "chrome/browser/renderer_host/site_instance.h" +#include "chrome/browser/worker_host/worker_process_host.h" +#include "chrome/common/child_process_host.h" +#include "grit/browser_resources.h" +#include "grit/generated_resources.h" + +// Creates a data:xxxx URL which contains the full HTML for a notification +// using supplied icon, title, and text, run through a template which contains +// the standard formatting for notifications. +static string16 CreateDataUrl(const GURL& icon_url, const string16& title, + const string16& body) { + const base::StringPiece template_html( + ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_NOTIFICATION_HTML)); + + if (template_html.empty()) { + NOTREACHED() << "unable to load template. ID: " << IDR_NOTIFICATION_HTML; + return EmptyString16(); + } + + std::vector<string16> subst; + if (icon_url.is_valid()) + subst.push_back(UTF8ToUTF16(icon_url.spec())); + else + subst.push_back(EmptyString16()); + + subst.push_back(title); + subst.push_back(body); + + if (icon_url.is_valid()) { + subst.push_back(ASCIIToUTF16("block")); + subst.push_back(ASCIIToUTF16("60")); + } else { + subst.push_back(ASCIIToUTF16("none")); + subst.push_back(ASCIIToUTF16("5")); + } + + string16 format_string = ASCIIToUTF16("data:text/html;charset=utf-8," + + template_html.as_string()); + return ReplaceStringPlaceholders(format_string, subst, NULL); +} + +// This will call the notification manager on the UI thread to actually +// put the notification with the requested parameters on the desktop. +void DesktopNotificationService::ShowNotification( + const Notification& notification) { + SiteInstance* site_instance = SiteInstance::CreateSiteInstance(profile_); + // TODO(johnnyg): When UI Manager is available, add from here. + // ui_manager_->Add(notification, profile_, site_instance); +} + +// Shows a notification bubble which contains the contents of url. +bool DesktopNotificationService::ShowDesktopNotification( + const GURL& origin, const GURL& url, int process_id, int route_id, + NotificationSource source, int notification_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + NotificationObjectProxy* proxy = + new NotificationObjectProxy(process_id, route_id, + notification_id, + source == WorkerNotification); + Notification notif(origin, url, proxy); + ShowNotification(notif); + return true; +} + +// Shows a notification constructed from an icon, title, and text. +bool DesktopNotificationService::ShowDesktopNotificationText( + const GURL& origin, const GURL& icon, const string16& title, + const string16& text, int process_id, int route_id, + NotificationSource source, int notification_id) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + NotificationObjectProxy* proxy = + new NotificationObjectProxy(process_id, route_id, + notification_id, + source == WorkerNotification); + // "upconvert" the string parameters to a data: URL. + string16 data_url = CreateDataUrl(icon, title, text); + Notification notif(origin, GURL(data_url), proxy); + ShowNotification(notif); + return true; +} + diff --git a/chrome/browser/notifications/notification.h b/chrome/browser/notifications/notification.h new file mode 100644 index 0000000..ed63e04 --- /dev/null +++ b/chrome/browser/notifications/notification.h @@ -0,0 +1,58 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_H_ +#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_H_ + +#include "base/basictypes.h" +#include "chrome/browser/notifications/notification_object_proxy.h" +#include "googleurl/src/gurl.h" + +// Representation of an notification to be shown to the user. All +// notifications at this level are HTML, although they may be +// data: URLs representing simple text+icon notifications. +class Notification { + public: + Notification(const GURL& origin_url, const GURL& content_url, + NotificationObjectProxy* proxy) + : origin_url_(origin_url), + content_url_(content_url), + proxy_(proxy) { + } + + Notification(const Notification& notification) + : origin_url_(notification.origin_url()), + content_url_(notification.content_url()), + proxy_(notification.proxy()) { + } + + // The URL (may be data:) containing the contents for the notification. + const GURL& content_url() const { return content_url_; } + + // The origin URL of the script which requested the notification. + const GURL& origin_url() const { return origin_url_; } + + void Display() const { proxy()->Display(); } + void Error() const { proxy()->Error(); } + void Close(bool by_user) const { proxy()->Close(by_user); } + + private: + NotificationObjectProxy* proxy() const { return proxy_.get(); } + + // The Origin of the page/worker which created this notification. + GURL origin_url_; + + // The URL of the HTML content of the toast (may be a data: URL for simple + // string-based notifications). + GURL content_url_; + + // A proxy object that allows access back to the JavaScript object that + // represents the notification, for firing events. + scoped_refptr<NotificationObjectProxy> proxy_; + + // Disallow assign. Copy constructor written above. + void operator=(const Notification&); +}; + +#endif // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_H_ diff --git a/chrome/browser/notifications/notification_object_proxy.cc b/chrome/browser/notifications/notification_object_proxy.cc new file mode 100644 index 0000000..f230d19 --- /dev/null +++ b/chrome/browser/notifications/notification_object_proxy.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/notifications/notification_object_proxy.h" + +#include "base/message_loop.h" +#include "base/string16.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/renderer_host/render_view_host.h" +#include "chrome/common/render_messages.h" + +NotificationObjectProxy::NotificationObjectProxy(int process_id, int route_id, + int notification_id, bool worker) + : process_id_(process_id), + route_id_(route_id), + notification_id_(notification_id), + worker_(worker) { +} + +void NotificationObjectProxy::Display() { + if (worker_) { + // TODO(johnnyg): http://crbug.com/23065 Worker support coming soon. + NOTREACHED(); + } else { + DeliverMessage(new ViewMsg_PostDisplayToNotificationObject( + route_id_, notification_id_)); + } +} + +void NotificationObjectProxy::Error() { + if (worker_) { + // TODO(johnnyg): http://crbug.com/23065 Worker support coming soon. + NOTREACHED(); + } else { + DeliverMessage(new ViewMsg_PostErrorToNotificationObject( + route_id_, notification_id_, string16())); + } +} + +void NotificationObjectProxy::Close(bool by_user) { + if (worker_) { + // TODO(johnnyg): http://crbug.com/23065 Worker support coming soon. + NOTREACHED(); + } else { + DeliverMessage(new ViewMsg_PostCloseToNotificationObject( + route_id_, notification_id_, by_user)); + } +} + +void NotificationObjectProxy::DeliverMessage(IPC::Message* message) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + MessageLoop* io_loop = ChromeThread::GetMessageLoop(ChromeThread::IO); + if (io_loop) { + io_loop->PostTask(FROM_HERE, + NewRunnableMethod(this, &NotificationObjectProxy::Send, message)); + } +} + +// Deferred method which runs on the IO thread and sends a message to the +// proxied notification, routing it through the correct host in the browser. +void NotificationObjectProxy::Send(IPC::Message* message) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + RenderViewHost* host = RenderViewHost::FromID(process_id_, route_id_); + if (host) + host->Send(message); +} diff --git a/chrome/browser/notifications/notification_object_proxy.h b/chrome/browser/notifications/notification_object_proxy.h new file mode 100644 index 0000000..168bd8a --- /dev/null +++ b/chrome/browser/notifications/notification_object_proxy.h @@ -0,0 +1,51 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_OBJECT_PROXY_H_ +#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_OBJECT_PROXY_H_ + +#include "base/ref_counted.h" + +class MessageLoop; +namespace IPC { +class Message; +} + +// A NotificationObjectProxy stands in for the JavaScript Notification object +// which corresponds to a notification toast on the desktop. It can be signaled +// when various events occur regarding the desktop notification, and the +// attached JS listeners will be invoked in the renderer or worker process. +class NotificationObjectProxy : + public base::RefCountedThreadSafe<NotificationObjectProxy> { + public: + // Creates a Proxy object with the necessary callback information. + NotificationObjectProxy(int process_id, int route_id, + int notification_id, bool worker); + + // To be called when the desktop notification is actually shown. + void Display(); + + // To be called when the desktop notification cannot be shown due to an + // error. + void Error(); + + // To be called when the desktop notification is closed. If closed by a + // user explicitly (as opposed to timeout), |by_user| should be true. + void Close(bool by_user); + + private: + // Called on UI thread to schedule a message for sending. + void DeliverMessage(IPC::Message* message); + + // Called via Task on IO thread to actually send a message to a notification. + void Send(IPC::Message* message); + + // Callback information to find the JS Notification object where it lives. + int process_id_; + int route_id_; + int notification_id_; + bool worker_; +}; + +#endif // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_OBJECT_PROXY_H_ diff --git a/chrome/browser/notifications/notifications_prefs_cache.cc b/chrome/browser/notifications/notifications_prefs_cache.cc new file mode 100644 index 0000000..c5663e4 --- /dev/null +++ b/chrome/browser/notifications/notifications_prefs_cache.cc @@ -0,0 +1,67 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/notifications/notifications_prefs_cache.h" + +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/common/pref_service.h" +#include "webkit/api/public/WebNotificationPresenter.h" + +NotificationsPrefsCache::NotificationsPrefsCache( + ListValue* allowed, ListValue* denied) { + ListValue::const_iterator i; + std::wstring origin; + if (allowed) { + for (i = allowed->begin(); i != allowed->end(); ++i) { + (*i)->GetAsString(&origin); + allowed_origins_.insert(GURL(WideToUTF8(origin))); + } + } + if (denied) { + for (i = denied->begin(); i != denied->end(); ++i) { + (*i)->GetAsString(&origin); + denied_origins_.insert(GURL(WideToUTF8(origin))); + } + } +} + +void NotificationsPrefsCache::CacheAllowedOrigin( + const GURL& origin) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + std::set<GURL>::iterator iter; + allowed_origins_.insert(origin); + if ((iter = denied_origins_.find(origin)) != denied_origins_.end()) + denied_origins_.erase(iter); +} + +void NotificationsPrefsCache::CacheDeniedOrigin( + const GURL& origin) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + std::set<GURL>::iterator iter; + denied_origins_.insert(origin); + if ((iter = allowed_origins_.find(origin)) != allowed_origins_.end()) + allowed_origins_.erase(iter); +} + +int NotificationsPrefsCache::HasPermission(const GURL& origin) { + if (IsOriginAllowed(origin)) + return WebKit::WebNotificationPresenter::PermissionAllowed; + if (IsOriginDenied(origin)) + return WebKit::WebNotificationPresenter::PermissionDenied; + return WebKit::WebNotificationPresenter::PermissionNotAllowed; +} + +bool NotificationsPrefsCache::IsOriginAllowed( + const GURL& origin) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + return (allowed_origins_.find(origin) != allowed_origins_.end()); +} + +bool NotificationsPrefsCache::IsOriginDenied( + const GURL& origin) { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); + return (denied_origins_.find(origin) != denied_origins_.end()); +} diff --git a/chrome/browser/notifications/notifications_prefs_cache.h b/chrome/browser/notifications/notifications_prefs_cache.h new file mode 100644 index 0000000..e873da7 --- /dev/null +++ b/chrome/browser/notifications/notifications_prefs_cache.h @@ -0,0 +1,45 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATIONS_PREFS_CACHE_H +#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATIONS_PREFS_CACHE_H + +#include <set> + +#include "base/ref_counted.h" +#include "googleurl/src/gurl.h" + +class ListValue; + +// Class which caches notification preferences. +// Construction occurs on the UI thread when the contents +// of the profile preferences are initially cached. Once constructed +// this class should only be accessed on the IO thread. +class NotificationsPrefsCache : + public base::RefCountedThreadSafe<NotificationsPrefsCache> { + public: + NotificationsPrefsCache(ListValue* allowed, ListValue* denied); + + // Checks to see if a given origin has permission to create desktop + // notifications. Returns a constant from WebNotificationPresenter + // class. + int HasPermission(const GURL& origin); + + // Updates the cache with a new origin allowed or denied. + void CacheAllowedOrigin(const GURL& origin); + void CacheDeniedOrigin(const GURL& origin); + + private: + // Helper functions which read preferences. + bool IsOriginAllowed(const GURL& origin); + bool IsOriginDenied(const GURL& origin); + + // Storage of the actual preferences. + std::set<GURL> allowed_origins_; + std::set<GURL> denied_origins_; + + DISALLOW_COPY_AND_ASSIGN(NotificationsPrefsCache); +}; + +#endif // #ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATIONS_PREFS_CACHE_H diff --git a/chrome/browser/profile.cc b/chrome/browser/profile.cc index 4508644..87c9713 100644 --- a/chrome/browser/profile.cc +++ b/chrome/browser/profile.cc @@ -27,6 +27,7 @@ #include "chrome/browser/in_process_webkit/webkit_context.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/net/ssl_config_service_manager.h" +#include "chrome/browser/notifications/desktop_notification_service.h" #include "chrome/browser/password_manager/password_store_default.h" #include "chrome/browser/privacy_blacklist/blacklist.h" #include "chrome/browser/profile_manager.h" @@ -459,6 +460,10 @@ class OffTheRecordProfileImpl : public Profile, return profile_->GetBookmarkModel(); } + virtual DesktopNotificationService* GetDesktopNotificationService() { + return profile_->GetDesktopNotificationService(); + } + virtual ProfileSyncService* GetProfileSyncService() { return NULL; } @@ -1344,6 +1349,17 @@ WebKitContext* ProfileImpl::GetWebKitContext() { return webkit_context_.get(); } +DesktopNotificationService* ProfileImpl::GetDesktopNotificationService() { + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + if (!desktop_notification_service_.get()) { + // TODO(johnnyg): hook this up with notification UI manager. + desktop_notification_service_.reset(new DesktopNotificationService( + this, NULL)); + } + + return desktop_notification_service_.get(); +} + void ProfileImpl::MarkAsCleanShutdown() { if (prefs_.get()) { // The session cleanly exited, set kSessionExitedCleanly appropriately. diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index 07e5e34..a7107f4 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -30,6 +30,7 @@ class BookmarkModel; class BrowserThemeProvider; class ChromeAppCacheService; class ChromeURLRequestContext; +class DesktopNotificationService; class DownloadManager; class Extension; class ExtensionDevToolsManager; @@ -343,6 +344,9 @@ class Profile { // Returns the WebKitContext assigned to this profile. virtual WebKitContext* GetWebKitContext() = 0; + // Returns the provider of desktop notifications for this profile. + virtual DesktopNotificationService* GetDesktopNotificationService() = 0; + // Marks the profile as cleanly shutdown. // // NOTE: this is invoked internally on a normal shutdown, but is public so @@ -439,6 +443,7 @@ class ProfileImpl : public Profile, virtual SpellChecker* GetSpellChecker(); virtual void DeleteSpellChecker() { DeleteSpellCheckerImpl(true); } virtual WebKitContext* GetWebKitContext(); + virtual DesktopNotificationService* GetDesktopNotificationService(); virtual void MarkAsCleanShutdown(); virtual void InitExtensions(); virtual void InitWebResources(); @@ -520,6 +525,7 @@ class ProfileImpl : public Profile, scoped_refptr<SessionService> session_service_; scoped_ptr<BrowserThemeProvider> theme_provider_; scoped_refptr<WebKitContext> webkit_context_; + scoped_ptr<DesktopNotificationService> desktop_notification_service_; bool history_service_created_; bool favicon_service_created_; bool created_web_data_service_; diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index af14f52..cd9eb26 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -20,6 +20,7 @@ #include "chrome/browser/dom_operation_notification_details.h" #include "chrome/browser/extensions/extension_message_service.h" #include "chrome/browser/metrics/user_metrics.h" +#include "chrome/browser/notifications/desktop_notification_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/renderer_host/render_process_host.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" @@ -833,6 +834,12 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) { OnQueryFormFieldAutofill) IPC_MESSAGE_HANDLER(ViewHostMsg_RemoveAutofillEntry, OnRemoveAutofillEntry) + IPC_MESSAGE_HANDLER(ViewHostMsg_ShowDesktopNotification, + OnShowDesktopNotification) + IPC_MESSAGE_HANDLER(ViewHostMsg_ShowDesktopNotificationText, + OnShowDesktopNotificationText) + IPC_MESSAGE_HANDLER(ViewHostMsg_RequestNotificationPermission, + OnRequestNotificationPermission) IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionRequest, OnExtensionRequest) IPC_MESSAGE_HANDLER(ViewHostMsg_SelectionChanged, OnMsgSelectionChanged) IPC_MESSAGE_HANDLER(ViewHostMsg_ExtensionPostMessage, @@ -1644,6 +1651,32 @@ void RenderViewHost::ForwardMessageFromExternalHost(const std::string& message, target)); } +void RenderViewHost::OnShowDesktopNotification(const GURL& source_origin, + const GURL& url, int notification_id) { + DesktopNotificationService* service = + process()->profile()->GetDesktopNotificationService(); + service->ShowDesktopNotification(source_origin, url, process()->id(), + routing_id(), DesktopNotificationService::PageNotification, + notification_id); +} + +void RenderViewHost::OnShowDesktopNotificationText(const GURL& source_origin, + const GURL& icon, const string16& title, const string16& text, + int notification_id) { + DesktopNotificationService* service = + process()->profile()->GetDesktopNotificationService(); + service->ShowDesktopNotificationText(source_origin, icon, title, text, + process()->id(), routing_id(), + DesktopNotificationService::PageNotification, notification_id); +} + +void RenderViewHost::OnRequestNotificationPermission( + const GURL& source_origin, int callback_context) { + DesktopNotificationService* service = + process()->profile()->GetDesktopNotificationService(); + service->RequestPermission(source_origin, callback_context); +} + void RenderViewHost::OnExtensionRequest(const std::string& name, const ListValue& args_holder, int request_id, diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index 76b7460..7f24d97 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -577,6 +577,14 @@ class RenderViewHost : public RenderWidgetHost, void OnRemoveAutofillEntry(const std::wstring& field_name, const std::wstring& value); + void OnShowDesktopNotification(const GURL& source_origin, + const GURL& url, int notification_id); + void OnShowDesktopNotificationText(const GURL& origin, const GURL& icon, + const string16& title, + const string16& text, + int notification_id); + void OnRequestNotificationPermission(const GURL& origin, int callback_id); + void OnExtensionRequest(const std::string& name, const ListValue& args, int request_id, bool has_callback); void OnExtensionPostMessage(int port_id, const std::string& message); diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index 5645ef6..8927ab0 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -19,6 +19,8 @@ #include "chrome/browser/nacl_process_host.h" #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/net/dns_global.h" +#include "chrome/browser/notifications/desktop_notification_service.h" +#include "chrome/browser/notifications/notifications_prefs_cache.h" #include "chrome/browser/plugin_service.h" #include "chrome/browser/profile.h" #include "chrome/browser/privacy_blacklist/blacklist.h" @@ -167,6 +169,8 @@ ResourceMessageFilter::ResourceMessageFilter( resource_dispatcher_host->webkit_thread()))), ALLOW_THIS_IN_INITIALIZER_LIST(db_dispatcher_host_( new DatabaseDispatcherHost(profile->GetPath(), this))), + notification_prefs_( + profile->GetDesktopNotificationService()->prefs_cache()), off_the_record_(profile->IsOffTheRecord()), next_route_id_callback_(NewCallbackWithReturnValue( render_widget_helper, &RenderWidgetHelper::GetNextRoutingID)) { @@ -335,6 +339,8 @@ bool ResourceMessageFilter::OnMessageReceived(const IPC::Message& msg) { IPC_MESSAGE_HANDLER(ViewHostMsg_ClipboardFindPboardWriteStringAsync, OnClipboardFindPboardWriteString) #endif + IPC_MESSAGE_HANDLER(ViewHostMsg_CheckNotificationPermission, + OnCheckNotificationPermission) IPC_MESSAGE_HANDLER(ViewHostMsg_GetMimeTypeFromExtension, OnGetMimeTypeFromExtension) IPC_MESSAGE_HANDLER(ViewHostMsg_GetMimeTypeFromFile, @@ -690,6 +696,11 @@ void ResourceMessageFilter::OnClipboardReadHTML(Clipboard::Buffer buffer, #endif +void ResourceMessageFilter::OnCheckNotificationPermission( + const GURL& source_origin, int* result) { + *result = notification_prefs_->HasPermission(source_origin); +} + void ResourceMessageFilter::OnGetMimeTypeFromExtension( const FilePath::StringType& ext, std::string* mime_type) { net::GetMimeTypeFromExtension(ext, mime_type); diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index 8084e72..bcb5ece5 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -36,6 +36,7 @@ class AudioRendererHost; class DatabaseDispatcherHost; class DOMStorageDispatcherHost; class ExtensionMessageService; +class NotificationsPrefsCache; class Profile; class RenderWidgetHelper; class SpellChecker; @@ -191,6 +192,9 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, void OnClipboardFindPboardWriteString(const string16& text); #endif + void OnCheckNotificationPermission(const GURL& origin, + int* permission_level); + #if !defined(OS_MACOSX) // Not handled in the IO thread on Mac. void OnGetWindowRect(gfx::NativeViewId window, IPC::Message* reply); @@ -350,6 +354,10 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter, // Handles HTML5 DB related messages scoped_ptr<DatabaseDispatcherHost> db_dispatcher_host_; + // A cache of notifications preferences which is used to handle + // Desktop Notifications permission messages. + scoped_refptr<NotificationsPrefsCache> notification_prefs_; + // Whether this process is used for off the record tabs. bool off_the_record_; diff --git a/chrome/browser/resources/notification.html b/chrome/browser/resources/notification.html new file mode 100644 index 0000000..5e436e7 --- /dev/null +++ b/chrome/browser/resources/notification.html @@ -0,0 +1,36 @@ +<html> +<head> +<title>$2</title> +<style type="text/css"><!-- +#icon { +height:48px; +width:48px; +position:absolute; +top:2px; +left:2px; +display:$4; +} +#title { +font-weight:bold; +position:absolute; +top:3px; +left:$5px; +font-family:sans-serif; +font-size:11pt; +} +#body { +position:absolute; +left:$5px; +top:20px; +font-family:sans-serif; +font-size:9pt; +} +//--> +</style> +</head> +<body> +<div id="icon"><img src="$1" /></div> +<div id="title">$2</div> +<div id="body">$3</div> +</body> +</html> diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index eac73f5..3708a3a 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -1724,6 +1724,17 @@ 'browser/net/url_request_slow_http_job.h', 'browser/net/url_request_tracking.cc', 'browser/net/url_request_tracking.h', + 'browser/notifications/balloons.h', + 'browser/notifications/desktop_notification_service.cc', + 'browser/notifications/desktop_notification_service.h', + 'browser/notifications/desktop_notification_service_linux.cc', + 'browser/notifications/desktop_notification_service_mac.mm', + 'browser/notifications/desktop_notification_service_win.cc', + 'browser/notifications/notification.h', + 'browser/notifications/notification_object_proxy.cc', + 'browser/notifications/notification_object_proxy.h', + 'browser/notifications/notifications_prefs_cache.cc', + 'browser/notifications/notifications_prefs_cache.h', 'browser/ntp_background_util.cc', 'browser/ntp_background_util.h', 'browser/omnibox_search_hint.cc', diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index b1104da..ee03bc3 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -281,6 +281,12 @@ const wchar_t kShowOmniboxSearchHint[] = L"browser.show_omnibox_search_hint"; // in a session. const wchar_t kNTPThemePromoRemaining[] = L"browser.ntp.theme_promo_remaining"; +// The list of origins which are allowed|denied to show desktop notifications. +const wchar_t kDesktopNotificationAllowedOrigins[] = + L"profile.notification_allowed_sites"; +const wchar_t kDesktopNotificationDeniedOrigins[] = + L"profile.notification_denied_sites"; + // *************** LOCAL STATE *************** // These are attached to the machine/installation diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 01fb279..f6d62ea 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -112,6 +112,8 @@ extern const wchar_t kCheckDefaultBrowser[]; extern const wchar_t kUseCustomChromeFrame[]; extern const wchar_t kShowOmniboxSearchHint[]; extern const wchar_t kNTPThemePromoRemaining[]; +extern const wchar_t kDesktopNotificationAllowedOrigins[]; +extern const wchar_t kDesktopNotificationDeniedOrigins[]; // Local state extern const wchar_t kMetricsClientID[]; diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 2758c95..d29d41d 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1701,10 +1701,10 @@ IPC_BEGIN_MESSAGES(ViewHost) IPC_MESSAGE_ROUTED1(ViewHostMsg_CancelDesktopNotification, int /* notification_id */ ) IPC_MESSAGE_ROUTED2(ViewHostMsg_RequestNotificationPermission, - string16 /* origin */, + GURL /* origin */, int /* callback_context */) IPC_SYNC_MESSAGE_ROUTED1_1(ViewHostMsg_CheckNotificationPermission, - string16 /* origin */, + GURL /* origin */, int /* permission_result */) // Sent if the worker object has sent a ViewHostMsg_CreateDedicatedWorker diff --git a/chrome/renderer/notification_provider.cc b/chrome/renderer/notification_provider.cc index f6baba8..505349d 100644 --- a/chrome/renderer/notification_provider.cc +++ b/chrome/renderer/notification_provider.cc @@ -47,8 +47,8 @@ void NotificationProvider::objectDestroyed( WebNotificationPresenter::Permission NotificationProvider::checkPermission( const WebString& origin) { int permission; - Send(new ViewHostMsg_CheckNotificationPermission(view_->routing_id(), origin, - &permission)); + Send(new ViewHostMsg_CheckNotificationPermission(view_->routing_id(), + GURL(origin), &permission)); return static_cast<WebNotificationPresenter::Permission>(permission); } @@ -57,7 +57,7 @@ void NotificationProvider::requestPermission( int id = manager_.RegisterPermissionRequest(callback); Send(new ViewHostMsg_RequestNotificationPermission(view_->routing_id(), - origin, id)); + GURL(origin), id)); } bool NotificationProvider::ShowHTML(const WebNotification& notification, diff --git a/chrome/test/testing_profile.h b/chrome/test/testing_profile.h index 8f49917..ca10ebd 100644 --- a/chrome/test/testing_profile.h +++ b/chrome/test/testing_profile.h @@ -173,6 +173,9 @@ class TestingProfile : public Profile { virtual void MarkAsCleanShutdown() {} virtual void InitExtensions() {} virtual void InitWebResources() {} + virtual DesktopNotificationService* GetDesktopNotificationService() { + return NULL; + } // Schedules a task on the history backend and runs a nested loop until the // task is processed. This has the effect of blocking the caller until the |