diff options
author | Ben Murdoch <benm@google.com> | 2011-01-07 14:18:56 +0000 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-01-11 10:23:13 +0000 |
commit | 201ade2fbba22bfb27ae029f4d23fca6ded109a0 (patch) | |
tree | b793f4ed916f73cf18357ea467ff3deb5ffb5b52 /chrome/browser/notifications | |
parent | d8c4c37a7d0961944bfdfaa117d5c68c8e129c97 (diff) | |
download | external_chromium-201ade2fbba22bfb27ae029f4d23fca6ded109a0.zip external_chromium-201ade2fbba22bfb27ae029f4d23fca6ded109a0.tar.gz external_chromium-201ade2fbba22bfb27ae029f4d23fca6ded109a0.tar.bz2 |
Merge chromium at 9.0.597.55: Initial merge by git.
Change-Id: Id686a88437441ec7e17abb3328a404c7b6c3c6ad
Diffstat (limited to 'chrome/browser/notifications')
22 files changed, 476 insertions, 134 deletions
diff --git a/chrome/browser/notifications/balloon.cc b/chrome/browser/notifications/balloon.cc index 96f3fca..d9f9111 100644 --- a/chrome/browser/notifications/balloon.cc +++ b/chrome/browser/notifications/balloon.cc @@ -9,6 +9,7 @@ #include "chrome/browser/notifications/notification.h" #include "chrome/browser/renderer_host/site_instance.h" #include "gfx/rect.h" +#include "gfx/size.h" Balloon::Balloon(const Notification& notification, Profile* profile, BalloonCollection* collection) diff --git a/chrome/browser/notifications/balloon_collection.cc b/chrome/browser/notifications/balloon_collection.cc index a125837..9d60626 100644 --- a/chrome/browser/notifications/balloon_collection.cc +++ b/chrome/browser/notifications/balloon_collection.cc @@ -45,7 +45,6 @@ BalloonCollectionImpl::BalloonCollectionImpl() } BalloonCollectionImpl::~BalloonCollectionImpl() { - STLDeleteElements(&balloons_); } void BalloonCollectionImpl::Add(const Notification& notification, @@ -59,10 +58,11 @@ void BalloonCollectionImpl::Add(const Notification& notification, new_balloon->SetPosition(layout_.OffScreenLocation(), false); new_balloon->Show(); #if USE_OFFSETS - if (balloons_.size() > 0) - new_balloon->set_offset(balloons_[balloons_.size() - 1]->offset()); + int count = base_.count(); + if (count > 0) + new_balloon->set_offset(base_.balloons()[count - 1]->offset()); #endif - balloons_.push_back(new_balloon); + base_.Add(new_balloon); PositionBalloons(false); // There may be no listener in a unit test. @@ -74,28 +74,28 @@ void BalloonCollectionImpl::Add(const Notification& notification, on_collection_changed_callback_->Run(); } -bool BalloonCollectionImpl::Remove(const Notification& notification) { - Balloons::iterator iter; - for (iter = balloons_.begin(); iter != balloons_.end(); ++iter) { - if (notification.IsSame((*iter)->notification())) { - // Balloon.CloseByScript() will cause OnBalloonClosed() to be called on - // this object, which will remove it from the collection and free it. - (*iter)->CloseByScript(); - return true; - } - } - return false; +bool BalloonCollectionImpl::RemoveById(const std::string& id) { + return base_.CloseById(id); +} + +bool BalloonCollectionImpl::RemoveBySourceOrigin(const GURL& origin) { + return base_.CloseAllBySourceOrigin(origin); +} + +void BalloonCollectionImpl::RemoveAll() { + base_.CloseAll(); } bool BalloonCollectionImpl::HasSpace() const { - if (count() < kMinAllowedBalloonCount) + int count = base_.count(); + if (count < kMinAllowedBalloonCount) return true; int max_balloon_size = 0; int total_size = 0; layout_.GetMaxLinearSize(&max_balloon_size, &total_size); - int current_max_size = max_balloon_size * count(); + int current_max_size = max_balloon_size * count; int max_allowed_size = static_cast<int>(total_size * kPercentBalloonFillFactor); return current_max_size < max_allowed_size - max_balloon_size; @@ -114,16 +114,16 @@ void BalloonCollectionImpl::DisplayChanged() { void BalloonCollectionImpl::OnBalloonClosed(Balloon* source) { // We want to free the balloon when finished. - scoped_ptr<Balloon> closed(source); - Balloons::iterator it = balloons_.begin(); + const Balloons& balloons = base_.balloons(); + Balloons::const_iterator it = balloons.begin(); #if USE_OFFSETS gfx::Point offset; bool apply_offset = false; - while (it != balloons_.end()) { + while (it != balloons.end()) { if (*it == source) { - it = balloons_.erase(it); - if (it != balloons_.end()) { + ++it; + if (it != balloons.end()) { apply_offset = true; offset.set_y((source)->offset().y() - (*it)->offset().y() + (*it)->content_size().height() - source->content_size().height()); @@ -138,15 +138,9 @@ void BalloonCollectionImpl::OnBalloonClosed(Balloon* source) { // leaves the balloon area. if (apply_offset) AddMessageLoopObserver(); -#else - for (; it != balloons_.end(); ++it) { - if (*it == source) { - balloons_.erase(it); - break; - } - } #endif + base_.Remove(source); PositionBalloons(true); // There may be no listener in a unit test. @@ -159,9 +153,13 @@ void BalloonCollectionImpl::OnBalloonClosed(Balloon* source) { } void BalloonCollectionImpl::PositionBalloonsInternal(bool reposition) { + const Balloons& balloons = base_.balloons(); + layout_.RefreshSystemMetrics(); gfx::Point origin = layout_.GetLayoutOrigin(); - for (Balloons::iterator it = balloons_.begin(); it != balloons_.end(); ++it) { + for (Balloons::const_iterator it = balloons.begin(); + it != balloons.end(); + ++it) { gfx::Point upper_left = layout_.NextPosition((*it)->GetViewSize(), &origin); (*it)->SetPosition(upper_left, reposition); } @@ -188,7 +186,10 @@ void BalloonCollectionImpl::CancelOffsets() { // Unhook from listening to all UI events. RemoveMessageLoopObserver(); - for (Balloons::iterator it = balloons_.begin(); it != balloons_.end(); ++it) + const Balloons& balloons = base_.balloons(); + for (Balloons::const_iterator it = balloons.begin(); + it != balloons.end(); + ++it) (*it)->set_offset(gfx::Point(0, 0)); PositionBalloons(true); diff --git a/chrome/browser/notifications/balloon_collection.h b/chrome/browser/notifications/balloon_collection.h index 499b937..13875dc 100644 --- a/chrome/browser/notifications/balloon_collection.h +++ b/chrome/browser/notifications/balloon_collection.h @@ -9,11 +9,13 @@ #pragma once #include <deque> +#include <string> #include "base/callback.h" #include "base/scoped_ptr.h" class Balloon; +class GURL; class Notification; class Profile; @@ -44,9 +46,16 @@ class BalloonCollection { virtual void Add(const Notification& notification, Profile* profile) = 0; - // Removes a balloon from the collection if present. Returns + // Removes any balloons that have this notification id. Returns // true if anything was removed. - virtual bool Remove(const Notification& notification) = 0; + virtual bool RemoveById(const std::string& id) = 0; + + // Removes any balloons that have this source origin. Returns + // true if anything was removed. + virtual bool RemoveBySourceOrigin(const GURL& source_origin) = 0; + + // Removes all balloons. + virtual void RemoveAll() = 0; // Is there room to add another notification? virtual bool HasSpace() const = 0; diff --git a/chrome/browser/notifications/balloon_collection_base.cc b/chrome/browser/notifications/balloon_collection_base.cc new file mode 100644 index 0000000..b0551dd --- /dev/null +++ b/chrome/browser/notifications/balloon_collection_base.cc @@ -0,0 +1,85 @@ +// Copyright (c) 2010 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/balloon_collection_base.h" + +#include "base/stl_util-inl.h" +#include "chrome/browser/notifications/balloon.h" +#include "chrome/browser/notifications/notification.h" +#include "googleurl/src/gurl.h" + +BalloonCollectionBase::BalloonCollectionBase() { +} + +BalloonCollectionBase::~BalloonCollectionBase() { + STLDeleteElements(&balloons_); +} + +void BalloonCollectionBase::Add(Balloon* balloon) { + balloons_.push_back(balloon); +} + +void BalloonCollectionBase::Remove(Balloon* balloon) { + // Free after removing. + scoped_ptr<Balloon> to_delete(balloon); + Balloons::iterator iter; + for (iter = balloons_.begin(); iter != balloons_.end(); ++iter) { + if ((*iter) == balloon) { + balloons_.erase(iter); + return; + } + } +} + +bool BalloonCollectionBase::CloseById(const std::string& id) { + // Use a local list of balloons to close to avoid breaking + // iterator changes on each close. + Balloons to_close; + Balloons::iterator iter; + for (iter = balloons_.begin(); iter != balloons_.end(); ++iter) { + if ((*iter)->notification().notification_id() == id) + to_close.push_back(*iter); + } + for (iter = to_close.begin(); iter != to_close.end(); ++iter) + (*iter)->CloseByScript(); + + return !to_close.empty(); +} + +bool BalloonCollectionBase::CloseAllBySourceOrigin( + const GURL& source_origin) { + // Use a local list of balloons to close to avoid breaking + // iterator changes on each close. + Balloons to_close; + Balloons::iterator iter; + for (iter = balloons_.begin(); iter != balloons_.end(); ++iter) { + if ((*iter)->notification().origin_url() == source_origin) + to_close.push_back(*iter); + } + for (iter = to_close.begin(); iter != to_close.end(); ++iter) + (*iter)->CloseByScript(); + + return !to_close.empty(); +} + +void BalloonCollectionBase::CloseAll() { + // Use a local list of balloons to close to avoid breaking + // iterator changes on each close. + Balloons to_close = balloons_; + for (Balloons::iterator iter = to_close.begin(); + iter != to_close.end(); ++iter) + (*iter)->CloseByScript(); +} + +Balloon* BalloonCollectionBase::FindBalloon( + const Notification& notification) { + Balloons::iterator iter; + for (iter = balloons_.begin(); iter != balloons_.end(); ++iter) { + if ((*iter)->notification().notification_id() == + notification.notification_id()) { + return *iter; + } + } + return NULL; +} diff --git a/chrome/browser/notifications/balloon_collection_base.h b/chrome/browser/notifications/balloon_collection_base.h new file mode 100644 index 0000000..c388ac9 --- /dev/null +++ b/chrome/browser/notifications/balloon_collection_base.h @@ -0,0 +1,65 @@ +// Copyright (c) 2010 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_BALLOON_COLLECTION_BASE_H_ +#define CHROME_BROWSER_NOTIFICATIONS_BALLOON_COLLECTION_BASE_H_ +#pragma once + +#include <deque> +#include <string> + +#include "base/basictypes.h" + +class Balloon; +class GURL; +class Notification; + +// This class provides support for implementing a BalloonCollection +// including the parts common between Chrome UI and ChromeOS UI. +class BalloonCollectionBase { + public: + BalloonCollectionBase(); + virtual ~BalloonCollectionBase(); + + typedef std::deque<Balloon*> Balloons; + + // Adds a balloon to the collection. Takes ownership of pointer. + virtual void Add(Balloon* balloon); + + // Removes a balloon from the collection (if present). Frees + // the pointer after removal. + virtual void Remove(Balloon* balloon); + + // Finds any balloon matching the given notification id, and + // calls CloseByScript on it. Returns true if anything was + // found. + virtual bool CloseById(const std::string& id); + + // Finds all balloons matching the given notification source, + // and calls CloseByScript on them. Returns true if anything + // was found. + virtual bool CloseAllBySourceOrigin(const GURL& source_origin); + + // Calls CloseByScript on all balloons. + virtual void CloseAll(); + + const Balloons& balloons() const { return balloons_; } + + // Returns the balloon matching the given notification, or + // NULL if there is no matching balloon. + Balloon* FindBalloon(const Notification& notification); + + // The number of balloons being displayed. + int count() const { return static_cast<int>(balloons_.size()); } + + private: + // Queue of active balloons. Pointers are owned by this class. + Balloons balloons_; + + DISALLOW_COPY_AND_ASSIGN(BalloonCollectionBase); +}; + +#endif // CHROME_BROWSER_NOTIFICATIONS_BALLOON_COLLECTION_BASE_H_ diff --git a/chrome/browser/notifications/balloon_collection_impl.h b/chrome/browser/notifications/balloon_collection_impl.h index a9c7afc..7fb1ea9 100644 --- a/chrome/browser/notifications/balloon_collection_impl.h +++ b/chrome/browser/notifications/balloon_collection_impl.h @@ -13,6 +13,7 @@ #include "base/basictypes.h" #include "base/message_loop.h" #include "chrome/browser/notifications/balloon_collection.h" +#include "chrome/browser/notifications/balloon_collection_base.h" #include "gfx/point.h" #include "gfx/rect.h" @@ -41,14 +42,14 @@ class BalloonCollectionImpl : public BalloonCollection // BalloonCollection interface. virtual void Add(const Notification& notification, Profile* profile); - virtual bool Remove(const Notification& notification); + virtual bool RemoveById(const std::string& id); + virtual bool RemoveBySourceOrigin(const GURL& source_origin); + virtual void RemoveAll(); virtual bool HasSpace() const; virtual void ResizeBalloon(Balloon* balloon, const gfx::Size& size); virtual void DisplayChanged(); virtual void OnBalloonClosed(Balloon* source); - virtual const Balloons& GetActiveBalloons() { - return balloons_; - } + virtual const Balloons& GetActiveBalloons() { return base_.balloons(); } // MessageLoopForUI::Observer interface. #if defined(OS_WIN) @@ -135,9 +136,6 @@ class BalloonCollectionImpl : public BalloonCollection Profile* profile); private: - // The number of balloons being displayed. - int count() const { return balloons_.size(); } - // Adjusts the positions of the balloons (e.g., when one is closed). // Implemented by each platform for specific UI requirements. void PositionBalloons(bool is_reposition); @@ -150,6 +148,12 @@ class BalloonCollectionImpl : public BalloonCollection static gfx::Rect GetMacWorkArea(); #endif + // Base implementation for the collection of active balloons. + BalloonCollectionBase base_; + + // The layout parameters for balloons in this collection. + Layout layout_; + #if USE_OFFSETS // Start and stop observing all UI events. void AddMessageLoopObserver(); @@ -163,16 +167,7 @@ class BalloonCollectionImpl : public BalloonCollection // Is the current cursor in the balloon area? bool IsCursorInBalloonCollection() const; -#endif - // Queue of active balloons. - typedef std::deque<Balloon*> Balloons; - Balloons balloons_; - - // The layout parameters for balloons in this collection. - Layout layout_; - -#if USE_OFFSETS // Factory for generating delayed reposition tasks on mouse motion. ScopedRunnableMethodFactory<BalloonCollectionImpl> reposition_factory_; diff --git a/chrome/browser/notifications/balloon_collection_linux.cc b/chrome/browser/notifications/balloon_collection_linux.cc index f15c713..08354a0 100644 --- a/chrome/browser/notifications/balloon_collection_linux.cc +++ b/chrome/browser/notifications/balloon_collection_linux.cc @@ -46,10 +46,11 @@ void BalloonCollectionImpl::DidProcessEvent(GdkEvent* event) { } bool BalloonCollectionImpl::IsCursorInBalloonCollection() const { - if (balloons_.empty()) + const Balloons& balloons = base_.balloons(); + if (balloons.empty()) return false; - gfx::Point upper_left = balloons_[balloons_.size() - 1]->GetPosition(); + gfx::Point upper_left = balloons[balloons.size() - 1]->GetPosition(); gfx::Point lower_right = layout_.GetLayoutOrigin(); gfx::Rect bounds = gfx::Rect(upper_left.x(), diff --git a/chrome/browser/notifications/balloon_collection_win.cc b/chrome/browser/notifications/balloon_collection_win.cc index 8915662..07bcd18 100644 --- a/chrome/browser/notifications/balloon_collection_win.cc +++ b/chrome/browser/notifications/balloon_collection_win.cc @@ -44,10 +44,11 @@ void BalloonCollectionImpl::DidProcessMessage(const MSG& msg) { } bool BalloonCollectionImpl::IsCursorInBalloonCollection() const { - if (balloons_.empty()) + const Balloons& balloons = base_.balloons(); + if (balloons.empty()) return false; - gfx::Point upper_left = balloons_[balloons_.size() - 1]->GetPosition(); + gfx::Point upper_left = balloons[balloons.size() - 1]->GetPosition(); gfx::Point lower_right = layout_.GetLayoutOrigin(); gfx::Rect bounds = gfx::Rect(upper_left.x(), diff --git a/chrome/browser/notifications/balloon_host.cc b/chrome/browser/notifications/balloon_host.cc index 04f0b89..6fbc1e0 100644 --- a/chrome/browser/notifications/balloon_host.cc +++ b/chrome/browser/notifications/balloon_host.cc @@ -20,6 +20,30 @@ #include "chrome/common/url_constants.h" #include "webkit/glue/webpreferences.h" +namespace { +class BalloonPaintObserver : public RenderWidgetHost::PaintObserver { + public: + explicit BalloonPaintObserver(BalloonHost* balloon_host) + : balloon_host_(balloon_host) { + } + + virtual void RenderWidgetHostWillPaint(RenderWidgetHost* rhw) {} + virtual void RenderWidgetHostDidPaint(RenderWidgetHost* rwh); + + private: + BalloonHost* balloon_host_; + + DISALLOW_COPY_AND_ASSIGN(BalloonPaintObserver); +}; + +void BalloonPaintObserver::RenderWidgetHostDidPaint(RenderWidgetHost* rwh) { + balloon_host_->RenderWidgetHostDidPaint(); + // WARNING: we may have been deleted (if the balloon host cleared the paint + // observer). +} + +} // namespace + BalloonHost::BalloonHost(Balloon* balloon) : render_view_host_(NULL), balloon_(balloon), @@ -66,9 +90,10 @@ const string16& BalloonHost::GetSource() const { } WebPreferences BalloonHost::GetWebkitPrefs() { - WebPreferences prefs; - prefs.allow_scripts_to_close_windows = true; - return prefs; + WebPreferences web_prefs = + RenderViewHostDelegateHelper::GetWebkitPrefs(GetProfile(), enable_dom_ui_); + web_prefs.allow_scripts_to_close_windows = true; + return web_prefs; } SiteInstance* BalloonHost::GetSiteInstance() const { @@ -92,8 +117,12 @@ void BalloonHost::RenderViewCreated(RenderViewHost* render_view_host) { render_view_host->Send(new ViewMsg_DisableScrollbarsForSmallWindows( render_view_host->routing_id(), balloon_->min_scrollbar_size())); render_view_host->WasResized(); +#if !defined(OS_MACOSX) + // TODO(levin): Make all of the code that went in originally with this change + // to be cross-platform. See http://crbug.com/64720 render_view_host->EnablePreferredSizeChangedMode( kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow); +#endif } void BalloonHost::RenderViewReady(RenderViewHost* render_view_host) { @@ -198,6 +227,9 @@ void BalloonHost::Init() { rvh->set_view(render_widget_host_view()); rvh->CreateRenderView(string16()); +#if defined(OS_MACOSX) + rvh->set_paint_observer(new BalloonPaintObserver(this)); +#endif rvh->NavigateToURL(balloon_->notification().content_url()); initialized_ = true; @@ -219,7 +251,15 @@ void BalloonHost::ClearInspectorSettings() { RenderViewHostDelegateHelper::ClearInspectorSettings(GetProfile()); } -BalloonHost::~BalloonHost() {} +void BalloonHost::RenderWidgetHostDidPaint() { + render_view_host_->set_paint_observer(NULL); + render_view_host_->EnablePreferredSizeChangedMode( + kPreferredSizeWidth | kPreferredSizeHeightThisIsSlow); +} + +BalloonHost::~BalloonHost() { + DCHECK(!render_view_host_); +} void BalloonHost::NotifyDisconnect() { if (!should_notify_on_disconnect_) diff --git a/chrome/browser/notifications/balloon_host.h b/chrome/browser/notifications/balloon_host.h index 4e51eba..c5a88e7 100644 --- a/chrome/browser/notifications/balloon_host.h +++ b/chrome/browser/notifications/balloon_host.h @@ -112,6 +112,9 @@ class BalloonHost : public RenderViewHostDelegate, const std::string& value); virtual void ClearInspectorSettings(); + // Called when the render view has painted. + void RenderWidgetHostDidPaint(); + protected: virtual ~BalloonHost(); // Must override in platform specific implementations. diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc index e7530e4..8aa82d1 100644 --- a/chrome/browser/notifications/desktop_notification_service.cc +++ b/chrome/browser/notifications/desktop_notification_service.cc @@ -215,7 +215,7 @@ DesktopNotificationService::DesktopNotificationService(Profile* profile, NotificationUIManager* ui_manager) : profile_(profile), ui_manager_(ui_manager) { - registrar_.Init(profile_->GetPrefs()); + prefs_registrar_.Init(profile_->GetPrefs()); InitPrefs(); StartObserving(); } @@ -260,16 +260,24 @@ void DesktopNotificationService::InitPrefs() { void DesktopNotificationService::StartObserving() { if (!profile_->IsOffTheRecord()) { - registrar_.Add(prefs::kDesktopNotificationDefaultContentSetting, this); - registrar_.Add(prefs::kDesktopNotificationAllowedOrigins, this); - registrar_.Add(prefs::kDesktopNotificationDeniedOrigins, this); + prefs_registrar_.Add(prefs::kDesktopNotificationDefaultContentSetting, + this); + prefs_registrar_.Add(prefs::kDesktopNotificationAllowedOrigins, this); + prefs_registrar_.Add(prefs::kDesktopNotificationDeniedOrigins, this); + + notification_registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, + NotificationService::AllSources()); } + + notification_registrar_.Add(this, NotificationType::PROFILE_DESTROYED, + Source<Profile>(profile_)); } void DesktopNotificationService::StopObserving() { if (!profile_->IsOffTheRecord()) { - registrar_.RemoveAll(); + prefs_registrar_.RemoveAll(); } + notification_registrar_.RemoveAll(); } void DesktopNotificationService::GrantPermission(const GURL& origin) { @@ -282,6 +290,8 @@ void DesktopNotificationService::GrantPermission(const GURL& origin) { NewRunnableMethod( prefs_cache_.get(), &NotificationsPrefsCache::CacheAllowedOrigin, origin)); + + NotifySettingsChange(); } void DesktopNotificationService::DenyPermission(const GURL& origin) { @@ -294,20 +304,32 @@ void DesktopNotificationService::DenyPermission(const GURL& origin) { NewRunnableMethod( prefs_cache_.get(), &NotificationsPrefsCache::CacheDeniedOrigin, origin)); + + NotifySettingsChange(); } void DesktopNotificationService::Observe(NotificationType type, const NotificationSource& source, const NotificationDetails& details) { - DCHECK(NotificationType::PREF_CHANGED == type); + if (NotificationType::PREF_CHANGED == type) { + const std::string& name = *Details<std::string>(details).ptr(); + OnPrefsChanged(name); + } else if (NotificationType::EXTENSION_UNLOADED == type) { + // Remove all notifications currently shown or queued by the extension + // which was unloaded. + Extension* extension = Details<Extension>(details).ptr(); + if (extension) + ui_manager_->CancelAllBySourceOrigin(extension->url()); + } else if (NotificationType::PROFILE_DESTROYED == type) { + StopObserving(); + } +} + +void DesktopNotificationService::OnPrefsChanged(const std::string& pref_name) { PrefService* prefs = profile_->GetPrefs(); - const std::string& name = *Details<std::string>(details).ptr(); - if (name == prefs::kDesktopNotificationAllowedOrigins) { - NotificationService::current()->Notify( - NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED, - Source<DesktopNotificationService>(this), - NotificationService::NoDetails()); + if (pref_name == prefs::kDesktopNotificationAllowedOrigins) { + NotifySettingsChange(); std::vector<GURL> allowed_origins(GetAllowedOrigins()); // Schedule a cache update on the IO thread. @@ -317,11 +339,8 @@ void DesktopNotificationService::Observe(NotificationType type, prefs_cache_.get(), &NotificationsPrefsCache::SetCacheAllowedOrigins, allowed_origins)); - } else if (name == prefs::kDesktopNotificationDeniedOrigins) { - NotificationService::current()->Notify( - NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED, - Source<DesktopNotificationService>(this), - NotificationService::NoDetails()); + } else if (pref_name == prefs::kDesktopNotificationDeniedOrigins) { + NotifySettingsChange(); std::vector<GURL> denied_origins(GetBlockedOrigins()); // Schedule a cache update on the IO thread. @@ -331,7 +350,7 @@ void DesktopNotificationService::Observe(NotificationType type, prefs_cache_.get(), &NotificationsPrefsCache::SetCacheDeniedOrigins, denied_origins)); - } else if (name == prefs::kDesktopNotificationDefaultContentSetting) { + } else if (pref_name == prefs::kDesktopNotificationDefaultContentSetting) { NotificationService::current()->Notify( NotificationType::DESKTOP_NOTIFICATION_DEFAULT_CHANGED, Source<DesktopNotificationService>(this), @@ -563,9 +582,7 @@ bool DesktopNotificationService::CancelDesktopNotification( scoped_refptr<NotificationObjectProxy> proxy( new NotificationObjectProxy(process_id, route_id, notification_id, false)); - // TODO(johnnyg): clean up this "empty" notification. - Notification notif(GURL(), GURL(), string16(), string16(), proxy); - return ui_manager_->Cancel(notif); + return ui_manager_->CancelById(proxy->id()); } @@ -607,3 +624,10 @@ string16 DesktopNotificationService::DisplayNameForOrigin( } return UTF8ToUTF16(origin.host()); } + +void DesktopNotificationService::NotifySettingsChange() { + NotificationService::current()->Notify( + NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED, + Source<DesktopNotificationService>(this), + NotificationService::NoDetails()); +} diff --git a/chrome/browser/notifications/desktop_notification_service.h b/chrome/browser/notifications/desktop_notification_service.h index d92d7e6..a7a4ce2 100644 --- a/chrome/browser/notifications/desktop_notification_service.h +++ b/chrome/browser/notifications/desktop_notification_service.h @@ -6,24 +6,24 @@ #define CHROME_BROWSER_NOTIFICATIONS_DESKTOP_NOTIFICATION_SERVICE_H_ #pragma once +#include <string> #include <vector> #include "base/basictypes.h" +#include "base/ref_counted.h" #include "base/string16.h" -#include "chrome/browser/notifications/notification.h" #include "chrome/browser/prefs/pref_change_registrar.h" #include "chrome/common/content_settings.h" #include "chrome/common/notification_observer.h" #include "chrome/common/notification_registrar.h" -#include "chrome/common/notification_service.h" #include "googleurl/src/gurl.h" #include "third_party/WebKit/WebKit/chromium/public/WebTextDirection.h" +class Notification; class NotificationUIManager; class NotificationsPrefsCache; class PrefService; class Profile; -class Task; class TabContents; struct ViewHostMsg_ShowNotification_Params; @@ -121,6 +121,8 @@ class DesktopNotificationService : public NotificationObserver { void StartObserving(); void StopObserving(); + void OnPrefsChanged(const std::string& pref_name); + // Takes a notification object and shows it in the UI. void ShowNotification(const Notification& notification); @@ -132,6 +134,9 @@ class DesktopNotificationService : public NotificationObserver { // itself when dealing with extensions. string16 DisplayNameForOrigin(const GURL& origin); + // Notifies the observers when permissions settings change. + void NotifySettingsChange(); + // The profile which owns this object. Profile* profile_; @@ -143,7 +148,8 @@ class DesktopNotificationService : public NotificationObserver { // UI for desktop toasts. NotificationUIManager* ui_manager_; - PrefChangeRegistrar registrar_; + PrefChangeRegistrar prefs_registrar_; + NotificationRegistrar notification_registrar_; DISALLOW_COPY_AND_ASSIGN(DesktopNotificationService); }; diff --git a/chrome/browser/notifications/desktop_notifications_unittest.cc b/chrome/browser/notifications/desktop_notifications_unittest.cc index 9946690..ebb6ab8 100644 --- a/chrome/browser/notifications/desktop_notifications_unittest.cc +++ b/chrome/browser/notifications/desktop_notifications_unittest.cc @@ -16,26 +16,18 @@ std::string DesktopNotificationsTest::log_output_; void MockBalloonCollection::Add(const Notification& notification, Profile* profile) { - // Swap in the logging proxy for the purpose of logging calls that + // Swap in a logging proxy for the purpose of logging calls that // would be made into javascript, then pass this down to the // balloon collection. - Notification test_notification(notification.origin_url(), - notification.content_url(), - notification.display_source(), - string16(), /* replace_id */ - log_proxy_.get()); + Notification test_notification( + notification.origin_url(), + notification.content_url(), + notification.display_source(), + notification.replace_id(), + new LoggingNotificationProxy(notification.notification_id())); BalloonCollectionImpl::Add(test_notification, profile); } -bool MockBalloonCollection::Remove(const Notification& notification) { - Notification test_notification(notification.origin_url(), - notification.content_url(), - notification.display_source(), - string16(), /* replace_id */ - log_proxy_.get()); - return BalloonCollectionImpl::Remove(test_notification); -} - Balloon* MockBalloonCollection::MakeBalloon(const Notification& notification, Profile* profile) { // Start with a normal balloon but mock out the view. diff --git a/chrome/browser/notifications/desktop_notifications_unittest.h b/chrome/browser/notifications/desktop_notifications_unittest.h index 3b02b7b..9f556e4 100644 --- a/chrome/browser/notifications/desktop_notifications_unittest.h +++ b/chrome/browser/notifications/desktop_notifications_unittest.h @@ -22,15 +22,14 @@ #include "testing/gtest/include/gtest/gtest.h" class DesktopNotificationsTest; -typedef LoggingNotificationProxyBase<DesktopNotificationsTest> +typedef LoggingNotificationDelegate<DesktopNotificationsTest> LoggingNotificationProxy; // Test version of the balloon collection which counts the number // of notifications that are added to it. class MockBalloonCollection : public BalloonCollectionImpl { public: - MockBalloonCollection() : - log_proxy_(new LoggingNotificationProxy()) {} + MockBalloonCollection() {} // Our mock collection has an area large enough for a fixed number // of balloons. @@ -40,7 +39,6 @@ class MockBalloonCollection : public BalloonCollectionImpl { // BalloonCollectionImpl overrides virtual void Add(const Notification& notification, Profile* profile); - virtual bool Remove(const Notification& notification); virtual bool HasSpace() const { return count() < kMockBalloonSpace; } virtual Balloon* MakeBalloon(const Notification& notification, Profile* profile); @@ -63,7 +61,6 @@ class MockBalloonCollection : public BalloonCollectionImpl { private: std::deque<Balloon*> balloons_; - scoped_refptr<LoggingNotificationProxy> log_proxy_; }; class DesktopNotificationsTest : public testing::Test { diff --git a/chrome/browser/notifications/notification.cc b/chrome/browser/notifications/notification.cc index c429efa..e6d69a6 100644 --- a/chrome/browser/notifications/notification.cc +++ b/chrome/browser/notifications/notification.cc @@ -34,7 +34,3 @@ Notification& Notification::operator=(const Notification& notification) { delegate_ = notification.delegate(); return *this; } - -bool Notification::IsSame(const Notification& other) const { - return delegate()->id() == other.delegate()->id(); -} diff --git a/chrome/browser/notifications/notification.h b/chrome/browser/notifications/notification.h index 7b0ab8c..2040cf3 100644 --- a/chrome/browser/notifications/notification.h +++ b/chrome/browser/notifications/notification.h @@ -6,6 +6,8 @@ #define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_H_ #pragma once +#include <string> + #include "base/basictypes.h" #include "chrome/browser/notifications/notification_object_proxy.h" #include "googleurl/src/gurl.h" @@ -42,7 +44,7 @@ class Notification { void Click() const { delegate()->Click(); } void Close(bool by_user) const { delegate()->Close(by_user); } - bool IsSame(const Notification& other) const; + std::string notification_id() const { return delegate()->id(); } private: NotificationDelegate* delegate() const { return delegate_.get(); } diff --git a/chrome/browser/notifications/notification_exceptions_table_model.cc b/chrome/browser/notifications/notification_exceptions_table_model.cc index 31a44d5..a3326f9 100644 --- a/chrome/browser/notifications/notification_exceptions_table_model.cc +++ b/chrome/browser/notifications/notification_exceptions_table_model.cc @@ -6,10 +6,13 @@ #include "app/l10n_util.h" #include "app/table_model_observer.h" +#include "base/auto_reset.h" #include "base/utf_string_conversions.h" #include "chrome/common/content_settings.h" #include "chrome/common/content_settings_helper.h" #include "chrome/common/content_settings_types.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" #include "chrome/common/url_constants.h" #include "grit/generated_resources.h" @@ -24,15 +27,11 @@ struct NotificationExceptionsTableModel::Entry { NotificationExceptionsTableModel::NotificationExceptionsTableModel( DesktopNotificationService* service) : service_(service), + updates_disabled_(false), observer_(NULL) { - std::vector<GURL> allowed(service_->GetAllowedOrigins()); - std::vector<GURL> blocked(service_->GetBlockedOrigins()); - entries_.reserve(allowed.size() + blocked.size()); - for (size_t i = 0; i < allowed.size(); ++i) - entries_.push_back(Entry(allowed[i], CONTENT_SETTING_ALLOW)); - for (size_t i = 0; i < blocked.size(); ++i) - entries_.push_back(Entry(blocked[i], CONTENT_SETTING_BLOCK)); - sort(entries_.begin(), entries_.end()); + registrar_.Add(this, NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED, + NotificationService::AllSources()); + LoadEntries(); } NotificationExceptionsTableModel::~NotificationExceptionsTableModel() {} @@ -43,6 +42,7 @@ bool NotificationExceptionsTableModel::CanRemoveRows( } void NotificationExceptionsTableModel::RemoveRows(const Rows& rows) { + AutoReset<bool> tmp(&updates_disabled_, true); // This is O(n^2) in rows.size(). Since n is small, that's ok. for (Rows::const_reverse_iterator i(rows.rbegin()); i != rows.rend(); ++i) { size_t row = *i; @@ -60,11 +60,11 @@ void NotificationExceptionsTableModel::RemoveRows(const Rows& rows) { } void NotificationExceptionsTableModel::RemoveAll() { - int old_row_count = RowCount(); + AutoReset<bool> tmp(&updates_disabled_, true); entries_.clear(); service_->ResetAllOrigins(); if (observer_) - observer_->OnItemsRemoved(0, old_row_count); + observer_->OnModelChanged(); } int NotificationExceptionsTableModel::RowCount() { @@ -98,6 +98,31 @@ void NotificationExceptionsTableModel::SetObserver( observer_ = observer; } +void NotificationExceptionsTableModel::Observe( + NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (!updates_disabled_) { + DCHECK(type == NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED); + entries_.clear(); + LoadEntries(); + + if (observer_) + observer_->OnModelChanged(); + } +} + +void NotificationExceptionsTableModel::LoadEntries() { + std::vector<GURL> allowed(service_->GetAllowedOrigins()); + std::vector<GURL> blocked(service_->GetBlockedOrigins()); + entries_.reserve(allowed.size() + blocked.size()); + for (size_t i = 0; i < allowed.size(); ++i) + entries_.push_back(Entry(allowed[i], CONTENT_SETTING_ALLOW)); + for (size_t i = 0; i < blocked.size(); ++i) + entries_.push_back(Entry(blocked[i], CONTENT_SETTING_BLOCK)); + std::sort(entries_.begin(), entries_.end()); +} + NotificationExceptionsTableModel::Entry::Entry( const GURL& in_origin, ContentSetting in_setting) diff --git a/chrome/browser/notifications/notification_exceptions_table_model.h b/chrome/browser/notifications/notification_exceptions_table_model.h index 0fcf335..107b2ec 100644 --- a/chrome/browser/notifications/notification_exceptions_table_model.h +++ b/chrome/browser/notifications/notification_exceptions_table_model.h @@ -11,35 +11,46 @@ #include "chrome/browser/notifications/desktop_notification_service.h" #include "chrome/browser/remove_rows_table_model.h" +#include "chrome/common/notification_observer.h" -class NotificationExceptionsTableModel : public RemoveRowsTableModel { +class NotificationExceptionsTableModel : public RemoveRowsTableModel, + public NotificationObserver { public: explicit NotificationExceptionsTableModel( DesktopNotificationService* service); virtual ~NotificationExceptionsTableModel(); - // RemoveRowsTableModel overrides: + // Overridden from RemoveRowsTableModel: virtual bool CanRemoveRows(const Rows& rows) const; virtual void RemoveRows(const Rows& rows); virtual void RemoveAll(); - // TableModel overrides: + // Overridden from TableModel: virtual int RowCount(); virtual std::wstring GetText(int row, int column_id); virtual void SetObserver(TableModelObserver* observer); + // Overridden from NotificationObserver: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); private: struct Entry; + void LoadEntries(); + DesktopNotificationService* service_; typedef std::vector<Entry> EntriesVector; EntriesVector entries_; + // We use this variable to prevent ourselves from handling further changes + // that we ourselves caused. + bool updates_disabled_; + NotificationRegistrar registrar_; TableModelObserver* observer_; DISALLOW_COPY_AND_ASSIGN(NotificationExceptionsTableModel); }; #endif // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_EXCEPTIONS_TABLE_MODEL_H_ - diff --git a/chrome/browser/notifications/notification_options_menu_model.cc b/chrome/browser/notifications/notification_options_menu_model.cc index 97d269c..7172cf7 100644 --- a/chrome/browser/notifications/notification_options_menu_model.cc +++ b/chrome/browser/notifications/notification_options_menu_model.cc @@ -10,6 +10,7 @@ #include "chrome/browser/browser_list.h" #include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/notifications/desktop_notification_service.h" +#include "chrome/browser/notifications/notification.h" #include "chrome/browser/notifications/notifications_prefs_cache.h" #include "chrome/browser/profile.h" #include "chrome/common/content_settings_types.h" @@ -17,6 +18,11 @@ #include "chrome/common/url_constants.h" #include "grit/generated_resources.h" +#if defined(OS_WIN) +#include "chrome/browser/ui/views/browser_dialogs.h" +#include "chrome/installer/util/install_util.h" +#endif // OS_WIN + // Menu commands const int kTogglePermissionCommand = 0; const int kToggleExtensionCommand = 1; @@ -139,9 +145,19 @@ void NotificationOptionsMenuModel::ExecuteCommand(int command_id) { } case kOpenContentSettingsCommand: { Browser* browser = BrowserList::GetLastActive(); - if (browser) + if (browser) { static_cast<TabContentsDelegate*>(browser)->ShowContentSettingsWindow( CONTENT_SETTINGS_TYPE_NOTIFICATIONS); + } else { +#if defined(OS_WIN) + if (InstallUtil::IsChromeFrameProcess()) { + // We may not have a browser if this is a chrome frame process. + browser::ShowContentSettingsWindow(NULL, + CONTENT_SETTINGS_TYPE_DEFAULT, + balloon_->profile()); + } +#endif // OS_WIN + } break; } default: diff --git a/chrome/browser/notifications/notification_test_util.h b/chrome/browser/notifications/notification_test_util.h index 4cbf600..fbaec4e 100644 --- a/chrome/browser/notifications/notification_test_util.h +++ b/chrome/browser/notifications/notification_test_util.h @@ -6,6 +6,8 @@ #define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_TEST_UTIL_H_ #pragma once +#include <string> + #include "chrome/browser/notifications/notification_object_proxy.h" #include "chrome/browser/notifications/balloon.h" #include "gfx/size.h" @@ -14,7 +16,7 @@ // the notification events are not important. class MockNotificationDelegate : public NotificationDelegate { public: - explicit MockNotificationDelegate(std::string id) : id_(id) {} + explicit MockNotificationDelegate(const std::string& id) : id_(id) {} virtual ~MockNotificationDelegate() {} // NotificationDelegate interface. @@ -26,6 +28,8 @@ class MockNotificationDelegate : public NotificationDelegate { private: std::string id_; + + DISALLOW_COPY_AND_ASSIGN(MockNotificationDelegate); }; // Mock implementation of Javascript object proxy which logs events that @@ -35,10 +39,11 @@ class MockNotificationDelegate : public NotificationDelegate { // |Logger| class provided in template must implement method // static void log(string); template<class Logger> -class LoggingNotificationProxyBase : public NotificationObjectProxy { +class LoggingNotificationDelegate : public NotificationDelegate { public: - LoggingNotificationProxyBase() : - NotificationObjectProxy(0, 0, 0, false) {} + explicit LoggingNotificationDelegate(std::string id) + : notification_id_(id) { + } // NotificationObjectProxy override virtual void Display() { @@ -47,12 +52,22 @@ class LoggingNotificationProxyBase : public NotificationObjectProxy { virtual void Error() { Logger::log("notification error\n"); } + virtual void Click() { + Logger::log("notification clicked\n"); + } virtual void Close(bool by_user) { if (by_user) Logger::log("notification closed by user\n"); else Logger::log("notification closed by script\n"); } + virtual std::string id() const { + return notification_id_; + } + private: + std::string notification_id_; + + DISALLOW_COPY_AND_ASSIGN(LoggingNotificationDelegate); }; // Test version of a balloon view which doesn't do anything diff --git a/chrome/browser/notifications/notification_ui_manager.cc b/chrome/browser/notifications/notification_ui_manager.cc index adc44cf..6e2ff02 100644 --- a/chrome/browser/notifications/notification_ui_manager.cc +++ b/chrome/browser/notifications/notification_ui_manager.cc @@ -10,6 +10,8 @@ #include "chrome/browser/notifications/balloon_collection.h" #include "chrome/browser/notifications/notification.h" #include "chrome/browser/renderer_host/site_instance.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" // A class which represents a notification waiting to be shown. class QueuedNotification { @@ -38,6 +40,8 @@ class QueuedNotification { NotificationUIManager::NotificationUIManager() : balloon_collection_(NULL) { + registrar_.Add(this, NotificationType::APP_TERMINATING, + NotificationService::AllSources()); } NotificationUIManager::~NotificationUIManager() { @@ -66,17 +70,39 @@ void NotificationUIManager::Add(const Notification& notification, CheckAndShowNotifications(); } -bool NotificationUIManager::Cancel(const Notification& notification) { - // First look through the notifications that haven't been shown. If not - // found there, call to the active balloon collection to tear it down. +bool NotificationUIManager::CancelById(const std::string& id) { + // See if this ID hasn't been shown yet. NotificationDeque::iterator iter; for (iter = show_queue_.begin(); iter != show_queue_.end(); ++iter) { - if (notification.IsSame((*iter)->notification())) { + if ((*iter)->notification().notification_id() == id) { show_queue_.erase(iter); return true; } } - return balloon_collection_->Remove(notification); + // If it has been shown, remove it from the balloon collections. + return balloon_collection_->RemoveById(id); +} + +bool NotificationUIManager::CancelAllBySourceOrigin(const GURL& source) { + // Same pattern as CancelById, but more complicated than the above + // because there may be multiple notifications from the same source. + bool removed = false; + NotificationDeque::iterator iter; + for (iter = show_queue_.begin(); iter != show_queue_.end();) { + if ((*iter)->notification().origin_url() == source) { + iter = show_queue_.erase(iter); + removed = true; + } else { + ++iter; + } + } + + return balloon_collection_->RemoveBySourceOrigin(source) || removed; +} + +void NotificationUIManager::CancelAll() { + STLDeleteElements(&show_queue_); + balloon_collection_->RemoveAll(); } void NotificationUIManager::CheckAndShowNotifications() { @@ -130,3 +156,12 @@ bool NotificationUIManager::TryReplacement(const Notification& notification) { return false; } + +void NotificationUIManager::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type == NotificationType::APP_TERMINATING) + CancelAll(); + else + NOTREACHED(); +} diff --git a/chrome/browser/notifications/notification_ui_manager.h b/chrome/browser/notifications/notification_ui_manager.h index 10687a9..de429db 100644 --- a/chrome/browser/notifications/notification_ui_manager.h +++ b/chrome/browser/notifications/notification_ui_manager.h @@ -7,11 +7,14 @@ #pragma once #include <deque> +#include <string> #include "base/id_map.h" #include "base/scoped_ptr.h" #include "chrome/browser/notifications/balloon.h" #include "chrome/browser/notifications/balloon_collection.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" class Notification; class Profile; @@ -21,7 +24,8 @@ class SiteInstance; // The notification manager manages use of the desktop for notifications. // It maintains a queue of pending notifications when space becomes constrained. class NotificationUIManager - : public BalloonCollection::BalloonSpaceChangeListener { + : public BalloonCollection::BalloonSpaceChangeListener, + public NotificationObserver { public: NotificationUIManager(); virtual ~NotificationUIManager(); @@ -43,14 +47,29 @@ class NotificationUIManager virtual void Add(const Notification& notification, Profile* profile); - // Removes a notification. - virtual bool Cancel(const Notification& notification); + // Removes any notifications matching the supplied ID, either currently + // displayed or in the queue. Returns true if anything was removed. + virtual bool CancelById(const std::string& notification_id); + + // Removes any notifications matching the supplied source origin + // (which could be an extension ID), either currently displayed or in the + // queue. Returns true if anything was removed. + virtual bool CancelAllBySourceOrigin(const GURL& source_origin); + + // Cancels all pending notifications and closes anything currently showing. + // Used when the app is terminating. + void CancelAll(); // Returns balloon collection. BalloonCollection* balloon_collection() { return balloon_collection_.get(); } + // NotificationObserver interface (the event signaling kind of notifications) + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + private: // Attempts to display notifications from the show_queue if the user // is active. @@ -73,6 +92,9 @@ class NotificationUIManager typedef std::deque<QueuedNotification*> NotificationDeque; NotificationDeque show_queue_; + // Registrar for the other kind of notifications (event signaling). + NotificationRegistrar registrar_; + DISALLOW_COPY_AND_ASSIGN(NotificationUIManager); }; |