summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/LauncherBackupHelper.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher3/LauncherBackupHelper.java')
-rw-r--r--src/com/android/launcher3/LauncherBackupHelper.java612
1 files 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<String> mExistingKeys;
+ private final ArrayList<Key> mKeys;
- private final boolean mRestoreEnabled;
-
+ private IconCache mIconCache;
+ private BackupManager mBackupManager;
private HashMap<ComponentName, AppWidgetProviderInfo> mWidgetMap;
-
- private final ArrayList<Key> mKeys;
+ private byte[] mBuffer = new byte[512];
+ private long mLastBackupRestoreTime;
public LauncherBackupHelper(Context context, boolean restoreEnabled) {
mContext = context;
- mRestoreEnabled = restoreEnabled;
+ mExistingKeys = new HashSet<String>();
mKeys = new ArrayList<Key>();
}
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<String> validKeys = new HashSet<String>();
+ for (Key key : mKeys) {
+ validKeys.add(keyToBackupKey(key));
+ }
+ mExistingKeys.removeAll(validKeys);
- ArrayList<Key> keys = new ArrayList<Key>();
- 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<Key> keys)
- throws IOException {
- // read the old ID set
- Set<String> 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<String> currentIds = new HashSet<String>(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<Key> 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<Key> keys)
- throws IOException {
- // read the old ID set
- Set<String> 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<String> currentIds = new HashSet<String>(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<Key> 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<Key> 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<String> 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<String> currentIds = new HashSet<String>(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<Key> 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<Key> 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<String> 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<String> currentIds = new HashSet<String>(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<Key> 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 extends MessageNano> 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<String> getSavedIdsByType(int type, Journal in) {
- Set<String> savedIds = new HashSet<String>();
- 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<String> 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);
}