Bug 1021055 - Add Sync client device type to Fennec's tabs provider. r=rnewman

This is the expedient thing to do.  The right thing to do is to
deprecate Sync's clients database in favour of Fennec's clients table,
but that's a good chunk of work for a small gain.
This commit is contained in:
Nick Alexander 2014-06-11 14:20:24 -07:00
parent c4bedd5427
commit 943b7aee84
4 changed files with 90 additions and 3 deletions

View File

@ -328,6 +328,8 @@ public class BrowserContract {
// Last modified time for the client's tab record. For remote records, a server
// timestamp provided by Sync during insertion.
public static final String LAST_MODIFIED = "last_modified";
public static final String DEVICE_TYPE = "device_type";
}
// Data storage for dynamic panels on about:home

View File

@ -26,7 +26,7 @@ import android.text.TextUtils;
public class TabsProvider extends PerProfileDatabaseProvider<TabsProvider.TabsDatabaseHelper> {
static final String DATABASE_NAME = "tabs.db";
static final int DATABASE_VERSION = 2;
static final int DATABASE_VERSION = 3;
static final String TABLE_TABS = "tabs";
static final String TABLE_CLIENTS = "clients";
@ -67,12 +67,14 @@ public class TabsProvider extends PerProfileDatabaseProvider<TabsProvider.TabsDa
map.put(Clients.GUID, Clients.GUID);
map.put(Clients.NAME, Clients.NAME);
map.put(Clients.LAST_MODIFIED, Clients.LAST_MODIFIED);
map.put(Clients.DEVICE_TYPE, Clients.DEVICE_TYPE);
TABS_PROJECTION_MAP = Collections.unmodifiableMap(map);
map = new HashMap<String, String>();
map.put(Clients.GUID, Clients.GUID);
map.put(Clients.NAME, Clients.NAME);
map.put(Clients.LAST_MODIFIED, Clients.LAST_MODIFIED);
map.put(Clients.DEVICE_TYPE, Clients.DEVICE_TYPE);
CLIENTS_PROJECTION_MAP = Collections.unmodifiableMap(map);
}
@ -114,7 +116,8 @@ public class TabsProvider extends PerProfileDatabaseProvider<TabsProvider.TabsDa
db.execSQL("CREATE TABLE " + TABLE_CLIENTS + "(" +
Clients.GUID + " TEXT PRIMARY KEY," +
Clients.NAME + " TEXT," +
Clients.LAST_MODIFIED + " INTEGER" +
Clients.LAST_MODIFIED + " INTEGER," +
Clients.DEVICE_TYPE + " TEXT" +
");");
// Index on GUID.
@ -133,6 +136,14 @@ public class TabsProvider extends PerProfileDatabaseProvider<TabsProvider.TabsDa
db.insertOrThrow(TABLE_CLIENTS, null, values);
}
protected void upgradeDatabaseFrom2to3(SQLiteDatabase db) {
debug("Setting remote client device types to 'mobile' in " + TABLE_CLIENTS + " table");
// Add type to client, defaulting to mobile. This is correct for our
// local client; all remote clients will be updated by Sync.
db.execSQL("ALTER TABLE " + TABLE_CLIENTS + " ADD COLUMN " + BrowserContract.Clients.DEVICE_TYPE + " TEXT DEFAULT 'mobile'");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
debug("Upgrading tabs.db: " + db.getPath() + " from " +
@ -145,6 +156,10 @@ public class TabsProvider extends PerProfileDatabaseProvider<TabsProvider.TabsDa
case 2:
createLocalClient(db);
break;
case 3:
upgradeDatabaseFrom2to3(db);
break;
}
}
}

View File

