forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[mac] Implement a windowed extension install/permissions prompt.
This allows extension install dialogs, and permissions upgrade prompts, to be shown on mac without requiring a parent WebContents to attach a sheet to. Currently, they hit NOTIMPLEMENTED(). The window is a titled NSPanel, centred on screen using [NSWindow center]. The implementation mostly uses the existing ExtensionInstallViewController, but puts it in a new, windowed-version of ExtensionInstallDialogController. Adds a test: WindowedInstallDialogControllerBrowserTest.ShowInstallDialog that mimics the way extension install and upgrade prompts are invoked via the app launcher. Screenshot at http://crbug.com/325030#c2 BUG=325030, 229094, 271809, 269151 Review URL: https://codereview.chromium.org/65043015 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238542 0039d316-1c4b-4281-b951-d872f2087c98
- Loading branch information
tapted@chromium.org
committed
Dec 4, 2013
1 parent
496dbbe
commit 0610ab5
Showing
12 changed files
with
268 additions
and
57 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// 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. | ||
|
||
#ifndef CHROME_BROWSER_UI_COCOA_EXTENSIONS_WINDOWED_INSTALL_DIALOG_CONTROLLER_H_ | ||
#define CHROME_BROWSER_UI_COCOA_EXTENSIONS_WINDOWED_INSTALL_DIALOG_CONTROLLER_H_ | ||
|
||
#import <Cocoa/Cocoa.h> | ||
|
||
#include "base/gtest_prod_util.h" | ||
#include "base/mac/scoped_nsobject.h" | ||
#include "chrome/browser/extensions/extension_install_prompt.h" | ||
|
||
@class ExtensionInstallViewController; | ||
@class WindowedInstallController; | ||
|
||
// Displays an app or extension install or permissions prompt as a standalone | ||
// NSPanel. | ||
class WindowedInstallDialogController | ||
: public ExtensionInstallPrompt::Delegate { | ||
public: | ||
// Initializes the ExtensionInstallViewController and shows the window. This | ||
// object will delete itself when the window is closed. | ||
WindowedInstallDialogController( | ||
const ExtensionInstallPrompt::ShowParams& show_params, | ||
ExtensionInstallPrompt::Delegate* delegate, | ||
const ExtensionInstallPrompt::Prompt& prompt); | ||
virtual ~WindowedInstallDialogController(); | ||
|
||
// Invoked by the -[NSWindow windowWillClose:] notification after a dialog | ||
// choice is invoked. Releases owned resources, then deletes |this|. | ||
void OnWindowClosing(); | ||
|
||
// ExtensionInstallPrompt::Delegate: | ||
virtual void InstallUIProceed() OVERRIDE; | ||
virtual void InstallUIAbort(bool user_initiated) OVERRIDE; | ||
|
||
private: | ||
FRIEND_TEST_ALL_PREFIXES(WindowedInstallDialogControllerBrowserTest, | ||
ShowInstallDialog); | ||
ExtensionInstallViewController* GetViewController(); | ||
|
||
ExtensionInstallPrompt::Delegate* delegate_; | ||
base::scoped_nsobject<WindowedInstallController> install_controller_; | ||
|
||
DISALLOW_COPY_AND_ASSIGN(WindowedInstallDialogController); | ||
}; | ||
|
||
#endif // CHROME_BROWSER_UI_COCOA_EXTENSIONS_WINDOWED_INSTALL_DIALOG_CONTROLLER_H_ |
117 changes: 117 additions & 0 deletions
117
chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.mm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// 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. | ||
|
||
#import "chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.h" | ||
|
||
#import "base/mac/sdk_forward_declarations.h" | ||
#include "base/message_loop/message_loop.h" | ||
#include "base/strings/sys_string_conversions.h" | ||
#import "chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h" | ||
#include "ui/base/cocoa/window_size_constants.h" | ||
|
||
@interface WindowedInstallController | ||
: NSWindowController<NSWindowDelegate> { | ||
@private | ||
base::scoped_nsobject<ExtensionInstallViewController> installViewController_; | ||
WindowedInstallDialogController* dialogController_; // Weak. Owns us. | ||
} | ||
|
||
@property(readonly, nonatomic) ExtensionInstallViewController* viewController; | ||
|
||
- (id)initWithNavigator:(content::PageNavigator*)navigator | ||
delegate:(WindowedInstallDialogController*)delegate | ||
prompt:(const ExtensionInstallPrompt::Prompt&)prompt; | ||
|
||
@end | ||
|
||
WindowedInstallDialogController::WindowedInstallDialogController( | ||
const ExtensionInstallPrompt::ShowParams& show_params, | ||
ExtensionInstallPrompt::Delegate* delegate, | ||
const ExtensionInstallPrompt::Prompt& prompt) | ||
: delegate_(delegate) { | ||
install_controller_.reset([[WindowedInstallController alloc] | ||
initWithNavigator:show_params.navigator | ||
delegate:this | ||
prompt:prompt]); | ||
[[install_controller_ window] makeKeyAndOrderFront:nil]; | ||
} | ||
|
||
WindowedInstallDialogController::~WindowedInstallDialogController() { | ||
DCHECK(!install_controller_); | ||
DCHECK(!delegate_); | ||
} | ||
|
||
void WindowedInstallDialogController::OnWindowClosing() { | ||
install_controller_.reset(); | ||
if (delegate_) { | ||
delegate_->InstallUIAbort(false); | ||
delegate_ = NULL; | ||
} | ||
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | ||
} | ||
|
||
ExtensionInstallViewController* | ||
WindowedInstallDialogController::GetViewController() { | ||
return [install_controller_ viewController]; | ||
} | ||
|
||
void WindowedInstallDialogController::InstallUIProceed() { | ||
delegate_->InstallUIProceed(); | ||
delegate_ = NULL; | ||
[[install_controller_ window] close]; | ||
} | ||
|
||
void WindowedInstallDialogController::InstallUIAbort(bool user_initiated) { | ||
delegate_->InstallUIAbort(user_initiated); | ||
delegate_ = NULL; | ||
[[install_controller_ window] close]; | ||
} | ||
|
||
@implementation WindowedInstallController | ||
|
||
- (id)initWithNavigator:(content::PageNavigator*)navigator | ||
delegate:(WindowedInstallDialogController*)delegate | ||
prompt:(const ExtensionInstallPrompt::Prompt&)prompt { | ||
base::scoped_nsobject<NSWindow> controlledPanel( | ||
[[NSPanel alloc] initWithContentRect:ui::kWindowSizeDeterminedLater | ||
styleMask:NSTitledWindowMask | ||
backing:NSBackingStoreBuffered | ||
defer:NO]); | ||
if ((self = [super initWithWindow:controlledPanel])) { | ||
dialogController_ = delegate; | ||
installViewController_.reset([[ExtensionInstallViewController alloc] | ||
initWithNavigator:navigator | ||
delegate:delegate | ||
prompt:prompt]); | ||
NSWindow* window = [self window]; | ||
|
||
// Ensure the window does not display behind the app launcher window, and is | ||
// otherwise hard to lose behind other windows (since it is not modal). | ||
[window setLevel:NSDockWindowLevel]; | ||
|
||
// Animate the window when ordered in, the same way as an NSAlert. | ||
if ([window respondsToSelector:@selector(setAnimationBehavior:)]) | ||
[window setAnimationBehavior:NSWindowAnimationBehaviorAlertPanel]; | ||
|
||
[window setTitle:base::SysUTF16ToNSString(prompt.GetDialogTitle())]; | ||
NSRect viewFrame = [[installViewController_ view] frame]; | ||
[window setFrame:[window frameRectForContentRect:viewFrame] | ||
display:NO]; | ||
[window setContentView:[installViewController_ view]]; | ||
[window setDelegate:self]; | ||
[window center]; | ||
} | ||
return self; | ||
} | ||
|
||
- (ExtensionInstallViewController*)viewController { | ||
return installViewController_; | ||
} | ||
|
||
- (void)windowWillClose:(NSNotification*)notification { | ||
[[self window] setDelegate:nil]; | ||
dialogController_->OnWindowClosing(); | ||
} | ||
|
||
@end |
67 changes: 67 additions & 0 deletions
67
chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller_browsertest.mm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// 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. | ||
|
||
#import "chrome/browser/ui/cocoa/extensions/windowed_install_dialog_controller.h" | ||
|
||
#include "base/run_loop.h" | ||
#include "chrome/browser/ui/browser.h" | ||
#import "chrome/browser/ui/cocoa/extensions/extension_install_prompt_test_utils.h" | ||
#import "chrome/browser/ui/cocoa/extensions/extension_install_view_controller.h" | ||
#include "chrome/test/base/in_process_browser_test.h" | ||
#include "content/public/browser/browser_thread.h" | ||
#include "extensions/common/extension.h" | ||
|
||
namespace { | ||
|
||
// Similar to ShowExtensionInstallDialogImpl except this allows the created | ||
// dialog controller to be captured and manipulated for tests. | ||
void TestingShowAppListInstallDialogController( | ||
WindowedInstallDialogController** controller, | ||
const ExtensionInstallPrompt::ShowParams& show_params, | ||
ExtensionInstallPrompt::Delegate* delegate, | ||
const ExtensionInstallPrompt::Prompt& prompt) { | ||
*controller = | ||
new WindowedInstallDialogController(show_params, delegate, prompt); | ||
} | ||
|
||
typedef InProcessBrowserTest WindowedInstallDialogControllerBrowserTest; | ||
|
||
} // namespace | ||
|
||
// Test for showing an extension install prompt with no parent WebContents. | ||
IN_PROC_BROWSER_TEST_F(WindowedInstallDialogControllerBrowserTest, | ||
ShowInstallDialog) { | ||
// Construct a prompt with a NULL parent window, the way ExtensionEnableFlow | ||
// will for the Mac app list. For testing, sets a NULL PageNavigator as well. | ||
scoped_ptr<ExtensionInstallPrompt> prompt( | ||
new ExtensionInstallPrompt(browser()->profile(), NULL, NULL)); | ||
|
||
WindowedInstallDialogController* controller = NULL; | ||
chrome::MockExtensionInstallPromptDelegate delegate; | ||
scoped_refptr<extensions::Extension> extension = | ||
chrome::LoadInstallPromptExtension("permissions", "many-apis.json"); | ||
prompt->ConfirmInstall( | ||
&delegate, | ||
extension.get(), | ||
base::Bind(&TestingShowAppListInstallDialogController, &controller)); | ||
|
||
// The prompt needs to load the image, which happens on the blocking pool. | ||
content::BrowserThread::GetBlockingPool()->FlushForTesting(); | ||
base::RunLoop().RunUntilIdle(); | ||
ASSERT_TRUE(controller); | ||
|
||
base::scoped_nsobject<NSWindow> window( | ||
[[[controller->GetViewController() view] window] retain]); | ||
EXPECT_TRUE([window isVisible]); | ||
EXPECT_TRUE([window delegate]); | ||
EXPECT_EQ(0, delegate.abort_count()); | ||
|
||
// Press cancel to close the window. | ||
[[controller->GetViewController() cancelButton] performClick:nil]; | ||
EXPECT_FALSE([window delegate]); | ||
EXPECT_EQ(1, delegate.abort_count()); | ||
|
||
// Ensure the window is closed. | ||
EXPECT_FALSE([window isVisible]); | ||
} |
Oops, something went wrong.