blob: 10f29823fae22774c79a82168b93f56e9372b3ba [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_SIGNIN_SIGNIN_VIEW_CONTROLLER_H_
#define CHROME_BROWSER_UI_SIGNIN_SIGNIN_VIEW_CONTROLLER_H_
#include <string>
#include "base/functional/callback.h"
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/ui/signin/signin_modal_dialog.h"
#include "chrome/browser/ui/webui/signin/signin_utils.h"
#include "chrome/common/url_constants.h"
#include "components/signin/public/base/signin_buildflags.h"
#include "components/signin/public/base/signin_metrics.h"
#include "components/sync/base/data_type.h"
#include "url/gurl.h"
#if BUILDFLAG(ENABLE_DICE_SUPPORT) || BUILDFLAG(IS_CHROMEOS_LACROS)
#include "chrome/browser/ui/webui/signin/signin_email_confirmation_dialog.h"
#endif
#if BUILDFLAG(IS_ANDROID)
#error This file should only be included on desktop.
#endif
class Browser;
struct AccountInfo;
struct CoreAccountId;
namespace content {
class WebContents;
}
namespace login_ui_test_utils {
class SigninViewControllerTestUtil;
}
namespace signin_metrics {
enum class AccessPoint;
enum class PromoAction;
enum class Reason;
enum class ReauthAccessPoint;
enum class SourceForRefreshTokenOperation;
} // namespace signin_metrics
namespace signin {
enum class ReauthResult;
}
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
namespace {
class NewTabWebContentsObserver;
}
#endif
// Class responsible for showing and hiding all sign-in related UIs
// (modal sign-in, DICE full-tab sign-in page, sync confirmation dialog, sign-in
// error dialog, reauth prompt). Sync confirmation is used on
// Win/Mac/Linux/Chrome OS. Sign-in is only used on Win/Mac/Linux because
// Chrome OS has its own sign-in flow and doesn't use DICE.
class SigninViewController {
public:
// Handle that will stop ongoing reauths upon destruction.
class ReauthAbortHandle {
public:
virtual ~ReauthAbortHandle() = default;
};
explicit SigninViewController(Browser* browser);
SigninViewController(const SigninViewController&) = delete;
SigninViewController& operator=(const SigninViewController&) = delete;
virtual ~SigninViewController();
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
// Returns true if Chrome new tab page/blank is displayed in `contents`.
static bool IsNTPTab(content::WebContents* contents);
// Shows the signin attached to |browser_|'s active web contents.
// |access_point| indicates the access point used to open the Gaia sign in
// page.
// DEPRECATED: Use ShowDiceEnableSyncTab instead.
void ShowSignin(signin_metrics::AccessPoint access_point,
const GURL& redirect_url = GURL(chrome::kChromeUINewTabURL));
// Shows a Chrome Sync signin tab. |email_hint| may be empty.
// Note: If the user has already set a primary account, then this is
// considered a reauth of the primary account, and |email_hint| is ignored.
void ShowDiceEnableSyncTab(signin_metrics::AccessPoint access_point,
signin_metrics::PromoAction promo_action,
const std::string& email_hint);
// Shows the Dice "add account" tab, which adds an account to the browser but
// does not turn sync on. |email_hint| may be empty.
virtual void ShowDiceAddAccountTab(signin_metrics::AccessPoint access_point,
const std::string& email_hint);
// Opens the Gaia logout page in a new tab. This removes the accounts from the
// web, as well as from Chrome (Dice intercepts the web signout and
// invalidates all Chrome accounts). If a primary account is set, this
// function does not clear it, but still invalidates its credentials.
// This is the only way to properly signout all accounts. In particular,
// calling Gaia logout programmatically or revoking the tokens does not sign
// out SAML accounts completely (see https://crbug.com/1069421).
void ShowGaiaLogoutTab(signin_metrics::SourceForRefreshTokenOperation source);
// Shows the modal signin intercept first run experience dialog as a
// browser-modal dialog on top of the `browser_`'s window. `account_id`
// corresponds to the intercepted account.
void ShowModalInterceptFirstRunExperienceDialog(
const CoreAccountId& account_id,
bool is_forced_intercept);
// Possibly show a confirmation prompt and then sign the user out, open a
// reauth tab, or do nothing depending on the user choice.
void SignoutOrReauthWithPrompt(
signin_metrics::AccessPoint reauth_access_point,
signin_metrics::ProfileSignout profile_signout_source,
signin_metrics::SourceForRefreshTokenOperation token_signout_source);
// Called by extensions to ask the user to sign in to chrome while they are
// signed in on the web only.
// This opens/reuses a new tab page and opens a modal dialog.
// Note: This should only be called if the dialog is not already showing.
void MaybeShowChromeSigninDialogForExtensions(
const std::u16string& extension_name_for_display,
base::OnceClosure on_complete);
#endif // BUILDFLAG(ENABLE_DICE_SUPPORT)
#if BUILDFLAG(ENABLE_DICE_SUPPORT) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Shows the modal profile customization dialog as a browser-modal dialog on
// top of the |browser_|'s window.
void ShowModalProfileCustomizationDialog(
bool is_local_profile_creation = false);
// Shows the modal sign-in email confirmation dialog as a tab-modal dialog on
// top of the currently displayed WebContents in |browser_|.
void ShowModalSigninEmailConfirmationDialog(
const std::string& last_email,
const std::string& email,
SigninEmailConfirmationDialog::Callback callback);
// Shows the reauth prompt for |account_id| as either:
// - a tab-modal dialog on top of the currently active tab, or
// - a new tab
// |account_id| should be signed into the content area. Otherwise, the method
// fails with |kAccountNotSignedIn| error.
// |access_point| indicates a call site of this method.
// Calls |reauth_callback| on completion of the reauth flow, or on error. The
// callback may be called synchronously. The user may also ignore the reauth
// indefinitely.
// Returns a handle that aborts the ongoing reauth on destruction.
virtual std::unique_ptr<ReauthAbortHandle> ShowReauthPrompt(
const CoreAccountId& account_id,
signin_metrics::ReauthAccessPoint access_point,
base::OnceCallback<void(signin::ReauthResult)> reauth_callback);
#endif // BUILDFLAG(ENABLE_DICE_SUPPORT) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Shows the modal sync confirmation dialog as a browser-modal dialog on top
// of the |browser_|'s window.
// `is_signin_intercept` is true if the confirmation dialog is shown after
// signin intercept, which has a slightly different UI.
// `is_sync_promo` is true if the sync confirmation dialog is offered as an
// option. It is false if the user explicitly initiated the flow.
void ShowModalSyncConfirmationDialog(bool is_signin_intercept,
bool is_sync_promo);
// Shows the modal managed user notice dialog as a browser-modal dialog on
// top of the `browser_`'s window. `domain_name` is the domain of the
// enterprise account being shown. `callback` is called with the user's action
// on the dialog.
// If `profile_creation_required_by_policy` is true, the wording of the dialog
// will tell the user that an admin requires a new profile for the account,
// otherwise the default wording will be used.
// When `show_link_data_option` is false, the callback is called with either
// SIGNIN_CHOICE_CANCEL or SIGNIN_CHOICE_NEW_PROFILE.
// `process_user_choice_callback` is the callback that handles the user
// choice. This callback may contain a callback to notify UI that that the
// operation is done. If no UI notification is required, that callback does
// not need to be set.
// `done_callback` is the callback when the flow is complete, this is
// where The UI cleanups should be handled.
void ShowModalManagedUserNoticeDialog(
std::unique_ptr<signin::EnterpriseProfileCreationDialogParams>
create_param);
// Shows the modal sign-in error dialog as a browser-modal dialog on top of
// the |browser_|'s window.
void ShowModalSigninErrorDialog();
// Returns true if the modal dialog is shown.
bool ShowsModalDialog();
// Closes the tab-modal signin flow previously shown using this
// SigninViewController, if one exists. Does nothing otherwise.
void CloseModalSignin();
// Sets the height of the modal signin dialog.
void SetModalSigninHeight(int height);
// Called by a `dialog_`' when it closes.
void OnModalDialogClosed();
base::WeakPtr<SigninViewController> AsWeakPtr();
private:
FRIEND_TEST_ALL_PREFIXES(SignInViewControllerBrowserTest,
EmailConfirmationDefaultFocus);
FRIEND_TEST_ALL_PREFIXES(SignInViewControllerBrowserTest,
ErrorDialogDefaultFocus);
FRIEND_TEST_ALL_PREFIXES(SignInViewControllerBrowserTest,
EnterpriseConfirmationDefaultFocus);
FRIEND_TEST_ALL_PREFIXES(SignInViewControllerBrowserOIDCAccountTest,
EnterpriseConfirmationDefaultFocus);
FRIEND_TEST_ALL_PREFIXES(SignInViewControllerBrowserOIDCAccountTest,
EnterpriseConfirmationCancel);
FRIEND_TEST_ALL_PREFIXES(SigninViewControllerDelegateViewsBrowserTest,
CloseImmediately);
FRIEND_TEST_ALL_PREFIXES(ProfilePickerCreationFlowBrowserTest,
CreateLocalProfile);
FRIEND_TEST_ALL_PREFIXES(ProfilePickerCreationFlowBrowserTest,
CancelLocalProfileCreation);
friend class login_ui_test_utils::SigninViewControllerTestUtil;
friend class SigninReauthViewControllerBrowserTest;
friend class SigninInterceptFirstRunExperienceDialogBrowserTest;
friend class SyncConfirmationUIDialogPixelTest;
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
// Shows the DICE-specific sign-in flow: opens a Gaia sign-in webpage in a new
// tab attached to |browser_|. |email_hint| may be empty.
// If `redirect_url` is empty, the Google search URL is used as continue_url.
// Internal URLs such as the NTP are only supported when `signin_reason` is
// `signin_metrics::Reason::kSigninPrimaryAccount`.
void ShowDiceSigninTab(signin_metrics::Reason signin_reason,
signin_metrics::AccessPoint access_point,
signin_metrics::PromoAction promo_action,
const std::string& email_hint,
const GURL& redirect_url);
// Called by `SignoutOrReauthWithPrompt()` once the unsynced datatypes are
// fetched.
void SignoutOrReauthWithPromptWithUnsyncedDataTypes(
signin_metrics::AccessPoint reauth_access_point,
signin_metrics::ProfileSignout profile_signout_source,
signin_metrics::SourceForRefreshTokenOperation token_signout_source,
syncer::DataTypeSet unsynced_datatypes);
void ShowChromeSigninDialogForExtensions(
const std::u16string& extension_name_for_display,
base::OnceClosure on_complete,
const AccountInfo& account_info_for_promos,
content::WebContents* contents);
#endif // BUILDFLAG(ENABLE_DICE_SUPPORT)
// Returns the web contents of the modal dialog.
content::WebContents* GetModalDialogWebContentsForTesting();
// Returns the currently displayed modal dialog, or nullptr if no modal dialog
// is currently displayed.
SigninModalDialog* GetModalDialogForTesting();
// Helper to create an on close callback for `SigninModalDialog`.
base::OnceClosure GetOnModalDialogClosedCallback();
// Browser owning this controller.
raw_ptr<Browser> browser_;
// Currently displayed modal dialog, or nullptr if none is displayed.
std::unique_ptr<SigninModalDialog> dialog_;
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
std::unique_ptr<NewTabWebContentsObserver> new_tab_web_contents_observer_;
#endif
base::WeakPtrFactory<SigninViewController> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_UI_SIGNIN_SIGNIN_VIEW_CONTROLLER_H_