diff options
Diffstat (limited to 'src/com/android/launcher3/IconCache.java')
-rw-r--r-- | src/com/android/launcher3/IconCache.java | 245 |
1 files changed, 199 insertions, 46 deletions
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java index e1659e795..1dade8027 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,16 +27,24 @@ 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.text.TextUtils; - +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; -import com.android.launcher3.settings.SettingsProvider; - /** * Cache of application icons. Icons can be made from any thread. */ @@ -43,7 +53,9 @@ public class IconCache { private static final String TAG = "Launcher.IconCache"; private static final int INITIAL_ICON_CACHE_CAPACITY = 50; - private IconPackHelper mIconPackHelper; + private static final String RESOURCE_FILE_PREFIX = "icon_"; + + private static final boolean DEBUG = true; private static class CacheEntry { public Bitmap icon; @@ -67,9 +79,6 @@ public class IconCache { // need to set mIconDpi before getting default icon mDefaultIcon = makeDefaultIcon(); - - mIconPackHelper = new IconPackHelper(context); - loadIconPack(); } public Drawable getFullResDefaultActivityIcon() { @@ -117,18 +126,12 @@ public class IconCache { resources = null; } if (resources != null) { - int iconId = 0; - if (mIconPackHelper != null && mIconPackHelper.isIconPackLoaded()) { - iconId = mIconPackHelper.getResourceIdForActivityIcon(info); - if (iconId != 0) { - return getFullResIcon(mIconPackHelper.getIconPackResources(), iconId); - } - } - iconId = info.getIconResource(); + int iconId = info.getIconResource(); if (iconId != 0) { return getFullResIcon(resources, iconId); } } + return getFullResDefaultActivityIcon(); } @@ -144,16 +147,6 @@ public class IconCache { return b; } - private void loadIconPack() { - mIconPackHelper.unloadIconPack(); - String iconPack = SettingsProvider.getStringCustomDefault(mContext, - SettingsProvider.SETTINGS_UI_GENERAL_ICONS_ICON_PACK, ""); - if (!TextUtils.isEmpty(iconPack) && !mIconPackHelper.loadIconPack(iconPack)) { - SettingsProvider.putString(mContext, - SettingsProvider.SETTINGS_UI_GENERAL_ICONS_ICON_PACK, ""); - } - } - /** * Remove any records for the supplied ComponentName. */ @@ -164,13 +157,27 @@ 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() { synchronized (mCache) { mCache.clear(); } - loadIconPack(); } /** @@ -181,7 +188,7 @@ public class IconCache { Iterator<Entry<ComponentName, CacheEntry>> it = mCache.entrySet().iterator(); while (it.hasNext()) { final CacheEntry e = it.next().getValue(); - if (e.icon.getWidth() != grid.iconSizePx || e.icon.getHeight() != grid.iconSizePx) { + if (e.icon.getWidth() < grid.iconSizePx || e.icon.getHeight() < grid.iconSizePx) { it.remove(); } } @@ -202,15 +209,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; } } @@ -239,28 +253,34 @@ public class IconCache { mCache.put(componentName, entry); - 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 (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; } - } - if (entry.title == null) { - entry.title = info.activityInfo.name; - } - Drawable icon = getFullResIcon(info); - if (mIconPackHelper.isIconPackLoaded() && (mIconPackHelper - .getResourceIdForActivityIcon(info.activityInfo) == 0)) { entry.icon = Utilities.createIconBitmap( - icon, mContext, mIconPackHelper.getIconBack(), - mIconPackHelper.getIconMask(), mIconPackHelper.getIconUpon(), mIconPackHelper.getIconScale()); + getFullResIcon(info), mContext); } else { - entry.icon = Utilities.createIconBitmap( - icon, mContext); + 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; @@ -276,4 +296,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; + } } |