diff options
author | johnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-12 17:13:49 +0000 |
---|---|---|
committer | johnnyg@chromium.org <johnnyg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-07-12 17:13:49 +0000 |
commit | 04b0c9332361ac2f7de9455d0df15290db94c693 (patch) | |
tree | fdc8b47e5f7c57b3e7382a7a236e5b92675b3f87 | |
parent | 9e5c05aa2d4404c2a9946b49df19c2f781116b29 (diff) | |
download | chromium_src-04b0c9332361ac2f7de9455d0df15290db94c693.zip chromium_src-04b0c9332361ac2f7de9455d0df15290db94c693.tar.gz chromium_src-04b0c9332361ac2f7de9455d0df15290db94c693.tar.bz2 |
Implement BiDi support and replace ID support for notifications.
BUG=none
TEST=layout tests
Review URL: http://codereview.chromium.org/1917004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@52090 0039d316-1c4b-4281-b951-d872f2087c98
22 files changed, 365 insertions, 172 deletions
diff --git a/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc b/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc index 5b0a200..63840ac 100644 --- a/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc +++ b/chrome/browser/chromeos/notifications/desktop_notifications_unittest.cc @@ -33,6 +33,7 @@ void MockBalloonCollection::Add(const Notification& notification, Notification test_notification(notification.origin_url(), notification.content_url(), notification.display_source(), + string16(), /* replace_id */ log_proxy_.get()); BalloonCollectionImpl::Add(test_notification, profile); } @@ -41,6 +42,7 @@ bool MockBalloonCollection::Remove(const Notification& notification) { Notification test_notification(notification.origin_url(), notification.content_url(), notification.display_source(), + string16(), /* replace_id */ log_proxy_.get()); return BalloonCollectionImpl::Remove(test_notification); } @@ -93,18 +95,35 @@ void DesktopNotificationsTest::TearDown() { ui_manager_.reset(NULL); } +ViewHostMsg_ShowNotification_Params +DesktopNotificationsTest::StandardTestNotification() { + ViewHostMsg_ShowNotification_Params params; + params.notification_id = 0; + params.origin = GURL("http://www.google.com"); + params.is_html = false; + params.icon_url = GURL("/icon.png"); + params.title = ASCIIToUTF16("Title"); + params.body = ASCIIToUTF16("Text"); + return params; +} + TEST_F(DesktopNotificationsTest, TestShow) { - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 1)); + ViewHostMsg_ShowNotification_Params params = StandardTestNotification(); + params.notification_id = 1; + EXPECT_TRUE(service_->ShowDesktopNotification( + params, 0, 0, DesktopNotificationService::PageNotification)); + MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); + ViewHostMsg_ShowNotification_Params params2; + params2.origin = GURL("http://www.google.com"); + params2.is_html = true; + params2.contents_url = GURL("http://www.google.com/notification.html"); + params2.notification_id = 2; + EXPECT_TRUE(service_->ShowDesktopNotification( - GURL("http://www.google.com"), - GURL("http://www.google.com/notification.html"), - 0, 0, DesktopNotificationService::PageNotification, 2)); + params2, 0, 0, DesktopNotificationService::PageNotification)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(2, balloon_collection_->count()); @@ -114,11 +133,12 @@ TEST_F(DesktopNotificationsTest, TestShow) { } TEST_F(DesktopNotificationsTest, TestClose) { + ViewHostMsg_ShowNotification_Params params = StandardTestNotification(); + params.notification_id = 1; + // Request a notification; should open a balloon. - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 1)); + EXPECT_TRUE(service_->ShowDesktopNotification( + params, 0, 0, DesktopNotificationService::PageNotification)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); @@ -141,12 +161,14 @@ TEST_F(DesktopNotificationsTest, TestCancel) { int process_id = 0; int route_id = 0; int notification_id = 1; + + ViewHostMsg_ShowNotification_Params params = StandardTestNotification(); + params.notification_id = notification_id; + // Request a notification; should open a balloon. - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - process_id, route_id, DesktopNotificationService::PageNotification, - notification_id)); + EXPECT_TRUE(service_->ShowDesktopNotification( + params, process_id, route_id, + DesktopNotificationService::PageNotification)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); @@ -171,11 +193,11 @@ TEST_F(DesktopNotificationsTest, TestManyNotifications) { const int kLotsOfToasts = 20; for (int id = 1; id <= kLotsOfToasts; ++id) { SCOPED_TRACE(StringPrintf("Creation loop: id=%d", id)); - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - process_id, route_id, - DesktopNotificationService::PageNotification, id)); + ViewHostMsg_ShowNotification_Params params = StandardTestNotification(); + params.notification_id = id; + EXPECT_TRUE(service_->ShowDesktopNotification( + params, process_id, route_id, + DesktopNotificationService::PageNotification)); } MessageLoopForUI::current()->RunAllPending(); @@ -222,10 +244,9 @@ TEST_F(DesktopNotificationsTest, TestEarlyDestruction) { for (int id = 0; id <= 3; ++id) { SCOPED_TRACE(StringPrintf("Show Text loop: id=%d", id)); - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, id)); + EXPECT_TRUE(service_->ShowDesktopNotification( + StandardTestNotification(), 0, 0, + DesktopNotificationService::PageNotification)); } service_.reset(NULL); } @@ -233,12 +254,12 @@ TEST_F(DesktopNotificationsTest, TestEarlyDestruction) { TEST_F(DesktopNotificationsTest, TestUserInputEscaping) { // Create a test script with some HTML; assert that it doesn't get into the // data:// URL that's produced for the balloon. - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), - ASCIIToUTF16("<script>window.alert('uh oh');</script>"), - ASCIIToUTF16("<i>this text is in italics</i>"), - 0, 0, DesktopNotificationService::PageNotification, 1)); + ViewHostMsg_ShowNotification_Params params = StandardTestNotification(); + params.title = ASCIIToUTF16("<script>window.alert('uh oh');</script>"); + params.body = ASCIIToUTF16("<i>this text is in italics</i>"); + params.notification_id = 1; + EXPECT_TRUE(service_->ShowDesktopNotification( + params, 0, 0, DesktopNotificationService::PageNotification)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); diff --git a/chrome/browser/chromeos/notifications/desktop_notifications_unittest.h b/chrome/browser/chromeos/notifications/desktop_notifications_unittest.h index a2d52c8..b424c67 100644 --- a/chrome/browser/chromeos/notifications/desktop_notifications_unittest.h +++ b/chrome/browser/chromeos/notifications/desktop_notifications_unittest.h @@ -20,6 +20,7 @@ #include "chrome/browser/notifications/notification_test_util.h" #include "chrome/browser/notifications/notification_ui_manager.h" #include "chrome/browser/notifications/notifications_prefs_cache.h" +#include "chrome/common/render_messages.h" #include "chrome/test/testing_profile.h" #include "testing/gtest/include/gtest/gtest.h" @@ -83,6 +84,9 @@ class DesktopNotificationsTest : public testing::Test { return service_->prefs_cache()->HasPermission(origin); } + // Constructs a notification parameter structure for use in tests. + ViewHostMsg_ShowNotification_Params StandardTestNotification(); + // Create a message loop to allow notifications code to post tasks, // and a thread so that notifications code runs on the expected thread. MessageLoopForUI message_loop_; diff --git a/chrome/browser/chromeos/notifications/notification_browsertest.cc b/chrome/browser/chromeos/notifications/notification_browsertest.cc index 35d7833..304b5d2 100644 --- a/chrome/browser/chromeos/notifications/notification_browsertest.cc +++ b/chrome/browser/chromeos/notifications/notification_browsertest.cc @@ -249,8 +249,8 @@ IN_PROC_BROWSER_TEST_F(NotificationTest, TestSystemNotification) { // Dismiss the notification. // TODO(oshima): Consider updating API to Remove(NotificationDelegate) // or Remove(std::string id); - collection->Remove(Notification(GURL(), GURL(), - std::wstring(), delegate.get())); + collection->Remove(Notification(GURL(), GURL(), std::wstring(), string16(), + delegate.get())); ui_test_utils::RunAllPendingInMessageLoop(); EXPECT_EQ(0, tester->GetStickyNotificationCount()); diff --git a/chrome/browser/chromeos/notifications/system_notification.cc b/chrome/browser/chromeos/notifications/system_notification.cc index a929793..f2d9d4a 100644 --- a/chrome/browser/chromeos/notifications/system_notification.cc +++ b/chrome/browser/chromeos/notifications/system_notification.cc @@ -59,7 +59,7 @@ void SystemNotification::Show(const string16& message, bool urgent) { void SystemNotification::Hide() { if (visible_) { - collection_->Remove(Notification(GURL(), GURL(), std::wstring(), + collection_->Remove(Notification(GURL(), GURL(), std::wstring(), string16(), delegate_.get())); visible_ = false; @@ -68,4 +68,3 @@ void SystemNotification::Hide() { } } // namespace chromeos - diff --git a/chrome/browser/chromeos/notifications/system_notification_factory.cc b/chrome/browser/chromeos/notifications/system_notification_factory.cc index 1e32d84..ac01322 100644 --- a/chrome/browser/chromeos/notifications/system_notification_factory.cc +++ b/chrome/browser/chromeos/notifications/system_notification_factory.cc @@ -14,7 +14,8 @@ Notification SystemNotificationFactory::Create( const string16& text, NotificationDelegate* delegate) { string16 content_url = DesktopNotificationService::CreateDataUrl( - icon, title, text); - return Notification(GURL(), GURL(content_url), std::wstring(), delegate); + icon, title, text, WebKit::WebTextDirectionDefault); + return Notification(GURL(), GURL(content_url), std::wstring(), string16(), + delegate); } } // namespace chromeos diff --git a/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm b/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm index c7b565c..c8c2743 100644 --- a/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm +++ b/chrome/browser/cocoa/notifications/balloon_controller_unittest.mm @@ -63,7 +63,8 @@ class BalloonControllerTest : public RenderViewHostTestHarness { TEST_F(BalloonControllerTest, ShowAndCloseTest) { Notification n(GURL("http://www.google.com"), GURL("http://www.google.com"), - L"http://www.google.com", new NotificationObjectProxy(-1, -1, -1, false)); + L"http://www.google.com", ASCIIToUTF16(""), + new NotificationObjectProxy(-1, -1, -1, false)); scoped_ptr<Balloon> balloon( new Balloon(n, profile_.get(), collection_.get())); @@ -81,7 +82,8 @@ TEST_F(BalloonControllerTest, ShowAndCloseTest) { TEST_F(BalloonControllerTest, SizesTest) { Notification n(GURL("http://www.google.com"), GURL("http://www.google.com"), - L"http://www.google.com", new NotificationObjectProxy(-1, -1, -1, false)); + L"http://www.google.com", ASCIIToUTF16(""), + new NotificationObjectProxy(-1, -1, -1, false)); scoped_ptr<Balloon> balloon( new Balloon(n, profile_.get(), collection_.get())); balloon->set_content_size(gfx::Size(100, 100)); diff --git a/chrome/browser/notifications/balloon.cc b/chrome/browser/notifications/balloon.cc index 4d9a94f..969bde1 100644 --- a/chrome/browser/notifications/balloon.cc +++ b/chrome/browser/notifications/balloon.cc @@ -38,10 +38,12 @@ void Balloon::Show() { notification_->Display(); if (balloon_view_.get()) { balloon_view_->Show(this); + balloon_view_->RepositionToBalloon(); } } void Balloon::Update(const Notification& notification) { + notification_->Close(false); notification_.reset(new Notification(notification)); notification_->Display(); if (balloon_view_.get()) { diff --git a/chrome/browser/notifications/desktop_notification_service.cc b/chrome/browser/notifications/desktop_notification_service.cc index 4a5f3ab..bc66077 100644 --- a/chrome/browser/notifications/desktop_notification_service.cc +++ b/chrome/browser/notifications/desktop_notification_service.cc @@ -36,12 +36,14 @@ #include "third_party/WebKit/WebKit/chromium/public/WebNotificationPresenter.h" using WebKit::WebNotificationPresenter; +using WebKit::WebTextDirection; const ContentSetting kDefaultSetting = CONTENT_SETTING_ASK; // static string16 DesktopNotificationService::CreateDataUrl( - const GURL& icon_url, const string16& title, const string16& body) { + const GURL& icon_url, const string16& title, const string16& body, + WebTextDirection dir) { int resource; string16 line_name; string16 line; @@ -51,6 +53,9 @@ string16 DesktopNotificationService::CreateDataUrl( subst.push_back(icon_url.spec()); subst.push_back(EscapeForHTML(UTF16ToUTF8(title))); subst.push_back(EscapeForHTML(UTF16ToUTF8(body))); + // icon float position + subst.push_back(dir == WebKit::WebTextDirectionRightToLeft ? + "right" : "left"); } else if (title.empty() || body.empty()) { resource = IDR_NOTIFICATION_1LINE_HTML; line = title.empty() ? body : title; @@ -64,6 +69,9 @@ string16 DesktopNotificationService::CreateDataUrl( subst.push_back(EscapeForHTML(UTF16ToUTF8(title))); subst.push_back(EscapeForHTML(UTF16ToUTF8(body))); } + // body text direction + subst.push_back(dir == WebKit::WebTextDirectionRightToLeft ? + "rtl" : "ltr"); const base::StringPiece template_html( ResourceBundle::GetSharedInstance().GetRawDataResource( @@ -529,37 +537,32 @@ bool DesktopNotificationService::CancelDesktopNotification( scoped_refptr<NotificationObjectProxy> proxy( new NotificationObjectProxy(process_id, route_id, notification_id, false)); - Notification notif(GURL(), GURL(), L"", proxy); + // TODO(johnnyg): clean up this "empty" notification. + Notification notif(GURL(), GURL(), L"", ASCIIToUTF16(""), proxy); return ui_manager_->Cancel(notif); } bool DesktopNotificationService::ShowDesktopNotification( - const GURL& origin, const GURL& url, int process_id, int route_id, - DesktopNotificationSource source, int notification_id) { + const ViewHostMsg_ShowNotification_Params& params, + int process_id, int route_id, DesktopNotificationSource source) { DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); + const GURL& origin = params.origin; NotificationObjectProxy* proxy = new NotificationObjectProxy(process_id, route_id, - notification_id, + params.notification_id, source == WorkerNotification); - Notification notif(origin, url, DisplayNameForOrigin(origin), proxy); - ShowNotification(notif); - return true; -} - -bool DesktopNotificationService::ShowDesktopNotificationText( - const GURL& origin, const GURL& icon, const string16& title, - const string16& text, int process_id, int route_id, - DesktopNotificationSource source, int notification_id) { - DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); - NotificationObjectProxy* proxy = - new NotificationObjectProxy(process_id, route_id, - notification_id, - source == WorkerNotification); - // "upconvert" the string parameters to a data: URL. - string16 data_url = CreateDataUrl(icon, title, text); + GURL contents; + if (params.is_html) { + contents = params.contents_url; + } else { + // "upconvert" the string parameters to a data: URL. + contents = GURL( + CreateDataUrl(params.icon_url, params.title, params.body, + params.direction)); + } Notification notif( - origin, GURL(data_url), DisplayNameForOrigin(origin), proxy); + origin, contents, DisplayNameForOrigin(origin), params.replace_id, proxy); ShowNotification(notif); return true; } diff --git a/chrome/browser/notifications/desktop_notification_service.h b/chrome/browser/notifications/desktop_notification_service.h index 3f97425..ae38b18 100644 --- a/chrome/browser/notifications/desktop_notification_service.h +++ b/chrome/browser/notifications/desktop_notification_service.h @@ -14,6 +14,7 @@ #include "chrome/common/notification_registrar.h" #include "chrome/common/notification_service.h" #include "googleurl/src/gurl.h" +#include "third_party/WebKit/WebKit/chromium/public/WebTextDirection.h" class NotificationUIManager; class NotificationsPrefsCache; @@ -21,6 +22,7 @@ class PrefService; class Profile; class Task; class TabContents; +struct ViewHostMsg_ShowNotification_Params; // The DesktopNotificationService is an object, owned by the Profile, // which provides the creation of desktop "toasts" to web pages and workers. @@ -44,23 +46,13 @@ class DesktopNotificationService : public NotificationObserver { int callback_context, TabContents* tab); - // Takes a notification object and shows it in the UI. - void ShowNotification(const Notification& notification); - - // Two ShowNotification methods: getting content either from remote - // URL or as local parameters. These are called on the UI thread - // in response to IPCs from a child process running script. |origin| - // is the origin of the script. |source| indicates whether the - // script is in a worker or page. |notification_id| is an opaque - // value to be passed back to the process when events occur on - // this notification. - bool ShowDesktopNotification(const GURL& origin, const GURL& url, - int process_id, int route_id, DesktopNotificationSource source, - int notification_id); - bool ShowDesktopNotificationText(const GURL& origin, const GURL& icon, - const string16& title, const string16& text, int process_id, - int route_id, DesktopNotificationSource source, int notification_id); - + // ShowNotification is called on the UI thread handling IPCs from a child + // process, identified by |process_id| and |route_id|. |source| indicates + // whether the script is in a worker or page. |params| contains all the + // other parameters supplied by the worker or page. + bool ShowDesktopNotification( + const ViewHostMsg_ShowNotification_Params& params, + int process_id, int route_id, DesktopNotificationSource source); // Cancels a notification. If it has already been shown, it will be // removed from the screen. If it hasn't been shown yet, it won't be @@ -83,8 +75,10 @@ class DesktopNotificationService : public NotificationObserver { // Creates a data:xxxx URL which contains the full HTML for a notification // using supplied icon, title, and text, run through a template which contains // the standard formatting for notifications. - static string16 CreateDataUrl(const GURL& icon_url, const string16& title, - const string16& body); + static string16 CreateDataUrl(const GURL& icon_url, + const string16& title, + const string16& body, + WebKit::WebTextDirection dir); // The default content setting determines how to handle origins that haven't // been allowed or denied yet. @@ -112,6 +106,9 @@ class DesktopNotificationService : public NotificationObserver { void StartObserving(); void StopObserving(); + // Takes a notification object and shows it in the UI. + void ShowNotification(const Notification& notification); + // Save a permission change to the profile. void PersistPermissionChange(const GURL& origin, bool is_allowed); diff --git a/chrome/browser/notifications/desktop_notifications_unittest.cc b/chrome/browser/notifications/desktop_notifications_unittest.cc index 5cd03c3..459d9a0 100644 --- a/chrome/browser/notifications/desktop_notifications_unittest.cc +++ b/chrome/browser/notifications/desktop_notifications_unittest.cc @@ -21,6 +21,7 @@ void MockBalloonCollection::Add(const Notification& notification, Notification test_notification(notification.origin_url(), notification.content_url(), notification.display_source(), + string16(), /* replace_id */ log_proxy_.get()); BalloonCollectionImpl::Add(test_notification, profile); } @@ -29,6 +30,7 @@ bool MockBalloonCollection::Remove(const Notification& notification) { Notification test_notification(notification.origin_url(), notification.content_url(), notification.display_source(), + string16(), /* replace_id */ log_proxy_.get()); return BalloonCollectionImpl::Remove(test_notification); } @@ -87,18 +89,35 @@ void DesktopNotificationsTest::TearDown() { ui_manager_.reset(NULL); } +ViewHostMsg_ShowNotification_Params +DesktopNotificationsTest::StandardTestNotification() { + ViewHostMsg_ShowNotification_Params params; + params.notification_id = 0; + params.origin = GURL("http://www.google.com"); + params.is_html = false; + params.icon_url = GURL("/icon.png"); + params.title = ASCIIToUTF16("Title"); + params.body = ASCIIToUTF16("Text"); + return params; +} + TEST_F(DesktopNotificationsTest, TestShow) { - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 1)); + ViewHostMsg_ShowNotification_Params params = StandardTestNotification(); + params.notification_id = 1; + + EXPECT_TRUE(service_->ShowDesktopNotification( + params, 0, 0, DesktopNotificationService::PageNotification)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); + ViewHostMsg_ShowNotification_Params params2; + params2.origin = GURL("http://www.google.com"); + params2.is_html = true; + params2.contents_url = GURL("http://www.google.com/notification.html"); + params2.notification_id = 2; + EXPECT_TRUE(service_->ShowDesktopNotification( - GURL("http://www.google.com"), - GURL("http://www.google.com/notification.html"), - 0, 0, DesktopNotificationService::PageNotification, 2)); + params2, 0, 0, DesktopNotificationService::PageNotification)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(2, balloon_collection_->count()); @@ -108,11 +127,12 @@ TEST_F(DesktopNotificationsTest, TestShow) { } TEST_F(DesktopNotificationsTest, TestClose) { + ViewHostMsg_ShowNotification_Params params = StandardTestNotification(); + params.notification_id = 1; + // Request a notification; should open a balloon. - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 1)); + EXPECT_TRUE(service_->ShowDesktopNotification( + params, 0, 0, DesktopNotificationService::PageNotification)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); @@ -130,12 +150,14 @@ TEST_F(DesktopNotificationsTest, TestCancel) { int process_id = 0; int route_id = 0; int notification_id = 1; + + ViewHostMsg_ShowNotification_Params params = StandardTestNotification(); + params.notification_id = notification_id; + // Request a notification; should open a balloon. - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - process_id, route_id, DesktopNotificationService::PageNotification, - notification_id)); + EXPECT_TRUE(service_->ShowDesktopNotification( + params, process_id, route_id, + DesktopNotificationService::PageNotification)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); @@ -154,15 +176,15 @@ TEST_F(DesktopNotificationsTest, TestCancel) { #if defined(OS_WIN) || defined(TOOLKIT_VIEWS) TEST_F(DesktopNotificationsTest, TestPositioning) { + ViewHostMsg_ShowNotification_Params params = StandardTestNotification(); std::string expected_log; // Create some toasts. After each but the first, make sure there // is a minimum separation between the toasts. int last_top = 0; for (int id = 0; id <= 3; ++id) { - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, id)); + params.notification_id = id; + EXPECT_TRUE(service_->ShowDesktopNotification( + params, 0, 0, DesktopNotificationService::PageNotification)); expected_log.append("notification displayed\n"); int top = balloon_collection_->UppermostVerticalPosition(); if (id > 0) @@ -174,21 +196,29 @@ TEST_F(DesktopNotificationsTest, TestPositioning) { } TEST_F(DesktopNotificationsTest, TestVariableSize) { + ViewHostMsg_ShowNotification_Params params; + params.origin = GURL("http://long.google.com"); + params.is_html = false; + params.icon_url = GURL("/icon.png"); + params.title = ASCIIToUTF16("Really Really Really Really Really Really " + "Really Really Really Really Really Really " + "Really Really Really Really Really Really " + "Really Long Title"), + params.body = ASCIIToUTF16("Text"); + params.notification_id = 0; + std::string expected_log; // Create some toasts. After each but the first, make sure there // is a minimum separation between the toasts. - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://long.google.com"), GURL("/icon.png"), - ASCIIToUTF16("Really Really Really Really Really Really " - "Really Really Really Really Really Really " - "Really Really Really Really Really Really Really Long Title"), - ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 0)); + EXPECT_TRUE(service_->ShowDesktopNotification( + params, 0, 0, DesktopNotificationService::PageNotification)); expected_log.append("notification displayed\n"); - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://short.google.com"), GURL("/icon.png"), - ASCIIToUTF16("Short title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, 1)); + + params.origin = GURL("http://short.google.com"); + params.title = ASCIIToUTF16("Short title"); + params.notification_id = 1; + EXPECT_TRUE(service_->ShowDesktopNotification( + params, 0, 0, DesktopNotificationService::PageNotification)); expected_log.append("notification displayed\n"); std::deque<Balloon*>& balloons = balloon_collection_->balloons(); @@ -213,13 +243,13 @@ TEST_F(DesktopNotificationsTest, TestQueueing) { int route_id = 0; // Request lots of identical notifications. + ViewHostMsg_ShowNotification_Params params = StandardTestNotification(); const int kLotsOfToasts = 20; for (int id = 1; id <= kLotsOfToasts; ++id) { - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - process_id, route_id, - DesktopNotificationService::PageNotification, id)); + params.notification_id = id; + EXPECT_TRUE(service_->ShowDesktopNotification( + params, process_id, route_id, + DesktopNotificationService::PageNotification)); } MessageLoopForUI::current()->RunAllPending(); @@ -265,11 +295,11 @@ TEST_F(DesktopNotificationsTest, TestQueueing) { TEST_F(DesktopNotificationsTest, TestEarlyDestruction) { // Create some toasts and then prematurely delete the notification service, // just to make sure nothing crashes/leaks. + ViewHostMsg_ShowNotification_Params params = StandardTestNotification(); for (int id = 0; id <= 3; ++id) { - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), ASCIIToUTF16("Title"), ASCIIToUTF16("Text"), - 0, 0, DesktopNotificationService::PageNotification, id)); + params.notification_id = id; + EXPECT_TRUE(service_->ShowDesktopNotification( + params, 0, 0, DesktopNotificationService::PageNotification)); } service_.reset(NULL); } @@ -277,12 +307,12 @@ TEST_F(DesktopNotificationsTest, TestEarlyDestruction) { TEST_F(DesktopNotificationsTest, TestUserInputEscaping) { // Create a test script with some HTML; assert that it doesn't get into the // data:// URL that's produced for the balloon. - EXPECT_TRUE(service_->ShowDesktopNotificationText( - GURL("http://www.google.com"), - GURL("/icon.png"), - ASCIIToUTF16("<script>window.alert('uh oh');</script>"), - ASCIIToUTF16("<i>this text is in italics</i>, as is %3ci%3ethis%3c/i%3e"), - 0, 0, DesktopNotificationService::PageNotification, 1)); + ViewHostMsg_ShowNotification_Params params = StandardTestNotification(); + params.title = ASCIIToUTF16("<script>window.alert('uh oh');</script>"); + params.body = ASCIIToUTF16("<i>this text is in italics</i>"); + params.notification_id = 1; + EXPECT_TRUE(service_->ShowDesktopNotification( + params, 0, 0, DesktopNotificationService::PageNotification)); MessageLoopForUI::current()->RunAllPending(); EXPECT_EQ(1, balloon_collection_->count()); diff --git a/chrome/browser/notifications/desktop_notifications_unittest.h b/chrome/browser/notifications/desktop_notifications_unittest.h index 46bfeb4e..56a2a6b 100644 --- a/chrome/browser/notifications/desktop_notifications_unittest.h +++ b/chrome/browser/notifications/desktop_notifications_unittest.h @@ -15,6 +15,7 @@ #include "chrome/browser/notifications/notification_test_util.h" #include "chrome/browser/notifications/notification_ui_manager.h" #include "chrome/browser/notifications/notifications_prefs_cache.h" +#include "chrome/common/render_messages.h" #include "chrome/test/testing_profile.h" #include "testing/gtest/include/gtest/gtest.h" @@ -91,6 +92,9 @@ class DesktopNotificationsTest : public testing::Test { return service_->prefs_cache()->HasPermission(origin); } + // Constructs a notification parameter structure for use in tests. + ViewHostMsg_ShowNotification_Params StandardTestNotification(); + // Create a message loop to allow notifications code to post tasks, // and a thread so that notifications code runs on the expected thread. MessageLoopForUI message_loop_; diff --git a/chrome/browser/notifications/notification.h b/chrome/browser/notifications/notification.h index a58c2ad..bdad291 100644 --- a/chrome/browser/notifications/notification.h +++ b/chrome/browser/notifications/notification.h @@ -16,12 +16,15 @@ class NotificationDelegate; // data: URLs representing simple text+icon notifications. class Notification { public: + // TODO: http://crbug.com/43899 Convert this class to string16. Notification(const GURL& origin_url, const GURL& content_url, const std::wstring& display_source, + const string16& replace_id, NotificationDelegate* delegate) : origin_url_(origin_url), content_url_(content_url), display_source_(display_source), + replace_id_(replace_id), delegate_(delegate) { } @@ -29,9 +32,18 @@ class Notification { : origin_url_(notification.origin_url()), content_url_(notification.content_url()), display_source_(notification.display_source()), + replace_id_(notification.replace_id()), delegate_(notification.delegate()) { } + void operator=(const Notification& notification) { + origin_url_ = notification.origin_url(); + content_url_ = notification.content_url(); + display_source_ = notification.display_source(); + replace_id_ = notification.replace_id(); + delegate_ = notification.delegate(); + } + // The URL (may be data:) containing the contents for the notification. const GURL& content_url() const { return content_url_; } @@ -41,6 +53,8 @@ class Notification { // A display string for the source of the notification. const std::wstring& display_source() const { return display_source_; } + const string16& replace_id() const { return replace_id_; } + void Display() const { delegate()->Display(); } void Error() const { delegate()->Error(); } void Close(bool by_user) const { delegate()->Close(by_user); } @@ -63,12 +77,12 @@ class Notification { // the same as origin_url_, or the name of an extension. std::wstring display_source_; + // The replace ID for the notification. + string16 replace_id_; + // A proxy object that allows access back to the JavaScript object that // represents the notification, for firing events. scoped_refptr<NotificationDelegate> delegate_; - - // Disallow assign. Copy constructor written above. - void operator=(const Notification&); }; #endif // CHROME_BROWSER_NOTIFICATIONS_NOTIFICATION_H_ diff --git a/chrome/browser/notifications/notification_ui_manager.cc b/chrome/browser/notifications/notification_ui_manager.cc index e5ae3bd..42b9c5e 100644 --- a/chrome/browser/notifications/notification_ui_manager.cc +++ b/chrome/browser/notifications/notification_ui_manager.cc @@ -22,6 +22,10 @@ class QueuedNotification { const Notification& notification() const { return notification_; } Profile* profile() const { return profile_; } + void Replace(const Notification& new_notification) { + notification_ = new_notification; + } + private: // The notification to be shown. Notification notification_; @@ -51,6 +55,10 @@ NotificationUIManager* NotificationUIManager::Create() { void NotificationUIManager::Add(const Notification& notification, Profile* profile) { + if (TryReplacement(notification)) { + return; + } + LOG(INFO) << "Added notification. URL: " << notification.content_url().spec().c_str(); show_queue_.push_back( @@ -88,3 +96,37 @@ void NotificationUIManager::ShowNotifications() { void NotificationUIManager::OnBalloonSpaceChanged() { CheckAndShowNotifications(); } + +bool NotificationUIManager::TryReplacement(const Notification& notification) { + const GURL& origin = notification.origin_url(); + const string16& replace_id = notification.replace_id(); + + if (replace_id.empty()) + return false; + + // First check the queue of pending notifications for replacement. + // Then check the list of notifications already being shown. + NotificationDeque::iterator iter; + for (iter = show_queue_.begin(); iter != show_queue_.end(); ++iter) { + if (origin == (*iter)->notification().origin_url() && + replace_id == (*iter)->notification().replace_id()) { + (*iter)->Replace(notification); + return true; + } + } + + BalloonCollection::Balloons::iterator balloon_iter; + BalloonCollection::Balloons balloons = + balloon_collection_->GetActiveBalloons(); + for (balloon_iter = balloons.begin(); + balloon_iter != balloons.end(); + ++balloon_iter) { + if (origin == (*balloon_iter)->notification().origin_url() && + replace_id == (*balloon_iter)->notification().replace_id()) { + (*balloon_iter)->Update(notification); + return true; + } + } + + return false; +} diff --git a/chrome/browser/notifications/notification_ui_manager.h b/chrome/browser/notifications/notification_ui_manager.h index 2eaedd3..e510e7f 100644 --- a/chrome/browser/notifications/notification_ui_manager.h +++ b/chrome/browser/notifications/notification_ui_manager.h @@ -61,6 +61,10 @@ class NotificationUIManager // BalloonCollectionObserver implementation. virtual void OnBalloonSpaceChanged(); + // Replace an existing notification with this one if applicable; + // returns true if the replacement happened. + bool TryReplacement(const Notification& notification); + // An owned pointer to the collection of active balloons. scoped_ptr<BalloonCollection> balloon_collection_; diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc index 92c2182..e7ba21f 100644 --- a/chrome/browser/renderer_host/render_view_host.cc +++ b/chrome/browser/renderer_host/render_view_host.cc @@ -817,8 +817,6 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) { OnFillAutoFillFormData) IPC_MESSAGE_HANDLER(ViewHostMsg_ShowDesktopNotification, OnShowDesktopNotification) - IPC_MESSAGE_HANDLER(ViewHostMsg_ShowDesktopNotificationText, - OnShowDesktopNotificationText) IPC_MESSAGE_HANDLER(ViewHostMsg_CancelDesktopNotification, OnCancelDesktopNotification) IPC_MESSAGE_HANDLER(ViewHostMsg_RequestNotificationPermission, @@ -1766,23 +1764,14 @@ void RenderViewHost::ForwardMessageFromExternalHost(const std::string& message, target)); } -void RenderViewHost::OnShowDesktopNotification(const GURL& source_origin, - const GURL& url, int notification_id) { +void RenderViewHost::OnShowDesktopNotification( + const ViewHostMsg_ShowNotification_Params& params) { DesktopNotificationService* service = process()->profile()->GetDesktopNotificationService(); - service->ShowDesktopNotification(source_origin, url, process()->id(), - routing_id(), DesktopNotificationService::PageNotification, - notification_id); -} -void RenderViewHost::OnShowDesktopNotificationText(const GURL& source_origin, - const GURL& icon, const string16& title, const string16& text, - int notification_id) { - DesktopNotificationService* service = - process()->profile()->GetDesktopNotificationService(); - service->ShowDesktopNotificationText(source_origin, icon, title, text, - process()->id(), routing_id(), - DesktopNotificationService::PageNotification, notification_id); + service->ShowDesktopNotification( + params, process()->id(), routing_id(), + DesktopNotificationService::PageNotification); } void RenderViewHost::OnCancelDesktopNotification(int notification_id) { diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h index c62f6ce..e1073ec 100644 --- a/chrome/browser/renderer_host/render_view_host.h +++ b/chrome/browser/renderer_host/render_view_host.h @@ -37,6 +37,7 @@ struct MediaPlayerAction; struct ThumbnailScore; struct ViewHostMsg_DidPrintPage_Params; struct ViewHostMsg_RunFileChooser_Params; +struct ViewHostMsg_ShowNotification_Params; struct ViewMsg_Navigate_Params; struct WebDropData; struct WebPreferences; @@ -613,12 +614,8 @@ class RenderViewHost : public RenderWidgetHost { const string16& value, const string16& label); - void OnShowDesktopNotification(const GURL& source_origin, - const GURL& url, int notification_id); - void OnShowDesktopNotificationText(const GURL& origin, const GURL& icon, - const string16& title, - const string16& text, - int notification_id); + void OnShowDesktopNotification( + const ViewHostMsg_ShowNotification_Params& params); void OnCancelDesktopNotification(int notification_id); void OnRequestNotificationPermission(const GURL& origin, int callback_id); diff --git a/chrome/browser/resources/notification_1line.html b/chrome/browser/resources/notification_1line.html index bc799fb..242f48b 100644 --- a/chrome/browser/resources/notification_1line.html +++ b/chrome/browser/resources/notification_1line.html @@ -10,5 +10,5 @@ } </style> </head> -<body><div id="$1">$2</div></body> +<body dir="$3"><div id="$1">$2</div></body> </html> diff --git a/chrome/browser/resources/notification_2line.html b/chrome/browser/resources/notification_2line.html index 2754817..1361393 100644 --- a/chrome/browser/resources/notification_2line.html +++ b/chrome/browser/resources/notification_2line.html @@ -17,7 +17,7 @@ } </style> </head> -<body> +<body dir="$3"> <div id="title">$1</div> <div id="description">$2</div> </body> diff --git a/chrome/browser/resources/notification_icon.html b/chrome/browser/resources/notification_icon.html index 0015234..f3cfc5f 100644 --- a/chrome/browser/resources/notification_icon.html +++ b/chrome/browser/resources/notification_icon.html @@ -6,20 +6,21 @@ body { margin: 6px; height: 50px; + direction: $5; } #icon { height: 48px; width: 48px; - float: left; + float: $4; } #title { - margin-left: 54px; + margin-$4: 54px; font-weight: bold; font-size: 13px; font-family: helvetica, arial, sans-serif; } #description { - margin-left: 54px; + margin-$4: 54px; font-family: helvetica, arial, sans-serif; font-size: 13px; } diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index 6ee03d1..37658a5 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -39,6 +39,7 @@ #include "net/base/upload_data.h" #include "net/http/http_response_headers.h" #include "third_party/WebKit/WebKit/chromium/public/WebStorageArea.h" +#include "third_party/WebKit/WebKit/chromium/public/WebTextDirection.h" #include "webkit/appcache/appcache_interfaces.h" #include "webkit/glue/context_menu.h" #include "webkit/glue/form_data.h" @@ -657,6 +658,33 @@ struct ViewHostMsg_CreateWorker_Params { int64 script_resource_appcache_id; }; +// Parameters for the message that creates a desktop notification. +struct ViewHostMsg_ShowNotification_Params { + // URL which is the origin that created this notification. + GURL origin; + + // True if this is HTML + bool is_html; + + // URL which contains the HTML contents (if is_html is true), otherwise empty. + GURL contents_url; + + // Contents of the notification if is_html is false. + GURL icon_url; + string16 title; + string16 body; + + // Directionality of the notification. + WebKit::WebTextDirection direction; + + // ReplaceID if this notification should replace an existing one; may be + // empty if no replacement is called for. + string16 replace_id; + + // Notification ID for sending events back for this notification. + int notification_id; +}; + // Creates a new view via a control message since the view doesn't yet exist. struct ViewMsg_New_Params { // The parent window's id. @@ -2558,6 +2586,56 @@ struct ParamTraits<ViewHostMsg_CreateWorker_Params> { } }; +// Traits for ShowNotification_Params +template <> +struct ParamTraits<ViewHostMsg_ShowNotification_Params> { + typedef ViewHostMsg_ShowNotification_Params param_type; + static void Write(Message* m, const param_type& p) { + WriteParam(m, p.origin); + WriteParam(m, p.is_html); + WriteParam(m, p.contents_url); + WriteParam(m, p.icon_url); + WriteParam(m, p.title); + WriteParam(m, p.body); + WriteParam(m, p.direction); + WriteParam(m, p.replace_id); + WriteParam(m, p.notification_id); + } + static bool Read(const Message* m, void** iter, param_type* p) { + return + ReadParam(m, iter, &p->origin) && + ReadParam(m, iter, &p->is_html) && + ReadParam(m, iter, &p->contents_url) && + ReadParam(m, iter, &p->icon_url) && + ReadParam(m, iter, &p->title) && + ReadParam(m, iter, &p->body) && + ReadParam(m, iter, &p->direction) && + ReadParam(m, iter, &p->replace_id) && + ReadParam(m, iter, &p->notification_id); + } + static void Log(const param_type &p, std::wstring* l) { + l->append(L"("); + LogParam(p.origin, l); + l->append(L", "); + LogParam(p.is_html, l); + l->append(L", "); + LogParam(p.contents_url, l); + l->append(L", "); + LogParam(p.icon_url, l); + l->append(L", "); + LogParam(p.title, l); + l->append(L","); + LogParam(p.body, l); + l->append(L","); + LogParam(p.direction, l); + l->append(L","); + LogParam(p.replace_id, l); + l->append(L","); + LogParam(p.notification_id, l); + l->append(L")"); + } +}; + // Traits for WebCookie template <> struct ParamTraits<webkit_glue::WebCookie> { diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index b7cda04..0b8e903 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -2036,16 +2036,8 @@ IPC_BEGIN_MESSAGES(ViewHost) // A message sent to the browser on behalf of a renderer which wants to show // a desktop notification. - IPC_MESSAGE_ROUTED3(ViewHostMsg_ShowDesktopNotification, - GURL /* origin */, - GURL /* contents_url */, - int /* notification_id */) - IPC_MESSAGE_ROUTED5(ViewHostMsg_ShowDesktopNotificationText, - GURL /* origin */, - GURL /* icon_url */, - string16 /* title */, - string16 /* text */, - int /* notification_id */) + IPC_MESSAGE_ROUTED1(ViewHostMsg_ShowDesktopNotification, + ViewHostMsg_ShowNotification_Params) IPC_MESSAGE_ROUTED1(ViewHostMsg_CancelDesktopNotification, int /* notification_id */ ) IPC_MESSAGE_ROUTED2(ViewHostMsg_RequestNotificationPermission, diff --git a/chrome/renderer/notification_provider.cc b/chrome/renderer/notification_provider.cc index 414966f..46e8cab 100644 --- a/chrome/renderer/notification_provider.cc +++ b/chrome/renderer/notification_provider.cc @@ -105,18 +105,31 @@ bool NotificationProvider::ShowHTML(const WebNotification& notification, return false; DCHECK(notification.isHTML()); + ViewHostMsg_ShowNotification_Params params; + params.origin = GURL(view_->webview()->mainFrame()->url()).GetOrigin(); + params.is_html = true; + params.contents_url = notification.url(); + params.notification_id = id; + params.replace_id = notification.replaceId(); return Send(new ViewHostMsg_ShowDesktopNotification(view_->routing_id(), - GURL(view_->webview()->mainFrame()->url()).GetOrigin(), - notification.url(), id)); + params)); } bool NotificationProvider::ShowText(const WebNotification& notification, int id) { DCHECK(!notification.isHTML()); - return Send(new ViewHostMsg_ShowDesktopNotificationText(view_->routing_id(), - GURL(view_->webview()->mainFrame()->url()).GetOrigin(), - notification.iconURL(), - notification.title(), notification.body(), id)); + ViewHostMsg_ShowNotification_Params params; + params.is_html = false; + params.origin = GURL(view_->webview()->mainFrame()->url()).GetOrigin(); + params.icon_url = notification.iconURL(); + params.title = notification.title(); + params.body = notification.body(); + params.direction = notification.direction(); + params.notification_id = id; + params.replace_id = notification.replaceId(); + + return Send(new ViewHostMsg_ShowDesktopNotification(view_->routing_id(), + params)); } void NotificationProvider::OnDisplay(int id) { |