summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ui/message_center/cocoa/settings_controller.h11
-rw-r--r--ui/message_center/cocoa/settings_controller.mm51
-rw-r--r--ui/message_center/cocoa/settings_controller_unittest.mm33
-rw-r--r--ui/message_center/cocoa/tray_controller.mm13
-rw-r--r--ui/message_center/cocoa/tray_view_controller.h10
-rw-r--r--ui/message_center/cocoa/tray_view_controller.mm103
-rw-r--r--ui/message_center/cocoa/tray_view_controller_unittest.mm62
-rw-r--r--ui/message_center/fake_notifier_settings_provider.cc39
-rw-r--r--ui/message_center/fake_notifier_settings_provider.h37
-rw-r--r--ui/message_center/message_center.gyp2
-rw-r--r--ui/resources/ui_resources.grd3
11 files changed, 296 insertions, 68 deletions
diff --git a/ui/message_center/cocoa/settings_controller.h b/ui/message_center/cocoa/settings_controller.h
index a802ad4..976172c 100644
--- a/ui/message_center/cocoa/settings_controller.h
+++ b/ui/message_center/cocoa/settings_controller.h
@@ -12,6 +12,7 @@
#include "ui/message_center/message_center_export.h"
#include "ui/message_center/notifier_settings.h"
+@class HoverImageButton;
@class MCSettingsController;
namespace message_center {
@@ -46,6 +47,9 @@ MESSAGE_CENTER_EXPORT
scoped_ptr<message_center::NotifierSettingsDelegateMac> delegate_;
message_center::NotifierSettingsProvider* provider_;
+ // The back button at the top.
+ scoped_nsobject<HoverImageButton> backButton_;
+
// The "Settings" text at the top.
scoped_nsobject<NSTextField> settingsText_;
@@ -64,6 +68,13 @@ MESSAGE_CENTER_EXPORT
// Returns the bridge object for this controller.
- (message_center::NotifierSettingsDelegateMac*)delegate;
+// Returns a view that should be initial first responder.
+- (NSView*)responderView;
+
+// Set up the close target and action.
+- (void)setCloseTarget:(id)target;
+- (void)setCloseAction:(SEL)action;
+
@end
// Testing API /////////////////////////////////////////////////////////////////
diff --git a/ui/message_center/cocoa/settings_controller.mm b/ui/message_center/cocoa/settings_controller.mm
index b5892ab..f1c4a35 100644
--- a/ui/message_center/cocoa/settings_controller.mm
+++ b/ui/message_center/cocoa/settings_controller.mm
@@ -5,13 +5,17 @@
#import "ui/message_center/cocoa/settings_controller.h"
#include "base/strings/sys_string_conversions.h"
+#include "grit/ui_resources.h"
#include "grit/ui_strings.h"
+#import "ui/base/cocoa/hover_image_button.h"
#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
#import "base/memory/scoped_nsobject.h"
#import "ui/message_center/cocoa/tray_view_controller.h"
#include "ui/message_center/message_center_style.h"
#include "skia/ext/skia_utils_mac.h"
+const int kBackButtonSize = 32;
const int kMarginWidth = 16;
const int kEntryHeight = 32;
@@ -50,6 +54,11 @@ NotifierSettingsDelegate* ShowSettings(NotifierSettingsProvider* provider,
return self;
}
+- (void)dealloc {
+ provider_->OnNotifierSettingsClosing();
+ [super dealloc];
+}
+
- (NSTextField*)newLabelWithFrame:(NSRect)frame {
NSTextField* label = [[NSTextField alloc] initWithFrame:frame];
[label setDrawsBackground:NO];
@@ -66,7 +75,7 @@ NotifierSettingsDelegate* ShowSettings(NotifierSettingsProvider* provider,
// Container view.
NSRect fullFrame =
- NSMakeRect(0, 0, message_center::kNotificationWidth, maxHeight);
+ NSMakeRect(0, 0, [MCTrayViewController trayWidth], maxHeight);
scoped_nsobject<NSBox> view([[NSBox alloc] initWithFrame:fullFrame]);
[view setBorderType:NSNoBorder];
[view setBoxType:NSBoxCustom];
@@ -76,9 +85,27 @@ NotifierSettingsDelegate* ShowSettings(NotifierSettingsProvider* provider,
[view setTitlePosition:NSNoTitle];
[self setView:view];
+ // Back button.
+ NSRect backButtonFrame = NSMakeRect(
+ kMarginWidth, kMarginWidth, kBackButtonSize, kBackButtonSize);
+ backButton_.reset([[HoverImageButton alloc] initWithFrame:backButtonFrame]);
+ ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
+ [backButton_ setDefaultImage:
+ rb.GetNativeImageNamed(IDR_NOTIFICATION_ARROW).ToNSImage()];
+ [backButton_ setHoverImage:
+ rb.GetNativeImageNamed(IDR_NOTIFICATION_ARROW_HOVER).ToNSImage()];
+ [backButton_ setPressedImage:
+ rb.GetNativeImageNamed(IDR_NOTIFICATION_ARROW_PRESSED).ToNSImage()];
+ [[backButton_ cell] setHighlightsBy:NSOnState];
+ [backButton_ setBordered:NO];
+ [backButton_ setAutoresizingMask:NSViewMinYMargin];
+ [[self view] addSubview:backButton_];
+
// "Settings" text.
- NSRect headerFrame = NSMakeRect(
- kMarginWidth, kMarginWidth, NSWidth(fullFrame), NSHeight(fullFrame));
+ NSRect headerFrame = NSMakeRect(NSMaxX(backButtonFrame),
+ kMarginWidth,
+ NSWidth(fullFrame) - NSMaxX(backButtonFrame),
+ NSHeight(fullFrame));
settingsText_.reset([self newLabelWithFrame:headerFrame]);
[settingsText_ setAutoresizingMask:NSViewMinYMargin];
[settingsText_ setTextColor:gfx::SkColorToCalibratedNSColor(
@@ -94,6 +121,10 @@ NotifierSettingsDelegate* ShowSettings(NotifierSettingsProvider* provider,
NSMaxY(fullFrame) - kMarginWidth - NSHeight(headerFrame);
[[self view] addSubview:settingsText_];
+ // Vertically center back button with "Settings" text.
+ backButtonFrame.origin.y =
+ NSMidY(headerFrame) - NSHeight(backButtonFrame) / 2;
+
// Subheader.
NSRect subheaderFrame = NSMakeRect(
kMarginWidth, kMarginWidth, NSWidth(fullFrame), NSHeight(fullFrame));
@@ -151,6 +182,7 @@ NotifierSettingsDelegate* ShowSettings(NotifierSettingsProvider* provider,
// Everything fits without scrolling.
CGFloat delta = remainingHeight - NSHeight(documentFrame);
headerFrame.origin.y -= delta;
+ backButtonFrame.origin.y -= delta;
subheaderFrame.origin.y -= delta;
fullFrame.size.height -= delta;
} else {
@@ -168,6 +200,7 @@ NotifierSettingsDelegate* ShowSettings(NotifierSettingsProvider* provider,
// Set final sizes.
[[self view] setFrame:fullFrame];
[[self view] addSubview:scrollView_];
+ [backButton_ setFrame:backButtonFrame];
[settingsText_ setFrame:headerFrame];
[detailsText_ setFrame:subheaderFrame];
}
@@ -181,6 +214,18 @@ NotifierSettingsDelegate* ShowSettings(NotifierSettingsProvider* provider,
return delegate_.get();
}
+- (NSView*)responderView {
+ return backButton_;
+}
+
+- (void)setCloseTarget:(id)target {
+ [backButton_ setTarget:target];
+}
+
+- (void)setCloseAction:(SEL)action {
+ [backButton_ setAction:action];
+}
+
// Testing API /////////////////////////////////////////////////////////////////
- (NSScrollView*)scrollView {
diff --git a/ui/message_center/cocoa/settings_controller_unittest.mm b/ui/message_center/cocoa/settings_controller_unittest.mm
index b9df383..037953c 100644
--- a/ui/message_center/cocoa/settings_controller_unittest.mm
+++ b/ui/message_center/cocoa/settings_controller_unittest.mm
@@ -7,6 +7,7 @@
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#import "ui/base/test/ui_cocoa_test_helper.h"
+#include "ui/message_center/fake_notifier_settings_provider.h"
@implementation MCSettingsController (TestingInterface)
- (NSUInteger)scrollViewItemCount {
@@ -26,34 +27,6 @@ using ui::CocoaTest;
namespace {
-class FakeNotifierSettingsProvider : public NotifierSettingsProvider {
- public:
- FakeNotifierSettingsProvider(
- const std::vector<Notifier*>& notifiers)
- : notifiers_(notifiers) {}
-
- virtual void GetNotifierList(
- std::vector<Notifier*>* notifiers) OVERRIDE {
- notifiers->clear();
- for (Notifier* notifier : notifiers_)
- notifiers->push_back(notifier);
- }
-
- virtual void SetNotifierEnabled(const Notifier& notifier,
- bool enabled) OVERRIDE {
- enabled_[&notifier] = enabled;
- }
- virtual void OnNotifierSettingsClosing() OVERRIDE {}
-
- bool WasEnabled(const Notifier& notifier) {
- return enabled_[&notifier];
- }
-
- private:
- std::vector<Notifier*> notifiers_;
- std::map<const Notifier*, bool> enabled_;
-};
-
Notifier* NewNotifier(const std::string& id,
const std::string& title,
bool enabled) {
@@ -97,6 +70,10 @@ TEST_F(CocoaTest, Toggle) {
[toggleSecond performClick:nil];
EXPECT_FALSE(provider.WasEnabled(*notifiers.back()));
+ EXPECT_EQ(0, provider.closed_called_count());
+ controller.reset();
+ EXPECT_EQ(1, provider.closed_called_count());
+
STLDeleteElements(&notifiers);
}
diff --git a/ui/message_center/cocoa/tray_controller.mm b/ui/message_center/cocoa/tray_controller.mm
index d8a986e..1e14aae 100644
--- a/ui/message_center/cocoa/tray_controller.mm
+++ b/ui/message_center/cocoa/tray_controller.mm
@@ -68,18 +68,15 @@
}
- (void)onMessageCenterTrayChanged {
- CGFloat oldHeight = NSHeight([[viewController_ view] frame]);
[viewController_ onMessageCenterTrayChanged];
- CGFloat newHeight = NSHeight([[viewController_ view] frame]);
-
- NSRect windowFrame = [[self window] frame];
- CGFloat delta = newHeight - oldHeight;
- windowFrame.origin.y -= delta;
- windowFrame.size.height += delta;
- [[self window] setFrame:windowFrame display:YES];
}
- (void)windowDidResignKey:(NSNotification*)notification {
+ // The settings bubble data structures assume that the settings dialog is
+ // visible only for short periods of time: There's a fixed list of permissions
+ // for example.
+ [viewController_ hideSettings:self];
+
tray_->HideMessageCenterBubble();
}
diff --git a/ui/message_center/cocoa/tray_view_controller.h b/ui/message_center/cocoa/tray_view_controller.h
index 422db78..3c02360 100644
--- a/ui/message_center/cocoa/tray_view_controller.h
+++ b/ui/message_center/cocoa/tray_view_controller.h
@@ -15,6 +15,7 @@
@class HoverImageButton;
@class MCNotificationController;
+@class MCSettingsController;
namespace message_center {
class MessageCenter;
@@ -52,6 +53,9 @@ MESSAGE_CENTER_EXPORT
// Used to animate multiple notifications simultaneously when they're being
// removed or repositioned.
scoped_nsobject<NSViewAnimation> animation_;
+
+ // The controller of the settings view. Only set while the view is open.
+ scoped_nsobject<MCSettingsController> settingsController_;
}
// Designated initializer.
@@ -69,12 +73,18 @@ MESSAGE_CENTER_EXPORT
// Action for the settings button.
- (void)showSettings:(id)sender;
+// Hides the settings dialog if it's open.
+- (void)hideSettings:(id)sender;
+
// Scroll to the topmost notification in the tray.
- (void)scrollToTop;
// Returns the maximum height of the notifications tray.
+ (CGFloat)maxTrayHeight;
+// Returns the width of the notifications tray.
++ (CGFloat)trayWidth;
+
@end
// Testing API /////////////////////////////////////////////////////////////////
diff --git a/ui/message_center/cocoa/tray_view_controller.mm b/ui/message_center/cocoa/tray_view_controller.mm
index ef50566..c344dc9 100644
--- a/ui/message_center/cocoa/tray_view_controller.mm
+++ b/ui/message_center/cocoa/tray_view_controller.mm
@@ -6,6 +6,7 @@
#include <cmath>
+#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/time.h"
#include "grit/ui_resources.h"
#include "grit/ui_strings.h"
@@ -22,8 +23,8 @@
// Creates all the views for the control area of the tray.
- (void)layoutControlArea;
-// Update the tray view by resizing it to fit its content.
-- (void)updateTrayView;
+// Update both tray view and window by resizing it to fit its content.
+- (void)updateTrayViewAndWindow;
// Remove notifications dismissed by the user. It is done in the following
// 3 steps.
@@ -39,6 +40,9 @@
// Step 3: finalize the tray view and window to get rid of the empty space.
- (void)finalizeTrayViewAndWindow;
+// Informs the window controller that it should update the window's size based
+// on the size of the tray view.
+- (void)forceWindowSizeUpdate;
@end
namespace {
@@ -72,11 +76,8 @@ const CGFloat kTrayBottomMargin = 75;
- (void)loadView {
// Configure the root view as a background-colored box.
- scoped_nsobject<NSBox> view([[NSBox alloc] initWithFrame:
- NSMakeRect(0, 0,
- message_center::kNotificationWidth +
- 2 * message_center::kMarginBetweenItems,
- kControlAreaHeight)]);
+ scoped_nsobject<NSBox> view([[NSBox alloc] initWithFrame:NSMakeRect(
+ 0, 0, [MCTrayViewController trayWidth], kControlAreaHeight)]);
[view setBorderType:NSNoBorder];
[view setBoxType:NSBoxCustom];
[view setContentViewMargins:NSZeroSize];
@@ -105,6 +106,9 @@ const CGFloat kTrayBottomMargin = 75;
}
- (void)onMessageCenterTrayChanged {
+ if (settingsController_)
+ return [self updateTrayViewAndWindow];
+
// When the window is visible, the only update is to remove notifications
// dismissed by the user.
if ([[[self view] window] isVisible]) {
@@ -172,7 +176,7 @@ const CGFloat kTrayBottomMargin = 75;
// Copy the new map of notifications to replace the old.
notificationsMap_ = newMap;
- [self updateTrayView];
+ [self updateTrayViewAndWindow];
}
- (void)toggleQuietMode:(id)sender {
@@ -195,14 +199,42 @@ const CGFloat kTrayBottomMargin = 75;
}
- (void)showSettings:(id)sender {
- // This ends up calling message_center::ShowSettings() and will set up the
- // NotifierSettingsProvider along the way.
- message_center::NotifierSettingsDelegateMac* delegate =
- static_cast<message_center::NotifierSettingsDelegateMac*>(
- messageCenter_->ShowNotificationSettingsDialog([self view]));
- // TODO(thakis): retain delegate->cocoa_controller(), install the controller's
- // view.
- (void)delegate;
+ if (settingsController_) {
+ NOTREACHED();
+ return [self hideSettings:sender];
+ }
+
+ {
+ // ShowNotificationSettingsDialog() returns an object owned by an
+ // autoreleased controller. Use a local autorelease pool to make sure this
+ // controller doesn't outlive self if self destroyed before the runloop
+ // flushes autoreleased objects (for example, in tests).
+ base::mac::ScopedNSAutoreleasePool pool;
+ // This ends up calling message_center::ShowSettings() and will set up the
+ // NotifierSettingsProvider along the way.
+ message_center::NotifierSettingsDelegateMac* delegate =
+ static_cast<message_center::NotifierSettingsDelegateMac*>(
+ messageCenter_->ShowNotificationSettingsDialog([self view]));
+ settingsController_.reset([delegate->cocoa_controller() retain]);
+ }
+
+ [[self view] addSubview:[settingsController_ view]];
+
+ [settingsController_ setCloseTarget:self];
+ [settingsController_ setCloseAction:@selector(hideSettings:)];
+
+ [[[self view] window] recalculateKeyViewLoop];
+ [[[self view] window] makeFirstResponder:[settingsController_ responderView]];
+
+ [self forceWindowSizeUpdate];
+}
+
+- (void)hideSettings:(id)sender {
+ [[settingsController_ view] removeFromSuperview];
+ settingsController_.reset();
+ [[[self view] window] recalculateKeyViewLoop];
+ [[[self view] window] makeFirstResponder:pauseButton_];
+ [self forceWindowSizeUpdate];
}
- (void)scrollToTop {
@@ -216,6 +248,11 @@ const CGFloat kTrayBottomMargin = 75;
return NSHeight(screenFrame) - kTrayBottomMargin;
}
++ (CGFloat)trayWidth {
+ return message_center::kNotificationWidth +
+ 2 * message_center::kMarginBetweenItems;
+}
+
// Testing API /////////////////////////////////////////////////////////////////
- (NSScrollView*)scrollView {
@@ -343,7 +380,7 @@ const CGFloat kTrayBottomMargin = 75;
[view addSubview:pauseButton_];
}
-- (void)updateTrayView {
+- (void)updateTrayViewAndWindow {
CGFloat scrollContentHeight = 0;
if ([notifications_ count]) {
scrollContentHeight = NSMaxY([[[notifications_ lastObject] view] frame]) +
@@ -359,14 +396,27 @@ const CGFloat kTrayBottomMargin = 75;
// Resize the container view.
NSRect frame = [[self view] frame];
- frame.size.height = std::min([MCTrayViewController maxTrayHeight],
- scrollContentHeight + kControlAreaHeight);
+ CGFloat oldHeight = NSHeight(frame);
+ if (settingsController_) {
+ frame.size.height = NSHeight([[settingsController_ view] frame]);
+ } else {
+ frame.size.height = std::min([MCTrayViewController maxTrayHeight],
+ scrollContentHeight + kControlAreaHeight);
+ }
+ CGFloat newHeight = NSHeight(frame);
[[self view] setFrame:frame];
// Resize the scroll view.
scrollViewFrame.size.height = NSHeight(frame) - kControlAreaHeight;
[scrollView_ setFrame:scrollViewFrame];
+ // Resize the window.
+ NSRect windowFrame = [[[self view] window] frame];
+ CGFloat delta = newHeight - oldHeight;
+ windowFrame.origin.y -= delta;
+ windowFrame.size.height += delta;
+
+ [[[self view] window] setFrame:windowFrame display:YES];
// Hide the clear-all button if there are no notifications. Simply swap the
// X position of it and the pause button in that case.
BOOL hidden = ![notifications_ count];
@@ -481,19 +531,14 @@ const CGFloat kTrayBottomMargin = 75;
minY = NSMaxY(frame) + message_center::kMarginBetweenItems;
}
- CGFloat oldHeight = NSHeight([[self view] frame]);
- [self updateTrayView];
- CGFloat newHeight = NSHeight([[self view] frame]);
-
- // Resize the window.
- NSRect windowFrame = [[[self view] window] frame];
- CGFloat delta = newHeight - oldHeight;
- windowFrame.origin.y -= delta;
- windowFrame.size.height += delta;
- [[[self view] window] setFrame:windowFrame display:YES];
+ [self updateTrayViewAndWindow];
// Check if there're more notifications pending removal.
[self closeNotificationsByUser];
}
+- (void)forceWindowSizeUpdate {
+ [self updateTrayViewAndWindow];
+}
+
@end
diff --git a/ui/message_center/cocoa/tray_view_controller_unittest.mm b/ui/message_center/cocoa/tray_view_controller_unittest.mm
index 366d4d3..0ff114d 100644
--- a/ui/message_center/cocoa/tray_view_controller_unittest.mm
+++ b/ui/message_center/cocoa/tray_view_controller_unittest.mm
@@ -7,10 +7,12 @@
#include "base/memory/scoped_nsobject.h"
#include "base/strings/utf_string_conversions.h"
#import "ui/base/test/ui_cocoa_test_helper.h"
+#include "ui/message_center/fake_notifier_settings_provider.h"
#include "ui/message_center/message_center.h"
#include "ui/message_center/message_center_impl.h"
#include "ui/message_center/message_center_style.h"
#include "ui/message_center/notification.h"
+#include "ui/message_center/notifier_settings.h"
class TrayViewControllerTest : public ui::CocoaTest {
public:
@@ -171,3 +173,63 @@ TEST_F(TrayViewControllerTest, NoClearAllWhenNoNotifications) {
EXPECT_LT(NSMinX([[tray_ clearAllButton] frame]),
NSMinX([[tray_ pauseButton] frame]));
}
+
+namespace message_center {
+
+namespace {
+
+class FakeDelegate : public MessageCenter::Delegate {
+ public:
+ FakeDelegate(NotifierSettingsProvider* provider) : provider_(provider) {}
+
+ virtual NotifierSettingsDelegate* ShowSettingsDialog(
+ gfx::NativeView context) OVERRIDE {
+ return message_center::ShowSettings(provider_, context);
+ }
+
+ virtual void DisableExtension(const std::string& notification_id) OVERRIDE {}
+ virtual void DisableNotificationsFromSource(
+ const std::string& notification_id) OVERRIDE {}
+ virtual void ShowSettings(const std::string& notification_id) OVERRIDE {}
+
+
+
+ NotifierSettingsProvider* provider_;
+};
+
+Notifier* NewNotifier(const std::string& id,
+ const std::string& title,
+ bool enabled) {
+ return new Notifier(id, base::UTF8ToUTF16(title), enabled);
+}
+
+} // namespace
+
+
+TEST_F(TrayViewControllerTest, Settings) {
+ std::vector<Notifier*> notifiers;
+ notifiers.push_back(NewNotifier("id", "title", /*enabled=*/true));
+ notifiers.push_back(NewNotifier("id2", "other title", /*enabled=*/false));
+
+ FakeNotifierSettingsProvider provider(notifiers);
+ FakeDelegate delegate(&provider);
+
+ center_->SetDelegate(&delegate);
+
+ CGFloat trayHeight = NSHeight([[tray_ view] frame]);
+ EXPECT_EQ(0, provider.closed_called_count());
+
+ [tray_ showSettings:nil];
+
+ // There are 0 notifications, but 2 notifiers. The settings pane should be
+ // higher than the empty tray bubble.
+ EXPECT_LT(trayHeight, NSHeight([[tray_ view] frame]));
+
+ [tray_ hideSettings:nil];
+ EXPECT_EQ(1, provider.closed_called_count());
+
+ // The tray should be back at its previous height now.
+ EXPECT_EQ(trayHeight, NSHeight([[tray_ view] frame]));
+}
+
+} // namespace message_center
diff --git a/ui/message_center/fake_notifier_settings_provider.cc b/ui/message_center/fake_notifier_settings_provider.cc
new file mode 100644
index 0000000..20493a2
--- /dev/null
+++ b/ui/message_center/fake_notifier_settings_provider.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 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 "ui/message_center/fake_notifier_settings_provider.h"
+
+namespace message_center {
+
+FakeNotifierSettingsProvider::FakeNotifierSettingsProvider(
+ const std::vector<Notifier*>& notifiers)
+ : notifiers_(notifiers), closed_called_count_(0) {}
+
+FakeNotifierSettingsProvider::~FakeNotifierSettingsProvider() {}
+
+void FakeNotifierSettingsProvider::GetNotifierList(
+ std::vector<Notifier*>* notifiers) {
+ notifiers->clear();
+ for (size_t i = 0; i < notifiers_.size(); ++i)
+ notifiers->push_back(notifiers_[i]);
+}
+
+void FakeNotifierSettingsProvider::SetNotifierEnabled(const Notifier& notifier,
+ bool enabled) {
+ enabled_[&notifier] = enabled;
+}
+
+void FakeNotifierSettingsProvider::OnNotifierSettingsClosing() {
+ closed_called_count_++;
+}
+
+bool FakeNotifierSettingsProvider::WasEnabled(const Notifier& notifier) {
+ return enabled_[&notifier];
+}
+
+int FakeNotifierSettingsProvider::closed_called_count() {
+ return closed_called_count_;
+}
+
+} // namespace message_center
diff --git a/ui/message_center/fake_notifier_settings_provider.h b/ui/message_center/fake_notifier_settings_provider.h
new file mode 100644
index 0000000..6ce8baa
--- /dev/null
+++ b/ui/message_center/fake_notifier_settings_provider.h
@@ -0,0 +1,37 @@
+// Copyright (c) 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.
+
+#ifndef UI_MESSAGE_CENTER_FAKE_NOTIFIER_SETTINGS_PROVIDER_H_
+#define UI_MESSAGE_CENTER_FAKE_NOTIFIER_SETTINGS_PROVIDER_H_
+
+#include "ui/message_center/notifier_settings.h"
+
+namespace message_center {
+
+// A NotifierSettingsProvider that returns a configurable, fixed set of
+// notifiers and records which callbacks were called. For use in tests.
+class FakeNotifierSettingsProvider : public NotifierSettingsProvider {
+ public:
+ FakeNotifierSettingsProvider(const std::vector<Notifier*>& notifiers);
+ ~FakeNotifierSettingsProvider();
+
+ virtual void GetNotifierList(std::vector<Notifier*>* notifiers) OVERRIDE;
+
+ virtual void SetNotifierEnabled(const Notifier& notifier,
+ bool enabled) OVERRIDE;
+
+ virtual void OnNotifierSettingsClosing() OVERRIDE;
+
+ bool WasEnabled(const Notifier& notifier);
+ int closed_called_count();
+
+ private:
+ std::vector<Notifier*> notifiers_;
+ std::map<const Notifier*, bool> enabled_;
+ int closed_called_count_;
+};
+
+} // namespace message_center
+
+#endif // UI_MESSAGE_CENTER_FAKE_NOTIFIER_SETTINGS_PROVIDER_H_
diff --git a/ui/message_center/message_center.gyp b/ui/message_center/message_center.gyp
index 81de349..ee469d2 100644
--- a/ui/message_center/message_center.gyp
+++ b/ui/message_center/message_center.gyp
@@ -148,6 +148,8 @@
'message_center_impl_unittest.cc',
'fake_message_center.h',
'fake_message_center.cc',
+ 'fake_notifier_settings_provider.h',
+ 'fake_notifier_settings_provider.cc',
'notification_list_unittest.cc',
'test/run_all_unittests.cc',
],
diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd
index e36b8aa..53bbaf7 100644
--- a/ui/resources/ui_resources.grd
+++ b/ui/resources/ui_resources.grd
@@ -336,6 +336,9 @@
<structure type="chrome_scaled_image" name="IDR_MINIMIZE_H" file="minimize_hover.png" />
<structure type="chrome_scaled_image" name="IDR_MINIMIZE_P" file="minimize_pressed.png" />
</if>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ARROW" file="common/notification_arrow.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ARROW_HOVER" file="common/notification_arrow_hover.png"/>
+ <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_ARROW_PRESSED" file="common/notification_arrow_pressed.png"/>
<structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL" file="common/notification_clear_all.png"/>
<structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL_HOVER" file="common/notification_clear_all_hover.png"/>
<structure type="chrome_scaled_image" name="IDR_NOTIFICATION_CLEAR_ALL_PRESSED" file="common/notification_clear_all_pressed.png"/>