Commit 5dd19912 authored by stevenjb@chromium.org's avatar stevenjb@chromium.org

Fix Ash notification updates

In Chrome, it turns out that every Notification has a unique id. In the Ash implementation we need to track and update that id when an existing Bubble is updated.

This also ensures that the UI is safely created initially (in case the initial asynchronous Update is delayed) to prevent crashes and to make Layout more consistent.

Also includes some cleanup of the WebNotificationTray API.

BUG=141285


Review URL: https://chromiumcodereview.appspot.com/10855079

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@150979 0039d316-1c4b-4281-b951-d872f2087c98
parent 97dc9396
...@@ -27,7 +27,10 @@ namespace ash { ...@@ -27,7 +27,10 @@ namespace ash {
namespace internal { namespace internal {
class StatusAreaWidget; class StatusAreaWidget;
class WebNotificationButtonView;
class WebNotificationList; class WebNotificationList;
class WebNotificationMenuModel;
class WebNotificationView;
} }
// Status area tray for showing browser and app notifications. The client // Status area tray for showing browser and app notifications. The client
...@@ -85,34 +88,25 @@ class ASH_EXPORT WebNotificationTray : public internal::TrayBackgroundView { ...@@ -85,34 +88,25 @@ class ASH_EXPORT WebNotificationTray : public internal::TrayBackgroundView {
const string16& display_source, const string16& display_source,
const std::string& extension_id); const std::string& extension_id);
// Update an existing notification. // Update an existing notification with id = old_id and set its id to new_id.
void UpdateNotification(const std::string& id, void UpdateNotification(const std::string& old_id,
const std::string& new_id,
const string16& title, const string16& title,
const string16& message); const string16& message);
// Remove an existing notification and notify the delegate. // Remove an existing notification.
void RemoveNotification(const std::string& id); void RemoveNotification(const std::string& id);
// Remove all notifications and notify the delegate.
void RemoveAllNotifications();
// Set the notification image. // Set the notification image.
void SetNotificationImage(const std::string& id, void SetNotificationImage(const std::string& id,
const gfx::ImageSkia& image); const gfx::ImageSkia& image);
// Disable all notifications matching notification |id|.
void DisableByExtension(const std::string& id);
void DisableByUrl(const std::string& id);
// Show the message center bubble. Should only be called by StatusAreaWidget. // Show the message center bubble. Should only be called by StatusAreaWidget.
void ShowMessageCenterBubble(); void ShowMessageCenterBubble();
// Hide the message center bubble. Should only be called by StatusAreaWidget. // Hide the message center bubble. Should only be called by StatusAreaWidget.
void HideMessageCenterBubble(); void HideMessageCenterBubble();
// Hide the message center bubble if there are no notifications.
void HideMessageCenterBubbleIfEmpty();
// Show a single notification bubble for the most recent notification. // Show a single notification bubble for the most recent notification.
void ShowNotificationBubble(); void ShowNotificationBubble();
...@@ -122,26 +116,42 @@ class ASH_EXPORT WebNotificationTray : public internal::TrayBackgroundView { ...@@ -122,26 +116,42 @@ class ASH_EXPORT WebNotificationTray : public internal::TrayBackgroundView {
// Updates tray visibility login status of the system changes. // Updates tray visibility login status of the system changes.
void UpdateAfterLoginStatusChange(user::LoginStatus login_status); void UpdateAfterLoginStatusChange(user::LoginStatus login_status);
// Request the Delegate to the settings dialog.
void ShowSettings(const std::string& id);
// Called when a notification is clicked on. Event is passed to the Delegate.
void OnClicked(const std::string& id);
// Overridden from TrayBackgroundView. // Overridden from TrayBackgroundView.
virtual void SetShelfAlignment(ShelfAlignment alignment) OVERRIDE; virtual void SetShelfAlignment(ShelfAlignment alignment) OVERRIDE;
// Overridden from internal::ActionableView. // Overridden from internal::ActionableView.
virtual bool PerformAction(const views::Event& event) OVERRIDE; virtual bool PerformAction(const views::Event& event) OVERRIDE;
protected:
// Send a remove request to the delegate.
void SendRemoveNotification(const std::string& id);
// Send a remove request for all notifications to the delegate.
void SendRemoveAllNotifications();
// Disable all notifications matching notification |id|.
void DisableByExtension(const std::string& id);
void DisableByUrl(const std::string& id);
// Request the Delegate to the settings dialog.
void ShowSettings(const std::string& id);
// Called when a notification is clicked on. Event is passed to the Delegate.
void OnClicked(const std::string& id);
private: private:
class Bubble; class Bubble;
friend class internal::WebNotificationButtonView;
friend class internal::WebNotificationMenuModel;
friend class internal::WebNotificationView;
FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, WebNotifications); FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, WebNotifications);
FRIEND_TEST_ALL_PREFIXES(WebNotificationTrayTest, WebNotificationBubble);
int GetNotificationCount() const; int GetNotificationCount() const;
void UpdateTray(); void UpdateTray();
void UpdateTrayAndBubble(); void UpdateTrayAndBubble();
void HideBubble(Bubble* bubble); void HideBubble(Bubble* bubble);
bool HasNotificationForTest(const std::string& id) const;
const internal::WebNotificationList* notification_list() const { const internal::WebNotificationList* notification_list() const {
return notification_list_.get(); return notification_list_.get();
......
...@@ -55,8 +55,19 @@ class TestDelegate : public WebNotificationTray::Delegate { ...@@ -55,8 +55,19 @@ class TestDelegate : public WebNotificationTray::Delegate {
"" /* extension id */); "" /* extension id */);
} }
void UpdateNotification(WebNotificationTray* tray,
const std::string& old_id,
const std::string& new_id) {
notification_ids_.erase(old_id);
notification_ids_.insert(new_id);
tray->UpdateNotification(old_id, new_id,
ASCIIToUTF16("Updated Web Notification"),
ASCIIToUTF16("Updated message body."));
}
void RemoveNotification(WebNotificationTray* tray, const std::string& id) { void RemoveNotification(WebNotificationTray* tray, const std::string& id) {
tray->RemoveNotification(id); tray->RemoveNotification(id);
notification_ids_.erase(id);
} }
bool HasNotificationId(const std::string& id) { bool HasNotificationId(const std::string& id) {
...@@ -80,23 +91,57 @@ TEST_F(WebNotificationTrayTest, WebNotifications) { ...@@ -80,23 +91,57 @@ TEST_F(WebNotificationTrayTest, WebNotifications) {
ASSERT_TRUE(tray->GetWidget()); ASSERT_TRUE(tray->GetWidget());
// Adding a notification should show the bubble. // Add a notification.
delegate->AddNotification(tray, "test_id1"); delegate->AddNotification(tray, "test_id1");
EXPECT_TRUE(tray->notification_bubble() != NULL);
EXPECT_EQ(1, tray->GetNotificationCount()); EXPECT_EQ(1, tray->GetNotificationCount());
EXPECT_TRUE(tray->HasNotificationForTest("test_id1"));
delegate->AddNotification(tray, "test_id2"); delegate->AddNotification(tray, "test_id2");
delegate->AddNotification(tray, "test_id2"); delegate->AddNotification(tray, "test_id2");
EXPECT_EQ(2, tray->GetNotificationCount()); EXPECT_EQ(2, tray->GetNotificationCount());
// Ensure that removing a notification removes it from the tray, and signals EXPECT_TRUE(tray->HasNotificationForTest("test_id2"));
// the delegate.
EXPECT_TRUE(delegate->HasNotificationId("test_id2")); // Ensure that updating a notification does not affect the count.
delegate->RemoveNotification(tray, "test_id2"); delegate->UpdateNotification(tray, "test_id2", "test_id3");
delegate->UpdateNotification(tray, "test_id3", "test_id3");
EXPECT_EQ(2, tray->GetNotificationCount());
EXPECT_FALSE(delegate->HasNotificationId("test_id2")); EXPECT_FALSE(delegate->HasNotificationId("test_id2"));
EXPECT_EQ(1, tray->GetNotificationCount()); EXPECT_FALSE(tray->HasNotificationForTest("test_id2"));
EXPECT_TRUE(delegate->HasNotificationId("test_id3"));
// Removing the last notification should hide the bubble. // Ensure that Removing the first notification removes it from the tray.
delegate->RemoveNotification(tray, "test_id1"); delegate->RemoveNotification(tray, "test_id1");
EXPECT_FALSE(delegate->HasNotificationId("test_id1"));
EXPECT_FALSE(tray->HasNotificationForTest("test_id1"));
EXPECT_EQ(1, tray->GetNotificationCount());
// Remove the remianing notification.
delegate->RemoveNotification(tray, "test_id3");
EXPECT_EQ(0, tray->GetNotificationCount()); EXPECT_EQ(0, tray->GetNotificationCount());
EXPECT_FALSE(tray->HasNotificationForTest("test_id3"));
}
TEST_F(WebNotificationTrayTest, WebNotificationBubble) {
WebNotificationTray* tray = GetWebNotificationTray();
scoped_ptr<TestDelegate> delegate(new TestDelegate);
tray->SetDelegate(delegate.get());
ASSERT_TRUE(tray->GetWidget());
// Adding a notification should show the bubble.
delegate->AddNotification(tray, "test_id1");
EXPECT_TRUE(tray->notification_bubble() != NULL);
// Updating a notification should not hide the bubble.
delegate->AddNotification(tray, "test_id2");
delegate->UpdateNotification(tray, "test_id2", "test_id3");
EXPECT_TRUE(tray->notification_bubble() != NULL);
// Removing the first notification should not hide the bubble.
delegate->RemoveNotification(tray, "test_id1");
EXPECT_TRUE(tray->notification_bubble() != NULL);
// Removing the visible notification should hide the bubble.
delegate->RemoveNotification(tray, "test_id3");
EXPECT_TRUE(tray->notification_bubble() == NULL); EXPECT_TRUE(tray->notification_bubble() == NULL);
} }
......
...@@ -93,8 +93,9 @@ BalloonViewAsh::~BalloonViewAsh() { ...@@ -93,8 +93,9 @@ BalloonViewAsh::~BalloonViewAsh() {
void BalloonViewAsh::Show(Balloon* balloon) { void BalloonViewAsh::Show(Balloon* balloon) {
balloon_ = balloon; balloon_ = balloon;
const Notification& notification = balloon_->notification(); const Notification& notification = balloon_->notification();
current_notification_id_ = notification.notification_id();
std::string extension_id = GetExtensionId(balloon); std::string extension_id = GetExtensionId(balloon);
GetWebNotificationTray()->AddNotification(notification.notification_id(), GetWebNotificationTray()->AddNotification(current_notification_id_,
notification.title(), notification.title(),
notification.body(), notification.body(),
notification.display_source(), notification.display_source(),
...@@ -104,9 +105,12 @@ void BalloonViewAsh::Show(Balloon* balloon) { ...@@ -104,9 +105,12 @@ void BalloonViewAsh::Show(Balloon* balloon) {
void BalloonViewAsh::Update() { void BalloonViewAsh::Update() {
const Notification& notification = balloon_->notification(); const Notification& notification = balloon_->notification();
GetWebNotificationTray()->UpdateNotification(notification.notification_id(), std::string new_notification_id = notification.notification_id();
GetWebNotificationTray()->UpdateNotification(current_notification_id_,
new_notification_id,
notification.title(), notification.title(),
notification.body()); notification.body());
current_notification_id_ = new_notification_id;
FetchIcon(notification); FetchIcon(notification);
} }
......
...@@ -30,6 +30,8 @@ class BalloonViewAsh : public BalloonView { ...@@ -30,6 +30,8 @@ class BalloonViewAsh : public BalloonView {
BalloonCollection* collection_; BalloonCollection* collection_;
Balloon* balloon_; Balloon* balloon_;
scoped_ptr<IconFetcher> icon_fetcher_; scoped_ptr<IconFetcher> icon_fetcher_;
// Track the current notification id so that it can be updated properly.
std::string current_notification_id_;
DISALLOW_COPY_AND_ASSIGN(BalloonViewAsh); DISALLOW_COPY_AND_ASSIGN(BalloonViewAsh);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment