--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/BrowserContractHelpers.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/BrowserContractHelpers.java
@@ -3,16 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.gecko.sync.repositories.android;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.sync.setup.Constants;
import android.net.Uri;
public class BrowserContractHelpers extends BrowserContract {
protected static Uri withSyncAndDeletedAndProfile(Uri u) {
@@ -29,39 +30,24 @@ public class BrowserContractHelpers exte
.build();
}
public static final Uri BOOKMARKS_CONTENT_URI = withSyncAndDeletedAndProfile(Bookmarks.CONTENT_URI);
public static final Uri BOOKMARKS_PARENTS_CONTENT_URI = withSyncAndDeletedAndProfile(Bookmarks.PARENTS_CONTENT_URI);
public static final Uri BOOKMARKS_POSITIONS_CONTENT_URI = withSyncAndDeletedAndProfile(Bookmarks.POSITIONS_CONTENT_URI);
public static final Uri HISTORY_CONTENT_URI = withSyncAndDeletedAndProfile(History.CONTENT_URI);
public static final Uri SCHEMA_CONTENT_URI = withSyncAndDeletedAndProfile(Schema.CONTENT_URI);
- public static final Uri PASSWORDS_CONTENT_URI = withSyncAndDeletedAndProfile(Passwords.CONTENT_URI);
- public static final Uri DELETED_PASSWORDS_CONTENT_URI = withSyncAndDeletedAndProfile(DeletedPasswords.CONTENT_URI);
+ public static final Uri PASSWORDS_CONTENT_URI;
+ public static final Uri DELETED_PASSWORDS_CONTENT_URI;
public static final Uri FORM_HISTORY_CONTENT_URI = withSyncAndProfile(FormHistory.CONTENT_URI);
public static final Uri DELETED_FORM_HISTORY_CONTENT_URI = withSyncAndProfile(DeletedFormHistory.CONTENT_URI);
public static final Uri TABS_CONTENT_URI = withSyncAndProfile(Tabs.CONTENT_URI);
public static final Uri CLIENTS_CONTENT_URI = withSyncAndProfile(Clients.CONTENT_URI);
- public static final String[] PasswordColumns = new String[] {
- Passwords.ID,
- Passwords.HOSTNAME,
- Passwords.HTTP_REALM,
- Passwords.FORM_SUBMIT_URL,
- Passwords.USERNAME_FIELD,
- Passwords.PASSWORD_FIELD,
- Passwords.ENCRYPTED_USERNAME,
- Passwords.ENCRYPTED_PASSWORD,
- Passwords.ENC_TYPE,
- Passwords.TIME_CREATED,
- Passwords.TIME_LAST_USED,
- Passwords.TIME_PASSWORD_CHANGED,
- Passwords.TIMES_USED,
- Passwords.GUID
- };
+ public static final String[] PasswordColumns;
public static final String[] HistoryColumns = new String[] {
CommonColumns._ID,
SyncColumns.GUID,
SyncColumns.DATE_CREATED,
SyncColumns.DATE_MODIFIED,
SyncColumns.IS_DELETED,
History.TITLE,
@@ -91,21 +77,73 @@ public class BrowserContractHelpers exte
FormHistory.GUID,
FormHistory.FIELD_NAME,
FormHistory.VALUE,
FormHistory.TIMES_USED,
FormHistory.FIRST_USED,
FormHistory.LAST_USED
};
- public static final String[] DeletedColumns = new String[] {
- BrowserContract.DeletedColumns.ID,
- BrowserContract.DeletedColumns.GUID,
- BrowserContract.DeletedColumns.TIME_DELETED
- };
+ public static final String[] DeletedColumns;
+
+ static {
+ if (AppConstants.MOZ_ANDROID_LOGINS_STORAGE_USE) {
+ PASSWORDS_CONTENT_URI = withSyncAndDeletedAndProfile(Logins.CONTENT_URI);
+ DELETED_PASSWORDS_CONTENT_URI = withSyncAndDeletedAndProfile(DeletedLogins.CONTENT_URI);
+
+ PasswordColumns = new String[] {
+ Logins._ID,
+ Logins.HOSTNAME,
+ Logins.HTTP_REALM,
+ Logins.FORM_SUBMIT_URL,
+ Logins.USERNAME_FIELD,
+ Logins.PASSWORD_FIELD,
+ Logins.ENCRYPTED_USERNAME,
+ Logins.ENCRYPTED_PASSWORD,
+ Logins.ENC_TYPE,
+ Logins.TIME_CREATED,
+ Logins.TIME_LAST_USED,
+ Logins.TIME_PASSWORD_CHANGED,
+ Logins.TIMES_USED,
+ Logins.GUID
+ };
+
+ DeletedColumns= new String[] {
+ BrowserContract.DeletedLogins._ID,
+ BrowserContract.DeletedLogins.GUID,
+ BrowserContract.DeletedLogins.TIME_DELETED
+ };
+ } else {
+ PASSWORDS_CONTENT_URI = withSyncAndDeletedAndProfile(Passwords.CONTENT_URI);
+ DELETED_PASSWORDS_CONTENT_URI = withSyncAndDeletedAndProfile(DeletedPasswords.CONTENT_URI);
+
+ PasswordColumns = new String[] {
+ Passwords.ID,
+ Passwords.HOSTNAME,
+ Passwords.HTTP_REALM,
+ Passwords.FORM_SUBMIT_URL,
+ Passwords.USERNAME_FIELD,
+ Passwords.PASSWORD_FIELD,
+ Passwords.ENCRYPTED_USERNAME,
+ Passwords.ENCRYPTED_PASSWORD,
+ Passwords.ENC_TYPE,
+ Passwords.TIME_CREATED,
+ Passwords.TIME_LAST_USED,
+ Passwords.TIME_PASSWORD_CHANGED,
+ Passwords.TIMES_USED,
+ Passwords.GUID
+ };
+
+ DeletedColumns= new String[] {
+ BrowserContract.DeletedColumns.ID,
+ BrowserContract.DeletedColumns.GUID,
+ BrowserContract.DeletedColumns.TIME_DELETED
+ };
+ }
+ }
// Mapping from Sync types to Fennec types.
public static final String[] BOOKMARK_TYPE_CODE_TO_STRING = {
// Observe omissions: "microsummary", "item".
"folder", "bookmark", "separator", "livemark", "query"
};
private static final int MAX_BOOKMARK_TYPE_CODE = BOOKMARK_TYPE_CODE_TO_STRING.length - 1;
public static final Map<String, Integer> BOOKMARK_TYPE_STRING_TO_CODE;
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/PasswordsRepositorySession.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/sync/repositories/android/PasswordsRepositorySession.java
@@ -2,20 +2,22 @@
* 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.sync.repositories.android;
import java.util.ArrayList;
import java.util.List;
+import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserContract.DeletedColumns;
-import org.mozilla.gecko.db.BrowserContract.DeletedPasswords;
+import org.mozilla.gecko.db.BrowserContract.DeletedLogins;
+import org.mozilla.gecko.db.BrowserContract.Logins;
import org.mozilla.gecko.db.BrowserContract.Passwords;
import org.mozilla.gecko.sync.repositories.InactiveSessionException;
import org.mozilla.gecko.sync.repositories.NoStoreDelegateException;
import org.mozilla.gecko.sync.repositories.NullCursorException;
import org.mozilla.gecko.sync.repositories.RecordFilter;
import org.mozilla.gecko.sync.repositories.Repository;
import org.mozilla.gecko.sync.repositories.StoreTrackingRepositorySession;
import org.mozilla.gecko.sync.repositories.android.RepoUtils.QueryHelper;
@@ -33,16 +35,77 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.RemoteException;
public class PasswordsRepositorySession extends
StoreTrackingRepositorySession {
+ private static final String PASSWORDS_HOSTNAME;
+ private static final String PASSWORDS_HTTP_REALM;
+ private static final String PASSWORDS_FORM_SUBMIT_URL;
+ private static final String PASSWORDS_USERNAME_FIELD;
+ private static final String PASSWORDS_PASSWORD_FIELD;
+ private static final String PASSWORDS_ENC_TYPE;
+ private static final String PASSWORDS_ENCRYPTED_USERNAME;
+ private static final String PASSWORDS_ENCRYPTED_PASSWORD;
+ private static final String PASSWORDS_TIME_CREATED;
+ private static final String PASSWORDS_TIME_LAST_USED;
+ private static final String PASSWORDS_TIMES_USED;
+ private static final String PASSWORDS_GUID;
+ private static final String PASSWORDS_TIME_PASSWORD_CHANGED;
+ private static final String PASSWORDS_ID;
+ private static final String DELETED_PASSWORDS_GUID;
+ private static final String DELETED_PASSWORDS_TIME_DELETED;
+ private static final String DELETED_PASSWORDS_ID;
+ private static final Uri AUTHORITY_URI;
+
+ static {
+ if (AppConstants.MOZ_ANDROID_LOGINS_STORAGE_USE) {
+ PASSWORDS_HOSTNAME = Logins.HOSTNAME;
+ PASSWORDS_HTTP_REALM = Logins.HTTP_REALM;
+ PASSWORDS_FORM_SUBMIT_URL = Logins.FORM_SUBMIT_URL;
+ PASSWORDS_USERNAME_FIELD = Logins.USERNAME_FIELD;
+ PASSWORDS_PASSWORD_FIELD = Logins.PASSWORD_FIELD;
+ PASSWORDS_ENC_TYPE = Logins.ENC_TYPE;
+ PASSWORDS_ENCRYPTED_USERNAME = Logins.ENCRYPTED_USERNAME;
+ PASSWORDS_ENCRYPTED_PASSWORD = Logins.ENCRYPTED_PASSWORD;
+ PASSWORDS_TIME_CREATED = Logins.TIME_CREATED;
+ PASSWORDS_TIME_LAST_USED = Logins.TIME_LAST_USED;
+ PASSWORDS_TIMES_USED = Logins.TIMES_USED;
+ PASSWORDS_GUID = Logins.GUID;
+ PASSWORDS_TIME_PASSWORD_CHANGED = Logins.TIME_PASSWORD_CHANGED;
+ PASSWORDS_ID = Logins._ID;
+ DELETED_PASSWORDS_GUID = DeletedLogins.GUID;
+ DELETED_PASSWORDS_TIME_DELETED = DeletedLogins.TIME_DELETED;
+ DELETED_PASSWORDS_ID = DeletedLogins._ID;
+ AUTHORITY_URI = BrowserContract.LOGINS_AUTHORITY_URI;
+ } else {
+ PASSWORDS_HOSTNAME = Passwords.HOSTNAME;
+ PASSWORDS_HTTP_REALM = Passwords.HTTP_REALM;
+ PASSWORDS_FORM_SUBMIT_URL = Passwords.FORM_SUBMIT_URL;
+ PASSWORDS_USERNAME_FIELD = Passwords.USERNAME_FIELD;
+ PASSWORDS_PASSWORD_FIELD = Passwords.PASSWORD_FIELD;
+ PASSWORDS_ENC_TYPE = Passwords.ENC_TYPE;
+ PASSWORDS_ENCRYPTED_USERNAME = Passwords.ENCRYPTED_USERNAME;
+ PASSWORDS_ENCRYPTED_PASSWORD = Passwords.ENCRYPTED_PASSWORD;
+ PASSWORDS_TIME_CREATED = Passwords.TIME_CREATED;
+ PASSWORDS_TIME_LAST_USED = Passwords.TIME_LAST_USED;
+ PASSWORDS_TIMES_USED = Passwords.TIMES_USED;
+ PASSWORDS_GUID = Passwords.GUID;
+ PASSWORDS_TIME_PASSWORD_CHANGED = Passwords.TIME_PASSWORD_CHANGED;
+ PASSWORDS_ID = Passwords.ID;
+ DELETED_PASSWORDS_GUID = DeletedColumns.GUID;
+ DELETED_PASSWORDS_TIME_DELETED = DeletedColumns.TIME_DELETED;
+ DELETED_PASSWORDS_ID = DeletedColumns.ID;
+ AUTHORITY_URI = BrowserContract.PASSWORDS_AUTHORITY_URI;
+ }
+ }
+
public static class PasswordsRepository extends Repository {
@Override
public void createSession(RepositorySessionCreationDelegate delegate,
Context context) {
PasswordsRepositorySession session = new PasswordsRepositorySession(PasswordsRepository.this, context);
final RepositorySessionCreationDelegate deferredCreationDelegate = delegate.deferredCreationDelegate();
deferredCreationDelegate.onSessionCreated(session);
}
@@ -57,24 +120,24 @@ public class PasswordsRepositorySession
private final Context context;
public PasswordsRepositorySession(Repository repository, Context context) {
super(repository);
this.context = context;
this.passwordsHelper = new QueryHelper(context, BrowserContractHelpers.PASSWORDS_CONTENT_URI, LOG_TAG);
this.deletedPasswordsHelper = new QueryHelper(context, BrowserContractHelpers.DELETED_PASSWORDS_CONTENT_URI, LOG_TAG);
- this.passwordsProvider = context.getContentResolver().acquireContentProviderClient(BrowserContract.PASSWORDS_AUTHORITY_URI);
+ this.passwordsProvider = context.getContentResolver().acquireContentProviderClient(AUTHORITY_URI);
}
- private static final String[] GUID_COLS = new String[] { Passwords.GUID };
- private static final String[] DELETED_GUID_COLS = new String[] { DeletedColumns.GUID };
+ private static final String[] GUID_COLS = new String[] { PASSWORDS_GUID };
+ private static final String[] DELETED_GUID_COLS = new String[] { DELETED_PASSWORDS_GUID };
- private static final String WHERE_GUID_IS = Passwords.GUID + " = ?";
- private static final String WHERE_DELETED_GUID_IS = DeletedPasswords.GUID + " = ?";
+ private static final String WHERE_GUID_IS = PASSWORDS_GUID + " = ?";
+ private static final String WHERE_DELETED_GUID_IS = DELETED_PASSWORDS_GUID + " = ?";
@Override
public void guidsSince(final long timestamp, final RepositorySessionGuidsSinceDelegate delegate) {
final Runnable guidsSinceRunnable = new Runnable() {
@Override
public void run() {
if (!isActive()) {
@@ -85,31 +148,31 @@ public class PasswordsRepositorySession
// Checks succeeded, now get GUIDs.
final List<String> guids = new ArrayList<String>();
try {
Logger.debug(LOG_TAG, "Fetching guidsSince from data table.");
final Cursor data = passwordsHelper.safeQuery(passwordsProvider, ".getGUIDsSince", GUID_COLS, dateModifiedWhere(timestamp), null, null);
try {
if (data.moveToFirst()) {
while (!data.isAfterLast()) {
- guids.add(RepoUtils.getStringFromCursor(data, Passwords.GUID));
+ guids.add(RepoUtils.getStringFromCursor(data, PASSWORDS_GUID));
data.moveToNext();
}
}
} finally {
data.close();
}
// Fetch guids from deleted table.
Logger.debug(LOG_TAG, "Fetching guidsSince from deleted table.");
final Cursor deleted = deletedPasswordsHelper.safeQuery(passwordsProvider, ".getGUIDsSince", DELETED_GUID_COLS, dateModifiedWhereDeleted(timestamp), null, null);
try {
if (deleted.moveToFirst()) {
while (!deleted.isAfterLast()) {
- guids.add(RepoUtils.getStringFromCursor(deleted, DeletedColumns.GUID));
+ guids.add(RepoUtils.getStringFromCursor(deleted, DELETED_PASSWORDS_GUID));
deleted.moveToNext();
}
}
} finally {
deleted.close();
}
} catch (Exception e) {
Logger.error(LOG_TAG, "Exception in fetch.");
@@ -509,27 +572,27 @@ public class PasswordsRepositorySession
/**
* Constructs the DB query string for entry age for deleted records.
*
* @param timestamp
* @return String DB query string for dates to fetch.
*/
private static String dateModifiedWhereDeleted(long timestamp) {
- return DeletedColumns.TIME_DELETED + " >= " + Long.toString(timestamp);
+ return DELETED_PASSWORDS_TIME_DELETED + " >= " + Long.toString(timestamp);
}
/**
* Constructs the DB query string for entry age for (undeleted) records.
*
* @param timestamp
* @return String DB query string for dates to fetch.
*/
private static String dateModifiedWhere(long timestamp) {
- return Passwords.TIME_PASSWORD_CHANGED + " >= " + Long.toString(timestamp);
+ return PASSWORDS_TIME_PASSWORD_CHANGED + " >= " + Long.toString(timestamp);
}
/**
* Fetch from the cursor with the given parameters, invoking
* delegate callbacks and closing the cursor.
* Returns true on success, false if failure was signaled.
*
@@ -592,38 +655,71 @@ public class PasswordsRepositorySession
}
} finally {
deleted.close();
}
return null;
}
- private static final String WHERE_RECORD_DATA =
- Passwords.HOSTNAME + " = ? AND " +
- Passwords.HTTP_REALM + " = ? AND " +
- Passwords.FORM_SUBMIT_URL + " = ? AND " +
- Passwords.USERNAME_FIELD + " = ? AND " +
- Passwords.PASSWORD_FIELD + " = ?";
+ private static final String WHERE_RECORD_DATA;
+ static {
+ if (AppConstants.MOZ_ANDROID_LOGINS_STORAGE_USE) {
+ WHERE_RECORD_DATA = PASSWORDS_HOSTNAME + " = ? AND " +
+ PASSWORDS_USERNAME_FIELD + " = ? AND " +
+ PASSWORDS_PASSWORD_FIELD + " = ?";
+ } else {
+ WHERE_RECORD_DATA = PASSWORDS_HOSTNAME + " = ? AND " +
+ PASSWORDS_HTTP_REALM + " = ? AND " +
+ PASSWORDS_FORM_SUBMIT_URL + " = ? AND " +
+ PASSWORDS_USERNAME_FIELD + " = ? AND " +
+ PASSWORDS_PASSWORD_FIELD + " = ?";
+ }
+ }
private PasswordRecord findExistingRecord(PasswordRecord record) throws NullCursorException, RemoteException {
PasswordRecord foundRecord = null;
Cursor cursor = null;
// Only check the data table.
// We can't encrypt username directly for query, so run a more general query and then filter.
- final String[] whereArgs = new String[] {
- record.hostname,
- record.httpRealm,
- record.formSubmitURL,
- record.usernameField,
- record.passwordField
- };
+ final String[] whereArgs;
+ final String whereRecordData;
+
+ // Android CP does not support null as bind parameter, so split the query.
+ if (AppConstants.MOZ_ANDROID_LOGINS_STORAGE_USE) {
+ String condition = WHERE_RECORD_DATA;
+ List<String> whereArgslist = new ArrayList<>();
+ whereArgslist.add(record.hostname);
+ whereArgslist.add(record.usernameField);
+ whereArgslist.add(record.passwordField);
+
+ if (record.httpRealm != null) {
+ whereArgslist.add(record.httpRealm);
+ condition += " AND " + PASSWORDS_HTTP_REALM + " = ?";
+ }
+
+ if (record.formSubmitURL != null) {
+ whereArgslist.add(record.formSubmitURL);
+ condition += " AND " + PASSWORDS_FORM_SUBMIT_URL + " = ?";
+ }
+ whereArgs = whereArgslist.toArray(new String[0]);
+ whereRecordData = condition;
+ } else {
+ whereRecordData = WHERE_RECORD_DATA;
+ whereArgs= new String[] {
+ record.hostname,
+ record.httpRealm,
+ record.formSubmitURL,
+ record.usernameField,
+ record.passwordField
+ };
+ }
try {
- cursor = passwordsHelper.safeQuery(passwordsProvider, ".findRecord", getAllColumns(), WHERE_RECORD_DATA, whereArgs, null);
+ cursor = passwordsHelper.safeQuery(passwordsProvider, ".findRecord", getAllColumns(), whereRecordData, whereArgs, null);
while (cursor.moveToNext()) {
foundRecord = passwordRecordFromCursor(cursor);
// We don't directly query for username because the
// username/password values are encrypted in the db.
// We don't have the keys for encrypting our query,
// so we run a more general query and then filter
// the returned records for a matching username.
@@ -661,65 +757,70 @@ public class PasswordsRepositorySession
* true if creating a deleted Record, false if otherwise.
* @return
* PasswordRecord populated from Cursor.
*/
private static PasswordRecord passwordRecordFromCursor(Cursor cur) {
if (cur.isAfterLast()) {
return null;
}
- String guid = RepoUtils.getStringFromCursor(cur, BrowserContract.Passwords.GUID);
- long lastModified = RepoUtils.getLongFromCursor(cur, BrowserContract.Passwords.TIME_PASSWORD_CHANGED);
+ String guid = RepoUtils.getStringFromCursor(cur, PASSWORDS_GUID);
+ long lastModified = RepoUtils.getLongFromCursor(cur, PASSWORDS_TIME_PASSWORD_CHANGED);
PasswordRecord rec = new PasswordRecord(guid, COLLECTION, lastModified, false);
- rec.id = RepoUtils.getStringFromCursor(cur, BrowserContract.Passwords.ID);
- rec.hostname = RepoUtils.getStringFromCursor(cur, BrowserContract.Passwords.HOSTNAME);
- rec.httpRealm = RepoUtils.getStringFromCursor(cur, BrowserContract.Passwords.HTTP_REALM);
- rec.formSubmitURL = RepoUtils.getStringFromCursor(cur, BrowserContract.Passwords.FORM_SUBMIT_URL);
- rec.usernameField = RepoUtils.getStringFromCursor(cur, BrowserContract.Passwords.USERNAME_FIELD);
- rec.passwordField = RepoUtils.getStringFromCursor(cur, BrowserContract.Passwords.PASSWORD_FIELD);
- rec.encType = RepoUtils.getStringFromCursor(cur, BrowserContract.Passwords.ENC_TYPE);
+ rec.id = RepoUtils.getStringFromCursor(cur, PASSWORDS_ID);
+ rec.hostname = RepoUtils.getStringFromCursor(cur, PASSWORDS_HOSTNAME);
+ rec.httpRealm = RepoUtils.getStringFromCursor(cur, PASSWORDS_HTTP_REALM);
+ rec.formSubmitURL = RepoUtils.getStringFromCursor(cur, PASSWORDS_FORM_SUBMIT_URL);
+ rec.usernameField = RepoUtils.getStringFromCursor(cur, PASSWORDS_USERNAME_FIELD);
+ rec.passwordField = RepoUtils.getStringFromCursor(cur, PASSWORDS_PASSWORD_FIELD);
+ rec.encType = RepoUtils.getStringFromCursor(cur, PASSWORDS_ENC_TYPE);
// TODO decryption of username/password here (Bug 711636)
- rec.encryptedUsername = RepoUtils.getStringFromCursor(cur, BrowserContract.Passwords.ENCRYPTED_USERNAME);
- rec.encryptedPassword = RepoUtils.getStringFromCursor(cur, BrowserContract.Passwords.ENCRYPTED_PASSWORD);
+ rec.encryptedUsername = RepoUtils.getStringFromCursor(cur, PASSWORDS_ENCRYPTED_USERNAME);
+ rec.encryptedPassword = RepoUtils.getStringFromCursor(cur, PASSWORDS_ENCRYPTED_PASSWORD);
- rec.timeCreated = RepoUtils.getLongFromCursor(cur, BrowserContract.Passwords.TIME_CREATED);
- rec.timeLastUsed = RepoUtils.getLongFromCursor(cur, BrowserContract.Passwords.TIME_LAST_USED);
- rec.timePasswordChanged = RepoUtils.getLongFromCursor(cur, BrowserContract.Passwords.TIME_PASSWORD_CHANGED);
- rec.timesUsed = RepoUtils.getLongFromCursor(cur, BrowserContract.Passwords.TIMES_USED);
+ rec.timeCreated = RepoUtils.getLongFromCursor(cur, PASSWORDS_TIME_CREATED);
+ rec.timeLastUsed = RepoUtils.getLongFromCursor(cur, PASSWORDS_TIME_LAST_USED);
+ rec.timePasswordChanged = RepoUtils.getLongFromCursor(cur, PASSWORDS_TIME_PASSWORD_CHANGED);
+ rec.timesUsed = RepoUtils.getLongFromCursor(cur, PASSWORDS_TIMES_USED);
return rec;
}
private static PasswordRecord deletedPasswordRecordFromCursor(Cursor cur) {
if (cur.isAfterLast()) {
return null;
}
- String guid = RepoUtils.getStringFromCursor(cur, DeletedColumns.GUID);
- long lastModified = RepoUtils.getLongFromCursor(cur, DeletedColumns.TIME_DELETED);
+ String guid = RepoUtils.getStringFromCursor(cur, DELETED_PASSWORDS_GUID);
+ long lastModified = RepoUtils.getLongFromCursor(cur, DELETED_PASSWORDS_TIME_DELETED);
PasswordRecord rec = new PasswordRecord(guid, COLLECTION, lastModified, true);
- rec.androidID = RepoUtils.getLongFromCursor(cur, DeletedColumns.ID);
+ rec.androidID = RepoUtils.getLongFromCursor(cur, DELETED_PASSWORDS_ID);
return rec;
}
private static ContentValues getContentValues(Record record) {
PasswordRecord rec = (PasswordRecord) record;
ContentValues cv = new ContentValues();
- cv.put(BrowserContract.Passwords.GUID, rec.guid);
- cv.put(BrowserContract.Passwords.HOSTNAME, rec.hostname);
- cv.put(BrowserContract.Passwords.HTTP_REALM, rec.httpRealm);
- cv.put(BrowserContract.Passwords.FORM_SUBMIT_URL, rec.formSubmitURL);
- cv.put(BrowserContract.Passwords.USERNAME_FIELD, rec.usernameField);
- cv.put(BrowserContract.Passwords.PASSWORD_FIELD, rec.passwordField);
+ cv.put(PASSWORDS_GUID, rec.guid);
+ cv.put(PASSWORDS_HOSTNAME, rec.hostname);
+ cv.put(PASSWORDS_HTTP_REALM, rec.httpRealm);
+ cv.put(PASSWORDS_FORM_SUBMIT_URL, rec.formSubmitURL);
+ cv.put(PASSWORDS_USERNAME_FIELD, rec.usernameField);
+ cv.put(PASSWORDS_PASSWORD_FIELD, rec.passwordField);
- // TODO Do encryption of username/password here. Bug 711636
- cv.put(BrowserContract.Passwords.ENC_TYPE, rec.encType);
- cv.put(BrowserContract.Passwords.ENCRYPTED_USERNAME, rec.encryptedUsername);
- cv.put(BrowserContract.Passwords.ENCRYPTED_PASSWORD, rec.encryptedPassword);
+ // Android Logins table introduces not null constraint for encType.
+ // Add encType to contentValues only iff it is not null.
+ if (!AppConstants.MOZ_ANDROID_LOGINS_STORAGE_USE || rec.encType != null) {
+ // TODO Do encryption of username/password here. Bug 711636
+ cv.put(PASSWORDS_ENC_TYPE, rec.encType);
+ }
- cv.put(BrowserContract.Passwords.TIME_CREATED, rec.timeCreated);
- cv.put(BrowserContract.Passwords.TIME_LAST_USED, rec.timeLastUsed);
- cv.put(BrowserContract.Passwords.TIME_PASSWORD_CHANGED, rec.timePasswordChanged);
- cv.put(BrowserContract.Passwords.TIMES_USED, rec.timesUsed);
+ cv.put(PASSWORDS_ENCRYPTED_USERNAME, rec.encryptedUsername);
+ cv.put(PASSWORDS_ENCRYPTED_PASSWORD, rec.encryptedPassword);
+
+ cv.put(PASSWORDS_TIME_CREATED, rec.timeCreated);
+ cv.put(PASSWORDS_TIME_LAST_USED, rec.timeLastUsed);
+ cv.put(PASSWORDS_TIME_PASSWORD_CHANGED, rec.timePasswordChanged);
+ cv.put(PASSWORDS_TIMES_USED, rec.timesUsed);
return cv;
}
}
--- a/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestPasswordsRepository.java
+++ b/mobile/android/tests/background/junit3/src/org/mozilla/gecko/background/db/TestPasswordsRepository.java
@@ -1,16 +1,17 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
package org.mozilla.gecko.background.db;
import java.util.HashSet;
import java.util.Set;
+import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
import org.mozilla.gecko.background.sync.helpers.ExpectFetchDelegate;
import org.mozilla.gecko.background.sync.helpers.ExpectFetchSinceDelegate;
import org.mozilla.gecko.background.sync.helpers.ExpectGuidsSinceDelegate;
import org.mozilla.gecko.background.sync.helpers.ExpectNoStoreDelegate;
import org.mozilla.gecko.background.sync.helpers.ExpectStoredDelegate;
import org.mozilla.gecko.background.sync.helpers.PasswordHelpers;
import org.mozilla.gecko.background.sync.helpers.SessionTestHelper;
@@ -28,22 +29,45 @@ import org.mozilla.gecko.sync.repositori
import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionStoreDelegate;
import org.mozilla.gecko.sync.repositories.domain.PasswordRecord;
import org.mozilla.gecko.sync.repositories.domain.Record;
import android.content.ContentProviderClient;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
+import android.net.Uri;
import android.os.RemoteException;
public class TestPasswordsRepository extends AndroidSyncTestCase {
+ private static final String DELETED_PASSWORD_GUID;
+ private static final String DELETED_PASSWORD_TIME_DELETED;
+ private static final String DELETED_PASSWORD_ID;
+ private static final Uri AUTHORITY_URI;
+ private static final String PASSWORDS_GUID;
+
private final String NEW_PASSWORD1 = "password";
private final String NEW_PASSWORD2 = "drowssap";
+ static {
+ if (AppConstants.MOZ_ANDROID_LOGINS_STORAGE_USE) {
+ PASSWORDS_GUID = BrowserContract.Logins.GUID;
+ DELETED_PASSWORD_GUID = BrowserContract.DeletedLogins.GUID;
+ DELETED_PASSWORD_TIME_DELETED = BrowserContract.DeletedLogins.TIME_DELETED;
+ DELETED_PASSWORD_ID = BrowserContract.DeletedLogins._ID;
+ AUTHORITY_URI = BrowserContract.LOGINS_AUTHORITY_URI;
+ } else {
+ PASSWORDS_GUID = BrowserContract.Passwords.GUID;
+ DELETED_PASSWORD_GUID = BrowserContract.DeletedColumns.GUID;
+ DELETED_PASSWORD_TIME_DELETED = BrowserContract.DeletedColumns.TIME_DELETED;
+ DELETED_PASSWORD_ID = BrowserContract.DeletedColumns.ID;
+ AUTHORITY_URI = BrowserContract.PASSWORDS_AUTHORITY_URI;
+ }
+ }
+
@Override
public void setUp() {
wipe();
assertTrue(WaitHelper.getTestWaiter().isIdle());
}
public void testFetchAll() {
RepositorySession session = createAndBeginSession();
@@ -94,20 +118,20 @@ public class TestPasswordsRepository ext
long timeModified1 = updatePassword(NEW_PASSWORD1, record1);
performWait(storeRunnable(session, record1));
PasswordRecord record2 = PasswordHelpers.createPassword2();
long timeModified2 = updatePassword(NEW_PASSWORD2, record2);
performWait(storeRunnable(session, record2));
String[] expectedOne = new String[] { record2.guid };
- performWait(fetchSinceRunnable(session, timeModified2 - 10, expectedOne));
+ performWait(fetchSinceRunnable(session, timeModified2 - 1, expectedOne));
String[] expectedBoth = new String[] { record1.guid, record2.guid };
- performWait(fetchSinceRunnable(session, timeModified1 - 10, expectedBoth));
+ performWait(fetchSinceRunnable(session, timeModified1 - 1, expectedBoth));
dispose(session);
}
public void testFetchSinceReturnNoRecords() {
RepositorySession session = createAndBeginSession();
performWait(storeRunnable(session, PasswordHelpers.createPassword2()));
@@ -337,23 +361,23 @@ public class TestPasswordsRepository ext
public void testRawFetch() throws RemoteException {
RepositorySession session = createAndBeginSession();
Record[] expected = new Record[] { PasswordHelpers.createPassword1(),
PasswordHelpers.createPassword2() };
performWait(storeRunnable(session, expected[0]));
performWait(storeRunnable(session, expected[1]));
- ContentProviderClient client = getApplicationContext().getContentResolver().acquireContentProviderClient(BrowserContract.PASSWORDS_AUTHORITY_URI);
+ ContentProviderClient client = getApplicationContext().getContentResolver().acquireContentProviderClient(AUTHORITY_URI);
Cursor cursor = client.query(BrowserContractHelpers.PASSWORDS_CONTENT_URI, null, null, null, null);
assertEquals(2, cursor.getCount());
cursor.moveToFirst();
Set<String> guids = new HashSet<String>();
while (!cursor.isAfterLast()) {
- String guid = RepoUtils.getStringFromCursor(cursor, BrowserContract.Passwords.GUID);
+ String guid = RepoUtils.getStringFromCursor(cursor, PASSWORDS_GUID);
guids.add(guid);
cursor.moveToNext();
}
cursor.close();
assertEquals(2, guids.size());
assertTrue(guids.contains(expected[0].guid));
assertTrue(guids.contains(expected[1].guid));
dispose(session);
@@ -392,19 +416,19 @@ public class TestPasswordsRepository ext
context.getContentResolver().delete(BrowserContractHelpers.DELETED_PASSWORDS_CONTENT_URI, null, null);
}
private void storeLocalDeletedRecord(Record record, long time) {
// Wipe data-store
wipe();
// Store record in deleted table.
ContentValues contentValues = new ContentValues();
- contentValues.put(BrowserContract.DeletedColumns.GUID, record.guid);
- contentValues.put(BrowserContract.DeletedColumns.TIME_DELETED, time);
- contentValues.put(BrowserContract.DeletedColumns.ID, record.androidID);
+ contentValues.put(DELETED_PASSWORD_GUID, record.guid);
+ contentValues.put(DELETED_PASSWORD_TIME_DELETED, time);
+ contentValues.put(DELETED_PASSWORD_ID, record.androidID);
getApplicationContext().getContentResolver().insert(BrowserContractHelpers.DELETED_PASSWORDS_CONTENT_URI, contentValues);
}
private static void dispose(RepositorySession session) {
if (session != null) {
session.abort();
}
}
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordEncrypt.java
+++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordEncrypt.java
@@ -2,27 +2,34 @@
* 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.tests;
import java.io.File;
import org.json.JSONObject;
+import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.NSSBridge;
import org.mozilla.gecko.db.BrowserContract;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.util.Log;
public class testPasswordEncrypt extends BaseTest {
public void testPasswordEncrypt() {
+ if (AppConstants.MOZ_ANDROID_LOGINS_STORAGE_USE) {
+ Log.d(LOGTAG, "New LoginsProvider in use. Skipping old PasswordsProvider tests");
+ return;
+ }
+
Context context = (Context)getActivity();
ContentResolver cr = context.getContentResolver();
mAsserter.isnot(cr, null, "Found a content resolver");
ContentValues cvs = new ContentValues();
blockForGeckoReady();
File db = new File(mProfile, "signons.sqlite");
--- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordProvider.java
+++ b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testPasswordProvider.java
@@ -1,39 +1,46 @@
/* 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.tests;
import java.io.File;
+import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.BrowserContract.GeckoDisabledHosts;
import org.mozilla.gecko.db.BrowserContract.Passwords;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.util.Log;
/**
* A basic password contentprovider test.
* - inserts a password when the database is not yet set up
* - inserts a password
* - updates a password
* - deletes a password
* - inserts a disabled host
* - queries for disabled host
*/
public class testPasswordProvider extends BaseTest {
private static final String DB_NAME = "signons.sqlite";
public void testPasswordProvider() {
+ if (AppConstants.MOZ_ANDROID_LOGINS_STORAGE_USE) {
+ Log.d(LOGTAG, "New LoginsProvider in use. Skipping old PasswordsProvider tests");
+ return;
+ }
+
Context context = (Context)getActivity();
ContentResolver cr = context.getContentResolver();
ContentValues[] cvs = new ContentValues[1];
cvs[0] = new ContentValues();
blockForGeckoReady();
cvs[0].put("hostname", "http://www.example.com");