Loading src/com/android/launcher3/AllAppsList.java +2 −3 Original line number Diff line number Diff line Loading @@ -115,8 +115,7 @@ class AllAppsList { data.remove(i); } } // This is more aggressive than it needs to be. mIconCache.flush(); mIconCache.remove(packageName); } /** Loading src/com/android/launcher3/IconCache.java +199 −14 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.launcher3; import com.android.launcher3.backup.BackupProtos; import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; Loading @@ -25,10 +27,20 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.util.Log; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map.Entry; Loading @@ -40,6 +52,9 @@ public class IconCache { private static final String TAG = "Launcher.IconCache"; private static final int INITIAL_ICON_CACHE_CAPACITY = 50; private static final String RESOURCE_FILE_PREFIX = "icon_"; private static final boolean DEBUG = true; private static class CacheEntry { public Bitmap icon; Loading Loading @@ -115,6 +130,7 @@ public class IconCache { return getFullResIcon(resources, iconId); } } return getFullResDefaultActivityIcon(); } Loading @@ -139,6 +155,21 @@ public class IconCache { } } /** * Remove any records for the supplied package name. */ public void remove(String packageName) { HashSet<ComponentName> forDeletion = new HashSet<ComponentName>(); for (ComponentName componentName: mCache.keySet()) { if (componentName.getPackageName().equals(packageName)) { forDeletion.add(componentName); } } for (ComponentName condemned: forDeletion) { remove(condemned); } } /** * Empty out the cache. */ Loading Loading @@ -177,15 +208,22 @@ public class IconCache { } public Bitmap getIcon(Intent intent) { return getIcon(intent, null); } public Bitmap getIcon(Intent intent, String title) { synchronized (mCache) { final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0); ComponentName component = intent.getComponent(); if (resolveInfo == null || component == null) { if (component == null) { return mDefaultIcon; } CacheEntry entry = cacheLocked(component, resolveInfo, null); if (title != null) { entry.title = title; } return entry.icon; } } Loading Loading @@ -214,6 +252,7 @@ public class IconCache { mCache.put(componentName, entry); if (info != null) { ComponentName key = LauncherModel.getComponentNameFromResolveInfo(info); if (labelCache != null && labelCache.containsKey(key)) { entry.title = labelCache.get(key).toString(); Loading @@ -229,6 +268,19 @@ public class IconCache { entry.icon = Utilities.createIconBitmap( getFullResIcon(info), mContext); } else { entry.title = ""; Bitmap preloaded = getPreloadedIcon(componentName); if (preloaded != null) { if (DEBUG) Log.d(TAG, "using preloaded icon for " + componentName.toShortString()); entry.icon = preloaded; } else { if (DEBUG) Log.d(TAG, "using default icon for " + componentName.toShortString()); entry.icon = mDefaultIcon; } } } return entry; } Loading @@ -243,4 +295,137 @@ public class IconCache { return set; } } /** * Pre-load an icon into the persistent cache. * * <P>Queries for a component that does not exist in the package manager * will be answered by the persistent cache. * * @param context application context * @param componentName the icon should be returned for this component * @param icon the icon to be persisted * @param dpi the native density of the icon */ public static void preloadIcon(Context context, ComponentName componentName, Bitmap icon, int dpi) { // TODO rescale to the correct native DPI try { PackageManager packageManager = context.getPackageManager(); packageManager.getActivityIcon(componentName); // component is present on the system already, do nothing return; } catch (PackageManager.NameNotFoundException e) { // pass } final String key = componentName.flattenToString(); FileOutputStream resourceFile = null; try { resourceFile = context.openFileOutput(getResourceFilename(componentName), Context.MODE_PRIVATE); ByteArrayOutputStream os = new ByteArrayOutputStream(); if (icon.compress(android.graphics.Bitmap.CompressFormat.PNG, 75, os)) { byte[] buffer = os.toByteArray(); resourceFile.write(buffer, 0, buffer.length); } else { Log.w(TAG, "failed to encode cache for " + key); return; } } catch (FileNotFoundException e) { Log.w(TAG, "failed to pre-load cache for " + key, e); } catch (IOException e) { Log.w(TAG, "failed to pre-load cache for " + key, e); } finally { if (resourceFile != null) { try { resourceFile.close(); } catch (IOException e) { Log.d(TAG, "failed to save restored icon for: " + key, e); } } } } /** * Read a pre-loaded icon from the persistent icon cache. * * @param componentName the component that should own the icon * @returns a bitmap if one is cached, or null. */ private Bitmap getPreloadedIcon(ComponentName componentName) { final String key = componentName.flattenToShortString(); if (DEBUG) Log.v(TAG, "looking for pre-load icon for " + key); Bitmap icon = null; FileInputStream resourceFile = null; try { resourceFile = mContext.openFileInput(getResourceFilename(componentName)); byte[] buffer = new byte[1024]; ByteArrayOutputStream bytes = new ByteArrayOutputStream(); int bytesRead = 0; while(bytesRead >= 0) { bytes.write(buffer, 0, bytesRead); bytesRead = resourceFile.read(buffer, 0, buffer.length); } if (DEBUG) Log.d(TAG, "read " + bytes.size()); icon = BitmapFactory.decodeByteArray(bytes.toByteArray(), 0, bytes.size()); if (icon == null) { Log.w(TAG, "failed to decode pre-load icon for " + key); } } catch (FileNotFoundException e) { if (DEBUG) Log.d(TAG, "there is no restored icon for: " + key, e); } catch (IOException e) { Log.w(TAG, "failed to read pre-load icon for: " + key, e); } finally { if(resourceFile != null) { try { resourceFile.close(); } catch (IOException e) { Log.d(TAG, "failed to manage pre-load icon file: " + key, e); } } } if (icon != null) { // TODO: handle alpha mask in the view layer Bitmap b = Bitmap.createBitmap(Math.max(icon.getWidth(), 1), Math.max(icon.getHeight(), 1), Bitmap.Config.ARGB_8888); Canvas c = new Canvas(b); Paint paint = new Paint(); paint.setAlpha(127); c.drawBitmap(icon, 0, 0, paint); c.setBitmap(null); icon.recycle(); icon = b; } return icon; } /** * Remove a pre-loaded icon from the persistent icon cache. * * @param componentName the component that should own the icon * @returns true on success */ public boolean deletePreloadedIcon(ComponentName componentName) { if (componentName == null) { return false; } if (mCache.remove(componentName) != null) { if (DEBUG) Log.d(TAG, "removed pre-loaded icon from the in-memory cache"); } boolean success = mContext.deleteFile(getResourceFilename(componentName)); if (DEBUG && success) Log.d(TAG, "removed pre-loaded icon from persistent cache"); return success; } private static String getResourceFilename(ComponentName component) { String resourceName = component.flattenToShortString(); String filename = resourceName.replace(File.separatorChar, '_'); return RESOURCE_FILE_PREFIX + filename; } } src/com/android/launcher3/LauncherBackupHelper.java +45 −20 Original line number Diff line number Diff line Loading @@ -50,7 +50,9 @@ import android.util.Base64; import android.util.Log; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.URISyntaxException; Loading Loading @@ -136,6 +138,8 @@ public class LauncherBackupHelper implements BackupHelper { private static final int SCREEN_RANK_INDEX = 2; private static IconCache mIconCache; private final Context mContext; private final boolean mRestoreEnabled; Loading Loading @@ -441,14 +445,12 @@ public class LauncherBackupHelper implements BackupHelper { private void backupIcons(Journal in, BackupDataOutput data, Journal out, ArrayList<Key> keys) throws IOException { // persist icons that haven't been persisted yet final LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); if (appState == null) { if (!initializeIconCache()) { dataChanged(); // try again later if (DEBUG) Log.d(TAG, "Launcher is not initialized, delaying icon backup"); return; } final ContentResolver cr = mContext.getContentResolver(); final IconCache iconCache = appState.getIconCache(); final int dpi = mContext.getResources().getDisplayMetrics().densityDpi; // read the old ID set Loading Loading @@ -487,9 +489,9 @@ public class LauncherBackupHelper implements BackupHelper { 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); Bitmap icon = iconCache.getIcon(intent); Bitmap icon = mIconCache.getIcon(intent); keys.add(key); if (icon != null && !iconCache.isDefaultIcon(icon)) { if (icon != null && !mIconCache.isDefaultIcon(icon)) { byte[] blob = packIcon(dpi, icon); writeRowToBackup(key, blob, out, data); } Loading Loading @@ -530,25 +532,33 @@ public class LauncherBackupHelper implements BackupHelper { 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 " + 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"); if (VERBOSE) { Log.v(TAG, "restore not enabled: skipping database mutation"); } return; } else { // future site of icon cache mutation IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(key.name), icon, res.dpi); } } catch (InvalidProtocolBufferNanoException e) { Log.e(TAG, "failed to decode icon", e); } catch (IOException e) { Log.d(TAG, "failed to save restored icon for: " + key.name, e); } } Loading @@ -566,15 +576,13 @@ public class LauncherBackupHelper implements BackupHelper { ArrayList<Key> keys) throws IOException { // persist static widget info that hasn't been persisted yet final LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); if (appState == null) { dataChanged(); // try again later if (DEBUG) Log.d(TAG, "Launcher is not initialized, delaying widget backup"); if (appState == null || !initializeIconCache()) { Log.w(TAG, "Failed to get icon cache during restore"); return; } 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 = mContext.getResources().getDisplayMetrics().densityDpi; final DeviceProfile profile = appState.getDynamicGrid().getDeviceProfile(); if (DEBUG) Log.d(TAG, "cellWidthPx: " + profile.cellWidthPx); Loading Loading @@ -617,7 +625,7 @@ public class LauncherBackupHelper implements BackupHelper { if (VERBOSE) Log.v(TAG, "saving widget " + backupKey); previewLoader.setPreviewSize(spanX * profile.cellWidthPx, spanY * profile.cellHeightPx, widgetSpacingLayout); byte[] blob = packWidget(dpi, previewLoader, iconCache, provider); byte[] blob = packWidget(dpi, previewLoader, mIconCache, provider); keys.add(key); writeRowToBackup(key, blob, out, data); Loading Loading @@ -882,7 +890,7 @@ public class LauncherBackupHelper implements BackupHelper { } /** Deserialize an icon resource from persistence, after verifying checksum wrapper. */ private Resource unpackIcon(byte[] buffer, int offset, int dataSize) private static Resource unpackIcon(byte[] buffer, int offset, int dataSize) throws InvalidProtocolBufferNanoException { Resource res = new Resource(); MessageNano.mergeFrom(res, readCheckedBytes(buffer, offset, dataSize)); Loading Loading @@ -1080,7 +1088,7 @@ public class LauncherBackupHelper implements BackupHelper { } /** Unwrap a proto message from a CheckedMessage, verifying the checksum. */ private byte[] readCheckedBytes(byte[] buffer, int offset, int dataSize) private static byte[] readCheckedBytes(byte[] buffer, int offset, int dataSize) throws InvalidProtocolBufferNanoException { CheckedMessage wrapper = new CheckedMessage(); MessageNano.mergeFrom(wrapper, buffer, offset, dataSize); Loading @@ -1104,6 +1112,23 @@ public class LauncherBackupHelper implements BackupHelper { return mWidgetMap.get(component); } private boolean initializeIconCache() { if (mIconCache != null) { return true; } final LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); if (appState == null) { Throwable stackTrace = new Throwable(); stackTrace.fillInStackTrace(); Log.w(TAG, "Failed to get app state during backup/restore", stackTrace); return false; } mIconCache = appState.getIconCache(); return mIconCache != null; } private class KeyParsingException extends Throwable { private KeyParsingException(Throwable cause) { super(cause); Loading src/com/android/launcher3/LauncherModel.java +9 −3 Original line number Diff line number Diff line Loading @@ -318,10 +318,16 @@ public class LauncherModel extends BroadcastReceiver { public void run() { Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; if (callbacks == cb && cb != null) { callbacks.bindAppsAdded(null, null, null, allAppsApps); if (!restoredAppsFinal.isEmpty()) { for (AppInfo info : restoredAppsFinal) { final Intent intent = info.getIntent(); if (intent != null) { mIconCache.deletePreloadedIcon(intent.getComponent()); } } callbacks.bindAppsUpdated(restoredAppsFinal); } callbacks.bindAppsAdded(null, null, null, allAppsApps); } } }); Loading Loading @@ -2667,6 +2673,7 @@ public class LauncherModel extends BroadcastReceiver { case OP_ADD: for (int i=0; i<N; i++) { if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]); mIconCache.remove(packages[i]); mBgAllAppsList.addPackage(context, packages[i]); } break; Loading Loading @@ -2862,13 +2869,12 @@ public class LauncherModel extends BroadcastReceiver { */ public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent) { final ShortcutInfo info = new ShortcutInfo(); info.usingFallbackIcon = true; info.setIcon(getFallbackIcon()); if (cursor != null) { info.title = cursor.getString(titleIndex); } else { info.title = ""; } info.setIcon(mIconCache.getIcon(intent, info.title.toString())); info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; info.restoredIntent = intent; return info; Loading Loading
src/com/android/launcher3/AllAppsList.java +2 −3 Original line number Diff line number Diff line Loading @@ -115,8 +115,7 @@ class AllAppsList { data.remove(i); } } // This is more aggressive than it needs to be. mIconCache.flush(); mIconCache.remove(packageName); } /** Loading
src/com/android/launcher3/IconCache.java +199 −14 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.launcher3; import com.android.launcher3.backup.BackupProtos; import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; Loading @@ -25,10 +27,20 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.util.Log; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map.Entry; Loading @@ -40,6 +52,9 @@ public class IconCache { private static final String TAG = "Launcher.IconCache"; private static final int INITIAL_ICON_CACHE_CAPACITY = 50; private static final String RESOURCE_FILE_PREFIX = "icon_"; private static final boolean DEBUG = true; private static class CacheEntry { public Bitmap icon; Loading Loading @@ -115,6 +130,7 @@ public class IconCache { return getFullResIcon(resources, iconId); } } return getFullResDefaultActivityIcon(); } Loading @@ -139,6 +155,21 @@ public class IconCache { } } /** * Remove any records for the supplied package name. */ public void remove(String packageName) { HashSet<ComponentName> forDeletion = new HashSet<ComponentName>(); for (ComponentName componentName: mCache.keySet()) { if (componentName.getPackageName().equals(packageName)) { forDeletion.add(componentName); } } for (ComponentName condemned: forDeletion) { remove(condemned); } } /** * Empty out the cache. */ Loading Loading @@ -177,15 +208,22 @@ public class IconCache { } public Bitmap getIcon(Intent intent) { return getIcon(intent, null); } public Bitmap getIcon(Intent intent, String title) { synchronized (mCache) { final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0); ComponentName component = intent.getComponent(); if (resolveInfo == null || component == null) { if (component == null) { return mDefaultIcon; } CacheEntry entry = cacheLocked(component, resolveInfo, null); if (title != null) { entry.title = title; } return entry.icon; } } Loading Loading @@ -214,6 +252,7 @@ public class IconCache { mCache.put(componentName, entry); if (info != null) { ComponentName key = LauncherModel.getComponentNameFromResolveInfo(info); if (labelCache != null && labelCache.containsKey(key)) { entry.title = labelCache.get(key).toString(); Loading @@ -229,6 +268,19 @@ public class IconCache { entry.icon = Utilities.createIconBitmap( getFullResIcon(info), mContext); } else { entry.title = ""; Bitmap preloaded = getPreloadedIcon(componentName); if (preloaded != null) { if (DEBUG) Log.d(TAG, "using preloaded icon for " + componentName.toShortString()); entry.icon = preloaded; } else { if (DEBUG) Log.d(TAG, "using default icon for " + componentName.toShortString()); entry.icon = mDefaultIcon; } } } return entry; } Loading @@ -243,4 +295,137 @@ public class IconCache { return set; } } /** * Pre-load an icon into the persistent cache. * * <P>Queries for a component that does not exist in the package manager * will be answered by the persistent cache. * * @param context application context * @param componentName the icon should be returned for this component * @param icon the icon to be persisted * @param dpi the native density of the icon */ public static void preloadIcon(Context context, ComponentName componentName, Bitmap icon, int dpi) { // TODO rescale to the correct native DPI try { PackageManager packageManager = context.getPackageManager(); packageManager.getActivityIcon(componentName); // component is present on the system already, do nothing return; } catch (PackageManager.NameNotFoundException e) { // pass } final String key = componentName.flattenToString(); FileOutputStream resourceFile = null; try { resourceFile = context.openFileOutput(getResourceFilename(componentName), Context.MODE_PRIVATE); ByteArrayOutputStream os = new ByteArrayOutputStream(); if (icon.compress(android.graphics.Bitmap.CompressFormat.PNG, 75, os)) { byte[] buffer = os.toByteArray(); resourceFile.write(buffer, 0, buffer.length); } else { Log.w(TAG, "failed to encode cache for " + key); return; } } catch (FileNotFoundException e) { Log.w(TAG, "failed to pre-load cache for " + key, e); } catch (IOException e) { Log.w(TAG, "failed to pre-load cache for " + key, e); } finally { if (resourceFile != null) { try { resourceFile.close(); } catch (IOException e) { Log.d(TAG, "failed to save restored icon for: " + key, e); } } } } /** * Read a pre-loaded icon from the persistent icon cache. * * @param componentName the component that should own the icon * @returns a bitmap if one is cached, or null. */ private Bitmap getPreloadedIcon(ComponentName componentName) { final String key = componentName.flattenToShortString(); if (DEBUG) Log.v(TAG, "looking for pre-load icon for " + key); Bitmap icon = null; FileInputStream resourceFile = null; try { resourceFile = mContext.openFileInput(getResourceFilename(componentName)); byte[] buffer = new byte[1024]; ByteArrayOutputStream bytes = new ByteArrayOutputStream(); int bytesRead = 0; while(bytesRead >= 0) { bytes.write(buffer, 0, bytesRead); bytesRead = resourceFile.read(buffer, 0, buffer.length); } if (DEBUG) Log.d(TAG, "read " + bytes.size()); icon = BitmapFactory.decodeByteArray(bytes.toByteArray(), 0, bytes.size()); if (icon == null) { Log.w(TAG, "failed to decode pre-load icon for " + key); } } catch (FileNotFoundException e) { if (DEBUG) Log.d(TAG, "there is no restored icon for: " + key, e); } catch (IOException e) { Log.w(TAG, "failed to read pre-load icon for: " + key, e); } finally { if(resourceFile != null) { try { resourceFile.close(); } catch (IOException e) { Log.d(TAG, "failed to manage pre-load icon file: " + key, e); } } } if (icon != null) { // TODO: handle alpha mask in the view layer Bitmap b = Bitmap.createBitmap(Math.max(icon.getWidth(), 1), Math.max(icon.getHeight(), 1), Bitmap.Config.ARGB_8888); Canvas c = new Canvas(b); Paint paint = new Paint(); paint.setAlpha(127); c.drawBitmap(icon, 0, 0, paint); c.setBitmap(null); icon.recycle(); icon = b; } return icon; } /** * Remove a pre-loaded icon from the persistent icon cache. * * @param componentName the component that should own the icon * @returns true on success */ public boolean deletePreloadedIcon(ComponentName componentName) { if (componentName == null) { return false; } if (mCache.remove(componentName) != null) { if (DEBUG) Log.d(TAG, "removed pre-loaded icon from the in-memory cache"); } boolean success = mContext.deleteFile(getResourceFilename(componentName)); if (DEBUG && success) Log.d(TAG, "removed pre-loaded icon from persistent cache"); return success; } private static String getResourceFilename(ComponentName component) { String resourceName = component.flattenToShortString(); String filename = resourceName.replace(File.separatorChar, '_'); return RESOURCE_FILE_PREFIX + filename; } }
src/com/android/launcher3/LauncherBackupHelper.java +45 −20 Original line number Diff line number Diff line Loading @@ -50,7 +50,9 @@ import android.util.Base64; import android.util.Log; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.net.URISyntaxException; Loading Loading @@ -136,6 +138,8 @@ public class LauncherBackupHelper implements BackupHelper { private static final int SCREEN_RANK_INDEX = 2; private static IconCache mIconCache; private final Context mContext; private final boolean mRestoreEnabled; Loading Loading @@ -441,14 +445,12 @@ public class LauncherBackupHelper implements BackupHelper { private void backupIcons(Journal in, BackupDataOutput data, Journal out, ArrayList<Key> keys) throws IOException { // persist icons that haven't been persisted yet final LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); if (appState == null) { if (!initializeIconCache()) { dataChanged(); // try again later if (DEBUG) Log.d(TAG, "Launcher is not initialized, delaying icon backup"); return; } final ContentResolver cr = mContext.getContentResolver(); final IconCache iconCache = appState.getIconCache(); final int dpi = mContext.getResources().getDisplayMetrics().densityDpi; // read the old ID set Loading Loading @@ -487,9 +489,9 @@ public class LauncherBackupHelper implements BackupHelper { 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); Bitmap icon = iconCache.getIcon(intent); Bitmap icon = mIconCache.getIcon(intent); keys.add(key); if (icon != null && !iconCache.isDefaultIcon(icon)) { if (icon != null && !mIconCache.isDefaultIcon(icon)) { byte[] blob = packIcon(dpi, icon); writeRowToBackup(key, blob, out, data); } Loading Loading @@ -530,25 +532,33 @@ public class LauncherBackupHelper implements BackupHelper { 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 " + 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"); if (VERBOSE) { Log.v(TAG, "restore not enabled: skipping database mutation"); } return; } else { // future site of icon cache mutation IconCache.preloadIcon(mContext, ComponentName.unflattenFromString(key.name), icon, res.dpi); } } catch (InvalidProtocolBufferNanoException e) { Log.e(TAG, "failed to decode icon", e); } catch (IOException e) { Log.d(TAG, "failed to save restored icon for: " + key.name, e); } } Loading @@ -566,15 +576,13 @@ public class LauncherBackupHelper implements BackupHelper { ArrayList<Key> keys) throws IOException { // persist static widget info that hasn't been persisted yet final LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); if (appState == null) { dataChanged(); // try again later if (DEBUG) Log.d(TAG, "Launcher is not initialized, delaying widget backup"); if (appState == null || !initializeIconCache()) { Log.w(TAG, "Failed to get icon cache during restore"); return; } 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 = mContext.getResources().getDisplayMetrics().densityDpi; final DeviceProfile profile = appState.getDynamicGrid().getDeviceProfile(); if (DEBUG) Log.d(TAG, "cellWidthPx: " + profile.cellWidthPx); Loading Loading @@ -617,7 +625,7 @@ public class LauncherBackupHelper implements BackupHelper { if (VERBOSE) Log.v(TAG, "saving widget " + backupKey); previewLoader.setPreviewSize(spanX * profile.cellWidthPx, spanY * profile.cellHeightPx, widgetSpacingLayout); byte[] blob = packWidget(dpi, previewLoader, iconCache, provider); byte[] blob = packWidget(dpi, previewLoader, mIconCache, provider); keys.add(key); writeRowToBackup(key, blob, out, data); Loading Loading @@ -882,7 +890,7 @@ public class LauncherBackupHelper implements BackupHelper { } /** Deserialize an icon resource from persistence, after verifying checksum wrapper. */ private Resource unpackIcon(byte[] buffer, int offset, int dataSize) private static Resource unpackIcon(byte[] buffer, int offset, int dataSize) throws InvalidProtocolBufferNanoException { Resource res = new Resource(); MessageNano.mergeFrom(res, readCheckedBytes(buffer, offset, dataSize)); Loading Loading @@ -1080,7 +1088,7 @@ public class LauncherBackupHelper implements BackupHelper { } /** Unwrap a proto message from a CheckedMessage, verifying the checksum. */ private byte[] readCheckedBytes(byte[] buffer, int offset, int dataSize) private static byte[] readCheckedBytes(byte[] buffer, int offset, int dataSize) throws InvalidProtocolBufferNanoException { CheckedMessage wrapper = new CheckedMessage(); MessageNano.mergeFrom(wrapper, buffer, offset, dataSize); Loading @@ -1104,6 +1112,23 @@ public class LauncherBackupHelper implements BackupHelper { return mWidgetMap.get(component); } private boolean initializeIconCache() { if (mIconCache != null) { return true; } final LauncherAppState appState = LauncherAppState.getInstanceNoCreate(); if (appState == null) { Throwable stackTrace = new Throwable(); stackTrace.fillInStackTrace(); Log.w(TAG, "Failed to get app state during backup/restore", stackTrace); return false; } mIconCache = appState.getIconCache(); return mIconCache != null; } private class KeyParsingException extends Throwable { private KeyParsingException(Throwable cause) { super(cause); Loading
src/com/android/launcher3/LauncherModel.java +9 −3 Original line number Diff line number Diff line Loading @@ -318,10 +318,16 @@ public class LauncherModel extends BroadcastReceiver { public void run() { Callbacks cb = mCallbacks != null ? mCallbacks.get() : null; if (callbacks == cb && cb != null) { callbacks.bindAppsAdded(null, null, null, allAppsApps); if (!restoredAppsFinal.isEmpty()) { for (AppInfo info : restoredAppsFinal) { final Intent intent = info.getIntent(); if (intent != null) { mIconCache.deletePreloadedIcon(intent.getComponent()); } } callbacks.bindAppsUpdated(restoredAppsFinal); } callbacks.bindAppsAdded(null, null, null, allAppsApps); } } }); Loading Loading @@ -2667,6 +2673,7 @@ public class LauncherModel extends BroadcastReceiver { case OP_ADD: for (int i=0; i<N; i++) { if (DEBUG_LOADERS) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]); mIconCache.remove(packages[i]); mBgAllAppsList.addPackage(context, packages[i]); } break; Loading Loading @@ -2862,13 +2869,12 @@ public class LauncherModel extends BroadcastReceiver { */ public ShortcutInfo getRestoredItemInfo(Cursor cursor, int titleIndex, Intent intent) { final ShortcutInfo info = new ShortcutInfo(); info.usingFallbackIcon = true; info.setIcon(getFallbackIcon()); if (cursor != null) { info.title = cursor.getString(titleIndex); } else { info.title = ""; } info.setIcon(mIconCache.getIcon(intent, info.title.toString())); info.itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; info.restoredIntent = intent; return info; Loading