blob: 1ceff75ff6a07260f48ef7d52fb2670799a79e1c [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/signin/model/account_consistency_browser_agent.h"
#import <UIKit/UIKit.h>
#import "base/functional/callback_helpers.h"
#import "base/metrics/histogram_functions.h"
#import "base/strings/sys_string_conversions.h"
#import "components/signin/core/browser/account_reconcilor.h"
#import "components/signin/ios/browser/account_consistency_service.h"
#import "components/signin/public/identity_manager/identity_manager.h"
#import "ios/chrome/browser/authentication/ui_bundled/continuation.h"
#import "ios/chrome/browser/authentication/ui_bundled/signin/signin_coordinator.h"
#import "ios/chrome/browser/shared/model/application_context/application_context.h"
#import "ios/chrome/browser/shared/model/profile/features.h"
#import "ios/chrome/browser/shared/model/profile/profile_attributes_storage_ios.h"
#import "ios/chrome/browser/shared/model/profile/profile_ios.h"
#import "ios/chrome/browser/shared/model/profile/profile_manager_ios.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
#import "ios/chrome/browser/shared/public/commands/application_commands.h"
#import "ios/chrome/browser/shared/public/commands/browser_coordinator_commands.h"
#import "ios/chrome/browser/shared/public/commands/command_dispatcher.h"
#import "ios/chrome/browser/shared/public/commands/open_new_tab_command.h"
#import "ios/chrome/browser/shared/public/commands/settings_commands.h"
#import "ios/chrome/browser/shared/public/commands/show_signin_command.h"
#import "ios/chrome/browser/signin/model/account_consistency_service_factory.h"
#import "ios/chrome/browser/signin/model/account_reconcilor_factory.h"
#import "ios/chrome/browser/signin/model/identity_manager_factory.h"
#import "ios/chrome/browser/tabs/model/tabs_dependency_installer.h"
#import "ios/chrome/browser/web/model/web_navigation_browser_agent.h"
#import "ios/web/public/navigation/referrer.h"
AccountConsistencyBrowserAgent::AccountConsistencyBrowserAgent(
Browser* browser,
UIViewController* base_view_controller)
: BrowserUserData(browser), base_view_controller_(base_view_controller) {
StartObserving(browser->GetWebStateList(), Policy::kOnlyRealized);
application_handler_ =
HandlerForProtocol(browser_->GetCommandDispatcher(), ApplicationCommands);
settings_handler_ =
HandlerForProtocol(browser_->GetCommandDispatcher(), SettingsCommands);
}
AccountConsistencyBrowserAgent::~AccountConsistencyBrowserAgent() {
StopSigninCoordinator(SigninCoordinatorResultInterrupted, nil);
StopObserving();
}
void AccountConsistencyBrowserAgent::StopSigninCoordinator(
SigninCoordinatorResult result,
id<SystemIdentity> identity) {
[add_account_coordinator_ stop];
add_account_coordinator_ = nil;
}
void AccountConsistencyBrowserAgent::OnWebStateInserted(
web::WebState* web_state) {
if (AccountConsistencyService* accountConsistencyService =
ios::AccountConsistencyServiceFactory::GetForProfile(
browser_->GetProfile())) {
accountConsistencyService->SetWebStateHandler(web_state, this);
}
}
void AccountConsistencyBrowserAgent::OnWebStateRemoved(
web::WebState* web_state) {
if (AccountConsistencyService* accountConsistencyService =
ios::AccountConsistencyServiceFactory::GetForProfile(
browser_->GetProfile())) {
accountConsistencyService->RemoveWebStateHandler(web_state);
}
}
void AccountConsistencyBrowserAgent::OnWebStateDeleted(
web::WebState* web_state) {
// Nothing to do.
}
void AccountConsistencyBrowserAgent::OnActiveWebStateChanged(
web::WebState* old_active,
web::WebState* new_active) {
// Nothing to do.
}
void AccountConsistencyBrowserAgent::OnRestoreGaiaCookies() {
signin_metrics::LogAccountReconcilorStateOnGaiaResponse(
ios::AccountReconcilorFactory::GetForProfile(browser_->GetProfile())
->GetState());
[application_handler_
showSigninAccountNotificationFromViewController:base_view_controller_];
}
void AccountConsistencyBrowserAgent::OnManageAccounts(const GURL& url) {
Browser::Type browser_type = browser_->type();
base::UmaHistogramEnumeration("Signin.ShowManageAccountFromGaia.BrowserType",
browser_type);
if (browser_type != Browser::Type::kRegular) {
return;
}
signin_metrics::LogAccountReconcilorStateOnGaiaResponse(
ios::AccountReconcilorFactory::GetForProfile(browser_->GetProfile())
->GetState());
if (ShouldShowAccountMenu()) {
ShowAccountMenu(url);
} else {
[settings_handler_
showAccountsSettingsFromViewController:base_view_controller_
skipIfUINotAvailable:YES];
}
}
void AccountConsistencyBrowserAgent::OnShowConsistencyPromo(
const GURL& url,
web::WebState* web_state) {
signin_metrics::LogAccountReconcilorStateOnGaiaResponse(
ios::AccountReconcilorFactory::GetForProfile(browser_->GetProfile())
->GetState());
web::WebState* current_web_state =
browser_->GetWebStateList()->GetActiveWebState();
if (current_web_state == web_state) {
[application_handler_
showWebSigninPromoFromViewController:base_view_controller_
URL:url];
}
}
void AccountConsistencyBrowserAgent::OnAddAccount(
const GURL& url,
const std::string& prefilled_email) {
if ([base_view_controller_ presentedViewController]) {
// If the base view controller is already presenting a view, the sign-in
// should not appear on top of it.
// See http://crbug.com/1399464.
return;
}
if (ShouldShowAccountMenu()) {
ShowAccountMenu(url);
} else {
id<BrowserCoordinatorCommands> browser_coordinator_handler =
HandlerForProtocol(browser_->GetCommandDispatcher(),
BrowserCoordinatorCommands);
signin_metrics::AccessPoint access_point =
signin_metrics::AccessPoint::kAccountConsistencyService;
[browser_coordinator_handler
showAddAccountWithAccessPoint:access_point
prefilledEmail:base::SysUTF8ToNSString(prefilled_email)];
}
}
void AccountConsistencyBrowserAgent::OnGoIncognito(const GURL& url) {
// The user taps on go incognito from the mobile U-turn webpage (the web
// page that displays all users accounts available in the content area). As
// the user chooses to go to incognito, the mobile U-turn page is no longer
// neeeded. The current solution is to go back in history. This has the
// advantage of keeping the current browsing session and give a good user
// experience when the user comes back from incognito.
WebNavigationBrowserAgent::FromBrowser(browser_)->GoBack();
GURL url_to_open;
if (url.is_valid()) {
url_to_open = url;
}
OpenNewTabCommand* command = [[OpenNewTabCommand alloc]
initWithURL:url_to_open
referrer:web::Referrer() // Strip referrer when switching modes.
inIncognito:YES
inBackground:NO
appendTo:OpenPosition::kLastTab];
[application_handler_ openURLInNewTab:command];
}
bool AccountConsistencyBrowserAgent::ShouldShowAccountMenu() const {
if (!AreSeparateProfilesForManagedAccountsEnabled()) {
return false;
}
ProfileIOS* profile = browser_->GetProfile()->GetOriginalProfile();
signin::IdentityManager* identity_manager =
IdentityManagerFactory::GetForProfile(profile);
if (!identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin)) {
// The account menu requires a primary identity.
return false;
}
size_t num_profiles = GetApplicationContext()
->GetProfileManager()
->GetProfileAttributesStorage()
->GetNumberOfProfiles();
// If there are any profiles beside the current one, it's likely the user
// wanted to switch to another profile rather than add/manage accounts.
return num_profiles > 1;
}
void AccountConsistencyBrowserAgent::ShowAccountMenu(const GURL& url) {
CHECK(AreSeparateProfilesForManagedAccountsEnabled());
[application_handler_ showAccountMenuFromWebWithURL:url];
}