зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1097220 - Extend client record format on Android. r=nalexander
This commit is contained in:
Родитель
8454984605
Коммит
0aacd30a3a
|
@ -7,6 +7,7 @@ package org.mozilla.gecko.sync;
|
|||
import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.background.common.GlobalConstants;
|
||||
import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
@ -22,6 +23,9 @@ public class SharedPreferencesClientsDataDelegate implements ClientsDataDelegate
|
|||
public SharedPreferencesClientsDataDelegate(SharedPreferences sharedPreferences, Context context) {
|
||||
this.sharedPreferences = sharedPreferences;
|
||||
this.context = context;
|
||||
|
||||
// It's safe to init this multiple times.
|
||||
HardwareUtils.init(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,4 +96,21 @@ public class SharedPreferencesClientsDataDelegate implements ClientsDataDelegate
|
|||
public long getLastModifiedTimestamp() {
|
||||
return sharedPreferences.getLong(SyncConfiguration.PREF_CLIENT_DATA_TIMESTAMP, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFormFactor() {
|
||||
if (HardwareUtils.isLargeTablet()) {
|
||||
return "largetablet";
|
||||
}
|
||||
|
||||
if (HardwareUtils.isSmallTablet()) {
|
||||
return "smalltablet";
|
||||
}
|
||||
|
||||
if (HardwareUtils.isTelevision()) {
|
||||
return "tv";
|
||||
}
|
||||
|
||||
return "phone";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ public interface ClientsDataDelegate {
|
|||
public void setClientsCount(int clientsCount);
|
||||
public int getClientsCount();
|
||||
public boolean isLocalGUID(String guid);
|
||||
public String getFormFactor();
|
||||
|
||||
/**
|
||||
* The last time the client's data was modified in a way that should be
|
||||
|
|
|
@ -19,7 +19,7 @@ public class ClientsDatabase extends CachedSQLiteOpenHelper {
|
|||
|
||||
// Database Specifications.
|
||||
protected static final String DB_NAME = "clients_database";
|
||||
protected static final int SCHEMA_VERSION = 2;
|
||||
protected static final int SCHEMA_VERSION = 3;
|
||||
|
||||
// Clients Table.
|
||||
public static final String TBL_CLIENTS = "clients";
|
||||
|
@ -28,7 +28,15 @@ public class ClientsDatabase extends CachedSQLiteOpenHelper {
|
|||
public static final String COL_NAME = "name";
|
||||
public static final String COL_TYPE = "device_type";
|
||||
|
||||
public static final String[] TBL_CLIENTS_COLUMNS = new String[] { COL_ACCOUNT_GUID, COL_PROFILE, COL_NAME, COL_TYPE };
|
||||
// Optional fields.
|
||||
public static final String COL_FORMFACTOR = "formfactor";
|
||||
public static final String COL_OS = "os";
|
||||
public static final String COL_APPLICATION = "application";
|
||||
public static final String COL_APP_PACKAGE = "appPackage";
|
||||
public static final String COL_DEVICE = "device";
|
||||
|
||||
public static final String[] TBL_CLIENTS_COLUMNS = new String[] { COL_ACCOUNT_GUID, COL_PROFILE, COL_NAME, COL_TYPE,
|
||||
COL_FORMFACTOR, COL_OS, COL_APPLICATION, COL_APP_PACKAGE, COL_DEVICE };
|
||||
public static final String TBL_CLIENTS_KEY = COL_ACCOUNT_GUID + " = ? AND " +
|
||||
COL_PROFILE + " = ?";
|
||||
|
||||
|
@ -65,6 +73,11 @@ public class ClientsDatabase extends CachedSQLiteOpenHelper {
|
|||
+ COL_PROFILE + " TEXT, "
|
||||
+ COL_NAME + " TEXT, "
|
||||
+ COL_TYPE + " TEXT, "
|
||||
+ COL_FORMFACTOR + " TEXT, "
|
||||
+ COL_OS + " TEXT, "
|
||||
+ COL_APPLICATION + " TEXT, "
|
||||
+ COL_APP_PACKAGE + " TEXT, "
|
||||
+ COL_DEVICE + " TEXT, "
|
||||
+ "PRIMARY KEY (" + COL_ACCOUNT_GUID + ", " + COL_PROFILE + "))";
|
||||
db.execSQL(createClientsTableSql);
|
||||
}
|
||||
|
@ -82,16 +95,28 @@ public class ClientsDatabase extends CachedSQLiteOpenHelper {
|
|||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
Logger.debug(LOG_TAG, "ClientsDatabase.onUpgrade().");
|
||||
// For now we'll just drop and recreate the tables.
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TBL_CLIENTS);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TBL_COMMANDS);
|
||||
onCreate(db);
|
||||
Logger.debug(LOG_TAG, "ClientsDatabase.onUpgrade(" + oldVersion + ", " + newVersion + ").");
|
||||
if (oldVersion < 2) {
|
||||
// For now we'll just drop and recreate the tables.
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TBL_CLIENTS);
|
||||
db.execSQL("DROP TABLE IF EXISTS " + TBL_COMMANDS);
|
||||
onCreate(db);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newVersion >= 3) {
|
||||
// Add the optional columns to clients.
|
||||
db.execSQL("ALTER TABLE " + TBL_CLIENTS + " ADD COLUMN " + COL_FORMFACTOR + " TEXT");
|
||||
db.execSQL("ALTER TABLE " + TBL_CLIENTS + " ADD COLUMN " + COL_OS + " TEXT");
|
||||
db.execSQL("ALTER TABLE " + TBL_CLIENTS + " ADD COLUMN " + COL_APPLICATION + " TEXT");
|
||||
db.execSQL("ALTER TABLE " + TBL_CLIENTS + " ADD COLUMN " + COL_APP_PACKAGE + " TEXT");
|
||||
db.execSQL("ALTER TABLE " + TBL_CLIENTS + " ADD COLUMN " + COL_DEVICE + " TEXT");
|
||||
}
|
||||
}
|
||||
|
||||
public void wipeDB() {
|
||||
SQLiteDatabase db = this.getCachedWritableDatabase();
|
||||
onUpgrade(db, SCHEMA_VERSION, SCHEMA_VERSION);
|
||||
onUpgrade(db, 0, SCHEMA_VERSION);
|
||||
}
|
||||
|
||||
public void wipeClientsTable() {
|
||||
|
@ -115,6 +140,26 @@ public class ClientsDatabase extends CachedSQLiteOpenHelper {
|
|||
cv.put(COL_NAME, record.name);
|
||||
cv.put(COL_TYPE, record.type);
|
||||
|
||||
if (record.formfactor != null) {
|
||||
cv.put(COL_FORMFACTOR, record.formfactor);
|
||||
}
|
||||
|
||||
if (record.os != null) {
|
||||
cv.put(COL_OS, record.os);
|
||||
}
|
||||
|
||||
if (record.application != null) {
|
||||
cv.put(COL_APPLICATION, record.application);
|
||||
}
|
||||
|
||||
if (record.appPackage != null) {
|
||||
cv.put(COL_APP_PACKAGE, record.appPackage);
|
||||
}
|
||||
|
||||
if (record.device != null) {
|
||||
cv.put(COL_DEVICE, record.device);
|
||||
}
|
||||
|
||||
String[] args = new String[] { record.guid, profileId };
|
||||
int rowsUpdated = db.update(TBL_CLIENTS, cv, TBL_CLIENTS_KEY, args);
|
||||
|
||||
|
|
|
@ -118,12 +118,21 @@ public class ClientsDatabaseAccessor {
|
|||
}
|
||||
|
||||
protected static ClientRecord recordFromCursor(Cursor cur) {
|
||||
String accountGUID = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_ACCOUNT_GUID);
|
||||
String clientName = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_NAME);
|
||||
String clientType = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_TYPE);
|
||||
ClientRecord record = new ClientRecord(accountGUID);
|
||||
final String accountGUID = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_ACCOUNT_GUID);
|
||||
final String clientName = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_NAME);
|
||||
final String clientType = RepoUtils.getStringFromCursor(cur, ClientsDatabase.COL_TYPE);
|
||||
|
||||
final ClientRecord record = new ClientRecord(accountGUID);
|
||||
record.name = clientName;
|
||||
record.type = clientType;
|
||||
|
||||
// Optional fields. These will either be null or strings.
|
||||
record.formfactor = RepoUtils.optStringFromCursor(cur, ClientsDatabase.COL_FORMFACTOR);
|
||||
record.os = RepoUtils.optStringFromCursor(cur, ClientsDatabase.COL_OS);
|
||||
record.device = RepoUtils.optStringFromCursor(cur, ClientsDatabase.COL_DEVICE);
|
||||
record.appPackage = RepoUtils.optStringFromCursor(cur, ClientsDatabase.COL_APP_PACKAGE);
|
||||
record.application = RepoUtils.optStringFromCursor(cur, ClientsDatabase.COL_APPLICATION);
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,24 @@ public class RepoUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static String getStringFromCursor(Cursor cur, String colId) {
|
||||
/**
|
||||
* This method exists because the behavior of <code>cur.getString()</code> is undefined
|
||||
* when the value in the database is <code>NULL</code>.
|
||||
* This method will return <code>null</code> in that case.
|
||||
*/
|
||||
public static String optStringFromCursor(final Cursor cur, final String colId) {
|
||||
final int col = cur.getColumnIndex(colId);
|
||||
if (cur.isNull(col)) {
|
||||
return null;
|
||||
}
|
||||
return cur.getString(col);
|
||||
}
|
||||
|
||||
/**
|
||||
* The behavior of this method when the value in the database is <code>NULL</code> is
|
||||
* determined by the implementation of the {@link Cursor}.
|
||||
*/
|
||||
public static String getStringFromCursor(final Cursor cur, final String colId) {
|
||||
// TODO: getColumnIndexOrThrow?
|
||||
// TODO: don't look up columns by name!
|
||||
return cur.getString(cur.getColumnIndex(colId));
|
||||
|
|
|
@ -41,6 +41,16 @@ public class ClientRecord extends Record {
|
|||
public JSONArray commands;
|
||||
public JSONArray protocols;
|
||||
|
||||
// Optional fields.
|
||||
// See <https://github.com/mozilla-services/docs/blob/master/source/sync/objectformats.rst#user-content-clients>
|
||||
// for full formats.
|
||||
// If a value isn't known, the field is omitted.
|
||||
public String formfactor; // "phone", "largetablet", "smalltablet", "desktop", "laptop", "tv".
|
||||
public String os; // One of "Android", "Darwin", "WINNT", "Linux", "iOS", "Firefox OS".
|
||||
public String application; // Display name, E.g., "Firefox Beta"
|
||||
public String appPackage; // E.g., "org.mozilla.firefox_beta"
|
||||
public String device; // E.g., "HTC One"
|
||||
|
||||
public ClientRecord(String guid, String collection, long lastModified, boolean deleted) {
|
||||
super(guid, collection, lastModified, deleted);
|
||||
this.ttl = CLIENTS_TTL;
|
||||
|
@ -85,6 +95,26 @@ public class ClientRecord extends Record {
|
|||
Logger.debug(LOG_TAG, "Got non-array protocols in client record " + guid, e);
|
||||
protocols = null;
|
||||
}
|
||||
|
||||
if (payload.containsKey("formfactor")) {
|
||||
this.formfactor = payload.getString("formfactor");
|
||||
}
|
||||
|
||||
if (payload.containsKey("os")) {
|
||||
this.os = payload.getString("os");
|
||||
}
|
||||
|
||||
if (payload.containsKey("application")) {
|
||||
this.application = payload.getString("application");
|
||||
}
|
||||
|
||||
if (payload.containsKey("appPackage")) {
|
||||
this.appPackage = payload.getString("appPackage");
|
||||
}
|
||||
|
||||
if (payload.containsKey("device")) {
|
||||
this.device = payload.getString("device");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,6 +131,27 @@ public class ClientRecord extends Record {
|
|||
if (this.protocols != null) {
|
||||
payload.put("protocols", this.protocols);
|
||||
}
|
||||
|
||||
|
||||
if (this.formfactor != null) {
|
||||
payload.put("formfactor", this.formfactor);
|
||||
}
|
||||
|
||||
if (this.os != null) {
|
||||
payload.put("os", this.os);
|
||||
}
|
||||
|
||||
if (this.application != null) {
|
||||
payload.put("application", this.application);
|
||||
}
|
||||
|
||||
if (this.appPackage != null) {
|
||||
payload.put("appPackage", this.appPackage);
|
||||
}
|
||||
|
||||
if (this.device != null) {
|
||||
payload.put("device", this.device);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -123,7 +174,7 @@ public class ClientRecord extends Record {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Don't compare versions or protocols, no matter how much we might want to.
|
||||
// Don't compare versions, protocols, or other optional fields, no matter how much we might want to.
|
||||
// They're not required by the spec.
|
||||
ClientRecord other = (ClientRecord) o;
|
||||
if (!RepoUtils.stringsEqual(other.name, this.name) ||
|
||||
|
@ -144,6 +195,13 @@ public class ClientRecord extends Record {
|
|||
out.type = this.type;
|
||||
out.version = this.version;
|
||||
out.protocols = this.protocols;
|
||||
|
||||
out.formfactor = this.formfactor;
|
||||
out.os = this.os;
|
||||
out.application = this.application;
|
||||
out.appPackage = this.appPackage;
|
||||
out.device = this.device;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.mozilla.gecko.AppConstants;
|
||||
import org.mozilla.gecko.background.common.GlobalConstants;
|
||||
import org.mozilla.gecko.background.common.log.Logger;
|
||||
import org.mozilla.gecko.sync.CommandProcessor;
|
||||
|
@ -38,7 +39,9 @@ import org.mozilla.gecko.sync.repositories.android.RepoUtils;
|
|||
import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
|
||||
import org.mozilla.gecko.sync.repositories.domain.ClientRecordFactory;
|
||||
import org.mozilla.gecko.sync.repositories.domain.VersionConstants;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
|
||||
import android.content.Context;
|
||||
import ch.boye.httpclientandroidlib.HttpStatus;
|
||||
|
||||
public class SyncClientsEngineStage extends AbstractSessionManagingSyncStage {
|
||||
|
@ -378,6 +381,13 @@ public class SyncClientsEngineStage extends AbstractSessionManagingSyncStage {
|
|||
r.name = ourName;
|
||||
r.version = getLocalClientVersion();
|
||||
r.protocols = getLocalClientProtocols();
|
||||
|
||||
r.os = "Android";
|
||||
r.application = GlobalConstants.MOZ_APP_DISPLAYNAME;
|
||||
r.appPackage = AppConstants.ANDROID_PACKAGE_NAME;
|
||||
r.device = android.os.Build.MODEL;
|
||||
r.formfactor = delegate.getFormFactor();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -63,16 +63,25 @@ public class TestClientsStage extends AndroidSyncTestCase {
|
|||
}
|
||||
};
|
||||
|
||||
String guid = "clientabcdef";
|
||||
final String guid = "clientabcdef";
|
||||
long lastModified = System.currentTimeMillis();
|
||||
ClientRecord record = new ClientRecord(guid, "clients", lastModified , false);
|
||||
record.name = "John's Phone";
|
||||
record.type = "mobile";
|
||||
record.device = "Some Device";
|
||||
record.os = "iOS";
|
||||
record.commands = new JSONArray();
|
||||
|
||||
dataAccessor.store(record);
|
||||
assertEquals(1, dataAccessor.clientsCount());
|
||||
|
||||
final ClientRecord stored = dataAccessor.fetchAllClients().get(guid);
|
||||
assertNotNull(stored);
|
||||
assertEquals("John's Phone", stored.name);
|
||||
assertEquals("mobile", stored.type);
|
||||
assertEquals("Some Device", stored.device);
|
||||
assertEquals("iOS", stored.os);
|
||||
|
||||
stage.wipeLocal(session);
|
||||
|
||||
try {
|
||||
|
|
|
@ -58,4 +58,9 @@ public class MockClientsDataDelegate implements ClientsDataDelegate {
|
|||
public synchronized long getLastModifiedTimestamp() {
|
||||
return clientDataTimestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFormFactor() {
|
||||
return "phone";
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче