blob: 37d031c055983fb992aee58b75867a0814dd2110 [file] [log] [blame]
// Copyright 2016 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/profiles/signin_view_controller_delegate_views.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_avatar_icon_util.h"
#include "chrome/browser/signin/signin_promo.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/webui/signin/sync_confirmation_ui.h"
#include "chrome/common/url_constants.h"
#include "components/constrained_window/constrained_window_views.h"
#include "components/unified_consent/feature.h"
#include "components/web_modal/web_contents_modal_dialog_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/widget/widget.h"
namespace {
const int kModalDialogWidth = 448;
const int kModalDialogWidthForUnifiedConsent = 512;
const int kSyncConfirmationDialogHeight = 487;
const int kSigninErrorDialogHeight = 164;
int GetSyncConfirmationDialogPreferredHeight(Profile* profile) {
// If sync is disabled, then the sync confirmation dialog looks like an error
// dialog and thus it has the same preferred size.
return profile->IsSyncAllowed() ? kSyncConfirmationDialogHeight
: kSigninErrorDialogHeight;
}
int GetSyncConfirmationDialogPreferredWidth(Profile* profile) {
// If unified consent is enabled, we show a different sync confirmation dialog
// which uses a different width.
return unified_consent::IsUnifiedConsentFeatureEnabled() &&
profile->IsSyncAllowed()
? kModalDialogWidthForUnifiedConsent
: kModalDialogWidth;
}
} // namespace
SigninViewControllerDelegateViews::SigninViewControllerDelegateViews(
SigninViewController* signin_view_controller,
std::unique_ptr<views::WebView> content_view,
Browser* browser,
ui::ModalType dialog_modal_type,
bool wait_for_size)
: signin_view_controller_(signin_view_controller),
web_contents_(content_view->GetWebContents()),
browser_(browser),
content_view_(content_view.release()),
modal_signin_widget_(nullptr),
dialog_modal_type_(dialog_modal_type) {
DCHECK(web_contents_);
DCHECK(browser_);
DCHECK(browser_->tab_strip_model()->GetActiveWebContents())
<< "A tab must be active to present the sign-in modal dialog.";
web_contents_->SetDelegate(this);
DCHECK(dialog_modal_type == ui::MODAL_TYPE_CHILD ||
dialog_modal_type == ui::MODAL_TYPE_WINDOW)
<< "Unsupported dialog modal type " << dialog_modal_type;
if (!wait_for_size)
DisplayModal();
}
SigninViewControllerDelegateViews::~SigninViewControllerDelegateViews() {}
// views::DialogDelegateView:
views::View* SigninViewControllerDelegateViews::GetContentsView() {
return content_view_;
}
views::Widget* SigninViewControllerDelegateViews::GetWidget() {
return content_view_->GetWidget();
}
const views::Widget* SigninViewControllerDelegateViews::GetWidget() const {
return content_view_->GetWidget();
}
void SigninViewControllerDelegateViews::DeleteDelegate() {
ResetSigninViewControllerDelegate();
delete this;
}
ui::ModalType SigninViewControllerDelegateViews::GetModalType() const {
return dialog_modal_type_;
}
bool SigninViewControllerDelegateViews::ShouldShowCloseButton() const {
return false;
}
int SigninViewControllerDelegateViews::GetDialogButtons() const {
return ui::DIALOG_BUTTON_NONE;
}
void SigninViewControllerDelegateViews::ResizeNativeView(int height) {
int max_height = browser()
->window()
->GetWebContentsModalDialogHost()
->GetMaximumDialogSize()
.height();
content_view_->SetPreferredSize(gfx::Size(
content_view_->GetPreferredSize().width(), std::min(height, max_height)));
if (!modal_signin_widget_) {
// The modal wasn't displayed yet so just show it with the already resized
// view.
DisplayModal();
}
}
content::WebContents* SigninViewControllerDelegateViews::GetWebContents() {
return web_contents_;
}
void SigninViewControllerDelegateViews::CloseModalSignin() {
ResetSigninViewControllerDelegate();
if (modal_signin_widget_)
modal_signin_widget_->Close();
}
void SigninViewControllerDelegateViews::DisplayModal() {
DCHECK(!modal_signin_widget_);
content::WebContents* host_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
// Avoid displaying the sign-in modal view if there are no active web
// contents. This happens if the user closes the browser window before this
// dialog has a chance to be displayed.
if (!host_web_contents)
return;
gfx::NativeWindow window = host_web_contents->GetTopLevelNativeWindow();
switch (dialog_modal_type_) {
case ui::MODAL_TYPE_WINDOW:
modal_signin_widget_ =
constrained_window::CreateBrowserModalDialogViews(this, window);
modal_signin_widget_->Show();
break;
case ui::MODAL_TYPE_CHILD:
modal_signin_widget_ = constrained_window::ShowWebModalDialogViews(
this, browser()->tab_strip_model()->GetActiveWebContents());
break;
default:
NOTREACHED() << "Unsupported dialog modal type " << dialog_modal_type_;
}
content_view_->RequestFocus();
}
bool SigninViewControllerDelegateViews::HandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) {
// If this is a MODAL_TYPE_CHILD, then GetFocusManager() will return the focus
// manager of the parent window, which has registered accelerators, and the
// accelerators will fire. If this is a MODAL_TYPE_WINDOW, then this will have
// no effect, since no accelerators have been registered for this standalone
// window.
return unhandled_keyboard_event_handler_.HandleKeyboardEvent(
event, GetFocusManager());
}
bool SigninViewControllerDelegateViews::HandleContextMenu(
const content::ContextMenuParams& params) {
// Discard the context menu
return true;
}
std::unique_ptr<views::WebView>
SigninViewControllerDelegateViews::CreateSyncConfirmationWebView(
Browser* browser) {
return CreateDialogWebView(
browser, chrome::kChromeUISyncConfirmationURL,
GetSyncConfirmationDialogPreferredHeight(browser->profile()),
GetSyncConfirmationDialogPreferredWidth(browser->profile()));
}
std::unique_ptr<views::WebView>
SigninViewControllerDelegateViews::CreateSigninErrorWebView(Browser* browser) {
return CreateDialogWebView(browser, chrome::kChromeUISigninErrorURL,
kSigninErrorDialogHeight, base::nullopt);
}
std::unique_ptr<views::WebView>
SigninViewControllerDelegateViews::CreateDialogWebView(
Browser* browser,
const std::string& url,
int dialog_height,
base::Optional<int> opt_width) {
int dialog_width = opt_width.value_or(kModalDialogWidth);
views::WebView* web_view = new views::WebView(browser->profile());
web_view->LoadInitialURL(GURL(url));
// To record metrics using javascript, extensions are needed.
extensions::ChromeExtensionWebContentsObserver::CreateForWebContents(
web_view->GetWebContents());
SigninWebDialogUI* web_dialog_ui = static_cast<SigninWebDialogUI*>(
web_view->GetWebContents()->GetWebUI()->GetController());
web_dialog_ui->InitializeMessageHandlerWithBrowser(browser);
int max_height = browser->window()
->GetWebContentsModalDialogHost()
->GetMaximumDialogSize()
.height();
web_view->SetPreferredSize(
gfx::Size(dialog_width, std::min(dialog_height, max_height)));
return std::unique_ptr<views::WebView>(web_view);
}
web_modal::WebContentsModalDialogHost*
SigninViewControllerDelegateViews::GetWebContentsModalDialogHost() {
return browser()->window()->GetWebContentsModalDialogHost();
}
void SigninViewControllerDelegateViews::ResetSigninViewControllerDelegate() {
if (signin_view_controller_) {
signin_view_controller_->ResetModalSigninDelegate();
signin_view_controller_ = nullptr;
}
}
// --------------------------------------------------------------------
// SigninViewControllerDelegate static methods
// --------------------------------------------------------------------
SigninViewControllerDelegate*
SigninViewControllerDelegate::CreateSyncConfirmationDelegate(
SigninViewController* signin_view_controller,
Browser* browser) {
return new SigninViewControllerDelegateViews(
signin_view_controller,
SigninViewControllerDelegateViews::CreateSyncConfirmationWebView(browser),
browser, ui::MODAL_TYPE_WINDOW, true);
}
SigninViewControllerDelegate*
SigninViewControllerDelegate::CreateSigninErrorDelegate(
SigninViewController* signin_view_controller,
Browser* browser) {
return new SigninViewControllerDelegateViews(
signin_view_controller,
SigninViewControllerDelegateViews::CreateSigninErrorWebView(browser),
browser, ui::MODAL_TYPE_WINDOW, true);
}