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/browser/notifications | |
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/browser/notifications')
11 files changed, 958 insertions, 0 deletions
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 |