mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 710330 - Refactor batch update helper functions into LocalDB. r=lucasr
This commit is contained in:
parent
316dca6e38
commit
4df3be97fa
@ -13,6 +13,7 @@ import org.mozilla.gecko.db.BrowserContract.Images;
|
||||
import org.mozilla.gecko.db.BrowserContract.Passwords;
|
||||
import org.mozilla.gecko.db.BrowserContract.URLColumns;
|
||||
import org.mozilla.gecko.db.BrowserContract.SyncColumns;
|
||||
import org.mozilla.gecko.db.LocalBrowserDB;
|
||||
import org.mozilla.gecko.sqlite.SQLiteBridge;
|
||||
import org.mozilla.gecko.sqlite.SQLiteBridgeException;
|
||||
import org.mozilla.gecko.sync.setup.SyncAccounts;
|
||||
@ -72,6 +73,7 @@ public class ProfileMigrator {
|
||||
private Runnable mLongOperationStartCallback;
|
||||
private boolean mLongOperationStartRun;
|
||||
private Runnable mLongOperationStopCallback;
|
||||
private LocalBrowserDB mDB;
|
||||
|
||||
// Default number of history entries to migrate in one run.
|
||||
private static final int DEFAULT_HISTORY_MIGRATE_COUNT = 2000;
|
||||
@ -709,32 +711,15 @@ public class ProfileMigrator {
|
||||
public PlacesRunnable(File profileDir, int limit) {
|
||||
mProfileDir = profileDir;
|
||||
mMaxEntries = limit;
|
||||
}
|
||||
|
||||
protected Uri getBookmarksUri() {
|
||||
Uri.Builder uriBuilder = Bookmarks.CONTENT_URI.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_SHOW_DELETED, "1");
|
||||
return uriBuilder.build();
|
||||
}
|
||||
|
||||
protected Uri getHistoryUri() {
|
||||
Uri.Builder uriBuilder = History.CONTENT_URI.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_SHOW_DELETED, "1");
|
||||
return uriBuilder.build();
|
||||
|
||||
}
|
||||
|
||||
protected Uri getImagesUri() {
|
||||
Uri.Builder uriBuilder = Images.CONTENT_URI.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_SHOW_DELETED, "1");
|
||||
return uriBuilder.build();
|
||||
mDB = new LocalBrowserDB(GeckoProfile.get(mContext).getName());
|
||||
}
|
||||
|
||||
private long getFolderId(String guid) {
|
||||
Cursor c = null;
|
||||
|
||||
try {
|
||||
c = mCr.query(getBookmarksUri(),
|
||||
// Uses default profile
|
||||
c = mCr.query(Bookmarks.CONTENT_URI,
|
||||
new String[] { Bookmarks._ID },
|
||||
Bookmarks.GUID + " = ?",
|
||||
new String [] { guid },
|
||||
@ -822,72 +807,7 @@ public class ProfileMigrator {
|
||||
|
||||
protected void updateBrowserHistory(String url, String title,
|
||||
long date, int visits) {
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
final String[] projection = new String[] {
|
||||
History._ID,
|
||||
History.VISITS,
|
||||
History.DATE_LAST_VISITED
|
||||
};
|
||||
|
||||
cursor = mCr.query(getHistoryUri(),
|
||||
projection,
|
||||
History.URL + " = ?",
|
||||
new String[] { url },
|
||||
null);
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
ContentProviderOperation.Builder builder = null;
|
||||
// Restore deleted record if possible
|
||||
values.put(History.IS_DELETED, 0);
|
||||
|
||||
if (cursor.moveToFirst()) {
|
||||
int visitsCol = cursor.getColumnIndexOrThrow(History.VISITS);
|
||||
int dateCol = cursor.getColumnIndexOrThrow(History.DATE_LAST_VISITED);
|
||||
int oldVisits = cursor.getInt(visitsCol);
|
||||
long oldDate = cursor.getLong(dateCol);
|
||||
|
||||
values.put(History.VISITS, oldVisits + visits);
|
||||
if (title != null) {
|
||||
values.put(History.TITLE, title);
|
||||
}
|
||||
// Only update last visited if newer.
|
||||
if (date > oldDate) {
|
||||
values.put(History.DATE_LAST_VISITED, date);
|
||||
}
|
||||
|
||||
int idCol = cursor.getColumnIndexOrThrow(History._ID);
|
||||
// We use default profile anyway
|
||||
Uri historyUri = ContentUris.withAppendedId(getHistoryUri(),
|
||||
cursor.getLong(idCol));
|
||||
|
||||
// Update
|
||||
builder = ContentProviderOperation.newUpdate(historyUri);
|
||||
// URL should be unique and we should hit it
|
||||
builder.withExpectedCount(1);
|
||||
builder.withValues(values);
|
||||
} else {
|
||||
values.put(History.URL, url);
|
||||
values.put(History.VISITS, visits);
|
||||
if (title != null) {
|
||||
values.put(History.TITLE, title);
|
||||
} else {
|
||||
values.put(History.TITLE, url);
|
||||
}
|
||||
values.put(History.DATE_LAST_VISITED, date);
|
||||
|
||||
// Insert
|
||||
builder = ContentProviderOperation.newInsert(getHistoryUri());
|
||||
builder.withValues(values);
|
||||
}
|
||||
|
||||
// Queue the operation
|
||||
mOperations.add(builder.build());
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
mDB.updateHistoryInBatch(mCr, mOperations, url, title, date, visits);
|
||||
}
|
||||
|
||||
protected BitmapDrawable decodeImageData(byte[] data) {
|
||||
@ -915,57 +835,21 @@ public class ProfileMigrator {
|
||||
}
|
||||
}
|
||||
try {
|
||||
ContentValues values = new ContentValues();
|
||||
byte[] newData = null;
|
||||
|
||||
// Recompress decoded images to PNG.
|
||||
if (image != null) {
|
||||
Bitmap bitmap = image.getBitmap();
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
|
||||
values.put(Images.FAVICON, stream.toByteArray());
|
||||
newData = stream.toByteArray();
|
||||
} else {
|
||||
// PNG images can be passed directly. Well, aside
|
||||
// from having to convert them into a byte[].
|
||||
values.put(Images.FAVICON, data);
|
||||
newData = data;
|
||||
}
|
||||
|
||||
values.put(Images.URL, url);
|
||||
values.put(Images.FAVICON_URL, faviconUrl);
|
||||
// Restore deleted record if possible
|
||||
values.put(Images.IS_DELETED, 0);
|
||||
if (faviconGuid != null) {
|
||||
values.put(Images.GUID, faviconGuid);
|
||||
}
|
||||
|
||||
Cursor cursor = null;
|
||||
ContentProviderOperation.Builder builder = null;
|
||||
try {
|
||||
cursor = mCr.query(getImagesUri(),
|
||||
null,
|
||||
Images.URL + " = ?",
|
||||
new String[] { url },
|
||||
null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
// Update
|
||||
builder = ContentProviderOperation.newUpdate(getImagesUri());
|
||||
// URL should be unique and we should hit it
|
||||
builder.withExpectedCount(1);
|
||||
builder.withValues(values);
|
||||
builder.withSelection(Images.URL + " = ?",
|
||||
new String[] { url });
|
||||
} else {
|
||||
// Insert
|
||||
builder = ContentProviderOperation.newInsert(getImagesUri());
|
||||
builder.withValues(values);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
// Queue the operation
|
||||
mOperations.add(builder.build());
|
||||
mDB.updateFaviconInBatch(mCr, mOperations, url, faviconUrl, faviconGuid, newData);
|
||||
} catch (SQLException e) {
|
||||
Log.i(LOGTAG, "Migrating favicon failed: " + mime + " URL: " + url
|
||||
+ " error:" + e.getMessage());
|
||||
@ -1081,81 +965,17 @@ public class ProfileMigrator {
|
||||
long parent, long added,
|
||||
long modified, long position,
|
||||
String keyword, int type) {
|
||||
ContentValues values = new ContentValues();
|
||||
if (title == null && url != null) {
|
||||
title = url;
|
||||
}
|
||||
if (title != null) {
|
||||
values.put(Bookmarks.TITLE, title);
|
||||
}
|
||||
if (url != null) {
|
||||
values.put(Bookmarks.URL, url);
|
||||
}
|
||||
if (guid != null) {
|
||||
values.put(SyncColumns.GUID, guid);
|
||||
}
|
||||
if (keyword != null) {
|
||||
values.put(Bookmarks.KEYWORD, keyword);
|
||||
}
|
||||
values.put(SyncColumns.DATE_CREATED, added);
|
||||
values.put(SyncColumns.DATE_MODIFIED, modified);
|
||||
values.put(Bookmarks.POSITION, position);
|
||||
// Restore deleted record if possible
|
||||
values.put(Bookmarks.IS_DELETED, 0);
|
||||
// Translate the parent pointer if needed
|
||||
if (mRerootMap.containsKey(parent)) {
|
||||
parent = mRerootMap.get(parent);
|
||||
}
|
||||
values.put(Bookmarks.PARENT, parent);
|
||||
|
||||
// The bookmark can only be one of three valid types
|
||||
values.put(Bookmarks.TYPE, type == PLACES_TYPE_BOOKMARK ? Bookmarks.TYPE_BOOKMARK :
|
||||
type == PLACES_TYPE_FOLDER ? Bookmarks.TYPE_FOLDER :
|
||||
Bookmarks.TYPE_SEPARATOR);
|
||||
|
||||
Cursor cursor = null;
|
||||
ContentProviderOperation.Builder builder = null;
|
||||
|
||||
if (url != null) {
|
||||
try {
|
||||
final String[] projection = new String[] {
|
||||
Bookmarks._ID,
|
||||
Bookmarks.URL
|
||||
};
|
||||
|
||||
// Check if the boomark exists
|
||||
cursor = mCr.query(getBookmarksUri(),
|
||||
projection,
|
||||
Bookmarks.URL + " = ?",
|
||||
new String[] { url },
|
||||
null);
|
||||
|
||||
if (cursor.moveToFirst()) {
|
||||
int idCol = cursor.getColumnIndexOrThrow(Bookmarks._ID);
|
||||
// We use default profile anyway
|
||||
Uri bookmarkUri = ContentUris.withAppendedId(getBookmarksUri(),
|
||||
cursor.getLong(idCol));
|
||||
// Update
|
||||
builder = ContentProviderOperation.newUpdate(bookmarkUri);
|
||||
// URL should be unique and we should hit it
|
||||
builder.withExpectedCount(1);
|
||||
builder.withValues(values);
|
||||
} else {
|
||||
// Insert
|
||||
builder = ContentProviderOperation.newInsert(getBookmarksUri());
|
||||
builder.withValues(values);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
} else {
|
||||
// Insert
|
||||
builder = ContentProviderOperation.newInsert(getBookmarksUri());
|
||||
builder.withValues(values);
|
||||
}
|
||||
|
||||
// Queue the operation
|
||||
mOperations.add(builder.build());
|
||||
int newtype = (type == PLACES_TYPE_BOOKMARK ? Bookmarks.TYPE_BOOKMARK :
|
||||
type == PLACES_TYPE_FOLDER ? Bookmarks.TYPE_FOLDER :
|
||||
Bookmarks.TYPE_SEPARATOR);
|
||||
mDB.updateBookmarkInBatch(mCr, mOperations,
|
||||
url, title, guid, parent, added,
|
||||
modified, position, keyword, newtype);
|
||||
}
|
||||
|
||||
protected void migrateBookmarks(SQLiteBridge db) {
|
||||
|
@ -7,6 +7,7 @@ package org.mozilla.gecko.db;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
|
||||
import org.mozilla.gecko.db.BrowserContract.History;
|
||||
@ -14,11 +15,14 @@ import org.mozilla.gecko.db.BrowserContract.ImageColumns;
|
||||
import org.mozilla.gecko.db.BrowserContract.Images;
|
||||
import org.mozilla.gecko.db.BrowserContract.Combined;
|
||||
import org.mozilla.gecko.db.BrowserContract.URLColumns;
|
||||
import org.mozilla.gecko.db.BrowserContract.SyncColumns;
|
||||
import org.mozilla.gecko.db.DBUtils;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.ContentProviderResult;
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
import android.database.CursorWrapper;
|
||||
@ -112,6 +116,24 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
||||
return uri.buildUpon().appendQueryParameter(BrowserContract.PARAM_PROFILE, mProfile).build();
|
||||
}
|
||||
|
||||
private Uri getAllBookmarksUri() {
|
||||
Uri.Builder uriBuilder = mBookmarksUriWithProfile.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_SHOW_DELETED, "1");
|
||||
return uriBuilder.build();
|
||||
}
|
||||
|
||||
private Uri getAllHistoryUri() {
|
||||
Uri.Builder uriBuilder = mHistoryUriWithProfile.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_SHOW_DELETED, "1");
|
||||
return uriBuilder.build();
|
||||
}
|
||||
|
||||
private Uri getAllImagesUri() {
|
||||
Uri.Builder uriBuilder = mImagesUriWithProfile.buildUpon()
|
||||
.appendQueryParameter(BrowserContract.PARAM_SHOW_DELETED, "1");
|
||||
return uriBuilder.build();
|
||||
}
|
||||
|
||||
private Cursor filterAllSites(ContentResolver cr, String[] projection, CharSequence constraint,
|
||||
int limit, CharSequence urlFilter) {
|
||||
String selection = "";
|
||||
@ -658,6 +680,148 @@ public class LocalBrowserDB implements BrowserDB.BrowserDBIface {
|
||||
return b;
|
||||
}
|
||||
|
||||
// Utility function for updating existing history using batch operations
|
||||
public void updateHistoryInBatch(ContentResolver cr,
|
||||
Collection<ContentProviderOperation> operations,
|
||||
String url, String title,
|
||||
long date, int visits) {
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
final String[] projection = new String[] {
|
||||
History._ID,
|
||||
History.VISITS,
|
||||
History.DATE_LAST_VISITED
|
||||
};
|
||||
|
||||
// We need to get the old visit count.
|
||||
cursor = cr.query(getAllHistoryUri(),
|
||||
projection,
|
||||
History.URL + " = ?",
|
||||
new String[] { url },
|
||||
null);
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
|
||||
// Restore deleted record if possible
|
||||
values.put(History.IS_DELETED, 0);
|
||||
|
||||
if (cursor.moveToFirst()) {
|
||||
int visitsCol = cursor.getColumnIndexOrThrow(History.VISITS);
|
||||
int dateCol = cursor.getColumnIndexOrThrow(History.DATE_LAST_VISITED);
|
||||
int oldVisits = cursor.getInt(visitsCol);
|
||||
long oldDate = cursor.getLong(dateCol);
|
||||
values.put(History.VISITS, oldVisits + visits);
|
||||
// Only update last visited if newer.
|
||||
if (date > oldDate) {
|
||||
values.put(History.DATE_LAST_VISITED, date);
|
||||
}
|
||||
} else {
|
||||
values.put(History.VISITS, 1);
|
||||
values.put(History.DATE_LAST_VISITED, date);
|
||||
}
|
||||
if (title != null) {
|
||||
values.put(History.TITLE, title);
|
||||
}
|
||||
values.put(History.URL, url);
|
||||
|
||||
Uri historyUri = getAllHistoryUri().buildUpon().
|
||||
appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build();
|
||||
|
||||
// Update or insert
|
||||
ContentProviderOperation.Builder builder =
|
||||
ContentProviderOperation.newUpdate(historyUri);
|
||||
builder.withSelection(History.URL + " = ?", new String[] { url });
|
||||
builder.withValues(values);
|
||||
|
||||
// Queue the operation
|
||||
operations.add(builder.build());
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateBookmarkInBatch(ContentResolver cr,
|
||||
Collection<ContentProviderOperation> operations,
|
||||
String url, String title, String guid,
|
||||
long parent, long added,
|
||||
long modified, long position,
|
||||
String keyword, int type) {
|
||||
ContentValues values = new ContentValues();
|
||||
if (title == null && url != null) {
|
||||
title = url;
|
||||
}
|
||||
if (title != null) {
|
||||
values.put(Bookmarks.TITLE, title);
|
||||
}
|
||||
if (url != null) {
|
||||
values.put(Bookmarks.URL, url);
|
||||
}
|
||||
if (guid != null) {
|
||||
values.put(SyncColumns.GUID, guid);
|
||||
}
|
||||
if (keyword != null) {
|
||||
values.put(Bookmarks.KEYWORD, keyword);
|
||||
}
|
||||
if (added > 0) {
|
||||
values.put(SyncColumns.DATE_CREATED, added);
|
||||
}
|
||||
if (modified > 0) {
|
||||
values.put(SyncColumns.DATE_MODIFIED, modified);
|
||||
}
|
||||
values.put(Bookmarks.POSITION, position);
|
||||
// Restore deleted record if possible
|
||||
values.put(Bookmarks.IS_DELETED, 0);
|
||||
|
||||
// This assumes no "real" folder has a negative ID. Only
|
||||
// things like the reading list folder do.
|
||||
if (parent < 0) {
|
||||
parent = getFolderIdFromGuid(cr, Bookmarks.MOBILE_FOLDER_GUID);
|
||||
}
|
||||
values.put(Bookmarks.PARENT, parent);
|
||||
values.put(Bookmarks.TYPE, type);
|
||||
|
||||
Uri bookmarkUri = getAllBookmarksUri().buildUpon().
|
||||
appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build();
|
||||
// Update or insert
|
||||
ContentProviderOperation.Builder builder =
|
||||
ContentProviderOperation.newUpdate(bookmarkUri);
|
||||
builder.withSelection(Bookmarks.URL + " = ?", new String[] { url });
|
||||
builder.withValues(values);
|
||||
|
||||
// Queue the operation
|
||||
operations.add(builder.build());
|
||||
}
|
||||
|
||||
public void updateFaviconInBatch(ContentResolver cr,
|
||||
Collection<ContentProviderOperation> operations,
|
||||
String url, String faviconUrl,
|
||||
String faviconGuid, byte[] data) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(Images.FAVICON, data);
|
||||
values.put(Images.URL, url);
|
||||
if (faviconUrl != null) {
|
||||
values.put(Images.FAVICON_URL, faviconUrl);
|
||||
}
|
||||
// Restore deleted record if possible
|
||||
values.put(Images.IS_DELETED, 0);
|
||||
if (faviconGuid != null) {
|
||||
values.put(Images.GUID, faviconGuid);
|
||||
}
|
||||
|
||||
// Update or insert
|
||||
Uri imagesUri = getAllImagesUri().buildUpon().
|
||||
appendQueryParameter(BrowserContract.PARAM_INSERT_IF_NEEDED, "true").build();
|
||||
// Update or insert
|
||||
ContentProviderOperation.Builder builder =
|
||||
ContentProviderOperation.newUpdate(imagesUri);
|
||||
builder.withValues(values);
|
||||
builder.withSelection(Images.URL + " = ?", new String[] { url });
|
||||
// Queue the operation
|
||||
operations.add(builder.build());
|
||||
}
|
||||
|
||||
// This wrapper adds a fake "Desktop Bookmarks" folder entry to the
|
||||
// beginning of the cursor's data set.
|
||||
private class SpecialFoldersCursorWrapper extends CursorWrapper {
|
||||
|
Loading…
Reference in New Issue
Block a user