@ -9,6 +9,7 @@ import java.util.ArrayList;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.db.Tab;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserContract.Clients;
import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
import org.mozilla.gecko.sync.repositories.InactiveSessionException;
import org.mozilla.gecko.sync.repositories.NoContentProviderException;
@ -20,6 +21,7 @@ import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecor
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFinishDelegate;
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionGuidsSinceDelegate;
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionWipeDelegate;
import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
import org.mozilla.gecko.sync.repositories.domain.Record;
import org.mozilla.gecko.sync.repositories.domain.TabsRecord;
@ -38,7 +40,7 @@ public class FennecTabsRepository extends Repository {
}
/**
* Note that unlike most repositories  this will only fetch Fennec's tabs,
* Note that -- unlike most repositories -- this will only fetch Fennec's tabs,
* and only store tabs from other clients.
*
* It will never retrieve tabs from other clients, or store tabs for Fennec,
@ -53,6 +55,8 @@ public class FennecTabsRepository extends Repository {
protected final RepoUtils.QueryHelper tabsHelper;
protected final ClientsDatabaseAccessor clientsDatabase;
protected ContentProviderClient getContentProvider(final Context context, final Uri uri) throws NoContentProviderException {
ContentProviderClient client = context.getContentResolver().acquireContentProviderClient(uri);
if (client == null) {
@ -68,6 +72,7 @@ public class FennecTabsRepository extends Repository {
try {
tabsProvider.release();
} catch (Exception e) {}
clientsDatabase.close();
}
public FennecTabsRepositorySession(Repository repository, Context context) throws NoContentProviderException {
@ -85,6 +90,7 @@ public class FennecTabsRepository extends Repository {
}
tabsHelper = new RepoUtils.QueryHelper(context, BrowserContractHelpers.TABS_CONTENT_URI, LOG_TAG);
clientsDatabase = new ClientsDatabaseAccessor(context);
}
@Override
@ -240,6 +246,12 @@ public class FennecTabsRepository extends Repository {
// If it exists, update the client record; otherwise insert.
final ContentValues clientsCV = tabsRecord.getClientsContentValues();
final ClientRecord clientRecord = clientsDatabase.fetchClient(tabsRecord.guid);
if (null != clientRecord) {
// Null is an acceptable device type.
clientsCV.put(Clients.DEVICE_TYPE, clientRecord.type);
}
Logger.debug(LOG_TAG, "Updating clients provider.");
final int updated = clientsProvider.update(BrowserContractHelpers.CLIENTS_CONTENT_URI,
clientsCV,

View File

@ -9,12 +9,15 @@ import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate;
import org.mozilla.gecko.background.sync.helpers.SessionTestHelper;
import org.mozilla.gecko.background.testhelpers.MockClientsDataDelegate;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserContract.Clients;
import org.mozilla.gecko.sync.repositories.NoContentProviderException;
import org.mozilla.gecko.sync.repositories.RepositorySession;
import org.mozilla.gecko.sync.repositories.android.BrowserContractHelpers;
import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository;
import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository.FennecTabsRepositorySession;
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
import org.mozilla.gecko.sync.repositories.domain.Record;
import org.mozilla.gecko.sync.repositories.domain.TabsRecord;
@ -28,11 +31,15 @@ public class TestFennecTabsRepositorySession extends AndroidSyncTestCase {
public static final MockClientsDataDelegate clientsDataDelegate = new MockClientsDataDelegate();
public static final String TEST_CLIENT_GUID = clientsDataDelegate.getAccountGUID();
public static final String TEST_CLIENT_NAME = clientsDataDelegate.getClientName();
public static final String TEST_CLIENT_DEVICE_TYPE = "phablet";
// Override these to test against data that is not live.
public static final String TEST_TABS_CLIENT_GUID_IS_LOCAL_SELECTION = BrowserContract.Tabs.CLIENT_GUID + " IS ?";
public static final String[] TEST_TABS_CLIENT_GUID_IS_LOCAL_SELECTION_ARGS = new String[] { TEST_CLIENT_GUID };
public static final String TEST_CLIENTS_GUID_IS_LOCAL_SELECTION = BrowserContract.Clients.GUID + " IS ?";
public static final String[] TEST_CLIENTS_GUID_IS_LOCAL_SELECTION_ARGS = new String[] { TEST_CLIENT_GUID };
protected ContentProviderClient tabsClient = null;
protected ContentProviderClient getTabsClient() {
@ -215,4 +222,55 @@ public class TestFennecTabsRepositorySession extends AndroidSyncTestCase {
session.abort();
}
// Verify that storing a tabs record writes a clients record with the correct
// device type to the Fennec clients provider.
public void testStore() throws NoContentProviderException, RemoteException {
// Get a valid tabsRecord to write.
final TabsRecord tabsRecord = insertTestTabsAndExtractTabsRecord();
deleteAllTestTabs(tabsClient);
final ContentResolver cr = getApplicationContext().getContentResolver();
final ContentProviderClient clientsClient = cr.acquireContentProviderClient(BrowserContractHelpers.CLIENTS_CONTENT_URI);
try {
// We can't delete only our test clients due to a Fennec CP issue with guid vs. client_guid.
clientsClient.delete(BrowserContractHelpers.CLIENTS_CONTENT_URI, null, null);
// This clients DB is not the Fennec DB; it's Sync's own clients DB.
final ClientsDatabaseAccessor db = new ClientsDatabaseAccessor(getApplicationContext());
try {
ClientRecord clientRecord = new ClientRecord(TEST_CLIENT_GUID);
clientRecord.name = TEST_CLIENT_NAME;
clientRecord.type = TEST_CLIENT_DEVICE_TYPE;
db.store(clientRecord);
} finally {
db.close();
}
final FennecTabsRepositorySession session = createAndBeginSession();
performWait(AndroidBrowserRepositoryTestCase.storeRunnable(session, tabsRecord));
session.abort();
// This store should write Sync's idea of the client's device_type to Fennec's clients CP.
final Cursor cursor = clientsClient.query(BrowserContractHelpers.CLIENTS_CONTENT_URI, null,
TEST_CLIENTS_GUID_IS_LOCAL_SELECTION, TEST_CLIENTS_GUID_IS_LOCAL_SELECTION_ARGS, null);
assertNotNull(cursor);
try {
assertTrue(cursor.moveToFirst());
assertEquals(TEST_CLIENT_GUID, cursor.getString(cursor.getColumnIndex(Clients.GUID)));
assertEquals(TEST_CLIENT_NAME, cursor.getString(cursor.getColumnIndex(Clients.NAME)));
assertEquals(TEST_CLIENT_DEVICE_TYPE, cursor.getString(cursor.getColumnIndex(Clients.DEVICE_TYPE)));
assertTrue(cursor.isLast());
} finally {
cursor.close();
}
} finally {
// We can't delete only our test client due to a Fennec CP issue with guid vs. client_guid.
clientsClient.delete(BrowserContractHelpers.CLIENTS_CONTENT_URI, null, null);
clientsClient.release();
}
}
}