summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/IconCache.java
diff options
context:
space:
mode:
authorChris Wren <cwren@android.com>2014-02-10 12:16:54 -0500
committerChris Wren <cwren@android.com>2014-02-14 11:49:30 -0500
commit6d0dde01f307051ee1849481c989d9e87774b894 (patch)
tree76a3c70f422e8a4e86352885d8239e67b17c8453 /src/com/android/launcher3/IconCache.java
parent55bd9725d5c0373b89f7b9bbd9547550ea3bbc63 (diff)
downloadandroid_packages_apps_Trebuchet-6d0dde01f307051ee1849481c989d9e87774b894.tar.gz
android_packages_apps_Trebuchet-6d0dde01f307051ee1849481c989d9e87774b894.tar.bz2
android_packages_apps_Trebuchet-6d0dde01f307051ee1849481c989d9e87774b894.zip
use restored icon for restored app shortcuts
Bug: 10778992 Change-Id: Ie430a6587d49dc0d78b87b81582c0cef7c281017
Diffstat (limited to 'src/com/android/launcher3/IconCache.java')
-rw-r--r--src/com/android/launcher3/IconCache.java213
1 files changed, 199 insertions, 14 deletions
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index a55fce01c..827718b9e 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -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;
@@ -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;
@@ -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;
@@ -115,6 +130,7 @@ public class IconCache {
return getFullResIcon(resources, iconId);
}
}
+
return getFullResDefaultActivityIcon();
}
@@ -140,6 +156,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.
*/
public void flush() {
@@ -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;
}
}
@@ -214,21 +252,35 @@ public class IconCache {
mCache.put(componentName, entry);
- ComponentName key = LauncherModel.getComponentNameFromResolveInfo(info);
- if (labelCache != null && labelCache.containsKey(key)) {
- entry.title = labelCache.get(key).toString();
+ if (info != null) {
+ ComponentName key = LauncherModel.getComponentNameFromResolveInfo(info);
+ if (labelCache != null && labelCache.containsKey(key)) {
+ entry.title = labelCache.get(key).toString();
+ } else {
+ entry.title = info.loadLabel(mPackageManager).toString();
+ if (labelCache != null) {
+ labelCache.put(key, entry.title);
+ }
+ }
+ if (entry.title == null) {
+ entry.title = info.activityInfo.name;
+ }
+
+ entry.icon = Utilities.createIconBitmap(
+ getFullResIcon(info), mContext);
} else {
- entry.title = info.loadLabel(mPackageManager).toString();
- if (labelCache != null) {
- labelCache.put(key, entry.title);
+ 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;
}
}
- if (entry.title == null) {
- entry.title = info.activityInfo.name;
- }
-
- entry.icon = Utilities.createIconBitmap(
- getFullResIcon(info), mContext);
}
return entry;
}
@@ -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;
+ }
}