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 |