1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.launcher3; 18 19import android.app.ActivityManager; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.Intent; 23import android.content.pm.ActivityInfo; 24import android.content.pm.PackageManager; 25import android.content.pm.ResolveInfo; 26import android.content.res.Resources; 27import android.graphics.Bitmap; 28import android.graphics.Canvas; 29import android.graphics.drawable.Drawable; 30 31import java.util.HashMap; 32import java.util.Iterator; 33import java.util.Map.Entry; 34 35/** 36 * Cache of application icons. Icons can be made from any thread. 37 */ 38public class IconCache { 39 @SuppressWarnings("unused") 40 private static final String TAG = "Launcher.IconCache"; 41 42 private static final int INITIAL_ICON_CACHE_CAPACITY = 50; 43 44 private static class CacheEntry { 45 public Bitmap icon; 46 public String title; 47 } 48 49 private final Bitmap mDefaultIcon; 50 private final Context mContext; 51 private final PackageManager mPackageManager; 52 private final HashMap<ComponentName, CacheEntry> mCache = 53 new HashMap<ComponentName, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY); 54 private int mIconDpi; 55 56 public IconCache(Context context) { 57 ActivityManager activityManager = 58 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 59 60 mContext = context; 61 mPackageManager = context.getPackageManager(); 62 mIconDpi = activityManager.getLauncherLargeIconDensity(); 63 64 // need to set mIconDpi before getting default icon 65 mDefaultIcon = makeDefaultIcon(); 66 } 67 68 public Drawable getFullResDefaultActivityIcon() { 69 return getFullResIcon(Resources.getSystem(), 70 android.R.mipmap.sym_def_app_icon); 71 } 72 73 public Drawable getFullResIcon(Resources resources, int iconId) { 74 Drawable d; 75 try { 76 d = resources.getDrawableForDensity(iconId, mIconDpi); 77 } catch (Resources.NotFoundException e) { 78 d = null; 79 } 80 81 return (d != null) ? d : getFullResDefaultActivityIcon(); 82 } 83 84 public Drawable getFullResIcon(String packageName, int iconId) { 85 Resources resources; 86 try { 87 resources = mPackageManager.getResourcesForApplication(packageName); 88 } catch (PackageManager.NameNotFoundException e) { 89 resources = null; 90 } 91 if (resources != null) { 92 if (iconId != 0) { 93 return getFullResIcon(resources, iconId); 94 } 95 } 96 return getFullResDefaultActivityIcon(); 97 } 98 99 public Drawable getFullResIcon(ResolveInfo info) { 100 return getFullResIcon(info.activityInfo); 101 } 102 103 public Drawable getFullResIcon(ActivityInfo info) { 104 105 Resources resources; 106 try { 107 resources = mPackageManager.getResourcesForApplication( 108 info.applicationInfo); 109 } catch (PackageManager.NameNotFoundException e) { 110 resources = null; 111 } 112 if (resources != null) { 113 int iconId = info.getIconResource(); 114 if (iconId != 0) { 115 return getFullResIcon(resources, iconId); 116 } 117 } 118 return getFullResDefaultActivityIcon(); 119 } 120 121 private Bitmap makeDefaultIcon() { 122 Drawable d = getFullResDefaultActivityIcon(); 123 Bitmap b = Bitmap.createBitmap(Math.max(d.getIntrinsicWidth(), 1), 124 Math.max(d.getIntrinsicHeight(), 1), 125 Bitmap.Config.ARGB_8888); 126 Canvas c = new Canvas(b); 127 d.setBounds(0, 0, b.getWidth(), b.getHeight()); 128 d.draw(c); 129 c.setBitmap(null); 130 return b; 131 } 132 133 /** 134 * Remove any records for the supplied ComponentName. 135 */ 136 public void remove(ComponentName componentName) { 137 synchronized (mCache) { 138 mCache.remove(componentName); 139 } 140 } 141 142 /** 143 * Empty out the cache. 144 */ 145 public void flush() { 146 synchronized (mCache) { 147 mCache.clear(); 148 } 149 } 150 151 /** 152 * Empty out the cache that aren't of the correct grid size 153 */ 154 public void flushInvalidIcons(DeviceProfile grid) { 155 synchronized (mCache) { 156 Iterator<Entry<ComponentName, CacheEntry>> it = mCache.entrySet().iterator(); 157 while (it.hasNext()) { 158 final CacheEntry e = it.next().getValue(); 159 if (e.icon.getWidth() != grid.iconSizePx || e.icon.getHeight() != grid.iconSizePx) { 160 it.remove(); 161 } 162 } 163 } 164 } 165 166 /** 167 * Fill in "application" with the icon and label for "info." 168 */ 169 public void getTitleAndIcon(AppInfo application, ResolveInfo info, 170 HashMap<Object, CharSequence> labelCache) { 171 synchronized (mCache) { 172 CacheEntry entry = cacheLocked(application.componentName, info, labelCache); 173 174 application.title = entry.title; 175 application.iconBitmap = entry.icon; 176 } 177 } 178 179 public Bitmap getIcon(Intent intent) { 180 synchronized (mCache) { 181 final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0); 182 ComponentName component = intent.getComponent(); 183 184 if (resolveInfo == null || component == null) { 185 return mDefaultIcon; 186 } 187 188 CacheEntry entry = cacheLocked(component, resolveInfo, null); 189 return entry.icon; 190 } 191 } 192 193 public Bitmap getIcon(ComponentName component, ResolveInfo resolveInfo, 194 HashMap<Object, CharSequence> labelCache) { 195 synchronized (mCache) { 196 if (resolveInfo == null || component == null) { 197 return null; 198 } 199 200 CacheEntry entry = cacheLocked(component, resolveInfo, labelCache); 201 return entry.icon; 202 } 203 } 204 205 public boolean isDefaultIcon(Bitmap icon) { 206 return mDefaultIcon == icon; 207 } 208 209 private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info, 210 HashMap<Object, CharSequence> labelCache) { 211 CacheEntry entry = mCache.get(componentName); 212 if (entry == null) { 213 entry = new CacheEntry(); 214 215 mCache.put(componentName, entry); 216 217 ComponentName key = LauncherModel.getComponentNameFromResolveInfo(info); 218 if (labelCache != null && labelCache.containsKey(key)) { 219 entry.title = labelCache.get(key).toString(); 220 } else { 221 entry.title = info.loadLabel(mPackageManager).toString(); 222 if (labelCache != null) { 223 labelCache.put(key, entry.title); 224 } 225 } 226 if (entry.title == null) { 227 entry.title = info.activityInfo.name; 228 } 229 230 entry.icon = Utilities.createIconBitmap( 231 getFullResIcon(info), mContext); 232 } 233 return entry; 234 } 235 236 public HashMap<ComponentName,Bitmap> getAllIcons() { 237 synchronized (mCache) { 238 HashMap<ComponentName,Bitmap> set = new HashMap<ComponentName,Bitmap>(); 239 for (ComponentName cn : mCache.keySet()) { 240 final CacheEntry e = mCache.get(cn); 241 set.put(cn, e.icon); 242 } 243 return set; 244 } 245 } 246} 247