WidgetPreviewLoader.java revision fd13c714f412dfa8130fa7a664cb1692a565c539
1325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3; 205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.appwidget.AppWidgetProviderInfo; 405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.ComponentName; 505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.ContentValues; 605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.Context; 705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.pm.PackageManager; 805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.pm.ResolveInfo; 905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.res.Resources; 1005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.Cursor; 1105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.sqlite.SQLiteDatabase; 1205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.sqlite.SQLiteOpenHelper; 1305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Bitmap; 1405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Bitmap.Config; 1505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.BitmapFactory; 1605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Canvas; 1705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.ColorMatrix; 1805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.ColorMatrixColorFilter; 1905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Paint; 2005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.PorterDuff; 2105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Rect; 2205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Shader; 2305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.drawable.BitmapDrawable; 2405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.drawable.Drawable; 2505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.os.AsyncTask; 2605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.util.Log; 2705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 2805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.io.ByteArrayOutputStream; 2905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.io.File; 3005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.lang.ref.SoftReference; 3105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.lang.ref.WeakReference; 3205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.ArrayList; 3305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.HashMap; 3405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.HashSet; 3505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 3605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaabstract class SoftReferenceThreadLocal<T> { 3705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private ThreadLocal<SoftReference<T>> mThreadLocal; 3805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public SoftReferenceThreadLocal() { 3905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mThreadLocal = new ThreadLocal<SoftReference<T>>(); 4005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 4105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka abstract T initialValue(); 4305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public void set(T t) { 4505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mThreadLocal.set(new SoftReference<T>(t)); 4605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 4705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public T get() { 4905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka SoftReference<T> reference = mThreadLocal.get(); 5005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka T obj; 5105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (reference == null) { 5205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka obj = initialValue(); 5305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mThreadLocal.set(new SoftReference<T>(obj)); 5405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return obj; 5505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 5605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka obj = reference.get(); 5705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (obj == null) { 5805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka obj = initialValue(); 5905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mThreadLocal.set(new SoftReference<T>(obj)); 6005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 6105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return obj; 6205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 6305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 6405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 6505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 6605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaclass CanvasCache extends SoftReferenceThreadLocal<Canvas> { 6705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 6805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka protected Canvas initialValue() { 6905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return new Canvas(); 7005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 7105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 7205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 7305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaclass PaintCache extends SoftReferenceThreadLocal<Paint> { 7405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 7505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka protected Paint initialValue() { 7605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 7705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 7805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 7905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 8005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaclass BitmapCache extends SoftReferenceThreadLocal<Bitmap> { 8105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 8205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka protected Bitmap initialValue() { 8305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 8405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 8505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 8605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 8705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaclass RectCache extends SoftReferenceThreadLocal<Rect> { 8805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 8905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka protected Rect initialValue() { 9005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return new Rect(); 9105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 9205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 9305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 9405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaclass BitmapFactoryOptionsCache extends SoftReferenceThreadLocal<BitmapFactory.Options> { 9505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 9605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka protected BitmapFactory.Options initialValue() { 9705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return new BitmapFactory.Options(); 9805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 9905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 10005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 10105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkapublic class WidgetPreviewLoader { 10205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka static final String TAG = "WidgetPreviewLoader"; 10305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1043f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka private int mPreviewBitmapWidth; 1053f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka private int mPreviewBitmapHeight; 10605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private String mSize; 10705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private Context mContext; 10805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private PackageManager mPackageManager; 10905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private PagedViewCellLayout mWidgetSpacingLayout; 11005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 11105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Used for drawing shortcut previews 11205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache(); 11305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private PaintCache mCachedShortcutPreviewPaint = new PaintCache(); 11405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private CanvasCache mCachedShortcutPreviewCanvas = new CanvasCache(); 11505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 11605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Used for drawing widget previews 11705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private CanvasCache mCachedAppWidgetPreviewCanvas = new CanvasCache(); 11805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private RectCache mCachedAppWidgetPreviewSrcRect = new RectCache(); 11905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private RectCache mCachedAppWidgetPreviewDestRect = new RectCache(); 12005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private PaintCache mCachedAppWidgetPreviewPaint = new PaintCache(); 12105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private String mCachedSelectQuery; 12205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache(); 12305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 12405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private int mAppIconSize; 12505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private IconCache mIconCache; 12605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 12705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private final float sWidgetPreviewIconPaddingPercentage = 0.25f; 12805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 129d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka private CacheDb mDb; 13005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1313f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka private HashMap<String, WeakReference<Bitmap>> mLoadedPreviews; 1323f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka private ArrayList<SoftReference<Bitmap>> mUnusedBitmaps; 13305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private static HashSet<String> sInvalidPackages; 13405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 13505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka static { 13605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sInvalidPackages = new HashSet<String>(); 13705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 13805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 139fd13c714f412dfa8130fa7a664cb1692a565c539Chris Wren public WidgetPreviewLoader(Context context) { 1405f8afe6280eae34620067696173e71943e1a30a3Winson Chung LauncherAppState app = LauncherAppState.getInstance(); 1415f8afe6280eae34620067696173e71943e1a30a3Winson Chung DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); 1425f8afe6280eae34620067696173e71943e1a30a3Winson Chung 143fd13c714f412dfa8130fa7a664cb1692a565c539Chris Wren mContext = context; 14405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mPackageManager = mContext.getPackageManager(); 1455f8afe6280eae34620067696173e71943e1a30a3Winson Chung mAppIconSize = grid.iconSizePx; 146d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka mIconCache = app.getIconCache(); 147d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka mDb = app.getWidgetPreviewCacheDb(); 1483f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mLoadedPreviews = new HashMap<String, WeakReference<Bitmap>>(); 1493f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mUnusedBitmaps = new ArrayList<SoftReference<Bitmap>>(); 1503f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka } 1513f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka 1523f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka public void setPreviewSize(int previewWidth, int previewHeight, 1533f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka PagedViewCellLayout widgetSpacingLayout) { 1543f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mPreviewBitmapWidth = previewWidth; 1553f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mPreviewBitmapHeight = previewHeight; 1563f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mSize = previewWidth + "x" + previewHeight; 1573f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mWidgetSpacingLayout = widgetSpacingLayout; 15805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 15905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 16005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Bitmap getPreview(final Object o) { 161eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka final String name = getObjectName(o); 162eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka final String packageName = getObjectPackage(o); 16305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // check if the package is valid 16405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka boolean packageValid = true; 16505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka synchronized(sInvalidPackages) { 166eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka packageValid = !sInvalidPackages.contains(packageName); 16705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 16805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (!packageValid) { 16905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 17005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 17105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (packageValid) { 1723f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka synchronized(mLoadedPreviews) { 17305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // check if it exists in our existing cache 1743f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka if (mLoadedPreviews.containsKey(name) && mLoadedPreviews.get(name).get() != null) { 1753f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka return mLoadedPreviews.get(name).get(); 17605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 17705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 17805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 17905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 18005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap unusedBitmap = null; 1813f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka synchronized(mUnusedBitmaps) { 18205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // not in cache; we need to load it from the db 1833f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka while ((unusedBitmap == null || !unusedBitmap.isMutable() || 1843f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka unusedBitmap.getWidth() != mPreviewBitmapWidth || 1853f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka unusedBitmap.getHeight() != mPreviewBitmapHeight) 1863f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka && mUnusedBitmaps.size() > 0) { 1873f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka unusedBitmap = mUnusedBitmaps.remove(0).get(); 18805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 18905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (unusedBitmap != null) { 19005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Canvas c = mCachedAppWidgetPreviewCanvas.get(); 19105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(unusedBitmap); 19205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.drawColor(0, PorterDuff.Mode.CLEAR); 19305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 19405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 19505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 19605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 19705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (unusedBitmap == null) { 1983f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka unusedBitmap = Bitmap.createBitmap(mPreviewBitmapWidth, mPreviewBitmapHeight, 19905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap.Config.ARGB_8888); 20005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 20105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 20205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap preview = null; 20305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 20405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (packageValid) { 20505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview = readFromDb(name, unusedBitmap); 20605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 20705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 20805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview != null) { 2093f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka synchronized(mLoadedPreviews) { 2103f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mLoadedPreviews.put(name, new WeakReference<Bitmap>(preview)); 21105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 21205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 21305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 21405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // it's not in the db... we need to generate it 21505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Bitmap generatedPreview = generatePreview(o, unusedBitmap); 21605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview = generatedPreview; 21705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview != unusedBitmap) { 21805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka throw new RuntimeException("generatePreview is not recycling the bitmap " + o); 21905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 22005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 2213f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka synchronized(mLoadedPreviews) { 2223f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mLoadedPreviews.put(name, new WeakReference<Bitmap>(preview)); 22305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 22405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 22505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // write to db on a thread pool... this can be done lazily and improves the performance 22605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // of the first time widget previews are loaded 22705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka new AsyncTask<Void, Void, Void>() { 22805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Void doInBackground(Void ... args) { 22905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka writeToDb(o, generatedPreview); 23005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 23105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 23205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); 23305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 23405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 23505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 23605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 23705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 238ee8e99fe3bde78885904b4d9ea789b4d2a6f2b16Michael Jurka public void recycleBitmap(Object o, Bitmap bitmapToRecycle) { 23905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka String name = getObjectName(o); 2405140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka synchronized (mLoadedPreviews) { 2415140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka if (mLoadedPreviews.containsKey(name)) { 2423f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka Bitmap b = mLoadedPreviews.get(name).get(); 243ee8e99fe3bde78885904b4d9ea789b4d2a6f2b16Michael Jurka if (b == bitmapToRecycle) { 2443f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mLoadedPreviews.remove(name); 245ee8e99fe3bde78885904b4d9ea789b4d2a6f2b16Michael Jurka if (bitmapToRecycle.isMutable()) { 2465140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka synchronized (mUnusedBitmaps) { 2475140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka mUnusedBitmaps.add(new SoftReference<Bitmap>(b)); 2485140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka } 24905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 25005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 25105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka throw new RuntimeException("Bitmap passed in doesn't match up"); 25205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 25305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 25405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 25505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 25605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 257d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka static class CacheDb extends SQLiteOpenHelper { 258e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka final static int DB_VERSION = 2; 25905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String DB_NAME = "widgetpreviews.db"; 26005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String TABLE_NAME = "shortcut_and_widget_previews"; 26105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String COLUMN_NAME = "name"; 26205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String COLUMN_SIZE = "size"; 26305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String COLUMN_PREVIEW_BITMAP = "preview_bitmap"; 26405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Context mContext; 26505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 266d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka public CacheDb(Context context) { 26705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka super(context, new File(context.getCacheDir(), DB_NAME).getPath(), null, DB_VERSION); 26805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Store the context for later use 26905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mContext = context; 27005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 27105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 27205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 27305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public void onCreate(SQLiteDatabase database) { 27432b7a097338b77d8999c706c42f19e8ba060ba62Michael Jurka database.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + 27505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka COLUMN_NAME + " TEXT NOT NULL, " + 27605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka COLUMN_SIZE + " TEXT NOT NULL, " + 27705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka COLUMN_PREVIEW_BITMAP + " BLOB NOT NULL, " + 27805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka "PRIMARY KEY (" + COLUMN_NAME + ", " + COLUMN_SIZE + ") " + 27932b7a097338b77d8999c706c42f19e8ba060ba62Michael Jurka ");"); 28005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 28105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 28205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 28305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 284e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka if (oldVersion != newVersion) { 285e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka // Delete all the records; they'll be repopulated as this is a cache 286e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka db.execSQL("DELETE FROM " + TABLE_NAME); 287e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka } 28805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 28905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 29005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 29105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private static final String WIDGET_PREFIX = "Widget:"; 29205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private static final String SHORTCUT_PREFIX = "Shortcut:"; 29305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 29405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private static String getObjectName(Object o) { 29505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // should cache the string builder 29605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka StringBuilder sb = new StringBuilder(); 29705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka String output; 29805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (o instanceof AppWidgetProviderInfo) { 29905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.append(WIDGET_PREFIX); 30005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.append(((AppWidgetProviderInfo) o).provider.flattenToString()); 30105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka output = sb.toString(); 30205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.setLength(0); 30305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 30405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.append(SHORTCUT_PREFIX); 30505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 30605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ResolveInfo info = (ResolveInfo) o; 30705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.append(new ComponentName(info.activityInfo.packageName, 30805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka info.activityInfo.name).flattenToString()); 30905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka output = sb.toString(); 31005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.setLength(0); 31105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 31205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return output; 31305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 31405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 31505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private String getObjectPackage(Object o) { 31605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (o instanceof AppWidgetProviderInfo) { 31705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return ((AppWidgetProviderInfo) o).provider.getPackageName(); 31805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 31905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ResolveInfo info = (ResolveInfo) o; 32005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return info.activityInfo.packageName; 32105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 32205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 32305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 32405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private void writeToDb(Object o, Bitmap preview) { 32505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka String name = getObjectName(o); 32605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka SQLiteDatabase db = mDb.getWritableDatabase(); 32705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ContentValues values = new ContentValues(); 32805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 329d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka values.put(CacheDb.COLUMN_NAME, name); 33005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ByteArrayOutputStream stream = new ByteArrayOutputStream(); 33105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview.compress(Bitmap.CompressFormat.PNG, 100, stream); 332d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka values.put(CacheDb.COLUMN_PREVIEW_BITMAP, stream.toByteArray()); 333d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka values.put(CacheDb.COLUMN_SIZE, mSize); 334d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka db.insert(CacheDb.TABLE_NAME, null, values); 33505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 33605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 337eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka public static void removePackageFromDb(final CacheDb cacheDb, final String packageName) { 33805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka synchronized(sInvalidPackages) { 33905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sInvalidPackages.add(packageName); 34005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 34105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka new AsyncTask<Void, Void, Void>() { 34205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Void doInBackground(Void ... args) { 343d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka SQLiteDatabase db = cacheDb.getWritableDatabase(); 344d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka db.delete(CacheDb.TABLE_NAME, 345d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka CacheDb.COLUMN_NAME + " LIKE ? OR " + 346d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka CacheDb.COLUMN_NAME + " LIKE ?", // SELECT query 34705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka new String[] { 34805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka WIDGET_PREFIX + packageName + "/%", 34905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka SHORTCUT_PREFIX + packageName + "/%"} // args to SELECT query 35005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ); 35105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka synchronized(sInvalidPackages) { 35205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sInvalidPackages.remove(packageName); 35305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 35405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 35505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 35605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); 35705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 35805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 359eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka public static void removeItemFromDb(final CacheDb cacheDb, final String objectName) { 360eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka new AsyncTask<Void, Void, Void>() { 361eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka public Void doInBackground(Void ... args) { 362eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka SQLiteDatabase db = cacheDb.getWritableDatabase(); 363eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka db.delete(CacheDb.TABLE_NAME, 364eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka CacheDb.COLUMN_NAME + " = ? ", // SELECT query 365eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka new String[] { objectName }); // args to SELECT query 366eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka return null; 367eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 368eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); 369eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 370eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka 37105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private Bitmap readFromDb(String name, Bitmap b) { 37205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (mCachedSelectQuery == null) { 373d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka mCachedSelectQuery = CacheDb.COLUMN_NAME + " = ? AND " + 374d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka CacheDb.COLUMN_SIZE + " = ?"; 37505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 37605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka SQLiteDatabase db = mDb.getReadableDatabase(); 377d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka Cursor result = db.query(CacheDb.TABLE_NAME, 378d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka new String[] { CacheDb.COLUMN_PREVIEW_BITMAP }, // cols to return 37905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mCachedSelectQuery, // select query 38005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka new String[] { name, mSize }, // args to select query 38105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka null, 38205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka null, 38305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka null, 38405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka null); 38505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (result.getCount() > 0) { 38605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka result.moveToFirst(); 38705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka byte[] blob = result.getBlob(0); 38805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka result.close(); 38905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final BitmapFactory.Options opts = mCachedBitmapFactoryOptions.get(); 39005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka opts.inBitmap = b; 39105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka opts.inSampleSize = 1; 392eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka try { 393eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka return BitmapFactory.decodeByteArray(blob, 0, blob.length, opts); 394eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } catch (IllegalArgumentException e) { 395eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka removeItemFromDb(mDb, name); 396eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka return null; 397eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 39805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 39905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka result.close(); 40005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 40105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 40205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 40305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 40405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Bitmap generatePreview(Object info, Bitmap preview) { 40505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview != null && 4063f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka (preview.getWidth() != mPreviewBitmapWidth || 4073f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka preview.getHeight() != mPreviewBitmapHeight)) { 40805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka throw new RuntimeException("Improperly sized bitmap passed as argument"); 40905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 41005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (info instanceof AppWidgetProviderInfo) { 41105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return generateWidgetPreview((AppWidgetProviderInfo) info, preview); 41205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 41305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return generateShortcutPreview( 4143f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka (ResolveInfo) info, mPreviewBitmapWidth, mPreviewBitmapHeight, preview); 41505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 41605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 41705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 41805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Bitmap generateWidgetPreview(AppWidgetProviderInfo info, Bitmap preview) { 419fd13c714f412dfa8130fa7a664cb1692a565c539Chris Wren int[] cellSpans = Launcher.getSpanForWidget(mContext, info); 42005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int maxWidth = maxWidthForWidgetPreview(cellSpans[0]); 42105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int maxHeight = maxHeightForWidgetPreview(cellSpans[1]); 42205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return generateWidgetPreview(info.provider, info.previewImage, info.icon, 42305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka cellSpans[0], cellSpans[1], maxWidth, maxHeight, preview, null); 42405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 42505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 42605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public int maxWidthForWidgetPreview(int spanX) { 4273f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka return Math.min(mPreviewBitmapWidth, 42805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mWidgetSpacingLayout.estimateCellWidth(spanX)); 42905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 43005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 43105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public int maxHeightForWidgetPreview(int spanY) { 4323f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka return Math.min(mPreviewBitmapHeight, 43305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mWidgetSpacingLayout.estimateCellHeight(spanY)); 43405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 43505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 43605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Bitmap generateWidgetPreview(ComponentName provider, int previewImage, 43705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int iconId, int cellHSpan, int cellVSpan, int maxPreviewWidth, int maxPreviewHeight, 43805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap preview, int[] preScaledWidthOut) { 43905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Load the preview image if possible 44005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka String packageName = provider.getPackageName(); 44105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE; 44205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (maxPreviewHeight < 0) maxPreviewHeight = Integer.MAX_VALUE; 44305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 44405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable drawable = null; 44505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (previewImage != 0) { 44605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka drawable = mPackageManager.getDrawable(packageName, previewImage, null); 44705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (drawable == null) { 44805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Log.w(TAG, "Can't load widget preview drawable 0x" + 44905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Integer.toHexString(previewImage) + " for provider: " + provider); 45005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 45105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 45205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 45305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int previewWidth; 45405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int previewHeight; 45505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap defaultPreview = null; 45605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka boolean widgetPreviewExists = (drawable != null); 45705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (widgetPreviewExists) { 45805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewWidth = drawable.getIntrinsicWidth(); 45905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = drawable.getIntrinsicHeight(); 46005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 46105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Generate a preview image if we couldn't load one 46205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (cellHSpan < 1) cellHSpan = 1; 46305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (cellVSpan < 1) cellVSpan = 1; 46405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 46505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka BitmapDrawable previewDrawable = (BitmapDrawable) mContext.getResources() 4666706ed826600683cd66a7a2af79137d9fdda34f8Winson Chung .getDrawable(R.drawable.widget_tile); 46705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final int previewDrawableWidth = previewDrawable 46805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka .getIntrinsicWidth(); 46905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final int previewDrawableHeight = previewDrawable 47005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka .getIntrinsicHeight(); 47145cab39eea097bf622cd1ed67d91d2336d78663aWinson Chung previewWidth = previewDrawableWidth * cellHSpan; 47205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = previewDrawableHeight * cellVSpan; 47305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 47405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka defaultPreview = Bitmap.createBitmap(previewWidth, previewHeight, 47505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Config.ARGB_8888); 47605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Canvas c = mCachedAppWidgetPreviewCanvas.get(); 47705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(defaultPreview); 47805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewDrawable.setBounds(0, 0, previewWidth, previewHeight); 47905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewDrawable.setTileModeXY(Shader.TileMode.REPEAT, 48005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Shader.TileMode.REPEAT); 48105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewDrawable.draw(c); 48205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 48305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 48405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Draw the icon in the top left corner 48505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int minOffset = (int) (mAppIconSize * sWidgetPreviewIconPaddingPercentage); 48605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int smallestSide = Math.min(previewWidth, previewHeight); 48705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka float iconScale = Math.min((float) smallestSide 48805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka / (mAppIconSize + 2 * minOffset), 1f); 48905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 49005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka try { 49105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable icon = null; 49205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int hoffset = 49305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka (int) ((previewDrawableWidth - mAppIconSize * iconScale) / 2); 49405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int yoffset = 49505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2); 49605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (iconId > 0) 49705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka icon = mIconCache.getFullResIcon(packageName, iconId); 49805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (icon != null) { 49905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka renderDrawableToBitmap(icon, defaultPreview, hoffset, 50005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka yoffset, (int) (mAppIconSize * iconScale), 50105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka (int) (mAppIconSize * iconScale)); 50205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 50305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } catch (Resources.NotFoundException e) { 50405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 50505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 50605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 50705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Scale to fit width only - let the widget preview be clipped in the 50805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // vertical dimension 50905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka float scale = 1f; 51005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preScaledWidthOut != null) { 51105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preScaledWidthOut[0] = previewWidth; 51205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 51305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (previewWidth > maxPreviewWidth) { 51405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka scale = maxPreviewWidth / (float) previewWidth; 51505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 51605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (scale != 1f) { 51705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewWidth = (int) (scale * previewWidth); 51805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = (int) (scale * previewHeight); 51905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 52005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 52105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // If a bitmap is passed in, we use it; otherwise, we create a bitmap of the right size 52205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview == null) { 52305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888); 52405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 52505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 52605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Draw the scaled preview into the final bitmap 52705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int x = (preview.getWidth() - previewWidth) / 2; 52805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (widgetPreviewExists) { 52905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka renderDrawableToBitmap(drawable, preview, x, 0, previewWidth, 53005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight); 53105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 53205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Canvas c = mCachedAppWidgetPreviewCanvas.get(); 53305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Rect src = mCachedAppWidgetPreviewSrcRect.get(); 53405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Rect dest = mCachedAppWidgetPreviewDestRect.get(); 53505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(preview); 53605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka src.set(0, 0, defaultPreview.getWidth(), defaultPreview.getHeight()); 537e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka dest.set(x, 0, x + previewWidth, previewHeight); 53805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 53905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Paint p = mCachedAppWidgetPreviewPaint.get(); 54005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (p == null) { 54105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka p = new Paint(); 54205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka p.setFilterBitmap(true); 54305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mCachedAppWidgetPreviewPaint.set(p); 54405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 54505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.drawBitmap(defaultPreview, src, dest, p); 54605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 54705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 54805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 54905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 55005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 55105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private Bitmap generateShortcutPreview( 55205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ResolveInfo info, int maxWidth, int maxHeight, Bitmap preview) { 55305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap tempBitmap = mCachedShortcutPreviewBitmap.get(); 55405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Canvas c = mCachedShortcutPreviewCanvas.get(); 55505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (tempBitmap == null || 55605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka tempBitmap.getWidth() != maxWidth || 55705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka tempBitmap.getHeight() != maxHeight) { 55805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka tempBitmap = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888); 55905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mCachedShortcutPreviewBitmap.set(tempBitmap); 56005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 56105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(tempBitmap); 56205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.drawColor(0, PorterDuff.Mode.CLEAR); 56305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 56405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 56505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Render the icon 56605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable icon = mIconCache.getFullResIcon(info); 56705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 56805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int paddingTop = mContext. 56905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top); 57005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int paddingLeft = mContext. 57105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left); 57205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int paddingRight = mContext. 57305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right); 57405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 57505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int scaledIconWidth = (maxWidth - paddingLeft - paddingRight); 57605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 57705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka renderDrawableToBitmap( 57805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka icon, tempBitmap, paddingLeft, paddingTop, scaledIconWidth, scaledIconWidth); 57905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 58005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview != null && 58105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka (preview.getWidth() != maxWidth || preview.getHeight() != maxHeight)) { 58205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka throw new RuntimeException("Improperly sized bitmap passed as argument"); 58305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else if (preview == null) { 58405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888); 58505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 58605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 58705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(preview); 58805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Draw a desaturated/scaled version of the icon in the background as a watermark 58905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Paint p = mCachedShortcutPreviewPaint.get(); 59005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (p == null) { 59105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka p = new Paint(); 59205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ColorMatrix colorMatrix = new ColorMatrix(); 59305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka colorMatrix.setSaturation(0); 59405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka p.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); 59505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka p.setAlpha((int) (255 * 0.06f)); 59605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mCachedShortcutPreviewPaint.set(p); 59705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 59805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.drawBitmap(tempBitmap, 0, 0, p); 59905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 60005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 60105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka renderDrawableToBitmap(icon, preview, 0, 0, mAppIconSize, mAppIconSize); 60205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 60305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 60405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 60505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 60605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 60705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public static void renderDrawableToBitmap( 60805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable d, Bitmap bitmap, int x, int y, int w, int h) { 60905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka renderDrawableToBitmap(d, bitmap, x, y, w, h, 1f); 61005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 61105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 61205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private static void renderDrawableToBitmap( 61305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable d, Bitmap bitmap, int x, int y, int w, int h, 61405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka float scale) { 61505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (bitmap != null) { 61605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Canvas c = new Canvas(bitmap); 61705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.scale(scale, scale); 61805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Rect oldBounds = d.copyBounds(); 61905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka d.setBounds(x, y, x + w, y + h); 62005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka d.draw(c); 62105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka d.setBounds(oldBounds); // Restore the bounds 62205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 62305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 62405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 62505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 62605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 627