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.support.annotation.IntDef; | 11 import android.support.annotation.IntDef; |
12 import android.text.TextUtils; | 12 import android.text.TextUtils; |
13 | 13 |
14 import org.chromium.base.Callback; | 14 import org.chromium.base.Callback; |
15 import org.chromium.base.Promise; | 15 import org.chromium.base.ThreadUtils; |
16 import org.chromium.chrome.browser.signin.ConfirmImportSyncDataDialog.ImportSync Type; | 16 import org.chromium.chrome.browser.signin.ConfirmImportSyncDataDialog.ImportSync Type; |
17 | 17 |
18 import java.lang.annotation.Retention; | 18 import java.lang.annotation.Retention; |
19 import java.lang.annotation.RetentionPolicy; | 19 import java.lang.annotation.RetentionPolicy; |
20 | 20 |
21 /** | 21 /** |
22 * This class takes care of the various dialogs that must be shown when the user changes the | 22 * 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 | 23 * 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 . | 24 * complexity is due to many of the decisions getting answered through callbacks . |
25 * | 25 * |
26 * This class progresses along the following state machine: | 26 * This class progresses along the following state machine: |
27 * | 27 * |
28 * E----\ G--\ | 28 * E-----\ G--\ |
29 * ^ | ^ | | 29 * ^ | ^ | |
30 * | | | v | 30 * | v | v |
31 * A->B->C->D-+->F->H | 31 * A->B->C->D->+->F->H |
32 * | | | 32 * | ^ |
33 * \-------/ | 33 * v | |
34 * \--------/ | |
34 * | 35 * |
35 * Where: | 36 * Where: |
36 * A - Start | 37 * A - Start |
37 * B - Decision: progress to C if the user signed in previously to a different a ccount, F otherwise. | 38 * 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. | 39 * C - Decision: progress to E if we are switching from a managed account, D oth erwise. |
39 * D - Action: show Import Data Dialog. | 40 * D - Action: show Import Data Dialog. |
40 * E - Action: show Switching from Managed Account Dialog. | 41 * 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. | 42 * 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. | 43 * G - Action: show Switching to Managed Account Dialog. |
43 * H - End: perform {@link ConfirmImportSyncDataDialog.Listener#onConfirm} with the result of the | 44 * 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. | 45 * Import Data Dialog, if displayed or true if switching from a managed acco unt. |
45 * | 46 * |
46 * At any dialog, the user can cancel the dialog and end the whole process (resu lting in | 47 * At any dialog, the user can cancel the dialog and end the whole process (resu lting in |
47 * {@link ConfirmImportSyncDataDialog.Listener#onCancel}). | 48 * {@link ConfirmImportSyncDataDialog.Listener#onCancel}). |
48 */ | 49 */ |
49 public class ConfirmSyncDataStateMachine | 50 public class ConfirmSyncDataStateMachine |
50 implements ConfirmImportSyncDataDialog.Listener, ConfirmManagedSyncDataD ialog.Listener { | 51 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) | 52 @Retention(RetentionPolicy.SOURCE) |
53 @IntDef({BEFORE_OLD_ACCOUNT_DIALOG, BEFORE_NEW_ACCOUNT_DIALOG, AFTER_NEW_ACC OUNT_DIALOG, DONE}) | |
57 private @interface State {} | 54 private @interface State {} |
58 private static final int BEFORE_OLD_ACCOUNT_DIALOG = 0; // Start of state B . | 55 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 . | 56 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 . | 57 private static final int AFTER_NEW_ACCOUNT_DIALOG = 2; // Start of state H . |
61 private static final int DONE = 4; | 58 private static final int DONE = 4; |
62 | 59 |
63 private boolean mWipeData; | |
64 @State private int mState = BEFORE_OLD_ACCOUNT_DIALOG; | 60 @State private int mState = BEFORE_OLD_ACCOUNT_DIALOG; |
65 | 61 |
62 private static final int ACCOUNT_CHECK_TIMEOUT_MS = 30000; | |
63 | |
66 private final ConfirmImportSyncDataDialog.Listener mCallback; | 64 private final ConfirmImportSyncDataDialog.Listener mCallback; |
67 private final String mOldAccountName; | 65 private final String mOldAccountName; |
68 private final String mNewAccountName; | 66 private final String mNewAccountName; |
69 private final boolean mCurrentlyManaged; | 67 private final boolean mCurrentlyManaged; |
70 private final Promise<Boolean> mNewAccountManaged = new Promise<>(); | |
71 private final FragmentManager mFragmentManager; | 68 private final FragmentManager mFragmentManager; |
72 private final Context mContext; | 69 private final Context mContext; |
73 private final ImportSyncType mImportSyncType; | 70 private final ImportSyncType mImportSyncType; |
71 private final ConfirmSyncDataStateMachineDelegate mDelegate; | |
72 | |
73 private boolean mWipeData; | |
74 private Boolean mNewAccountManaged; | |
74 | 75 |
75 /** | 76 /** |
76 * Run this state machine, displaying the appropriate dialogs. | 77 * Run this state machine, displaying the appropriate dialogs. |
77 * @param callback One of the two functions of the {@link ConfirmImportSyncD ataDialog.Listener} | 78 * @param callback One of the two functions of the {@link ConfirmImportSyncD ataDialog.Listener} |
78 * are guaranteed to be called. | 79 * are guaranteed to be called. |
79 */ | 80 */ |
80 public static void run(String oldAccountName, String newAccountName, | 81 public static void run(String oldAccountName, String newAccountName, |
81 ImportSyncType importSyncType, FragmentManager fragmentManager, Cont ext context, | 82 ImportSyncType importSyncType, FragmentManager fragmentManager, Cont ext context, |
82 ConfirmImportSyncDataDialog.Listener callback) { | 83 ConfirmImportSyncDataDialog.Listener callback) { |
83 // Includes implicit not-null assertion. | 84 // Includes implicit not-null assertion. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
115 ConfirmImportSyncDataDialog.Listener callback) { | 116 ConfirmImportSyncDataDialog.Listener callback) { |
116 mOldAccountName = oldAccountName; | 117 mOldAccountName = oldAccountName; |
117 mNewAccountName = newAccountName; | 118 mNewAccountName = newAccountName; |
118 mImportSyncType = importSyncType; | 119 mImportSyncType = importSyncType; |
119 mFragmentManager = fragmentManager; | 120 mFragmentManager = fragmentManager; |
120 mContext = context; | 121 mContext = context; |
121 mCallback = callback; | 122 mCallback = callback; |
122 | 123 |
123 mCurrentlyManaged = SigninManager.get(context).getManagementDomain() != null; | 124 mCurrentlyManaged = SigninManager.get(context).getManagementDomain() != null; |
124 | 125 |
126 mDelegate = new ConfirmSyncDataStateMachineDelegate(mContext); | |
127 | |
125 // This check isn't needed right now, but can take a few seconds, so we kick it off early. | 128 // This check isn't needed right now, but can take a few seconds, so we kick it off early. |
126 SigninManager.isUserManaged(mNewAccountName, mNewAccountManaged.fulfillm entCallback()); | 129 requestNewAccountManagementStatus(); |
127 } | 130 } |
128 | 131 |
129 /** | 132 /** |
130 * This will progress the state machine, by moving the state along and then by either calling | 133 * 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 | 134 * 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 | 135 * entire flow is over, if it is answered positively one of the onConfirm fu nctions is called |
133 * and this function is called again. | 136 * and this function is called again. |
134 */ | 137 */ |
135 private void progress() { | 138 private void progress() { |
136 switch (mState) { | 139 switch (mState) { |
(...skipping 18 matching lines...) Expand all Loading... | |
155 mOldAccountName, mNewAccountName); | 158 mOldAccountName, mNewAccountName); |
156 } else { | 159 } else { |
157 // This will call back into onConfirm(boolean wipeData) on s uccess. | 160 // This will call back into onConfirm(boolean wipeData) on s uccess. |
158 ConfirmImportSyncDataDialog.showNewInstance(mOldAccountName, mNewAccountName, | 161 ConfirmImportSyncDataDialog.showNewInstance(mOldAccountName, mNewAccountName, |
159 mImportSyncType, mFragmentManager, this); | 162 mImportSyncType, mFragmentManager, this); |
160 } | 163 } |
161 | 164 |
162 break; | 165 break; |
163 case BEFORE_NEW_ACCOUNT_DIALOG: | 166 case BEFORE_NEW_ACCOUNT_DIALOG: |
164 mState = AFTER_NEW_ACCOUNT_DIALOG; | 167 mState = AFTER_NEW_ACCOUNT_DIALOG; |
165 | 168 if (mNewAccountManaged != null) { |
166 mNewAccountManaged.then(new Callback<Boolean>() { | 169 // No need to show dialog if account management status is al ready known |
167 @Override | 170 handleNewAccountManagementStatus(); |
168 public void onResult(Boolean newAccountManaged) { | 171 } else { |
169 if (newAccountManaged) { | 172 showProgressDialog(); |
170 // Show 'logging into managed account' dialog | 173 scheduleTimeout(); |
171 // This will call back into onConfirm on success. | 174 } |
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; | 175 break; |
183 case AFTER_NEW_ACCOUNT_DIALOG: | 176 case AFTER_NEW_ACCOUNT_DIALOG: |
184 mState = DONE; | 177 mState = DONE; |
185 mCallback.onConfirm(mWipeData); | 178 mCallback.onConfirm(mWipeData); |
186 break; | 179 break; |
187 case DONE: | 180 case DONE: |
188 throw new IllegalStateException("Can't progress from DONE state! "); | 181 throw new IllegalStateException("Can't progress from DONE state! "); |
189 } | 182 } |
190 } | 183 } |
191 | 184 |
185 private void requestNewAccountManagementStatus() { | |
186 SigninManager.isUserManaged(mNewAccountName, new Callback<Boolean>() { | |
187 @Override | |
188 public void onResult(Boolean result) { | |
189 setIsNewAccountManaged(result); | |
190 } | |
191 }); | |
192 } | |
193 | |
194 private void setIsNewAccountManaged(Boolean isManaged) { | |
195 assert isManaged != null; | |
196 mNewAccountManaged = isManaged; | |
197 if (mState == AFTER_NEW_ACCOUNT_DIALOG) { | |
198 handleNewAccountManagementStatus(); | |
199 } | |
200 } | |
201 | |
202 private void handleNewAccountManagementStatus() { | |
203 assert mNewAccountManaged != null; | |
204 assert mState == AFTER_NEW_ACCOUNT_DIALOG; | |
205 | |
206 mDelegate.dismissProgressDialog(); | |
207 mDelegate.dismissTimeoutDialog(); | |
208 | |
209 if (mNewAccountManaged) { | |
210 // Show 'logging into managed account' dialog | |
211 // This will call back into onConfirm on success. | |
212 ConfirmManagedSyncDataDialog.showSignInToManagedAccountDialog( | |
213 ConfirmSyncDataStateMachine.this, mFragmentManager, mContext .getResources(), | |
214 SigninManager.extractDomainName(mNewAccountName)); | |
215 } else { | |
216 progress(); | |
217 } | |
218 } | |
219 | |
220 private void showProgressDialog() { | |
221 mDelegate.showProgressDialog( | |
222 new ConfirmSyncDataStateMachineDelegate.ProgressDialogListener() { | |
223 @Override | |
224 public void onCancel() { | |
225 ConfirmSyncDataStateMachine.this.onCancel(); | |
226 } | |
227 }); | |
228 } | |
229 | |
230 private void scheduleTimeout() { | |
231 ThreadUtils.postOnUiThreadDelayed(new Runnable() { | |
msarda
2017/03/28 11:09:02
I do not know how this works, but it would be bett
bsazonov
2017/03/28 12:59:58
I've found only https://developer.android.com/refe
Bernhard Bauer
2017/03/28 14:19:21
If you keep a reference to the Runnable around, yo
bsazonov
2017/03/29 13:05:05
Thanks for the tip! Done.
| |
232 @Override | |
233 public void run() { | |
234 checkTimeout(); | |
235 } | |
236 }, ACCOUNT_CHECK_TIMEOUT_MS); | |
237 } | |
238 | |
239 private void checkTimeout() { | |
240 if (mState != AFTER_NEW_ACCOUNT_DIALOG || mNewAccountManaged != null) { | |
241 return; | |
242 } | |
243 | |
244 mDelegate.showTimeoutDialog( | |
245 new ConfirmSyncDataStateMachineDelegate.TimeoutDialogListener() { | |
246 @Override | |
247 public void onCancel() { | |
248 ConfirmSyncDataStateMachine.this.onCancel(); | |
249 } | |
250 | |
251 @Override | |
252 public void onRetry() { | |
253 requestNewAccountManagementStatus(); | |
254 scheduleTimeout(); | |
255 } | |
256 }); | |
257 } | |
258 | |
192 // ConfirmImportSyncDataDialog.Listener implementation. | 259 // ConfirmImportSyncDataDialog.Listener implementation. |
193 @Override | 260 @Override |
194 public void onConfirm(boolean wipeData) { | 261 public void onConfirm(boolean wipeData) { |
195 mWipeData = wipeData; | 262 mWipeData = wipeData; |
196 progress(); | 263 progress(); |
197 } | 264 } |
198 | 265 |
199 // ConfirmManagedSyncDataDialog.Listener implementation. | 266 // ConfirmManagedSyncDataDialog.Listener implementation. |
200 @Override | 267 @Override |
201 public void onConfirm() { | 268 public void onConfirm() { |
202 progress(); | 269 progress(); |
203 } | 270 } |
204 | 271 |
205 // ConfirmImportSyncDataDialog.Listener & ConfirmManagedSyncDataDialog.Liste ner implementation. | 272 // ConfirmImportSyncDataDialog.Listener & ConfirmManagedSyncDataDialog.Liste ner implementation. |
msarda
2017/03/28 11:09:02
This is also the implementation for the new dialog
bsazonov
2017/03/28 12:59:58
Nope. This method is called from new dialogs liste
| |
206 @Override | 273 @Override |
207 public void onCancel() { | 274 public void onCancel() { |
208 mState = DONE; | 275 mState = DONE; |
209 mCallback.onCancel(); | 276 mCallback.onCancel(); |
277 mDelegate.dismissProgressDialog(); | |
278 mDelegate.dismissTimeoutDialog(); | |
210 } | 279 } |
211 } | 280 } |
212 | 281 |
OLD | NEW |