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 
17 package com.android.launcher2;
18 
19 import android.app.ActivityManager;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.pm.ActivityInfo;
24 import android.content.pm.LauncherActivityInfo;
25 import android.content.pm.LauncherApps;
26 import android.content.pm.PackageManager;
27 import android.content.pm.ResolveInfo;
28 import android.content.res.Resources;
29 import android.graphics.Bitmap;
30 import android.graphics.Canvas;
31 import android.graphics.drawable.Drawable;
32 import android.os.UserHandle;
33 
34 import java.util.HashMap;
35 
36 /**
37  * Cache of application icons.  Icons can be made from any thread.
38  */
39 public class IconCache {
40     @SuppressWarnings("unused")
41     private static final String TAG = "Launcher.IconCache";
42 
43     private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
44 
45     private static class CacheEntry {
46         public Bitmap icon;
47         public String title;
48         public CharSequence contentDescription;
49     }
50 
51     private static class CacheKey {
52         public ComponentName componentName;
53         public UserHandle user;
54 
CacheKey(ComponentName componentName, UserHandle user)55         CacheKey(ComponentName componentName, UserHandle user) {
56             this.componentName = componentName;
57             this.user = user;
58         }
59 
60         @Override
hashCode()61         public int hashCode() {
62             return componentName.hashCode() + user.hashCode();
63         }
64 
65         @Override
equals(Object o)66         public boolean equals(Object o) {
67             CacheKey other = (CacheKey) o;
68             return other.componentName.equals(componentName) && other.user.equals(user);
69         }
70     }
71 
72     private final Bitmap mDefaultIcon;
73     private final LauncherApplication mContext;
74     private final PackageManager mPackageManager;
75     private final HashMap<CacheKey, CacheEntry> mCache =
76             new HashMap<CacheKey, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY);
77     private int mIconDpi;
78 
IconCache(LauncherApplication context)79     public IconCache(LauncherApplication context) {
80         ActivityManager activityManager =
81                 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
82 
83         mContext = context;
84         mPackageManager = context.getPackageManager();
85         mIconDpi = activityManager.getLauncherLargeIconDensity();
86         // need to set mIconDpi before getting default icon
87         mDefaultIcon = makeDefaultIcon();
88     }
89 
getFullResDefaultActivityIcon()90     public Drawable getFullResDefaultActivityIcon() {
91         return getFullResIcon(Resources.getSystem(),
92                 android.R.mipmap.sym_def_app_icon, android.os.Process.myUserHandle());
93     }
94 
getFullResIcon(Resources resources, int iconId, UserHandle user)95     public Drawable getFullResIcon(Resources resources, int iconId, UserHandle user) {
96         Drawable d;
97         try {
98             d = resources.getDrawableForDensity(iconId, mIconDpi);
99         } catch (Resources.NotFoundException e) {
100             d = null;
101         }
102 
103         if (d == null) {
104             d = getFullResDefaultActivityIcon();
105         }
106         return mPackageManager.getUserBadgedIcon(d, user);
107     }
108 
getFullResIcon(String packageName, int iconId, UserHandle user)109     public Drawable getFullResIcon(String packageName, int iconId, UserHandle user) {
110         Resources resources;
111         try {
112             // TODO: Check if this needs to use the user param if we support
113             // shortcuts/widgets from other profiles. It won't work as is
114             // for packages that are only available in a different user profile.
115             resources = mPackageManager.getResourcesForApplication(packageName);
116         } catch (PackageManager.NameNotFoundException e) {
117             resources = null;
118         }
119         if (resources != null) {
120             if (iconId != 0) {
121                 return getFullResIcon(resources, iconId, user);
122             }
123         }
124         return getFullResDefaultActivityIcon();
125     }
126 
getFullResIcon(ResolveInfo info, UserHandle user)127     public Drawable getFullResIcon(ResolveInfo info, UserHandle user) {
128         return getFullResIcon(info.activityInfo, user);
129     }
130 
getFullResIcon(ActivityInfo info, UserHandle user)131     public Drawable getFullResIcon(ActivityInfo info, UserHandle user) {
132         Resources resources;
133         try {
134             resources = mPackageManager.getResourcesForApplication(
135                     info.applicationInfo);
136         } catch (PackageManager.NameNotFoundException e) {
137             resources = null;
138         }
139         if (resources != null) {
140             int iconId = info.getIconResource();
141             if (iconId != 0) {
142                 return getFullResIcon(resources, iconId, user);
143             }
144         }
145         return getFullResDefaultActivityIcon();
146     }
147 
makeDefaultIcon()148     private Bitmap makeDefaultIcon() {
149         Drawable d = getFullResDefaultActivityIcon();
150         Bitmap b = Bitmap.createBitmap(Math.max(d.getIntrinsicWidth(), 1),
151                 Math.max(d.getIntrinsicHeight(), 1),
152                 Bitmap.Config.ARGB_8888);
153         Canvas c = new Canvas(b);
154         d.setBounds(0, 0, b.getWidth(), b.getHeight());
155         d.draw(c);
156         c.setBitmap(null);
157         return b;
158     }
159 
160     /**
161      * Remove any records for the supplied ComponentName.
162      */
remove(ComponentName componentName)163     public void remove(ComponentName componentName) {
164         synchronized (mCache) {
165             mCache.remove(componentName);
166         }
167     }
168 
169     /**
170      * Empty out the cache.
171      */
flush()172     public void flush() {
173         synchronized (mCache) {
174             mCache.clear();
175         }
176     }
177 
178     /**
179      * Fill in "application" with the icon and label for "info."
180      */
getTitleAndIcon(ApplicationInfo application, LauncherActivityInfo info, HashMap<Object, CharSequence> labelCache)181     public void getTitleAndIcon(ApplicationInfo application, LauncherActivityInfo info,
182             HashMap<Object, CharSequence> labelCache) {
183         synchronized (mCache) {
184             CacheEntry entry = cacheLocked(application.componentName, info, labelCache,
185                     info.getUser());
186 
187             application.title = entry.title;
188             application.iconBitmap = entry.icon;
189             application.contentDescription = entry.contentDescription;
190         }
191     }
192 
getIcon(Intent intent, UserHandle user)193     public Bitmap getIcon(Intent intent, UserHandle user) {
194         synchronized (mCache) {
195             LauncherApps launcherApps = (LauncherApps)
196                     mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
197             final LauncherActivityInfo launcherActInfo =
198                     launcherApps.resolveActivity(intent, user);
199             ComponentName component = intent.getComponent();
200 
201             if (launcherActInfo == null || component == null) {
202                 return mDefaultIcon;
203             }
204 
205             CacheEntry entry = cacheLocked(component, launcherActInfo, null, user);
206             return entry.icon;
207         }
208     }
209 
getIcon(ComponentName component, LauncherActivityInfo info, HashMap<Object, CharSequence> labelCache)210     public Bitmap getIcon(ComponentName component, LauncherActivityInfo info,
211             HashMap<Object, CharSequence> labelCache) {
212         synchronized (mCache) {
213             if (info == null || component == null) {
214                 return null;
215             }
216 
217             CacheEntry entry = cacheLocked(component, info, labelCache, info.getUser());
218             return entry.icon;
219         }
220     }
221 
isDefaultIcon(Bitmap icon)222     public boolean isDefaultIcon(Bitmap icon) {
223         return mDefaultIcon == icon;
224     }
225 
cacheLocked(ComponentName componentName, LauncherActivityInfo info, HashMap<Object, CharSequence> labelCache, UserHandle user)226     private CacheEntry cacheLocked(ComponentName componentName, LauncherActivityInfo info,
227             HashMap<Object, CharSequence> labelCache, UserHandle user) {
228         CacheKey cacheKey = new CacheKey(componentName, user);
229         CacheEntry entry = mCache.get(cacheKey);
230         if (entry == null) {
231             entry = new CacheEntry();
232 
233             mCache.put(cacheKey, entry);
234 
235             ComponentName key = info.getComponentName();
236             if (labelCache != null && labelCache.containsKey(key)) {
237                 entry.title = labelCache.get(key).toString();
238             } else {
239                 entry.title = info.getLabel().toString();
240                 if (labelCache != null) {
241                     labelCache.put(key, entry.title);
242                 }
243             }
244             if (entry.title == null) {
245                 entry.title = info.getComponentName().getShortClassName();
246             }
247             entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user);
248             entry.icon = Utilities.createIconBitmap(info.getBadgedIcon(mIconDpi), mContext);
249         }
250         return entry;
251     }
252 }
253