| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.chrome.browser.signin; | 5 package org.chromium.chrome.browser.signin; |
| 6 | 6 |
| 7 import android.app.DialogFragment; | 7 import android.app.DialogFragment; |
| 8 import android.app.Fragment; | 8 import android.app.Fragment; |
| 9 import android.app.FragmentManager; | 9 import android.app.FragmentManager; |
| 10 import android.content.Context; | 10 import android.content.Context; |
| 11 import android.os.Handler; |
| 11 import android.support.annotation.IntDef; | 12 import android.support.annotation.IntDef; |
| 12 import android.text.TextUtils; | 13 import android.text.TextUtils; |
| 13 | 14 |
| 14 import org.chromium.base.Callback; | 15 import org.chromium.base.Callback; |
| 15 import org.chromium.base.Promise; | 16 import org.chromium.base.ThreadUtils; |
| 16 import org.chromium.chrome.browser.signin.ConfirmImportSyncDataDialog.ImportSync
Type; | 17 import org.chromium.chrome.browser.signin.ConfirmImportSyncDataDialog.ImportSync
Type; |
| 17 | 18 |
| 18 import java.lang.annotation.Retention; | 19 import java.lang.annotation.Retention; |
| 19 import java.lang.annotation.RetentionPolicy; | 20 import java.lang.annotation.RetentionPolicy; |
| 20 | 21 |
| 21 /** | 22 /** |
| 22 * This class takes care of the various dialogs that must be shown when the user
changes the | 23 * This class takes care of the various dialogs that must be shown when the user
changes the |
| 23 * account they are syncing to (either directly, or by signing in to a new accou
nt). Most of the | 24 * account they are syncing to (either directly, or by signing in to a new accou
nt). Most of the |
| 24 * complexity is due to many of the decisions getting answered through callbacks
. | 25 * complexity is due to many of the decisions getting answered through callbacks
. |
| 25 * | 26 * |
| 26 * This class progresses along the following state machine: | 27 * This class progresses along the following state machine: |
| 27 * | 28 * |
| 28 * E----\ G--\ | 29 * E-----\ G--\ |
| 29 * ^ | ^ | | 30 * ^ | ^ | |
| 30 * | | | v | 31 * | v | v |
| 31 * A->B->C->D-+->F->H | 32 * A->B->C->D->+->F->H |
| 32 * | | | 33 * | ^ |
| 33 * \-------/ | 34 * v | |
| 35 * \--------/ |
| 34 * | 36 * |
| 35 * Where: | 37 * Where: |
| 36 * A - Start | 38 * A - Start |
| 37 * B - Decision: progress to C if the user signed in previously to a different a
ccount, F otherwise. | 39 * B - Decision: progress to C if the user signed in previously to a different a
ccount, F otherwise. |
| 38 * C - Decision: progress to E if we are switching from a managed account, D oth
erwise. | 40 * C - Decision: progress to E if we are switching from a managed account, D oth
erwise. |
| 39 * D - Action: show Import Data Dialog. | 41 * D - Action: show Import Data Dialog. |
| 40 * E - Action: show Switching from Managed Account Dialog. | 42 * E - Action: show Switching from Managed Account Dialog. |
| 41 * F - Decision: progress to G if we are switching to a managed account, H other
wise. | 43 * F - Decision: progress to G if we are switching to a managed account, H other
wise. |
| 42 * G - Action: show Switching to Managed Account Dialog. | 44 * G - Action: show Switching to Managed Account Dialog. |
| 43 * H - End: perform {@link ConfirmImportSyncDataDialog.Listener#onConfirm} with
the result of the | 45 * H - End: perform {@link ConfirmImportSyncDataDialog.Listener#onConfirm} with
the result of the |
| 44 * Import Data Dialog, if displayed or true if switching from a managed acco
unt. | 46 * Import Data Dialog, if displayed or true if switching from a managed acco
unt. |
| 45 * | 47 * |
| 46 * At any dialog, the user can cancel the dialog and end the whole process (resu
lting in | 48 * At any dialog, the user can cancel the dialog and end the whole process (resu
lting in |
| 47 * {@link ConfirmImportSyncDataDialog.Listener#onCancel}). | 49 * {@link ConfirmImportSyncDataDialog.Listener#onCancel}). |
| 48 */ | 50 */ |
| 49 public class ConfirmSyncDataStateMachine | 51 public class ConfirmSyncDataStateMachine |
| 50 implements ConfirmImportSyncDataDialog.Listener, ConfirmManagedSyncDataD
ialog.Listener { | 52 implements ConfirmImportSyncDataDialog.Listener, ConfirmManagedSyncDataD
ialog.Listener { |
| 51 | |
| 52 @IntDef({ | |
| 53 BEFORE_OLD_ACCOUNT_DIALOG, BEFORE_NEW_ACCOUNT_DIALOG, | |
| 54 AFTER_NEW_ACCOUNT_DIALOG, DONE | |
| 55 }) | |
| 56 @Retention(RetentionPolicy.SOURCE) | 53 @Retention(RetentionPolicy.SOURCE) |
| 54 @IntDef({BEFORE_OLD_ACCOUNT_DIALOG, BEFORE_NEW_ACCOUNT_DIALOG, AFTER_NEW_ACC
OUNT_DIALOG, DONE}) |
| 57 private @interface State {} | 55 private @interface State {} |
| 58 private static final int BEFORE_OLD_ACCOUNT_DIALOG = 0; // Start of state B
. | 56 private static final int BEFORE_OLD_ACCOUNT_DIALOG = 0; // Start of state B
. |
| 59 private static final int BEFORE_NEW_ACCOUNT_DIALOG = 1; // Start of state F
. | 57 private static final int BEFORE_NEW_ACCOUNT_DIALOG = 1; // Start of state F
. |
| 60 private static final int AFTER_NEW_ACCOUNT_DIALOG = 2; // Start of state H
. | 58 private static final int AFTER_NEW_ACCOUNT_DIALOG = 2; // Start of state H
. |
| 61 private static final int DONE = 4; | 59 private static final int DONE = 4; |
| 62 | 60 |
| 63 private boolean mWipeData; | |
| 64 @State private int mState = BEFORE_OLD_ACCOUNT_DIALOG; | 61 @State private int mState = BEFORE_OLD_ACCOUNT_DIALOG; |
| 65 | 62 |
| 63 private static final int ACCOUNT_CHECK_TIMEOUT_MS = 30000; |
| 64 |
| 66 private final ConfirmImportSyncDataDialog.Listener mCallback; | 65 private final ConfirmImportSyncDataDialog.Listener mCallback; |
| 67 private final String mOldAccountName; | 66 private final String mOldAccountName; |
| 68 private final String mNewAccountName; | 67 private final String mNewAccountName; |
| 69 private final boolean mCurrentlyManaged; | 68 private final boolean mCurrentlyManaged; |
| 70 private final Promise<Boolean> mNewAccountManaged = new Promise<>(); | |
| 71 private final FragmentManager mFragmentManager; | 69 private final FragmentManager mFragmentManager; |
| 72 private final Context mContext; | 70 private final Context mContext; |
| 73 private final ImportSyncType mImportSyncType; | 71 private final ImportSyncType mImportSyncType; |
| 72 private final ConfirmSyncDataStateMachineDelegate mDelegate; |
| 73 private final Handler mHandler = new Handler(); |
| 74 |
| 75 private boolean mWipeData; |
| 76 private Boolean mNewAccountManaged; |
| 77 private Runnable mCheckTimeoutRunnable; |
| 74 | 78 |
| 75 /** | 79 /** |
| 76 * Run this state machine, displaying the appropriate dialogs. | 80 * Run this state machine, displaying the appropriate dialogs. |
| 77 * @param callback One of the two functions of the {@link ConfirmImportSyncD
ataDialog.Listener} | 81 * @param callback One of the two functions of the {@link ConfirmImportSyncD
ataDialog.Listener} |
| 78 * are guaranteed to be called. | 82 * are guaranteed to be called. |
| 79 */ | 83 */ |
| 80 public static void run(String oldAccountName, String newAccountName, | 84 public static void run(String oldAccountName, String newAccountName, |
| 81 ImportSyncType importSyncType, FragmentManager fragmentManager, Cont
ext context, | 85 ImportSyncType importSyncType, FragmentManager fragmentManager, Cont
ext context, |
| 82 ConfirmImportSyncDataDialog.Listener callback) { | 86 ConfirmImportSyncDataDialog.Listener callback) { |
| 83 // Includes implicit not-null assertion. | 87 // Includes implicit not-null assertion. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 106 if (fragment == null) return; | 110 if (fragment == null) return; |
| 107 DialogFragment dialogFragment = (DialogFragment) fragment; | 111 DialogFragment dialogFragment = (DialogFragment) fragment; |
| 108 | 112 |
| 109 if (dialogFragment.getDialog() == null) return; | 113 if (dialogFragment.getDialog() == null) return; |
| 110 dialogFragment.getDialog().cancel(); | 114 dialogFragment.getDialog().cancel(); |
| 111 } | 115 } |
| 112 | 116 |
| 113 private ConfirmSyncDataStateMachine(String oldAccountName, String newAccount
Name, | 117 private ConfirmSyncDataStateMachine(String oldAccountName, String newAccount
Name, |
| 114 ImportSyncType importSyncType, FragmentManager fragmentManager, Cont
ext context, | 118 ImportSyncType importSyncType, FragmentManager fragmentManager, Cont
ext context, |
| 115 ConfirmImportSyncDataDialog.Listener callback) { | 119 ConfirmImportSyncDataDialog.Listener callback) { |
| 120 ThreadUtils.assertOnUiThread(); |
| 121 |
| 116 mOldAccountName = oldAccountName; | 122 mOldAccountName = oldAccountName; |
| 117 mNewAccountName = newAccountName; | 123 mNewAccountName = newAccountName; |
| 118 mImportSyncType = importSyncType; | 124 mImportSyncType = importSyncType; |
| 119 mFragmentManager = fragmentManager; | 125 mFragmentManager = fragmentManager; |
| 120 mContext = context; | 126 mContext = context; |
| 121 mCallback = callback; | 127 mCallback = callback; |
| 122 | 128 |
| 123 mCurrentlyManaged = SigninManager.get(context).getManagementDomain() !=
null; | 129 mCurrentlyManaged = SigninManager.get(context).getManagementDomain() !=
null; |
| 124 | 130 |
| 125 // This check isn't needed right now, but can take a few seconds, so we
kick it off early. | 131 mDelegate = new ConfirmSyncDataStateMachineDelegate(mContext); |
| 126 SigninManager.isUserManaged(mNewAccountName, mNewAccountManaged.fulfillm
entCallback()); | 132 |
| 133 // New account management status isn't needed right now, but fetching it |
| 134 // can take a few seconds, so we kick it off early. |
| 135 requestNewAccountManagementStatus(); |
| 127 } | 136 } |
| 128 | 137 |
| 129 /** | 138 /** |
| 130 * This will progress the state machine, by moving the state along and then
by either calling | 139 * This will progress the state machine, by moving the state along and then
by either calling |
| 131 * itself directly or creating a dialog. If the dialog is dismissed or answe
red negatively the | 140 * itself directly or creating a dialog. If the dialog is dismissed or answe
red negatively the |
| 132 * entire flow is over, if it is answered positively one of the onConfirm fu
nctions is called | 141 * entire flow is over, if it is answered positively one of the onConfirm fu
nctions is called |
| 133 * and this function is called again. | 142 * and this function is called again. |
| 134 */ | 143 */ |
| 135 private void progress() { | 144 private void progress() { |
| 136 switch (mState) { | 145 switch (mState) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 155 mOldAccountName, mNewAccountName); | 164 mOldAccountName, mNewAccountName); |
| 156 } else { | 165 } else { |
| 157 // This will call back into onConfirm(boolean wipeData) on s
uccess. | 166 // This will call back into onConfirm(boolean wipeData) on s
uccess. |
| 158 ConfirmImportSyncDataDialog.showNewInstance(mOldAccountName,
mNewAccountName, | 167 ConfirmImportSyncDataDialog.showNewInstance(mOldAccountName,
mNewAccountName, |
| 159 mImportSyncType, mFragmentManager, this); | 168 mImportSyncType, mFragmentManager, this); |
| 160 } | 169 } |
| 161 | 170 |
| 162 break; | 171 break; |
| 163 case BEFORE_NEW_ACCOUNT_DIALOG: | 172 case BEFORE_NEW_ACCOUNT_DIALOG: |
| 164 mState = AFTER_NEW_ACCOUNT_DIALOG; | 173 mState = AFTER_NEW_ACCOUNT_DIALOG; |
| 165 | 174 if (mNewAccountManaged != null) { |
| 166 mNewAccountManaged.then(new Callback<Boolean>() { | 175 // No need to show dialog if account management status is al
ready known |
| 167 @Override | 176 handleNewAccountManagementStatus(); |
| 168 public void onResult(Boolean newAccountManaged) { | 177 } else { |
| 169 if (newAccountManaged) { | 178 showProgressDialog(); |
| 170 // Show 'logging into managed account' dialog | 179 scheduleTimeout(); |
| 171 // This will call back into onConfirm on success. | 180 } |
| 172 ConfirmManagedSyncDataDialog.showSignInToManagedAcco
untDialog( | |
| 173 ConfirmSyncDataStateMachine.this, | |
| 174 mFragmentManager, mContext.getResources(), | |
| 175 SigninManager.extractDomainName(mNewAccountN
ame)); | |
| 176 } else { | |
| 177 progress(); | |
| 178 } | |
| 179 } | |
| 180 }); | |
| 181 | |
| 182 break; | 181 break; |
| 183 case AFTER_NEW_ACCOUNT_DIALOG: | 182 case AFTER_NEW_ACCOUNT_DIALOG: |
| 184 mState = DONE; | 183 mState = DONE; |
| 185 mCallback.onConfirm(mWipeData); | 184 mCallback.onConfirm(mWipeData); |
| 186 break; | 185 break; |
| 187 case DONE: | 186 case DONE: |
| 188 throw new IllegalStateException("Can't progress from DONE state!
"); | 187 throw new IllegalStateException("Can't progress from DONE state!
"); |
| 189 } | 188 } |
| 190 } | 189 } |
| 191 | 190 |
| 191 private void requestNewAccountManagementStatus() { |
| 192 SigninManager.isUserManaged(mNewAccountName, new Callback<Boolean>() { |
| 193 @Override |
| 194 public void onResult(Boolean result) { |
| 195 setIsNewAccountManaged(result); |
| 196 } |
| 197 }); |
| 198 } |
| 199 |
| 200 private void setIsNewAccountManaged(Boolean isManaged) { |
| 201 assert isManaged != null; |
| 202 mNewAccountManaged = isManaged; |
| 203 if (mState == AFTER_NEW_ACCOUNT_DIALOG) { |
| 204 cancelTimeout(); |
| 205 handleNewAccountManagementStatus(); |
| 206 } |
| 207 } |
| 208 |
| 209 private void handleNewAccountManagementStatus() { |
| 210 assert mNewAccountManaged != null; |
| 211 assert mState == AFTER_NEW_ACCOUNT_DIALOG; |
| 212 |
| 213 mDelegate.dismissAllDialogs(); |
| 214 |
| 215 if (mNewAccountManaged) { |
| 216 // Show 'logging into managed account' dialog |
| 217 // This will call back into onConfirm on success. |
| 218 ConfirmManagedSyncDataDialog.showSignInToManagedAccountDialog( |
| 219 ConfirmSyncDataStateMachine.this, mFragmentManager, mContext
.getResources(), |
| 220 SigninManager.extractDomainName(mNewAccountName)); |
| 221 } else { |
| 222 progress(); |
| 223 } |
| 224 } |
| 225 |
| 226 private void showProgressDialog() { |
| 227 mDelegate.showFetchManagementPolicyProgressDialog( |
| 228 new ConfirmSyncDataStateMachineDelegate.ProgressDialogListener()
{ |
| 229 @Override |
| 230 public void onCancel() { |
| 231 ConfirmSyncDataStateMachine.this.onCancel(); |
| 232 } |
| 233 }); |
| 234 } |
| 235 |
| 236 private void scheduleTimeout() { |
| 237 if (mCheckTimeoutRunnable == null) { |
| 238 mCheckTimeoutRunnable = new Runnable() { |
| 239 @Override |
| 240 public void run() { |
| 241 checkTimeout(); |
| 242 } |
| 243 }; |
| 244 } |
| 245 mHandler.postDelayed(mCheckTimeoutRunnable, ACCOUNT_CHECK_TIMEOUT_MS); |
| 246 } |
| 247 |
| 248 private void cancelTimeout() { |
| 249 if (mCheckTimeoutRunnable == null) { |
| 250 return; |
| 251 } |
| 252 mHandler.removeCallbacks(mCheckTimeoutRunnable); |
| 253 mCheckTimeoutRunnable = null; |
| 254 } |
| 255 |
| 256 private void checkTimeout() { |
| 257 assert mState == AFTER_NEW_ACCOUNT_DIALOG; |
| 258 assert mNewAccountManaged == null; |
| 259 |
| 260 mDelegate.showFetchManagementPolicyTimeoutDialog( |
| 261 new ConfirmSyncDataStateMachineDelegate.TimeoutDialogListener()
{ |
| 262 @Override |
| 263 public void onCancel() { |
| 264 ConfirmSyncDataStateMachine.this.onCancel(); |
| 265 } |
| 266 |
| 267 @Override |
| 268 public void onRetry() { |
| 269 requestNewAccountManagementStatus(); |
| 270 scheduleTimeout(); |
| 271 } |
| 272 }); |
| 273 } |
| 274 |
| 192 // ConfirmImportSyncDataDialog.Listener implementation. | 275 // ConfirmImportSyncDataDialog.Listener implementation. |
| 193 @Override | 276 @Override |
| 194 public void onConfirm(boolean wipeData) { | 277 public void onConfirm(boolean wipeData) { |
| 195 mWipeData = wipeData; | 278 mWipeData = wipeData; |
| 196 progress(); | 279 progress(); |
| 197 } | 280 } |
| 198 | 281 |
| 199 // ConfirmManagedSyncDataDialog.Listener implementation. | 282 // ConfirmManagedSyncDataDialog.Listener implementation. |
| 200 @Override | 283 @Override |
| 201 public void onConfirm() { | 284 public void onConfirm() { |
| 202 progress(); | 285 progress(); |
| 203 } | 286 } |
| 204 | 287 |
| 205 // ConfirmImportSyncDataDialog.Listener & ConfirmManagedSyncDataDialog.Liste
ner implementation. | 288 // ConfirmImportSyncDataDialog.Listener & ConfirmManagedSyncDataDialog.Liste
ner implementation. |
| 206 @Override | 289 @Override |
| 207 public void onCancel() { | 290 public void onCancel() { |
| 291 cancelTimeout(); |
| 292 mDelegate.dismissAllDialogs(); |
| 293 |
| 208 mState = DONE; | 294 mState = DONE; |
| 209 mCallback.onCancel(); | 295 mCallback.onCancel(); |
| 210 } | 296 } |
| 211 } | 297 } |
| 212 | 298 |
| OLD | NEW |