From fba09deec7da994ca4376421cf4b8f5be67d729f Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 22 Oct 2014 11:28:28 -0700 Subject: Refactoring LauncherBackupHelper.java > Moving a bunch of variables to Global level to make it easier to maintain state. Change-Id: I9ded313bd4f673f45c61556b8c66607dc78a5ae9 --- .../android/launcher3/LauncherBackupHelper.java | 612 ++++++++------------- 1 file changed, 222 insertions(+), 390 deletions(-) diff --git a/src/com/android/launcher3/LauncherBackupHelper.java b/src/com/android/launcher3/LauncherBackupHelper.java index 201f3e9bb..b2ac577f4 100644 --- a/src/com/android/launcher3/LauncherBackupHelper.java +++ b/src/com/android/launcher3/LauncherBackupHelper.java @@ -15,22 +15,6 @@ */ package com.android.launcher3; -import com.google.protobuf.nano.InvalidProtocolBufferNanoException; -import com.google.protobuf.nano.MessageNano; - -import com.android.launcher3.LauncherSettings.Favorites; -import com.android.launcher3.LauncherSettings.WorkspaceScreens; -import com.android.launcher3.backup.BackupProtos; -import com.android.launcher3.backup.BackupProtos.CheckedMessage; -import com.android.launcher3.backup.BackupProtos.Favorite; -import com.android.launcher3.backup.BackupProtos.Journal; -import com.android.launcher3.backup.BackupProtos.Key; -import com.android.launcher3.backup.BackupProtos.Resource; -import com.android.launcher3.backup.BackupProtos.Screen; -import com.android.launcher3.backup.BackupProtos.Widget; -import com.android.launcher3.compat.UserManagerCompat; -import com.android.launcher3.compat.UserHandleCompat; - import android.app.backup.BackupDataInputStream; import android.app.backup.BackupDataOutput; import android.app.backup.BackupHelper; @@ -42,6 +26,7 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager.NameNotFoundException; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -51,6 +36,21 @@ import android.text.TextUtils; import android.util.Base64; import android.util.Log; +import com.android.launcher3.LauncherSettings.Favorites; +import com.android.launcher3.LauncherSettings.WorkspaceScreens; +import com.android.launcher3.backup.BackupProtos; +import com.android.launcher3.backup.BackupProtos.CheckedMessage; +import com.android.launcher3.backup.BackupProtos.Favorite; +import com.android.launcher3.backup.BackupProtos.Journal; +import com.android.launcher3.backup.BackupProtos.Key; +import com.android.launcher3.backup.BackupProtos.Resource; +import com.android.launcher3.backup.BackupProtos.Screen; +import com.android.launcher3.backup.BackupProtos.Widget; +import com.android.launcher3.compat.UserHandleCompat; +import com.android.launcher3.compat.UserManagerCompat; +import com.google.protobuf.nano.InvalidProtocolBufferNanoException; +import com.google.protobuf.nano.MessageNano; + import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -60,7 +60,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.zip.CRC32; /** @@ -71,7 +70,6 @@ public class LauncherBackupHelper implements BackupHelper { private static final String TAG = "LauncherBackupHelper"; private static final boolean VERBOSE = LauncherBackupAgentHelper.VERBOSE; private static final boolean DEBUG = LauncherBackupAgentHelper.DEBUG; - private static final boolean DEBUG_PAYLOAD = false; private static final int MAX_JOURNAL_SIZE = 1000000; @@ -90,27 +88,25 @@ public class LauncherBackupHelper implements BackupHelper { private static final Bitmap.CompressFormat IMAGE_FORMAT = android.graphics.Bitmap.CompressFormat.PNG; - private static BackupManager sBackupManager; - private static final String[] FAVORITE_PROJECTION = { - Favorites._ID, // 0 - Favorites.MODIFIED, // 1 - Favorites.INTENT, // 2 - Favorites.APPWIDGET_PROVIDER, // 3 - Favorites.APPWIDGET_ID, // 4 - Favorites.CELLX, // 5 - Favorites.CELLY, // 6 - Favorites.CONTAINER, // 7 - Favorites.ICON, // 8 - Favorites.ICON_PACKAGE, // 9 - Favorites.ICON_RESOURCE, // 10 - Favorites.ICON_TYPE, // 11 - Favorites.ITEM_TYPE, // 12 - Favorites.SCREEN, // 13 - Favorites.SPANX, // 14 - Favorites.SPANY, // 15 - Favorites.TITLE, // 16 - Favorites.PROFILE_ID, // 17 + Favorites._ID, // 0 + Favorites.MODIFIED, // 1 + Favorites.INTENT, // 2 + Favorites.APPWIDGET_PROVIDER, // 3 + Favorites.APPWIDGET_ID, // 4 + Favorites.CELLX, // 5 + Favorites.CELLY, // 6 + Favorites.CONTAINER, // 7 + Favorites.ICON, // 8 + Favorites.ICON_PACKAGE, // 9 + Favorites.ICON_RESOURCE, // 10 + Favorites.ICON_TYPE, // 11 + Favorites.ITEM_TYPE, // 12 + Favorites.SCREEN, // 13 + Favorites.SPANX, // 14 + Favorites.SPANY, // 15 + Favorites.TITLE, // 16 + Favorites.PROFILE_ID, // 17 }; private static final int ID_INDEX = 0; @@ -130,37 +126,46 @@ public class LauncherBackupHelper implements BackupHelper { private static final int SPANX_INDEX = 14; private static final int SPANY_INDEX = 15; private static final int TITLE_INDEX = 16; - private static final int PROFILE_ID_INDEX = 17; private static final String[] SCREEN_PROJECTION = { - WorkspaceScreens._ID, // 0 - WorkspaceScreens.MODIFIED, // 1 - WorkspaceScreens.SCREEN_RANK // 2 + WorkspaceScreens._ID, // 0 + WorkspaceScreens.MODIFIED, // 1 + WorkspaceScreens.SCREEN_RANK // 2 }; private static final int SCREEN_RANK_INDEX = 2; - private static IconCache mIconCache; - private final Context mContext; + private final HashSet mExistingKeys; + private final ArrayList mKeys; - private final boolean mRestoreEnabled; - + private IconCache mIconCache; + private BackupManager mBackupManager; private HashMap mWidgetMap; - - private final ArrayList mKeys; + private byte[] mBuffer = new byte[512]; + private long mLastBackupRestoreTime; public LauncherBackupHelper(Context context, boolean restoreEnabled) { mContext = context; - mRestoreEnabled = restoreEnabled; + mExistingKeys = new HashSet(); mKeys = new ArrayList(); } private void dataChanged() { - if (sBackupManager == null) { - sBackupManager = new BackupManager(mContext); + if (mBackupManager == null) { + mBackupManager = new BackupManager(mContext); + } + mBackupManager.dataChanged(); + } + + private void applyJournal(Journal journal) { + mLastBackupRestoreTime = journal.t; + mExistingKeys.clear(); + if (journal.key != null) { + for (Key key : journal.key) { + mExistingKeys.add(keyToBackupKey(key)); + } } - sBackupManager.dataChanged(); } /** @@ -181,32 +186,45 @@ public class LauncherBackupHelper implements BackupHelper { if (VERBOSE) Log.v(TAG, "onBackup"); Journal in = readJournal(oldState); - Journal out = new Journal(); + if (!launcherIsReady()) { + // Perform backup later. + writeJournal(newState, in); + return; + } + Log.v(TAG, "lastBackupTime = " + in.t); + mKeys.clear(); + applyJournal(in); - long lastBackupTime = in.t; - out.t = System.currentTimeMillis(); - out.rows = 0; - out.bytes = 0; + // Record the time before performing backup so that entries edited while the backup + // was going on, do not get missed in next backup. + long newBackupTime = System.currentTimeMillis(); - Log.v(TAG, "lastBackupTime = " + lastBackupTime); + try { + backupFavorites(data); + backupScreens(data); + backupIcons(data); + backupWidgets(data); + + // Delete any key which still exist in the old backup, but is not valid anymore. + HashSet validKeys = new HashSet(); + for (Key key : mKeys) { + validKeys.add(keyToBackupKey(key)); + } + mExistingKeys.removeAll(validKeys); - ArrayList keys = new ArrayList(); - if (launcherIsReady()) { - try { - backupFavorites(in, data, out, keys); - backupScreens(in, data, out, keys); - backupIcons(in, data, out, keys); - backupWidgets(in, data, out, keys); - } catch (IOException e) { - Log.e(TAG, "launcher backup has failed", e); + // Delete anything left in the existing keys. + for (String deleted: mExistingKeys) { + if (VERBOSE) Log.v(TAG, "dropping deleted item " + deleted); + data.writeEntityHeader(deleted, -1); } - out.key = keys.toArray(new BackupProtos.Key[keys.size()]); - } else { - out = in; + + mExistingKeys.clear(); + mLastBackupRestoreTime = newBackupTime; + } catch (IOException e) { + Log.e(TAG, "launcher backup has failed", e); } - writeJournal(newState, out); - Log.v(TAG, "onBackup: wrote " + out.bytes + "b in " + out.rows + " rows."); + writeNewStateDescription(newState); } /** @@ -218,49 +236,41 @@ public class LauncherBackupHelper implements BackupHelper { */ @Override public void restoreEntity(BackupDataInputStream data) { - if (VERBOSE) Log.v(TAG, "restoreEntity"); - byte[] buffer = new byte[512]; - String backupKey = data.getKey(); - int dataSize = data.size(); - if (buffer.length < dataSize) { - buffer = new byte[dataSize]; - } - Key key = null; - int bytesRead = 0; - try { - bytesRead = data.read(buffer, 0, dataSize); - if (DEBUG) Log.d(TAG, "read " + bytesRead + " of " + dataSize + " available"); - } catch (IOException e) { - Log.e(TAG, "failed to read entity from restore data", e); + int dataSize = data.size(); + if (mBuffer.length < dataSize) { + mBuffer = new byte[dataSize]; } try { - key = backupKeyToKey(backupKey); + int bytesRead = data.read(mBuffer, 0, dataSize); + if (DEBUG) Log.d(TAG, "read " + bytesRead + " of " + dataSize + " available"); + String backupKey = data.getKey(); + Key key = backupKeyToKey(backupKey); mKeys.add(key); switch (key.type) { case Key.FAVORITE: - restoreFavorite(key, buffer, dataSize, mKeys); + restoreFavorite(key, mBuffer, dataSize); break; case Key.SCREEN: - restoreScreen(key, buffer, dataSize, mKeys); + restoreScreen(key, mBuffer, dataSize); break; case Key.ICON: - restoreIcon(key, buffer, dataSize, mKeys); + restoreIcon(key, mBuffer, dataSize); break; case Key.WIDGET: - restoreWidget(key, buffer, dataSize, mKeys); + restoreWidget(key, mBuffer, dataSize); break; default: Log.w(TAG, "unknown restore entity type: " + key.type); + mKeys.remove(key); break; } - } catch (KeyParsingException e) { - Log.w(TAG, "ignoring unparsable backup key: " + backupKey); + } catch (IOException e) { + Log.w(TAG, "ignoring unparsable backup entry", e); } - } /** @@ -270,63 +280,55 @@ public class LauncherBackupHelper implements BackupHelper { */ @Override public void writeNewStateDescription(ParcelFileDescriptor newState) { - // clear the output journal time, to force a full backup to - // will catch any changes the restore process might have made - Journal out = new Journal(); - out.t = 0; - out.key = mKeys.toArray(new BackupProtos.Key[mKeys.size()]); - writeJournal(newState, out); - Log.v(TAG, "onRestore: read " + mKeys.size() + " rows"); - mKeys.clear(); + writeJournal(newState, getCurrentStateJournal()); + } + + private Journal getCurrentStateJournal() { + Journal journal = new Journal(); + journal.t = mLastBackupRestoreTime; + journal.key = mKeys.toArray(new BackupProtos.Key[mKeys.size()]); + journal.appVersion = getAppVersion(); + return journal; + } + + private int getAppVersion() { + try { + return mContext.getPackageManager() + .getPackageInfo(mContext.getPackageName(), 0).versionCode; + } catch (NameNotFoundException e) { + return 0; + } } /** * Write all modified favorites to the data stream. * - * - * @param in notes from last backup * @param data output stream for key/value pairs - * @param out notes about this backup - * @param keys keys to mark as clean in the notes for next backup * @throws IOException */ - private void backupFavorites(Journal in, BackupDataOutput data, Journal out, - ArrayList keys) - throws IOException { - // read the old ID set - Set savedIds = getSavedIdsByType(Key.FAVORITE, in); - if (DEBUG) Log.d(TAG, "favorite savedIds.size()=" + savedIds.size()); - + private void backupFavorites(BackupDataOutput data) throws IOException { // persist things that have changed since the last backup ContentResolver cr = mContext.getContentResolver(); // Don't backup apps in other profiles for now. Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION, getUserSelectionArg(), null, null); - Set currentIds = new HashSet(cursor.getCount()); try { cursor.moveToPosition(-1); while(cursor.moveToNext()) { final long id = cursor.getLong(ID_INDEX); final long updateTime = cursor.getLong(ID_MODIFIED); Key key = getKey(Key.FAVORITE, id); - keys.add(key); + mKeys.add(key); final String backupKey = keyToBackupKey(key); - currentIds.add(backupKey); - if (!savedIds.contains(backupKey) || updateTime >= in.t) { - byte[] blob = packFavorite(cursor); - writeRowToBackup(key, blob, out, data); + if (!mExistingKeys.contains(backupKey) || updateTime >= mLastBackupRestoreTime) { + writeRowToBackup(key, packFavorite(cursor), data); } else { - if (VERBOSE) Log.v(TAG, "favorite " + id + " was too old: " + updateTime); + if (DEBUG) Log.d(TAG, "favorite already backup up: " + id); } } } finally { cursor.close(); } - if (DEBUG) Log.d(TAG, "favorite currentIds.size()=" + currentIds.size()); - - // these IDs must have been deleted - savedIds.removeAll(currentIds); - out.rows += removeDeletedKeysFromBackup(savedIds, data); } /** @@ -337,74 +339,46 @@ public class LauncherBackupHelper implements BackupHelper { * @param key identifier for the row * @param buffer the serialized proto from the stream, may be larger than dataSize * @param dataSize the size of the proto from the stream - * @param keys keys to mark as clean in the notes for next backup */ - private void restoreFavorite(Key key, byte[] buffer, int dataSize, ArrayList keys) { + private void restoreFavorite(Key key, byte[] buffer, int dataSize) throws IOException { if (VERBOSE) Log.v(TAG, "unpacking favorite " + key.id); if (DEBUG) Log.d(TAG, "read (" + buffer.length + "): " + Base64.encodeToString(buffer, 0, dataSize, Base64.NO_WRAP)); - if (!mRestoreEnabled) { - if (VERBOSE) Log.v(TAG, "restore not enabled: skipping database mutation"); - return; - } - - try { - ContentResolver cr = mContext.getContentResolver(); - ContentValues values = unpackFavorite(buffer, 0, dataSize); - cr.insert(Favorites.CONTENT_URI_NO_NOTIFICATION, values); - } catch (InvalidProtocolBufferNanoException e) { - Log.e(TAG, "failed to decode favorite", e); - } + ContentResolver cr = mContext.getContentResolver(); + ContentValues values = unpackFavorite(buffer, dataSize); + cr.insert(Favorites.CONTENT_URI_NO_NOTIFICATION, values); } /** * Write all modified screens to the data stream. * - * - * @param in notes from last backup * @param data output stream for key/value pairs - * @param out notes about this backup - * @param keys keys to mark as clean in the notes for next backup * @throws IOException */ - private void backupScreens(Journal in, BackupDataOutput data, Journal out, - ArrayList keys) - throws IOException { - // read the old ID set - Set savedIds = getSavedIdsByType(Key.SCREEN, in); - if (DEBUG) Log.d(TAG, "screen savedIds.size()=" + savedIds.size()); - + private void backupScreens(BackupDataOutput data) throws IOException { // persist things that have changed since the last backup ContentResolver cr = mContext.getContentResolver(); Cursor cursor = cr.query(WorkspaceScreens.CONTENT_URI, SCREEN_PROJECTION, null, null, null); - Set currentIds = new HashSet(cursor.getCount()); try { cursor.moveToPosition(-1); - if (DEBUG) Log.d(TAG, "dumping screens after: " + in.t); + if (DEBUG) Log.d(TAG, "dumping screens after: " + mLastBackupRestoreTime); while(cursor.moveToNext()) { final long id = cursor.getLong(ID_INDEX); final long updateTime = cursor.getLong(ID_MODIFIED); Key key = getKey(Key.SCREEN, id); - keys.add(key); + mKeys.add(key); final String backupKey = keyToBackupKey(key); - currentIds.add(backupKey); - if (!savedIds.contains(backupKey) || updateTime >= in.t) { - byte[] blob = packScreen(cursor); - writeRowToBackup(key, blob, out, data); + if (!mExistingKeys.contains(backupKey) || updateTime >= mLastBackupRestoreTime) { + writeRowToBackup(key, packScreen(cursor), data); } else { - if (VERBOSE) Log.v(TAG, "screen " + id + " was too old: " + updateTime); + if (VERBOSE) Log.v(TAG, "screen already backup up " + id); } } } finally { cursor.close(); } - if (DEBUG) Log.d(TAG, "screen currentIds.size()=" + currentIds.size()); - - // these IDs must have been deleted - savedIds.removeAll(currentIds); - out.rows += removeDeletedKeysFromBackup(savedIds, data); } /** @@ -415,40 +389,24 @@ public class LauncherBackupHelper implements BackupHelper { * @param key identifier for the row * @param buffer the serialized proto from the stream, may be larger than dataSize * @param dataSize the size of the proto from the stream - * @param keys keys to mark as clean in the notes for next backup */ - private void restoreScreen(Key key, byte[] buffer, int dataSize, ArrayList keys) { + private void restoreScreen(Key key, byte[] buffer, int dataSize) throws IOException { if (VERBOSE) Log.v(TAG, "unpacking screen " + key.id); if (DEBUG) Log.d(TAG, "read (" + buffer.length + "): " + Base64.encodeToString(buffer, 0, dataSize, Base64.NO_WRAP)); - if (!mRestoreEnabled) { - if (VERBOSE) Log.v(TAG, "restore not enabled: skipping database mutation"); - return; - } - - try { - ContentResolver cr = mContext.getContentResolver(); - ContentValues values = unpackScreen(buffer, 0, dataSize); - cr.insert(WorkspaceScreens.CONTENT_URI, values); - - } catch (InvalidProtocolBufferNanoException e) { - Log.e(TAG, "failed to decode screen", e); - } + ContentResolver cr = mContext.getContentResolver(); + ContentValues values = unpackScreen(buffer, dataSize); + cr.insert(WorkspaceScreens.CONTENT_URI, values); } /** * Write all the static icon resources we need to render placeholders * for a package that is not installed. * - * @param in notes from last backup * @param data output stream for key/value pairs - * @param out notes about this backup - * @param keys keys to mark as clean in the notes for next backup - * @throws IOException */ - private void backupIcons(Journal in, BackupDataOutput data, Journal out, - ArrayList keys) throws IOException { + private void backupIcons(BackupDataOutput data) throws IOException { // persist icons that haven't been persisted yet if (!initializeIconCache()) { dataChanged(); // try again later @@ -458,21 +416,14 @@ public class LauncherBackupHelper implements BackupHelper { final ContentResolver cr = mContext.getContentResolver(); final int dpi = mContext.getResources().getDisplayMetrics().densityDpi; final UserHandleCompat myUserHandle = UserHandleCompat.myUserHandle(); - - // read the old ID set - Set savedIds = getSavedIdsByType(Key.ICON, in); - if (DEBUG) Log.d(TAG, "icon savedIds.size()=" + savedIds.size()); + int backupUpIconCount = 0; // Don't backup apps in other profiles for now. - int startRows = out.rows; - if (DEBUG) Log.d(TAG, "starting here: " + startRows); - String where = "(" + Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPLICATION + " OR " + Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_SHORTCUT + ") AND " + getUserSelectionArg(); Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION, where, null, null); - Set currentIds = new HashSet(cursor.getCount()); try { cursor.moveToPosition(-1); while(cursor.moveToNext()) { @@ -486,27 +437,26 @@ public class LauncherBackupHelper implements BackupHelper { if (cn != null) { key = getKey(Key.ICON, cn.flattenToShortString()); backupKey = keyToBackupKey(key); - currentIds.add(backupKey); } else { Log.w(TAG, "empty intent on application favorite: " + id); } - if (savedIds.contains(backupKey)) { - if (VERBOSE) Log.v(TAG, "already saved icon " + backupKey); + if (mExistingKeys.contains(backupKey)) { + if (DEBUG) Log.d(TAG, "already saved icon " + backupKey); // remember that we already backed this up previously - keys.add(key); + mKeys.add(key); } else if (backupKey != null) { - if (DEBUG) Log.d(TAG, "I can count this high: " + out.rows); - if ((out.rows - startRows) < MAX_ICONS_PER_PASS) { - if (VERBOSE) Log.v(TAG, "saving icon " + backupKey); + if (DEBUG) Log.d(TAG, "I can count this high: " + backupUpIconCount); + if (backupUpIconCount < MAX_ICONS_PER_PASS) { + if (DEBUG) Log.d(TAG, "saving icon " + backupKey); Bitmap icon = mIconCache.getIcon(intent, myUserHandle); - keys.add(key); if (icon != null && !mIconCache.isDefaultIcon(icon, myUserHandle)) { - byte[] blob = packIcon(dpi, icon); - writeRowToBackup(key, blob, out, data); + writeRowToBackup(key, packIcon(dpi, icon), data); + mKeys.add(key); + backupUpIconCount ++; } } else { - if (VERBOSE) Log.d(TAG, "deferring icon backup " + backupKey); + if (VERBOSE) Log.v(TAG, "deferring icon backup " + backupKey); // too many icons for this pass, request another. dataChanged(); } @@ -521,11 +471,6 @@ public class LauncherBackupHelper implements BackupHelper { } finally { cursor.close(); } - if (DEBUG) Log.d(TAG, "icon currentIds.size()=" + currentIds.size()); - - // these IDs must have been deleted - savedIds.removeAll(currentIds); - out.rows += removeDeletedKeysFromBackup(savedIds, data); } /** @@ -536,55 +481,32 @@ public class LauncherBackupHelper implements BackupHelper { * @param key identifier for the row * @param buffer the serialized proto from the stream, may be larger than dataSize * @param dataSize the size of the proto from the stream - * @param keys keys to mark as clean in the notes for next backup */ - private void restoreIcon(Key key, byte[] buffer, int dataSize, ArrayList keys) { + private void restoreIcon(Key key, byte[] buffer, int dataSize) throws IOException { if (VERBOSE) Log.v(TAG, "unpacking icon " + key.id); if (DEBUG) Log.d(TAG, "read (" + buffer.length + "): " + Base64.encodeToString(buffer, 0, dataSize, Base64.NO_WRAP)); - try { - Resource res = unpackIcon(buffer, 0, dataSize); - if (DEBUG) { - Log.d(TAG, "unpacked " + res.dpi + " dpi icon"); - } - if (DEBUG_PAYLOAD) { - Log.d(TAG, "read " + - Base64.encodeToString(res.data, 0, res.data.length, - Base64.NO_WRAP)); - } - Bitmap icon = BitmapFactory.decodeByteArray(res.data, 0, res.data.length); - if (icon == null) { - Log.w(TAG, "failed to unpack icon for " + key.name); - } - - if (!mRestoreEnabled) { - if (VERBOSE) { - Log.v(TAG, "restore not enabled: skipping database mutation"); - } - return; - } else { - if (VERBOSE) Log.v(TAG, "saving restored icon as: " + key.name); - IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(key.name), - icon, res.dpi); - } - } catch (IOException e) { - Log.d(TAG, "failed to save restored icon for: " + key.name, e); + Resource res = unpackProto(new Resource(), buffer, dataSize); + if (DEBUG) { + Log.d(TAG, "unpacked " + res.dpi + " dpi icon"); } + Bitmap icon = BitmapFactory.decodeByteArray(res.data, 0, res.data.length); + if (icon == null) { + Log.w(TAG, "failed to unpack icon for " + key.name); + } + if (VERBOSE) Log.v(TAG, "saving restored icon as: " + key.name); + IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(key.name), icon, res.dpi); } /** * Write all the static widget resources we need to render placeholders * for a package that is not installed. * - * @param in notes from last backup * @param data output stream for key/value pairs - * @param out notes about this backup - * @param keys keys to mark as clean in the notes for next backup * @throws IOException */ - private void backupWidgets(Journal in, BackupDataOutput data, Journal out, - ArrayList keys) throws IOException { + private void backupWidgets(BackupDataOutput data) throws IOException { // persist static widget info that hasn't been persisted yet final LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); if (appState == null || !initializeIconCache()) { @@ -597,18 +519,12 @@ public class LauncherBackupHelper implements BackupHelper { final int dpi = mContext.getResources().getDisplayMetrics().densityDpi; final DeviceProfile profile = appState.getDynamicGrid().getDeviceProfile(); if (DEBUG) Log.d(TAG, "cellWidthPx: " + profile.cellWidthPx); + int backupWidgetCount = 0; - // read the old ID set - Set savedIds = getSavedIdsByType(Key.WIDGET, in); - if (DEBUG) Log.d(TAG, "widgets savedIds.size()=" + savedIds.size()); - - int startRows = out.rows; - if (DEBUG) Log.d(TAG, "starting here: " + startRows); String where = Favorites.ITEM_TYPE + "=" + Favorites.ITEM_TYPE_APPWIDGET + " AND " + getUserSelectionArg(); Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION, where, null, null); - Set currentIds = new HashSet(cursor.getCount()); try { cursor.moveToPosition(-1); while(cursor.moveToNext()) { @@ -622,27 +538,25 @@ public class LauncherBackupHelper implements BackupHelper { if (provider != null) { key = getKey(Key.WIDGET, providerName); backupKey = keyToBackupKey(key); - currentIds.add(backupKey); } else { Log.w(TAG, "empty intent on appwidget: " + id); } - if (savedIds.contains(backupKey)) { - if (VERBOSE) Log.v(TAG, "already saved widget " + backupKey); + if (mExistingKeys.contains(backupKey)) { + if (DEBUG) Log.d(TAG, "already saved widget " + backupKey); // remember that we already backed this up previously - keys.add(key); + mKeys.add(key); } else if (backupKey != null) { - if (DEBUG) Log.d(TAG, "I can count this high: " + out.rows); - if ((out.rows - startRows) < MAX_WIDGETS_PER_PASS) { - if (VERBOSE) Log.v(TAG, "saving widget " + backupKey); + if (DEBUG) Log.d(TAG, "I can count this high: " + backupWidgetCount); + if (backupWidgetCount < MAX_WIDGETS_PER_PASS) { + if (DEBUG) Log.d(TAG, "saving widget " + backupKey); previewLoader.setPreviewSize(spanX * profile.cellWidthPx, spanY * profile.cellHeightPx, widgetSpacingLayout); - byte[] blob = packWidget(dpi, previewLoader, mIconCache, provider); - keys.add(key); - writeRowToBackup(key, blob, out, data); - + writeRowToBackup(key, packWidget(dpi, previewLoader, mIconCache, provider), data); + mKeys.add(key); + backupWidgetCount ++; } else { - if (VERBOSE) Log.d(TAG, "deferring widget backup " + backupKey); + if (VERBOSE) Log.v(TAG, "deferring widget backup " + backupKey); // too many widgets for this pass, request another. dataChanged(); } @@ -651,11 +565,6 @@ public class LauncherBackupHelper implements BackupHelper { } finally { cursor.close(); } - if (DEBUG) Log.d(TAG, "widget currentIds.size()=" + currentIds.size()); - - // these IDs must have been deleted - savedIds.removeAll(currentIds); - out.rows += removeDeletedKeysFromBackup(savedIds, data); } /** @@ -666,35 +575,25 @@ public class LauncherBackupHelper implements BackupHelper { * @param key identifier for the row * @param buffer the serialized proto from the stream, may be larger than dataSize * @param dataSize the size of the proto from the stream - * @param keys keys to mark as clean in the notes for next backup */ - private void restoreWidget(Key key, byte[] buffer, int dataSize, ArrayList keys) { + private void restoreWidget(Key key, byte[] buffer, int dataSize) throws IOException { if (VERBOSE) Log.v(TAG, "unpacking widget " + key.id); if (DEBUG) Log.d(TAG, "read (" + buffer.length + "): " + Base64.encodeToString(buffer, 0, dataSize, Base64.NO_WRAP)); - try { - Widget widget = unpackWidget(buffer, 0, dataSize); - if (DEBUG) Log.d(TAG, "unpacked " + widget.provider); - if (widget.icon.data != null) { - Bitmap icon = BitmapFactory - .decodeByteArray(widget.icon.data, 0, widget.icon.data.length); - if (icon == null) { - Log.w(TAG, "failed to unpack widget icon for " + key.name); - } else { - IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(widget.provider), - icon, widget.icon.dpi); - } - } - - if (!mRestoreEnabled) { - if (VERBOSE) Log.v(TAG, "restore not enabled: skipping database mutation"); - return; + Widget widget = unpackProto(new Widget(), buffer, dataSize); + if (DEBUG) Log.d(TAG, "unpacked " + widget.provider); + if (widget.icon.data != null) { + Bitmap icon = BitmapFactory + .decodeByteArray(widget.icon.data, 0, widget.icon.data.length); + if (icon == null) { + Log.w(TAG, "failed to unpack widget icon for " + key.name); } else { - // future site of widget table mutation + IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(widget.provider), + icon, widget.icon.dpi); } - } catch (InvalidProtocolBufferNanoException e) { - Log.e(TAG, "failed to decode widget", e); } + + // future site of widget table mutation } /** create a new key, with an integer ID. @@ -744,30 +643,6 @@ public class LauncherBackupHelper implements BackupHelper { } } - private String getKeyName(Key key) { - if (TextUtils.isEmpty(key.name)) { - return Long.toString(key.id); - } else { - return key.name; - } - - } - - private String geKeyType(Key key) { - switch (key.type) { - case Key.FAVORITE: - return "favorite"; - case Key.SCREEN: - return "screen"; - case Key.ICON: - return "icon"; - case Key.WIDGET: - return "widget"; - default: - return "anonymous"; - } - } - /** Compute the checksum over the important bits of a key. */ private long checkKey(Key key) { CRC32 checksum = new CRC32(); @@ -781,7 +656,7 @@ public class LauncherBackupHelper implements BackupHelper { } /** Serialize a Favorite for persistence, including a checksum wrapper. */ - private byte[] packFavorite(Cursor c) { + private Favorite packFavorite(Cursor c) { Favorite favorite = new Favorite(); favorite.id = c.getLong(ID_INDEX); favorite.screen = c.getInt(SCREEN_INDEX); @@ -819,7 +694,7 @@ public class LauncherBackupHelper implements BackupHelper { favorite.intent = intent.toUri(0); } catch (URISyntaxException e) { Log.e(TAG, "Invalid intent", e); - } + } } favorite.itemType = c.getInt(ITEM_TYPE_INDEX); if (favorite.itemType == Favorites.ITEM_TYPE_APPWIDGET) { @@ -830,16 +705,13 @@ public class LauncherBackupHelper implements BackupHelper { } } - return writeCheckedBytes(favorite); + return favorite; } /** Deserialize a Favorite from persistence, after verifying checksum wrapper. */ - private ContentValues unpackFavorite(byte[] buffer, int offset, int dataSize) + private ContentValues unpackFavorite(byte[] buffer, int dataSize) throws InvalidProtocolBufferNanoException { - Favorite favorite = new Favorite(); - MessageNano.mergeFrom(favorite, readCheckedBytes(buffer, offset, dataSize)); - if (VERBOSE) Log.v(TAG, "unpacked favorite " + favorite.itemType + ", " + - (TextUtils.isEmpty(favorite.title) ? favorite.id : favorite.title)); + Favorite favorite = unpackProto(new Favorite(), buffer, dataSize); ContentValues values = new ContentValues(); values.put(Favorites._ID, favorite.id); values.put(Favorites.SCREEN, favorite.screen); @@ -889,20 +761,17 @@ public class LauncherBackupHelper implements BackupHelper { } /** Serialize a Screen for persistence, including a checksum wrapper. */ - private byte[] packScreen(Cursor c) { + private Screen packScreen(Cursor c) { Screen screen = new Screen(); screen.id = c.getLong(ID_INDEX); screen.rank = c.getInt(SCREEN_RANK_INDEX); - - return writeCheckedBytes(screen); + return screen; } /** Deserialize a Screen from persistence, after verifying checksum wrapper. */ - private ContentValues unpackScreen(byte[] buffer, int offset, int dataSize) + private ContentValues unpackScreen(byte[] buffer, int dataSize) throws InvalidProtocolBufferNanoException { - Screen screen = new Screen(); - MessageNano.mergeFrom(screen, readCheckedBytes(buffer, offset, dataSize)); - if (VERBOSE) Log.v(TAG, "unpacked screen " + screen.id + "/" + screen.rank); + Screen screen = unpackProto(new Screen(), buffer, dataSize); ContentValues values = new ContentValues(); values.put(WorkspaceScreens._ID, screen.id); values.put(WorkspaceScreens.SCREEN_RANK, screen.rank); @@ -910,27 +779,18 @@ public class LauncherBackupHelper implements BackupHelper { } /** Serialize an icon Resource for persistence, including a checksum wrapper. */ - private byte[] packIcon(int dpi, Bitmap icon) { + private Resource packIcon(int dpi, Bitmap icon) { Resource res = new Resource(); res.dpi = dpi; ByteArrayOutputStream os = new ByteArrayOutputStream(); if (icon.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) { res.data = os.toByteArray(); } - return writeCheckedBytes(res); - } - - /** Deserialize an icon resource from persistence, after verifying checksum wrapper. */ - private static Resource unpackIcon(byte[] buffer, int offset, int dataSize) - throws InvalidProtocolBufferNanoException { - Resource res = new Resource(); - MessageNano.mergeFrom(res, readCheckedBytes(buffer, offset, dataSize)); - if (VERBOSE) Log.v(TAG, "unpacked icon " + res.dpi + "/" + res.data.length); return res; } /** Serialize a widget for persistence, including a checksum wrapper. */ - private byte[] packWidget(int dpi, WidgetPreviewLoader previewLoader, IconCache iconCache, + private Widget packWidget(int dpi, WidgetPreviewLoader previewLoader, IconCache iconCache, ComponentName provider) { final AppWidgetProviderInfo info = findAppWidgetProviderInfo(provider); Widget widget = new Widget(); @@ -956,16 +816,17 @@ public class LauncherBackupHelper implements BackupHelper { widget.preview.dpi = dpi; } } - return writeCheckedBytes(widget); + return widget; } - /** Deserialize a widget from persistence, after verifying checksum wrapper. */ - private Widget unpackWidget(byte[] buffer, int offset, int dataSize) + /** + * Deserialize a proto after verifying checksum wrapper. + */ + private T unpackProto(T proto, byte[] buffer, int dataSize) throws InvalidProtocolBufferNanoException { - Widget widget = new Widget(); - MessageNano.mergeFrom(widget, readCheckedBytes(buffer, offset, dataSize)); - if (VERBOSE) Log.v(TAG, "unpacked widget " + widget.provider); - return widget; + MessageNano.mergeFrom(proto, readCheckedBytes(buffer, dataSize)); + if (DEBUG) Log.d(TAG, "unpacked proto " + proto); + return proto; } /** @@ -1001,9 +862,6 @@ public class LauncherBackupHelper implements BackupHelper { if (result > 0) { availableBytes -= result; bytesRead += result; - if (DEBUG && (bytesRead % 100 == 0)) { - Log.d(TAG, "read some bytes: " + bytesRead); - } } else { Log.w(TAG, "unexpected end of file while reading journal."); // stop reading and see what there is to parse @@ -1016,7 +874,7 @@ public class LauncherBackupHelper implements BackupHelper { // check the buffer to see if we have a valid journal try { - MessageNano.mergeFrom(journal, readCheckedBytes(buffer, 0, bytesRead)); + MessageNano.mergeFrom(journal, readCheckedBytes(buffer, bytesRead)); // if we are here, then we have read a valid, checksum-verified journal valid = true; availableBytes = 0; @@ -1044,46 +902,18 @@ public class LauncherBackupHelper implements BackupHelper { return journal; } - private void writeRowToBackup(Key key, byte[] blob, Journal out, - BackupDataOutput data) throws IOException { - String backupKey = keyToBackupKey(key); - data.writeEntityHeader(backupKey, blob.length); - data.writeEntityData(blob, blob.length); - out.rows++; - out.bytes += blob.length; - if (VERBOSE) Log.v(TAG, "saving " + geKeyType(key) + " " + backupKey + ": " + - getKeyName(key) + "/" + blob.length); - if(DEBUG_PAYLOAD) { - String encoded = Base64.encodeToString(blob, 0, blob.length, Base64.NO_WRAP); - final int chunkSize = 1024; - for (int offset = 0; offset < encoded.length(); offset += chunkSize) { - int end = offset + chunkSize; - end = Math.min(end, encoded.length()); - Log.w(TAG, "wrote " + encoded.substring(offset, end)); - } - } - } - private Set getSavedIdsByType(int type, Journal in) { - Set savedIds = new HashSet(); - for(int i = 0; i < in.key.length; i++) { - Key key = in.key[i]; - if (key.type == type) { - savedIds.add(keyToBackupKey(key)); - } - } - return savedIds; + private void writeRowToBackup(Key key, MessageNano proto, BackupDataOutput data) + throws IOException { + writeRowToBackup(keyToBackupKey(key), proto, data); } - private int removeDeletedKeysFromBackup(Set deletedIds, BackupDataOutput data) - throws IOException { - int rows = 0; - for(String deleted: deletedIds) { - if (VERBOSE) Log.v(TAG, "dropping deleted item " + deleted); - data.writeEntityHeader(deleted, -1); - rows++; - } - return rows; + private void writeRowToBackup(String backupKey, MessageNano proto, + BackupDataOutput data) throws IOException { + byte[] blob = writeCheckedBytes(proto); + data.writeEntityHeader(backupKey, blob.length); + data.writeEntityData(blob, blob.length); + if (VERBOSE) Log.v(TAG, "Writing New entry " + backupKey); } /** @@ -1119,10 +949,10 @@ public class LauncherBackupHelper implements BackupHelper { } /** Unwrap a proto message from a CheckedMessage, verifying the checksum. */ - private static byte[] readCheckedBytes(byte[] buffer, int offset, int dataSize) + private static byte[] readCheckedBytes(byte[] buffer, int dataSize) throws InvalidProtocolBufferNanoException { CheckedMessage wrapper = new CheckedMessage(); - MessageNano.mergeFrom(wrapper, buffer, offset, dataSize); + MessageNano.mergeFrom(wrapper, buffer, 0, dataSize); CRC32 checksum = new CRC32(); checksum.update(wrapper.payload); if (wrapper.checksum != checksum.getValue()) { @@ -1161,7 +991,9 @@ public class LauncherBackupHelper implements BackupHelper { } - // check if the launcher is in a state to support backup + /** + * @return true if the launcher is in a state to support backup + */ private boolean launcherIsReady() { ContentResolver cr = mContext.getContentResolver(); Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION, null, null, null); @@ -1185,7 +1017,7 @@ public class LauncherBackupHelper implements BackupHelper { .getSerialNumberForUser(UserHandleCompat.myUserHandle()); } - private class KeyParsingException extends Throwable { + private class KeyParsingException extends IOException { private KeyParsingException(Throwable cause) { super(cause); } -- cgit v1.2.3