blob: 7c646cd27a2ea0a38eeaf9d215da99eb2a889804 [file] [log] [blame]
// Copyright 2015 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.
package org.chromium.chrome.browser.sync.settings;
import android.content.Context;
import android.util.AttributeSet;
import androidx.annotation.IntDef;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.signin.ProfileDataCache;
import org.chromium.chrome.browser.signin.SigninUtils;
import org.chromium.chrome.browser.signin.services.DisplayableProfileData;
import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
import org.chromium.chrome.browser.signin.services.SigninManager.SignInAllowedObserver;
import org.chromium.chrome.browser.sync.AndroidSyncSettings;
import org.chromium.chrome.browser.sync.ProfileSyncService;
import org.chromium.chrome.browser.sync.ProfileSyncService.SyncStateChangedListener;
import org.chromium.components.browser_ui.settings.ManagedPreferencesUtils;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.signin.AccountManagerFacade;
import org.chromium.components.signin.AccountManagerFacadeProvider;
import org.chromium.components.signin.AccountsChangeObserver;
import org.chromium.components.signin.base.CoreAccountInfo;
import org.chromium.components.signin.identitymanager.ConsentLevel;
import org.chromium.components.signin.metrics.SigninAccessPoint;
import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.ui.base.ViewUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
/**
* A preference that displays "Sign in to Chrome" when the user is not sign in, and displays
* the user's name, email, profile image and sync error icon if necessary when the user is signed
* in.
*/
public class SignInPreference
extends Preference implements SignInAllowedObserver, ProfileDataCache.Observer,
AndroidSyncSettings.AndroidSyncSettingsObserver,
SyncStateChangedListener, AccountsChangeObserver {
@IntDef({State.SIGNIN_DISABLED_BY_POLICY, State.SIGNIN_DISALLOWED, State.GENERIC_PROMO,
State.SIGNED_IN})
@Retention(RetentionPolicy.SOURCE)
public @interface State {
int SIGNIN_DISABLED_BY_POLICY = 0;
int SIGNIN_DISALLOWED = 1;
int GENERIC_PROMO = 2;
int SIGNED_IN = 3;
}
private final PrefService mPrefService;
private boolean mWasGenericSigninPromoDisplayed;
private boolean mViewEnabled;
private final ProfileDataCache mProfileDataCache;
private final AccountManagerFacade mAccountManagerFacade;
private @State int mState;
/**
* Constructor for inflating from XML.
*/
public SignInPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.account_management_account_row);
mPrefService = UserPrefs.get(Profile.getLastUsedRegularProfile());
int imageSize = context.getResources().getDimensionPixelSize(R.dimen.user_picture_size);
mProfileDataCache = new ProfileDataCache(context, imageSize);
mAccountManagerFacade = AccountManagerFacadeProvider.getInstance();
// State will be updated in registerForUpdates.
mState = State.SIGNED_IN;
}
@Override
public void onAttached() {
super.onAttached();
mAccountManagerFacade.addObserver(this);
IdentityServicesProvider.get()
.getSigninManager(Profile.getLastUsedRegularProfile())
.addSignInAllowedObserver(this);
mProfileDataCache.addObserver(this);
FirstRunSignInProcessor.updateSigninManagerFirstRunCheckDone();
AndroidSyncSettings.get().registerObserver(this);
ProfileSyncService syncService = ProfileSyncService.get();
if (syncService != null) {
syncService.addSyncStateChangedListener(this);
}
update();
}
@Override
public void onDetached() {
super.onDetached();
mAccountManagerFacade.removeObserver(this);
IdentityServicesProvider.get()
.getSigninManager(Profile.getLastUsedRegularProfile())
.removeSignInAllowedObserver(this);
mProfileDataCache.removeObserver(this);
AndroidSyncSettings.get().unregisterObserver(this);
ProfileSyncService syncService = ProfileSyncService.get();
if (syncService != null) {
syncService.removeSyncStateChangedListener(this);
}
}
/** Returns the state of the preference. Not valid until registerForUpdates is called. */
@State
public int getState() {
return mState;
}
/** Updates the title, summary, and image based on the current sign-in state. */
private void update() {
if (IdentityServicesProvider.get()
.getSigninManager(Profile.getLastUsedRegularProfile())
.isSigninDisabledByPolicy()) {
// TODO(https://crbug.com/1133739): Clean up after revising isSigninDisabledByPolicy.
if (mPrefService.isManagedPreference(Pref.SIGNIN_ALLOWED)) {
setupSigninDisabledByPolicy();
} else {
setupSigninDisallowed();
}
return;
}
CoreAccountInfo accountInfo =
IdentityServicesProvider.get()
.getIdentityManager(Profile.getLastUsedRegularProfile())
.getPrimaryAccountInfo(ConsentLevel.NOT_REQUIRED);
if (accountInfo != null) {
setupSignedIn(accountInfo.getEmail());
return;
}
setupGenericPromo();
}
private void setupSigninDisabledByPolicy() {
mState = State.SIGNIN_DISABLED_BY_POLICY;
if (ChromeFeatureList.isEnabled(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)) {
setTitle(R.string.sync_promo_turn_on_sync);
} else {
setTitle(R.string.sign_in_to_chrome);
}
setSummary(R.string.sign_in_to_chrome_disabled_summary);
setFragment(null);
setIcon(ManagedPreferencesUtils.getManagedByEnterpriseIconId());
setWidgetLayoutResource(0);
setViewEnabled(false);
setOnPreferenceClickListener(pref -> {
ManagedPreferencesUtils.showManagedByAdministratorToast(getContext());
return true;
});
mWasGenericSigninPromoDisplayed = false;
}
private void setupSigninDisallowed() {
// TODO(https://crbug.com/1133743): Revise the preference behavior.
mState = State.SIGNIN_DISALLOWED;
setTitle(R.string.signin_pref_disallowed_title);
setSummary(null);
setFragment(null);
setIcon(AppCompatResources.getDrawable(getContext(), R.drawable.logo_avatar_anonymous));
setWidgetLayoutResource(0);
setViewEnabled(false);
setOnPreferenceClickListener(null);
mWasGenericSigninPromoDisplayed = false;
}
private void setupGenericPromo() {
mState = State.GENERIC_PROMO;
if (ChromeFeatureList.isEnabled(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)) {
setTitle(R.string.sync_promo_turn_on_sync);
} else {
setTitle(R.string.sign_in_to_chrome);
}
setSummary(R.string.signin_pref_summary);
setFragment(null);
setIcon(AppCompatResources.getDrawable(getContext(), R.drawable.logo_avatar_anonymous));
setWidgetLayoutResource(0);
setViewEnabled(true);
setOnPreferenceClickListener(pref
-> SigninUtils.startSigninActivityIfAllowed(
getContext(), SigninAccessPoint.SETTINGS));
if (!mWasGenericSigninPromoDisplayed) {
RecordUserAction.record("Signin_Impression_FromSettings");
}
mWasGenericSigninPromoDisplayed = true;
}
private void setupSignedIn(String accountName) {
mState = State.SIGNED_IN;
mProfileDataCache.update(Collections.singletonList(accountName));
DisplayableProfileData profileData = mProfileDataCache.getProfileDataOrDefault(accountName);
setTitle(profileData.getFullNameOrEmail());
setSummary(accountName);
setFragment(AccountManagementFragment.class.getName());
setIcon(profileData.getImage());
setWidgetLayoutResource(0);
setViewEnabled(true);
setOnPreferenceClickListener(null);
mWasGenericSigninPromoDisplayed = false;
}
// This just changes visual representation. Actual enabled flag in preference stays
// always true to receive clicks (necessary to show "Managed by administrator" toast).
private void setViewEnabled(boolean enabled) {
if (mViewEnabled == enabled) {
return;
}
mViewEnabled = enabled;
notifyChanged();
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
ViewUtils.setEnabledRecursive(holder.itemView, mViewEnabled);
}
// ProfileSyncServiceListener implementation.
@Override
public void syncStateChanged() {
update();
}
// SignInAllowedObserver implementation.
@Override
public void onSignInAllowedChanged() {
update();
}
// ProfileDataCache.Observer implementation.
@Override
public void onProfileDataUpdated(String accountEmail) {
update();
}
// AndroidSyncSettings.AndroidSyncSettingsObserver implementation.
@Override
public void androidSyncSettingsChanged() {
update();
}
// AccountsChangeObserver implementation.
@Override
public void onAccountsChanged() {
update();
}
}