зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 3 changesets (bug 1351805) for android Test failures a=backout
Backed out changeset da34da5f310a (bug 1351805) Backed out changeset 430b56176e04 (bug 1351805) Backed out changeset a3dfb4b9dc66 (bug 1351805) MozReview-Commit-ID: AE4RcKV3akz
This commit is contained in:
Родитель
ae260ad8c3
Коммит
c9b3f40856
|
@ -831,11 +831,10 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
|
|||
'fxa/authenticator/FxAccountLoginDelegate.java',
|
||||
'fxa/authenticator/FxAccountLoginException.java',
|
||||
'fxa/authenticator/FxADefaultLoginStateMachineDelegate.java',
|
||||
'fxa/devices/FxAccountDevice.java',
|
||||
'fxa/devices/FxAccountDeviceListUpdater.java',
|
||||
'fxa/devices/FxAccountDeviceRegistrator.java',
|
||||
'fxa/FirefoxAccounts.java',
|
||||
'fxa/FxAccountConstants.java',
|
||||
'fxa/FxAccountDevice.java',
|
||||
'fxa/FxAccountDeviceRegistrator.java',
|
||||
'fxa/FxAccountPushHandler.java',
|
||||
'fxa/login/BaseRequestDelegate.java',
|
||||
'fxa/login/Cohabiting.java',
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.json.JSONException;
|
|||
import org.mozilla.gecko.background.fxa.FxAccountUtils;
|
||||
import org.mozilla.gecko.fxa.FirefoxAccounts;
|
||||
import org.mozilla.gecko.fxa.FxAccountConstants;
|
||||
import org.mozilla.gecko.fxa.FxAccountDeviceRegistrator;
|
||||
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
|
||||
import org.mozilla.gecko.fxa.login.Engaged;
|
||||
import org.mozilla.gecko.fxa.login.State;
|
||||
|
|
|
@ -60,7 +60,6 @@ public class BrowserContract {
|
|||
public static final String PARAM_GROUP_BY = "group_by";
|
||||
|
||||
public static final String METHOD_INSERT_HISTORY_WITH_VISITS_FROM_SYNC = "insertHistoryWithVisitsSync";
|
||||
public static final String METHOD_REPLACE_REMOTE_CLIENTS = "replaceRemoteClients";
|
||||
public static final String METHOD_RESULT = "methodResult";
|
||||
public static final String METHOD_PARAM_OBJECT = "object";
|
||||
public static final String METHOD_PARAM_DATA = "data";
|
||||
|
@ -462,19 +461,6 @@ public class BrowserContract {
|
|||
public static final String DEVICE_TYPE = "device_type";
|
||||
}
|
||||
|
||||
public static final class RemoteDevices implements CommonColumns, DateSyncColumns {
|
||||
private RemoteDevices() {}
|
||||
public static final String TABLE_NAME = "remote_devices";
|
||||
|
||||
public static final String GUID = "guid"; // FxA device ID
|
||||
public static final String NAME = "name";
|
||||
public static final String TYPE = "type";
|
||||
public static final String IS_CURRENT_DEVICE = "is_current_device";
|
||||
public static final String LAST_ACCESS_TIME = "last_access_time";
|
||||
|
||||
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "remote_devices");
|
||||
}
|
||||
|
||||
// Data storage for dynamic panels on about:home
|
||||
@RobocopTarget
|
||||
public static final class HomeItems implements CommonColumns {
|
||||
|
|
|
@ -24,7 +24,6 @@ import org.mozilla.gecko.db.BrowserContract.ActivityStreamBlocklist;
|
|||
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
|
||||
import org.mozilla.gecko.db.BrowserContract.Combined;
|
||||
import org.mozilla.gecko.db.BrowserContract.Favicons;
|
||||
import org.mozilla.gecko.db.BrowserContract.RemoteDevices;
|
||||
import org.mozilla.gecko.db.BrowserContract.History;
|
||||
import org.mozilla.gecko.db.BrowserContract.Visits;
|
||||
import org.mozilla.gecko.db.BrowserContract.PageMetadata;
|
||||
|
@ -61,7 +60,7 @@ public final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
|||
|
||||
// Replace the Bug number below with your Bug that is conducting a DB upgrade, as to force a merge conflict with any
|
||||
// other patches that require a DB upgrade.
|
||||
public static final int DATABASE_VERSION = 37; // Bug 1351805
|
||||
public static final int DATABASE_VERSION = 36; // Bug 1301717
|
||||
public static final String DATABASE_NAME = "browser.db";
|
||||
|
||||
final protected Context mContext;
|
||||
|
@ -70,7 +69,6 @@ public final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
|||
static final String TABLE_HISTORY = History.TABLE_NAME;
|
||||
static final String TABLE_VISITS = Visits.TABLE_NAME;
|
||||
static final String TABLE_PAGE_METADATA = PageMetadata.TABLE_NAME;
|
||||
static final String TABLE_REMOTE_DEVICES = RemoteDevices.TABLE_NAME;
|
||||
static final String TABLE_FAVICONS = Favicons.TABLE_NAME;
|
||||
static final String TABLE_THUMBNAILS = Thumbnails.TABLE_NAME;
|
||||
static final String TABLE_READING_LIST = ReadingListItems.TABLE_NAME;
|
||||
|
@ -238,21 +236,6 @@ public final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
|||
+ PageMetadata.HISTORY_GUID + ", " + PageMetadata.HAS_IMAGE + ")");
|
||||
}
|
||||
|
||||
private void createRemoteDevicesTable(SQLiteDatabase db) {
|
||||
debug("Creating " + TABLE_REMOTE_DEVICES + " table");
|
||||
db.execSQL("CREATE TABLE " + TABLE_REMOTE_DEVICES + "(" +
|
||||
RemoteDevices._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
|
||||
RemoteDevices.GUID + " TEXT UNIQUE NOT NULL," +
|
||||
RemoteDevices.NAME + " TEXT NOT NULL," +
|
||||
RemoteDevices.TYPE + " TEXT NOT NULL," +
|
||||
RemoteDevices.IS_CURRENT_DEVICE + " INTEGER NOT NULL," +
|
||||
RemoteDevices.DATE_CREATED + " INTEGER NOT NULL," + // Timestamp - in milliseconds.
|
||||
RemoteDevices.DATE_MODIFIED + " INTEGER NOT NULL," +
|
||||
RemoteDevices.LAST_ACCESS_TIME + " INTEGER NOT NULL" + // Timestamp - in milliseconds.
|
||||
");");
|
||||
// Creating an index is not worth it, because most users have less than 3 devices.
|
||||
}
|
||||
|
||||
private void createBookmarksWithFaviconsView(SQLiteDatabase db) {
|
||||
debug("Creating " + VIEW_BOOKMARKS_WITH_FAVICONS + " view");
|
||||
|
||||
|
@ -768,8 +751,6 @@ public final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
|||
createActivityStreamBlocklistTable(db);
|
||||
|
||||
createPageMetadataTable(db);
|
||||
|
||||
createRemoteDevicesTable(db);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1999,10 +1980,6 @@ public final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
|||
createPageMetadataTable(db);
|
||||
}
|
||||
|
||||
private void upgradeDatabaseFrom36to37(final SQLiteDatabase db) {
|
||||
createRemoteDevicesTable(db);
|
||||
}
|
||||
|
||||
private void createV33CombinedView(final SQLiteDatabase db) {
|
||||
db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED);
|
||||
db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED_WITH_FAVICONS);
|
||||
|
@ -2138,10 +2115,6 @@ public final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
|||
case 36:
|
||||
upgradeDatabaseFrom35to36(db);
|
||||
break;
|
||||
|
||||
case 37:
|
||||
upgradeDatabaseFrom36to37(db);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ import org.mozilla.gecko.db.BrowserContract.Bookmarks;
|
|||
import org.mozilla.gecko.db.BrowserContract.Combined;
|
||||
import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
|
||||
import org.mozilla.gecko.db.BrowserContract.Favicons;
|
||||
import org.mozilla.gecko.db.BrowserContract.RemoteDevices;
|
||||
import org.mozilla.gecko.db.BrowserContract.Highlights;
|
||||
import org.mozilla.gecko.db.BrowserContract.History;
|
||||
import org.mozilla.gecko.db.BrowserContract.Visits;
|
||||
|
@ -95,7 +94,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
static final String TABLE_URL_ANNOTATIONS = UrlAnnotations.TABLE_NAME;
|
||||
static final String TABLE_ACTIVITY_STREAM_BLOCKLIST = ActivityStreamBlocklist.TABLE_NAME;
|
||||
static final String TABLE_PAGE_METADATA = PageMetadata.TABLE_NAME;
|
||||
static final String TABLE_REMOTE_DEVICES = RemoteDevices.TABLE_NAME;
|
||||
|
||||
static final String VIEW_COMBINED = Combined.VIEW_NAME;
|
||||
static final String VIEW_BOOKMARKS_WITH_FAVICONS = Bookmarks.VIEW_WITH_FAVICONS;
|
||||
|
@ -149,9 +147,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
|
||||
static final int PAGE_METADATA = 1500;
|
||||
|
||||
static final int REMOTE_DEVICES = 1600;
|
||||
static final int REMOTE_DEVICES_ID = 1601;
|
||||
|
||||
static final String DEFAULT_BOOKMARKS_SORT_ORDER = Bookmarks.TYPE
|
||||
+ " ASC, " + Bookmarks.POSITION + " ASC, " + Bookmarks._ID
|
||||
+ " ASC";
|
||||
|
@ -170,7 +165,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
static final Map<String, String> URL_ANNOTATIONS_PROJECTION_MAP;
|
||||
static final Map<String, String> VISIT_PROJECTION_MAP;
|
||||
static final Map<String, String> PAGE_METADATA_PROJECTION_MAP;
|
||||
static final Map<String, String> REMOTE_DEVICES_PROJECTION_MAP;
|
||||
static final Table[] sTables;
|
||||
|
||||
static {
|
||||
|
@ -330,21 +324,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, ActivityStreamBlocklist.TABLE_NAME, ACTIVITY_STREAM_BLOCKLIST);
|
||||
|
||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "highlight_candidates", HIGHLIGHT_CANDIDATES);
|
||||
|
||||
// FxA Devices
|
||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "remote_devices", REMOTE_DEVICES);
|
||||
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "remote_devices/#", REMOTE_DEVICES_ID);
|
||||
|
||||
map = new HashMap<>();
|
||||
map.put(RemoteDevices._ID, RemoteDevices._ID);
|
||||
map.put(RemoteDevices.GUID, RemoteDevices.GUID);
|
||||
map.put(RemoteDevices.NAME, RemoteDevices.NAME);
|
||||
map.put(RemoteDevices.TYPE, RemoteDevices.TYPE);
|
||||
map.put(RemoteDevices.IS_CURRENT_DEVICE, RemoteDevices.IS_CURRENT_DEVICE);
|
||||
map.put(RemoteDevices.DATE_CREATED, RemoteDevices.DATE_CREATED);
|
||||
map.put(RemoteDevices.DATE_MODIFIED, RemoteDevices.DATE_MODIFIED);
|
||||
map.put(RemoteDevices.LAST_ACCESS_TIME, RemoteDevices.LAST_ACCESS_TIME);
|
||||
REMOTE_DEVICES_PROJECTION_MAP = Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
private static class ShrinkMemoryReceiver extends BroadcastReceiver {
|
||||
|
@ -670,20 +649,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
deleted = deletePageMetadata(uri, selection, selectionArgs);
|
||||
break;
|
||||
|
||||
case REMOTE_DEVICES_ID:
|
||||
debug("Delete on REMOTE_DEVICES_ID: " + uri);
|
||||
|
||||
selection = DBUtils.concatenateWhere(selection, TABLE_REMOTE_DEVICES + "._ID = ?");
|
||||
selectionArgs = DBUtils.appendSelectionArgs(selectionArgs,
|
||||
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
||||
// fall through
|
||||
case REMOTE_DEVICES: {
|
||||
trace("Deleting FxA devices: " + uri);
|
||||
beginWrite(db);
|
||||
deleted = deleteRemoteDevices(uri, selection, selectionArgs);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
Table table = findTableFor(match);
|
||||
if (table == null) {
|
||||
|
@ -756,12 +721,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
break;
|
||||
}
|
||||
|
||||
case REMOTE_DEVICES: {
|
||||
trace("Insert on REMOTE_DEVICES: " + uri);
|
||||
id = insertFxADevice(uri, values);
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
Table table = findTableFor(match);
|
||||
if (table == null) {
|
||||
|
@ -1432,20 +1391,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
break;
|
||||
}
|
||||
|
||||
case REMOTE_DEVICES_ID:
|
||||
selection = DBUtils.concatenateWhere(selection, RemoteDevices._ID + " = ?");
|
||||
selectionArgs = DBUtils.appendSelectionArgs(selectionArgs,
|
||||
new String[] { Long.toString(ContentUris.parseId(uri)) });
|
||||
// fall through
|
||||
case REMOTE_DEVICES: {
|
||||
debug("FxA devices query: " + uri);
|
||||
|
||||
qb.setProjectionMap(REMOTE_DEVICES_PROJECTION_MAP);
|
||||
qb.setTables(TABLE_REMOTE_DEVICES);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
Table table = findTableFor(match);
|
||||
if (table == null) {
|
||||
|
@ -2052,13 +1997,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
TABLE_PAGE_METADATA, null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
||||
}
|
||||
|
||||
private long insertFxADevice(final Uri uri, final ContentValues values) {
|
||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||
|
||||
beginWrite(db);
|
||||
return db.insertOrThrow(TABLE_REMOTE_DEVICES, null, values);
|
||||
}
|
||||
|
||||
private long insertUrlAnnotation(final Uri uri, final ContentValues values) {
|
||||
final String url = values.getAsString(UrlAnnotations.URL);
|
||||
trace("Inserting url annotations for URL: " + url);
|
||||
|
@ -2082,13 +2020,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
return db.delete(TABLE_PAGE_METADATA, selection, selectionArgs);
|
||||
}
|
||||
|
||||
private int deleteRemoteDevices(final Uri uri, final String selection, final String[] selectionArgs) {
|
||||
trace("Deleting FxA Devices for URI: " + uri);
|
||||
|
||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||
return db.delete(TABLE_REMOTE_DEVICES, selection, selectionArgs);
|
||||
}
|
||||
|
||||
private void updateUrlAnnotation(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) {
|
||||
trace("Updating url annotation for URI: " + uri);
|
||||
|
||||
|
@ -2344,23 +2275,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
result.putSerializable(BrowserContract.METHOD_RESULT, e);
|
||||
}
|
||||
break;
|
||||
case BrowserContract.METHOD_REPLACE_REMOTE_CLIENTS:
|
||||
try {
|
||||
final Uri uri = RemoteDevices.CONTENT_URI
|
||||
.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_PROFILE,
|
||||
Uri.parse(uriArg).getQueryParameter(BrowserContract.PARAM_PROFILE))
|
||||
.build();
|
||||
bulkReplaceRemoteDevices(uri, extras);
|
||||
result.putSerializable(BrowserContract.METHOD_RESULT, null);
|
||||
|
||||
// If anything went wrong during insertion, we know that changes were rolled back.
|
||||
// Inform our caller that we have failed.
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Unexpected error while bulk inserting remote clients", e);
|
||||
result.putSerializable(BrowserContract.METHOD_RESULT, e);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown method call: " + method);
|
||||
}
|
||||
|
@ -2368,40 +2282,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
|
|||
return result;
|
||||
}
|
||||
|
||||
private void bulkReplaceRemoteDevices(final Uri uri, @NonNull Bundle dataBundle) {
|
||||
final ContentValues[] values = (ContentValues[]) dataBundle.getParcelableArray(BrowserContract.METHOD_PARAM_DATA);
|
||||
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("Received null recordBundle while bulk inserting remote clients.");
|
||||
}
|
||||
|
||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||
|
||||
// Wrap everything in a transaction.
|
||||
beginBatch(db);
|
||||
|
||||
try {
|
||||
// First purge our list of remote devices.
|
||||
// We pass "1" to get a count of the affected rows (see SQLiteDatabase#delete)
|
||||
int count = deleteInTransaction(uri, "1", null);
|
||||
Log.i(LOGTAG, "Deleted " + count + " remote devices.");
|
||||
|
||||
// Then insert the new ones.
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
try {
|
||||
insertFxADevice(uri, values[i]);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOGTAG, "Could not insert device with ID " + values[i].getAsString(RemoteDevices.GUID) + ": " + e);
|
||||
}
|
||||
}
|
||||
markBatchSuccessful(db);
|
||||
} finally {
|
||||
endBatch(db);
|
||||
}
|
||||
|
||||
getContext().getContentResolver().notifyChange(uri, null, false);
|
||||
}
|
||||
|
||||
private void bulkInsertHistoryWithVisits(final SQLiteDatabase db, @NonNull Bundle dataBundle) {
|
||||
// NB: dataBundle structure:
|
||||
// Key METHOD_PARAM_DATA=[Bundle,...]
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.mozilla.gecko.TelemetryContract;
|
|||
import org.mozilla.gecko.annotation.ReflectionTarget;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.fxa.FxAccountConstants;
|
||||
import org.mozilla.gecko.fxa.devices.FxAccountDeviceRegistrator;
|
||||
import org.mozilla.gecko.fxa.FxAccountDeviceRegistrator;
|
||||
import org.mozilla.gecko.fxa.FxAccountPushHandler;
|
||||
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
|
||||
import org.mozilla.gecko.fxa.login.State;
|
||||
|
|
|
@ -8,7 +8,7 @@ import org.mozilla.gecko.background.fxa.FxAccountClient20.AccountStatusResponse;
|
|||
import org.mozilla.gecko.background.fxa.FxAccountClient20.RecoveryEmailStatusResponse;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClient20.RequestDelegate;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClient20.TwoKeys;
|
||||
import org.mozilla.gecko.fxa.devices.FxAccountDevice;
|
||||
import org.mozilla.gecko.fxa.FxAccountDevice;
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
|
||||
import java.util.List;
|
||||
|
|
|
@ -13,7 +13,7 @@ import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClient
|
|||
import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
|
||||
import org.mozilla.gecko.fxa.FxAccountConstants;
|
||||
import org.mozilla.gecko.Locales;
|
||||
import org.mozilla.gecko.fxa.devices.FxAccountDevice;
|
||||
import org.mozilla.gecko.fxa.FxAccountDevice;
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
import org.mozilla.gecko.sync.crypto.HKDF;
|
||||
|
|
|
@ -2,54 +2,48 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.fxa.devices;
|
||||
package org.mozilla.gecko.fxa;
|
||||
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
|
||||
public class FxAccountDevice {
|
||||
|
||||
private static final String JSON_KEY_NAME = "name";
|
||||
private static final String JSON_KEY_ID = "id";
|
||||
private static final String JSON_KEY_TYPE = "type";
|
||||
private static final String JSON_KEY_ISCURRENTDEVICE = "isCurrentDevice";
|
||||
private static final String JSON_KEY_PUSH_CALLBACK = "pushCallback";
|
||||
private static final String JSON_KEY_PUSH_PUBLICKEY = "pushPublicKey";
|
||||
private static final String JSON_KEY_PUSH_AUTHKEY = "pushAuthKey";
|
||||
private static final String JSON_LAST_ACCESS_TIME = "lastAccessTime";
|
||||
public static final String JSON_KEY_NAME = "name";
|
||||
public static final String JSON_KEY_ID = "id";
|
||||
public static final String JSON_KEY_TYPE = "type";
|
||||
public static final String JSON_KEY_ISCURRENTDEVICE = "isCurrentDevice";
|
||||
public static final String JSON_KEY_PUSH_CALLBACK = "pushCallback";
|
||||
public static final String JSON_KEY_PUSH_PUBLICKEY = "pushPublicKey";
|
||||
public static final String JSON_KEY_PUSH_AUTHKEY = "pushAuthKey";
|
||||
|
||||
public final String id;
|
||||
public final String name;
|
||||
public final String type;
|
||||
public final Boolean isCurrentDevice;
|
||||
public final Long lastAccessTime;
|
||||
public final String pushCallback;
|
||||
public final String pushPublicKey;
|
||||
public final String pushAuthKey;
|
||||
|
||||
public FxAccountDevice(String name, String id, String type, Boolean isCurrentDevice,
|
||||
Long lastAccessTime, String pushCallback, String pushPublicKey,
|
||||
String pushAuthKey) {
|
||||
String pushCallback, String pushPublicKey, String pushAuthKey) {
|
||||
this.name = name;
|
||||
this.id = id;
|
||||
this.type = type;
|
||||
this.isCurrentDevice = isCurrentDevice;
|
||||
this.lastAccessTime = lastAccessTime;
|
||||
this.pushCallback = pushCallback;
|
||||
this.pushPublicKey = pushPublicKey;
|
||||
this.pushAuthKey = pushAuthKey;
|
||||
}
|
||||
|
||||
public static FxAccountDevice fromJson(ExtendedJSONObject json) {
|
||||
final String name = json.getString(JSON_KEY_NAME);
|
||||
final String id = json.getString(JSON_KEY_ID);
|
||||
final String type = json.getString(JSON_KEY_TYPE);
|
||||
final Boolean isCurrentDevice = json.getBoolean(JSON_KEY_ISCURRENTDEVICE);
|
||||
final Long lastAccessTime = json.getLong(JSON_LAST_ACCESS_TIME);
|
||||
final String pushCallback = json.getString(JSON_KEY_PUSH_CALLBACK);
|
||||
final String pushPublicKey = json.getString(JSON_KEY_PUSH_PUBLICKEY);
|
||||
final String pushAuthKey = json.getString(JSON_KEY_PUSH_AUTHKEY);
|
||||
return new FxAccountDevice(name, id, type, isCurrentDevice, lastAccessTime, pushCallback,
|
||||
pushPublicKey, pushAuthKey);
|
||||
String name = json.getString(JSON_KEY_NAME);
|
||||
String id = json.getString(JSON_KEY_ID);
|
||||
String type = json.getString(JSON_KEY_TYPE);
|
||||
Boolean isCurrentDevice = json.getBoolean(JSON_KEY_ISCURRENTDEVICE);
|
||||
String pushCallback = json.getString(JSON_KEY_PUSH_CALLBACK);
|
||||
String pushPublicKey = json.getString(JSON_KEY_PUSH_PUBLICKEY);
|
||||
String pushAuthKey = json.getString(JSON_KEY_PUSH_AUTHKEY);
|
||||
return new FxAccountDevice(name, id, type, isCurrentDevice, pushCallback, pushPublicKey, pushAuthKey);
|
||||
}
|
||||
|
||||
public ExtendedJSONObject toJson() {
|
||||
|
@ -79,6 +73,7 @@ public class FxAccountDevice {
|
|||
private String id;
|
||||
private String name;
|
||||
private String type;
|
||||
private Boolean isCurrentDevice;
|
||||
private String pushCallback;
|
||||
private String pushPublicKey;
|
||||
private String pushAuthKey;
|
||||
|
@ -95,6 +90,10 @@ public class FxAccountDevice {
|
|||
this.type = type;
|
||||
}
|
||||
|
||||
public void isCurrentDevice() {
|
||||
this.isCurrentDevice = Boolean.TRUE;
|
||||
}
|
||||
|
||||
public void pushCallback(String pushCallback) {
|
||||
this.pushCallback = pushCallback;
|
||||
}
|
||||
|
@ -108,7 +107,7 @@ public class FxAccountDevice {
|
|||
}
|
||||
|
||||
public FxAccountDevice build() {
|
||||
return new FxAccountDevice(this.name, this.id, this.type, null, null,
|
||||
return new FxAccountDevice(this.name, this.id, this.type, this.isCurrentDevice,
|
||||
this.pushCallback, this.pushPublicKey, this.pushAuthKey);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.fxa.devices;
|
||||
package org.mozilla.gecko.fxa;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -378,9 +378,8 @@ public class FxAccountDeviceRegistrator implements BundleEventListener {
|
|||
break;
|
||||
}
|
||||
final FxAccountDevice updatedDevice = new FxAccountDevice(device.name, fxaDevice.id, device.type,
|
||||
null, null,
|
||||
device.pushCallback, device.pushPublicKey,
|
||||
device.pushAuthKey);
|
||||
device.isCurrentDevice, device.pushCallback,
|
||||
device.pushPublicKey, device.pushAuthKey);
|
||||
doFxaRegistration(context, fxAccount, updatedDevice, false);
|
||||
return;
|
||||
}
|
|
@ -805,15 +805,16 @@ public class AndroidFxAccount {
|
|||
});
|
||||
}
|
||||
|
||||
private long getUserDataLong(String key, long defaultValue) {
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends Number> T getUserDataNumber(String key, T defaultValue) {
|
||||
final String numStr = accountManager.getUserData(account, key);
|
||||
if (TextUtils.isEmpty(numStr)) {
|
||||
return defaultValue;
|
||||
}
|
||||
try {
|
||||
return Long.parseLong(key);
|
||||
} catch (NumberFormatException e) {
|
||||
Logger.warn(LOG_TAG, "Couldn't parse " + key + "; defaulting to " + defaultValue, e);
|
||||
return (T) NumberFormat.getInstance().parse(numStr);
|
||||
} catch (ParseException e) {
|
||||
Logger.warn(LOG_TAG, "Couldn't parse " + key + "; defaulting to 0L.", e);
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
@ -824,28 +825,19 @@ public class AndroidFxAccount {
|
|||
}
|
||||
|
||||
public synchronized int getDeviceRegistrationVersion() {
|
||||
final String numStr = accountManager.getUserData(account, ACCOUNT_KEY_DEVICE_REGISTRATION_VERSION);
|
||||
if (TextUtils.isEmpty(numStr)) {
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(numStr);
|
||||
} catch (NumberFormatException e) {
|
||||
Logger.warn(LOG_TAG, "Couldn't parse ACCOUNT_KEY_DEVICE_REGISTRATION_VERSION; defaulting to 0", e);
|
||||
return 0;
|
||||
}
|
||||
return getUserDataNumber(ACCOUNT_KEY_DEVICE_REGISTRATION_VERSION, 0);
|
||||
}
|
||||
|
||||
public synchronized long getDeviceRegistrationTimestamp() {
|
||||
return getUserDataLong(ACCOUNT_KEY_DEVICE_REGISTRATION_TIMESTAMP, 0L);
|
||||
return getUserDataNumber(ACCOUNT_KEY_DEVICE_REGISTRATION_TIMESTAMP, 0L);
|
||||
}
|
||||
|
||||
public synchronized long getDevicePushRegistrationError() {
|
||||
return getUserDataLong(ACCOUNT_KEY_DEVICE_PUSH_REGISTRATION_ERROR, 0L);
|
||||
return getUserDataNumber(ACCOUNT_KEY_DEVICE_PUSH_REGISTRATION_ERROR, 0L);
|
||||
}
|
||||
|
||||
public synchronized long getDevicePushRegistrationErrorTime() {
|
||||
return getUserDataLong(ACCOUNT_KEY_DEVICE_PUSH_REGISTRATION_ERROR_TIME, 0L);
|
||||
return getUserDataNumber(ACCOUNT_KEY_DEVICE_PUSH_REGISTRATION_ERROR_TIME, 0L);
|
||||
}
|
||||
|
||||
public synchronized void setDeviceId(String id) {
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.fxa.devices;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.VisibleForTesting;
|
||||
import android.util.Log;
|
||||
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClient;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClient20;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClientException;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.db.BrowserContract.RemoteDevices;
|
||||
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
|
||||
import org.mozilla.gecko.fxa.login.State;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
public class FxAccountDeviceListUpdater implements FxAccountClient20.RequestDelegate<FxAccountDevice[]> {
|
||||
private static final String LOG_TAG = "FxADeviceListUpdater";
|
||||
|
||||
private final AndroidFxAccount fxAccount;
|
||||
private final ContentResolver contentResolver;
|
||||
|
||||
public FxAccountDeviceListUpdater(final AndroidFxAccount fxAccount, final ContentResolver cr) {
|
||||
this.fxAccount = fxAccount;
|
||||
this.contentResolver = cr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSuccess(final FxAccountDevice[] result) {
|
||||
final Uri uri = RemoteDevices.CONTENT_URI
|
||||
.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_PROFILE, fxAccount.getProfile())
|
||||
.build();
|
||||
|
||||
final Bundle valuesBundle = new Bundle();
|
||||
final ContentValues[] insertValues = new ContentValues[result.length];
|
||||
|
||||
final long now = System.currentTimeMillis();
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
final FxAccountDevice fxADevice = result[i];
|
||||
final ContentValues deviceValues = new ContentValues();
|
||||
deviceValues.put(RemoteDevices.GUID, fxADevice.id);
|
||||
deviceValues.put(RemoteDevices.TYPE, fxADevice.type);
|
||||
deviceValues.put(RemoteDevices.NAME, fxADevice.name);
|
||||
deviceValues.put(RemoteDevices.IS_CURRENT_DEVICE, fxADevice.isCurrentDevice);
|
||||
deviceValues.put(RemoteDevices.DATE_CREATED, now);
|
||||
deviceValues.put(RemoteDevices.DATE_MODIFIED, now);
|
||||
// TODO: Remove that line once FxA sends lastAccessTime all the time.
|
||||
final Long lastAccessTime = fxADevice.lastAccessTime != null ? fxADevice.lastAccessTime : 0;
|
||||
deviceValues.put(RemoteDevices.LAST_ACCESS_TIME, lastAccessTime);
|
||||
insertValues[i] = deviceValues;
|
||||
}
|
||||
valuesBundle.putParcelableArray(BrowserContract.METHOD_PARAM_DATA, insertValues);
|
||||
try {
|
||||
contentResolver.call(uri, BrowserContract.METHOD_REPLACE_REMOTE_CLIENTS, uri.toString(),
|
||||
valuesBundle);
|
||||
Log.i(LOG_TAG, "FxA Device list update done.");
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "Error persisting the new remote device list.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleError(Exception e) {
|
||||
onError(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleFailure(FxAccountClientException.FxAccountClientRemoteException e) {
|
||||
onError(e);
|
||||
}
|
||||
|
||||
private void onError(final Exception e) {
|
||||
Log.e(LOG_TAG, "Error while getting the FxA device list.", e);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
FxAccountClient getSynchronousFxaClient() {
|
||||
return new FxAccountClient20(fxAccount.getAccountServerURI(),
|
||||
// Current thread executor :)
|
||||
new Executor() {
|
||||
@Override
|
||||
public void execute(@NonNull Runnable runnable) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
Log.i(LOG_TAG, "Beginning FxA device list update.");
|
||||
final byte[] sessionToken;
|
||||
try {
|
||||
sessionToken = fxAccount.getState().getSessionToken();
|
||||
} catch (State.NotASessionTokenState e) {
|
||||
// This should never happen, because the caller (FxAccountSyncAdapter) verifies that
|
||||
// we are in a token state before calling this method.
|
||||
throw new IllegalStateException("Could not get a session token during Sync (?) " + e);
|
||||
}
|
||||
final FxAccountClient fxaClient = getSynchronousFxaClient();
|
||||
fxaClient.deviceList(sessionToken, this);
|
||||
}
|
||||
}
|
|
@ -5,10 +5,8 @@
|
|||
package org.mozilla.gecko.fxa.receivers;
|
||||
|
||||
import android.app.IntentService;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.mozilla.gecko.background.common.log.Logger;
|
||||
|
@ -17,7 +15,6 @@ import org.mozilla.gecko.background.fxa.FxAccountClientException;
|
|||
import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClient;
|
||||
import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClientException.FxAccountAbstractClientRemoteException;
|
||||
import org.mozilla.gecko.background.fxa.oauth.FxAccountOAuthClient10;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.fxa.FxAccountConstants;
|
||||
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
|
||||
import org.mozilla.gecko.fxa.sync.FxAccountNotificationManager;
|
||||
|
@ -78,8 +75,6 @@ public class FxAccountDeletedService extends IntentService {
|
|||
return;
|
||||
}
|
||||
|
||||
clearRemoteDevicesList(intent, context);
|
||||
|
||||
// Delete current device the from FxA devices list.
|
||||
deleteFxADevice(intent);
|
||||
|
||||
|
@ -164,17 +159,6 @@ public class FxAccountDeletedService extends IntentService {
|
|||
}
|
||||
}
|
||||
|
||||
private void clearRemoteDevicesList(Intent intent, Context context) {
|
||||
final Uri remoteDevicesUriWithProfile = BrowserContract.RemoteDevices.CONTENT_URI
|
||||
.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_PROFILE,
|
||||
intent.getStringExtra(FxAccountConstants.ACCOUNT_DELETED_INTENT_ACCOUNT_PROFILE))
|
||||
.build();
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
|
||||
cr.delete(remoteDevicesUriWithProfile, null, null);
|
||||
}
|
||||
|
||||
// Remove our current device from the FxA device list.
|
||||
private void deleteFxADevice(Intent intent) {
|
||||
final byte[] sessionToken = intent.getByteArrayExtra(FxAccountConstants.ACCOUNT_DELETED_INTENT_ACCOUNT_SESSION_TOKEN);
|
||||
|
|
|
@ -6,7 +6,6 @@ package org.mozilla.gecko.fxa.sync;
|
|||
|
||||
import android.accounts.Account;
|
||||
import android.content.AbstractThreadedSyncAdapter;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
|
@ -23,8 +22,7 @@ import org.mozilla.gecko.background.fxa.SkewHandler;
|
|||
import org.mozilla.gecko.browserid.JSONWebTokenUtils;
|
||||
import org.mozilla.gecko.fxa.FirefoxAccounts;
|
||||
import org.mozilla.gecko.fxa.FxAccountConstants;
|
||||
import org.mozilla.gecko.fxa.devices.FxAccountDeviceListUpdater;
|
||||
import org.mozilla.gecko.fxa.devices.FxAccountDeviceRegistrator;
|
||||
import org.mozilla.gecko.fxa.FxAccountDeviceRegistrator;
|
||||
import org.mozilla.gecko.fxa.authenticator.AccountPickler;
|
||||
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
|
||||
import org.mozilla.gecko.fxa.authenticator.FxADefaultLoginStateMachineDelegate;
|
||||
|
@ -36,6 +34,7 @@ import org.mozilla.gecko.fxa.login.State.StateLabel;
|
|||
import org.mozilla.gecko.fxa.sync.FxAccountSyncDelegate.Result;
|
||||
import org.mozilla.gecko.sync.BackoffHandler;
|
||||
import org.mozilla.gecko.sync.GlobalSession;
|
||||
import org.mozilla.gecko.sync.MetaGlobal;
|
||||
import org.mozilla.gecko.sync.PrefsBackoffHandler;
|
||||
import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate;
|
||||
import org.mozilla.gecko.sync.SyncConfiguration;
|
||||
|
@ -420,15 +419,6 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
|
|||
}
|
||||
}
|
||||
|
||||
private void onSessionTokenStateReached(Context context, AndroidFxAccount fxAccount) {
|
||||
// This does not block the main thread, if work has to be done it is executed in a new thread.
|
||||
maybeRegisterDevice(context, fxAccount);
|
||||
|
||||
FxAccountDeviceListUpdater deviceListUpdater = new FxAccountDeviceListUpdater(fxAccount, context.getContentResolver());
|
||||
// Since the clients stage requires a fresh list of remote devices, we update the device list synchronously.
|
||||
deviceListUpdater.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* A trivial Sync implementation that does not cache client keys,
|
||||
* certificates, or tokens.
|
||||
|
@ -556,7 +546,7 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
|
|||
schedulePolicy.onHandleFinal(notMarried.getNeededAction());
|
||||
syncDelegate.handleCannotSync(notMarried);
|
||||
if (notMarried.getStateLabel() == StateLabel.Engaged) {
|
||||
onSessionTokenStateReached(context, fxAccount);
|
||||
maybeRegisterDevice(context, fxAccount);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -599,8 +589,6 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
|
|||
return;
|
||||
}
|
||||
|
||||
onSessionTokenStateReached(context, fxAccount);
|
||||
|
||||
final SessionCallback sessionCallback = new SessionCallback(syncDelegate, schedulePolicy);
|
||||
final KeyBundle syncKeyBundle = married.getSyncKeyBundle();
|
||||
final String clientState = married.getClientState();
|
||||
|
@ -608,6 +596,8 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
|
|||
assertion, tokenServerEndpointURI, tokenBackoffHandler, sharedPrefs,
|
||||
syncKeyBundle, clientState, sessionCallback, extras, fxAccount, syncDeadline);
|
||||
|
||||
maybeRegisterDevice(context, fxAccount);
|
||||
|
||||
// Force fetch the profile avatar information. (asynchronous, in another thread)
|
||||
Logger.info(LOG_TAG, "Fetching profile avatar information.");
|
||||
fxAccount.fetchProfileJSON();
|
||||
|
|
|
@ -6,6 +6,7 @@ package org.mozilla.gecko.sync;
|
|||
|
||||
import org.mozilla.gecko.background.fxa.FxAccountUtils;
|
||||
import org.mozilla.gecko.fxa.FirefoxAccounts;
|
||||
import org.mozilla.gecko.fxa.FxAccountDeviceRegistrator;
|
||||
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
|
||||
import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
package org.mozilla.gecko.fxa.devices;
|
||||
package org.mozilla.gecko.fxa;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
|
@ -1,188 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
package org.mozilla.gecko.fxa.devices;
|
||||
|
||||
import android.content.ContentProviderClient;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mozilla.gecko.background.db.DelegatingTestContentProvider;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClient;
|
||||
import org.mozilla.gecko.background.testhelpers.TestRunner;
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.db.BrowserProvider;
|
||||
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
|
||||
import org.mozilla.gecko.fxa.login.State;
|
||||
import org.robolectric.shadows.ShadowContentResolver;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Objects.deepEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.any;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.eq;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(TestRunner.class)
|
||||
public class TestFxAccountDeviceListUpdater {
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
// Process Mockito annotations
|
||||
MockitoAnnotations.initMocks(this);
|
||||
fxaDevicesUpdater = spy(new FxAccountDeviceListUpdater(fxAccount, contentResolver));
|
||||
}
|
||||
|
||||
FxAccountDeviceListUpdater fxaDevicesUpdater;
|
||||
|
||||
@Mock
|
||||
AndroidFxAccount fxAccount;
|
||||
|
||||
@Mock
|
||||
State state;
|
||||
|
||||
@Mock
|
||||
ContentResolver contentResolver;
|
||||
|
||||
@Mock
|
||||
FxAccountClient fxaClient;
|
||||
|
||||
@Test
|
||||
public void testUpdate() throws Throwable {
|
||||
byte[] token = "usertoken".getBytes();
|
||||
|
||||
when(fxAccount.getState()).thenReturn(state);
|
||||
when(state.getSessionToken()).thenReturn(token);
|
||||
doReturn(fxaClient).when(fxaDevicesUpdater).getSynchronousFxaClient();
|
||||
|
||||
fxaDevicesUpdater.update();
|
||||
verify(fxaClient).deviceList(token, fxaDevicesUpdater);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccessHandler() throws Throwable {
|
||||
FxAccountDevice[] result = new FxAccountDevice[2];
|
||||
FxAccountDevice device1 = new FxAccountDevice("Current device", "deviceid1", "mobile", true, System.currentTimeMillis(),
|
||||
"https://localhost/push/callback1", "abc123", "321cba");
|
||||
FxAccountDevice device2 = new FxAccountDevice("Desktop PC", "deviceid2", "desktop", true, System.currentTimeMillis(),
|
||||
"https://localhost/push/callback2", "abc123", "321cba");
|
||||
result[0] = device1;
|
||||
result[1] = device2;
|
||||
|
||||
when(fxAccount.getProfile()).thenReturn("default");
|
||||
|
||||
long timeBeforeCall = System.currentTimeMillis();
|
||||
fxaDevicesUpdater.handleSuccess(result);
|
||||
|
||||
ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
|
||||
verify(contentResolver).call(any(Uri.class), eq(BrowserContract.METHOD_REPLACE_REMOTE_CLIENTS), anyString(), captor.capture());
|
||||
List<Bundle> allArgs = captor.getAllValues();
|
||||
assertTrue(allArgs.size() == 1);
|
||||
ContentValues[] allValues = (ContentValues[]) allArgs.get(0).getParcelableArray(BrowserContract.METHOD_PARAM_DATA);
|
||||
|
||||
ContentValues firstDevice = allValues[0];
|
||||
checkInsertDeviceContentValues(device1, firstDevice, timeBeforeCall);
|
||||
ContentValues secondDevice = allValues[1];
|
||||
checkInsertDeviceContentValues(device2, secondDevice, timeBeforeCall);
|
||||
}
|
||||
|
||||
private void checkInsertDeviceContentValues(FxAccountDevice device, ContentValues firstDevice, long timeBeforeCall) {
|
||||
assertEquals(firstDevice.getAsString(BrowserContract.RemoteDevices.GUID), device.id);
|
||||
assertEquals(firstDevice.getAsString(BrowserContract.RemoteDevices.TYPE), device.type);
|
||||
assertEquals(firstDevice.getAsString(BrowserContract.RemoteDevices.NAME), device.name);
|
||||
assertEquals(firstDevice.getAsBoolean(BrowserContract.RemoteDevices.IS_CURRENT_DEVICE), device.isCurrentDevice);
|
||||
deepEquals(firstDevice.getAsString(BrowserContract.RemoteDevices.LAST_ACCESS_TIME), device.lastAccessTime);
|
||||
assertTrue(firstDevice.getAsLong(BrowserContract.RemoteDevices.DATE_CREATED) < timeBeforeCall + 10000); // Give 10 secs of leeway
|
||||
assertTrue(firstDevice.getAsLong(BrowserContract.RemoteDevices.DATE_MODIFIED) < timeBeforeCall + 10000);
|
||||
assertEquals(firstDevice.getAsString(BrowserContract.RemoteDevices.NAME), device.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBrowserProvider() {
|
||||
Uri uri = testUri(BrowserContract.RemoteDevices.CONTENT_URI);
|
||||
|
||||
BrowserProvider provider = new BrowserProvider();
|
||||
Cursor c = null;
|
||||
try {
|
||||
provider.onCreate();
|
||||
ShadowContentResolver.registerProvider(BrowserContract.AUTHORITY, new DelegatingTestContentProvider(provider));
|
||||
|
||||
final ShadowContentResolver cr = new ShadowContentResolver();
|
||||
ContentProviderClient remoteDevicesClient = cr.acquireContentProviderClient(BrowserContract.RemoteDevices.CONTENT_URI);
|
||||
|
||||
// First let's insert a client for initial state.
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
ContentValues device1 = createMockRemoteClientValues("device1");
|
||||
bundle.putParcelableArray(BrowserContract.METHOD_PARAM_DATA, new ContentValues[] { device1 });
|
||||
|
||||
remoteDevicesClient.call(BrowserContract.METHOD_REPLACE_REMOTE_CLIENTS, uri.toString(), bundle);
|
||||
|
||||
c = remoteDevicesClient.query(uri, null, null, null, "name ASC");
|
||||
assertEquals(c.getCount(), 1);
|
||||
c.moveToFirst();
|
||||
int nameCol = c.getColumnIndexOrThrow("name");
|
||||
assertEquals(c.getString(nameCol), "device1");
|
||||
c.close();
|
||||
|
||||
// Then we replace our remote clients list with a new one.
|
||||
|
||||
bundle = new Bundle();
|
||||
ContentValues device2 = createMockRemoteClientValues("device2");
|
||||
ContentValues device3 = createMockRemoteClientValues("device3");
|
||||
bundle.putParcelableArray(BrowserContract.METHOD_PARAM_DATA, new ContentValues[] { device2, device3 });
|
||||
|
||||
remoteDevicesClient.call(BrowserContract.METHOD_REPLACE_REMOTE_CLIENTS, uri.toString(), bundle);
|
||||
|
||||
c = remoteDevicesClient.query(uri, null, null, null, "name ASC");
|
||||
assertEquals(c.getCount(), 2);
|
||||
c.moveToFirst();
|
||||
nameCol = c.getColumnIndexOrThrow("name");
|
||||
assertEquals(c.getString(nameCol), "device2");
|
||||
c.moveToNext();
|
||||
assertEquals(c.getString(nameCol), "device3");
|
||||
c.close();
|
||||
} catch (RemoteException e) {
|
||||
fail(e.getMessage());
|
||||
} finally {
|
||||
if (c != null && !c.isClosed()) {
|
||||
c.close();
|
||||
}
|
||||
provider.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private Uri testUri(Uri baseUri) {
|
||||
return baseUri.buildUpon().appendQueryParameter(BrowserContract.PARAM_IS_TEST, "1").build();
|
||||
}
|
||||
|
||||
private ContentValues createMockRemoteClientValues(String name) {
|
||||
final long now = System.currentTimeMillis();
|
||||
ContentValues cli = new ContentValues();
|
||||
cli.put(BrowserContract.RemoteDevices.GUID, "R" + Math.floor(Math.random() * 10));
|
||||
cli.put(BrowserContract.RemoteDevices.NAME, name);
|
||||
cli.put(BrowserContract.RemoteDevices.TYPE, "mobile");
|
||||
cli.put(BrowserContract.RemoteDevices.IS_CURRENT_DEVICE, false);
|
||||
cli.put(BrowserContract.RemoteDevices.LAST_ACCESS_TIME, System.currentTimeMillis());
|
||||
cli.put(BrowserContract.RemoteDevices.DATE_CREATED, now);
|
||||
cli.put(BrowserContract.RemoteDevices.DATE_MODIFIED, now);
|
||||
return cli;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ package org.mozilla.gecko.fxa.login;
|
|||
import android.text.TextUtils;
|
||||
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClient;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClient20;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClient20.AccountStatusResponse;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClient20.RequestDelegate;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClient20.RecoveryEmailStatusResponse;
|
||||
|
@ -14,7 +15,7 @@ import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse;
|
|||
import org.mozilla.gecko.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountRemoteError;
|
||||
import org.mozilla.gecko.background.fxa.FxAccountUtils;
|
||||
import org.mozilla.gecko.fxa.devices.FxAccountDevice;
|
||||
import org.mozilla.gecko.fxa.FxAccountDevice;
|
||||
import org.mozilla.gecko.browserid.MockMyIDTokenFactory;
|
||||
import org.mozilla.gecko.browserid.RSACryptoImplementation;
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
|
@ -179,7 +180,7 @@ public class MockFxAccountClient implements FxAccountClient {
|
|||
String deviceId = deviceToRegister.id;
|
||||
if (TextUtils.isEmpty(deviceId)) { // Create
|
||||
deviceId = UUID.randomUUID().toString();
|
||||
FxAccountDevice device = new FxAccountDevice(deviceToRegister.name, deviceId, deviceToRegister.type, null, null, null, null, null);
|
||||
FxAccountDevice device = new FxAccountDevice(deviceToRegister.name, deviceId, deviceToRegister.type, null, null, null, null);
|
||||
requestDelegate.handleSuccess(device);
|
||||
} else { // Update
|
||||
FxAccountDevice existingDevice = user.devices.get(deviceId);
|
||||
|
@ -188,8 +189,8 @@ public class MockFxAccountClient implements FxAccountClient {
|
|||
if (!TextUtils.isEmpty(deviceToRegister.name)) {
|
||||
deviceName = deviceToRegister.name;
|
||||
} // We could also update the other fields..
|
||||
FxAccountDevice device = new FxAccountDevice(deviceName, existingDevice.id, existingDevice.type, existingDevice.isCurrentDevice,
|
||||
existingDevice.lastAccessTime, existingDevice.pushCallback, existingDevice.pushPublicKey,existingDevice.pushAuthKey);
|
||||
FxAccountDevice device = new FxAccountDevice(deviceName, existingDevice.id, existingDevice.type,
|
||||
existingDevice.isCurrentDevice, existingDevice.pushCallback, existingDevice.pushPublicKey,existingDevice.pushAuthKey);
|
||||
requestDelegate.handleSuccess(device);
|
||||
} else { // Device unknown
|
||||
handleFailure(requestDelegate, HttpStatus.SC_BAD_REQUEST, FxAccountRemoteError.UNKNOWN_DEVICE, "device is unknown");
|
||||
|
|
Двоичный файл не отображается.
Загрузка…
Ссылка в новой задаче