// 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.preferences;
import android.accounts.Account;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.preference.Preference;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.firstrun.FirstRunSignInProcessor;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.profiles.ProfileDownloader;
import org.chromium.chrome.browser.signin.AccountManagementFragment;
import org.chromium.chrome.browser.signin.AccountSigninActivity;
import org.chromium.chrome.browser.signin.SigninAccessPoint;
import org.chromium.chrome.browser.signin.SigninManager;
import org.chromium.chrome.browser.signin.SigninManager.SignInAllowedObserver;
import org.chromium.chrome.browser.sync.ProfileSyncService;
import org.chromium.chrome.browser.sync.ProfileSyncService.SyncStateChangedListener;
import org.chromium.components.signin.ChromeSigninController;
import org.chromium.components.sync.AndroidSyncSettings;
/**
* 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, ProfileDownloader.Observer,
AndroidSyncSettings.AndroidSyncSettingsObserver, SyncStateChangedListener {
private boolean mViewEnabled;
/**
* Constructor for inflating from XML.
*/
public SignInPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setShouldDisableView(false);
update();
}
/**
* Starts listening for updates to the sign-in and sync state.
*/
public void registerForUpdates() {
SigninManager manager = SigninManager.get(getContext());
manager.addSignInAllowedObserver(this);
ProfileDownloader.addObserver(this);
FirstRunSignInProcessor.updateSigninManagerFirstRunCheckDone(getContext());
AndroidSyncSettings.registerObserver(getContext(), this);
ProfileSyncService syncService = ProfileSyncService.get();
if (syncService != null) {
syncService.addSyncStateChangedListener(this);
}
}
/**
* Stops listening for updates to the sign-in and sync state. Every call to registerForUpdates()
* must be matched with a call to this method.
*/
public void unregisterForUpdates() {
SigninManager manager = SigninManager.get(getContext());
manager.removeSignInAllowedObserver(this);
ProfileDownloader.removeObserver(this);
AndroidSyncSettings.unregisterObserver(getContext(), this);
ProfileSyncService syncService = ProfileSyncService.get();
if (syncService != null) {
syncService.removeSyncStateChangedListener(this);
}
}
/**
* Updates the title, summary, and image based on the current sign-in state.
*/
private void update() {
String title;
String summary;
String fragment;
Account account = ChromeSigninController.get(getContext()).getSignedInUser();
if (account == null) {
title = getContext().getString(R.string.sign_in_to_chrome);
summary = getContext().getString(R.string.sign_in_to_chrome_summary);
fragment = null;
} else {
summary = SyncPreference.getSyncStatusSummary(getContext());
fragment = AccountManagementFragment.class.getName();
title = AccountManagementFragment.getCachedUserName(account.name);
if (title == null) {
final Profile profile = Profile.getLastUsedProfile();
String cachedName = ProfileDownloader.getCachedFullName(profile);
Bitmap cachedBitmap = ProfileDownloader.getCachedAvatar(profile);
if (TextUtils.isEmpty(cachedName) || cachedBitmap == null) {
AccountManagementFragment.startFetchingAccountInformation(
getContext(), profile, account.name);
}
title = TextUtils.isEmpty(cachedName) ? account.name : cachedName;
}
}
setTitle(title);
setSummary(summary);
setFragment(fragment);
updateSyncStatusIcon();
ChromeSigninController signinController = ChromeSigninController.get(getContext());
boolean enabled = signinController.isSignedIn()
|| SigninManager.get(getContext()).isSignInAllowed();
if (mViewEnabled != enabled) {
mViewEnabled = enabled;
notifyChanged();
}
if (!enabled) setFragment(null);
if (SigninManager.get(getContext()).isSigninDisabledByPolicy()) {
setIcon(ManagedPreferencesUtils.getManagedByEnterpriseIconId());
} else {
Resources resources = getContext().getResources();
Bitmap bitmap = AccountManagementFragment.getUserPicture(
signinController.getSignedInAccountName(), resources);
setIcon(new BitmapDrawable(resources, bitmap));
}
setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
if (!AccountSigninActivity.startIfAllowed(
getContext(), SigninAccessPoint.SETTINGS)) {
return false;
}
setEnabled(false);
return true;
}
});
if (account == null && enabled) {
RecordUserAction.record("Signin_Impression_FromSettings");
}
}
private void updateSyncStatusIcon() {
if (SyncPreference.showSyncErrorIcon(getContext())
&& ChromeSigninController.get(getContext()).isSignedIn()) {
setWidgetLayoutResource(R.layout.sync_error_widget);
} else {
setWidgetLayoutResource(0);
}
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
view.setEnabled(mViewEnabled);
view.findViewById(android.R.id.title).setEnabled(mViewEnabled);
view.findViewById(android.R.id.summary).setEnabled(mViewEnabled);
}
// ProfileSyncServiceListener implementation:
@Override
public void syncStateChanged() {
update();
}
// SignInAllowedObserver
@Override
public void onSignInAllowedChanged() {
update();
}
// ProfileDownloader.Observer
@Override
public void onProfileDownloaded(String accountId, String fullName, String givenName,
Bitmap bitmap) {
AccountManagementFragment.updateUserNamePictureCache(accountId, fullName, bitmap);
update();
}
// AndroidSyncSettings.AndroidSyncSettingsObserver
@Override
public void androidSyncSettingsChanged() {
update();
}
}