|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 package org.mozilla.gecko.sync.setup; |
|
6 |
|
7 import java.io.File; |
|
8 import java.io.UnsupportedEncodingException; |
|
9 import java.security.NoSuchAlgorithmException; |
|
10 |
|
11 import org.mozilla.gecko.background.common.GlobalConstants; |
|
12 import org.mozilla.gecko.background.common.log.Logger; |
|
13 import org.mozilla.gecko.db.BrowserContract; |
|
14 import org.mozilla.gecko.sync.CredentialException; |
|
15 import org.mozilla.gecko.sync.ExtendedJSONObject; |
|
16 import org.mozilla.gecko.sync.SyncConfiguration; |
|
17 import org.mozilla.gecko.sync.SyncConstants; |
|
18 import org.mozilla.gecko.sync.ThreadPool; |
|
19 import org.mozilla.gecko.sync.Utils; |
|
20 import org.mozilla.gecko.sync.config.AccountPickler; |
|
21 import org.mozilla.gecko.sync.repositories.android.RepoUtils; |
|
22 |
|
23 import android.accounts.Account; |
|
24 import android.accounts.AccountManager; |
|
25 import android.content.ActivityNotFoundException; |
|
26 import android.content.ContentResolver; |
|
27 import android.content.Context; |
|
28 import android.content.Intent; |
|
29 import android.content.SharedPreferences; |
|
30 import android.content.pm.PackageManager.NameNotFoundException; |
|
31 import android.os.Bundle; |
|
32 import android.provider.Settings; |
|
33 import android.util.Log; |
|
34 |
|
35 /** |
|
36 * This class contains utilities that are of use to Fennec |
|
37 * and Sync setup activities. |
|
38 * <p> |
|
39 * Do not break these APIs without correcting upstream code! |
|
40 */ |
|
41 public class SyncAccounts { |
|
42 private static final String LOG_TAG = "SyncAccounts"; |
|
43 |
|
44 private static final String MOTO_BLUR_SETTINGS_ACTIVITY = "com.motorola.blur.settings.AccountsAndServicesPreferenceActivity"; |
|
45 private static final String MOTO_BLUR_PACKAGE = "com.motorola.blur.setup"; |
|
46 |
|
47 /** |
|
48 * Return Sync accounts. |
|
49 * |
|
50 * @param c |
|
51 * Android context. |
|
52 * @return Sync accounts. |
|
53 */ |
|
54 public static Account[] syncAccounts(final Context c) { |
|
55 return AccountManager.get(c).getAccountsByType(SyncConstants.ACCOUNTTYPE_SYNC); |
|
56 } |
|
57 |
|
58 /** |
|
59 * Returns true if a Sync account is set up, or we have a pickled Sync account |
|
60 * on disk that should be un-pickled (Bug 769745). If we have a pickled Sync |
|
61 * account, try to un-pickle it and create the corresponding Sync account. |
|
62 * <p> |
|
63 * Do not call this method from the main thread. |
|
64 */ |
|
65 public static boolean syncAccountsExist(Context c) { |
|
66 final boolean accountsExist = AccountManager.get(c).getAccountsByType(SyncConstants.ACCOUNTTYPE_SYNC).length > 0; |
|
67 if (accountsExist) { |
|
68 return true; |
|
69 } |
|
70 |
|
71 final File file = c.getFileStreamPath(Constants.ACCOUNT_PICKLE_FILENAME); |
|
72 if (!file.exists()) { |
|
73 return false; |
|
74 } |
|
75 |
|
76 // There is a small race window here: if the user creates a new Sync account |
|
77 // between our checks, this could erroneously report that no Sync accounts |
|
78 // exist. |
|
79 final Account account = AccountPickler.unpickle(c, Constants.ACCOUNT_PICKLE_FILENAME); |
|
80 return (account != null); |
|
81 } |
|
82 |
|
83 /** |
|
84 * This class encapsulates the parameters needed to create a new Firefox Sync |
|
85 * account. |
|
86 */ |
|
87 public static class SyncAccountParameters { |
|
88 public final Context context; |
|
89 public final AccountManager accountManager; |
|
90 |
|
91 |
|
92 public final String username; // services.sync.account |
|
93 public final String syncKey; // in password manager: "chrome://weave (Mozilla Services Encryption Passphrase)" |
|
94 public final String password; // in password manager: "chrome://weave (Mozilla Services Password)" |
|
95 public final String serverURL; // services.sync.serverURL |
|
96 public final String clusterURL; // services.sync.clusterURL |
|
97 public final String clientName; // services.sync.client.name |
|
98 public final String clientGuid; // services.sync.client.GUID |
|
99 |
|
100 /** |
|
101 * Encapsulate the parameters needed to create a new Firefox Sync account. |
|
102 * |
|
103 * @param context |
|
104 * the current <code>Context</code>; cannot be null. |
|
105 * @param accountManager |
|
106 * an <code>AccountManager</code> instance to use; if null, get it |
|
107 * from <code>context</code>. |
|
108 * @param username |
|
109 * the desired username; cannot be null. |
|
110 * @param syncKey |
|
111 * the desired sync key; cannot be null. |
|
112 * @param password |
|
113 * the desired password; cannot be null. |
|
114 * @param serverURL |
|
115 * the server URL to use; if null, use the default. |
|
116 * @param clusterURL |
|
117 * the cluster URL to use; if null, a fresh cluster URL will be |
|
118 * retrieved from the server during the next sync. |
|
119 * @param clientName |
|
120 * the client name; if null, a fresh client record will be uploaded |
|
121 * to the server during the next sync. |
|
122 * @param clientGuid |
|
123 * the client GUID; if null, a fresh client record will be uploaded |
|
124 * to the server during the next sync. |
|
125 */ |
|
126 public SyncAccountParameters(Context context, AccountManager accountManager, |
|
127 String username, String syncKey, String password, |
|
128 String serverURL, String clusterURL, |
|
129 String clientName, String clientGuid) { |
|
130 if (context == null) { |
|
131 throw new IllegalArgumentException("Null context passed to SyncAccountParameters constructor."); |
|
132 } |
|
133 if (username == null) { |
|
134 throw new IllegalArgumentException("Null username passed to SyncAccountParameters constructor."); |
|
135 } |
|
136 if (syncKey == null) { |
|
137 throw new IllegalArgumentException("Null syncKey passed to SyncAccountParameters constructor."); |
|
138 } |
|
139 if (password == null) { |
|
140 throw new IllegalArgumentException("Null password passed to SyncAccountParameters constructor."); |
|
141 } |
|
142 this.context = context; |
|
143 this.accountManager = accountManager; |
|
144 this.username = username; |
|
145 this.syncKey = syncKey; |
|
146 this.password = password; |
|
147 this.serverURL = serverURL; |
|
148 this.clusterURL = clusterURL; |
|
149 this.clientName = clientName; |
|
150 this.clientGuid = clientGuid; |
|
151 } |
|
152 |
|
153 public SyncAccountParameters(Context context, AccountManager accountManager, |
|
154 String username, String syncKey, String password, String serverURL) { |
|
155 this(context, accountManager, username, syncKey, password, serverURL, null, null, null); |
|
156 } |
|
157 |
|
158 public SyncAccountParameters(final Context context, final AccountManager accountManager, final ExtendedJSONObject o) { |
|
159 this(context, accountManager, |
|
160 o.getString(Constants.JSON_KEY_ACCOUNT), |
|
161 o.getString(Constants.JSON_KEY_SYNCKEY), |
|
162 o.getString(Constants.JSON_KEY_PASSWORD), |
|
163 o.getString(Constants.JSON_KEY_SERVER), |
|
164 o.getString(Constants.JSON_KEY_CLUSTER), |
|
165 o.getString(Constants.JSON_KEY_CLIENT_NAME), |
|
166 o.getString(Constants.JSON_KEY_CLIENT_GUID)); |
|
167 } |
|
168 |
|
169 public ExtendedJSONObject asJSON() { |
|
170 final ExtendedJSONObject o = new ExtendedJSONObject(); |
|
171 o.put(Constants.JSON_KEY_ACCOUNT, username); |
|
172 o.put(Constants.JSON_KEY_PASSWORD, password); |
|
173 o.put(Constants.JSON_KEY_SERVER, serverURL); |
|
174 o.put(Constants.JSON_KEY_SYNCKEY, syncKey); |
|
175 o.put(Constants.JSON_KEY_CLUSTER, clusterURL); |
|
176 o.put(Constants.JSON_KEY_CLIENT_NAME, clientName); |
|
177 o.put(Constants.JSON_KEY_CLIENT_GUID, clientGuid); |
|
178 return o; |
|
179 } |
|
180 } |
|
181 |
|
182 /** |
|
183 * Create a sync account, clearing any existing preferences, and set it to |
|
184 * sync automatically. |
|
185 * <p> |
|
186 * Do not call this method from the main thread. |
|
187 * |
|
188 * @param syncAccount |
|
189 * parameters of the account to be created. |
|
190 * @return created <code>Account</code>, or null if an error occurred and the |
|
191 * account could not be added. |
|
192 */ |
|
193 public static Account createSyncAccount(SyncAccountParameters syncAccount) { |
|
194 return createSyncAccount(syncAccount, true, true); |
|
195 } |
|
196 |
|
197 /** |
|
198 * Create a sync account, clearing any existing preferences. |
|
199 * <p> |
|
200 * Do not call this method from the main thread. |
|
201 * <p> |
|
202 * Intended for testing; use |
|
203 * <code>createSyncAccount(SyncAccountParameters)</code> instead. |
|
204 * |
|
205 * @param syncAccount |
|
206 * parameters of the account to be created. |
|
207 * @param syncAutomatically |
|
208 * whether to start syncing this Account automatically ( |
|
209 * <code>false</code> for test accounts). |
|
210 * @return created Android <code>Account</code>, or null if an error occurred |
|
211 * and the account could not be added. |
|
212 */ |
|
213 public static Account createSyncAccount(SyncAccountParameters syncAccount, |
|
214 boolean syncAutomatically) { |
|
215 return createSyncAccount(syncAccount, syncAutomatically, true); |
|
216 } |
|
217 |
|
218 public static Account createSyncAccountPreservingExistingPreferences(SyncAccountParameters syncAccount, |
|
219 boolean syncAutomatically) { |
|
220 return createSyncAccount(syncAccount, syncAutomatically, false); |
|
221 } |
|
222 |
|
223 /** |
|
224 * Create a sync account. |
|
225 * <p> |
|
226 * Do not call this method from the main thread. |
|
227 * <p> |
|
228 * Intended for testing; use |
|
229 * <code>createSyncAccount(SyncAccountParameters)</code> instead. |
|
230 * |
|
231 * @param syncAccount |
|
232 * parameters of the account to be created. |
|
233 * @param syncAutomatically |
|
234 * whether to start syncing this Account automatically ( |
|
235 * <code>false</code> for test accounts). |
|
236 * @param clearPreferences |
|
237 * <code>true</code> to clear existing preferences before creating. |
|
238 * @return created Android <code>Account</code>, or null if an error occurred |
|
239 * and the account could not be added. |
|
240 */ |
|
241 protected static Account createSyncAccount(SyncAccountParameters syncAccount, |
|
242 boolean syncAutomatically, boolean clearPreferences) { |
|
243 final Context context = syncAccount.context; |
|
244 final AccountManager accountManager = (syncAccount.accountManager == null) ? |
|
245 AccountManager.get(syncAccount.context) : syncAccount.accountManager; |
|
246 final String username = syncAccount.username; |
|
247 final String syncKey = syncAccount.syncKey; |
|
248 final String password = syncAccount.password; |
|
249 final String serverURL = (syncAccount.serverURL == null) ? |
|
250 SyncConstants.DEFAULT_AUTH_SERVER : syncAccount.serverURL; |
|
251 |
|
252 Logger.debug(LOG_TAG, "Using account manager " + accountManager); |
|
253 if (!RepoUtils.stringsEqual(syncAccount.serverURL, SyncConstants.DEFAULT_AUTH_SERVER)) { |
|
254 Logger.info(LOG_TAG, "Setting explicit server URL: " + serverURL); |
|
255 } |
|
256 |
|
257 final Account account = new Account(username, SyncConstants.ACCOUNTTYPE_SYNC); |
|
258 final Bundle userbundle = new Bundle(); |
|
259 |
|
260 // Add sync key and server URL. |
|
261 userbundle.putString(Constants.OPTION_SYNCKEY, syncKey); |
|
262 userbundle.putString(Constants.OPTION_SERVER, serverURL); |
|
263 Logger.debug(LOG_TAG, "Adding account for " + SyncConstants.ACCOUNTTYPE_SYNC); |
|
264 boolean result = false; |
|
265 try { |
|
266 result = accountManager.addAccountExplicitly(account, password, userbundle); |
|
267 } catch (SecurityException e) { |
|
268 // We use Log rather than Logger here to avoid possibly hiding these errors. |
|
269 final String message = e.getMessage(); |
|
270 if (message != null && (message.indexOf("is different than the authenticator's uid") > 0)) { |
|
271 Log.wtf(SyncConstants.GLOBAL_LOG_TAG, |
|
272 "Unable to create account. " + |
|
273 "If you have more than one version of " + |
|
274 "Firefox/Beta/Aurora/Nightly/Fennec installed, that's why.", |
|
275 e); |
|
276 } else { |
|
277 Log.e(SyncConstants.GLOBAL_LOG_TAG, "Unable to create account.", e); |
|
278 } |
|
279 } |
|
280 |
|
281 if (!result) { |
|
282 Logger.error(LOG_TAG, "Failed to add account " + account + "!"); |
|
283 return null; |
|
284 } |
|
285 Logger.debug(LOG_TAG, "Account " + account + " added successfully."); |
|
286 |
|
287 setSyncAutomatically(account, syncAutomatically); |
|
288 setIsSyncable(account, syncAutomatically); |
|
289 Logger.debug(LOG_TAG, "Set account to sync automatically? " + syncAutomatically + "."); |
|
290 |
|
291 try { |
|
292 final String product = GlobalConstants.BROWSER_INTENT_PACKAGE; |
|
293 final String profile = Constants.DEFAULT_PROFILE; |
|
294 final long version = SyncConfiguration.CURRENT_PREFS_VERSION; |
|
295 |
|
296 final SharedPreferences.Editor editor = Utils.getSharedPreferences(context, product, username, serverURL, profile, version).edit(); |
|
297 if (clearPreferences) { |
|
298 final String prefsPath = Utils.getPrefsPath(product, username, serverURL, profile, version); |
|
299 Logger.info(LOG_TAG, "Clearing preferences path " + prefsPath + " for this account."); |
|
300 editor.clear(); |
|
301 } |
|
302 |
|
303 if (syncAccount.clusterURL != null) { |
|
304 editor.putString(SyncConfiguration.PREF_CLUSTER_URL, syncAccount.clusterURL); |
|
305 } |
|
306 |
|
307 if (syncAccount.clientName != null && syncAccount.clientGuid != null) { |
|
308 Logger.debug(LOG_TAG, "Setting client name to " + syncAccount.clientName + " and client GUID to " + syncAccount.clientGuid + "."); |
|
309 editor.putString(SyncConfiguration.PREF_CLIENT_NAME, syncAccount.clientName); |
|
310 editor.putString(SyncConfiguration.PREF_ACCOUNT_GUID, syncAccount.clientGuid); |
|
311 } else { |
|
312 Logger.debug(LOG_TAG, "Client name and guid not both non-null, so not setting client data."); |
|
313 } |
|
314 |
|
315 editor.commit(); |
|
316 } catch (Exception e) { |
|
317 Logger.error(LOG_TAG, "Could not clear prefs path!", e); |
|
318 } |
|
319 return account; |
|
320 } |
|
321 |
|
322 public static void setIsSyncable(Account account, boolean isSyncable) { |
|
323 String authority = BrowserContract.AUTHORITY; |
|
324 ContentResolver.setIsSyncable(account, authority, isSyncable ? 1 : 0); |
|
325 } |
|
326 |
|
327 public static void setSyncAutomatically(Account account, boolean syncAutomatically) { |
|
328 if (syncAutomatically) { |
|
329 ContentResolver.setMasterSyncAutomatically(true); |
|
330 } |
|
331 |
|
332 String authority = BrowserContract.AUTHORITY; |
|
333 Logger.debug(LOG_TAG, "Setting authority " + authority + " to " + |
|
334 (syncAutomatically ? "" : "not ") + "sync automatically."); |
|
335 ContentResolver.setSyncAutomatically(account, authority, syncAutomatically); |
|
336 } |
|
337 |
|
338 public static void backgroundSetSyncAutomatically(final Account account, final boolean syncAutomatically) { |
|
339 ThreadPool.run(new Runnable() { |
|
340 @Override |
|
341 public void run() { |
|
342 setSyncAutomatically(account, syncAutomatically); |
|
343 } |
|
344 }); |
|
345 } |
|
346 /** |
|
347 * Bug 721760: try to start a vendor-specific Accounts & Sync activity on Moto |
|
348 * Blur devices. |
|
349 * <p> |
|
350 * Bug 773562: actually start and catch <code>ActivityNotFoundException</code>, |
|
351 * rather than just returning the <code>Intent</code> only, because some |
|
352 * Moto devices fail to start the activity. |
|
353 * |
|
354 * @param context |
|
355 * current Android context. |
|
356 * @param vendorPackage |
|
357 * vendor specific package name. |
|
358 * @param vendorClass |
|
359 * vendor specific class name. |
|
360 * @return null on failure, otherwise the <code>Intent</code> started. |
|
361 */ |
|
362 protected static Intent openVendorSyncSettings(Context context, final String vendorPackage, final String vendorClass) { |
|
363 try { |
|
364 final int contextFlags = Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY; |
|
365 Context foreignContext = context.createPackageContext(vendorPackage, contextFlags); |
|
366 Class<?> klass = foreignContext.getClassLoader().loadClass(vendorClass); |
|
367 |
|
368 final Intent intent = new Intent(foreignContext, klass); |
|
369 context.startActivity(intent); |
|
370 Logger.info(LOG_TAG, "Vendor package " + vendorPackage + " and class " + |
|
371 vendorClass + " found, and activity launched."); |
|
372 return intent; |
|
373 } catch (NameNotFoundException e) { |
|
374 Logger.debug(LOG_TAG, "Vendor package " + vendorPackage + " not found. Skipping."); |
|
375 } catch (ClassNotFoundException e) { |
|
376 Logger.debug(LOG_TAG, "Vendor package " + vendorPackage + " found but class " + |
|
377 vendorClass + " not found. Skipping.", e); |
|
378 } catch (ActivityNotFoundException e) { |
|
379 // Bug 773562 - android.content.ActivityNotFoundException on Motorola devices. |
|
380 Logger.warn(LOG_TAG, "Vendor package " + vendorPackage + " and class " + |
|
381 vendorClass + " found, but activity not launched. Skipping.", e); |
|
382 } catch (Exception e) { |
|
383 // Just in case. |
|
384 Logger.warn(LOG_TAG, "Caught exception launching activity from vendor package " + vendorPackage + |
|
385 " and class " + vendorClass + ". Ignoring.", e); |
|
386 } |
|
387 return null; |
|
388 } |
|
389 |
|
390 /** |
|
391 * Start Sync settings activity. |
|
392 * |
|
393 * @param context |
|
394 * current Android context. |
|
395 * @return the <code>Intent</code> started. |
|
396 */ |
|
397 public static Intent openSyncSettings(Context context) { |
|
398 // Bug 721760 - opening Sync settings takes user to Battery & Data Manager |
|
399 // on a variety of Motorola devices. This work around tries to load the |
|
400 // correct Intent by hand. Oh, Android. |
|
401 Intent intent = openVendorSyncSettings(context, MOTO_BLUR_PACKAGE, MOTO_BLUR_SETTINGS_ACTIVITY); |
|
402 if (intent != null) { |
|
403 return intent; |
|
404 } |
|
405 |
|
406 // Open default Sync settings activity. |
|
407 intent = new Intent(Settings.ACTION_SYNC_SETTINGS); |
|
408 // Bug 774233: do not start activity as a new task (second run fails on some HTC devices). |
|
409 context.startActivity(intent); // We should always find this Activity. |
|
410 return intent; |
|
411 } |
|
412 |
|
413 /** |
|
414 * Synchronously extract Sync account parameters from Android account version |
|
415 * 0, using plain auth token type. |
|
416 * <p> |
|
417 * Safe to call from main thread. |
|
418 * |
|
419 * @param context |
|
420 * Android context. |
|
421 * @param accountManager |
|
422 * Android account manager. |
|
423 * @param account |
|
424 * Android Account. |
|
425 * @return Sync account parameters, always non-null; fields username, |
|
426 * password, serverURL, and syncKey always non-null. |
|
427 */ |
|
428 public static SyncAccountParameters blockingFromAndroidAccountV0(final Context context, final AccountManager accountManager, final Account account) |
|
429 throws CredentialException { |
|
430 String username; |
|
431 try { |
|
432 username = Utils.usernameFromAccount(account.name); |
|
433 } catch (NoSuchAlgorithmException e) { |
|
434 throw new CredentialException.MissingCredentialException("username"); |
|
435 } catch (UnsupportedEncodingException e) { |
|
436 throw new CredentialException.MissingCredentialException("username"); |
|
437 } |
|
438 |
|
439 /* |
|
440 * If we are accessing an Account that we don't own, Android will throw an |
|
441 * unchecked <code>SecurityException</code> saying |
|
442 * "W FxSync(XXXX) java.lang.SecurityException: caller uid XXXXX is different than the authenticator's uid". |
|
443 * We catch that error and throw accordingly. |
|
444 */ |
|
445 String password; |
|
446 String syncKey; |
|
447 String serverURL; |
|
448 try { |
|
449 password = accountManager.getPassword(account); |
|
450 syncKey = accountManager.getUserData(account, Constants.OPTION_SYNCKEY); |
|
451 serverURL = accountManager.getUserData(account, Constants.OPTION_SERVER); |
|
452 } catch (SecurityException e) { |
|
453 Logger.warn(LOG_TAG, "Got security exception fetching Sync account parameters; throwing."); |
|
454 throw new CredentialException.MissingAllCredentialsException(e); |
|
455 } |
|
456 |
|
457 if (password == null && |
|
458 username == null && |
|
459 syncKey == null && |
|
460 serverURL == null) { |
|
461 throw new CredentialException.MissingAllCredentialsException(); |
|
462 } |
|
463 |
|
464 if (password == null) { |
|
465 throw new CredentialException.MissingCredentialException("password"); |
|
466 } |
|
467 |
|
468 if (syncKey == null) { |
|
469 throw new CredentialException.MissingCredentialException("syncKey"); |
|
470 } |
|
471 |
|
472 if (serverURL == null) { |
|
473 throw new CredentialException.MissingCredentialException("serverURL"); |
|
474 } |
|
475 |
|
476 try { |
|
477 // SyncAccountParameters constructor throws on null inputs. This shouldn't |
|
478 // happen, but let's be safe. |
|
479 return new SyncAccountParameters(context, accountManager, username, syncKey, password, serverURL); |
|
480 } catch (Exception e) { |
|
481 Logger.warn(LOG_TAG, "Got exception fetching Sync account parameters; throwing."); |
|
482 throw new CredentialException.MissingAllCredentialsException(e); |
|
483 } |
|
484 } |
|
485 |
|
486 /** |
|
487 * Bug 790931: create an intent announcing that a Sync account will be |
|
488 * deleted. |
|
489 * <p> |
|
490 * This intent <b>must</b> be broadcast with secure permissions, because it |
|
491 * contains sensitive user information including the Sync account password and |
|
492 * Sync key. |
|
493 * <p> |
|
494 * Version 1 of the created intent includes extras with keys |
|
495 * <code>Constants.JSON_KEY_VERSION</code>, |
|
496 * <code>Constants.JSON_KEY_TIMESTAMP</code>, and |
|
497 * <code>Constants.JSON_KEY_ACCOUNT</code> (which is the Android Account name, |
|
498 * not the encoded Sync Account name). |
|
499 * <p> |
|
500 * If possible, it contains the key <code>Constants.JSON_KEY_PAYLOAD</code> |
|
501 * with value the Sync account parameters as JSON, <b>except the Sync key has |
|
502 * been replaced with the empty string</b>. (We replace, rather than remove, |
|
503 * the Sync key because SyncAccountParameters expects a non-null Sync key.) |
|
504 * |
|
505 * @see SyncAccountParameters#asJSON |
|
506 * |
|
507 * @param context |
|
508 * Android context. |
|
509 * @param accountManager |
|
510 * Android account manager. |
|
511 * @param account |
|
512 * Android account being removed. |
|
513 * @return <code>Intent</code> to broadcast. |
|
514 */ |
|
515 public static Intent makeSyncAccountDeletedIntent(final Context context, final AccountManager accountManager, final Account account) { |
|
516 final Intent intent = new Intent(SyncConstants.SYNC_ACCOUNT_DELETED_ACTION); |
|
517 |
|
518 intent.putExtra(Constants.JSON_KEY_VERSION, Long.valueOf(SyncConstants.SYNC_ACCOUNT_DELETED_INTENT_VERSION)); |
|
519 intent.putExtra(Constants.JSON_KEY_TIMESTAMP, Long.valueOf(System.currentTimeMillis())); |
|
520 intent.putExtra(Constants.JSON_KEY_ACCOUNT, account.name); |
|
521 |
|
522 SyncAccountParameters accountParameters = null; |
|
523 try { |
|
524 accountParameters = SyncAccounts.blockingFromAndroidAccountV0(context, accountManager, account); |
|
525 } catch (Exception e) { |
|
526 Logger.warn(LOG_TAG, "Caught exception fetching account parameters.", e); |
|
527 } |
|
528 |
|
529 if (accountParameters != null) { |
|
530 ExtendedJSONObject json = accountParameters.asJSON(); |
|
531 json.put(Constants.JSON_KEY_SYNCKEY, ""); // Reduce attack surface area by removing Sync key. |
|
532 intent.putExtra(Constants.JSON_KEY_PAYLOAD, json.toJSONString()); |
|
533 } |
|
534 |
|
535 return intent; |
|
536 } |
|
537 |
|
538 /** |
|
539 * Synchronously fetch SharedPreferences of a profile associated with a Sync |
|
540 * account. |
|
541 * <p> |
|
542 * Safe to call from main thread. |
|
543 * |
|
544 * @param context |
|
545 * Android context. |
|
546 * @param accountManager |
|
547 * Android account manager. |
|
548 * @param account |
|
549 * Android Account. |
|
550 * @param product |
|
551 * package. |
|
552 * @param profile |
|
553 * of account. |
|
554 * @param version |
|
555 * number. |
|
556 * @return SharedPreferences associated with Sync account. |
|
557 * @throws CredentialException |
|
558 * @throws NoSuchAlgorithmException |
|
559 * @throws UnsupportedEncodingException |
|
560 */ |
|
561 public static SharedPreferences blockingPrefsFromAndroidAccountV0(final Context context, final AccountManager accountManager, final Account account, |
|
562 final String product, final String profile, final long version) |
|
563 throws CredentialException, NoSuchAlgorithmException, UnsupportedEncodingException { |
|
564 SyncAccountParameters params = SyncAccounts.blockingFromAndroidAccountV0(context, accountManager, account); |
|
565 String prefsPath = Utils.getPrefsPath(product, params.username, params.serverURL, profile, version); |
|
566 |
|
567 return context.getSharedPreferences(prefsPath, Utils.SHARED_PREFERENCES_MODE); |
|
568 } |
|
569 |
|
570 /** |
|
571 * Synchronously fetch SharedPreferences of a profile associated with the |
|
572 * default Firefox profile of a Sync Account. |
|
573 * <p> |
|
574 * Uses the default package, default profile, and current version. |
|
575 * <p> |
|
576 * Safe to call from main thread. |
|
577 * |
|
578 * @param context |
|
579 * Android context. |
|
580 * @param accountManager |
|
581 * Android account manager. |
|
582 * @param account |
|
583 * Android Account. |
|
584 * @return SharedPreferences associated with Sync account. |
|
585 * @throws CredentialException |
|
586 * @throws NoSuchAlgorithmException |
|
587 * @throws UnsupportedEncodingException |
|
588 */ |
|
589 public static SharedPreferences blockingPrefsFromDefaultProfileV0(final Context context, final AccountManager accountManager, final Account account) |
|
590 throws CredentialException, NoSuchAlgorithmException, UnsupportedEncodingException { |
|
591 final String product = GlobalConstants.BROWSER_INTENT_PACKAGE; |
|
592 final String profile = Constants.DEFAULT_PROFILE; |
|
593 final long version = SyncConfiguration.CURRENT_PREFS_VERSION; |
|
594 |
|
595 return blockingPrefsFromAndroidAccountV0(context, accountManager, account, product, profile, version); |
|
596 } |
|
597 } |