1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
package org.mozilla.gecko.fxa;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
public class FxAccountPushHandler {
private static final String LOG_TAG = "FxAccountPush";
private static final String COMMAND_DEVICE_DISCONNECTED = "fxaccounts:device_disconnected";
private static final String COMMAND_COLLECTION_CHANGED = "sync:collection_changed";
private static final String CLIENTS_COLLECTION = "clients";
// Forbid instantiation
private FxAccountPushHandler() {}
public static void handleFxAPushMessage(Context context, Bundle bundle) {
Log.i(LOG_TAG, "Handling FxA Push Message");
String rawMessage = bundle.getString("message");
JSONObject message = null;
if (!TextUtils.isEmpty(rawMessage)) {
try {
message = new JSONObject(rawMessage);
} catch (JSONException e) {
Log.e(LOG_TAG, "Could not parse JSON", e);
return;
}
}
if (message == null) {
// An empty body means we should check the verification state of the account (FxA sends this
// when the account email is verified for example).
// TODO: We're only registering the push endpoint when we are in the Married state, that's why we're skipping the message :(
Log.d(LOG_TAG, "Skipping empty message");
return;
}
try {
String command = message.getString("command");
JSONObject data = message.getJSONObject("data");
switch (command) {
case COMMAND_DEVICE_DISCONNECTED:
handleDeviceDisconnection(context, data);
break;
case COMMAND_COLLECTION_CHANGED:
handleCollectionChanged(context, data);
break;
default:
Log.d(LOG_TAG, "No handler defined for FxA Push command " + command);
break;
}
} catch (JSONException e) {
Log.e(LOG_TAG, "Error while handling FxA push notification", e);
}
}
private static void handleCollectionChanged(Context context, JSONObject data) throws JSONException {
JSONArray collections = data.getJSONArray("collections");
int len = collections.length();
for (int i = 0; i < len; i++) {
if (collections.getString(i).equals(CLIENTS_COLLECTION)) {
final Account account = FirefoxAccounts.getFirefoxAccount(context);
if (account == null) {
Log.e(LOG_TAG, "The account does not exist anymore");
return;
}
final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
fxAccount.requestImmediateSync(new String[] { CLIENTS_COLLECTION }, null);
return;
}
}
}
private static void handleDeviceDisconnection(Context context, JSONObject data) throws JSONException {
final Account account = FirefoxAccounts.getFirefoxAccount(context);
if (account == null) {
Log.e(LOG_TAG, "The account does not exist anymore");
return;
}
final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
if (!fxAccount.getDeviceId().equals(data.getString("id"))) {
Log.e(LOG_TAG, "The device ID to disconnect doesn't match with the local device ID.\n"
+ "Local: " + fxAccount.getDeviceId() + ", ID to disconnect: " + data.getString("id"));
return;
}
AccountManager.get(context).removeAccount(account, null, null);
}
}
|