Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
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/. */
5 package org.mozilla.gecko.fxa.receivers;
7 import java.util.LinkedList;
8 import java.util.List;
9 import java.util.concurrent.Executor;
10 import java.util.concurrent.Executors;
12 import org.mozilla.gecko.background.common.log.Logger;
13 import org.mozilla.gecko.fxa.FirefoxAccounts;
14 import org.mozilla.gecko.fxa.FxAccountConstants;
15 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
16 import org.mozilla.gecko.fxa.login.State;
17 import org.mozilla.gecko.fxa.login.State.StateLabel;
18 import org.mozilla.gecko.sync.Utils;
20 import android.accounts.Account;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
25 /**
26 * A receiver that takes action when our Android package is upgraded (replaced).
27 */
28 public class FxAccountUpgradeReceiver extends BroadcastReceiver {
29 private static final String LOG_TAG = FxAccountUpgradeReceiver.class.getSimpleName();
31 /**
32 * Produce a list of Runnable instances to be executed sequentially on
33 * upgrade.
34 * <p>
35 * Each Runnable will be executed sequentially on a background thread. Any
36 * unchecked Exception thrown will be caught and ignored.
37 *
38 * @param context Android context.
39 * @return list of Runnable instances.
40 */
41 protected List<Runnable> onUpgradeRunnables(Context context) {
42 List<Runnable> runnables = new LinkedList<Runnable>();
43 runnables.add(new MaybeUnpickleRunnable(context));
44 // Recovering accounts that are in the Doghouse should happen *after* we
45 // unpickle any accounts saved to disk.
46 runnables.add(new AdvanceFromDoghouseRunnable(context));
47 return runnables;
48 }
50 @Override
51 public void onReceive(final Context context, Intent intent) {
52 Logger.setThreadLogTag(FxAccountConstants.GLOBAL_LOG_TAG);
53 Logger.info(LOG_TAG, "Upgrade broadcast received.");
55 // Iterate Runnable instances one at a time.
56 final Executor executor = Executors.newSingleThreadExecutor();
57 for (final Runnable runnable : onUpgradeRunnables(context)) {
58 executor.execute(new Runnable() {
59 @Override
60 public void run() {
61 try {
62 runnable.run();
63 } catch (Exception e) {
64 // We really don't want to throw on a background thread, so we
65 // catch, log, and move on.
66 Logger.error(LOG_TAG, "Got exception executing background upgrade Runnable; ignoring.", e);
67 }
68 }
69 });
70 }
71 }
73 /**
74 * A Runnable that tries to unpickle any pickled Firefox Accounts.
75 */
76 protected static class MaybeUnpickleRunnable implements Runnable {
77 protected final Context context;
79 public MaybeUnpickleRunnable(Context context) {
80 this.context = context;
81 }
83 @Override
84 public void run() {
85 // Querying the accounts will unpickle any pickled Firefox Account.
86 Logger.info(LOG_TAG, "Trying to unpickle any pickled Firefox Account.");
87 FirefoxAccounts.getFirefoxAccounts(context);
88 }
89 }
91 /**
92 * A Runnable that tries to advance existing Firefox Accounts that are in the
93 * Doghouse state to the Separated state.
94 * <p>
95 * This is our main deprecation-and-upgrade mechanism: in some way, the
96 * Account gets moved to the Doghouse state. If possible, an upgraded version
97 * of the package advances to Separated, prompting the user to re-connect the
98 * Account.
99 */
100 protected static class AdvanceFromDoghouseRunnable implements Runnable {
101 protected final Context context;
103 public AdvanceFromDoghouseRunnable(Context context) {
104 this.context = context;
105 }
107 @Override
108 public void run() {
109 final Account[] accounts = FirefoxAccounts.getFirefoxAccounts(context);
110 Logger.info(LOG_TAG, "Trying to advance " + accounts.length + " existing Firefox Accounts from the Doghouse to Separated (if necessary).");
111 for (Account account : accounts) {
112 try {
113 final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
114 // For great debugging.
115 if (FxAccountConstants.LOG_PERSONAL_INFORMATION) {
116 fxAccount.dump();
117 }
118 State state = fxAccount.getState();
119 if (state == null || state.getStateLabel() != StateLabel.Doghouse) {
120 Logger.debug(LOG_TAG, "Account named like " + Utils.obfuscateEmail(account.name) + " is not in the Doghouse; skipping.");
121 continue;
122 }
123 Logger.debug(LOG_TAG, "Account named like " + Utils.obfuscateEmail(account.name) + " is in the Doghouse; advancing to Separated.");
124 fxAccount.setState(state.makeSeparatedState());
125 } catch (Exception e) {
126 Logger.warn(LOG_TAG, "Got exception trying to advance account named like " + Utils.obfuscateEmail(account.name) +
127 " from Doghouse to Separated state; ignoring.", e);
128 }
129 }
130 }
131 }
132 }