Commit 963b13c0 authored by dewittj@chromium.org's avatar dewittj@chromium.org

Adds a first-run balloon to the Windows notification center.

This is designed to attract attention to the system tray icon which
can be hidden in the overflow area.

BUG=246322

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@208031 0039d316-1c4b-4281-b951-d872f2087c98
parent 4eeb0f5f
......@@ -977,6 +977,16 @@ Signing in anyway will merge Chromium information like bookmarks, history, and o
<ph name="DOMAIN">$1<ex>example.com</ex></ph> requires that you read and accept the following Terms of Service before using this device. These terms do not expand, modify or limit the Chromium OS Terms.
</message>
</if>
<!-- Chrome Notifications center -->
<if expr="is_win">
<message name="IDS_MESSAGE_CENTER_BALLOON_TITLE" desc="Title of the first run notification ballon describing the notification center.">
Chromium Notification Center
</message>
<message name="IDS_MESSAGE_CENTER_BALLOON_TEXT" desc="Body text for the the first run notification ballon describing the notification center.">
You can see all your notifications from Chromium apps, extensions, and websites here.
</message>
</if>
</messages>
</release>
</grit>
......@@ -901,6 +901,16 @@ Signing in anyway will merge Chrome information like bookmarks, history, and oth
<ph name="DOMAIN">$1<ex>example.com</ex></ph> requires that you read and accept the following Terms of Service before using this device. These terms do not expand, modify or limit the Google Chrome OS Terms.
</message>
</if>
<!-- Chrome Notifications center -->
<if expr="is_win">
<message name="IDS_MESSAGE_CENTER_BALLOON_TITLE" desc="Title of the first run notification ballon describing the notification center.">
Chrome Notification Center
</message>
<message name="IDS_MESSAGE_CENTER_BALLOON_TEXT" desc="Body text for the the first run notification ballon describing the notification center.">
You can see all your notifications from Chrome apps, extensions, and websites here.
</message>
</if>
</messages>
</release>
</grit>
......@@ -25,10 +25,26 @@
#include "ui/message_center/message_center_tray.h"
#include "ui/message_center/notifier_settings.h"
namespace {
// The first-run balloon will be shown |kFirstRunIdleDelaySeconds| after all
// popups go away and the user has notifications in the message center.
const int kFirstRunIdleDelaySeconds = 1;
} // namespace
MessageCenterNotificationManager::MessageCenterNotificationManager(
message_center::MessageCenter* message_center)
message_center::MessageCenter* message_center,
PrefService* local_state)
: message_center_(message_center),
#if defined(OS_WIN)
first_run_idle_timeout_(
base::TimeDelta::FromSeconds(kFirstRunIdleDelaySeconds)),
weak_factory_(this),
#endif
settings_controller_(new MessageCenterSettingsController) {
#if defined(OS_WIN)
first_run_pref_.Init(prefs::kMessageCenterShowedFirstRunBalloon, local_state);
#endif
message_center_->SetDelegate(this);
message_center_->AddObserver(this);
message_center_->SetNotifierSettingsProvider(settings_controller_.get());
......@@ -45,7 +61,6 @@ MessageCenterNotificationManager::~MessageCenterNotificationManager() {
message_center_->RemoveObserver(this);
}
////////////////////////////////////////////////////////////////////////////////
// NotificationUIManager
......@@ -270,12 +285,31 @@ void MessageCenterNotificationManager::OnNotificationRemoved(
profile_notifications_.find(notification_id);
if (iter != profile_notifications_.end())
RemoveProfileNotification(iter->second, by_user);
#if defined(OS_WIN)
CheckFirstRunTimer();
#endif
}
void MessageCenterNotificationManager::OnNotificationCenterClosed() {
// When the center is open it halts all notifications, so we need to listen
// for events indicating it's been closed.
CheckAndShowNotifications();
#if defined(OS_WIN)
CheckFirstRunTimer();
#endif
}
void MessageCenterNotificationManager::OnNotificationUpdated(
const std::string& notification_id) {
#if defined(OS_WIN)
CheckFirstRunTimer();
#endif
}
void MessageCenterNotificationManager::SetMessageCenterTrayDelegateForTest(
message_center::MessageCenterTrayDelegate* delegate) {
tray_.reset(delegate);
}
////////////////////////////////////////////////////////////////////////////////
......
......@@ -9,6 +9,10 @@
#include <string>
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/prefs/pref_member.h"
#include "base/time.h"
#include "base/timer.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_ui_manager.h"
#include "chrome/browser/notifications/notification_ui_manager_impl.h"
......@@ -18,6 +22,7 @@
class MessageCenterSettingsController;
class Notification;
class PrefService;
class Profile;
// This class extends NotificationUIManagerImpl and delegates actual display
......@@ -28,7 +33,8 @@ class MessageCenterNotificationManager
public message_center::MessageCenterObserver {
public:
explicit MessageCenterNotificationManager(
message_center::MessageCenter* message_center);
message_center::MessageCenter* message_center,
PrefService* local_state);
virtual ~MessageCenterNotificationManager();
// NotificationUIManager
......@@ -57,6 +63,22 @@ class MessageCenterNotificationManager
virtual void OnNotificationRemoved(const std::string& notification_id,
bool by_user) OVERRIDE;
virtual void OnNotificationCenterClosed() OVERRIDE;
virtual void OnNotificationUpdated(const std::string& notification_id)
OVERRIDE;
#if defined(OS_WIN)
// Called when the pref changes for the first run balloon. The first run
// balloon is only displayed on Windows, since the visibility of the tray
// icon is limited.
void DisplayFirstRunBalloon();
void SetFirstRunTimeoutForTest(base::TimeDelta timeout);
bool FirstRunTimerIsActive() const;
#endif
// Takes ownership of |delegate|.
void SetMessageCenterTrayDelegateForTest(
message_center::MessageCenterTrayDelegate* delegate);
private:
class ImageDownloadsObserver {
......@@ -157,8 +179,6 @@ class MessageCenterNotificationManager
typedef std::map<std::string, ProfileNotification*> NotificationMap;
NotificationMap profile_notifications_;
scoped_ptr<MessageCenterSettingsController> settings_controller_;
// Helpers that add/remove the notification from local map and MessageCenter.
// They take ownership of profile_notification object.
void AddProfileNotification(ProfileNotification* profile_notification);
......@@ -169,6 +189,30 @@ class MessageCenterNotificationManager
// notification is found.
ProfileNotification* FindProfileNotification(const std::string& id) const;
#if defined(OS_WIN)
// This function is run on update to ensure that the notification balloon is
// shown only when there are no popups present.
void CheckFirstRunTimer();
// |first_run_pref_| is used to keep track of whether we've ever shown the
// first run balloon before, even across restarts.
BooleanPrefMember first_run_pref_;
// The timer after which we will show the first run balloon. This timer is
// restarted every time the message center is closed and every time the last
// popup disappears from the screen.
base::OneShotTimer<MessageCenterNotificationManager> first_run_balloon_timer_;
// The first-run balloon will be shown |first_run_idle_timeout_| after all
// popups go away and the user has notifications in the message center.
base::TimeDelta first_run_idle_timeout_;
// Provides weak pointers for the purpose of the first run timer.
base::WeakPtrFactory<MessageCenterNotificationManager> weak_factory_;
#endif
scoped_ptr<MessageCenterSettingsController> settings_controller_;
DISALLOW_COPY_AND_ASSIGN(MessageCenterNotificationManager);
};
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/notifications/message_center_notification_manager.h"
#include "chrome/common/pref_names.h"
#include "ui/message_center/message_center_tray.h"
void MessageCenterNotificationManager::DisplayFirstRunBalloon() {
// Store for posterity the fact that we've shown the first-run balloon.
DCHECK(tray_.get());
first_run_pref_.SetValue(true);
tray_->DisplayFirstRunBalloon();
}
void MessageCenterNotificationManager::SetFirstRunTimeoutForTest(
base::TimeDelta timeout) {
first_run_idle_timeout_ = timeout;
}
bool MessageCenterNotificationManager::FirstRunTimerIsActive() const {
return first_run_balloon_timer_.IsRunning();
}
void MessageCenterNotificationManager::CheckFirstRunTimer() {
// If there is no tray_, we can't display a balloon here anyway.
// Also, we only want to display the first run balloon once, so the pref will
// store the flag on disk based on whether we ever showed the balloon.
DCHECK(tray_.get());
if (first_run_pref_.GetValue())
return;
// If there are popups, the message center is visible, or there are no more
// notifications, don't continue the timer since it will be annoying or
// useless.
if (message_center_->HasPopupNotifications() ||
message_center_->IsMessageCenterVisible() ||
0 == message_center_->NotificationCount()) {
first_run_balloon_timer_.Stop();
return;
}
// No need to restart the timer if it's already going.
if (first_run_balloon_timer_.IsRunning())
return;
first_run_balloon_timer_.Start(
FROM_HERE,
first_run_idle_timeout_,
base::Bind(&MessageCenterNotificationManager::DisplayFirstRunBalloon,
weak_factory_.GetWeakPtr()));
}
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/memory/scoped_ptr.h"
#include "base/prefs/testing_pref_service.h"
#include "base/run_loop.h"
#include "base/test/test_timeouts.h"
#include "base/values.h"
#include "chrome/browser/notifications/message_center_notification_manager.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/notifications/notification_prefs_manager.h"
#include "chrome/browser/notifications/notification_test_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/message_center/message_center_impl.h"
#include "ui/message_center/message_center_tray.h"
#include "ui/message_center/message_center_tray_delegate.h"
namespace message_center {
class FakeMessageCenterTrayDelegate : public MessageCenterTrayDelegate {
public:
FakeMessageCenterTrayDelegate(MessageCenter* message_center,
base::Closure quit_closure)
: tray_(this, message_center),
quit_closure_(quit_closure),
displayed_first_run_balloon_(false) {}
virtual void DisplayFirstRunBalloon() OVERRIDE {
displayed_first_run_balloon_ = true;
base::MessageLoop::current()->PostTask(FROM_HERE, quit_closure_);
}
virtual void OnMessageCenterTrayChanged() OVERRIDE {}
virtual bool ShowPopups() OVERRIDE { return true; }
virtual void HidePopups() OVERRIDE {}
virtual void UpdatePopups() OVERRIDE {}
virtual bool ShowMessageCenter() OVERRIDE { return true; }
virtual bool ShowNotifierSettings() OVERRIDE { return true; }
virtual void HideMessageCenter() OVERRIDE {}
bool displayed_first_run_balloon() const {
return displayed_first_run_balloon_;
}
private:
MessageCenterTray tray_;
base::Closure quit_closure_;
bool displayed_first_run_balloon_;
};
class MessageCenterNotificationManagerTest : public testing::Test {
protected:
MessageCenterNotificationManagerTest() {
NotificationPrefsManager::RegisterPrefs(local_state_.registry());
}
virtual void SetUp() {
// Clear the preference and initialize.
local_state_.ClearPref(prefs::kMessageCenterShowedFirstRunBalloon);
first_run_pref_.Init(prefs::kMessageCenterShowedFirstRunBalloon,
&local_state_);
// Get ourselves a run loop.
run_loop_.reset(new base::RunLoop());
// Initialize message center infrastructure with mock tray delegate.
MessageCenter::Initialize();
message_center_ = MessageCenter::Get();
notification_manager_.reset(
new MessageCenterNotificationManager(message_center_, &local_state_));
delegate_ = new FakeMessageCenterTrayDelegate(message_center_,
run_loop_->QuitClosure());
notification_manager_->SetMessageCenterTrayDelegateForTest(delegate_);
notification_manager_->SetFirstRunTimeoutForTest(
TestTimeouts::tiny_timeout());
}
virtual void TearDown() {
run_loop_.reset();
notification_manager_.reset();
MessageCenter::Shutdown();
}
MessageCenterNotificationManager* notification_manager() {
return notification_manager_.get();
}
FakeMessageCenterTrayDelegate* delegate() { return delegate_; }
MessageCenter* message_center() { return message_center_; }
const ::Notification GetANotification(const std::string& id) {
return ::Notification(GURL(),
GURL(),
string16(),
string16(),
new MockNotificationDelegate(id));
}
base::RunLoop* run_loop() { return run_loop_.get(); }
const TestingPrefServiceSimple& local_state() { return local_state_; }
bool DidFirstRunPref() { return first_run_pref_.GetValue(); }
private:
scoped_ptr<base::RunLoop> run_loop_;
TestingPrefServiceSimple local_state_;
MessageCenter* message_center_;
scoped_ptr<MessageCenterNotificationManager> notification_manager_;
FakeMessageCenterTrayDelegate* delegate_;
content::TestBrowserThreadBundle thread_bundle_;
BooleanPrefMember first_run_pref_;
};
TEST_F(MessageCenterNotificationManagerTest, SetupNotificationManager) {
TestingProfile profile;
notification_manager()->Add(GetANotification("test"), &profile);
EXPECT_FALSE(DidFirstRunPref());
}
// The following tests test the first run balloon, which is only implemented for
// Windows.
TEST_F(MessageCenterNotificationManagerTest, FirstRunShown) {
TestingProfile profile;
notification_manager()->Add(GetANotification("test"), &profile);
message_center()->DisplayedNotification("test");
message_center()->MarkSinglePopupAsShown("test", false);
run_loop()->Run();
base::RunLoop run_loop_2;
run_loop_2.RunUntilIdle();
EXPECT_TRUE(delegate()->displayed_first_run_balloon());
EXPECT_TRUE(DidFirstRunPref());
}
TEST_F(MessageCenterNotificationManagerTest,
FirstRunNotShownWithPopupsVisible) {
TestingProfile profile;
notification_manager()->Add(GetANotification("test"), &profile);
message_center()->DisplayedNotification("test");
run_loop()->RunUntilIdle();
EXPECT_FALSE(delegate()->displayed_first_run_balloon());
EXPECT_FALSE(notification_manager()->FirstRunTimerIsActive());
EXPECT_FALSE(DidFirstRunPref());
}
TEST_F(MessageCenterNotificationManagerTest,
FirstRunNotShownWithMessageCenter) {
TestingProfile profile;
notification_manager()->Add(GetANotification("test"), &profile);
message_center()->SetMessageCenterVisible(true);
run_loop()->RunUntilIdle();
EXPECT_FALSE(notification_manager()->FirstRunTimerIsActive());
EXPECT_FALSE(DidFirstRunPref());
}
} // namespace message_center
......@@ -25,4 +25,6 @@ NotificationPrefsManager::NotificationPrefsManager(PrefService* prefs) {
void NotificationPrefsManager::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(prefs::kDesktopNotificationPosition,
BalloonCollection::DEFAULT_POSITION);
registry->RegisterBooleanPref(prefs::kMessageCenterShowedFirstRunBalloon,
false);
}
......@@ -26,7 +26,7 @@ bool NotificationUIManager::DelegatesToMessageCenter() {
NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) {
if (DelegatesToMessageCenter())
return new MessageCenterNotificationManager(
g_browser_process->message_center());
g_browser_process->message_center(), local_state);
BalloonNotificationUIManager* balloon_manager =
new BalloonNotificationUIManager(local_state);
......
......@@ -102,7 +102,7 @@ NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) {
// notification_ui_manager.cc.
if (DelegatesToMessageCenter()) {
return new MessageCenterNotificationManager(
g_browser_process->message_center());
g_browser_process->message_center(), local_state);
}
BalloonNotificationUIManager* balloon_manager = NULL;
......
......@@ -29,6 +29,12 @@ void StatusIcon::DispatchClickEvent() {
FOR_EACH_OBSERVER(StatusIconObserver, observers_, OnStatusIconClicked());
}
#if defined(OS_WIN)
void StatusIcon::DispatchBalloonClickEvent() {
FOR_EACH_OBSERVER(StatusIconObserver, observers_, OnBalloonClicked());
}
#endif
void StatusIcon::SetContextMenu(ui::MenuModel* menu) {
// The UI may been showing a menu for the current model, don't destroy it
// until we've notified the UI of the change.
......
......@@ -56,6 +56,9 @@ class StatusIcon {
// Dispatches a click event to the observers.
void DispatchClickEvent();
#if defined(OS_WIN)
void DispatchBalloonClickEvent();
#endif
protected:
// Invoked after a call to SetContextMenu() to let the platform-specific
......
......@@ -16,6 +16,13 @@ class StatusIconObserver {
// This will only be fired for this platform if no context menu is present.
virtual void OnStatusIconClicked() = 0;
#if defined(OS_WIN)
// Called when the user clicks on a balloon generated for a system tray icon.
// TODO(dewittj): Implement on platforms other than Windows. Currently this
// event will never fire on non-Windows platforms.
virtual void OnBalloonClicked() {}
#endif
protected:
virtual ~StatusIconObserver() {}
};
......
......@@ -30,10 +30,6 @@
#include "ui/message_center/views/message_popup_collection.h"
#include "ui/views/widget/widget.h"
#if defined(OS_WIN)
#include "ui/base/win/hwnd_util.h"
#endif
namespace {
// Tray constants
......
......@@ -62,6 +62,13 @@ class WebNotificationTray : public message_center::MessageCenterTrayDelegate,
// StatusIconObserver implementation.
virtual void OnStatusIconClicked() OVERRIDE;
#if defined(OS_WIN)
virtual void OnBalloonClicked() OVERRIDE;
// This shows a platform-specific balloon informing the user of the existence
// of the message center in the status tray area.
void DisplayFirstRunBalloon();
#endif
// Changes the icon and hovertext based on number of unread notifications.
void UpdateStatusIcon();
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/message_center/web_notification_tray.h"
#include <windows.h>
#include "base/win/windows_version.h"
#include "chrome/browser/app_icon_win.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/status_icons/status_icon.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/host_desktop.h"
#include "chrome/browser/ui/singleton_tabs.h"
#include "chrome/common/url_constants.h"
#include "grit/chromium_strings.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image_skia.h"
namespace message_center {
void WebNotificationTray::OnBalloonClicked() {
Browser* browser = chrome::FindOrCreateTabbedBrowser(
ProfileManager::GetLastUsedProfileAllowedByPolicy(),
chrome::GetActiveDesktop());
chrome::ShowSingletonTab(browser, GURL(chrome::kNotificationsHelpURL));
}
void WebNotificationTray::DisplayFirstRunBalloon() {
StatusIcon* status_icon = GetStatusIcon();
if (!status_icon)
return;
base::win::Version win_version = base::win::GetVersion();
if (win_version == base::win::VERSION_PRE_XP)
return;
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
// StatusIconWin uses NIIF_LARGE_ICON if the version is >= vista. According
// to http://msdn.microsoft.com/en-us/library/windows/desktop/bb773352.aspx:
// This corresponds to the icon with dimensions SM_CXICON x SM_CYICON. If
// this flag is not set, the icon with dimensions SM_CXSMICON x SM_CYSMICON
// is used.
int icon_size = GetSystemMetrics(SM_CXICON);
if (win_version < base::win::VERSION_VISTA)
icon_size = GetSystemMetrics(SM_CXSMICON);
scoped_ptr<SkBitmap> sized_app_icon_bitmap = GetAppIconForSize(icon_size);
gfx::ImageSkia sized_app_icon_skia =
gfx::ImageSkia::CreateFrom1xBitmap(*sized_app_icon_bitmap);
string16 product_name(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
GetStatusIcon()->DisplayBalloon(
sized_app_icon_skia,
l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_BALLOON_TITLE),
l10n_util::GetStringUTF16(IDS_MESSAGE_CENTER_BALLOON_TEXT));
}
} // namespace message_center
......@@ -63,6 +63,11 @@ void StatusIconWin::HandleClickEvent(const gfx::Point& cursor_pos,
ui::MENU_SOURCE_MOUSE, views::MenuRunner::HAS_MNEMONICS));
}
void StatusIconWin::HandleBalloonClickEvent() {
if (HasObservers())
DispatchBalloonClickEvent();
}
void StatusIconWin::ResetIcon() {
NOTIFYICONDATA icon_data;
InitIconData(&icon_data);
......
......@@ -33,6 +33,9 @@ class StatusIconWin : public StatusIcon {
// otherwise displays the context menu if there is one.
void HandleClickEvent(const gfx::Point& cursor_pos, bool left_button_click);
// Handles a click on the balloon from the user.
void HandleBalloonClickEvent();
// Re-creates the status tray icon now after the taskbar has been created.
void ResetIcon();
......
......@@ -4,6 +4,8 @@
#include "chrome/browser/ui/views/status_icons/status_tray_win.h"
#include <commctrl.h>
#include "base/win/wrapped_window_proc.h"
#include "chrome/browser/ui/views/status_icons/status_icon_win.h"
#include "chrome/common/chrome_constants.h"
......@@ -68,22 +70,32 @@ LRESULT CALLBACK StatusTrayWin::WndProc(HWND hwnd,
}
return TRUE;
} else if (message == kStatusIconMessage) {
StatusIconWin* win_icon = NULL;
// Find the selected status icon.
for (StatusIcons::const_iterator i(status_icons().begin());
i != status_icons().end();
++i) {
StatusIconWin* current_win_icon = static_cast<StatusIconWin*>(*i);
if (current_win_icon->icon_id() == wparam) {
win_icon = current_win_icon;
break;
}
}
switch (lparam) {
case TB_INDETERMINATE:
win_icon->HandleBalloonClickEvent();
return TRUE;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_CONTEXTMENU:
// Walk our icons, find which one was clicked on, and invoke its
// HandleClickEvent() method.
for (StatusIcons::const_iterator i(status_icons().begin());
i != status_icons().end(); ++i) {
StatusIconWin* win_icon = static_cast<StatusIconWin*>(*i);
if (win_icon->icon_id() == wparam) {
gfx::Point cursor_pos(
gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN);
break;
}
}
gfx::Point cursor_pos(
gfx::Screen::GetNativeScreen()->GetCursorScreenPoint());
win_icon->HandleClickEvent(cursor_pos, lparam == WM_LBUTTONDOWN);
return TRUE;
}
}
......
......@@ -4,21 +4,34 @@
#include "chrome/browser/ui/views/status_icons/status_tray_win.h"
#include <commctrl.h>
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/status_icons/status_icon_observer.h"
#include "chrome/browser/ui/views/status_icons/status_icon_win.h"
#include "grit/chrome_unscaled_resources.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/base/resource/resource_bundle.h"
class SkBitmap;
class MockStatusIconObserver : public StatusIconObserver {
class FakeStatusIconObserver : public StatusIconObserver {
public:
MOCK_METHOD0(OnStatusIconClicked, void());
FakeStatusIconObserver()
: balloon_clicked_(false),
status_icon_click_count_(0) {}
virtual void OnStatusIconClicked() {
++status_icon_click_count_;
}
virtual void OnBalloonClicked() { balloon_clicked_ = true; }
bool balloon_clicked() const { return balloon_clicked_; }
size_t status_icon_click_count() const {
return status_icon_click_count_;
}
private:
size_t status_icon_click_count_;
bool balloon_clicked_;
};
TEST(StatusTrayWinTest, CreateTray) {
......@@ -46,13 +59,26 @@ TEST(StatusTrayWinTest, ClickOnIcon) {
// Create an icon, send a fake click event, make sure observer is called.
StatusTrayWin tray;
StatusIconWin* icon = static_cast<StatusIconWin*>(tray.CreateStatusIcon());
MockStatusIconObserver observer;
FakeStatusIconObserver observer;
icon->AddObserver(&observer);
EXPECT_CALL(observer, OnStatusIconClicked());
// Mimic a click.
tray.WndProc(NULL, icon->message_id(), icon->icon_id(), WM_LBUTTONDOWN);
// Mimic a right-click - observer should not be called.
tray.WndProc(NULL, icon->message_id(), icon->icon_id(), WM_RBUTTONDOWN);
EXPECT_EQ(1, observer.status_icon_click_count());
icon->RemoveObserver(&observer);
}
TEST(StatusTrayWinTest, ClickOnBalloon) {
// Create an icon, send a fake click event, make sure observer is called.
StatusTrayWin tray;
StatusIconWin* icon = static_cast<StatusIconWin*>(tray.CreateStatusIcon());
FakeStatusIconObserver observer;
icon->AddObserver(&observer);
// Mimic a click.
tray.WndProc(
NULL, icon->message_id(), icon->icon_id(), TB_INDETERMINATE);
EXPECT_TRUE(observer.balloon_clicked());
icon->RemoveObserver(&observer);
}
#endif // !defined(USE_AURA)
......@@ -1203,6 +1203,7 @@
'browser/notifications/fake_balloon_view.h',
'browser/notifications/message_center_notification_manager.cc',
'browser/notifications/message_center_notification_manager.h',
'browser/notifications/message_center_notification_manager_win.cc',
'browser/notifications/message_center_settings_controller.cc',
'browser/notifications/message_center_settings_controller.h',
'browser/notifications/notification.cc',
......
......@@ -1804,6 +1804,7 @@
'browser/ui/views/message_center/notification_bubble_wrapper.cc',
'browser/ui/views/message_center/web_notification_tray.h',
'browser/ui/views/message_center/web_notification_tray.cc',
'browser/ui/views/message_center/web_notification_tray_win.cc',
'browser/ui/views/native_focus_tracker_views.cc',
'browser/ui/views/native_focus_tracker_views.h',
'browser/ui/views/native_focus_tracker_views_aura.cc',
......
......@@ -989,6 +989,7 @@
'browser/net/url_fixer_upper_unittest.cc',
'browser/net/url_info_unittest.cc',
'browser/notifications/desktop_notification_service_unittest.cc',
'browser/notifications/message_center_notifications_unittest_win.cc',
'browser/notifications/notification_audio_controller_unittest.cc',
'browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc',
'browser/notifications/sync_notifier/synced_notification_unittest.cc',
......
......@@ -2164,6 +2164,11 @@ const char kDisableCloudPolicyOnSignin[] =
// Indicates that factory reset was requested from options page.
const char kFactoryResetRequested[] = "FactoryResetRequested";
// Boolean recording whether we have showed a balloon that calls out the message
// center for desktop notifications.
const char kMessageCenterShowedFirstRunBalloon[] =
"message_center.showed_first_run_balloon";
// *************** SERVICE PREFS ***************
// These are attached to the service process.
......
......@@ -833,6 +833,8 @@ extern const char kDisableCloudPolicyOnSignin[];
extern const char kFactoryResetRequested[];
extern const char kMessageCenterShowedFirstRunBalloon[];
extern const char kRecoveryComponentVersion[];
extern const char kComponentUpdaterState[];
......
......@@ -492,6 +492,9 @@ const char kLearnMoreEnterpriseURL[] =
"https://support.google.com/chromeos/bin/answer.py?answer=2535613";
#endif
const char kNotificationsHelpURL[] =
"https://support.google.com/chrome/?p=ui_notifications";
const char* const kChromeDebugURLs[] = {
content::kChromeUICrashURL,
content::kChromeUIKillURL,
......
......@@ -403,6 +403,8 @@ extern const char kNaturalScrollHelpURL[];
extern const char kLearnMoreEnterpriseURL[];
#endif
extern const char kNotificationsHelpURL[];
// "Debug" pages which are dangerous and not for general consumption.
extern const char* const kChromeDebugURLs[];
extern const int kNumberOfChromeDebugURLs;
......
......@@ -38,6 +38,10 @@ class MESSAGE_CENTER_EXPORT MessageCenterTrayDelegate {
// Display the notifier settings as a bubble.
virtual bool ShowNotifierSettings() = 0;
// Show a platform-specific UI that informs the user how to open the message
// center.
virtual void DisplayFirstRunBalloon() {};
};
} // namespace message_center
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment