Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/sync/ui/ConfirmSyncDataStateMachine.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/ConfirmSyncDataStateMachine.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/ConfirmSyncDataStateMachine.java |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d1bba6cc8f3f79b7842c86c758e2efabb4ad6a7b |
| --- /dev/null |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/ConfirmSyncDataStateMachine.java |
| @@ -0,0 +1,196 @@ |
| +// 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.ui; |
| + |
| +import android.app.FragmentManager; |
| +import android.content.Context; |
| +import android.text.TextUtils; |
| + |
| +import org.chromium.base.Callback; |
| +import org.chromium.chrome.browser.signin.SigninManager; |
| +import org.chromium.chrome.browser.sync.ui.ConfirmImportSyncDataDialog.ImportSyncType; |
| + |
| +/** |
| + * This class takes care of the various dialogs that must be shown when the user changes the |
| + * account they are syncing to (either directly, or by signing in to a new account). Most of the |
| + * complexity is due to many of the decisions getting answered through callbacks. |
| + * |
| + * This class progresses along the following state machine: |
| + * |
| + * E----\ H--\ |
| + * ^ | ^ | |
| + * | | | v |
| + * A->B->C->D-+->F->G->I |
| + * | | |
| + * \-------/ |
| + * |
| + * Where: |
| + * A - Start |
| + * B - Decision: progress to C if the user signed in previously to a different account, F otherwise. |
| + * C - Decision: progress to E if we are switching from a managed account, D otherwise. |
| + * D - Action: show Import Data Dialog. |
| + * E - Action: show Switching from Managed Account Dialog. |
| + * F - Action: start the asynchronous request to check if the next account is managed. |
| + * G - Decision: progress to H if we are switching to a managed account, I otherwise. |
| + * H - Action: show Switching to Managed Account Dialog. |
| + * I - End: perform {@link ConfirmImportSyncDataDialog.Listener#onConfirm} with the result of the |
| + * Import Data Dialog, if displayed or true if switching from a managed account. |
| + * |
| + * At any dialog, the user can cancel the dialog and end the whole process (resulting in |
| + * {@link ConfirmImportSyncDataDialog.Listener#onCancel}). |
| + */ |
| +public class ConfirmSyncDataStateMachine |
| + implements ConfirmImportSyncDataDialog.Listener, ConfirmManagedSyncDataDialog.Listener { |
| + private enum State { |
| + BEFORE_OLD_ACCOUNT_DIALOG, // Start of state B. |
| + AFTER_OLD_ACCOUNT_DIALOG, // Start of state F. |
| + BEFORE_NEW_ACCOUNT_DIALOG, // Start of state G. |
| + AFTER_NEW_ACCOUNT_DIALOG, // Start of state I. |
| + DONE |
| + } |
| + |
| + private boolean mWipeData; |
| + private State mState = State.BEFORE_OLD_ACCOUNT_DIALOG; |
| + |
| + private final ConfirmImportSyncDataDialog.Listener mCallback; |
| + private final String mOldAccountName; |
| + private final String mNewAccountName; |
| + private final boolean mCurrentlyManaged; |
| + private boolean mNewAccountManaged; |
| + private final FragmentManager mFragmentManager; |
| + private final Context mContext; |
| + private final ImportSyncType mImportSyncType; |
| + |
| + /** |
| + * Run this state machine, displaying the appropriate dialogs. |
| + * @param callback One of the two functions of the {@link ConfirmImportSyncDataDialog.Listener} |
| + * are guaranteed to be called. |
| + */ |
| + public static void run(String oldAccountName, String newAccountName, |
| + ImportSyncType importSyncType, FragmentManager fragmentManager, Context context, |
| + ConfirmImportSyncDataDialog.Listener callback) { |
| + ConfirmSyncDataStateMachine stateMachine = new ConfirmSyncDataStateMachine(oldAccountName, |
| + newAccountName, importSyncType, fragmentManager, context, callback); |
| + stateMachine.progress(); |
| + } |
| + |
| + private ConfirmSyncDataStateMachine(String oldAccountName, String newAccountName, |
| + ImportSyncType importSyncType, FragmentManager fragmentManager, Context context, |
| + ConfirmImportSyncDataDialog.Listener callback) { |
| + mOldAccountName = oldAccountName; |
| + mNewAccountName = newAccountName; |
| + mImportSyncType = importSyncType; |
| + mFragmentManager = fragmentManager; |
| + mContext = context; |
| + mCallback = callback; |
| + |
| + mCurrentlyManaged = SigninManager.get(context).getManagementDomain() != null; |
| + |
| + // TODO(peconn): Kick off the mNewAccountManaged check here. |
| + } |
| + |
| + private static String getDomain(String email) { |
| + // Assumes that the email is of the form user@domain.com, and returns Domain. |
|
Bernhard Bauer
2016/06/03 08:50:06
This should use (the native) gaia::ExtractDomainNa
PEConn
2016/06/27 09:34:32
Done.
|
| + int start = email.indexOf('@') + 1; |
| + int end = email.lastIndexOf('.'); |
|
Bernhard Bauer
2016/06/03 08:50:06
This is also a bit weird. For user@example.co.uk,
PEConn
2016/06/27 09:34:33
Why did you think 'Example.co' - it returns 'Examp
Bernhard Bauer
2016/06/29 10:51:26
But it's _last_ index of, and the last index in `u
|
| + return Character.toUpperCase(email.charAt(start)) + email.substring(start + 1, end); |
| + } |
| + |
| + /** |
| + * This will progress the state machine, by moving the state along and then by either calling |
| + * itself directly or creating a dialog. If the dialog is dismissed or answered negatively, the |
|
Bernhard Bauer
2016/06/03 08:50:06
Nit: remove the command after "negatively" (or add
PEConn
2016/06/27 09:34:33
Done.
|
| + * entire flow is over, if it is answered positively one of the onConfirm functions is called |
| + * and this function is called again. |
| + */ |
| + private void progress() { |
| + switch (mState) { |
| + case BEFORE_OLD_ACCOUNT_DIALOG: |
| + mState = State.AFTER_OLD_ACCOUNT_DIALOG; |
| + |
| + if (TextUtils.isEmpty(mOldAccountName) || mOldAccountName == mNewAccountName) { |
| + // If there is no old account or the user is just logging back into whatever |
| + // they were previously logged in as, progress past the old account checks. |
| + progress(); |
| + } else if (mCurrentlyManaged |
| + && mImportSyncType == ImportSyncType.SWITCHING_SYNC_ACCOUNTS) { |
| + // We only care about the user's previous account being managed if they are |
| + // switching accounts. |
| + |
| + mWipeData = true; |
| + |
| + // This will call back into onConfirm() on success. |
| + ConfirmManagedSyncDataDialog.showSwitchFromManagedAccountDialog(this, |
| + mFragmentManager, mContext.getResources(), |
| + getDomain(mOldAccountName), mOldAccountName, mNewAccountName); |
| + } else { |
| + // This will call back into onConfirm(boolean wipeData) on success. |
| + ConfirmImportSyncDataDialog.showNewInstance(mOldAccountName, mNewAccountName, |
| + mImportSyncType, mFragmentManager, this); |
| + } |
| + |
| + break; |
| + case AFTER_OLD_ACCOUNT_DIALOG: |
| + mState = State.BEFORE_NEW_ACCOUNT_DIALOG; |
| + |
| + // We can shortcut the account management step since we know certain domains are |
| + // not going to be managed (eg, gmail, hotmail, yahoo). |
| + if (SigninManager.couldUserBeManaged(mNewAccountName)) { |
|
Bernhard Bauer
2016/06/03 08:50:06
You could also move this into fetchManagementDomai
PEConn
2016/06/27 09:34:32
Done.
|
| + |
|
Bernhard Bauer
2016/06/03 08:50:06
Remove the empty line.
PEConn
2016/06/27 09:34:32
Done.
|
| + SigninManager.fetchManagementDomain(mNewAccountName, new Callback<String>(){ |
| + @Override |
| + public void onResult(String result) { |
| + mNewAccountManaged = !TextUtils.isEmpty(result); |
| + progress(); |
| + } |
| + }); |
| + } else { |
| + mNewAccountManaged = false; |
| + progress(); |
| + } |
| + |
| + break; |
| + case BEFORE_NEW_ACCOUNT_DIALOG: |
| + mState = State.AFTER_NEW_ACCOUNT_DIALOG; |
| + |
| + if (mNewAccountManaged) { |
| + // Show 'logging into managed account' dialog |
| + // This will call back into onConfirm on success. |
| + ConfirmManagedSyncDataDialog.showSignInToManagedAccountDialog(this, |
| + mFragmentManager, mContext.getResources(), getDomain(mNewAccountName)); |
| + } else { |
| + // Go to the next state. |
| + progress(); |
| + } |
| + |
| + break; |
| + case AFTER_NEW_ACCOUNT_DIALOG: |
| + mState = State.DONE; |
| + mCallback.onConfirm(mWipeData); |
| + break; |
| + default: |
|
Bernhard Bauer
2016/06/03 08:50:06
Could you just list the remaining value here?
PEConn
2016/06/27 09:34:32
Done.
|
| + assert false : "Invalid state"; |
| + } |
| + } |
| + |
| + // ConfirmImportSyncDataDialog.Listener implementation. |
| + @Override |
| + public void onConfirm(boolean wipeData) { |
| + mWipeData = wipeData; |
| + progress(); |
| + } |
| + |
| + // ConfirmManagedSyncDataDialog.Listener implementation. |
| + @Override |
| + public void onConfirm() { |
| + progress(); |
| + } |
| + |
| + // ConfirmImportSyncDataDialog.Listener & ConfirmManagedSyncDataDialog.Listener implementation. |
| + @Override |
| + public void onCancel() { |
| + mCallback.onCancel(); |
|
Bernhard Bauer
2016/06/03 08:50:06
You could also transition to the DONE state here,
PEConn
2016/06/27 09:34:32
Done.
|
| + } |
| +} |
| + |