diff options
author | dewittj@chromium.org <dewittj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-06 04:48:57 +0000 |
---|---|---|
committer | dewittj@chromium.org <dewittj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-06-06 04:48:57 +0000 |
commit | 0fa85dd72dad4416aa8dd2c9d06cea7e413031cd (patch) | |
tree | 10c2795922686d59950df01d8cd39e249789246e | |
parent | 91a43c197b68ac384d1ad2fef900f7a536b0d8b7 (diff) | |
download | chromium_src-0fa85dd72dad4416aa8dd2c9d06cea7e413031cd.zip chromium_src-0fa85dd72dad4416aa8dd2c9d06cea7e413031cd.tar.gz chromium_src-0fa85dd72dad4416aa8dd2c9d06cea7e413031cd.tar.bz2 |
Enable users of NotificationUIManager to specify binary images.
This refactors message_center::Notification to hold a class
containing the optional data associated with the
notification. It also alters chrome/browser/notification so
that you can manually set this.
Ash tests only updated to use new API.
TBR=sky@chromium.org,stevenjb@chromium.org
BUG=227093
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=204181
Review URL: https://chromiumcodereview.appspot.com/14631005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@204419 0039d316-1c4b-4281-b951-d872f2087c98
33 files changed, 882 insertions, 685 deletions
diff --git a/ash/shell/window_type_launcher.cc b/ash/shell/window_type_launcher.cc index bf7d059..3080f91 100644 --- a/ash/shell/window_type_launcher.cc +++ b/ash/shell/window_type_launcher.cc @@ -347,16 +347,21 @@ void WindowTypeLauncher::ButtonPressed(views::Button* sender, base::TimeDelta::FromSeconds(5)); } else if (sender == show_web_notification_) { + scoped_ptr<message_center::Notification> notification; + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "id0", + ASCIIToUTF16("Test Shell Web Notification"), + ASCIIToUTF16("Notification message body."), + gfx::Image(), + ASCIIToUTF16("www.testshell.org"), + "" /* extension id */, + NULL /* optional_fields */, + NULL /* delegate */)); + ash::Shell::GetPrimaryRootWindowController()->shelf()->status_area_widget() ->web_notification_tray()->message_center() - ->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "id0", - ASCIIToUTF16("Test Shell Web Notification"), - ASCIIToUTF16("Notification message body."), - ASCIIToUTF16("www.testshell.org"), - "" /* extension id */, - NULL /* optional_fields */, - NULL /* delegate */); + ->AddNotification(notification.Pass()); } #if !defined(OS_MACOSX) else if (sender == examples_button_) { diff --git a/ash/system/web_notification/web_notification_tray_unittest.cc b/ash/system/web_notification/web_notification_tray_unittest.cc index e144fe9..5b59312 100644 --- a/ash/system/web_notification/web_notification_tray_unittest.cc +++ b/ash/system/web_notification/web_notification_tray_unittest.cc @@ -56,26 +56,34 @@ class WebNotificationTrayTest : public test::AshTestBase { protected: void AddNotification(const std::string& id) { - GetMessageCenter()->AddNotification( + scoped_ptr<message_center::Notification> notification; + notification.reset(new message_center::Notification( message_center::NOTIFICATION_TYPE_SIMPLE, id, ASCIIToUTF16("Test Web Notification"), ASCIIToUTF16("Notification message body."), + gfx::Image(), ASCIIToUTF16("www.test.org"), "" /* extension id */, NULL /* optional_fields */, - NULL /* delegate */); + NULL /* delegate */)); + GetMessageCenter()->AddNotification(notification.Pass()); } void UpdateNotification(const std::string& old_id, const std::string& new_id) { - GetMessageCenter()->UpdateNotification( - old_id, + scoped_ptr<message_center::Notification> notification; + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, new_id, ASCIIToUTF16("Updated Web Notification"), ASCIIToUTF16("Updated message body."), - NULL, - NULL); + gfx::Image(), + ASCIIToUTF16("www.test.org"), + "" /* extension id */, + NULL /* optional_fields */, + NULL /* delegate */)); + GetMessageCenter()->UpdateNotification(old_id, notification.Pass()); } void RemoveNotification(const std::string& id) { diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc index d3bf8ab..3479ade 100644 --- a/chrome/browser/notifications/desktop_notification_service.cc +++ b/chrome/browser/notifications/desktop_notification_service.cc @@ -512,7 +512,7 @@ bool DesktopNotificationService::ShowDesktopNotification( params.body, params.direction, display_source, params.replace_id, proxy); // The webkit notification doesn't timeout. - notification.DisableTimeout(); + notification.set_never_timeout(true); ShowNotification(notification); } return true; diff --git a/chrome/browser/notifications/desktop_notification_service_win.cc b/chrome/browser/notifications/desktop_notification_service_win.cc index 473eef6..a399596 100644 --- a/chrome/browser/notifications/desktop_notification_service_win.cc +++ b/chrome/browser/notifications/desktop_notification_service_win.cc @@ -46,7 +46,7 @@ void DesktopNotificationService::ShowNotification( display_metro_notification(notification.origin_url().spec().c_str(), notification.content_url().spec().c_str(), notification.title().c_str(), - notification.body().c_str(), + notification.message().c_str(), notification.display_source().c_str(), notification.notification_id().c_str()); return; diff --git a/chrome/browser/notifications/message_center_notification_manager.cc b/chrome/browser/notifications/message_center_notification_manager.cc index d2cc43f..0bf2429d 100644 --- a/chrome/browser/notifications/message_center_notification_manager.cc +++ b/chrome/browser/notifications/message_center_notification_manager.cc @@ -27,8 +27,8 @@ MessageCenterNotificationManager::MessageCenterNotificationManager( message_center::MessageCenter* message_center) - : message_center_(message_center), - settings_controller_(new MessageCenterSettingsController) { + : message_center_(message_center), + settings_controller_(new MessageCenterSettingsController) { message_center_->SetDelegate(this); message_center_->AddObserver(this); @@ -166,12 +166,15 @@ bool MessageCenterNotificationManager::UpdateNotification( ProfileNotification* new_notification = new ProfileNotification(profile, notification, message_center_); profile_notifications_[notification.notification_id()] = new_notification; + + // Now pass a copy to message center. + scoped_ptr<message_center::Notification> message_center_notification( + make_scoped_ptr(new message_center::Notification(notification))); + message_center_notification->set_extension_id( + new_notification->GetExtensionId()); message_center_->UpdateNotification(old_id, - notification.notification_id(), - notification.title(), - notification.body(), - notification.optional_fields(), - notification.delegate()); + message_center_notification.Pass()); + new_notification->StartDownloads(); return true; } @@ -291,28 +294,34 @@ void MessageCenterNotificationManager::ImageDownloads::StartDownloads( notification.notification_id())); // Notification image. - StartDownloadByKey( + StartDownloadWithImage( notification, - message_center::kImageUrlKey, + NULL, + notification.image_url(), message_center::kNotificationPreferredImageSize, base::Bind(&message_center::MessageCenter::SetNotificationImage, base::Unretained(message_center_), notification.notification_id())); // Notification button icons. - StartDownloadByKey( + StartDownloadWithImage( notification, - message_center::kButtonOneIconUrlKey, + NULL, + notification.button_one_icon_url(), message_center::kNotificationButtonIconSize, base::Bind(&message_center::MessageCenter::SetNotificationButtonIcon, base::Unretained(message_center_), - notification.notification_id(), 0)); - StartDownloadByKey( - notification, message_center::kButtonTwoIconUrlKey, + notification.notification_id(), + 0)); + StartDownloadWithImage( + notification, + NULL, + notification.button_two_icon_url(), message_center::kNotificationButtonIconSize, base::Bind(&message_center::MessageCenter::SetNotificationButtonIcon, base::Unretained(message_center_), - notification.notification_id(), 1)); + notification.notification_id(), + 1)); // This should tell the observer we're done if everything was synchronous. PendingDownloadCompleted(); @@ -359,19 +368,6 @@ void MessageCenterNotificationManager::ImageDownloads::StartDownloadWithImage( callback)); } -void MessageCenterNotificationManager::ImageDownloads::StartDownloadByKey( - const Notification& notification, - const char* key, - int size, - const SetImageCallback& callback) { - const base::DictionaryValue* optional_fields = notification.optional_fields(); - if (optional_fields && optional_fields->HasKey(key)) { - string16 url; - optional_fields->GetString(key, &url); - StartDownloadWithImage(notification, NULL, GURL(url), size, callback); - } -} - void MessageCenterNotificationManager::ImageDownloads::DownloadComplete( const SetImageCallback& callback, int download_id, @@ -455,14 +451,13 @@ void MessageCenterNotificationManager::AddProfileNotification( DCHECK(profile_notifications_.find(id) == profile_notifications_.end()); profile_notifications_[id] = profile_notification; - message_center_->AddNotification(notification.type(), - notification.notification_id(), - notification.title(), - notification.body(), - notification.display_source(), - profile_notification->GetExtensionId(), - notification.optional_fields(), - notification.delegate()); + // Create the copy for message center, and ensure the extension ID is correct. + scoped_ptr<message_center::Notification> message_center_notification( + new message_center::Notification(notification)); + message_center_notification->set_extension_id( + profile_notification->GetExtensionId()); + message_center_->AddNotification(message_center_notification.Pass()); + profile_notification->StartDownloads(); } diff --git a/chrome/browser/notifications/message_center_notifications_browsertest.cc b/chrome/browser/notifications/message_center_notifications_browsertest.cc index 71cc0a6..6c1d9c5 100644 --- a/chrome/browser/notifications/message_center_notifications_browsertest.cc +++ b/chrome/browser/notifications/message_center_notifications_browsertest.cc @@ -79,13 +79,35 @@ class MessageCenterNotificationsTest : public InProcessBrowserTest { new_delegate->AddRef(); } - return Notification(GURL(), + return Notification(GURL("chrome-test://testing/"), GURL(), ASCIIToUTF16("title"), ASCIIToUTF16("message"), WebKit::WebTextDirectionDefault, - EmptyString16(), - EmptyString16(), + UTF8ToUTF16("chrome-test://testing/"), + UTF8ToUTF16("REPLACE-ME"), + new_delegate); + } + + Notification CreateRichTestNotification(const std::string& id, + TestDelegate** delegate = NULL) { + TestDelegate* new_delegate = new TestDelegate(id); + if (delegate) { + *delegate = new_delegate; + new_delegate->AddRef(); + } + + message_center::RichNotificationData data; + + return Notification(message_center::NOTIFICATION_TYPE_BASE_FORMAT, + GURL("chrome-test://testing/"), + ASCIIToUTF16("title"), + ASCIIToUTF16("message"), + gfx::Image(), + WebKit::WebTextDirectionDefault, + UTF8ToUTF16("chrome-test://testing/"), + UTF8ToUTF16("REPLACE-ME"), + data, new_delegate); } }; @@ -154,4 +176,27 @@ IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, delegate->Release(); } +// MessaceCenter-specific test. +#if defined(RUN_MESSAGE_CENTER_TESTS) +#define MAYBE_UpdateExistingNotification UpdateExistingNotification +#else +#define MAYBE_UpdateExistingNotification DISABLED_UpdateExistingNotification +#endif + +IN_PROC_BROWSER_TEST_F(MessageCenterNotificationsTest, + MAYBE_UpdateExistingNotification) { + EXPECT_TRUE(NotificationUIManager::DelegatesToMessageCenter()); + TestDelegate* delegate; + manager()->Add(CreateTestNotification("n", &delegate), profile()); + TestDelegate* delegate2; + manager()->Add(CreateRichTestNotification("n", &delegate2), profile()); + + manager()->CancelById("n"); + EXPECT_EQ("Display_Close_programmatically_", delegate->log()); + EXPECT_EQ("Close_programmatically_", delegate2->log()); + + delegate->Release(); + delegate2->Release(); +} + #endif // !defined(OS_MACOSX) diff --git a/chrome/browser/notifications/notification.cc b/chrome/browser/notifications/notification.cc index 3e24b23..592ca43 100644 --- a/chrome/browser/notifications/notification.cc +++ b/chrome/browser/notifications/notification.cc @@ -4,18 +4,28 @@ #include "chrome/browser/notifications/notification.h" +#include "base/string_util.h" #include "chrome/browser/notifications/desktop_notification_service.h" +#include "ui/message_center/message_center_util.h" +#include "ui/webui/web_ui_util.h" Notification::Notification(const GURL& origin_url, const GURL& content_url, const string16& display_source, const string16& replace_id, NotificationDelegate* delegate) - : type_(message_center::NOTIFICATION_TYPE_SIMPLE), + : message_center::Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + delegate->id(), + EmptyString16(), + EmptyString16(), + gfx::Image(), + display_source, + origin_url.spec(), + NULL, + delegate), origin_url_(origin_url), is_html_(true), content_url_(content_url), - display_source_(display_source), replace_id_(replace_id), delegate_(delegate) {} @@ -27,13 +37,18 @@ Notification::Notification(const GURL& origin_url, const string16& display_source, const string16& replace_id, NotificationDelegate* delegate) - : type_(message_center::NOTIFICATION_TYPE_SIMPLE), + : message_center::Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + delegate->id(), + title, + body, + gfx::Image(), + display_source, + origin_url.spec(), + NULL, + delegate), origin_url_(origin_url), icon_url_(icon_url), is_html_(false), - title_(title), - body_(body), - display_source_(display_source), replace_id_(replace_id), delegate_(delegate) { // "Upconvert" the string parameters to a data: URL. @@ -51,24 +66,63 @@ Notification::Notification(message_center::NotificationType type, const string16& replace_id, const DictionaryValue* optional_fields, NotificationDelegate* delegate) - : type_(type), + : message_center::Notification(type, + delegate->id(), + title, + body, + gfx::Image(), + display_source, + origin_url.spec(), + optional_fields, + delegate), origin_url_(origin_url), icon_url_(icon_url), is_html_(false), - title_(title), - body_(body), - display_source_(display_source), replace_id_(replace_id), - optional_fields_(NULL), delegate_(delegate) { if (optional_fields) - optional_fields_.reset(optional_fields->DeepCopy()); + ApplyOptionalFields(optional_fields); // "Upconvert" the string parameters to a data: URL. Some balloon views // require content URL to render anything, so this serves as a backup. content_url_ = GURL(DesktopNotificationService::CreateDataUrl( icon_url, title, body, dir)); } +Notification::Notification( + message_center::NotificationType type, + const GURL& origin_url, + const string16& title, + const string16& body, + const gfx::Image& icon, + WebKit::WebTextDirection dir, + const string16& display_source, + const string16& replace_id, + const message_center::RichNotificationData& rich_notification_data, + NotificationDelegate* delegate) + : message_center::Notification(type, + delegate->id(), + title, + body, + icon, + display_source, + origin_url.spec(), + rich_notification_data, + delegate), + origin_url_(origin_url), + is_html_(false), + replace_id_(replace_id), + delegate_(delegate) { + if (!message_center::IsRichNotificationEnabled()) { + // "Upconvert" the string parameters to a data: URL. Some balloon views + // require content URL to render anything, so this serves as a backup. + GURL icon_url; + if (!icon.IsEmpty()) + icon_url_ = GURL(webui::GetBitmapDataUrl(*icon.ToSkBitmap())); + content_url_ = GURL( + DesktopNotificationService::CreateDataUrl(icon_url, title, body, dir)); + } +} + Notification::Notification(const GURL& origin_url, const gfx::Image& icon, const string16& title, @@ -77,55 +131,60 @@ Notification::Notification(const GURL& origin_url, const string16& display_source, const string16& replace_id, NotificationDelegate* delegate) - : type_(message_center::NOTIFICATION_TYPE_SIMPLE), + : message_center::Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + delegate->id(), + title, + body, + icon, + display_source, + origin_url.spec(), + NULL, + delegate), origin_url_(origin_url), - icon_(icon), is_html_(false), - title_(title), - body_(body), - display_source_(display_source), replace_id_(replace_id), delegate_(delegate) {} Notification::Notification(const Notification& notification) - : type_(notification.type()), + : message_center::Notification(notification), origin_url_(notification.origin_url()), - icon_(notification.icon()), icon_url_(notification.icon_url()), is_html_(notification.is_html()), content_url_(notification.content_url()), - title_(notification.title()), - body_(notification.body()), - display_source_(notification.display_source()), + button_one_icon_url_(notification.button_one_icon_url()), + button_two_icon_url_(notification.button_two_icon_url()), + image_url_(notification.image_url()), replace_id_(notification.replace_id()), - delegate_(notification.delegate()) { - if (notification.optional_fields()) - optional_fields_.reset(notification.optional_fields()->DeepCopy()); -} + delegate_(notification.delegate()) {} Notification::~Notification() {} Notification& Notification::operator=(const Notification& notification) { - type_ = notification.type(); + message_center::Notification::operator=(notification); origin_url_ = notification.origin_url(); - icon_ = notification.icon_; icon_url_ = notification.icon_url(); is_html_ = notification.is_html(); content_url_ = notification.content_url(); - title_ = notification.title(); - body_ = notification.body(); - display_source_ = notification.display_source(); + button_one_icon_url_ = notification.button_one_icon_url(); + button_two_icon_url_ = notification.button_two_icon_url(); + image_url_ = notification.image_url(); replace_id_ = notification.replace_id(); - if (notification.optional_fields()) - optional_fields_.reset(notification.optional_fields()->DeepCopy()); - else - optional_fields_.reset(); delegate_ = notification.delegate(); return *this; } -void Notification::DisableTimeout() { - if (!optional_fields_.get()) - optional_fields_.reset(new base::DictionaryValue()); - optional_fields_->SetBoolean(message_center::kPrivateNeverTimeoutKey, true); +void Notification::ApplyOptionalFields(const DictionaryValue* optional_fields) { + if (!optional_fields) + return; + + string16 url; + if (optional_fields->GetString(message_center::kButtonOneIconUrlKey, &url)) { + button_one_icon_url_ = GURL(url); + } + if (optional_fields->GetString(message_center::kButtonTwoIconUrlKey, &url)) { + button_two_icon_url_ = GURL(url); + } + if (optional_fields->GetString(message_center::kImageUrlKey, &url)) { + image_url_ = GURL(url); + } } diff --git a/chrome/browser/notifications/notification.h b/chrome/browser/notifications/notification.h index bbbe73f..3936aea 100644 --- a/chrome/browser/notifications/notification.h +++ b/chrome/browser/notifications/notification.h @@ -15,13 +15,14 @@ #include "googleurl/src/gurl.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebTextDirection.h" #include "ui/gfx/image/image.h" +#include "ui/message_center/notification.h" #include "ui/message_center/notification_types.h" // Representation of a notification to be shown to the user. // On non-Ash platforms these are rendered as HTML, sometimes described by a // data url converted from text + icon data. On Ash they are rendered as // formated text and icon data. -class Notification { +class Notification : public message_center::Notification { public: // Initializes a notification with HTML content. Notification(const GURL& origin_url, @@ -65,100 +66,83 @@ class Notification { const string16& replace_id, NotificationDelegate* delegate); + Notification( + message_center::NotificationType type, + const GURL& origin_url, + const string16& title, + const string16& body, + const gfx::Image& icon, + WebKit::WebTextDirection dir, + const string16& display_source, + const string16& replace_id, + const message_center::RichNotificationData& rich_notification_data, + NotificationDelegate* delegate); + Notification(const Notification& notification); - ~Notification(); + virtual ~Notification(); Notification& operator=(const Notification& notification); // If this is a HTML notification. bool is_html() const { return is_html_; } - message_center::NotificationType type() const { - return type_; - } - // The URL (may be data:) containing the contents for the notification. const GURL& content_url() const { return content_url_; } - // Title and message text of the notification. - const string16& title() const { return title_; } - const string16& body() const { return body_; } - // The origin URL of the script which requested the notification. const GURL& origin_url() const { return origin_url_; } // A url for the icon to be shown (optional). const GURL& icon_url() const { return icon_url_; } - // An image for the icon to be shown (optional). - const gfx::Image& icon() const { return icon_; } - - // A display string for the source of the notification. - const string16& display_source() const { return display_source_; } - // A unique identifier used to update (replace) or remove a notification. const string16& replace_id() const { return replace_id_; } - const DictionaryValue* optional_fields() const { - return optional_fields_.get(); - } + // A url for the button icons to be shown (optional). + const GURL& button_one_icon_url() const { return button_one_icon_url_; } + const GURL& button_two_icon_url() const { return button_two_icon_url_; } - // Marks this explicitly to prevent the timeout dismiss of notification. - // This is used by webkit notifications to keep the existing behavior. - void DisableTimeout(); - - void Display() const { delegate()->Display(); } - void Error() const { delegate()->Error(); } - bool HasClickedListener() const { return delegate()->HasClickedListener(); } - void Click() const { delegate()->Click(); } - void ButtonClick(int index) const { delegate()->ButtonClick(index); } - void Close(bool by_user) const { delegate()->Close(by_user); } - void DoneRendering() { delegate()->ReleaseRenderViewHost(); } + // A url for the image to be shown (optional). + const GURL& image_url() const { return image_url_; } std::string notification_id() const { return delegate()->id(); } - int process_id() const { return delegate()->process_id(); } content::RenderViewHost* GetRenderViewHost() const { return delegate()->GetRenderViewHost(); } + void DoneRendering() { delegate()->ReleaseRenderViewHost(); } NotificationDelegate* delegate() const { return delegate_.get(); } private: - // The type of notification we'd like displayed. - message_center::NotificationType type_; + // Extracts optional URLs from a dictionary value. + void ApplyOptionalFields(const DictionaryValue* optional_fields); // The Origin of the page/worker which created this notification. GURL origin_url_; - // Image data for the associated icon, used by Ash when available. - gfx::Image icon_; - // URL for the icon associated with the notification. Requires delegate_ // to have a non NULL RenderViewHost. GURL icon_url_; // If this is a HTML notification, the content is in |content_url_|. If - // false, the data is in |title_| and |body_|. + // false, the data is in |title_| and |message_|. bool is_html_; // The URL of the HTML content of the toast (may be a data: URL for simple // string-based notifications). GURL content_url_; - // The content for a text notification. - string16 title_; - string16 body_; + // The URLs of the button images for a rich notification. + GURL button_one_icon_url_; + GURL button_two_icon_url_; - // The display string for the source of the notification. Could be - // the same as origin_url_, or the name of an extension. - string16 display_source_; + // The URL of a large image to be displayed for a a rich notification. + GURL image_url_; - // The replace ID for the notification. + // The user-supplied replace ID for the notification. string16 replace_id_; - scoped_ptr<DictionaryValue> optional_fields_; - // A proxy object that allows access back to the JavaScript object that // represents the notification, for firing events. scoped_refptr<NotificationDelegate> delegate_; diff --git a/chrome/browser/notifications/notification_browsertest.cc b/chrome/browser/notifications/notification_browsertest.cc index b92b337..853bb2f 100644 --- a/chrome/browser/notifications/notification_browsertest.cc +++ b/chrome/browser/notifications/notification_browsertest.cc @@ -542,7 +542,7 @@ IN_PROC_BROWSER_TEST_F(NotificationsTest, TestCreateSimpleNotification) { const Notification& notification = balloon->notification(); EXPECT_EQ(EXPECTED_ICON_URL, notification.icon_url()); EXPECT_EQ(ASCIIToUTF16("My Title"), notification.title()); - EXPECT_EQ(ASCIIToUTF16("My Body"), notification.body()); + EXPECT_EQ(ASCIIToUTF16("My Body"), notification.message()); } } @@ -961,6 +961,6 @@ IN_PROC_BROWSER_TEST_F(NotificationsTest, TestNotificationReplacement) { GURL EXPECTED_ICON_URL = test_server()->GetURL(kExpectedIconUrl); EXPECT_EQ(EXPECTED_ICON_URL, notification.icon_url()); EXPECT_EQ(ASCIIToUTF16("Title2"), notification.title()); - EXPECT_EQ(ASCIIToUTF16("Body2"), notification.body()); + EXPECT_EQ(ASCIIToUTF16("Body2"), notification.message()); } } diff --git a/chrome/browser/notifications/notification_ui_manager_mac.mm b/chrome/browser/notifications/notification_ui_manager_mac.mm index 0f0322b..96cea87 100644 --- a/chrome/browser/notifications/notification_ui_manager_mac.mm +++ b/chrome/browser/notifications/notification_ui_manager_mac.mm @@ -145,7 +145,7 @@ void NotificationUIManagerMac::Add(const Notification& notification, ns_notification.subtitle = base::SysUTF16ToNSString(notification.display_source()); ns_notification.informativeText = - base::SysUTF16ToNSString(notification.body()); + base::SysUTF16ToNSString(notification.message()); ns_notification.userInfo = [NSDictionary dictionaryWithObject:base::SysUTF8ToNSString( notification.notification_id()) diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc index 2fc4db7..79f5aef 100644 --- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc +++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc @@ -8,6 +8,7 @@ #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/notifications/notification.h" +#include "chrome/browser/notifications/notification_test_util.h" #include "chrome/browser/notifications/notification_ui_manager.h" #include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h" #include "chrome/browser/notifications/sync_notifier/synced_notification.h" @@ -114,8 +115,12 @@ std::string GetNotificationId(const SyncData& sync_data) { // Stub out the NotificationUIManager for unit testing. class StubNotificationUIManager : public NotificationUIManager { public: - StubNotificationUIManager() : notification_(GURL(), GURL(), string16(), - string16(), NULL) {} + StubNotificationUIManager() + : notification_(GURL(), + GURL(), + string16(), + string16(), + new MockNotificationDelegate("stub")) {} virtual ~StubNotificationUIManager() {} // Adds a notification to be displayed. Virtual for unit test override. diff --git a/chrome/browser/notifications/sync_notifier/synced_notification.cc b/chrome/browser/notifications/sync_notifier/synced_notification.cc index 1e4720b..99fc4ff 100644 --- a/chrome/browser/notifications/sync_notifier/synced_notification.cc +++ b/chrome/browser/notifications/sync_notifier/synced_notification.cc @@ -5,6 +5,7 @@ #include "chrome/browser/notifications/sync_notifier/synced_notification.h" #include "base/basictypes.h" +#include "base/time.h" #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/browser_process.h" @@ -13,6 +14,7 @@ #include "chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h" #include "sync/protocol/sync.pb.h" #include "sync/protocol/synced_notification_specifics.pb.h" +#include "ui/gfx/image/image.h" #include "ui/message_center/message_center_util.h" #include "ui/message_center/notification_types.h" @@ -84,15 +86,14 @@ void SyncedNotification::Show(NotificationUIManager* notification_manager, // Some inputs and fields are only used if there is a notification center. if (UseRichNotifications()) { - double creation_time = static_cast<double>(GetCreationTime()); + base::Time creation_time = + base::Time::FromDoubleT(static_cast<double>(GetCreationTime())); int priority = GetPriority(); int notification_count = GetNotificationCount(); int button_count = GetButtonCount(); // TODO(petewil): Refactor this for an arbitrary number of buttons. std::string button_one_title = GetButtonOneTitle(); - std::string button_one_icon_url = GetButtonOneIconUrl(); std::string button_two_title = GetButtonTwoTitle(); - std::string button_two_icon_url = GetButtonTwoIconUrl(); // Deduce which notification template to use from the data. message_center::NotificationType notification_type = @@ -107,52 +108,44 @@ void SyncedNotification::Show(NotificationUIManager* notification_manager, // Fill the optional fields with the information we need to make a // notification. - DictionaryValue optional_fields; - optional_fields.SetDouble(message_center::kTimestampKey, creation_time); + message_center::RichNotificationData rich_notification_data; + rich_notification_data.timestamp = creation_time; if (priority != SyncedNotification::kUndefinedPriority) - optional_fields.SetInteger(message_center::kPriorityKey, priority); - if (!button_one_title.empty()) - optional_fields.SetString(message_center::kButtonOneTitleKey, - button_one_title); - if (!button_one_icon_url.empty()) - optional_fields.SetString(message_center::kButtonOneIconUrlKey, - button_one_icon_url); - if (!button_two_title.empty()) - optional_fields.SetString(message_center::kButtonTwoTitleKey, - button_two_title); - if (!button_two_icon_url.empty()) - optional_fields.SetString(message_center::kButtonTwoIconUrlKey, - button_two_icon_url); + rich_notification_data.priority = priority; + if (!button_one_title.empty()) { + message_center::ButtonInfo button_info(UTF8ToUTF16(button_one_title)); + rich_notification_data.buttons.push_back(button_info); + // TODO(petewil): Add a button icon here. + } + if (!button_two_title.empty()) { + message_center::ButtonInfo button_info(UTF8ToUTF16(button_two_title)); + rich_notification_data.buttons.push_back(button_info); + // TODO(petewil): Add a button icon here. + } // Fill the individual notification fields for a multiple notification. if (notification_count > 1) { - base::ListValue* items = new base::ListValue(); - for (int ii = 0; ii < notification_count; ++ii) { - DictionaryValue* item = new DictionaryValue(); - item->SetString(message_center::kItemTitleKey, - UTF8ToUTF16(GetContainedNotificationTitle( - ii))); - item->SetString(message_center::kItemMessageKey, - UTF8ToUTF16(GetContainedNotificationMessage( - ii))); - items->Append(item); + message_center::NotificationItem item( + UTF8ToUTF16(GetContainedNotificationTitle(ii)), + UTF8ToUTF16(GetContainedNotificationMessage(ii))); + rich_notification_data.items.push_back(item); } - - optional_fields.Set(message_center::kItemsKey, items); } + // TODO(petewil): Add code here that sets the various notification images + // that have been decoded. Also, don't use the notification tray icon once + // this is enabled, that could cause user confusion. Notification ui_notification(notification_type, GetOriginUrl(), - GetAppIconUrl(), heading, text, + gfx::Image(), WebKit::WebTextDirectionDefault, display_source, replace_key, - &optional_fields, + rich_notification_data, delegate.get()); - notification_manager->Add(ui_notification, profile); } else { diff --git a/chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc b/chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc index 6d7061d..4163d8c 100644 --- a/chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc +++ b/chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc @@ -7,6 +7,7 @@ #include "base/memory/scoped_ptr.h" #include "base/utf_string_conversions.h" #include "chrome/browser/notifications/notification.h" +#include "chrome/browser/notifications/notification_test_util.h" #include "chrome/browser/notifications/notification_ui_manager.h" #include "chrome/browser/notifications/sync_notifier/synced_notification.h" #include "chrome/browser/profiles/profile.h" @@ -80,7 +81,11 @@ const sync_pb::CoalescedSyncedNotification_ReadState kDismissed = class StubNotificationUIManager : public NotificationUIManager { public: StubNotificationUIManager() - : notification_(GURL(), GURL(), string16(), string16(), NULL) {} + : notification_(GURL(), + GURL(), + string16(), + string16(), + new MockNotificationDelegate("stub")) {} virtual ~StubNotificationUIManager() {} // Adds a notification to be displayed. Virtual for unit test override. @@ -472,7 +477,7 @@ TEST_F(SyncedNotificationTest, GetImageURLTest) { EXPECT_EQ(expected_image_url, found_image_url); } -// TODO(petewil): test with a multi-line body +// TODO(petewil): test with a multi-line message TEST_F(SyncedNotificationTest, GetTextTest) { std::string found_text = notification1_->GetText(); std::string expected_text(kText1); @@ -580,62 +585,28 @@ TEST_F(SyncedNotificationTest, ShowTest) { // Call the method under test using the pre-populated data. notification1_->Show(¬ification_manager, NULL, NULL); + const Notification notification = notification_manager.notification(); + // Check the base fields of the notification. - EXPECT_EQ(message_center::NOTIFICATION_TYPE_IMAGE, - notification_manager.notification().type()); - EXPECT_EQ(kTitle1, - UTF16ToUTF8(notification_manager.notification().title())); - EXPECT_EQ(kText1, - UTF16ToUTF8(notification_manager.notification().body())); - EXPECT_EQ(kExpectedOriginUrl, - notification_manager.notification().origin_url().spec()); - EXPECT_EQ(kIconUrl1, notification_manager.notification().icon_url().spec()); - EXPECT_EQ(kKey1, - UTF16ToUTF8(notification_manager.notification().replace_id())); - const DictionaryValue* actual_fields = - notification_manager.notification().optional_fields(); - - // Check the optional fields of the notification. - // Make an optional fields struct like we expect, compare it with actual. - DictionaryValue expected_fields; - expected_fields.SetDouble(message_center::kTimestampKey, kFakeCreationTime); - expected_fields.SetInteger(message_center::kPriorityKey, - kNotificationPriority); - expected_fields.SetString(message_center::kButtonOneTitleKey, - kButtonOneTitle); - expected_fields.SetString(message_center::kButtonOneIconUrlKey, - kButtonOneIconUrl); - expected_fields.SetString(message_center::kButtonTwoTitleKey, - kButtonTwoTitle); - expected_fields.SetString(message_center::kButtonTwoIconUrlKey, - kButtonTwoIconUrl); - - // Fill the individual notification fields for a mutiple notification. - base::ListValue* items = new base::ListValue(); - DictionaryValue* item1 = new DictionaryValue(); - DictionaryValue* item2 = new DictionaryValue(); - DictionaryValue* item3 = new DictionaryValue(); - item1->SetString(message_center::kItemTitleKey, - UTF8ToUTF16(kContainedTitle1)); - item1->SetString(message_center::kItemMessageKey, - UTF8ToUTF16(kContainedMessage1)); - item2->SetString(message_center::kItemTitleKey, - UTF8ToUTF16(kContainedTitle2)); - item2->SetString(message_center::kItemMessageKey, - UTF8ToUTF16(kContainedMessage2)); - item3->SetString(message_center::kItemTitleKey, - UTF8ToUTF16(kContainedTitle3)); - item3->SetString(message_center::kItemMessageKey, - UTF8ToUTF16(kContainedMessage3)); - items->Append(item1); - items->Append(item2); - items->Append(item3); - expected_fields.Set(message_center::kItemsKey, items); - - EXPECT_TRUE(expected_fields.Equals(actual_fields)) - << "Expected: " << expected_fields - << ", but actual: " << *actual_fields; + EXPECT_EQ(message_center::NOTIFICATION_TYPE_IMAGE, notification.type()); + EXPECT_EQ(kTitle1, UTF16ToUTF8(notification.title())); + EXPECT_EQ(kText1, UTF16ToUTF8(notification.message())); + EXPECT_EQ(kExpectedOriginUrl, notification.origin_url().spec()); + EXPECT_EQ(kKey1, UTF16ToUTF8(notification.replace_id())); + + EXPECT_EQ(kFakeCreationTime, notification.timestamp().ToDoubleT()); + EXPECT_EQ(kNotificationPriority, notification.priority()); + + EXPECT_EQ(UTF8ToUTF16(kButtonOneTitle), notification.buttons()[0].title); + EXPECT_EQ(UTF8ToUTF16(kButtonTwoTitle), notification.buttons()[1].title); + + EXPECT_EQ(UTF8ToUTF16(kContainedTitle1), notification.items()[0].title); + EXPECT_EQ(UTF8ToUTF16(kContainedTitle2), notification.items()[1].title); + EXPECT_EQ(UTF8ToUTF16(kContainedTitle3), notification.items()[2].title); + EXPECT_EQ(UTF8ToUTF16(kContainedMessage1), notification.items()[0].message); + EXPECT_EQ(UTF8ToUTF16(kContainedMessage2), notification.items()[1].message); + EXPECT_EQ(UTF8ToUTF16(kContainedMessage3), notification.items()[2].message); } // TODO(petewil): Add a test for a notification being read and or deleted. diff --git a/ui/message_center/cocoa/notification_controller_unittest.mm b/ui/message_center/cocoa/notification_controller_unittest.mm index 0c70e98..e60093b 100644 --- a/ui/message_center/cocoa/notification_controller_unittest.mm +++ b/ui/message_center/cocoa/notification_controller_unittest.mm @@ -103,6 +103,7 @@ TEST_F(NotificationControllerTest, BasicLayout) { "", ASCIIToUTF16("Added to circles"), ASCIIToUTF16("Jonathan and 5 others"), + gfx::Image(), string16(), std::string(), NULL, @@ -132,6 +133,7 @@ TEST_F(NotificationControllerTest, OverflowText) { ASCIIToUTF16("And even the message is long. This sure is a wordy " "notification. Are you really going to read this " "entire thing?"), + gfx::Image(), string16(), std::string(), NULL, @@ -152,6 +154,7 @@ TEST_F(NotificationControllerTest, Close) { "an_id", string16(), string16(), + gfx::Image(), string16(), std::string(), NULL, @@ -178,6 +181,7 @@ TEST_F(NotificationControllerTest, Update) { ASCIIToUTF16("A simple title"), ASCIIToUTF16("This message isn't too long and should fit in the" "default bounds."), + gfx::Image(), string16(), std::string(), NULL, @@ -211,6 +215,7 @@ TEST_F(NotificationControllerTest, Buttons) { "an_id", string16(), string16(), + gfx::Image(), string16(), std::string(), &buttons, @@ -235,6 +240,7 @@ TEST_F(NotificationControllerTest, Image) { "an_id", string16(), string16(), + gfx::Image(), string16(), std::string(), NULL, @@ -278,6 +284,7 @@ TEST_F(NotificationControllerTest, List) { "an_id", string16(), string16(), + gfx::Image(), string16(), std::string(), &items, diff --git a/ui/message_center/cocoa/popup_collection_unittest.mm b/ui/message_center/cocoa/popup_collection_unittest.mm index ee9f984..75e5b09 100644 --- a/ui/message_center/cocoa/popup_collection_unittest.mm +++ b/ui/message_center/cocoa/popup_collection_unittest.mm @@ -47,36 +47,47 @@ class PopupCollectionTest : public ui::CocoaTest { } void AddThreeNotifications() { - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "1", - ASCIIToUTF16("One"), - ASCIIToUTF16("This is the first notification to" - " be displayed"), - string16(), - std::string(), - NULL, - NULL); - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "2", - ASCIIToUTF16("Two"), - ASCIIToUTF16("This is the second notification."), - string16(), - std::string(), - NULL, - NULL); - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "3", - ASCIIToUTF16("Three"), - ASCIIToUTF16("This is the third notification " - "that has a much longer body " - "than the other notifications. It " - "may not fit on the screen if we " - "set the screen size too small."), - string16(), - std::string(), - NULL, - NULL); - + scoped_ptr<message_center::Notification> notification; + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "1", + ASCIIToUTF16("One"), + ASCIIToUTF16("This is the first notification to" + " be displayed"), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification.Pass()); + + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "2", + ASCIIToUTF16("Two"), + ASCIIToUTF16("This is the second notification."), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification.Pass()); + + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "3", + ASCIIToUTF16("Three"), + ASCIIToUTF16("This is the third notification " + "that has a much longer body " + "than the other notifications. It " + "may not fit on the screen if we " + "set the screen size too small."), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification.Pass()); WaitForAnimationEnded(); } @@ -124,14 +135,19 @@ TEST_F(PopupCollectionTest, AttemptFourOneOffscreen) { AddThreeNotifications(); EXPECT_EQ(2u, [[collection_ popups] count]); // "3" does not fit on screen. - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "4", - ASCIIToUTF16("Four"), - ASCIIToUTF16("This is the fourth notification."), - string16(), - std::string(), - NULL, - NULL); + scoped_ptr<message_center::Notification> notification; + + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "4", + ASCIIToUTF16("Four"), + ASCIIToUTF16("This is the fourth notification."), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification.Pass()); WaitForAnimationEnded(); // Remove "1" and "3" should fit on screen. @@ -170,14 +186,18 @@ TEST_F(PopupCollectionTest, LayoutSpacing) { scoped_ptr<base::DictionaryValue> optional(new base::DictionaryValue); optional->SetInteger(message_center::kPriorityKey, message_center::HIGH_PRIORITY); - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "4", - ASCIIToUTF16("Four"), - ASCIIToUTF16("This is the fourth notification."), - string16(), - std::string(), - optional.get(), - NULL); + scoped_ptr<message_center::Notification> notification; + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "4", + ASCIIToUTF16("Four"), + ASCIIToUTF16("This is the fourth notification."), + gfx::Image(), + string16(), + std::string(), + optional.get(), + NULL)); + center_->AddNotification(notification.Pass()); WaitForAnimationEnded(); EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:2], [popups objectAtIndex:3])); @@ -203,32 +223,41 @@ TEST_F(PopupCollectionTest, TinyScreen) { [collection_ setScreenFrame:NSMakeRect(0, 0, 800, 100)]; EXPECT_EQ(0u, [[collection_ popups] count]); - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "1", - ASCIIToUTF16("One"), - ASCIIToUTF16("This is the first notification to" - " be displayed"), - string16(), - std::string(), - NULL, - NULL); + scoped_ptr<message_center::Notification> notification; + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "1", + ASCIIToUTF16("One"), + ASCIIToUTF16("This is the first notification to" + " be displayed"), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification.Pass()); WaitForAnimationEnded(); EXPECT_EQ(1u, [[collection_ popups] count]); // Now give the notification a longer message so that it no longer fits. - center_->UpdateNotification("1", - "1", - ASCIIToUTF16("One"), - ASCIIToUTF16("This is now a very very very very " - "very very very very very very very " - "very very very very very very very " - "very very very very very very very " - "very very very very very very very " - "very very very very very very very " - "very very very very very very very " - "long notification."), - NULL, - NULL); + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "1", + ASCIIToUTF16("One"), + ASCIIToUTF16("This is now a very very very very " + "very very very very very very very " + "very very very very very very very " + "very very very very very very very " + "very very very very very very very " + "very very very very very very very " + "very very very very very very very " + "long notification."), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->UpdateNotification("1", notification.Pass()); WaitForAnimationEnded(); EXPECT_EQ(0u, [[collection_ popups] count]); } @@ -257,18 +286,22 @@ TEST_F(PopupCollectionTest, UpdateIconAndBody) { // Replace "1". controller = [[popups objectAtIndex:0] notificationController]; NSRect old_frame = [[controller view] frame]; - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "1", - ASCIIToUTF16("One is going to get a much longer " - "title than it previously had."), - ASCIIToUTF16("This is the first notification to " - "be displayed, but it will also be " - "updated to have a significantly " - "longer body"), - string16(), - std::string(), - NULL, - NULL); + scoped_ptr<message_center::Notification> notification; + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "1", + ASCIIToUTF16("One is going to get a much longer " + "title than it previously had."), + ASCIIToUTF16("This is the first notification to " + "be displayed, but it will also be " + "updated to have a significantly " + "longer body"), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification.Pass()); WaitForAnimationEnded(); EXPECT_GT(NSHeight([[controller view] frame]), NSHeight(old_frame)); @@ -285,15 +318,19 @@ TEST_F(PopupCollectionTest, UpdateIconAndBody) { TEST_F(PopupCollectionTest, CloseCollectionBeforeNewPopupAnimationEnds) { // Add a notification and don't wait for the animation to finish. - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "1", - ASCIIToUTF16("One"), - ASCIIToUTF16("This is the first notification to" - " be displayed"), - string16(), - std::string(), - NULL, - NULL); + scoped_ptr<message_center::Notification> notification; + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "1", + ASCIIToUTF16("One"), + ASCIIToUTF16("This is the first notification to" + " be displayed"), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification.Pass()); // Release the popup collection before the animation ends. No crash should // be expected. @@ -315,12 +352,18 @@ TEST_F(PopupCollectionTest, CloseCollectionBeforeUpdatePopupAnimationEnds) { AddThreeNotifications(); // Update a notification and don't wait for the animation to finish. - center_->UpdateNotification("1", - "1", - ASCIIToUTF16("One"), - ASCIIToUTF16("New message."), - NULL, - NULL); + scoped_ptr<message_center::Notification> notification; + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "1", + ASCIIToUTF16("One"), + ASCIIToUTF16("New message."), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->UpdateNotification("1", notification.Pass()); // Release the popup collection before the animation ends. No crash should // be expected. diff --git a/ui/message_center/cocoa/popup_controller_unittest.mm b/ui/message_center/cocoa/popup_controller_unittest.mm index dd2503c..81402e8 100644 --- a/ui/message_center/cocoa/popup_controller_unittest.mm +++ b/ui/message_center/cocoa/popup_controller_unittest.mm @@ -21,6 +21,7 @@ TEST_F(PopupControllerTest, Creation) { "", ASCIIToUTF16("Added to circles"), ASCIIToUTF16("Jonathan and 5 others"), + gfx::Image(), string16(), std::string(), NULL, diff --git a/ui/message_center/cocoa/tray_view_controller_unittest.mm b/ui/message_center/cocoa/tray_view_controller_unittest.mm index c32be80..aa370e1 100644 --- a/ui/message_center/cocoa/tray_view_controller_unittest.mm +++ b/ui/message_center/cocoa/tray_view_controller_unittest.mm @@ -36,14 +36,18 @@ class TrayViewControllerTest : public ui::CocoaTest { TEST_F(TrayViewControllerTest, AddRemoveOne) { NSScrollView* view = [[tray_ scrollView] documentView]; EXPECT_EQ(0u, [[view subviews] count]); - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "1", - ASCIIToUTF16("First notification"), - ASCIIToUTF16("This is a simple test."), - string16(), - std::string(), - NULL, - NULL); + scoped_ptr<message_center::Notification> notification_data; + notification_data.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "1", + ASCIIToUTF16("First notification"), + ASCIIToUTF16("This is a simple test."), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification_data.Pass()); [tray_ onMessageCenterTrayChanged]; ASSERT_EQ(1u, [[view subviews] count]); @@ -66,30 +70,40 @@ TEST_F(TrayViewControllerTest, AddRemoveOne) { TEST_F(TrayViewControllerTest, AddThreeClearAll) { NSScrollView* view = [[tray_ scrollView] documentView]; EXPECT_EQ(0u, [[view subviews] count]); - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "1", - ASCIIToUTF16("First notification"), - ASCIIToUTF16("This is a simple test."), - string16(), - std::string(), - NULL, - NULL); - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "2", - ASCIIToUTF16("Second notification"), - ASCIIToUTF16("This is a simple test."), - string16(), - std::string(), - NULL, - NULL); - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "3", - ASCIIToUTF16("Third notification"), - ASCIIToUTF16("This is a simple test."), - string16(), - std::string(), - NULL, - NULL); + scoped_ptr<message_center::Notification> notification; + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "1", + ASCIIToUTF16("First notification"), + ASCIIToUTF16("This is a simple test."), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification.Pass()); + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "2", + ASCIIToUTF16("Second notification"), + ASCIIToUTF16("This is a simple test."), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification.Pass()); + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "3", + ASCIIToUTF16("Third notification"), + ASCIIToUTF16("This is a simple test."), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification.Pass()); [tray_ onMessageCenterTrayChanged]; ASSERT_EQ(3u, [[view subviews] count]); @@ -110,14 +124,18 @@ TEST_F(TrayViewControllerTest, NoClearAllWhenNoNotifications) { NSMinX([[tray_ pauseButton] frame])); // Add a notification. - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "1", - ASCIIToUTF16("First notification"), - ASCIIToUTF16("This is a simple test."), - string16(), - std::string(), - NULL, - NULL); + scoped_ptr<message_center::Notification> notification; + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "1", + ASCIIToUTF16("First notification"), + ASCIIToUTF16("This is a simple test."), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification.Pass()); [tray_ onMessageCenterTrayChanged]; // Clear all should now be visible. @@ -126,14 +144,17 @@ TEST_F(TrayViewControllerTest, NoClearAllWhenNoNotifications) { NSMinX([[tray_ pauseButton] frame])); // Adding a second notification should keep things still visible. - center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "2", - ASCIIToUTF16("Second notification"), - ASCIIToUTF16("This is a simple test."), - string16(), - std::string(), - NULL, - NULL); + notification.reset(new message_center::Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + "2", + ASCIIToUTF16("Second notification"), + ASCIIToUTF16("This is a simple test."), + gfx::Image(), + string16(), + std::string(), + NULL, + NULL)); + center_->AddNotification(notification.Pass()); [tray_ onMessageCenterTrayChanged]; EXPECT_FALSE([[tray_ clearAllButton] isHidden]); EXPECT_GT(NSMinX([[tray_ clearAllButton] frame]), diff --git a/ui/message_center/fake_message_center.cc b/ui/message_center/fake_message_center.cc index b48961c..f8b94ef 100644 --- a/ui/message_center/fake_message_center.cc +++ b/ui/message_center/fake_message_center.cc @@ -55,23 +55,12 @@ NotificationList::PopupNotifications return NotificationList::PopupNotifications(); } -void FakeMessageCenter::AddNotification( - NotificationType type, - const std::string& id, - const string16& title, - const string16& message, - const string16& display_source, - const std::string& extension_id, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate) {} +void FakeMessageCenter::AddNotification(scoped_ptr<Notification> notification) { +} void FakeMessageCenter::UpdateNotification( const std::string& old_id, - const std::string& new_id, - const string16& title, - const string16& message, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate) {} + scoped_ptr<Notification> new_notification) {} void FakeMessageCenter::RemoveNotification(const std::string& id, bool by_user) { diff --git a/ui/message_center/fake_message_center.h b/ui/message_center/fake_message_center.h index 65ddc4b..1d75cd9 100644 --- a/ui/message_center/fake_message_center.h +++ b/ui/message_center/fake_message_center.h @@ -29,20 +29,11 @@ class FakeMessageCenter : public MessageCenter { virtual bool HasClickedListener(const std::string& id) OVERRIDE; virtual const NotificationList::Notifications& GetNotifications() OVERRIDE; virtual NotificationList::PopupNotifications GetPopupNotifications() OVERRIDE; - virtual void AddNotification(NotificationType type, - const std::string& id, - const string16& title, - const string16& message, - const string16& display_source, - const std::string& extension_id, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate) OVERRIDE; + virtual void AddNotification(scoped_ptr<Notification> notification) OVERRIDE; virtual void UpdateNotification(const std::string& old_id, - const std::string& new_id, - const string16& title, - const string16& message, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate) OVERRIDE; + scoped_ptr<Notification> new_notification) + OVERRIDE; + virtual void RemoveNotification(const std::string& id, bool by_user) OVERRIDE; virtual void RemoveAllNotifications(bool by_user) OVERRIDE; virtual void SetNotificationIcon(const std::string& notification_id, diff --git a/ui/message_center/message_center.h b/ui/message_center/message_center.h index 7be6cc8..ff247d3 100644 --- a/ui/message_center/message_center.h +++ b/ui/message_center/message_center.h @@ -84,32 +84,13 @@ class MESSAGE_CENTER_EXPORT MessageCenter { // Basic operations of notification: add/remove/update. - // Adds a new notification. |id| is a unique identifier, used to update or - // remove notifications. |title| and |meesage| describe the notification text. - // Use SetNotificationIcon, SetNotificationImage, or SetNotificationButtonIcon - // to set images. If |extension_id| is provided then 'Disable extension' will - // appear in a dropdown menu and the id will be used to disable notifications - // from the extension. Otherwise if |display_source| is provided, a menu item - // showing the source and allowing notifications from that source to be - // disabled will be shown. All actual disabling is handled by the Delegate. - virtual void AddNotification(NotificationType type, - const std::string& id, - const string16& title, - const string16& message, - const string16& display_source, - const std::string& extension_id, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate) = 0; + // Adds a new notification. + virtual void AddNotification(scoped_ptr<Notification> notification) = 0; // Updates an existing notification with id = old_id and set its id to new_id. - // |delegate| and |optional_fields| can be NULL in case of no updates on - // those fields. - virtual void UpdateNotification(const std::string& old_id, - const std::string& new_id, - const string16& title, - const string16& message, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate) = 0; + virtual void UpdateNotification( + const std::string& old_id, + scoped_ptr<Notification> new_notification) = 0; // Removes an existing notification. virtual void RemoveNotification(const std::string& id, bool by_user) = 0; diff --git a/ui/message_center/message_center_impl.cc b/ui/message_center/message_center_impl.cc index 58aebbb..68780c5 100644 --- a/ui/message_center/message_center_impl.cc +++ b/ui/message_center/message_center_impl.cc @@ -80,46 +80,31 @@ NotificationList::PopupNotifications //------------------------------------------------------------------------------ // Client code interface. +void MessageCenterImpl::AddNotification(scoped_ptr<Notification> notification) { + DCHECK(notification.get()); -void MessageCenterImpl::AddNotification( - NotificationType type, - const std::string& id, - const string16& title, - const string16& message, - const string16& display_source, - const std::string& extension_id, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate) { // Sometimes the notification can be added with the same id and the // |notification_list| will replace the notification instead of adding new. // This is essentially an update rather than addition. + const std::string& id = notification->id(); bool already_exists = notification_list_->HasNotification(id); - notification_list_->AddNotification(type, - id, - title, - message, - display_source, - extension_id, - optional_fields, - delegate); + notification_list_->AddNotification(notification.Pass()); + if (already_exists) { - FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_, - OnNotificationUpdated(id)); + FOR_EACH_OBSERVER( + MessageCenterObserver, observer_list_, OnNotificationUpdated(id)); } else { - FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_, - OnNotificationAdded(id)); + FOR_EACH_OBSERVER( + MessageCenterObserver, observer_list_, OnNotificationAdded(id)); } } void MessageCenterImpl::UpdateNotification( const std::string& old_id, - const std::string& new_id, - const string16& title, - const string16& message, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate) { - notification_list_->UpdateNotificationMessage( - old_id, new_id, title, message, optional_fields, delegate); + scoped_ptr<Notification> new_notification) { + std::string new_id = new_notification->id(); + notification_list_->UpdateNotificationMessage(old_id, + new_notification.Pass()); if (old_id == new_id) { FOR_EACH_OBSERVER(MessageCenterObserver, observer_list_, OnNotificationUpdated(new_id)); diff --git a/ui/message_center/message_center_impl.h b/ui/message_center/message_center_impl.h index 33e7a14..f39dc74 100644 --- a/ui/message_center/message_center_impl.h +++ b/ui/message_center/message_center_impl.h @@ -32,20 +32,10 @@ class MessageCenterImpl : public MessageCenter { virtual bool HasClickedListener(const std::string& id) OVERRIDE; virtual const NotificationList::Notifications& GetNotifications() OVERRIDE; virtual NotificationList::PopupNotifications GetPopupNotifications() OVERRIDE; - virtual void AddNotification(NotificationType type, - const std::string& id, - const string16& title, - const string16& message, - const string16& display_source, - const std::string& extension_id, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate) OVERRIDE; + virtual void AddNotification(scoped_ptr<Notification> notification) OVERRIDE; virtual void UpdateNotification(const std::string& old_id, - const std::string& new_id, - const string16& title, - const string16& message, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate) OVERRIDE; + scoped_ptr<Notification> new_notification) + OVERRIDE; virtual void RemoveNotification(const std::string& id, bool by_user) OVERRIDE; virtual void RemoveAllNotifications(bool by_user) OVERRIDE; virtual void SetNotificationIcon(const std::string& notification_id, diff --git a/ui/message_center/message_center_style.h b/ui/message_center/message_center_style.h index b54a624..a995cea 100644 --- a/ui/message_center/message_center_style.h +++ b/ui/message_center/message_center_style.h @@ -64,8 +64,11 @@ const int kButtonHeight = 38; // In DIPs. const int kButtonHorizontalPadding = 16; // In DIPs. const int kButtonIconTopPadding = 11; // In DIPs. const int kButtonIconToTitlePadding = 16; // In DIPs. + +#if !defined(OS_LINUX) || defined(USE_AURA) const SkColor kButtonSeparatorColor = SkColorSetRGB(234, 234, 234); const SkColor kHoveredButtonBackgroundColor = SkColorSetRGB(243, 243, 243); +#endif // Around notifications //////////////////////////////////////////////////////// diff --git a/ui/message_center/message_center_tray_unittest.cc b/ui/message_center/message_center_tray_unittest.cc index 1b774f8..b8aaad3 100644 --- a/ui/message_center/message_center_tray_unittest.cc +++ b/ui/message_center/message_center_tray_unittest.cc @@ -57,6 +57,19 @@ class MessageCenterTrayTest : public testing::Test { } protected: + void AddNotification(const std::string& id) { + scoped_ptr<Notification> notification( + new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + id, + ASCIIToUTF16("Test Web Notification"), + ASCIIToUTF16("Notification message body."), + gfx::Image(), + ASCIIToUTF16("www.test.org"), + "" /* extension id */, + NULL /* optional_fields */, + NULL /* delegate */)); + message_center_->AddNotification(notification.Pass()); + } scoped_ptr<MockDelegate> delegate_; scoped_ptr<MessageCenterTray> message_center_tray_; MessageCenter* message_center_; @@ -102,14 +115,7 @@ TEST_F(MessageCenterTrayTest, BasicPopup) { ASSERT_FALSE(message_center_tray_->popups_visible()); ASSERT_FALSE(message_center_tray_->message_center_visible()); - message_center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "BasicPopup", - ASCIIToUTF16("Test Web Notification"), - ASCIIToUTF16("Notification message body."), - ASCIIToUTF16("www.test.org"), - "" /* extension id */, - NULL /* optional_fields */, - NULL /* delegate */); + AddNotification("BasicPopup"); ASSERT_TRUE(message_center_tray_->popups_visible()); ASSERT_FALSE(message_center_tray_->message_center_visible()); @@ -124,14 +130,7 @@ TEST_F(MessageCenterTrayTest, MessageCenterClosesPopups) { ASSERT_FALSE(message_center_tray_->popups_visible()); ASSERT_FALSE(message_center_tray_->message_center_visible()); - message_center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "MessageCenterClosesPopups", - ASCIIToUTF16("Test Web Notification"), - ASCIIToUTF16("Notification message body."), - ASCIIToUTF16("www.test.org"), - "" /* extension id */, - NULL /* optional_fields */, - NULL /* delegate */); + AddNotification("MessageCenterClosesPopups"); ASSERT_TRUE(message_center_tray_->popups_visible()); ASSERT_FALSE(message_center_tray_->message_center_visible()); @@ -142,14 +141,7 @@ TEST_F(MessageCenterTrayTest, MessageCenterClosesPopups) { ASSERT_FALSE(message_center_tray_->popups_visible()); ASSERT_TRUE(message_center_tray_->message_center_visible()); - message_center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "MessageCenterClosesPopups2", - ASCIIToUTF16("Test Web Notification"), - ASCIIToUTF16("Notification message body."), - ASCIIToUTF16("www.test.org"), - "" /* extension id */, - NULL /* optional_fields */, - NULL /* delegate */); + AddNotification("MessageCenterClosesPopups2"); message_center_tray_->ShowPopupBubble(); @@ -170,14 +162,7 @@ TEST_F(MessageCenterTrayTest, ShowBubbleFails) { ASSERT_FALSE(message_center_tray_->popups_visible()); ASSERT_FALSE(message_center_tray_->message_center_visible()); - message_center_->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "ShowBubbleFails", - ASCIIToUTF16("Test Web Notification"), - ASCIIToUTF16("Notification message body."), - ASCIIToUTF16("www.test.org"), - "" /* extension id */, - NULL /* optional_fields */, - NULL /* delegate */); + AddNotification("ShowBubbleFails"); message_center_tray_->ShowPopupBubble(); diff --git a/ui/message_center/notification.cc b/ui/message_center/notification.cc index c4db2d5..43e3de7 100644 --- a/ui/message_center/notification.cc +++ b/ui/message_center/notification.cc @@ -23,10 +23,27 @@ ButtonInfo::ButtonInfo(const string16& title) : title(title) { } +RichNotificationData::RichNotificationData() + : priority(DEFAULT_PRIORITY), + never_timeout(false), + timestamp(base::Time::Now()) {} + +RichNotificationData::RichNotificationData(const RichNotificationData& other) + : priority(other.priority), + never_timeout(other.never_timeout), + timestamp(other.timestamp), + expanded_message(other.expanded_message), + image(other.image), + items(other.items), + buttons(other.buttons) {} + +RichNotificationData::~RichNotificationData() {} + Notification::Notification(NotificationType type, const std::string& id, const string16& title, const string16& message, + const gfx::Image& icon, const string16& display_source, const std::string& extension_id, const DictionaryValue* optional_fields, @@ -35,48 +52,97 @@ Notification::Notification(NotificationType type, id_(id), title_(title), message_(message), + icon_(icon), display_source_(display_source), extension_id_(extension_id), - priority_(DEFAULT_PRIORITY), - timestamp_(base::Time::Now()), serial_number_(g_next_serial_number_++), shown_as_popup_(false), is_read_(false), is_expanded_(false), - never_timeout_(false), delegate_(delegate) { - // This can override some data members initialized to deafule values above. + // This can override some data members initialized to default values above. ApplyOptionalFields(optional_fields); } -Notification::~Notification() { +Notification::Notification(NotificationType type, + const std::string& id, + const string16& title, + const string16& message, + const gfx::Image& icon, + const string16& display_source, + const std::string& extension_id, + const RichNotificationData& optional_fields, + NotificationDelegate* delegate) + : type_(type), + id_(id), + title_(title), + message_(message), + icon_(icon), + display_source_(display_source), + extension_id_(extension_id), + serial_number_(g_next_serial_number_++), + optional_fields_(optional_fields), + delegate_(delegate) {} + +Notification::Notification(const Notification& other) + : type_(other.type_), + id_(other.id_), + title_(other.title_), + message_(other.message_), + icon_(other.icon_), + display_source_(other.display_source_), + extension_id_(other.extension_id_), + serial_number_(other.serial_number_), + optional_fields_(other.optional_fields_), + shown_as_popup_(other.shown_as_popup_), + is_read_(other.is_read_), + is_expanded_(other.is_expanded_), + delegate_(other.delegate_) {} + +Notification& Notification::operator=(const Notification& other) { + type_ = other.type_; + id_ = other.id_; + title_ = other.title_; + message_ = other.message_; + icon_ = other.icon_; + display_source_ = other.display_source_; + extension_id_ = other.extension_id_; + serial_number_ = other.serial_number_; + optional_fields_ = other.optional_fields_; + shown_as_popup_ = other.shown_as_popup_; + is_read_ = other.is_read_; + is_expanded_ = other.is_expanded_; + delegate_ = other.delegate_; + + return *this; } +Notification::~Notification() {} + void Notification::CopyState(Notification* base) { shown_as_popup_ = base->shown_as_popup(); is_read_ = base->is_read(); is_expanded_ = base->is_expanded(); - never_timeout_ = base->never_timeout(); if (!delegate_.get()) delegate_ = base->delegate(); + optional_fields_.never_timeout = base->never_timeout(); } -bool Notification::SetButtonIcon(size_t index, const gfx::Image& icon) { - if (index >= buttons_.size()) - return false; - buttons_[index].icon = icon; - return true; +void Notification::SetButtonIcon(size_t index, const gfx::Image& icon) { + if (index >= optional_fields_.buttons.size()) + return; + optional_fields_.buttons[index].icon = icon; } void Notification::ApplyOptionalFields(const DictionaryValue* fields) { if (!fields) return; - fields->GetInteger(kPriorityKey, &priority_); + fields->GetInteger(kPriorityKey, &optional_fields_.priority); if (fields->HasKey(kTimestampKey)) { std::string time_string; fields->GetString(kTimestampKey, &time_string); - base::Time::FromString(time_string.c_str(), ×tamp_); + base::Time::FromString(time_string.c_str(), &optional_fields_.timestamp); } if (fields->HasKey(kButtonOneTitleKey) || fields->HasKey(kButtonOneIconUrlKey)) { @@ -84,14 +150,14 @@ void Notification::ApplyOptionalFields(const DictionaryValue* fields) { string16 icon; if (fields->GetString(kButtonOneTitleKey, &title) || fields->GetString(kButtonOneIconUrlKey, &icon)) { - buttons_.push_back(ButtonInfo(title)); + optional_fields_.buttons.push_back(ButtonInfo(title)); if (fields->GetString(kButtonTwoTitleKey, &title) || fields->GetString(kButtonTwoIconUrlKey, &icon)) { - buttons_.push_back(ButtonInfo(title)); + optional_fields_.buttons.push_back(ButtonInfo(title)); } } } - fields->GetString(kExpandedMessageKey, &expanded_message_); + fields->GetString(kExpandedMessageKey, &optional_fields_.expanded_message); if (fields->HasKey(kItemsKey)) { const ListValue* items; CHECK(fields->GetList(kItemsKey, &items)); @@ -102,11 +168,11 @@ void Notification::ApplyOptionalFields(const DictionaryValue* fields) { items->GetDictionary(i, &item); item->GetString(kItemTitleKey, &title); item->GetString(kItemMessageKey, &message); - items_.push_back(NotificationItem(title, message)); + optional_fields_.items.push_back(NotificationItem(title, message)); } } - fields->GetBoolean(kPrivateNeverTimeoutKey, &never_timeout_); + fields->GetBoolean(kPrivateNeverTimeoutKey, &optional_fields_.never_timeout); } } // namespace message_center diff --git a/ui/message_center/notification.h b/ui/message_center/notification.h index 5f7ee12..c6c43b9 100644 --- a/ui/message_center/notification.h +++ b/ui/message_center/notification.h @@ -32,16 +32,45 @@ struct MESSAGE_CENTER_EXPORT ButtonInfo { ButtonInfo(const string16& title); }; +class MESSAGE_CENTER_EXPORT RichNotificationData { + public: + RichNotificationData(); + RichNotificationData(const RichNotificationData& other); + ~RichNotificationData(); + + int priority; + bool never_timeout; + base::Time timestamp; + string16 expanded_message; + gfx::Image image; + std::vector<NotificationItem> items; + std::vector<ButtonInfo> buttons; +}; + class MESSAGE_CENTER_EXPORT Notification { public: Notification(NotificationType type, const std::string& id, const string16& title, const string16& message, + const gfx::Image& icon, const string16& display_source, const std::string& extension_id, const DictionaryValue* optional_fields, // May be NULL. NotificationDelegate* delegate); // May be NULL. + + Notification(NotificationType type, + const std::string& id, + const string16& title, + const string16& message, + const gfx::Image& icon, + const string16& display_source, + const std::string& extension_id, + const RichNotificationData& optional_fields, + NotificationDelegate* delegate); + + Notification(const Notification& other); + Notification& operator=(const Notification& other); virtual ~Notification(); // Copies the internal on-memory state from |base|, i.e. shown_as_popup, @@ -52,26 +81,37 @@ class MESSAGE_CENTER_EXPORT Notification { const std::string& id() const { return id_; } const string16& title() const { return title_; } const string16& message() const { return message_; } + + // A display string for the source of the notification. const string16& display_source() const { return display_source_; } const std::string& extension_id() const { return extension_id_; } + void set_extension_id(const std::string& extension_id) { + extension_id_ = extension_id; + } // Begin unpacked values from optional_fields. - int priority() const { return priority_; } - base::Time timestamp() const { return timestamp_; } - const string16& expanded_message() const { return expanded_message_; } - const std::vector<NotificationItem>& items() const { return items_; } + int priority() const { return optional_fields_.priority; } + base::Time timestamp() const { return optional_fields_.timestamp; } + const string16& expanded_message() const { + return optional_fields_.expanded_message; + } + const std::vector<NotificationItem>& items() const { + return optional_fields_.items; + } // End unpacked values. // Images fetched asynchronously. const gfx::Image& icon() const { return icon_; } void set_icon(const gfx::Image& icon) { icon_ = icon; } - const gfx::Image& image() const { return image_; } - void set_image(const gfx::Image& image) { image_ = image; } + const gfx::Image& image() const { return optional_fields_.image; } + void set_image(const gfx::Image& image) { optional_fields_.image = image; } // Buttons, with icons fetched asynchronously. - const std::vector<ButtonInfo>& buttons() const { return buttons_; } - bool SetButtonIcon(size_t index, const gfx::Image& icon); + const std::vector<ButtonInfo>& buttons() const { + return optional_fields_.buttons; + } + void SetButtonIcon(size_t index, const gfx::Image& icon); bool shown_as_popup() const { return shown_as_popup_; } void set_shown_as_popup(bool shown_as_popup) { @@ -90,38 +130,56 @@ class MESSAGE_CENTER_EXPORT Notification { // The notification with lesser serial_number is considered 'older'. unsigned serial_number() { return serial_number_; } - bool never_timeout() const { return never_timeout_; } - NotificationDelegate* delegate() { return delegate_.get(); } + // Marks this explicitly to prevent the timeout dismiss of notification. + // This is used by webkit notifications to keep the existing behavior. + void set_never_timeout(bool never_timeout) { + optional_fields_.never_timeout = never_timeout; + } - private: - // Unpacks the provided |optional_fields| and applies the values to override - // the notification's data members. - void ApplyOptionalFields(const DictionaryValue* optional_fields); + bool never_timeout() const { return optional_fields_.never_timeout; } + NotificationDelegate* delegate() const { return delegate_.get(); } + const RichNotificationData& rich_notification_data() const { + return optional_fields_; + } + + // Delegate actions. + void Display() const { delegate()->Display(); } + void Error() const { delegate()->Error(); } + bool HasClickedListener() const { return delegate()->HasClickedListener(); } + void Click() const { delegate()->Click(); } + void ButtonClick(int index) const { delegate()->ButtonClick(index); } + void Close(bool by_user) const { delegate()->Close(by_user); } + protected: + // The type of notification we'd like displayed. NotificationType type_; + std::string id_; string16 title_; string16 message_; + + // Image data for the associated icon, used by Ash when available. + gfx::Image icon_; + + // The display string for the source of the notification. Could be + // the same as origin_url_, or the name of an extension. string16 display_source_; + + private: + // Unpacks the provided |optional_fields| and applies the values to override + // the notification's data members. + void ApplyOptionalFields(const DictionaryValue* optional_fields); + std::string extension_id_; - int priority_; - base::Time timestamp_; unsigned serial_number_; - string16 expanded_message_; - std::vector<NotificationItem> items_; - gfx::Image icon_; - gfx::Image image_; - std::vector<ButtonInfo> buttons_; + RichNotificationData optional_fields_; bool shown_as_popup_; // True if this has been shown as a popup. bool is_read_; // True if this has been seen in the message center. bool is_expanded_; // True if this has been expanded in the message center. - bool never_timeout_; // True if it doesn't timeout when it appears as a toast. // A proxy object that allows access back to the JavaScript object that // represents the notification, for firing events. scoped_refptr<NotificationDelegate> delegate_; - - DISALLOW_COPY_AND_ASSIGN(Notification); }; } // namespace message_center diff --git a/ui/message_center/notification_list.cc b/ui/message_center/notification_list.cc index 8770ee7..4191f7c 100644 --- a/ui/message_center/notification_list.cc +++ b/ui/message_center/notification_list.cc @@ -71,63 +71,33 @@ void NotificationList::SetMessageCenterVisible( } } -void NotificationList::AddNotification(NotificationType type, - const std::string& id, - const string16& title, - const string16& message, - const string16& display_source, - const std::string& extension_id, - const DictionaryValue* optional_fields, - NotificationDelegate* delegate) { - scoped_ptr<Notification> notification(new Notification(type, - id, - title, - message, - display_source, - extension_id, - optional_fields, - delegate)); +void NotificationList::AddNotification(scoped_ptr<Notification> notification) { PushNotification(notification.Pass()); } void NotificationList::UpdateNotificationMessage( const std::string& old_id, - const std::string& new_id, - const string16& title, - const string16& message, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate) { + scoped_ptr<Notification> new_notification) { Notifications::iterator iter = GetNotification(old_id); if (iter == notifications_.end()) return; - // Copy and update a notification. It has an effect of setting a new timestamp - // if not overridden by optional_fields - scoped_ptr<Notification> notification( - new Notification((*iter)->type(), - new_id, - title, - message, - (*iter)->display_source(), - (*iter)->extension_id(), - optional_fields, - delegate)); - notification->CopyState(*iter); + new_notification->CopyState(*iter); // Handles priority promotion. If the notification is already dismissed but // the updated notification has higher priority, it should re-appear as a // toast. - if ((*iter)->priority() < notification->priority()) { - notification->set_is_read(false); - notification->set_shown_as_popup(false); + if ((*iter)->priority() < new_notification->priority()) { + new_notification->set_is_read(false); + new_notification->set_shown_as_popup(false); } // Do not use EraseNotification and PushNotification, since we don't want to // change unread counts nor to update is_read/shown_as_popup states. - Notification *old = *iter; + Notification* old = *iter; notifications_.erase(iter); delete old; - notifications_.insert(notification.release()); + notifications_.insert(new_notification.release()); } void NotificationList::RemoveNotification(const std::string& id) { @@ -199,7 +169,8 @@ bool NotificationList::SetNotificationButtonIcon( Notifications::iterator iter = GetNotification(notification_id); if (iter == notifications_.end()) return false; - return (*iter)->SetButtonIcon(button_index, image); + (*iter)->SetButtonIcon(button_index, image); + return true; } bool NotificationList::HasNotification(const std::string& id) { diff --git a/ui/message_center/notification_list.h b/ui/message_center/notification_list.h index 4155853..49dba30 100644 --- a/ui/message_center/notification_list.h +++ b/ui/message_center/notification_list.h @@ -58,21 +58,10 @@ class MESSAGE_CENTER_EXPORT NotificationList { void SetMessageCenterVisible(bool visible, std::set<std::string>* updated_ids); - void AddNotification(NotificationType type, - const std::string& id, - const string16& title, - const string16& message, - const string16& display_source, - const std::string& extension_id, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate); + void AddNotification(scoped_ptr<Notification> notification); void UpdateNotificationMessage(const std::string& old_id, - const std::string& new_id, - const string16& title, - const string16& message, - const base::DictionaryValue* optional_fields, - NotificationDelegate* delegate); + scoped_ptr<Notification> new_notification); void RemoveNotification(const std::string& id); diff --git a/ui/message_center/notification_list_unittest.cc b/ui/message_center/notification_list_unittest.cc index 02e3a5d..710b229 100644 --- a/ui/message_center/notification_list_unittest.cc +++ b/ui/message_center/notification_list_unittest.cc @@ -32,15 +32,17 @@ class NotificationListTest : public testing::Test { // notification. std::string AddNotification(const base::DictionaryValue* optional_fields) { std::string new_id = base::StringPrintf(kIdFormat, counter_); - notification_list_->AddNotification( + scoped_ptr<Notification> notification(new Notification( message_center::NOTIFICATION_TYPE_SIMPLE, new_id, UTF8ToUTF16(base::StringPrintf(kTitleFormat, counter_)), UTF8ToUTF16(base::StringPrintf(kMessageFormat, counter_)), + gfx::Image(), UTF8ToUTF16(kDisplaySource), kExtensionId, optional_fields, - NULL); + NULL)); + notification_list_->AddNotification(notification.Pass()); counter_++; return new_id; } @@ -72,13 +74,13 @@ class NotificationListTest : public testing::Test { NotificationList* notification_list() { return notification_list_.get(); } - private: static const char kIdFormat[]; static const char kTitleFormat[]; static const char kMessageFormat[]; static const char kDisplaySource[]; static const char kExtensionId[]; + private: scoped_ptr<NotificationList> notification_list_; size_t counter_; @@ -164,12 +166,17 @@ TEST_F(NotificationListTest, UpdateNotification) { std::string id0 = AddNotification(NULL); std::string replaced = id0 + "_replaced"; EXPECT_EQ(1u, notification_list()->NotificationCount()); - notification_list()->UpdateNotificationMessage(id0, - replaced, - UTF8ToUTF16("newtitle"), - UTF8ToUTF16("newbody"), - NULL, - NULL); + scoped_ptr<Notification> notification( + new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + replaced, + UTF8ToUTF16("newtitle"), + UTF8ToUTF16("newbody"), + gfx::Image(), + UTF8ToUTF16(kDisplaySource), + kExtensionId, + NULL, + NULL)); + notification_list()->UpdateNotificationMessage(id0, notification.Pass()); EXPECT_EQ(1u, notification_list()->NotificationCount()); const NotificationList::Notifications& notifications = notification_list()->GetNotifications(); @@ -179,38 +186,47 @@ TEST_F(NotificationListTest, UpdateNotification) { } TEST_F(NotificationListTest, GetNotificationsBySourceOrExtensions) { - notification_list()->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "id0", - UTF8ToUTF16("title0"), - UTF8ToUTF16("message0"), - UTF8ToUTF16("source0"), - "ext0", - NULL, - NULL); - notification_list()->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "id1", - UTF8ToUTF16("title1"), - UTF8ToUTF16("message1"), - UTF8ToUTF16("source0"), - "ext0", - NULL, - NULL); - notification_list()->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "id2", - UTF8ToUTF16("title1"), - UTF8ToUTF16("message1"), - UTF8ToUTF16("source1"), - "ext0", - NULL, - NULL); - notification_list()->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE, - "id3", - UTF8ToUTF16("title1"), - UTF8ToUTF16("message1"), - UTF8ToUTF16("source2"), - "ext1", - NULL, - NULL); + scoped_ptr<Notification> notification( + new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + "id0", + UTF8ToUTF16("title0"), + UTF8ToUTF16("message0"), + gfx::Image(), + UTF8ToUTF16("source0"), + "ext0", + NULL, + NULL)); + notification_list()->AddNotification(notification.Pass()); + notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + "id1", + UTF8ToUTF16("title1"), + UTF8ToUTF16("message1"), + gfx::Image(), + UTF8ToUTF16("source0"), + "ext0", + NULL, + NULL)); + notification_list()->AddNotification(notification.Pass()); + notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + "id2", + UTF8ToUTF16("title1"), + UTF8ToUTF16("message1"), + gfx::Image(), + UTF8ToUTF16("source1"), + "ext0", + NULL, + NULL)); + notification_list()->AddNotification(notification.Pass()); + notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + "id3", + UTF8ToUTF16("title1"), + UTF8ToUTF16("message1"), + gfx::Image(), + UTF8ToUTF16("source2"), + "ext1", + NULL, + NULL)); + notification_list()->AddNotification(notification.Pass()); NotificationList::Notifications by_source = notification_list()->GetNotificationsBySource("id0"); @@ -308,12 +324,17 @@ TEST_F(NotificationListTest, PriorityPromotion) { EXPECT_EQ(0u, GetPopupCounts()); base::DictionaryValue optional; optional.SetInteger(message_center::kPriorityKey, 1); - notification_list()->UpdateNotificationMessage(id0, - replaced, - UTF8ToUTF16("newtitle"), - UTF8ToUTF16("newbody"), - &optional, - NULL); + scoped_ptr<Notification> notification( + new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + replaced, + UTF8ToUTF16("newtitle"), + UTF8ToUTF16("newbody"), + gfx::Image(), + UTF8ToUTF16(kDisplaySource), + kExtensionId, + &optional, + NULL)); + notification_list()->UpdateNotificationMessage(id0, notification.Pass()); EXPECT_EQ(1u, notification_list()->NotificationCount()); EXPECT_EQ(1u, GetPopupCounts()); const NotificationList::Notifications& notifications = @@ -335,31 +356,48 @@ TEST_F(NotificationListTest, PriorityPromotionWithPopups) { base::DictionaryValue priority_default; priority_default.SetInteger(message_center::kPriorityKey, static_cast<int>(DEFAULT_PRIORITY)); - notification_list()->UpdateNotificationMessage(id0, - id0, - UTF8ToUTF16("newtitle"), - UTF8ToUTF16("newbody"), - &priority_default, - NULL); + scoped_ptr<Notification> notification( + new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + id0, + UTF8ToUTF16("newtitle"), + UTF8ToUTF16("newbody"), + gfx::Image(), + UTF8ToUTF16(kDisplaySource), + kExtensionId, + &priority_default, + NULL)); + notification_list()->UpdateNotificationMessage(id0, notification.Pass()); EXPECT_EQ(1u, GetPopupCounts()); notification_list()->MarkSinglePopupAsShown(id0, true); EXPECT_EQ(0u, GetPopupCounts()); // update with no promotion change for id0, it won't appear as a toast. - notification_list()->UpdateNotificationMessage( - id0, id0, UTF8ToUTF16("newtitle2"), UTF8ToUTF16("newbody2"), NULL, NULL); + notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + id0, + UTF8ToUTF16("newtitle2"), + UTF8ToUTF16("newbody2"), + gfx::Image(), + UTF8ToUTF16(kDisplaySource), + kExtensionId, + NULL, + NULL)); + notification_list()->UpdateNotificationMessage(id0, notification.Pass()); EXPECT_EQ(0u, GetPopupCounts()); // id1 promoted to DEFAULT->HIGH, it'll appear as toast (popup). base::DictionaryValue priority_high; priority_high.SetInteger(message_center::kPriorityKey, static_cast<int>(HIGH_PRIORITY)); - notification_list()->UpdateNotificationMessage(id1, - id1, - UTF8ToUTF16("newtitle"), - UTF8ToUTF16("newbody"), - &priority_high, - NULL); + notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + id1, + UTF8ToUTF16("newtitle"), + UTF8ToUTF16("newbody"), + gfx::Image(), + UTF8ToUTF16(kDisplaySource), + kExtensionId, + &priority_high, + NULL)); + notification_list()->UpdateNotificationMessage(id1, notification.Pass()); EXPECT_EQ(1u, GetPopupCounts()); notification_list()->MarkSinglePopupAsShown(id1, true); EXPECT_EQ(0u, GetPopupCounts()); @@ -368,23 +406,31 @@ TEST_F(NotificationListTest, PriorityPromotionWithPopups) { base::DictionaryValue priority_max; priority_max.SetInteger(message_center::kPriorityKey, static_cast<int>(MAX_PRIORITY)); - notification_list()->UpdateNotificationMessage(id1, - id1, - UTF8ToUTF16("newtitle2"), - UTF8ToUTF16("newbody2"), - &priority_max, - NULL); + notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + id1, + UTF8ToUTF16("newtitle2"), + UTF8ToUTF16("newbody2"), + gfx::Image(), + UTF8ToUTF16(kDisplaySource), + kExtensionId, + &priority_max, + NULL)); + notification_list()->UpdateNotificationMessage(id1, notification.Pass()); EXPECT_EQ(1u, GetPopupCounts()); notification_list()->MarkSinglePopupAsShown(id1, true); EXPECT_EQ(0u, GetPopupCounts()); // id1 demoted to MAX->DEFAULT, no appearing as toast. - notification_list()->UpdateNotificationMessage(id1, - id1, - UTF8ToUTF16("newtitle3"), - UTF8ToUTF16("newbody3"), - &priority_default, - NULL); + notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + id1, + UTF8ToUTF16("newtitle3"), + UTF8ToUTF16("newbody3"), + gfx::Image(), + UTF8ToUTF16(kDisplaySource), + kExtensionId, + &priority_default, + NULL)); + notification_list()->UpdateNotificationMessage(id1, notification.Pass()); EXPECT_EQ(0u, GetPopupCounts()); } @@ -513,12 +559,17 @@ TEST_F(NotificationListTest, UpdateAfterMarkedAsShown) { EXPECT_TRUE(n1->is_read()); const std::string replaced("test-replaced-id"); - notification_list()->UpdateNotificationMessage(id1, - replaced, - UTF8ToUTF16("newtitle"), - UTF8ToUTF16("newbody"), - NULL, - NULL); + scoped_ptr<Notification> notification( + new Notification(message_center::NOTIFICATION_TYPE_SIMPLE, + replaced, + UTF8ToUTF16("newtitle"), + UTF8ToUTF16("newbody"), + gfx::Image(), + UTF8ToUTF16(kDisplaySource), + kExtensionId, + NULL, + NULL)); + notification_list()->UpdateNotificationMessage(id1, notification.Pass()); n1 = GetNotification(id1); EXPECT_TRUE(n1 == NULL); const Notification* nr = GetNotification(replaced); diff --git a/ui/message_center/notification_types.cc b/ui/message_center/notification_types.cc index a391987..a54ed7b 100644 --- a/ui/message_center/notification_types.cc +++ b/ui/message_center/notification_types.cc @@ -6,10 +6,8 @@ namespace message_center { -const char kMessageIntentKey[] = "message_intent"; const char kPriorityKey[] = "priority"; const char kTimestampKey[] = "timestamp"; -const char kUnreadCountKey[] = "unread_count"; const char kButtonOneTitleKey[] = "button_one_title"; const char kButtonOneIconUrlKey[] = "button_one_icon_url"; const char kButtonTwoTitleKey[] = "button_two_title"; diff --git a/ui/message_center/notification_types.h b/ui/message_center/notification_types.h index 161fb14..c935cfa 100644 --- a/ui/message_center/notification_types.h +++ b/ui/message_center/notification_types.h @@ -15,7 +15,6 @@ namespace message_center { // Keys for optional fields in Notification. MESSAGE_CENTER_EXPORT extern const char kPriorityKey[]; MESSAGE_CENTER_EXPORT extern const char kTimestampKey[]; -MESSAGE_CENTER_EXPORT extern const char kUnreadCountKey[]; MESSAGE_CENTER_EXPORT extern const char kButtonOneTitleKey[]; MESSAGE_CENTER_EXPORT extern const char kButtonOneIconUrlKey[]; MESSAGE_CENTER_EXPORT extern const char kButtonTwoTitleKey[]; diff --git a/ui/message_center/views/message_center_view_unittest.cc b/ui/message_center/views/message_center_view_unittest.cc index 3a000f5..4e6c779 100644 --- a/ui/message_center/views/message_center_view_unittest.cc +++ b/ui/message_center/views/message_center_view_unittest.cc @@ -131,6 +131,7 @@ void MessageCenterViewTest::SetUp() { std::string("notification id"), UTF8ToUTF16("title"), UTF8ToUTF16("message"), + gfx::Image(), UTF8ToUTF16("display source"), std::string("extension id"), NULL, diff --git a/ui/message_center/views/message_popup_collection_unittest.cc b/ui/message_center/views/message_popup_collection_unittest.cc index a032aaf..46fbacd9 100644 --- a/ui/message_center/views/message_popup_collection_unittest.cc +++ b/ui/message_center/views/message_popup_collection_unittest.cc @@ -68,14 +68,17 @@ class MessagePopupCollectionTest : public views::ViewsTestBase { std::string AddNotification() { std::string id = base::IntToString(id_++); - MessageCenter::Get()->AddNotification(NOTIFICATION_TYPE_BASE_FORMAT, - id, - UTF8ToUTF16("test title"), - UTF8ToUTF16("test message"), - string16() /* display_source */, - "" /* extension_id */, - NULL /* optional_fields */, - NULL /* delegate */); + scoped_ptr<Notification> notification( + new Notification(NOTIFICATION_TYPE_BASE_FORMAT, + id, + UTF8ToUTF16("test title"), + UTF8ToUTF16("test message"), + gfx::Image(), + string16() /* display_source */, + "" /* extension_id */, + NULL /* optional_fields */, + NULL /* delegate */)); + MessageCenter::Get()->AddNotification(notification.Pass()); return id; } |