summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/launcher3/LauncherBackupAgentHelper.java46
-rw-r--r--src/com/android/launcher3/LauncherBackupHelper.java (renamed from src/com/android/launcher3/LauncherBackupAgent.java)254
-rw-r--r--src/com/android/launcher3/LauncherProvider.java2
-rw-r--r--util/com/android/launcher3/DecoderRing.java20
4 files changed, 199 insertions, 123 deletions
diff --git a/src/com/android/launcher3/LauncherBackupAgentHelper.java b/src/com/android/launcher3/LauncherBackupAgentHelper.java
new file mode 100644
index 0000000..2b5059b
--- /dev/null
+++ b/src/com/android/launcher3/LauncherBackupAgentHelper.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3;
+
+import android.app.backup.BackupAgentHelper;
+import android.app.backup.BackupManager;
+import android.content.Context;
+
+public class LauncherBackupAgentHelper extends BackupAgentHelper {
+
+ private static BackupManager sBackupManager;
+
+ /**
+ * Notify the backup manager that out database is dirty.
+ *
+ * <P>This does not force an immediate backup.
+ *
+ * @param context application context
+ */
+ public static void dataChanged(Context context) {
+ if (sBackupManager == null) {
+ sBackupManager = new BackupManager(context);
+ }
+ sBackupManager.dataChanged();
+ }
+
+
+ @Override
+ public void onCreate() {
+ addHelper(LauncherBackupHelper.LAUNCHER_PREFIX, new LauncherBackupHelper(this));
+ }
+}
diff --git a/src/com/android/launcher3/LauncherBackupAgent.java b/src/com/android/launcher3/LauncherBackupHelper.java
index f40238c..9b901ee 100644
--- a/src/com/android/launcher3/LauncherBackupAgent.java
+++ b/src/com/android/launcher3/LauncherBackupHelper.java
@@ -30,7 +30,8 @@ import com.android.launcher3.backup.BackupProtos.Resource;
import com.android.launcher3.backup.BackupProtos.Screen;
import com.android.launcher3.backup.BackupProtos.Widget;
-import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInputStream;
+import android.app.backup.BackupHelper;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupManager;
@@ -64,10 +65,11 @@ import java.util.zip.CRC32;
/**
* Persist the launcher home state across calamities.
*/
-public class LauncherBackupAgent extends BackupAgent {
+public class LauncherBackupHelper implements BackupHelper {
- private static final String TAG = "LauncherBackupAgent";
+ private static final String TAG = "LauncherBackupHelper";
private static final boolean DEBUG = false;
+ private static final boolean DEBUG_PAYLOAD = false;
private static final int MAX_JOURNAL_SIZE = 1000000;
@@ -79,6 +81,8 @@ public class LauncherBackupAgent extends BackupAgent {
public static final int IMAGE_COMPRESSION_QUALITY = 75;
+ public static final String LAUNCHER_PREFIX = "L";
+
private static final Bitmap.CompressFormat IMAGE_FORMAT =
android.graphics.Bitmap.CompressFormat.PNG;
@@ -130,26 +134,19 @@ public class LauncherBackupAgent extends BackupAgent {
private static final int SCREEN_RANK_INDEX = 2;
-
- private static final String[] ICON_PROJECTION = {
- Favorites._ID, // 0
- Favorites.MODIFIED, // 1
- Favorites.INTENT // 2
- };
+ private final Context mContext;
private HashMap<ComponentName, AppWidgetProviderInfo> mWidgetMap;
+ private ArrayList<Key> mKeys;
- /**
- * Notify the backup manager that out database is dirty.
- *
- * <P>This does not force an immediate backup.
- *
- * @param context application context
- */
- public static void dataChanged(Context context) {
+ public LauncherBackupHelper(Context context) {
+ mContext = context;
+ }
+
+ private void dataChanged() {
if (sBackupManager == null) {
- sBackupManager = new BackupManager(context);
+ sBackupManager = new BackupManager(mContext);
}
sBackupManager.dataChanged();
}
@@ -167,9 +164,8 @@ public class LauncherBackupAgent extends BackupAgent {
* @throws IOException
*/
@Override
- public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
- ParcelFileDescriptor newState)
- throws IOException {
+ public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) {
Log.v(TAG, "onBackup");
Journal in = readJournal(oldState);
@@ -183,10 +179,14 @@ public class LauncherBackupAgent extends BackupAgent {
Log.v(TAG, "lastBackupTime=" + lastBackupTime);
ArrayList<Key> keys = new ArrayList<Key>();
- backupFavorites(in, data, out, keys);
- backupScreens(in, data, out, keys);
- backupIcons(in, data, out, keys);
- backupWidgets(in, data, out, keys);
+ 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);
+ }
out.key = keys.toArray(BackupProtos.Key.EMPTY_ARRAY);
writeJournal(newState, out);
@@ -194,70 +194,76 @@ public class LauncherBackupAgent extends BackupAgent {
}
/**
- * Restore home screen from the restored data stream.
+ * Restore launcher configuration from the restored data stream.
*
* <P>Keys may arrive in any order.
*
- * @param data the key/value pairs from the server
- * @param versionCode the version of the app that generated the data
- * @param newState notes for the next backup
- * @throws IOException
+ * @param data the key/value pair from the server
*/
@Override
- public void onRestore(BackupDataInput data, int versionCode, ParcelFileDescriptor newState)
- throws IOException {
- Log.v(TAG, "onRestore");
- int numRows = 0;
- Journal out = new Journal();
-
- ArrayList<Key> keys = new ArrayList<Key>();
+ public void restoreEntity(BackupDataInputStream data) {
+ Log.v(TAG, "restoreEntity");
+ if (mKeys == null) {
+ mKeys = new ArrayList<Key>();
+ }
byte[] buffer = new byte[512];
- while (data.readNextHeader()) {
- numRows++;
String backupKey = data.getKey();
- int dataSize = data.getDataSize();
+ int dataSize = data.size();
if (buffer.length < dataSize) {
buffer = new byte[dataSize];
}
Key key = null;
- int bytesRead = data.readEntityData(buffer, 0, dataSize);
- if (DEBUG) {
- Log.d(TAG, "read " + bytesRead + " of " + dataSize + " available");
- }
- try {
- key = backupKeyToKey(backupKey);
- switch (key.type) {
- case Key.FAVORITE:
- restoreFavorite(key, buffer, dataSize, keys);
- break;
-
- case Key.SCREEN:
- restoreScreen(key, buffer, dataSize, keys);
- break;
-
- case Key.ICON:
- restoreIcon(key, buffer, dataSize, keys);
- break;
-
- case Key.WIDGET:
- restoreWidget(key, buffer, dataSize, keys);
- break;
-
- default:
- Log.w(TAG, "unknown restore entity type: " + key.type);
- break;
- }
- } catch (KeyParsingException e) {
- Log.w(TAG, "ignoring unparsable backup key: " + backupKey);
+ int bytesRead = 0;
+ try {
+ bytesRead = data.read(buffer, 0, dataSize);
+ if (DEBUG) Log.d(TAG, "read " + bytesRead + " of " + dataSize + " available");
+ } catch (IOException e) {
+ Log.d(TAG, "failed to read entity from restore data", e);
+ }
+ try {
+ key = backupKeyToKey(backupKey);
+ switch (key.type) {
+ case Key.FAVORITE:
+ restoreFavorite(key, buffer, dataSize, mKeys);
+ break;
+
+ case Key.SCREEN:
+ restoreScreen(key, buffer, dataSize, mKeys);
+ break;
+
+ case Key.ICON:
+ restoreIcon(key, buffer, dataSize, mKeys);
+ break;
+
+ case Key.WIDGET:
+ restoreWidget(key, buffer, dataSize, mKeys);
+ break;
+
+ default:
+ Log.w(TAG, "unknown restore entity type: " + key.type);
+ break;
}
+ } catch (KeyParsingException e) {
+ Log.w(TAG, "ignoring unparsable backup key: " + backupKey);
}
+ }
+
+ /**
+ * Record the restore state for the next backup.
+ *
+ * @param newState notes about the backup state after restore.
+ */
+ @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 = keys.toArray(BackupProtos.Key.EMPTY_ARRAY);
+ out.key = mKeys.toArray(BackupProtos.Key.EMPTY_ARRAY);
writeJournal(newState, out);
- Log.v(TAG, "onRestore: read " + numRows + " rows");
+ Log.v(TAG, "onRestore: read " + mKeys.size() + " rows");
+ mKeys.clear();
}
/**
@@ -278,7 +284,7 @@ public class LauncherBackupAgent extends BackupAgent {
if (DEBUG) Log.d(TAG, "favorite savedIds.size()=" + savedIds.size());
// persist things that have changed since the last backup
- ContentResolver cr = getContentResolver();
+ ContentResolver cr = mContext.getContentResolver();
Cursor cursor = cr.query(Favorites.CONTENT_URI, FAVORITE_PROJECTION,
null, null, null);
Set<String> currentIds = new HashSet<String>(cursor.getCount());
@@ -346,7 +352,7 @@ public class LauncherBackupAgent extends BackupAgent {
if (DEBUG) Log.d(TAG, "screen savedIds.size()=" + savedIds.size());
// persist things that have changed since the last backup
- ContentResolver cr = getContentResolver();
+ ContentResolver cr = mContext.getContentResolver();
Cursor cursor = cr.query(WorkspaceScreens.CONTENT_URI, SCREEN_PROJECTION,
null, null, null);
Set<String> currentIds = new HashSet<String>(cursor.getCount());
@@ -408,15 +414,15 @@ public class LauncherBackupAgent extends BackupAgent {
private void backupIcons(Journal in, BackupDataOutput data, Journal out,
ArrayList<Key> keys) throws IOException {
// persist icons that haven't been persisted yet
- final LauncherAppState app = LauncherAppState.getInstanceNoCreate();
- if (app == null) {
- dataChanged(this); // try again later
+ final LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
+ if (appState == null) {
+ dataChanged(); // try again later
if (DEBUG) Log.d(TAG, "Launcher is not initialized, delaying icon backup");
return;
}
- final ContentResolver cr = getContentResolver();
- final IconCache iconCache = app.getIconCache();
- final int dpi = getResources().getDisplayMetrics().densityDpi;
+ final ContentResolver cr = mContext.getContentResolver();
+ final IconCache iconCache = appState.getIconCache();
+ final int dpi = mContext.getResources().getDisplayMetrics().densityDpi;
// read the old ID set
Set<String> savedIds = getSavedIdsByType(Key.ICON, in);
@@ -463,7 +469,7 @@ public class LauncherBackupAgent extends BackupAgent {
} else {
if (DEBUG) Log.d(TAG, "scheduling another run for icon " + backupKey);
// too many icons for this pass, request another.
- dataChanged(this);
+ dataChanged();
}
}
} catch (URISyntaxException e) {
@@ -527,15 +533,15 @@ public class LauncherBackupAgent extends BackupAgent {
// persist static widget info that hasn't been persisted yet
final LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
if (appState == null) {
- dataChanged(this); // try again later
+ dataChanged(); // try again later
if (DEBUG) Log.d(TAG, "Launcher is not initialized, delaying widget backup");
return;
}
- final ContentResolver cr = getContentResolver();
- final WidgetPreviewLoader previewLoader = new WidgetPreviewLoader(this);
- final PagedViewCellLayout widgetSpacingLayout = new PagedViewCellLayout(this);
+ final ContentResolver cr = mContext.getContentResolver();
+ final WidgetPreviewLoader previewLoader = new WidgetPreviewLoader(mContext);
+ final PagedViewCellLayout widgetSpacingLayout = new PagedViewCellLayout(mContext);
final IconCache iconCache = appState.getIconCache();
- final int dpi = getResources().getDisplayMetrics().densityDpi;
+ final int dpi = mContext.getResources().getDisplayMetrics().densityDpi;
final DeviceProfile profile = appState.getDynamicGrid().getDeviceProfile();
if (DEBUG) Log.d(TAG, "cellWidthPx: " + profile.cellWidthPx);
@@ -584,7 +590,7 @@ public class LauncherBackupAgent extends BackupAgent {
} else {
if (DEBUG) Log.d(TAG, "scheduling another run for widget " + backupKey);
// too many widgets for this pass, request another.
- dataChanged(this);
+ dataChanged();
}
}
}
@@ -812,7 +818,7 @@ public class LauncherBackupAgent extends BackupAgent {
if (info.icon != 0) {
widget.icon = new Resource();
Drawable fullResIcon = iconCache.getFullResIcon(provider.getPackageName(), info.icon);
- Bitmap icon = Utilities.createIconBitmap(fullResIcon, this);
+ Bitmap icon = Utilities.createIconBitmap(fullResIcon, mContext);
ByteArrayOutputStream os = new ByteArrayOutputStream();
if (icon.compress(IMAGE_FORMAT, IMAGE_COMPRESSION_QUALITY, os)) {
widget.icon.data = os.toByteArray();
@@ -849,43 +855,49 @@ public class LauncherBackupAgent extends BackupAgent {
* @return a Journal protocol bugffer
*/
private Journal readJournal(ParcelFileDescriptor oldState) {
- int fileSize = (int) oldState.getStatSize();
- int remaining = fileSize;
- byte[] buffer = null;
Journal journal = new Journal();
- if (remaining < MAX_JOURNAL_SIZE) {
- FileInputStream inStream = new FileInputStream(oldState.getFileDescriptor());
- int offset = 0;
-
- buffer = new byte[remaining];
- while (remaining > 0) {
+ if (oldState == null) {
+ return journal;
+ }
+ FileInputStream inStream = new FileInputStream(oldState.getFileDescriptor());
+ try {
+ int remaining = inStream.available();
+ if (DEBUG) Log.d(TAG, "available " + remaining);
+ if (remaining < MAX_JOURNAL_SIZE) {
+ byte[] buffer = new byte[remaining];
int bytesRead = 0;
- try {
- bytesRead = inStream.read(buffer, offset, remaining);
- } catch (IOException e) {
- Log.w(TAG, "failed to read the journal", e);
- buffer = null;
- remaining = 0;
- }
- if (bytesRead > 0) {
- remaining -= bytesRead;
- } else {
- // act like there is not journal
- Log.w(TAG, "failed to read the journal");
- buffer = null;
- remaining = 0;
+ while (remaining > 0) {
+ try {
+ int result = inStream.read(buffer, bytesRead, remaining);
+ if (result > 0) {
+ if (DEBUG) Log.d(TAG, "read some bytes: " + result);
+ remaining -= result;
+ bytesRead += result;
+ } else {
+ // stop reading ands see what there is to parse
+ Log.w(TAG, "read error: " + result);
+ remaining = 0;
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "failed to read the journal", e);
+ buffer = null;
+ remaining = 0;
+ }
}
- }
-
- if (buffer != null) {
- try {
- MessageNano.mergeFrom(journal, readCheckedBytes(buffer, 0, fileSize));
- } catch (InvalidProtocolBufferNanoException e) {
- Log.d(TAG, "failed to read the journal", e);
- journal.clear();
+ if (DEBUG) Log.d(TAG, "journal bytes read: " + bytesRead);
+
+ if (buffer != null) {
+ try {
+ MessageNano.mergeFrom(journal, readCheckedBytes(buffer, 0, bytesRead));
+ } catch (InvalidProtocolBufferNanoException e) {
+ Log.d(TAG, "failed to read the journal", e);
+ journal.clear();
+ }
}
}
-
+ } catch (IOException e) {
+ Log.d(TAG, "failed to close the journal", e);
+ } finally {
try {
inStream.close();
} catch (IOException e) {
@@ -904,7 +916,7 @@ public class LauncherBackupAgent extends BackupAgent {
out.bytes += blob.length;
Log.v(TAG, "saving " + geKeyType(key) + " " + backupKey + ": " +
getKeyName(key) + "/" + blob.length);
- if(DEBUG) {
+ 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) {
@@ -983,7 +995,7 @@ public class LauncherBackupAgent extends BackupAgent {
private AppWidgetProviderInfo findAppWidgetProviderInfo(ComponentName component) {
if (mWidgetMap == null) {
List<AppWidgetProviderInfo> widgets =
- AppWidgetManager.getInstance(this).getInstalledProviders();
+ AppWidgetManager.getInstance(mContext).getInstalledProviders();
mWidgetMap = new HashMap<ComponentName, AppWidgetProviderInfo>(widgets.size());
for (AppWidgetProviderInfo info : widgets) {
mWidgetMap.put(info.provider, info);
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 5a8f630..39afe10 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -210,7 +210,7 @@ public class LauncherProvider extends ContentProvider {
}
// always notify the backup agent
- LauncherBackupAgent.dataChanged(getContext());
+ LauncherBackupAgentHelper.dataChanged(getContext());
}
private void addModifiedTime(ContentValues values) {
diff --git a/util/com/android/launcher3/DecoderRing.java b/util/com/android/launcher3/DecoderRing.java
index b7349fe..1d9e0de 100644
--- a/util/com/android/launcher3/DecoderRing.java
+++ b/util/com/android/launcher3/DecoderRing.java
@@ -18,6 +18,7 @@ package com.android.launcher3;
import com.android.launcher3.backup.BackupProtos.CheckedMessage;
import com.android.launcher3.backup.BackupProtos.Favorite;
import com.android.launcher3.backup.BackupProtos.Key;
+import com.android.launcher3.backup.BackupProtos.Journal;
import com.android.launcher3.backup.BackupProtos.Resource;
import com.android.launcher3.backup.BackupProtos.Screen;
import com.android.launcher3.backup.BackupProtos.Widget;
@@ -49,17 +50,27 @@ class DecoderRing {
throws Exception {
File source = null;
Class type = Key.class;
+ int skip = 0;
+
for (int i = 0; i < args.length; i++) {
if ("-k".equals(args[i])) {
type = Key.class;
} else if ("-f".equals(args[i])) {
type = Favorite.class;
+ } else if ("-j".equals(args[i])) {
+ type = Journal.class;
} else if ("-i".equals(args[i])) {
type = Resource.class;
} else if ("-s".equals(args[i])) {
type = Screen.class;
} else if ("-w".equals(args[i])) {
type = Widget.class;
+ } else if ("-S".equals(args[i])) {
+ if ((i + 1) < args.length) {
+ skip = Integer.valueOf(args[++i]);
+ } else {
+ usage(args);
+ }
} else if (args[i] != null && !args[i].startsWith("-")) {
source = new File(args[i]);
} else {
@@ -86,8 +97,14 @@ class DecoderRing {
try {
while (input.available() > 0) {
int n = input.read(buffer);
+ int offset = 0;
+ if (skip > 0) {
+ offset = Math.min(skip, n);
+ n -= offset;
+ skip -= offset;
+ }
if (n > 0) {
- byteStream.write(buffer, 0, n);
+ byteStream.write(buffer, offset, n);
}
}
} catch (IOException e) {
@@ -190,6 +207,7 @@ class DecoderRing {
System.err.println("\t-i\tdecode a icon");
System.err.println("\t-s\tdecode a screen");
System.err.println("\t-w\tdecode a widget");
+ System.err.println("\t-s b\tskip b bytes");
System.err.println("\tfilename\tread from filename, not stdin");
System.exit(1);
}