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:
Wes Kocher 2017-04-25 12:47:59 -07:00
Родитель ae260ad8c3
Коммит c9b3f40856
19 изменённых файлов: 54 добавлений и 548 удалений

Просмотреть файл

@ -831,11 +831,10 @@ sync_java_files = [TOPSRCDIR + '/mobile/android/services/src/main/java/org/mozil
'fxa/authenticator/FxAccountLoginDelegate.java', 'fxa/authenticator/FxAccountLoginDelegate.java',
'fxa/authenticator/FxAccountLoginException.java', 'fxa/authenticator/FxAccountLoginException.java',
'fxa/authenticator/FxADefaultLoginStateMachineDelegate.java', 'fxa/authenticator/FxADefaultLoginStateMachineDelegate.java',
'fxa/devices/FxAccountDevice.java',
'fxa/devices/FxAccountDeviceListUpdater.java',
'fxa/devices/FxAccountDeviceRegistrator.java',
'fxa/FirefoxAccounts.java', 'fxa/FirefoxAccounts.java',
'fxa/FxAccountConstants.java', 'fxa/FxAccountConstants.java',
'fxa/FxAccountDevice.java',
'fxa/FxAccountDeviceRegistrator.java',
'fxa/FxAccountPushHandler.java', 'fxa/FxAccountPushHandler.java',
'fxa/login/BaseRequestDelegate.java', 'fxa/login/BaseRequestDelegate.java',
'fxa/login/Cohabiting.java', 'fxa/login/Cohabiting.java',

Просмотреть файл

@ -19,6 +19,7 @@ import org.json.JSONException;
import org.mozilla.gecko.background.fxa.FxAccountUtils; import org.mozilla.gecko.background.fxa.FxAccountUtils;
import org.mozilla.gecko.fxa.FirefoxAccounts; import org.mozilla.gecko.fxa.FirefoxAccounts;
import org.mozilla.gecko.fxa.FxAccountConstants; import org.mozilla.gecko.fxa.FxAccountConstants;
import org.mozilla.gecko.fxa.FxAccountDeviceRegistrator;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.fxa.login.Engaged; import org.mozilla.gecko.fxa.login.Engaged;
import org.mozilla.gecko.fxa.login.State; 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 PARAM_GROUP_BY = "group_by";
public static final String METHOD_INSERT_HISTORY_WITH_VISITS_FROM_SYNC = "insertHistoryWithVisitsSync"; 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_RESULT = "methodResult";
public static final String METHOD_PARAM_OBJECT = "object"; public static final String METHOD_PARAM_OBJECT = "object";
public static final String METHOD_PARAM_DATA = "data"; 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 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 // Data storage for dynamic panels on about:home
@RobocopTarget @RobocopTarget
public static final class HomeItems implements CommonColumns { 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.Bookmarks;
import org.mozilla.gecko.db.BrowserContract.Combined; import org.mozilla.gecko.db.BrowserContract.Combined;
import org.mozilla.gecko.db.BrowserContract.Favicons; 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.History;
import org.mozilla.gecko.db.BrowserContract.Visits; import org.mozilla.gecko.db.BrowserContract.Visits;
import org.mozilla.gecko.db.BrowserContract.PageMetadata; 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 // 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. // 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"; public static final String DATABASE_NAME = "browser.db";
final protected Context mContext; 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_HISTORY = History.TABLE_NAME;
static final String TABLE_VISITS = Visits.TABLE_NAME; static final String TABLE_VISITS = Visits.TABLE_NAME;
static final String TABLE_PAGE_METADATA = PageMetadata.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_FAVICONS = Favicons.TABLE_NAME;
static final String TABLE_THUMBNAILS = Thumbnails.TABLE_NAME; static final String TABLE_THUMBNAILS = Thumbnails.TABLE_NAME;
static final String TABLE_READING_LIST = ReadingListItems.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 + ")"); + 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) { private void createBookmarksWithFaviconsView(SQLiteDatabase db) {
debug("Creating " + VIEW_BOOKMARKS_WITH_FAVICONS + " view"); debug("Creating " + VIEW_BOOKMARKS_WITH_FAVICONS + " view");
@ -768,8 +751,6 @@ public final class BrowserDatabaseHelper extends SQLiteOpenHelper {
createActivityStreamBlocklistTable(db); createActivityStreamBlocklistTable(db);
createPageMetadataTable(db); createPageMetadataTable(db);
createRemoteDevicesTable(db);
} }
/** /**
@ -1999,10 +1980,6 @@ public final class BrowserDatabaseHelper extends SQLiteOpenHelper {
createPageMetadataTable(db); createPageMetadataTable(db);
} }
private void upgradeDatabaseFrom36to37(final SQLiteDatabase db) {
createRemoteDevicesTable(db);
}
private void createV33CombinedView(final SQLiteDatabase db) { private void createV33CombinedView(final SQLiteDatabase db) {
db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED); db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED);
db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED_WITH_FAVICONS); db.execSQL("DROP VIEW IF EXISTS " + VIEW_COMBINED_WITH_FAVICONS);
@ -2138,10 +2115,6 @@ public final class BrowserDatabaseHelper extends SQLiteOpenHelper {
case 36: case 36:
upgradeDatabaseFrom35to36(db); upgradeDatabaseFrom35to36(db);
break; 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.Combined;
import org.mozilla.gecko.db.BrowserContract.FaviconColumns; import org.mozilla.gecko.db.BrowserContract.FaviconColumns;
import org.mozilla.gecko.db.BrowserContract.Favicons; 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.Highlights;
import org.mozilla.gecko.db.BrowserContract.History; import org.mozilla.gecko.db.BrowserContract.History;
import org.mozilla.gecko.db.BrowserContract.Visits; 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_URL_ANNOTATIONS = UrlAnnotations.TABLE_NAME;
static final String TABLE_ACTIVITY_STREAM_BLOCKLIST = ActivityStreamBlocklist.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_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_COMBINED = Combined.VIEW_NAME;
static final String VIEW_BOOKMARKS_WITH_FAVICONS = Bookmarks.VIEW_WITH_FAVICONS; 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 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 static final String DEFAULT_BOOKMARKS_SORT_ORDER = Bookmarks.TYPE
+ " ASC, " + Bookmarks.POSITION + " ASC, " + Bookmarks._ID + " ASC, " + Bookmarks.POSITION + " ASC, " + Bookmarks._ID
+ " ASC"; + " ASC";
@ -170,7 +165,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
static final Map<String, String> URL_ANNOTATIONS_PROJECTION_MAP; static final Map<String, String> URL_ANNOTATIONS_PROJECTION_MAP;
static final Map<String, String> VISIT_PROJECTION_MAP; static final Map<String, String> VISIT_PROJECTION_MAP;
static final Map<String, String> PAGE_METADATA_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 final Table[] sTables;
static { 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, ActivityStreamBlocklist.TABLE_NAME, ACTIVITY_STREAM_BLOCKLIST);
URI_MATCHER.addURI(BrowserContract.AUTHORITY, "highlight_candidates", HIGHLIGHT_CANDIDATES); 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 { private static class ShrinkMemoryReceiver extends BroadcastReceiver {
@ -670,20 +649,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
deleted = deletePageMetadata(uri, selection, selectionArgs); deleted = deletePageMetadata(uri, selection, selectionArgs);
break; 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: { default: {
Table table = findTableFor(match); Table table = findTableFor(match);
if (table == null) { if (table == null) {
@ -756,12 +721,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
break; break;
} }
case REMOTE_DEVICES: {
trace("Insert on REMOTE_DEVICES: " + uri);
id = insertFxADevice(uri, values);
break;
}
default: { default: {
Table table = findTableFor(match); Table table = findTableFor(match);
if (table == null) { if (table == null) {
@ -1432,20 +1391,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
break; 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: { default: {
Table table = findTableFor(match); Table table = findTableFor(match);
if (table == null) { if (table == null) {
@ -2052,13 +1997,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
TABLE_PAGE_METADATA, null, values, SQLiteDatabase.CONFLICT_REPLACE); 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) { private long insertUrlAnnotation(final Uri uri, final ContentValues values) {
final String url = values.getAsString(UrlAnnotations.URL); final String url = values.getAsString(UrlAnnotations.URL);
trace("Inserting url annotations for URL: " + 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); 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) { private void updateUrlAnnotation(final Uri uri, final ContentValues values, final String selection, final String[] selectionArgs) {
trace("Updating url annotation for URI: " + uri); trace("Updating url annotation for URI: " + uri);
@ -2344,23 +2275,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
result.putSerializable(BrowserContract.METHOD_RESULT, e); result.putSerializable(BrowserContract.METHOD_RESULT, e);
} }
break; 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: default:
throw new IllegalArgumentException("Unknown method call: " + method); throw new IllegalArgumentException("Unknown method call: " + method);
} }
@ -2368,40 +2282,6 @@ public class BrowserProvider extends SharedBrowserDatabaseProvider {
return result; 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) { private void bulkInsertHistoryWithVisits(final SQLiteDatabase db, @NonNull Bundle dataBundle) {
// NB: dataBundle structure: // NB: dataBundle structure:
// Key METHOD_PARAM_DATA=[Bundle,...] // Key METHOD_PARAM_DATA=[Bundle,...]

Просмотреть файл

@ -25,7 +25,7 @@ import org.mozilla.gecko.TelemetryContract;
import org.mozilla.gecko.annotation.ReflectionTarget; import org.mozilla.gecko.annotation.ReflectionTarget;
import org.mozilla.gecko.db.BrowserDB; import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.fxa.FxAccountConstants; 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.FxAccountPushHandler;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.fxa.login.State; 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.RecoveryEmailStatusResponse;
import org.mozilla.gecko.background.fxa.FxAccountClient20.RequestDelegate; import org.mozilla.gecko.background.fxa.FxAccountClient20.RequestDelegate;
import org.mozilla.gecko.background.fxa.FxAccountClient20.TwoKeys; 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 org.mozilla.gecko.sync.ExtendedJSONObject;
import java.util.List; 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.background.fxa.FxAccountClientException.FxAccountClientRemoteException;
import org.mozilla.gecko.fxa.FxAccountConstants; import org.mozilla.gecko.fxa.FxAccountConstants;
import org.mozilla.gecko.Locales; 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.ExtendedJSONObject;
import org.mozilla.gecko.sync.Utils; import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.sync.crypto.HKDF; 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 * 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/. */ * 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; import org.mozilla.gecko.sync.ExtendedJSONObject;
public class FxAccountDevice { public class FxAccountDevice {
private static final String JSON_KEY_NAME = "name"; public static final String JSON_KEY_NAME = "name";
private static final String JSON_KEY_ID = "id"; public static final String JSON_KEY_ID = "id";
private static final String JSON_KEY_TYPE = "type"; public static final String JSON_KEY_TYPE = "type";
private static final String JSON_KEY_ISCURRENTDEVICE = "isCurrentDevice"; public static final String JSON_KEY_ISCURRENTDEVICE = "isCurrentDevice";
private static final String JSON_KEY_PUSH_CALLBACK = "pushCallback"; public static final String JSON_KEY_PUSH_CALLBACK = "pushCallback";
private static final String JSON_KEY_PUSH_PUBLICKEY = "pushPublicKey"; public static final String JSON_KEY_PUSH_PUBLICKEY = "pushPublicKey";
private static final String JSON_KEY_PUSH_AUTHKEY = "pushAuthKey"; public static final String JSON_KEY_PUSH_AUTHKEY = "pushAuthKey";
private static final String JSON_LAST_ACCESS_TIME = "lastAccessTime";
public final String id; public final String id;
public final String name; public final String name;
public final String type; public final String type;
public final Boolean isCurrentDevice; public final Boolean isCurrentDevice;
public final Long lastAccessTime;
public final String pushCallback; public final String pushCallback;
public final String pushPublicKey; public final String pushPublicKey;
public final String pushAuthKey; public final String pushAuthKey;
public FxAccountDevice(String name, String id, String type, Boolean isCurrentDevice, public FxAccountDevice(String name, String id, String type, Boolean isCurrentDevice,
Long lastAccessTime, String pushCallback, String pushPublicKey, String pushCallback, String pushPublicKey, String pushAuthKey) {
String pushAuthKey) {
this.name = name; this.name = name;
this.id = id; this.id = id;
this.type = type; this.type = type;
this.isCurrentDevice = isCurrentDevice; this.isCurrentDevice = isCurrentDevice;
this.lastAccessTime = lastAccessTime;
this.pushCallback = pushCallback; this.pushCallback = pushCallback;
this.pushPublicKey = pushPublicKey; this.pushPublicKey = pushPublicKey;
this.pushAuthKey = pushAuthKey; this.pushAuthKey = pushAuthKey;
} }
public static FxAccountDevice fromJson(ExtendedJSONObject json) { public static FxAccountDevice fromJson(ExtendedJSONObject json) {
final String name = json.getString(JSON_KEY_NAME); String name = json.getString(JSON_KEY_NAME);
final String id = json.getString(JSON_KEY_ID); String id = json.getString(JSON_KEY_ID);
final String type = json.getString(JSON_KEY_TYPE); String type = json.getString(JSON_KEY_TYPE);
final Boolean isCurrentDevice = json.getBoolean(JSON_KEY_ISCURRENTDEVICE); Boolean isCurrentDevice = json.getBoolean(JSON_KEY_ISCURRENTDEVICE);
final Long lastAccessTime = json.getLong(JSON_LAST_ACCESS_TIME); String pushCallback = json.getString(JSON_KEY_PUSH_CALLBACK);
final String pushCallback = json.getString(JSON_KEY_PUSH_CALLBACK); String pushPublicKey = json.getString(JSON_KEY_PUSH_PUBLICKEY);
final String pushPublicKey = json.getString(JSON_KEY_PUSH_PUBLICKEY); String pushAuthKey = json.getString(JSON_KEY_PUSH_AUTHKEY);
final String pushAuthKey = json.getString(JSON_KEY_PUSH_AUTHKEY); return new FxAccountDevice(name, id, type, isCurrentDevice, pushCallback, pushPublicKey, pushAuthKey);
return new FxAccountDevice(name, id, type, isCurrentDevice, lastAccessTime, pushCallback,
pushPublicKey, pushAuthKey);
} }
public ExtendedJSONObject toJson() { public ExtendedJSONObject toJson() {
@ -79,6 +73,7 @@ public class FxAccountDevice {
private String id; private String id;
private String name; private String name;
private String type; private String type;
private Boolean isCurrentDevice;
private String pushCallback; private String pushCallback;
private String pushPublicKey; private String pushPublicKey;
private String pushAuthKey; private String pushAuthKey;
@ -95,6 +90,10 @@ public class FxAccountDevice {
this.type = type; this.type = type;
} }
public void isCurrentDevice() {
this.isCurrentDevice = Boolean.TRUE;
}
public void pushCallback(String pushCallback) { public void pushCallback(String pushCallback) {
this.pushCallback = pushCallback; this.pushCallback = pushCallback;
} }
@ -108,7 +107,7 @@ public class FxAccountDevice {
} }
public FxAccountDevice build() { 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); 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 * 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/. */ * 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.Context;
import android.content.Intent; import android.content.Intent;
@ -378,9 +378,8 @@ public class FxAccountDeviceRegistrator implements BundleEventListener {
break; break;
} }
final FxAccountDevice updatedDevice = new FxAccountDevice(device.name, fxaDevice.id, device.type, final FxAccountDevice updatedDevice = new FxAccountDevice(device.name, fxaDevice.id, device.type,
null, null, device.isCurrentDevice, device.pushCallback,
device.pushCallback, device.pushPublicKey, device.pushPublicKey, device.pushAuthKey);
device.pushAuthKey);
doFxaRegistration(context, fxAccount, updatedDevice, false); doFxaRegistration(context, fxAccount, updatedDevice, false);
return; 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); final String numStr = accountManager.getUserData(account, key);
if (TextUtils.isEmpty(numStr)) { if (TextUtils.isEmpty(numStr)) {
return defaultValue; return defaultValue;
} }
try { try {
return Long.parseLong(key); return (T) NumberFormat.getInstance().parse(numStr);
} catch (NumberFormatException e) { } catch (ParseException e) {
Logger.warn(LOG_TAG, "Couldn't parse " + key + "; defaulting to " + defaultValue, e); Logger.warn(LOG_TAG, "Couldn't parse " + key + "; defaulting to 0L.", e);
return defaultValue; return defaultValue;
} }
} }
@ -824,28 +825,19 @@ public class AndroidFxAccount {
} }
public synchronized int getDeviceRegistrationVersion() { public synchronized int getDeviceRegistrationVersion() {
final String numStr = accountManager.getUserData(account, ACCOUNT_KEY_DEVICE_REGISTRATION_VERSION); return getUserDataNumber(ACCOUNT_KEY_DEVICE_REGISTRATION_VERSION, 0);
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;
}
} }
public synchronized long getDeviceRegistrationTimestamp() { public synchronized long getDeviceRegistrationTimestamp() {
return getUserDataLong(ACCOUNT_KEY_DEVICE_REGISTRATION_TIMESTAMP, 0L); return getUserDataNumber(ACCOUNT_KEY_DEVICE_REGISTRATION_TIMESTAMP, 0L);
} }
public synchronized long getDevicePushRegistrationError() { 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() { 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) { 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; package org.mozilla.gecko.fxa.receivers;
import android.app.IntentService; import android.app.IntentService;
import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import org.mozilla.gecko.background.common.log.Logger; 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.FxAccountAbstractClient;
import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClientException.FxAccountAbstractClientRemoteException; import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClientException.FxAccountAbstractClientRemoteException;
import org.mozilla.gecko.background.fxa.oauth.FxAccountOAuthClient10; 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.FxAccountConstants;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.fxa.sync.FxAccountNotificationManager; import org.mozilla.gecko.fxa.sync.FxAccountNotificationManager;
@ -78,8 +75,6 @@ public class FxAccountDeletedService extends IntentService {
return; return;
} }
clearRemoteDevicesList(intent, context);
// Delete current device the from FxA devices list. // Delete current device the from FxA devices list.
deleteFxADevice(intent); 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. // Remove our current device from the FxA device list.
private void deleteFxADevice(Intent intent) { private void deleteFxADevice(Intent intent) {
final byte[] sessionToken = intent.getByteArrayExtra(FxAccountConstants.ACCOUNT_DELETED_INTENT_ACCOUNT_SESSION_TOKEN); 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.accounts.Account;
import android.content.AbstractThreadedSyncAdapter; import android.content.AbstractThreadedSyncAdapter;
import android.content.ContentProvider;
import android.content.ContentProviderClient; import android.content.ContentProviderClient;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; 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.browserid.JSONWebTokenUtils;
import org.mozilla.gecko.fxa.FirefoxAccounts; import org.mozilla.gecko.fxa.FirefoxAccounts;
import org.mozilla.gecko.fxa.FxAccountConstants; import org.mozilla.gecko.fxa.FxAccountConstants;
import org.mozilla.gecko.fxa.devices.FxAccountDeviceListUpdater; import org.mozilla.gecko.fxa.FxAccountDeviceRegistrator;
import org.mozilla.gecko.fxa.devices.FxAccountDeviceRegistrator;
import org.mozilla.gecko.fxa.authenticator.AccountPickler; import org.mozilla.gecko.fxa.authenticator.AccountPickler;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.fxa.authenticator.FxADefaultLoginStateMachineDelegate; 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.fxa.sync.FxAccountSyncDelegate.Result;
import org.mozilla.gecko.sync.BackoffHandler; import org.mozilla.gecko.sync.BackoffHandler;
import org.mozilla.gecko.sync.GlobalSession; import org.mozilla.gecko.sync.GlobalSession;
import org.mozilla.gecko.sync.MetaGlobal;
import org.mozilla.gecko.sync.PrefsBackoffHandler; import org.mozilla.gecko.sync.PrefsBackoffHandler;
import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate; import org.mozilla.gecko.sync.SharedPreferencesClientsDataDelegate;
import org.mozilla.gecko.sync.SyncConfiguration; 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, * A trivial Sync implementation that does not cache client keys,
* certificates, or tokens. * certificates, or tokens.
@ -556,7 +546,7 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
schedulePolicy.onHandleFinal(notMarried.getNeededAction()); schedulePolicy.onHandleFinal(notMarried.getNeededAction());
syncDelegate.handleCannotSync(notMarried); syncDelegate.handleCannotSync(notMarried);
if (notMarried.getStateLabel() == StateLabel.Engaged) { if (notMarried.getStateLabel() == StateLabel.Engaged) {
onSessionTokenStateReached(context, fxAccount); maybeRegisterDevice(context, fxAccount);
} }
} }
@ -599,8 +589,6 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
return; return;
} }
onSessionTokenStateReached(context, fxAccount);
final SessionCallback sessionCallback = new SessionCallback(syncDelegate, schedulePolicy); final SessionCallback sessionCallback = new SessionCallback(syncDelegate, schedulePolicy);
final KeyBundle syncKeyBundle = married.getSyncKeyBundle(); final KeyBundle syncKeyBundle = married.getSyncKeyBundle();
final String clientState = married.getClientState(); final String clientState = married.getClientState();
@ -608,6 +596,8 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
assertion, tokenServerEndpointURI, tokenBackoffHandler, sharedPrefs, assertion, tokenServerEndpointURI, tokenBackoffHandler, sharedPrefs,
syncKeyBundle, clientState, sessionCallback, extras, fxAccount, syncDeadline); syncKeyBundle, clientState, sessionCallback, extras, fxAccount, syncDeadline);
maybeRegisterDevice(context, fxAccount);
// Force fetch the profile avatar information. (asynchronous, in another thread) // Force fetch the profile avatar information. (asynchronous, in another thread)
Logger.info(LOG_TAG, "Fetching profile avatar information."); Logger.info(LOG_TAG, "Fetching profile avatar information.");
fxAccount.fetchProfileJSON(); fxAccount.fetchProfileJSON();

