Commit ba2c8624 authored by dconnelly's avatar dconnelly Committed by Commit bot

Add ManagePasswordsBubbleCocoa and unit tests.

BUG=328847

Review URL: https://codereview.chromium.org/441683002

Cr-Commit-Position: refs/heads/master@{#291667}
parent 029d24a9
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "chrome/app/chrome_command_ids.h" #include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/command_updater.h" #include "chrome/browser/command_updater.h"
#include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h" #include "chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.h"
#include "chrome/browser/ui/cocoa/passwords/manage_passwords_bubble_cocoa.h"
#include "ui/base/l10n/l10n_util_mac.h" #include "ui/base/l10n/l10n_util_mac.h"
// ManagePasswordsIconCocoa // ManagePasswordsIconCocoa
...@@ -58,7 +59,8 @@ void ManagePasswordsDecoration::UpdateVisibleUI() { ...@@ -58,7 +59,8 @@ void ManagePasswordsDecoration::UpdateVisibleUI() {
if (icon_->state() == password_manager::ui::INACTIVE_STATE) { if (icon_->state() == password_manager::ui::INACTIVE_STATE) {
SetVisible(false); SetVisible(false);
SetImage(nil); SetImage(nil);
// TODO(dconnelly): Hide the bubble once it is implemented. if (ManagePasswordsBubbleCocoa::instance())
ManagePasswordsBubbleCocoa::instance()->Close();
return; return;
} }
SetVisible(true); SetVisible(true);
......
// Copyright 2014 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 CHROME_BROWSER_UI_COCOA_PASSWORDS_MANAGE_PASSWORDS_BUBBLE_COCOA_H_
#define CHROME_BROWSER_UI_COCOA_PASSWORDS_MANAGE_PASSWORDS_BUBBLE_COCOA_H_
#import <Cocoa/Cocoa.h>
#include "base/mac/scoped_nsobject.h"
#import "chrome/browser/ui/passwords/manage_passwords_bubble.h"
namespace content {
class WebContents;
}
@class ManagePasswordsBubbleController;
@class ManagePasswordsBubbleCocoaNotificationBridge;
// Cocoa implementation of the platform-independent password bubble interface.
class ManagePasswordsBubbleCocoa : public ManagePasswordsBubble {
public:
// Creates and shows the bubble, which owns itself. Does nothing if the bubble
// is already shown.
static void ShowBubble(content::WebContents* webContents,
DisplayReason displayReason);
// Closes and deletes the bubble.
void Close();
// Accessor for the global bubble.
static ManagePasswordsBubbleCocoa* instance() { return bubble_; }
private:
friend class ManagePasswordsBubbleCocoaTest;
// Instance-specific logic. Clients should use the static interface.
ManagePasswordsBubbleCocoa(content::WebContents* webContents,
DisplayReason displayReason);
virtual ~ManagePasswordsBubbleCocoa();
void Show();
// Cleans up state and deletes itself. Called when the bubble is closed.
void OnClose();
// Whether there is currently a close operation taking place. Prevents
// multiple attempts to close the window.
bool closing_;
// The view controller for the bubble. Weak; owns itself. Must be nilled
// after the bubble is closed.
ManagePasswordsBubbleController* controller_;
// WebContents on which the bubble should be displayed. Weak.
content::WebContents* webContents_;
// Listens for NSNotificationCenter notifications.
base::scoped_nsobject<ManagePasswordsBubbleCocoaNotificationBridge> bridge_;
// The global bubble instance. Deleted by Close().
static ManagePasswordsBubbleCocoa* bubble_;
DISALLOW_COPY_AND_ASSIGN(ManagePasswordsBubbleCocoa);
};
#endif // CHROME_BROWSER_UI_COCOA_PASSWORDS_MANAGE_PASSWORDS_BUBBLE_COCOA_H_
// Copyright 2014 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.
#import "chrome/browser/ui/cocoa/passwords/manage_passwords_bubble_cocoa.h"
#include "base/mac/scoped_block.h"
#include "chrome/browser/ui/browser_dialogs.h"
#include "chrome/browser/ui/browser_finder.h"
#import "chrome/browser/ui/cocoa/passwords/manage_passwords_bubble_controller.h"
#include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
#include "content/public/browser/web_contents.h"
typedef void (^Callback)(void);
@interface ManagePasswordsBubbleCocoaNotificationBridge : NSObject {
base::mac::ScopedBlock<Callback> callback_;
}
- (id)initWithCallback:(Callback)callback;
- (void)onClose;
@end
@implementation ManagePasswordsBubbleCocoaNotificationBridge
- (id)initWithCallback:(Callback)callback {
if ((self = [super init])) {
callback_.reset(callback, base::scoped_policy::RETAIN);
}
return self;
}
- (void)onClose {
callback_.get()();
}
@end
// static
ManagePasswordsBubbleCocoa* ManagePasswordsBubbleCocoa::bubble_ = NULL;
ManagePasswordsBubbleCocoa::ManagePasswordsBubbleCocoa(
content::WebContents* webContents,
DisplayReason displayReason)
: ManagePasswordsBubble(webContents, displayReason),
closing_(false),
controller_(nil),
webContents_(webContents),
bridge_(nil) {
}
ManagePasswordsBubbleCocoa::~ManagePasswordsBubbleCocoa() {
[[NSNotificationCenter defaultCenter] removeObserver:bridge_];
// Clear the global instance pointer.
bubble_ = NULL;
}
void ManagePasswordsBubbleCocoa::Show() {
// Create and show the bubble.
NSView* browserView = webContents_->GetNativeView();
DCHECK(browserView);
NSWindow* browserWindow = [browserView window];
DCHECK(browserWindow);
controller_ = [[ManagePasswordsBubbleController alloc]
initWithParentWindow:browserWindow
model:model()];
[controller_ showWindow:nil];
// Listen for close notification to perform cleanup: the window isn't
// necessarily closed by calling Close(). Use a block instead of directly
// calling OnClose from the bridge so that we don't need to expose OnClose
// in the public API of ManagePasswordsBubbleCocoa.
bridge_.reset([[ManagePasswordsBubbleCocoaNotificationBridge alloc]
initWithCallback:^{
OnClose();
}]);
[[NSNotificationCenter defaultCenter]
addObserver:bridge_
selector:@selector(onClose)
name:NSWindowWillCloseNotification
object:[controller_ window]];
}
void ManagePasswordsBubbleCocoa::Close() {
if (!closing_) {
closing_ = true;
[controller_ close];
}
}
void ManagePasswordsBubbleCocoa::OnClose() {
delete this;
}
// static
void ManagePasswordsBubbleCocoa::ShowBubble(content::WebContents* webContents,
DisplayReason displayReason) {
if (bubble_)
return;
bubble_ = new ManagePasswordsBubbleCocoa(webContents, displayReason);
bubble_->Show();
}
// Copyright 2014 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/cocoa/passwords/manage_passwords_bubble_cocoa.h"
#import <Cocoa/Cocoa.h>
#include "base/compiler_specific.h"
#include "base/mac/foundation_util.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/cocoa/cocoa_profile_test.h"
#include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
#import "chrome/browser/ui/cocoa/info_bubble_window.h"
#import "chrome/browser/ui/cocoa/passwords/manage_passwords_bubble_controller.h"
#include "chrome/browser/ui/passwords/manage_passwords_bubble.h"
#include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "content/public/browser/site_instance.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
#include "testing/platform_test.h"
class ManagePasswordsBubbleCocoaTest : public CocoaProfileTest {
public:
virtual void SetUp() OVERRIDE {
CocoaProfileTest::SetUp();
// Create the WebContents.
siteInstance_ = content::SiteInstance::Create(profile());
webContents_ = content::WebContents::Create(
content::WebContents::CreateParams(profile(), siteInstance_.get()));
browser()->tab_strip_model()->AppendWebContents(
webContents_, /*foreground=*/true);
// Create the test UIController here so that it's bound to
// |test_web_contents_| and therefore accessible to the model.
new ManagePasswordsUIControllerMock(webContents_);
}
content::WebContents* webContents() { return webContents_; }
void ShowBubble() {
ManagePasswordsBubbleCocoa::ShowBubble(
webContents(), ManagePasswordsBubble::DisplayReason::AUTOMATIC);
// Disable animations so that closing happens immediately.
InfoBubbleWindow* window = base::mac::ObjCCast<InfoBubbleWindow>(
[ManagePasswordsBubbleCocoa::instance()->controller_ window]);
[window setAllowedAnimations:info_bubble::kAnimateNone];
}
void CloseBubble() {
ManagePasswordsBubbleCocoa::instance()->Close();
}
NSWindow* bubbleWindow() {
ManagePasswordsBubbleCocoa* bubble = ManagePasswordsBubbleCocoa::instance();
return bubble ? [bubble->controller_ window] : nil;
}
private:
scoped_refptr<content::SiteInstance> siteInstance_;
content::WebContents* webContents_; // weak
};
TEST_F(ManagePasswordsBubbleCocoaTest, ShowShouldCreateAndShowBubble) {
EXPECT_FALSE(ManagePasswordsBubbleCocoa::instance());
EXPECT_FALSE([bubbleWindow() isVisible]);
ShowBubble();
EXPECT_TRUE(ManagePasswordsBubbleCocoa::instance());
EXPECT_TRUE([bubbleWindow() isVisible]);
}
TEST_F(ManagePasswordsBubbleCocoaTest, CloseShouldCloseAndDeleteBubble) {
ShowBubble();
EXPECT_TRUE(ManagePasswordsBubbleCocoa::instance());
EXPECT_TRUE([bubbleWindow() isVisible]);
CloseBubble();
EXPECT_FALSE(ManagePasswordsBubbleCocoa::instance());
EXPECT_FALSE([bubbleWindow() isVisible]);
}
TEST_F(ManagePasswordsBubbleCocoaTest, BackgroundCloseShouldDeleteBubble) {
ShowBubble();
EXPECT_TRUE(ManagePasswordsBubbleCocoa::instance());
EXPECT_TRUE([bubbleWindow() isVisible]);
// Close the window directly instead of using the bubble interface.
[bubbleWindow() close];
EXPECT_FALSE(ManagePasswordsBubbleCocoa::instance());
EXPECT_FALSE([bubbleWindow() isVisible]);
}
...@@ -27,7 +27,7 @@ class ManagePasswordsBubble { ...@@ -27,7 +27,7 @@ class ManagePasswordsBubble {
// ManagePasswordsBubbleModel; this class neither takes ownership of the // ManagePasswordsBubbleModel; this class neither takes ownership of the
// object nor stores the pointer. // object nor stores the pointer.
ManagePasswordsBubble(content::WebContents* contents, DisplayReason reason); ManagePasswordsBubble(content::WebContents* contents, DisplayReason reason);
~ManagePasswordsBubble(); virtual ~ManagePasswordsBubble();
ManagePasswordsBubbleModel* model() { return model_.get(); } ManagePasswordsBubbleModel* model() { return model_.get(); }
const ManagePasswordsBubbleModel* model() const { return model_.get(); } const ManagePasswordsBubbleModel* model() const { return model_.get(); }
......
...@@ -233,7 +233,8 @@ class ManagePasswordsBubbleView : public ManagePasswordsBubble, ...@@ -233,7 +233,8 @@ class ManagePasswordsBubbleView : public ManagePasswordsBubble,
// Singleton instance of the Password bubble. The Password bubble can only be // Singleton instance of the Password bubble. The Password bubble can only be
// shown on the active browser window, so there is no case in which it will be // shown on the active browser window, so there is no case in which it will be
// shown twice at the same time. // shown twice at the same time. The instance is owned by the Bubble and will
// be deleted when the bubble closes.
static ManagePasswordsBubbleView* manage_passwords_bubble_; static ManagePasswordsBubbleView* manage_passwords_bubble_;
ManagePasswordsIconView* anchor_view_; ManagePasswordsIconView* anchor_view_;
......
...@@ -629,6 +629,8 @@ ...@@ -629,6 +629,8 @@
'browser/ui/cocoa/panels/panel_window_controller_cocoa.mm', 'browser/ui/cocoa/panels/panel_window_controller_cocoa.mm',
'browser/ui/cocoa/passwords/manage_password_item_view_controller.h', 'browser/ui/cocoa/passwords/manage_password_item_view_controller.h',
'browser/ui/cocoa/passwords/manage_password_item_view_controller.mm', 'browser/ui/cocoa/passwords/manage_password_item_view_controller.mm',
'browser/ui/cocoa/passwords/manage_passwords_bubble_cocoa.h',
'browser/ui/cocoa/passwords/manage_passwords_bubble_cocoa.mm',
'browser/ui/cocoa/passwords/manage_passwords_bubble_content_view_controller.h', 'browser/ui/cocoa/passwords/manage_passwords_bubble_content_view_controller.h',
'browser/ui/cocoa/passwords/manage_passwords_bubble_content_view_controller.mm', 'browser/ui/cocoa/passwords/manage_passwords_bubble_content_view_controller.mm',
'browser/ui/cocoa/passwords/manage_passwords_bubble_controller.h', 'browser/ui/cocoa/passwords/manage_passwords_bubble_controller.h',
......
...@@ -1624,6 +1624,7 @@ ...@@ -1624,6 +1624,7 @@
'browser/ui/cocoa/one_click_signin_bubble_controller_unittest.mm', 'browser/ui/cocoa/one_click_signin_bubble_controller_unittest.mm',
'browser/ui/cocoa/panels/panel_cocoa_unittest.mm', 'browser/ui/cocoa/panels/panel_cocoa_unittest.mm',
'browser/ui/cocoa/passwords/manage_password_item_view_controller_unittest.mm', 'browser/ui/cocoa/passwords/manage_password_item_view_controller_unittest.mm',
'browser/ui/cocoa/passwords/manage_passwords_bubble_cocoa_unittest.mm',
'browser/ui/cocoa/passwords/manage_passwords_bubble_controller_unittest.mm', 'browser/ui/cocoa/passwords/manage_passwords_bubble_controller_unittest.mm',
'browser/ui/cocoa/passwords/manage_passwords_bubble_pending_view_controller_unittest.mm', 'browser/ui/cocoa/passwords/manage_passwords_bubble_pending_view_controller_unittest.mm',
'browser/ui/cocoa/passwords/manage_passwords_controller_test.h', 'browser/ui/cocoa/passwords/manage_passwords_controller_test.h',
......
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