diff options
author | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-17 01:19:06 +0000 |
---|---|---|
committer | oshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-17 01:19:06 +0000 |
commit | 3b845753b707daca3fe3e733263065f162b7162b (patch) | |
tree | b674a4d72a118323da1fad83f8caa43f57a86b32 | |
parent | fee8f0222a5f2a377ba5d7f2d3383481c02eafac (diff) | |
download | chromium_src-3b845753b707daca3fe3e733263065f162b7162b.zip chromium_src-3b845753b707daca3fe3e733263065f162b7162b.tar.gz chromium_src-3b845753b707daca3fe3e733263065f162b7162b.tar.bz2 |
* Moved sticky/controls frag to chromeos::BalloonViewImpl
* Added AddSystemNotification to add system notification
and UpdateNotification to update a notification.
* refactored NotificationObjectProxy and added NotificationDelegate class.
* Added notification_browser.cc.
BUG=33306
TEST=added notification_browser.cc with minimal test. I'll add more in next step.
Review URL: http://codereview.chromium.org/1013002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@41801 0039d316-1c4b-4281-b951-d872f2087c98
31 files changed, 500 insertions, 233 deletions
diff --git a/chrome/browser/chromeos/notifications/balloon_collection_impl.cc b/chrome/browser/chromeos/notifications/balloon_collection_impl.cc index 82a2594..b06edf1 100644 --- a/chrome/browser/chromeos/notifications/balloon_collection_impl.cc +++ b/chrome/browser/chromeos/notifications/balloon_collection_impl.cc @@ -4,6 +4,8 @@ #include "chrome/browser/chromeos/notifications/balloon_collection_impl.h" +#include <algorithm> + #include "base/logging.h" #include "base/stl_util-inl.h" #include "chrome/browser/chromeos/notifications/balloon_view.h" @@ -27,19 +29,30 @@ const int kMinAllowedBalloonCount = 2; const int kVerticalEdgeMargin = 5; const int kHorizontalEdgeMargin = 5; +class NotificationMatcher { + public: + explicit NotificationMatcher(const Notification& notification) + : notification_(notification) {} + bool operator()(const Balloon* b) { + return notification_.IsSame(b->notification()); + } + private: + Notification notification_; +}; + } // namespace namespace chromeos { BalloonCollectionImpl::BalloonCollectionImpl() - : panel_(new NotificationPanel()) { + : notification_ui_(new NotificationPanel()) { } BalloonCollectionImpl::~BalloonCollectionImpl() { // We need to remove the panel first because deleting // views that are not owned by parent will not remove // themselves from the parent. - panel_.reset(); + notification_ui_.reset(); STLDeleteElements(&balloons_); } @@ -48,22 +61,51 @@ void BalloonCollectionImpl::Add(const Notification& notification, Balloon* new_balloon = MakeBalloon(notification, profile); balloons_.push_back(new_balloon); new_balloon->Show(); - panel_->Add(new_balloon); + notification_ui_->Add(new_balloon); // There may be no listener in a unit test. if (space_change_listener_) space_change_listener_->OnBalloonSpaceChanged(); } +void BalloonCollectionImpl::AddSystemNotification( + const Notification& notification, + Profile* profile, + bool sticky, + bool control) { + // TODO(oshima): We need to modify BallonCollection/MakeBalloon pattern + // in order to add unit tests for system notification. + Balloon* new_balloon = new Balloon(notification, profile, this); + new_balloon->set_view( + new chromeos::BalloonViewImpl(sticky, control)); + balloons_.push_back(new_balloon); + new_balloon->Show(); + notification_ui_->Add(new_balloon); + + // There may be no listener in a unit test. + if (space_change_listener_) + space_change_listener_->OnBalloonSpaceChanged(); +} + +bool BalloonCollectionImpl::UpdateNotification( + const Notification& notification) { + Balloons::iterator iter = FindBalloon(notification); + if (iter != balloons_.end()) { + Balloon* balloon = *iter; + balloon->Update(notification); + notification_ui_->Update(balloon); + return true; + } + return false; +} + 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; - } + Balloons::iterator iter = FindBalloon(notification); + if (iter != balloons_.end()) { + // 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; } @@ -74,20 +116,18 @@ bool BalloonCollectionImpl::HasSpace() const { void BalloonCollectionImpl::ResizeBalloon(Balloon* balloon, const gfx::Size& size) { - panel_->ResizeNotification(balloon, size); + notification_ui_->ResizeNotification(balloon, size); } void BalloonCollectionImpl::OnBalloonClosed(Balloon* source) { // We want to free the balloon when finished. scoped_ptr<Balloon> closed(source); - panel_->Remove(source); + notification_ui_->Remove(source); - for (Balloons::iterator it = balloons_.begin(); it != balloons_.end(); ++it) { - if (*it == source) { - balloons_.erase(it); - break; - } + Balloons::iterator iter = FindBalloon(source->notification()); + if (iter != balloons_.end()) { + balloons_.erase(iter); } // There may be no listener in a unit test. if (space_change_listener_) @@ -96,9 +136,16 @@ void BalloonCollectionImpl::OnBalloonClosed(Balloon* source) { Balloon* BalloonCollectionImpl::MakeBalloon(const Notification& notification, Profile* profile) { - Balloon* balloon = new Balloon(notification, profile, this); - balloon->set_view(new chromeos::BalloonViewImpl()); - return balloon; + Balloon* new_balloon = new Balloon(notification, profile, this); + new_balloon->set_view(new chromeos::BalloonViewImpl(false, true)); + return new_balloon; +} + +std::deque<Balloon*>::iterator BalloonCollectionImpl::FindBalloon( + const Notification& notification) { + return std::find_if(balloons_.begin(), + balloons_.end(), + NotificationMatcher(notification)); } } // namespace chromeos diff --git a/chrome/browser/chromeos/notifications/balloon_collection_impl.h b/chrome/browser/chromeos/notifications/balloon_collection_impl.h index 4172b0d..870030d 100644 --- a/chrome/browser/chromeos/notifications/balloon_collection_impl.h +++ b/chrome/browser/chromeos/notifications/balloon_collection_impl.h @@ -34,6 +34,7 @@ class BalloonCollectionImpl : public BalloonCollection { // Add, remove and resize the balloon. virtual void Add(Balloon* balloon) = 0; + virtual bool Update(Balloon* balloon) = 0; virtual void Remove(Balloon* balloon) = 0; virtual void ResizeNotification(Balloon* balloon, const gfx::Size& size) = 0; @@ -53,9 +54,26 @@ class BalloonCollectionImpl : public BalloonCollection { virtual void DisplayChanged() {} virtual void OnBalloonClosed(Balloon* source); + // Adds new system notification. + // |sticky| is used to indicate that the notification + // is sticky and cannot be dismissed by a user. |controls| turns on/off + // info label and option/dismiss buttons. + void AddSystemNotification(const Notification& notification, + Profile* profile, bool sticky, bool controls); + + // Update the notification's content. It uses + // NotificationDelegate::id() to check the equality of notifications. + // Returns true if the notification has been updated. False if + // no corresponding notification is found. + bool UpdateNotification(const Notification& notification); + // Injects notification ui. Used to inject a mock implementation in tests. void set_notification_ui(NotificationUI* ui) { - panel_.reset(ui); + notification_ui_.reset(ui); + } + + NotificationUI* notification_ui() { + return notification_ui_.get(); } protected: @@ -68,11 +86,13 @@ class BalloonCollectionImpl : public BalloonCollection { // The number of balloons being displayed. int count() const { return balloons_.size(); } - // Queue of active balloons. typedef std::deque<Balloon*> Balloons; + Balloons::iterator FindBalloon(const Notification& notification); + + // Queue of active balloons. Balloons balloons_; - scoped_ptr<NotificationUI> panel_; + scoped_ptr<NotificationUI> notification_ui_; DISALLOW_COPY_AND_ASSIGN(BalloonCollectionImpl); }; diff --git a/chrome/browser/chromeos/notifications/balloon_view.cc b/chrome/browser/chromeos/notifications/balloon_view.cc index 94feeae..6b9c4f0 100644 --- a/chrome/browser/chromeos/notifications/balloon_view.cc +++ b/chrome/browser/chromeos/notifications/balloon_view.cc @@ -35,7 +35,7 @@ const int kRevokePermissionCommand = 0; namespace chromeos { -BalloonViewImpl::BalloonViewImpl() +BalloonViewImpl::BalloonViewImpl(bool sticky, bool controls) : balloon_(NULL), html_contents_(NULL), method_factory_(this), @@ -43,7 +43,9 @@ BalloonViewImpl::BalloonViewImpl() options_menu_contents_(NULL), options_menu_menu_(NULL), options_menu_button_(NULL), - stale_(false) { + stale_(false), + sticky_(sticky), + controls_(controls) { // This object is not to be deleted by the views hierarchy, // as it is owned by the balloon. set_parent_owned(false); @@ -71,41 +73,46 @@ void BalloonViewImpl::Show(Balloon* balloon) { html_contents_ = new BalloonViewHost(balloon); AddChildView(html_contents_); - close_button_ = new views::TextButton(this, dismiss_text); - close_button_->SetIcon(*rb.GetBitmapNamed(IDR_BALLOON_CLOSE)); - close_button_->SetHoverIcon(*rb.GetBitmapNamed(IDR_BALLOON_CLOSE_HOVER)); - close_button_->SetFont(rb.GetFont(ResourceBundle::SmallFont)); - close_button_->SetEnabledColor(SK_ColorWHITE); - close_button_->SetHoverColor(SK_ColorDKGRAY); - close_button_->set_alignment(views::TextButton::ALIGN_CENTER); - close_button_->set_icon_placement(views::TextButton::ICON_ON_RIGHT); - AddChildView(close_button_); - - options_menu_button_ = new views::MenuButton(NULL, options_text, this, false); - options_menu_button_->SetFont(rb.GetFont(ResourceBundle::SmallFont)); - options_menu_button_->SetIcon(*rb.GetBitmapNamed(IDR_BALLOON_OPTIONS_ARROW)); - options_menu_button_->SetHoverIcon( - *rb.GetBitmapNamed(IDR_BALLOON_OPTIONS_ARROW_HOVER)); - options_menu_button_->set_alignment(views::TextButton::ALIGN_CENTER); - options_menu_button_->set_icon_placement(views::TextButton::ICON_ON_RIGHT); - options_menu_button_->SetEnabledColor(SK_ColorWHITE); - options_menu_button_->SetHoverColor(SK_ColorDKGRAY); - AddChildView(options_menu_button_); - - source_label_ = new views::Label(source_label_text); - source_label_->SetFont(rb.GetFont(ResourceBundle::SmallFont)); - source_label_->SetColor(SK_ColorWHITE); - source_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); - AddChildView(source_label_); - - SetBounds(0, 0, - balloon_->content_size().width(), - balloon_->content_size().height() + - close_button_->GetPreferredSize().height()); + if (controls_) { + close_button_ = new views::TextButton(this, dismiss_text); + close_button_->SetIcon(*rb.GetBitmapNamed(IDR_BALLOON_CLOSE)); + close_button_->SetHoverIcon(*rb.GetBitmapNamed(IDR_BALLOON_CLOSE_HOVER)); + close_button_->SetFont(rb.GetFont(ResourceBundle::SmallFont)); + close_button_->SetEnabledColor(SK_ColorWHITE); + close_button_->SetHoverColor(SK_ColorDKGRAY); + close_button_->set_alignment(views::TextButton::ALIGN_CENTER); + close_button_->set_icon_placement(views::TextButton::ICON_ON_RIGHT); + AddChildView(close_button_); + + options_menu_button_ + = new views::MenuButton(NULL, options_text, this, false); + options_menu_button_->SetFont(rb.GetFont(ResourceBundle::SmallFont)); + options_menu_button_->SetIcon( + *rb.GetBitmapNamed(IDR_BALLOON_OPTIONS_ARROW)); + options_menu_button_->SetHoverIcon( + *rb.GetBitmapNamed(IDR_BALLOON_OPTIONS_ARROW_HOVER)); + options_menu_button_->set_alignment(views::TextButton::ALIGN_CENTER); + options_menu_button_->set_icon_placement(views::TextButton::ICON_ON_RIGHT); + options_menu_button_->SetEnabledColor(SK_ColorWHITE); + options_menu_button_->SetHoverColor(SK_ColorDKGRAY); + AddChildView(options_menu_button_); + + source_label_ = new views::Label(source_label_text); + source_label_->SetFont(rb.GetFont(ResourceBundle::SmallFont)); + source_label_->SetColor(SK_ColorWHITE); + source_label_->SetHorizontalAlignment(views::Label::ALIGN_LEFT); + AddChildView(source_label_); + } notification_registrar_.Add(this, NotificationType::NOTIFY_BALLOON_DISCONNECTED, Source<Balloon>(balloon)); } +void BalloonViewImpl::Update() { + stale_ = false; + html_contents_->render_view_host()->NavigateToURL( + balloon_->notification().content_url()); +} + void BalloonViewImpl::Close(bool by_user) { MessageLoop::current()->PostTask( FROM_HERE, @@ -126,7 +133,10 @@ void BalloonViewImpl::RepositionToBalloon() { // views::View interface overrides. void BalloonViewImpl::Layout() { - gfx::Size button_size = close_button_->GetPreferredSize(); + gfx::Size button_size; + if (close_button_) { + button_size = close_button_->GetPreferredSize(); + } SetBounds(x(), y(), balloon_->content_size().width(), @@ -141,12 +151,13 @@ void BalloonViewImpl::Layout() { if (view) view->SetSize(gfx::Size(width(), y)); } - - close_button_->SetBounds(x, y, button_size.width(), button_size.height()); - x -= close_button_->GetPreferredSize().width(); - options_menu_button_->SetBounds( - x, y, button_size.width(), button_size.height()); - source_label_->SetBounds(0, y, x, button_size.height()); + if (controls_) { + close_button_->SetBounds(x, y, button_size.width(), button_size.height()); + x -= close_button_->GetPreferredSize().width(); + options_menu_button_->SetBounds( + x, y, button_size.width(), button_size.height()); + source_label_->SetBounds(0, y, x, button_size.height()); + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/chrome/browser/chromeos/notifications/balloon_view.h b/chrome/browser/chromeos/notifications/balloon_view.h index fa51883..bd89f8b 100644 --- a/chrome/browser/chromeos/notifications/balloon_view.h +++ b/chrome/browser/chromeos/notifications/balloon_view.h @@ -43,27 +43,27 @@ class BalloonViewImpl : public BalloonView, public NotificationObserver, public views::ButtonListener { public: - BalloonViewImpl(); + BalloonViewImpl(bool sticky, bool controls); ~BalloonViewImpl(); // views::View interface. virtual void Layout(); // BalloonView interface. - void Show(Balloon* balloon); - void Close(bool by_user); - void RepositionToBalloon(); + virtual void Show(Balloon* balloon); + virtual void Update(); + virtual void Close(bool by_user); + virtual void RepositionToBalloon(); gfx::Size GetSize() const; // True if the notification is stale. False if the notification is new. - bool stale() const { - return stale_; - } + bool stale() const { return stale_; } - // Makes the notification stable. - void set_stale() { - stale_ = true; - } + // Makes the notification stale. + void set_stale() { stale_ = true; } + + // True if the notification is sticky. + bool sticky() { return sticky_; } private: // views::View interface. @@ -116,6 +116,10 @@ class BalloonViewImpl : public BalloonView, views::MenuButton* options_menu_button_; bool stale_; NotificationRegistrar notification_registrar_; + // A sticky flag. A sticky notification cannot be dismissed by a user. + bool sticky_; + // True if a notification should have info/option/dismiss label/buttons. + bool controls_; DISALLOW_COPY_AND_ASSIGN(BalloonViewImpl); }; diff --git a/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc b/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc index 5702049..428ea3e 100644 --- a/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc +++ b/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc @@ -12,7 +12,8 @@ std::string DesktopNotificationsTest::log_output_; class MockNotificationUI : public BalloonCollectionImpl::NotificationUI { public: virtual void Add(Balloon* balloon) {} - virtual void Remove(Balloon* ballon) {} + virtual bool Update(Balloon* balloon) { return false; } + virtual void Remove(Balloon* balloon) {} virtual void ResizeNotification(Balloon* balloon, const gfx::Size& size) {} }; @@ -30,8 +31,7 @@ void MockBalloonCollection::Add(const Notification& notification, Notification test_notification(notification.origin_url(), notification.content_url(), notification.display_source(), - log_proxy_.get(), - notification.sticky()); + log_proxy_.get()); BalloonCollectionImpl::Add(test_notification, profile); } @@ -39,8 +39,7 @@ bool MockBalloonCollection::Remove(const Notification& notification) { Notification test_notification(notification.origin_url(), notification.content_url(), notification.display_source(), - log_proxy_.get(), - notification.sticky()); + log_proxy_.get()); return BalloonCollectionImpl::Remove(test_notification); } @@ -96,25 +95,20 @@ TEST_F(DesktopNotificationsTest, TestShow) { EXPECT_TRUE(service_->ShowDesktopNotificationText( GURL("http://www.google.com"), GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 1, false)); + 0, 0, DesktopNotificationService::PageNotification, 1)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); EXPECT_TRUE(service_->ShowDesktopNotification( GURL("http://www.google.com"), GURL("http://www.google.com/notification.html"), - 0, 0, DesktopNotificationService::PageNotification, 2, false)); + 0, 0, DesktopNotificationService::PageNotification, 2)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(2, balloon_collection_->count()); EXPECT_EQ("notification displayed\n" "notification displayed\n", log_output_); - - std::set<Balloon*>::iterator iter = balloon_collection_->balloons().begin(); - EXPECT_FALSE((*iter)->notification().sticky()); - iter++; - EXPECT_FALSE((*iter)->notification().sticky()); } TEST_F(DesktopNotificationsTest, TestClose) { @@ -122,7 +116,7 @@ TEST_F(DesktopNotificationsTest, TestClose) { EXPECT_TRUE(service_->ShowDesktopNotificationText( GURL("http://www.google.com"), GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 1, false)); + 0, 0, DesktopNotificationService::PageNotification, 1)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); @@ -150,7 +144,7 @@ TEST_F(DesktopNotificationsTest, TestCancel) { GURL("http://www.google.com"), GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), process_id, route_id, DesktopNotificationService::PageNotification, - notification_id, false)); + notification_id)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); @@ -179,7 +173,7 @@ TEST_F(DesktopNotificationsTest, TestManyNotifications) { GURL("http://www.google.com"), GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), process_id, route_id, - DesktopNotificationService::PageNotification, id, false)); + DesktopNotificationService::PageNotification, id)); } MessageLoopForUI::current()->RunAllPending(); @@ -229,7 +223,7 @@ TEST_F(DesktopNotificationsTest, TestEarlyDestruction) { EXPECT_TRUE(service_->ShowDesktopNotificationText( GURL("http://www.google.com"), GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, id, false)); + 0, 0, DesktopNotificationService::PageNotification, id)); } service_.reset(NULL); } @@ -242,7 +236,7 @@ TEST_F(DesktopNotificationsTest, TestUserInputEscaping) { GURL("/icon.png"), ASCIIToUTF16("<script>window.alert('uh oh');</script>"), ASCIIToUTF16("<i>this text is in italics</i>"), - 0, 0, DesktopNotificationService::PageNotification, 1, false)); + 0, 0, DesktopNotificationService::PageNotification, 1)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); @@ -252,22 +246,4 @@ TEST_F(DesktopNotificationsTest, TestUserInputEscaping) { EXPECT_EQ(std::string::npos, data_url.spec().find("<i>")); } -TEST_F(DesktopNotificationsTest, TestSticky) { - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 1, true)); - MessageLoopForUI::current()->RunAllPending(); - EXPECT_TRUE(service_->ShowDesktopNotification( - GURL("http://www.google.com"), - GURL("http://www.google.com/notification.html"), - 0, 0, DesktopNotificationService::PageNotification, 2, true)); - MessageLoopForUI::current()->RunAllPending(); - - std::set<Balloon*>::iterator iter = balloon_collection_->balloons().begin(); - EXPECT_TRUE((*iter)->notification().sticky()); - iter++; - EXPECT_TRUE((*iter)->notification().sticky()); -} - } // namespace chromeos diff --git a/chrome/browser/chromeos/notifications/notification_browsertest.cc b/chrome/browser/chromeos/notifications/notification_browsertest.cc new file mode 100644 index 0000000..c2c83ac --- /dev/null +++ b/chrome/browser/chromeos/notifications/notification_browsertest.cc @@ -0,0 +1,83 @@ +// 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 "base/message_loop.h" +#include "base/ref_counted.h" +#include "chrome/browser/browser.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/notifications/balloon_collection_impl.h" +#include "chrome/browser/chromeos/notifications/notification_panel.h" +#include "chrome/browser/chromeos/notifications/system_notification_factory.h" +#include "chrome/browser/notifications/notification_delegate.h" +#include "chrome/browser/notifications/notification_ui_manager.h" +#include "chrome/test/in_process_browser_test.h" +#include "chrome/test/ui_test_utils.h" + +namespace chromeos { + +class SystemNotificationDelegate : public NotificationDelegate { + public: + explicit SystemNotificationDelegate(const std::string id) : id_(id) {} + + virtual void Display() {} + virtual void Error() {} + virtual void Close(bool by_user) {} + virtual std::string id() const { return id_; } + + private: + std::string id_; + + DISALLOW_COPY_AND_ASSIGN(SystemNotificationDelegate); +}; + +class NotificationTest : public InProcessBrowserTest { + public: + NotificationTest() { + } + + protected: + BalloonCollectionImpl* GetBalloonCollectionImpl() { + return static_cast<BalloonCollectionImpl*>( + g_browser_process->notification_ui_manager()->balloon_collection()); + } + + NotificationPanel* GetNotificationPanel() { + return static_cast<NotificationPanel*>( + GetBalloonCollectionImpl()->notification_ui()); + } +}; + +IN_PROC_BROWSER_TEST_F(NotificationTest, TestSystemNotification) { + BalloonCollectionImpl* collection = GetBalloonCollectionImpl(); + NotificationPanel* panel = GetNotificationPanel(); + scoped_refptr<SystemNotificationDelegate> delegate( + new SystemNotificationDelegate("power")); + + Notification notify = SystemNotificationFactory::Create( + GURL(), ASCIIToUTF16("Title"), ASCIIToUTF16("test"), delegate.get()); + collection->AddSystemNotification(notify, browser()->profile(), true, false); + + EXPECT_EQ(1, panel->GetNewNotificationCount()); + EXPECT_EQ(1, panel->GetStickyNotificationCount()); + + Notification update = SystemNotificationFactory::Create( + GURL(), ASCIIToUTF16("Title"), ASCIIToUTF16("updated"), delegate.get()); + collection->UpdateNotification(update); + + EXPECT_EQ(1, panel->GetStickyNotificationCount()); + + // Dismiss the notification. + // TODO(oshima): Consider updating API to Remove(NotificationDelegate) + // or Remove(std::string id); + collection->Remove(Notification(GURL(), GURL(), + std::wstring(), delegate.get())); + + MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask()); + ui_test_utils::RunMessageLoop(); + + EXPECT_EQ(0, panel->GetStickyNotificationCount()); + EXPECT_EQ(0, panel->GetNewNotificationCount()); + // TODO(oshima): check content, etc.. +} +} // namespace chromeos diff --git a/chrome/browser/chromeos/notifications/notification_panel.cc b/chrome/browser/chromeos/notifications/notification_panel.cc index 724c451..0e76591 100644 --- a/chrome/browser/chromeos/notifications/notification_panel.cc +++ b/chrome/browser/chromeos/notifications/notification_panel.cc @@ -160,13 +160,32 @@ class BalloonContainer : public views::View { return new_sticky.Union(new_non_sticky).size(); } - // Add a ballon to the panel. + // Adds a ballon to the panel. void Add(Balloon* balloon) { BalloonViewImpl* view = static_cast<BalloonViewImpl*>(balloon->view()); GetContainerFor(balloon)->AddChildView(view); } + // Updates the position of the |balloon|. + bool Update(Balloon* balloon) { + BalloonViewImpl* view = + static_cast<BalloonViewImpl*>(balloon->view()); + View* container = NULL; + if (sticky_container_->HasChildView(view)) { + container = sticky_container_; + } else if (non_sticky_container_->HasChildView(view)) { + container = non_sticky_container_; + } + if (container) { + container->RemoveChildView(view); + container->AddChildView(view); + return true; + } else { + return false; + } + } + // Removes a ballon from the panel. void Remove(Balloon* balloon) { BalloonViewImpl* view = @@ -180,9 +199,15 @@ class BalloonContainer : public views::View { non_sticky_container_->GetChildViewCount(); } - // Returns true if the container has sticky notification. - bool HasStickyNotifications() { - return sticky_container_->GetChildViewCount() > 0; + // Returns the # of new notifications. + bool GetNewNotificationCount() { + return sticky_container_->GetNewCount() + + non_sticky_container_->GetNewCount(); + } + + // Returns the # of sticky notifications. + bool GetStickyNotificationCount() { + return sticky_container_->GetChildViewCount(); } // Returns true if the |view| is contained in the panel. @@ -191,7 +216,7 @@ class BalloonContainer : public views::View { non_sticky_container_->HasChildView(view); } - // Update the bounds so that all notifications are visible. + // Updates the bounds so that all notifications are visible. void UpdateBounds() { sticky_container_->UpdateBounds(); non_sticky_container_->UpdateBounds(); @@ -214,7 +239,9 @@ class BalloonContainer : public views::View { private: BalloonSubContainer* GetContainerFor(Balloon* balloon) const { - return balloon->notification().sticky() ? + BalloonViewImpl* view = + static_cast<BalloonViewImpl*>(balloon->view()); + return view->sticky() ? sticky_container_ : non_sticky_container_; } @@ -279,6 +306,14 @@ void NotificationPanel::Hide() { } } +int NotificationPanel::GetStickyNotificationCount() const { + return balloon_container_->GetStickyNotificationCount(); +} + +int NotificationPanel::GetNewNotificationCount() const { + return balloon_container_->GetNewNotificationCount(); +} + //////////////////////////////////////////////////////////////////////////////// // BalloonCollectionImpl::NotificationUI overrides. @@ -291,6 +326,19 @@ void NotificationPanel::Add(Balloon* balloon) { StartStaleTimer(balloon); } +bool NotificationPanel::Update(Balloon* balloon) { + if (balloon_container_->Update(balloon)) { + if (state_ == CLOSED || state_ == MINIMIZED) + state_ = STICKY_AND_NEW; + Show(); + UpdatePanel(true); + StartStaleTimer(balloon); + return true; + } else { + return false; + } +} + void NotificationPanel::Remove(Balloon* balloon) { balloon_container_->Remove(balloon); // no change to the state @@ -425,7 +473,7 @@ void NotificationPanel::StartStaleTimer(Balloon* balloon) { void NotificationPanel::OnStale(BalloonViewImpl* view) { if (balloon_container_->HasBalloonView(view) && !view->stale()) { view->set_stale(); - if (balloon_container_->HasStickyNotifications()) { + if (balloon_container_->GetStickyNotificationCount() > 0) { state_ = STICKY_AND_NEW; } else { state_ = MINIMIZED; diff --git a/chrome/browser/chromeos/notifications/notification_panel.h b/chrome/browser/chromeos/notifications/notification_panel.h index cd9bf49..bbf8740 100644 --- a/chrome/browser/chromeos/notifications/notification_panel.h +++ b/chrome/browser/chromeos/notifications/notification_panel.h @@ -71,6 +71,7 @@ class NotificationPanel : public PanelController::Delegate, // BalloonCollectionImpl::NotificationUI overrides.. virtual void Add(Balloon* balloon); + virtual bool Update(Balloon* balloon); virtual void Remove(Balloon* balloon); virtual void ResizeNotification(Balloon* balloon, const gfx::Size& size); @@ -81,6 +82,12 @@ class NotificationPanel : public PanelController::Delegate, virtual void ClosePanel(); virtual void OnPanelStateChanged(PanelController::State state); + // Returns number of of sticky notifications. + int GetStickyNotificationCount() const; + + // Returns number of new notifications. + int GetNewNotificationCount() const; + private: enum State { FULL, // Show all notifications diff --git a/chrome/browser/chromeos/notifications/system_notification_factory.cc b/chrome/browser/chromeos/notifications/system_notification_factory.cc new file mode 100644 index 0000000..1e32d84 --- /dev/null +++ b/chrome/browser/chromeos/notifications/system_notification_factory.cc @@ -0,0 +1,20 @@ +// 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/chromeos/notifications/system_notification_factory.h" + +#include "chrome/browser/notifications/desktop_notification_service.h" + +namespace chromeos { + +// static +Notification SystemNotificationFactory::Create( + const GURL& icon, const string16& title, + const string16& text, + NotificationDelegate* delegate) { + string16 content_url = DesktopNotificationService::CreateDataUrl( + icon, title, text); + return Notification(GURL(), GURL(content_url), std::wstring(), delegate); +} +} // namespace chromeos diff --git a/chrome/browser/chromeos/notifications/system_notification_factory.h b/chrome/browser/chromeos/notifications/system_notification_factory.h new file mode 100644 index 0000000..8dc8d93 --- /dev/null +++ b/chrome/browser/chromeos/notifications/system_notification_factory.h @@ -0,0 +1,29 @@ +// 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. + +#ifndef CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_SYSTEM_NOTIFICATION_H_ +#define CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_SYSTEM_NOTIFICATION_H_ + +#include "base/basictypes.h" +#include "chrome/browser/notifications/notification.h" + +class GURL; +class NotificationDelegate; + +namespace chromeos { + +// A utility class for system notifications. +class SystemNotificationFactory { + public: + + // Creates a system notification. + static Notification Create( + const GURL& icon, const string16& title, + const string16& text, + NotificationDelegate* delegate); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_NOTIFICATIONS_SYSTEM_NOTIFICATION_H_ diff --git a/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm b/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm index d9f9c8f..7f48b1e 100644 --- a/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm +++ b/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm @@ -8,6 +8,7 @@ #include "chrome/browser/cocoa/notifications/balloon_controller.h" #include "chrome/browser/notifications/balloon.h" #include "chrome/browser/notifications/balloon_collection.h" +#include "chrome/browser/notifications/notification.h" #include "chrome/browser/renderer_host/test/test_render_view_host.h" #include "chrome/test/testing_profile.h" #import "third_party/ocmock/OCMock/OCMock.h" @@ -56,8 +57,7 @@ class BalloonControllerTest : public RenderViewHostTestHarness { TEST_F(BalloonControllerTest, ShowAndCloseTest) { Notification n(GURL("http://www.google.com"), GURL("http://www.google.com"), - L"http://www.google.com", new NotificationObjectProxy(-1, -1, -1, false), - false); + L"http://www.google.com", new NotificationObjectProxy(-1, -1, -1, false)); scoped_ptr<Balloon> balloon( new Balloon(n, profile_.get(), collection_.get())); @@ -75,8 +75,7 @@ TEST_F(BalloonControllerTest, ShowAndCloseTest) { TEST_F(BalloonControllerTest, SizesTest) { Notification n(GURL("http://www.google.com"), GURL("http://www.google.com"), - L"http://www.google.com", new NotificationObjectProxy(-1, -1, -1, false), - false); + L"http://www.google.com", new NotificationObjectProxy(-1, -1, -1, false)); scoped_ptr<Balloon> balloon( new Balloon(n, profile_.get(), collection_.get())); balloon->set_content_size(gfx::Size(100, 100)); diff --git a/chrome/browser/cocoa/notifications/balloon_view_bridge.h b/chrome/browser/cocoa/notifications/balloon_view_bridge.h index b3c552b..5c4b927 100644 --- a/chrome/browser/cocoa/notifications/balloon_view_bridge.h +++ b/chrome/browser/cocoa/notifications/balloon_view_bridge.h @@ -19,6 +19,7 @@ class BalloonViewBridge : public BalloonView { // BalloonView interface. virtual void Show(Balloon* balloon); + virtual void Update() {} virtual void RepositionToBalloon(); virtual void Close(bool by_user); virtual gfx::Size GetSize() const; diff --git a/chrome/browser/cocoa/notifications/balloon_view_host_mac.h b/chrome/browser/cocoa/notifications/balloon_view_host_mac.h index aabbba8..235ab3c 100644 --- a/chrome/browser/cocoa/notifications/balloon_view_host_mac.h +++ b/chrome/browser/cocoa/notifications/balloon_view_host_mac.h @@ -7,6 +7,7 @@ #include "app/gfx/native_widget_types.h" #include "chrome/browser/notifications/balloon.h" +#include "chrome/browser/notifications/notification.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" #import "chrome/browser/renderer_host/render_widget_host_view_mac.h" #include "chrome/browser/renderer_host/site_instance.h" diff --git a/chrome/browser/gtk/notifications/balloon_view_gtk.h b/chrome/browser/gtk/notifications/balloon_view_gtk.h index 9e2e871..69bd696 100644 --- a/chrome/browser/gtk/notifications/balloon_view_gtk.h +++ b/chrome/browser/gtk/notifications/balloon_view_gtk.h @@ -39,6 +39,7 @@ class BalloonViewImpl : public BalloonView, // BalloonView interface. virtual void Show(Balloon* balloon); + virtual void Update() {} virtual void RepositionToBalloon(); virtual void Close(bool by_user); virtual gfx::Size GetSize() const; diff --git a/chrome/browser/gtk/notifications/balloon_view_host_gtk.h b/chrome/browser/gtk/notifications/balloon_view_host_gtk.h index 4bcd5b4..43a0e7d 100644 --- a/chrome/browser/gtk/notifications/balloon_view_host_gtk.h +++ b/chrome/browser/gtk/notifications/balloon_view_host_gtk.h @@ -8,6 +8,7 @@ #include "app/gfx/native_widget_types.h" #include "chrome/browser/gtk/extension_view_gtk.h" #include "chrome/browser/notifications/balloon.h" +#include "chrome/browser/notifications/notification.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" #include "chrome/browser/renderer_host/render_widget_host_view_gtk.h" #include "chrome/browser/renderer_host/site_instance.h" diff --git a/chrome/browser/notifications/balloon.cc b/chrome/browser/notifications/balloon.cc index 040abec..4d9a94f 100644 --- a/chrome/browser/notifications/balloon.cc +++ b/chrome/browser/notifications/balloon.cc @@ -6,13 +6,14 @@ #include "base/logging.h" #include "chrome/browser/notifications/balloon_collection.h" +#include "chrome/browser/notifications/notification.h" #include "chrome/browser/renderer_host/site_instance.h" #include "gfx/rect.h" Balloon::Balloon(const Notification& notification, Profile* profile, BalloonCollection* collection) : profile_(profile), - notification_(notification), + notification_(new Notification(notification)), collection_(collection) { } @@ -34,14 +35,22 @@ void Balloon::set_view(BalloonView* balloon_view) { } void Balloon::Show() { - notification_.Display(); + notification_->Display(); if (balloon_view_.get()) { balloon_view_->Show(this); } } +void Balloon::Update(const Notification& notification) { + notification_.reset(new Notification(notification)); + notification_->Display(); + if (balloon_view_.get()) { + balloon_view_->Update(); + } +} + void Balloon::OnClose(bool by_user) { - notification_.Close(by_user); + notification_->Close(by_user); collection_->OnBalloonClosed(this); } diff --git a/chrome/browser/notifications/balloon.h b/chrome/browser/notifications/balloon.h index 0136a9c..ddaa14d 100644 --- a/chrome/browser/notifications/balloon.h +++ b/chrome/browser/notifications/balloon.h @@ -11,13 +11,13 @@ #include "base/basictypes.h" #include "base/scoped_ptr.h" -#include "chrome/browser/notifications/notification.h" #include "gfx/point.h" #include "gfx/rect.h" #include "gfx/size.h" class Balloon; class BalloonCollection; +class Notification; class Profile; class SiteInstance; @@ -29,6 +29,9 @@ class BalloonView { // Show the view on the screen. virtual void Show(Balloon* balloon) = 0; + // Notify that the content of notification has chagned. + virtual void Update() = 0; + // Reposition the view to match the position of its balloon. virtual void RepositionToBalloon() = 0; @@ -47,7 +50,7 @@ class Balloon { BalloonCollection* collection); virtual ~Balloon(); - const Notification& notification() const { return notification_; } + const Notification& notification() const { return *notification_.get(); } Profile* profile() const { return profile_; } const gfx::Point& position() const { return position_; } @@ -76,6 +79,9 @@ class Balloon { // Shows the balloon. virtual void Show(); + // Notify that the content of notification has changed. + virtual void Update(const Notification& notification); + // Called when the balloon is closed, either by user (through the UI) // or by a script. virtual void OnClose(bool by_user); @@ -88,7 +94,7 @@ class Balloon { Profile* profile_; // The notification being shown in this balloon. - Notification notification_; + scoped_ptr<Notification> notification_; // The collection that this balloon belongs to. Non-owned pointer. BalloonCollection* collection_; diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc index 55613f5..d351880 100644 --- a/chrome/browser/notifications/desktop_notification_service.cc +++ b/chrome/browser/notifications/desktop_notification_service.cc @@ -36,14 +36,9 @@ using WebKit::WebNotificationPresenter; -namespace { - -// 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) { - +// static +string16 DesktopNotificationService::CreateDataUrl( + const GURL& icon_url, const string16& title, const string16& body) { int resource; string16 line_name; string16 line; @@ -81,8 +76,6 @@ static string16 CreateDataUrl(const GURL& icon_url, const string16& title, return ReplaceStringPlaceholders(format_string, subst, NULL); } -} - // A task object which calls the renderer to inform the web page that the // permission request has completed. class NotificationPermissionCallbackTask : public Task { @@ -334,21 +327,20 @@ bool DesktopNotificationService::CancelDesktopNotification( scoped_refptr<NotificationObjectProxy> proxy( new NotificationObjectProxy(process_id, route_id, notification_id, false)); - Notification notif(GURL(), GURL(), L"", proxy, false); + Notification notif(GURL(), GURL(), L"", proxy); return ui_manager_->Cancel(notif); } bool DesktopNotificationService::ShowDesktopNotification( const GURL& origin, const GURL& url, int process_id, int route_id, - DesktopNotificationSource source, int notification_id, - bool sticky) { + DesktopNotificationSource 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, DisplayNameForOrigin(origin), proxy, sticky); + Notification notif(origin, url, DisplayNameForOrigin(origin), proxy); ShowNotification(notif); return true; } @@ -356,8 +348,7 @@ bool DesktopNotificationService::ShowDesktopNotification( bool DesktopNotificationService::ShowDesktopNotificationText( const GURL& origin, const GURL& icon, const string16& title, const string16& text, int process_id, int route_id, - DesktopNotificationSource source, int notification_id, - bool sticky) { + DesktopNotificationSource source, int notification_id) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); NotificationObjectProxy* proxy = new NotificationObjectProxy(process_id, route_id, @@ -366,7 +357,7 @@ bool DesktopNotificationService::ShowDesktopNotificationText( // "upconvert" the string parameters to a data: URL. string16 data_url = CreateDataUrl(icon, title, text); Notification notif( - origin, GURL(data_url), DisplayNameForOrigin(origin), proxy, sticky); + origin, GURL(data_url), DisplayNameForOrigin(origin), proxy); ShowNotification(notif); return true; } diff --git a/chrome/browser/notifications/desktop_notification_service.h b/chrome/browser/notifications/desktop_notification_service.h index b1050c9..6e9a6d8 100644 --- a/chrome/browser/notifications/desktop_notification_service.h +++ b/chrome/browser/notifications/desktop_notification_service.h @@ -49,16 +49,14 @@ class DesktopNotificationService : public NotificationObserver { // 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. |sticky| is used to indicate that the notification - // is sticky and cannot be dismissed by a user. + // this notification. bool ShowDesktopNotification(const GURL& origin, const GURL& url, int process_id, int route_id, DesktopNotificationSource source, - int notification_id, - bool sticky); + int notification_id); bool ShowDesktopNotificationText(const GURL& origin, const GURL& icon, const string16& title, const string16& text, int process_id, - int route_id, DesktopNotificationSource source, int notification_id, - bool sticky); + int route_id, DesktopNotificationSource source, int notification_id); + // Cancels a notification. If it has already been shown, it will be // removed from the screen. If it hasn't been shown yet, it won't be @@ -78,6 +76,11 @@ class DesktopNotificationService : public NotificationObserver { const NotificationSource& source, const NotificationDetails& details); + // 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); private: void InitPrefs(); diff --git a/chrome/browser/notifications/desktop_notifications_unittest.cc b/chrome/browser/notifications/desktop_notifications_unittest.cc index ecc8f73..b15a46e 100644 --- a/chrome/browser/notifications/desktop_notifications_unittest.cc +++ b/chrome/browser/notifications/desktop_notifications_unittest.cc @@ -21,8 +21,7 @@ void MockBalloonCollection::Add(const Notification& notification, Notification test_notification(notification.origin_url(), notification.content_url(), notification.display_source(), - log_proxy_.get(), - notification.sticky()); + log_proxy_.get()); BalloonCollectionImpl::Add(test_notification, profile); } @@ -30,8 +29,7 @@ bool MockBalloonCollection::Remove(const Notification& notification) { Notification test_notification(notification.origin_url(), notification.content_url(), notification.display_source(), - log_proxy_.get(), - notification.sticky()); + log_proxy_.get()); return BalloonCollectionImpl::Remove(test_notification); } @@ -87,25 +85,20 @@ TEST_F(DesktopNotificationsTest, TestShow) { EXPECT_TRUE(service_->ShowDesktopNotificationText( GURL("http://www.google.com"), GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 1, false)); + 0, 0, DesktopNotificationService::PageNotification, 1)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); EXPECT_TRUE(service_->ShowDesktopNotification( GURL("http://www.google.com"), GURL("http://www.google.com/notification.html"), - 0, 0, DesktopNotificationService::PageNotification, 2, false)); + 0, 0, DesktopNotificationService::PageNotification, 2)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(2, balloon_collection_->count()); EXPECT_EQ("notification displayed\n" "notification displayed\n", log_output_); - - std::set<Balloon*>::iterator iter = balloon_collection_->balloons().begin(); - EXPECT_FALSE((*iter)->notification().sticky()); - iter++; - EXPECT_FALSE((*iter)->notification().sticky()); } TEST_F(DesktopNotificationsTest, TestClose) { @@ -113,7 +106,7 @@ TEST_F(DesktopNotificationsTest, TestClose) { EXPECT_TRUE(service_->ShowDesktopNotificationText( GURL("http://www.google.com"), GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 1, false)); + 0, 0, DesktopNotificationService::PageNotification, 1)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); @@ -141,7 +134,7 @@ TEST_F(DesktopNotificationsTest, TestCancel) { GURL("http://www.google.com"), GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), process_id, route_id, DesktopNotificationService::PageNotification, - notification_id, false)); + notification_id)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); @@ -168,7 +161,7 @@ TEST_F(DesktopNotificationsTest, TestPositioning) { EXPECT_TRUE(service_->ShowDesktopNotificationText( GURL("http://www.google.com"), GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, id, false)); + 0, 0, DesktopNotificationService::PageNotification, id)); expected_log.append("notification displayed\n"); int top = balloon_collection_->UppermostVerticalPosition(); if (id > 0) @@ -189,12 +182,12 @@ TEST_F(DesktopNotificationsTest, TestVariableSize) { "Really Really Really Really Really Really " "Really Really Really Really Really Really Really Long Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 0, false)); + 0, 0, DesktopNotificationService::PageNotification, 0)); expected_log.append("notification displayed\n"); EXPECT_TRUE(service_->ShowDesktopNotificationText( GURL("http://short.google.com"), GURL("/icon.png"), ASCIIToUTF16("Short title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 1, false)); + 0, 0, DesktopNotificationService::PageNotification, 1)); expected_log.append("notification displayed\n"); std::set<Balloon*>& balloons = balloon_collection_->balloons(); @@ -225,7 +218,7 @@ TEST_F(DesktopNotificationsTest, TestQueueing) { GURL("http://www.google.com"), GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), process_id, route_id, - DesktopNotificationService::PageNotification, id, false)); + DesktopNotificationService::PageNotification, id)); } MessageLoopForUI::current()->RunAllPending(); @@ -275,7 +268,7 @@ TEST_F(DesktopNotificationsTest, TestEarlyDestruction) { EXPECT_TRUE(service_->ShowDesktopNotificationText( GURL("http://www.google.com"), GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, id, false)); + 0, 0, DesktopNotificationService::PageNotification, id)); } service_.reset(NULL); } @@ -288,7 +281,7 @@ TEST_F(DesktopNotificationsTest, TestUserInputEscaping) { GURL("/icon.png"), ASCIIToUTF16("<script>window.alert('uh oh');</script>"), ASCIIToUTF16("<i>this text is in italics</i>"), - 0, 0, DesktopNotificationService::PageNotification, 1, false)); + 0, 0, DesktopNotificationService::PageNotification, 1)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); @@ -297,21 +290,3 @@ TEST_F(DesktopNotificationsTest, TestUserInputEscaping) { EXPECT_EQ(std::string::npos, data_url.spec().find("<script>")); EXPECT_EQ(std::string::npos, data_url.spec().find("<i>")); } - -TEST_F(DesktopNotificationsTest, TestSticky) { - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 1, true)); - MessageLoopForUI::current()->RunAllPending(); - EXPECT_TRUE(service_->ShowDesktopNotification( - GURL("http://www.google.com"), - GURL("http://www.google.com/notification.html"), - 0, 0, DesktopNotificationService::PageNotification, 2, true)); - MessageLoopForUI::current()->RunAllPending(); - - std::set<Balloon*>::iterator iter = balloon_collection_->balloons().begin(); - EXPECT_TRUE((*iter)->notification().sticky()); - iter++; - EXPECT_TRUE((*iter)->notification().sticky()); -} diff --git a/chrome/browser/notifications/notification.h b/chrome/browser/notifications/notification.h index f80a65f..a58c2ad 100644 --- a/chrome/browser/notifications/notification.h +++ b/chrome/browser/notifications/notification.h @@ -1,16 +1,16 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// 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. #ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_H_ #define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_H_ -#include <string> - #include "base/basictypes.h" #include "chrome/browser/notifications/notification_object_proxy.h" #include "googleurl/src/gurl.h" +class NotificationDelegate; + // 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. @@ -18,21 +18,18 @@ class Notification { public: Notification(const GURL& origin_url, const GURL& content_url, const std::wstring& display_source, - NotificationObjectProxy* proxy, - bool sticky) + NotificationDelegate* delegate) : origin_url_(origin_url), content_url_(content_url), display_source_(display_source), - proxy_(proxy), - sticky_(sticky) { + delegate_(delegate) { } Notification(const Notification& notification) : origin_url_(notification.origin_url()), content_url_(notification.content_url()), display_source_(notification.display_source()), - proxy_(notification.proxy()), - sticky_(notification.sticky()) { + delegate_(notification.delegate()) { } // The URL (may be data:) containing the contents for the notification. @@ -44,20 +41,16 @@ class Notification { // A display string for the source of the notification. const std::wstring& display_source() const { return display_source_; } - void Display() const { proxy()->Display(); } - void Error() const { proxy()->Error(); } - void Close(bool by_user) const { proxy()->Close(by_user); } - - bool sticky() const { - return sticky_; - } + void Display() const { delegate()->Display(); } + void Error() const { delegate()->Error(); } + void Close(bool by_user) const { delegate()->Close(by_user); } bool IsSame(const Notification& other) const { - return (*proxy_).IsSame(*(other.proxy())); + return delegate()->id() == other.delegate()->id(); } private: - NotificationObjectProxy* proxy() const { return proxy_.get(); } + NotificationDelegate* delegate() const { return delegate_.get(); } // The Origin of the page/worker which created this notification. GURL origin_url_; @@ -72,11 +65,7 @@ class Notification { // A proxy object that allows access back to the JavaScript object that // represents the notification, for firing events. - scoped_refptr<NotificationObjectProxy> proxy_; - - // A sticky flag. A sticky notification cannot be dismissed by a - // user. - bool sticky_; + scoped_refptr<NotificationDelegate> delegate_; // Disallow assign. Copy constructor written above. void operator=(const Notification&); diff --git a/chrome/browser/notifications/notification_delegate.h b/chrome/browser/notifications/notification_delegate.h new file mode 100644 index 0000000..6d69335 --- /dev/null +++ b/chrome/browser/notifications/notification_delegate.h @@ -0,0 +1,34 @@ +// 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. + +#ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_DELEGATE_H_ +#define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_DELEGATE_H_ + +#include <string> + +#include "base/ref_counted.h" + +// Delegate for a notification. This class has two role, to implement +// callback methods for notification, and provides an identify of +// the associated notification. +class NotificationDelegate + : public base::RefCountedThreadSafe<NotificationDelegate> { + public: + + // To be called when the desktop notification is actually shown. + virtual void Display() = 0; + + // To be called when the desktop notification cannot be shown due to an + // error. + virtual void Error() = 0; + + // To be called when the desktop notification is closed. If closed by a + // user explicitly (as opposed to timeout/script), |by_user| should be true. + virtual void Close(bool by_user) = 0; + + // Returns unique id of the notification. + virtual std::string id() const = 0; +}; + +#endif // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_DELEGATE_H_ diff --git a/chrome/browser/notifications/notification_object_proxy.cc b/chrome/browser/notifications/notification_object_proxy.cc index 3b45ddf..76363e5 100644 --- a/chrome/browser/notifications/notification_object_proxy.cc +++ b/chrome/browser/notifications/notification_object_proxy.cc @@ -49,6 +49,12 @@ void NotificationObjectProxy::Close(bool by_user) { } } +std::string NotificationObjectProxy::id() const { + return StringPrintf("%d:%d:%d:%d", process_id_, route_id_, + notification_id_, worker_); +} + + void NotificationObjectProxy::DeliverMessage(IPC::Message* message) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); ChromeThread::PostTask( diff --git a/chrome/browser/notifications/notification_object_proxy.h b/chrome/browser/notifications/notification_object_proxy.h index 46c56f5..a956b3a 100644 --- a/chrome/browser/notifications/notification_object_proxy.h +++ b/chrome/browser/notifications/notification_object_proxy.h @@ -5,7 +5,9 @@ #ifndef CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_OBJECT_PROXY_H_ #define CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_OBJECT_PROXY_H_ -#include "base/ref_counted.h" +#include <string> + +#include "chrome/browser/notifications/notification_delegate.h" class MessageLoop; namespace IPC { @@ -17,30 +19,17 @@ class Message; // 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 NotificationDelegate { 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. + // NotificationDelegate implementation. virtual void Display(); - - // To be called when the desktop notification cannot be shown due to an - // error. virtual void Error(); - - // To be called when the desktop notification is closed. If closed by a - // user explicitly (as opposed to timeout/script), |by_user| should be true. virtual void Close(bool by_user); - - // Compares two proxies by ids to decide if they are equal. - bool IsSame(const NotificationObjectProxy& other) const { - return (notification_id_ == other.notification_id_ && - route_id_ == other.route_id_ && - process_id_ == other.process_id_ && - worker_ == other.worker_); - } + virtual std::string id() const; protected: friend class base::RefCountedThreadSafe<NotificationObjectProxy>; diff --git a/chrome/browser/notifications/notification_test_util.h b/chrome/browser/notifications/notification_test_util.h index b4530f5..95e8fd1 100644 --- a/chrome/browser/notifications/notification_test_util.h +++ b/chrome/browser/notifications/notification_test_util.h @@ -40,6 +40,7 @@ class MockBalloonView : public BalloonView { explicit MockBalloonView(Balloon * balloon) : balloon_(balloon) {} void Show(Balloon* balloon) {} + void Update() {} void RepositionToBalloon() {} void Close(bool by_user) { balloon_->OnClose(by_user); } gfx::Size GetSize() const { return balloon_->content_size(); } diff --git a/chrome/browser/notifications/notification_ui_manager.h b/chrome/browser/notifications/notification_ui_manager.h index 9e2cf18..2eaedd3 100644 --- a/chrome/browser/notifications/notification_ui_manager.h +++ b/chrome/browser/notifications/notification_ui_manager.h @@ -45,6 +45,11 @@ class NotificationUIManager // Removes a notification. virtual bool Cancel(const Notification& notification); + // Returns balloon collection. + BalloonCollection* balloon_collection() { + return balloon_collection_.get(); + } + private: // Attempts to display notifications from the show_queue if the user // is active. diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 7307a82..6d62fb2 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -1731,7 +1731,7 @@ void RenderViewHost::OnShowDesktopNotification(const GURL& source_origin, process()->profile()->GetDesktopNotificationService(); service->ShowDesktopNotification(source_origin, url, process()->id(), routing_id(), DesktopNotificationService::PageNotification, - notification_id, false); + notification_id); } void RenderViewHost::OnShowDesktopNotificationText(const GURL& source_origin, @@ -1741,7 +1741,7 @@ void RenderViewHost::OnShowDesktopNotificationText(const GURL& source_origin, process()->profile()->GetDesktopNotificationService(); service->ShowDesktopNotificationText(source_origin, icon, title, text, process()->id(), routing_id(), - DesktopNotificationService::PageNotification, notification_id, false); + DesktopNotificationService::PageNotification, notification_id); } void RenderViewHost::OnCancelDesktopNotification(int notification_id) { diff --git a/chrome/browser/views/notifications/balloon_view.h b/chrome/browser/views/notifications/balloon_view.h index 1e03be1..e6853e0 100644 --- a/chrome/browser/views/notifications/balloon_view.h +++ b/chrome/browser/views/notifications/balloon_view.h @@ -53,10 +53,11 @@ class BalloonViewImpl : public BalloonView, ~BalloonViewImpl(); // BalloonView interface. - void Show(Balloon* balloon); - void RepositionToBalloon(); - void Close(bool by_user); - gfx::Size GetSize() const; + virtual void Show(Balloon* balloon); + virtual void Update() {} + virtual void RepositionToBalloon(); + virtual void Close(bool by_user); + virtual gfx::Size GetSize() const; private: // views::View interface. diff --git a/chrome/browser/views/notifications/balloon_view_host.h b/chrome/browser/views/notifications/balloon_view_host.h index 75f3ef7..84610a0 100644 --- a/chrome/browser/views/notifications/balloon_view_host.h +++ b/chrome/browser/views/notifications/balloon_view_host.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_VIEWS_NOTIFICATIONS_BALLOON_VIEW_HOST_H_ #include "chrome/browser/notifications/balloon.h" +#include "chrome/browser/notifications/notification.h" #include "chrome/browser/renderer_host/render_view_host_delegate.h" #include "chrome/browser/renderer_host/site_instance.h" #include "chrome/browser/tab_contents/render_view_host_delegate_helper.h" diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index be04397..f3058c9 100755 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -306,6 +306,8 @@ 'browser/chromeos/notifications/balloon_view.cc', 'browser/chromeos/notifications/notification_panel.h', 'browser/chromeos/notifications/notification_panel.cc', + 'browser/chromeos/notifications/system_notification_factory.h', + 'browser/chromeos/notifications/system_notification_factory.cc', 'browser/chromeos/browser_notification_observers.cc', 'browser/chromeos/compact_location_bar_host.cc', 'browser/chromeos/compact_location_bar_host.h', @@ -1545,6 +1547,7 @@ 'browser/notifications/desktop_notification_service.cc', 'browser/notifications/desktop_notification_service.h', 'browser/notifications/notification.h', + 'browser/notifications/notification_delegate.h', 'browser/notifications/notification_object_proxy.cc', 'browser/notifications/notification_object_proxy.h', 'browser/notifications/notification_ui_manager.cc', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index bd19489..c809459 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1189,6 +1189,7 @@ 'browser/browser_browsertest.cc', 'browser/browser_init_browsertest.cc', 'browser/browsing_data_local_storage_helper_unittest.cc', + 'browser/chromeos/notifications/notification_browsertest.cc', 'browser/crash_recovery_browsertest.cc', 'browser/download/save_page_browsertest.cc', 'browser/extensions/autoupdate_interceptor.cc', @@ -1245,6 +1246,11 @@ 'test/render_view_test.h', ], 'conditions': [ + ['chromeos==0', { + 'sources/': [ + ['exclude', '^browser/chromeos'], + ], + }], ['OS=="win"', { 'sources': [ 'app/chrome_dll.rc', |