IconCache.java revision 86c119a2267398dfe7ccbc2c262c6b48c93d76c4
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.launcher2;
18
19import android.content.ComponentName;
20import android.content.Intent;
21import android.content.pm.PackageManager;
22import android.content.pm.ResolveInfo;
23import android.content.res.Resources;
24import android.graphics.Bitmap;
25import android.graphics.Canvas;
26import android.graphics.drawable.Drawable;
27import android.util.DisplayMetrics;
28
29import java.util.HashMap;
30
31/**
32 * Cache of application icons.  Icons can be made from any thread.
33 */
34public class IconCache {
35    private static final String TAG = "Launcher.IconCache";
36
37    private static final int INITIAL_ICON_CACHE_CAPACITY = 50;
38
39    private static class CacheEntry {
40        public Bitmap icon;
41        public String title;
42    }
43
44    private final Bitmap mDefaultIcon;
45    private final LauncherApplication mContext;
46    private final PackageManager mPackageManager;
47    private final HashMap<ComponentName, CacheEntry> mCache =
48            new HashMap<ComponentName, CacheEntry>(INITIAL_ICON_CACHE_CAPACITY);
49    private int mIconDpi;
50
51    public IconCache(LauncherApplication context) {
52        mContext = context;
53        mPackageManager = context.getPackageManager();
54        int density = context.getResources().getDisplayMetrics().densityDpi;
55        if (LauncherApplication.isScreenLarge()) {
56            if (density == DisplayMetrics.DENSITY_LOW) {
57                mIconDpi = DisplayMetrics.DENSITY_MEDIUM;
58            } else if (density == DisplayMetrics.DENSITY_MEDIUM) {
59                mIconDpi = DisplayMetrics.DENSITY_HIGH;
60            } else if (density == DisplayMetrics.DENSITY_HIGH) {
61                mIconDpi = DisplayMetrics.DENSITY_XHIGH;
62            } else if (density == DisplayMetrics.DENSITY_XHIGH) {
63                // We'll need to use a denser icon, or some sort of a mipmap
64                mIconDpi = DisplayMetrics.DENSITY_XHIGH;
65            }
66        } else {
67            mIconDpi = context.getResources().getDisplayMetrics().densityDpi;
68        }
69        // need to set mIconDpi before getting default icon
70        mDefaultIcon = makeDefaultIcon();
71    }
72
73    public Drawable getFullResDefaultActivityIcon() {
74        return getFullResIcon(Resources.getSystem(),
75                com.android.internal.R.mipmap.sym_def_app_icon);
76    }
77
78    public Drawable getFullResIcon(Resources resources, int iconId) {
79        Drawable d;
80        try {
81            d = resources.getDrawableForDensity(iconId, mIconDpi);
82        } catch (Resources.NotFoundException e) {
83            d = null;
84        }
85
86        return (d != null) ? d : getFullResDefaultActivityIcon();
87    }
88
89    public Drawable getFullResIcon(ResolveInfo info, PackageManager packageManager) {
90        Resources resources;
91        try {
92            resources = packageManager.getResourcesForApplication(
93                    info.activityInfo.applicationInfo);
94        } catch (PackageManager.NameNotFoundException e) {
95            resources = null;
96        }
97        if (resources != null) {
98            int iconId = info.activityInfo.getIconResource();
99            if (iconId != 0) {
100                return getFullResIcon(resources, iconId);
101            }
102        }
103        return getFullResDefaultActivityIcon();
104    }
105
106    private Bitmap makeDefaultIcon() {
107        Drawable d = getFullResDefaultActivityIcon();
108        Bitmap b = Bitmap.createBitmap(Math.max(d.getIntrinsicWidth(), 1),
109                Math.max(d.getIntrinsicHeight(), 1),
110                Bitmap.Config.ARGB_8888);
111        Canvas c = new Canvas(b);
112        d.setBounds(0, 0, b.getWidth(), b.getHeight());
113        d.draw(c);
114        c.setBitmap(null);
115        return b;
116    }
117
118    /**
119     * Remove any records for the supplied ComponentName.
120     */
121    public void remove(ComponentName componentName) {
122        synchronized (mCache) {
123            mCache.remove(componentName);
124        }
125    }
126
127    /**
128     * Empty out the cache.
129     */
130    public void flush() {
131        synchronized (mCache) {
132            mCache.clear();
133        }
134    }
135
136    /**
137     * Fill in "application" with the icon and label for "info."
138     */
139    public void getTitleAndIcon(ApplicationInfo application, ResolveInfo info,
140            HashMap<Object, CharSequence> labelCache) {
141        synchronized (mCache) {
142            CacheEntry entry = cacheLocked(application.componentName, info, labelCache);
143
144            application.title = entry.title;
145            application.iconBitmap = entry.icon;
146        }
147    }
148
149    public Bitmap getIcon(Intent intent) {
150        synchronized (mCache) {
151            final ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, 0);
152            ComponentName component = intent.getComponent();
153
154            if (resolveInfo == null || component == null) {
155                return mDefaultIcon;
156            }
157
158            CacheEntry entry = cacheLocked(component, resolveInfo, null);
159            return entry.icon;
160        }
161    }
162
163    public Bitmap getIcon(ComponentName component, ResolveInfo resolveInfo) {
164        synchronized (mCache) {
165            if (resolveInfo == null || component == null) {
166                return null;
167            }
168
169            CacheEntry entry = cacheLocked(component, resolveInfo, null);
170            return entry.icon;
171        }
172    }
173
174    public boolean isDefaultIcon(Bitmap icon) {
175        return mDefaultIcon == icon;
176    }
177
178    private CacheEntry cacheLocked(ComponentName componentName, ResolveInfo info,
179            HashMap<Object, CharSequence> labelCache) {
180        CacheEntry entry = mCache.get(componentName);
181        if (entry == null) {
182            entry = new CacheEntry();
183
184            mCache.put(componentName, entry);
185
186            if (labelCache != null && labelCache.containsKey(info)) {
187                entry.title = labelCache.get(info).toString();
188            } else {
189                entry.title = info.loadLabel(mPackageManager).toString();
190                if (labelCache != null) {
191                    labelCache.put(info, entry.title);
192                }
193            }
194            if (entry.title == null) {
195                entry.title = info.activityInfo.name;
196            }
197
198            entry.icon = Utilities.createIconBitmap(
199                    getFullResIcon(info, mPackageManager), mContext);
200        }
201        return entry;
202    }
203
204    public HashMap<ComponentName,Bitmap> getAllIcons() {
205        synchronized (mCache) {
206            HashMap<ComponentName,Bitmap> set = new HashMap<ComponentName,Bitmap>();
207            int i = 0;
208            for (ComponentName cn : mCache.keySet()) {
209                final CacheEntry e = mCache.get(cn);
210                set.put(cn, e.icon);
211            }
212            return set;
213        }
214    }
215}
216