Просмотреть файл

@ -6,6 +6,7 @@ package org.mozilla.gecko.sync;
import org.mozilla.gecko.background.fxa.FxAccountUtils; import org.mozilla.gecko.background.fxa.FxAccountUtils;
import org.mozilla.gecko.fxa.FirefoxAccounts; import org.mozilla.gecko.fxa.FirefoxAccounts;
import org.mozilla.gecko.fxa.FxAccountDeviceRegistrator;
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.sync.delegates.ClientsDataDelegate; import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
import org.mozilla.gecko.util.HardwareUtils; import org.mozilla.gecko.util.HardwareUtils;

Просмотреть файл

@ -1,7 +1,7 @@
/* Any copyright is dedicated to the Public Domain. /* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */ 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.Before;
import org.junit.Test; 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 android.text.TextUtils;
import org.mozilla.gecko.background.fxa.FxAccountClient; 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.AccountStatusResponse;
import org.mozilla.gecko.background.fxa.FxAccountClient20.RequestDelegate; import org.mozilla.gecko.background.fxa.FxAccountClient20.RequestDelegate;
import org.mozilla.gecko.background.fxa.FxAccountClient20.RecoveryEmailStatusResponse; 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.FxAccountClientException.FxAccountClientRemoteException;
import org.mozilla.gecko.background.fxa.FxAccountRemoteError; import org.mozilla.gecko.background.fxa.FxAccountRemoteError;
import org.mozilla.gecko.background.fxa.FxAccountUtils; 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.MockMyIDTokenFactory;
import org.mozilla.gecko.browserid.RSACryptoImplementation; import org.mozilla.gecko.browserid.RSACryptoImplementation;
import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.ExtendedJSONObject;
@ -179,7 +180,7 @@ public class MockFxAccountClient implements FxAccountClient {
String deviceId = deviceToRegister.id; String deviceId = deviceToRegister.id;
if (TextUtils.isEmpty(deviceId)) { // Create if (TextUtils.isEmpty(deviceId)) { // Create
deviceId = UUID.randomUUID().toString(); 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); requestDelegate.handleSuccess(device);
} else { // Update } else { // Update
FxAccountDevice existingDevice = user.devices.get(deviceId); FxAccountDevice existingDevice = user.devices.get(deviceId);
@ -188,8 +189,8 @@ public class MockFxAccountClient implements FxAccountClient {
if (!TextUtils.isEmpty(deviceToRegister.name)) { if (!TextUtils.isEmpty(deviceToRegister.name)) {
deviceName = deviceToRegister.name; deviceName = deviceToRegister.name;
} // We could also update the other fields.. } // We could also update the other fields..
FxAccountDevice device = new FxAccountDevice(deviceName, existingDevice.id, existingDevice.type, existingDevice.isCurrentDevice, FxAccountDevice device = new FxAccountDevice(deviceName, existingDevice.id, existingDevice.type,
existingDevice.lastAccessTime, existingDevice.pushCallback, existingDevice.pushPublicKey,existingDevice.pushAuthKey); existingDevice.isCurrentDevice, existingDevice.pushCallback, existingDevice.pushPublicKey,existingDevice.pushAuthKey);
requestDelegate.handleSuccess(device); requestDelegate.handleSuccess(device);
} else { // Device unknown } else { // Device unknown
handleFailure(requestDelegate, HttpStatus.SC_BAD_REQUEST, FxAccountRemoteError.UNKNOWN_DEVICE, "device is unknown"); handleFailure(requestDelegate, HttpStatus.SC_BAD_REQUEST, FxAccountRemoteError.UNKNOWN_DEVICE, "device is unknown");

Двоичный файл не отображается.