// 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. package org.chromium.chrome.browser.sync; import android.app.Activity; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.text.TextUtils; import org.chromium.base.Callback; import org.chromium.base.Promise; import org.chromium.chrome.browser.preferences.SyncedAccountPreference; import org.chromium.chrome.browser.signin.ConfirmImportSyncDataDialog; import org.chromium.chrome.browser.signin.ConfirmImportSyncDataDialog.ImportSyncType; import org.chromium.chrome.browser.signin.ConfirmSyncDataStateMachine; import org.chromium.chrome.browser.signin.SigninManager; import org.chromium.chrome.browser.signin.SigninManager.SignInCallback; /** * A class that encapsulates the control flow of listeners and callbacks when switching sync * accounts. * * Control flows through the method in this order: * {@link OnPreferenceChangeListener#onPreferenceChange} * {@link ConfirmImportSyncDataDialog.Listener#onConfirm} * {@link SignInCallback#onSignInComplete} */ public class SyncAccountSwitcher implements OnPreferenceChangeListener, ConfirmImportSyncDataDialog.Listener, SignInCallback { private static final String TAG = "SyncAccountSwitcher"; private final SyncedAccountPreference mSyncedAccountPreference; private final Activity mActivity; private String mNewAccountName; /** * Sets up a SyncAccountSwitcher to be ready to accept callbacks. * @param activity Activity used to get the context for signin and get the fragmentManager * for the data sync fragment. * @param syncedAccountPreference The preference to update once signin has been completed. */ public SyncAccountSwitcher(Activity activity, SyncedAccountPreference syncedAccountPreference) { mActivity = activity; mSyncedAccountPreference = syncedAccountPreference; } @Override public boolean onPreferenceChange(Preference p, Object newValue) { if (newValue == null) return false; mNewAccountName = (String) newValue; String currentAccount = mSyncedAccountPreference.getValue(); if (TextUtils.equals(mNewAccountName, currentAccount)) return false; ConfirmSyncDataStateMachine.run(currentAccount, mNewAccountName, ImportSyncType.SWITCHING_SYNC_ACCOUNTS, mActivity.getFragmentManager(), mActivity, this); // Don't update the selected account in the preference. It will be updated by // the call to mSyncAccountListPreference.update() if everything succeeds. return false; } @Override public void onConfirm(final boolean wipeData) { assert mNewAccountName != null; // Sign out first to ensure we don't wipe the data when sync is still on. SigninManager.get(mActivity).signOutPromise() .then(new Promise.AsyncFunction<Void, Void>(){ @Override public Promise<Void> apply(Void argument) { // Once signed out, clear the last signed in user and wipe data if needed. SigninManager.get(mActivity).clearLastSignedInUser(); return SigninManager.wipeSyncUserDataIfRequired(wipeData); } }).then(new Callback<Void>(){ @Override public void onResult(Void result) { // Once the data has been wiped (if needed), sign in to the next account. SigninManager.get(mActivity) .signIn(mNewAccountName, mActivity, SyncAccountSwitcher.this); } }); } @Override public void onCancel() { // The user aborted the 'merge data' dialog, there is nothing to do. } @Override public void onSignInComplete() { // Update the Preference so it displays the correct account name. mSyncedAccountPreference.update(); } @Override public void onSignInAborted() { // If the user aborted signin, there is nothing to do. } }