WidgetPreviewLoader.java revision fa9ffc28fd4d230cf38b55840238f5595716abc8
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; 78ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurkaimport android.content.SharedPreferences; 805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.pm.PackageManager; 905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.pm.ResolveInfo; 1005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.res.Resources; 1105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.Cursor; 121f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roosimport android.database.sqlite.SQLiteCantOpenDatabaseException; 1305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.sqlite.SQLiteDatabase; 146e27f642ae66dd1920b25b527fced7268943d11aMichael Jurkaimport android.database.sqlite.SQLiteDiskIOException; 1505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.sqlite.SQLiteOpenHelper; 1605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Bitmap; 1705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Bitmap.Config; 1805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.BitmapFactory; 19fa4c799a9bc6b2eb55ce21609591d49f5c5ea9baAdrian Roosimport android.graphics.BitmapShader; 2005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Canvas; 2105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.ColorMatrix; 2205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.ColorMatrixColorFilter; 2305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Paint; 2405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.PorterDuff; 2505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Rect; 2605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Shader; 2705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.drawable.BitmapDrawable; 2805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.drawable.Drawable; 2905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.os.AsyncTask; 3005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.util.Log; 3105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 3205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.io.ByteArrayOutputStream; 3305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.io.File; 341f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roosimport java.io.IOException; 3505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.lang.ref.SoftReference; 3605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.lang.ref.WeakReference; 3705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.ArrayList; 381f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roosimport java.util.Arrays; 3905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.HashMap; 4005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.HashSet; 411f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roosimport java.util.List; 4265d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roosimport java.util.concurrent.Callable; 4365d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roosimport java.util.concurrent.ExecutionException; 4405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaabstract class SoftReferenceThreadLocal<T> { 4605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private ThreadLocal<SoftReference<T>> mThreadLocal; 4705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public SoftReferenceThreadLocal() { 4805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mThreadLocal = new ThreadLocal<SoftReference<T>>(); 4905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 5005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 5105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka abstract T initialValue(); 5205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 5305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public void set(T t) { 5405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mThreadLocal.set(new SoftReference<T>(t)); 5505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 5605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 5705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public T get() { 5805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka SoftReference<T> reference = mThreadLocal.get(); 5905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka T obj; 6005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (reference == null) { 6105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka obj = initialValue(); 6205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mThreadLocal.set(new SoftReference<T>(obj)); 6305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return obj; 6405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 6505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka obj = reference.get(); 6605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (obj == null) { 6705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka obj = initialValue(); 6805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mThreadLocal.set(new SoftReference<T>(obj)); 6905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 7005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return obj; 7105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 7205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 7305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 7405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 7505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaclass CanvasCache extends SoftReferenceThreadLocal<Canvas> { 7605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 7705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka protected Canvas initialValue() { 7805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return new Canvas(); 7905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 8005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 8105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 8205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaclass PaintCache extends SoftReferenceThreadLocal<Paint> { 8305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 8405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka protected Paint initialValue() { 8505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 8605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 8705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 8805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 8905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaclass BitmapCache extends SoftReferenceThreadLocal<Bitmap> { 9005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 9105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka protected Bitmap initialValue() { 9205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 9305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 9405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 9505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 9605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaclass RectCache extends SoftReferenceThreadLocal<Rect> { 9705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 9805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka protected Rect initialValue() { 9905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return new Rect(); 10005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 10105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 10205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 10305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaclass BitmapFactoryOptionsCache extends SoftReferenceThreadLocal<BitmapFactory.Options> { 10405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 10505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka protected BitmapFactory.Options initialValue() { 10605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return new BitmapFactory.Options(); 10705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 10805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 10905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 11005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkapublic class WidgetPreviewLoader { 11105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka static final String TAG = "WidgetPreviewLoader"; 1128ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka static final String ANDROID_INCREMENTAL_VERSION_NAME_KEY = "android.incremental.version"; 11305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1143f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka private int mPreviewBitmapWidth; 1153f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka private int mPreviewBitmapHeight; 11605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private String mSize; 11705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private Context mContext; 11805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private PackageManager mPackageManager; 11905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private PagedViewCellLayout mWidgetSpacingLayout; 12005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 12105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Used for drawing shortcut previews 12205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private BitmapCache mCachedShortcutPreviewBitmap = new BitmapCache(); 12305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private PaintCache mCachedShortcutPreviewPaint = new PaintCache(); 12405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private CanvasCache mCachedShortcutPreviewCanvas = new CanvasCache(); 12505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 12605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Used for drawing widget previews 12705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private CanvasCache mCachedAppWidgetPreviewCanvas = new CanvasCache(); 12805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private RectCache mCachedAppWidgetPreviewSrcRect = new RectCache(); 12905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private RectCache mCachedAppWidgetPreviewDestRect = new RectCache(); 13005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private PaintCache mCachedAppWidgetPreviewPaint = new PaintCache(); 131fa4c799a9bc6b2eb55ce21609591d49f5c5ea9baAdrian Roos private PaintCache mDefaultAppWidgetPreviewPaint = new PaintCache(); 13205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private String mCachedSelectQuery; 13305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private BitmapFactoryOptionsCache mCachedBitmapFactoryOptions = new BitmapFactoryOptionsCache(); 13405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 13505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private int mAppIconSize; 13605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private IconCache mIconCache; 13705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1385d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos private static final float sWidgetPreviewIconPaddingPercentage = 0.25f; 13905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 140d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka private CacheDb mDb; 14105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1425d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos private final HashMap<String, WeakReference<Bitmap>> mLoadedPreviews; 1435d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos private final ArrayList<SoftReference<Bitmap>> mUnusedBitmaps; 1445d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos private final static HashSet<String> sInvalidPackages; 14505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 14665d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor(); 14765d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos 14805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka static { 14905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sInvalidPackages = new HashSet<String>(); 15005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 15105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 152fd13c714f412dfa8130fa7a664cb1692a565c539Chris Wren public WidgetPreviewLoader(Context context) { 1535f8afe6280eae34620067696173e71943e1a30a3Winson Chung LauncherAppState app = LauncherAppState.getInstance(); 1545f8afe6280eae34620067696173e71943e1a30a3Winson Chung DeviceProfile grid = app.getDynamicGrid().getDeviceProfile(); 1555f8afe6280eae34620067696173e71943e1a30a3Winson Chung 156fd13c714f412dfa8130fa7a664cb1692a565c539Chris Wren mContext = context; 15705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mPackageManager = mContext.getPackageManager(); 1585f8afe6280eae34620067696173e71943e1a30a3Winson Chung mAppIconSize = grid.iconSizePx; 159d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka mIconCache = app.getIconCache(); 160d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka mDb = app.getWidgetPreviewCacheDb(); 1613f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mLoadedPreviews = new HashMap<String, WeakReference<Bitmap>>(); 1623f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mUnusedBitmaps = new ArrayList<SoftReference<Bitmap>>(); 1638ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka 1648ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka SharedPreferences sp = context.getSharedPreferences( 1658ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE); 1668ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka final String lastVersionName = sp.getString(ANDROID_INCREMENTAL_VERSION_NAME_KEY, null); 1678ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka final String versionName = android.os.Build.VERSION.INCREMENTAL; 1688ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka if (!versionName.equals(lastVersionName)) { 1698ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka // clear all the previews whenever the system version changes, to ensure that previews 1708ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka // are up-to-date for any apps that might have been updated with the system 1718ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka clearDb(); 1728ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka 1738ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka SharedPreferences.Editor editor = sp.edit(); 1748ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka editor.putString(ANDROID_INCREMENTAL_VERSION_NAME_KEY, versionName); 1758ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka editor.commit(); 1768ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka } 1773f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka } 1786e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka 1796e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka public void recreateDb() { 1806e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka LauncherAppState app = LauncherAppState.getInstance(); 1816e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka app.recreateWidgetPreviewDb(); 1826e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka mDb = app.getWidgetPreviewCacheDb(); 1836e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 1843f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka 1853f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka public void setPreviewSize(int previewWidth, int previewHeight, 1863f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka PagedViewCellLayout widgetSpacingLayout) { 1873f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mPreviewBitmapWidth = previewWidth; 1883f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mPreviewBitmapHeight = previewHeight; 1893f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mSize = previewWidth + "x" + previewHeight; 1903f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mWidgetSpacingLayout = widgetSpacingLayout; 19105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 19205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 19305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Bitmap getPreview(final Object o) { 194eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka final String name = getObjectName(o); 195eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka final String packageName = getObjectPackage(o); 19605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // check if the package is valid 19705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka synchronized(sInvalidPackages) { 1985d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos boolean packageValid = !sInvalidPackages.contains(packageName); 1995d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos if (!packageValid) { 2005d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos return null; 2015d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos } 20205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 2035d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos synchronized(mLoadedPreviews) { 2045d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos // check if it exists in our existing cache 2055d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos if (mLoadedPreviews.containsKey(name)) { 2065d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos WeakReference<Bitmap> bitmapReference = mLoadedPreviews.get(name); 2075d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos Bitmap bitmap = bitmapReference.get(); 2085d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos if (bitmap != null) { 2095d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos return bitmap; 21005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 21105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 21205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 21305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 21405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap unusedBitmap = null; 2153f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka synchronized(mUnusedBitmaps) { 21605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // not in cache; we need to load it from the db 2175d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos while (unusedBitmap == null && mUnusedBitmaps.size() > 0) { 2185d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos Bitmap candidate = mUnusedBitmaps.remove(0).get(); 2195d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos if (candidate != null && candidate.isMutable() && 2205d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos candidate.getWidth() == mPreviewBitmapWidth && 2215d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos candidate.getHeight() == mPreviewBitmapHeight) { 2225d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos unusedBitmap = candidate; 2235d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos } 22405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 22505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (unusedBitmap != null) { 22605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Canvas c = mCachedAppWidgetPreviewCanvas.get(); 22705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(unusedBitmap); 22805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.drawColor(0, PorterDuff.Mode.CLEAR); 22905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 23005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 23105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 23205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 23305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (unusedBitmap == null) { 2343f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka unusedBitmap = Bitmap.createBitmap(mPreviewBitmapWidth, mPreviewBitmapHeight, 23505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap.Config.ARGB_8888); 23605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 2375d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos Bitmap preview = readFromDb(name, unusedBitmap); 23805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 23905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview != null) { 2403f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka synchronized(mLoadedPreviews) { 2413f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mLoadedPreviews.put(name, new WeakReference<Bitmap>(preview)); 24205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 24305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 24405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 24505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // it's not in the db... we need to generate it 24605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Bitmap generatedPreview = generatePreview(o, unusedBitmap); 24705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview = generatedPreview; 24805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview != unusedBitmap) { 24905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka throw new RuntimeException("generatePreview is not recycling the bitmap " + o); 25005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 25105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 2523f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka synchronized(mLoadedPreviews) { 2533f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mLoadedPreviews.put(name, new WeakReference<Bitmap>(preview)); 25405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 25505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 25605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // write to db on a thread pool... this can be done lazily and improves the performance 25705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // of the first time widget previews are loaded 25805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka new AsyncTask<Void, Void, Void>() { 25905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Void doInBackground(Void ... args) { 26005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka writeToDb(o, generatedPreview); 26105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 26205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 26305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); 26405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 26505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 26605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 26705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 26805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 269ee8e99fe3bde78885904b4d9ea789b4d2a6f2b16Michael Jurka public void recycleBitmap(Object o, Bitmap bitmapToRecycle) { 27005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka String name = getObjectName(o); 2715140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka synchronized (mLoadedPreviews) { 2725140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka if (mLoadedPreviews.containsKey(name)) { 2733f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka Bitmap b = mLoadedPreviews.get(name).get(); 274ee8e99fe3bde78885904b4d9ea789b4d2a6f2b16Michael Jurka if (b == bitmapToRecycle) { 2753f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka mLoadedPreviews.remove(name); 276ee8e99fe3bde78885904b4d9ea789b4d2a6f2b16Michael Jurka if (bitmapToRecycle.isMutable()) { 2775140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka synchronized (mUnusedBitmaps) { 2785140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka mUnusedBitmaps.add(new SoftReference<Bitmap>(b)); 2795140cfaf471ed21c1cdcf0edcb53ae89b87c6848Michael Jurka } 28005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 28105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 28205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka throw new RuntimeException("Bitmap passed in doesn't match up"); 28305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 28405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 28505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 28605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 28705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 288d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka static class CacheDb extends SQLiteOpenHelper { 289e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka final static int DB_VERSION = 2; 29005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String DB_NAME = "widgetpreviews.db"; 29105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String TABLE_NAME = "shortcut_and_widget_previews"; 29205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String COLUMN_NAME = "name"; 29305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String COLUMN_SIZE = "size"; 29405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final static String COLUMN_PREVIEW_BITMAP = "preview_bitmap"; 29505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Context mContext; 29605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 297d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka public CacheDb(Context context) { 29805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka super(context, new File(context.getCacheDir(), DB_NAME).getPath(), null, DB_VERSION); 29905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Store the context for later use 30005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mContext = context; 30105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 30205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 30305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 30405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public void onCreate(SQLiteDatabase database) { 30532b7a097338b77d8999c706c42f19e8ba060ba62Michael Jurka database.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + 30605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka COLUMN_NAME + " TEXT NOT NULL, " + 30705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka COLUMN_SIZE + " TEXT NOT NULL, " + 30805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka COLUMN_PREVIEW_BITMAP + " BLOB NOT NULL, " + 30905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka "PRIMARY KEY (" + COLUMN_NAME + ", " + COLUMN_SIZE + ") " + 31032b7a097338b77d8999c706c42f19e8ba060ba62Michael Jurka ");"); 31105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 31205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 31305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 31405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 315e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka if (oldVersion != newVersion) { 316e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka // Delete all the records; they'll be repopulated as this is a cache 317e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka db.execSQL("DELETE FROM " + TABLE_NAME); 318e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka } 31905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 32005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 32105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 32205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private static final String WIDGET_PREFIX = "Widget:"; 32305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private static final String SHORTCUT_PREFIX = "Shortcut:"; 32405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 32505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private static String getObjectName(Object o) { 32605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // should cache the string builder 32705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka StringBuilder sb = new StringBuilder(); 32805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka String output; 32905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (o instanceof AppWidgetProviderInfo) { 33005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.append(WIDGET_PREFIX); 33105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.append(((AppWidgetProviderInfo) o).provider.flattenToString()); 33205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka output = sb.toString(); 33305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.setLength(0); 33405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 33505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.append(SHORTCUT_PREFIX); 33605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 33705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ResolveInfo info = (ResolveInfo) o; 33805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.append(new ComponentName(info.activityInfo.packageName, 33905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka info.activityInfo.name).flattenToString()); 34005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka output = sb.toString(); 34105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sb.setLength(0); 34205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 34305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return output; 34405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 34505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 34605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private String getObjectPackage(Object o) { 34705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (o instanceof AppWidgetProviderInfo) { 34805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return ((AppWidgetProviderInfo) o).provider.getPackageName(); 34905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 35005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ResolveInfo info = (ResolveInfo) o; 35105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return info.activityInfo.packageName; 35205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 35305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 35405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 35505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private void writeToDb(Object o, Bitmap preview) { 35605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka String name = getObjectName(o); 35705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka SQLiteDatabase db = mDb.getWritableDatabase(); 35805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ContentValues values = new ContentValues(); 35905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 360d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka values.put(CacheDb.COLUMN_NAME, name); 36105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ByteArrayOutputStream stream = new ByteArrayOutputStream(); 36205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview.compress(Bitmap.CompressFormat.PNG, 100, stream); 363d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka values.put(CacheDb.COLUMN_PREVIEW_BITMAP, stream.toByteArray()); 364d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka values.put(CacheDb.COLUMN_SIZE, mSize); 3656e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 3666e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka db.insert(CacheDb.TABLE_NAME, null, values); 3676e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } catch (SQLiteDiskIOException e) { 3686e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka recreateDb(); 3691f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (SQLiteCantOpenDatabaseException e) { 3701f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos dumpOpenFiles(); 3711f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos throw e; 3726e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 37305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 37405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 3758ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka private void clearDb() { 3768ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka SQLiteDatabase db = mDb.getWritableDatabase(); 3778ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka // Delete everything 3786e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 3796e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka db.delete(CacheDb.TABLE_NAME, null, null); 3806e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } catch (SQLiteDiskIOException e) { 3811f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (SQLiteCantOpenDatabaseException e) { 3821f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos dumpOpenFiles(); 3831f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos throw e; 3846e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 3858ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka } 3868ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka 387eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka public static void removePackageFromDb(final CacheDb cacheDb, final String packageName) { 38805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka synchronized(sInvalidPackages) { 38905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sInvalidPackages.add(packageName); 39005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 39105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka new AsyncTask<Void, Void, Void>() { 39205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Void doInBackground(Void ... args) { 393d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka SQLiteDatabase db = cacheDb.getWritableDatabase(); 3946e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 3956e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka db.delete(CacheDb.TABLE_NAME, 3966e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka CacheDb.COLUMN_NAME + " LIKE ? OR " + 3976e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka CacheDb.COLUMN_NAME + " LIKE ?", // SELECT query 3986e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka new String[] { 3996e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka WIDGET_PREFIX + packageName + "/%", 4006e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka SHORTCUT_PREFIX + packageName + "/%" 4016e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } // args to SELECT query 4026e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka ); 4036e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } catch (SQLiteDiskIOException e) { 4041f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (SQLiteCantOpenDatabaseException e) { 4051f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos dumpOpenFiles(); 4061f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos throw e; 4076e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 40805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka synchronized(sInvalidPackages) { 40905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka sInvalidPackages.remove(packageName); 41005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 41105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 41205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 41305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); 41405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 41505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 416eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka public static void removeItemFromDb(final CacheDb cacheDb, final String objectName) { 417eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka new AsyncTask<Void, Void, Void>() { 418eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka public Void doInBackground(Void ... args) { 419eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka SQLiteDatabase db = cacheDb.getWritableDatabase(); 4206e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 4216e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka db.delete(CacheDb.TABLE_NAME, 4226e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka CacheDb.COLUMN_NAME + " = ? ", // SELECT query 4236e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka new String[] { objectName }); // args to SELECT query 4246e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } catch (SQLiteDiskIOException e) { 4251f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (SQLiteCantOpenDatabaseException e) { 4261f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos dumpOpenFiles(); 4271f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos throw e; 4286e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 429eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka return null; 430eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 431eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null); 432eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 433eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka 43405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private Bitmap readFromDb(String name, Bitmap b) { 43505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (mCachedSelectQuery == null) { 436d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka mCachedSelectQuery = CacheDb.COLUMN_NAME + " = ? AND " + 437d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka CacheDb.COLUMN_SIZE + " = ?"; 43805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 43905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka SQLiteDatabase db = mDb.getReadableDatabase(); 4406e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka Cursor result; 4416e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 4426e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka result = db.query(CacheDb.TABLE_NAME, 4436e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka new String[] { CacheDb.COLUMN_PREVIEW_BITMAP }, // cols to return 4446e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka mCachedSelectQuery, // select query 4456e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka new String[] { name, mSize }, // args to select query 4466e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka null, 4476e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka null, 4486e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka null, 4496e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka null); 4506e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } catch (SQLiteDiskIOException e) { 4516e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka recreateDb(); 4526e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka return null; 4531f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (SQLiteCantOpenDatabaseException e) { 4541f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos dumpOpenFiles(); 4551f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos throw e; 4566e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 45705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (result.getCount() > 0) { 45805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka result.moveToFirst(); 45905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka byte[] blob = result.getBlob(0); 46005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka result.close(); 46105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final BitmapFactory.Options opts = mCachedBitmapFactoryOptions.get(); 46205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka opts.inBitmap = b; 46305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka opts.inSampleSize = 1; 464eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka try { 465eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka return BitmapFactory.decodeByteArray(blob, 0, blob.length, opts); 466eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } catch (IllegalArgumentException e) { 467eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka removeItemFromDb(mDb, name); 468eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka return null; 469eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 47005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 47105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka result.close(); 47205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return null; 47305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 47405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 47505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 47605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Bitmap generatePreview(Object info, Bitmap preview) { 47705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview != null && 4783f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka (preview.getWidth() != mPreviewBitmapWidth || 4793f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka preview.getHeight() != mPreviewBitmapHeight)) { 48005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka throw new RuntimeException("Improperly sized bitmap passed as argument"); 48105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 48205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (info instanceof AppWidgetProviderInfo) { 48305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return generateWidgetPreview((AppWidgetProviderInfo) info, preview); 48405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 48505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return generateShortcutPreview( 4863f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka (ResolveInfo) info, mPreviewBitmapWidth, mPreviewBitmapHeight, preview); 48705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 48805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 48905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 49005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Bitmap generateWidgetPreview(AppWidgetProviderInfo info, Bitmap preview) { 491fd13c714f412dfa8130fa7a664cb1692a565c539Chris Wren int[] cellSpans = Launcher.getSpanForWidget(mContext, info); 49205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int maxWidth = maxWidthForWidgetPreview(cellSpans[0]); 49305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int maxHeight = maxHeightForWidgetPreview(cellSpans[1]); 49405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return generateWidgetPreview(info.provider, info.previewImage, info.icon, 49505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka cellSpans[0], cellSpans[1], maxWidth, maxHeight, preview, null); 49605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 49705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 49805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public int maxWidthForWidgetPreview(int spanX) { 4993f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka return Math.min(mPreviewBitmapWidth, 50005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mWidgetSpacingLayout.estimateCellWidth(spanX)); 50105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 50205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 50305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public int maxHeightForWidgetPreview(int spanY) { 5043f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka return Math.min(mPreviewBitmapHeight, 50505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mWidgetSpacingLayout.estimateCellHeight(spanY)); 50605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 50705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 50805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public Bitmap generateWidgetPreview(ComponentName provider, int previewImage, 50905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int iconId, int cellHSpan, int cellVSpan, int maxPreviewWidth, int maxPreviewHeight, 51005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap preview, int[] preScaledWidthOut) { 51105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Load the preview image if possible 51205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka String packageName = provider.getPackageName(); 51305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE; 51405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (maxPreviewHeight < 0) maxPreviewHeight = Integer.MAX_VALUE; 51505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 51605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable drawable = null; 51705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (previewImage != 0) { 518fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos drawable = mPackageManager.getDrawable(packageName, previewImage, null); 519fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos if (drawable != null) { 520fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos drawable = mutateOnMainThread(drawable); 521fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos } else { 52205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Log.w(TAG, "Can't load widget preview drawable 0x" + 52305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Integer.toHexString(previewImage) + " for provider: " + provider); 52405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 52505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 52605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 52705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int previewWidth; 52805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int previewHeight; 52905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap defaultPreview = null; 53005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka boolean widgetPreviewExists = (drawable != null); 53105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (widgetPreviewExists) { 53205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewWidth = drawable.getIntrinsicWidth(); 53305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = drawable.getIntrinsicHeight(); 53405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 53505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Generate a preview image if we couldn't load one 53605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (cellHSpan < 1) cellHSpan = 1; 53705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (cellVSpan < 1) cellVSpan = 1; 53805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 53965d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos // This Drawable is not directly drawn, so there's no need to mutate it. 54005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka BitmapDrawable previewDrawable = (BitmapDrawable) mContext.getResources() 5416706ed826600683cd66a7a2af79137d9fdda34f8Winson Chung .getDrawable(R.drawable.widget_tile); 54205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final int previewDrawableWidth = previewDrawable 54305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka .getIntrinsicWidth(); 54405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final int previewDrawableHeight = previewDrawable 54505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka .getIntrinsicHeight(); 54645cab39eea097bf622cd1ed67d91d2336d78663aWinson Chung previewWidth = previewDrawableWidth * cellHSpan; 54705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = previewDrawableHeight * cellVSpan; 54805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 5495d2704fbb0a7bb4763d4e2ee031e16a8913ba003Adrian Roos defaultPreview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888); 55005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Canvas c = mCachedAppWidgetPreviewCanvas.get(); 55105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(defaultPreview); 552fa4c799a9bc6b2eb55ce21609591d49f5c5ea9baAdrian Roos Paint p = mDefaultAppWidgetPreviewPaint.get(); 553fa4c799a9bc6b2eb55ce21609591d49f5c5ea9baAdrian Roos if (p == null) { 554fa4c799a9bc6b2eb55ce21609591d49f5c5ea9baAdrian Roos p = new Paint(); 555fa4c799a9bc6b2eb55ce21609591d49f5c5ea9baAdrian Roos p.setShader(new BitmapShader(previewDrawable.getBitmap(), 556fa4c799a9bc6b2eb55ce21609591d49f5c5ea9baAdrian Roos Shader.TileMode.REPEAT, Shader.TileMode.REPEAT)); 557fa4c799a9bc6b2eb55ce21609591d49f5c5ea9baAdrian Roos mDefaultAppWidgetPreviewPaint.set(p); 558fa4c799a9bc6b2eb55ce21609591d49f5c5ea9baAdrian Roos } 559fa4c799a9bc6b2eb55ce21609591d49f5c5ea9baAdrian Roos final Rect dest = mCachedAppWidgetPreviewDestRect.get(); 560fa4c799a9bc6b2eb55ce21609591d49f5c5ea9baAdrian Roos dest.set(0, 0, previewWidth, previewHeight); 561fa4c799a9bc6b2eb55ce21609591d49f5c5ea9baAdrian Roos c.drawRect(dest, p); 56205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 56305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 56405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Draw the icon in the top left corner 56505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int minOffset = (int) (mAppIconSize * sWidgetPreviewIconPaddingPercentage); 56605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int smallestSide = Math.min(previewWidth, previewHeight); 56705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka float iconScale = Math.min((float) smallestSide 56805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka / (mAppIconSize + 2 * minOffset), 1f); 56905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 57005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka try { 57105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable icon = null; 57205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int hoffset = 57305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka (int) ((previewDrawableWidth - mAppIconSize * iconScale) / 2); 57405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int yoffset = 57505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka (int) ((previewDrawableHeight - mAppIconSize * iconScale) / 2); 576fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos if (iconId > 0) { 577fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos icon = mIconCache.getFullResIcon(packageName, iconId); 578fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos } 57905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (icon != null) { 580fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos icon = mutateOnMainThread(icon); 58105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka renderDrawableToBitmap(icon, defaultPreview, hoffset, 58205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka yoffset, (int) (mAppIconSize * iconScale), 58305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka (int) (mAppIconSize * iconScale)); 58405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 58505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } catch (Resources.NotFoundException e) { 58605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 58705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 58805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 58905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Scale to fit width only - let the widget preview be clipped in the 59005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // vertical dimension 59105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka float scale = 1f; 59205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preScaledWidthOut != null) { 59305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preScaledWidthOut[0] = previewWidth; 59405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 59505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (previewWidth > maxPreviewWidth) { 59605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka scale = maxPreviewWidth / (float) previewWidth; 59705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 59805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (scale != 1f) { 59905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewWidth = (int) (scale * previewWidth); 60005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = (int) (scale * previewHeight); 60105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 60205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 60305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // If a bitmap is passed in, we use it; otherwise, we create a bitmap of the right size 60405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview == null) { 60505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888); 60605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 60705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 60805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Draw the scaled preview into the final bitmap 60905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int x = (preview.getWidth() - previewWidth) / 2; 61005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (widgetPreviewExists) { 61105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka renderDrawableToBitmap(drawable, preview, x, 0, previewWidth, 61205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight); 61305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 61405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Canvas c = mCachedAppWidgetPreviewCanvas.get(); 61505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Rect src = mCachedAppWidgetPreviewSrcRect.get(); 61605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Rect dest = mCachedAppWidgetPreviewDestRect.get(); 61705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(preview); 61805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka src.set(0, 0, defaultPreview.getWidth(), defaultPreview.getHeight()); 619e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka dest.set(x, 0, x + previewWidth, previewHeight); 62005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 62105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Paint p = mCachedAppWidgetPreviewPaint.get(); 62205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (p == null) { 62305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka p = new Paint(); 62405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka p.setFilterBitmap(true); 62505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mCachedAppWidgetPreviewPaint.set(p); 62605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 62705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.drawBitmap(defaultPreview, src, dest, p); 62805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 62905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 63005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 63105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 63205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 63305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private Bitmap generateShortcutPreview( 63405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ResolveInfo info, int maxWidth, int maxHeight, Bitmap preview) { 63505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Bitmap tempBitmap = mCachedShortcutPreviewBitmap.get(); 63605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka final Canvas c = mCachedShortcutPreviewCanvas.get(); 63705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (tempBitmap == null || 63805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka tempBitmap.getWidth() != maxWidth || 63905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka tempBitmap.getHeight() != maxHeight) { 64005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka tempBitmap = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888); 64105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mCachedShortcutPreviewBitmap.set(tempBitmap); 64205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 64305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(tempBitmap); 64405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.drawColor(0, PorterDuff.Mode.CLEAR); 64505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 64605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 64705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Render the icon 64865d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info)); 64905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 65005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int paddingTop = mContext. 65105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top); 65205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int paddingLeft = mContext. 65305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left); 65405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int paddingRight = mContext. 65505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka getResources().getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right); 65605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 65705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int scaledIconWidth = (maxWidth - paddingLeft - paddingRight); 65805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 65905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka renderDrawableToBitmap( 66005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka icon, tempBitmap, paddingLeft, paddingTop, scaledIconWidth, scaledIconWidth); 66105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 66205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview != null && 66305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka (preview.getWidth() != maxWidth || preview.getHeight() != maxHeight)) { 66405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka throw new RuntimeException("Improperly sized bitmap passed as argument"); 66505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else if (preview == null) { 66605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888); 66705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 66805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 66905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(preview); 67005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Draw a desaturated/scaled version of the icon in the background as a watermark 67105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Paint p = mCachedShortcutPreviewPaint.get(); 67205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (p == null) { 67305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka p = new Paint(); 67405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ColorMatrix colorMatrix = new ColorMatrix(); 67505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka colorMatrix.setSaturation(0); 67605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka p.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); 67705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka p.setAlpha((int) (255 * 0.06f)); 67805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka mCachedShortcutPreviewPaint.set(p); 67905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 68005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.drawBitmap(tempBitmap, 0, 0, p); 68105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 68205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 68305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka renderDrawableToBitmap(icon, preview, 0, 0, mAppIconSize, mAppIconSize); 68405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 68505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 68605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 68705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 68805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 68905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public static void renderDrawableToBitmap( 69005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable d, Bitmap bitmap, int x, int y, int w, int h) { 69105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka renderDrawableToBitmap(d, bitmap, x, y, w, h, 1f); 69205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 69305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 69405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private static void renderDrawableToBitmap( 69505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable d, Bitmap bitmap, int x, int y, int w, int h, 69605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka float scale) { 69705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (bitmap != null) { 69805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Canvas c = new Canvas(bitmap); 69905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.scale(scale, scale); 70005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Rect oldBounds = d.copyBounds(); 70105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka d.setBounds(x, y, x + w, y + h); 70205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka d.draw(c); 70305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka d.setBounds(oldBounds); // Restore the bounds 70405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 70505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 70605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 70705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 70865d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos private Drawable mutateOnMainThread(final Drawable drawable) { 70965d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos try { 71065d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos return mMainThreadExecutor.submit(new Callable<Drawable>() { 71165d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos @Override 71265d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos public Drawable call() throws Exception { 71365d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos return drawable.mutate(); 71465d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 71565d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos }).get(); 71665d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } catch (InterruptedException e) { 71765d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos Thread.currentThread().interrupt(); 71865d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos throw new RuntimeException(e); 71965d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } catch (ExecutionException e) { 72065d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos throw new RuntimeException(e); 72165d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 72265d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 7231f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos 7241f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos private static final int MAX_OPEN_FILES = 1024; 7251f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos private static final int SAMPLE_RATE = 23; 7261f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos /** 7271f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos * Dumps all files that are open in this process without allocating a file descriptor. 7281f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos */ 7291f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos private static void dumpOpenFiles() { 7301f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos try { 7311f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos Log.i(TAG, "DUMP OF OPEN FILES (sample rate: 1 every " + SAMPLE_RATE + "):"); 7321f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_APK = "apk"; 7331f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_JAR = "jar"; 7341f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_PIPE = "pipe"; 7351f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_SOCKET = "socket"; 7361f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_DB = "db"; 7371f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_ANON_INODE = "anon_inode"; 7381f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_DEV = "dev"; 7391f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_NON_FS = "non-fs"; 7401f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos final String TYPE_OTHER = "other"; 7411f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos List<String> types = Arrays.asList(TYPE_APK, TYPE_JAR, TYPE_PIPE, TYPE_SOCKET, TYPE_DB, 7421f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos TYPE_ANON_INODE, TYPE_DEV, TYPE_NON_FS, TYPE_OTHER); 7431f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos int[] count = new int[types.size()]; 7441f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos int[] duplicates = new int[types.size()]; 7451f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos HashSet<String> files = new HashSet<String>(); 7461f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos int total = 0; 7471f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos for (int i = 0; i < MAX_OPEN_FILES; i++) { 7481f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // This is a gigantic hack but unfortunately the only way to resolve an fd 7491f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // to a file name. Note that we have to loop over all possible fds because 7501f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // reading the directory would require allocating a new fd. The kernel is 7511f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // currently implemented such that no fd is larger then the current rlimit, 7521f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // which is why it's safe to loop over them in such a way. 7531f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos String fd = "/proc/self/fd/" + i; 7541f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos try { 7551f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // getCanonicalPath() uses readlink behind the scene which doesn't require 7561f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // a file descriptor. 7571f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos String resolved = new File(fd).getCanonicalPath(); 7581f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos int type = types.indexOf(TYPE_OTHER); 7591f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos if (resolved.startsWith("/dev/")) { 7601f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_DEV); 7611f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.endsWith(".apk")) { 7621f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_APK); 7631f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.endsWith(".jar")) { 7641f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_JAR); 7651f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.contains("/fd/pipe:")) { 7661f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_PIPE); 7671f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.contains("/fd/socket:")) { 7681f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_SOCKET); 7691f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.contains("/fd/anon_inode:")) { 7701f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_ANON_INODE); 7711f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.endsWith(".db") || resolved.contains("/databases/")) { 7721f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_DB); 7731f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } else if (resolved.startsWith("/proc/") && resolved.contains("/fd/")) { 7741f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // Those are the files that don't point anywhere on the file system. 7751f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // getCanonicalPath() wrongly interprets these as relative symlinks and 7761f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // resolves them within /proc/<pid>/fd/. 7771f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos type = types.indexOf(TYPE_NON_FS); 7781f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 7791f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos count[type]++; 7801f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos total++; 7811f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos if (files.contains(resolved)) { 7821f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos duplicates[type]++; 7831f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 7841f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos files.add(resolved); 7851f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos if (total % SAMPLE_RATE == 0) { 7861f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos Log.i(TAG, " fd " + i + ": " + resolved 7871f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos + " (" + types.get(type) + ")"); 7881f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 7891f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (IOException e) { 7901f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // Ignoring exceptions for non-existing file descriptors. 7911f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 7921f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 7931f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos for (int i = 0; i < types.size(); i++) { 7941f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos Log.i(TAG, String.format("Open %10s files: %4d total, %4d duplicates", 7951f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos types.get(i), count[i], duplicates[i])); 7961f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 7971f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } catch (Throwable t) { 7981f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos // Catch everything. This is called from an exception handler that we shouldn't upset. 7991f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos Log.e(TAG, "Unable to log open files.", t); 8001f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 8011f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 80205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 803