WidgetPreviewLoader.java revision e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffc
1325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3; 205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.ComponentName; 405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.ContentValues; 505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.Context; 65b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport android.content.pm.PackageInfo; 75b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport android.content.pm.PackageManager.NameNotFoundException; 805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.pm.ResolveInfo; 905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.res.Resources; 1005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.Cursor; 115b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport android.database.SQLException; 1205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.sqlite.SQLiteDatabase; 1305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.sqlite.SQLiteOpenHelper; 1405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Bitmap; 1505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Bitmap.Config; 1605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.BitmapFactory; 1705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Canvas; 1805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.ColorMatrix; 1905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.ColorMatrixColorFilter; 2005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Paint; 2105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.PorterDuff; 2205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.Rect; 234cad7538c9615303d291f5b52e960aaf0985828fSunny Goyalimport android.graphics.RectF; 2405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.drawable.BitmapDrawable; 2505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.graphics.drawable.Drawable; 2605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.os.AsyncTask; 2705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chungimport android.os.Handler; 2805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.util.Log; 295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport android.util.LongSparseArray; 30ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyalimport com.android.launcher3.compat.AppWidgetManagerCompat; 315b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport com.android.launcher3.compat.UserHandleCompat; 325b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport com.android.launcher3.compat.UserManagerCompat; 335b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport com.android.launcher3.util.ComponentKey; 34091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk; 353f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.widget.WidgetCell; 368821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Song 378821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Songimport java.util.ArrayList; 385b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport java.util.Collections; 3905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.HashMap; 4005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.HashSet; 415b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport java.util.Set; 425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport java.util.WeakHashMap; 4365d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roosimport java.util.concurrent.Callable; 4465d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roosimport java.util.concurrent.ExecutionException; 4505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 46ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyalpublic class WidgetPreviewLoader { 4705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 48ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private static final String TAG = "WidgetPreviewLoader"; 493f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song private static final boolean DEBUG = false; 50ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 51ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f; 52ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 535b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final HashMap<String, long[]> mPackageVersions = new HashMap<>(); 54559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song 55559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song /** 56559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song * Weak reference objects, do not prevent their referents from being made finalizable, 57559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song * finalized, and then reclaimed. 58e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song * Note: synchronized block used for this variable is expensive and the block should always 59e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song * be posted to a background thread. 60559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song */ 61316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk Set<Bitmap> mUnusedBitmaps = 62559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>()); 634cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 644cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal private final Context mContext; 65ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private final IconCache mIconCache; 665b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final UserManagerCompat mUserManager; 67ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private final AppWidgetManagerCompat mManager; 685b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final CacheDb mDb; 6941e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song private final int mProfileBadgeMargin; 7005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 7165d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor(); 72316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk final Handler mWorkerHandler; 7365d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos 742e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen public WidgetPreviewLoader(Context context, InvariantDeviceProfile inv, IconCache iconCache) { 75fd13c714f412dfa8130fa7a664cb1692a565c539Chris Wren mContext = context; 765b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mIconCache = iconCache; 77ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal mManager = AppWidgetManagerCompat.getInstance(context); 785b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mUserManager = UserManagerCompat.getInstance(context); 795b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mDb = new CacheDb(context); 8005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mWorkerHandler = new Handler(LauncherModel.getWorkerLooper()); 8141e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song mProfileBadgeMargin = context.getResources() 8241e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song .getDimensionPixelSize(R.dimen.profile_badge_margin); 833f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka } 84ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 855b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal /** 865b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * Generates the widget preview on {@link AsyncTask#THREAD_POOL_EXECUTOR}. Must be 875b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * called on UI thread 885b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * 895b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * @param o either {@link LauncherAppWidgetProviderInfo} or {@link ResolveInfo} 905b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * @return a request id which can be used to cancel the request. 915b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 922e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen public PreviewLoadRequest getPreview(final Object o, int previewWidth, 932e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen int previewHeight, WidgetCell caller) { 945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal String size = previewWidth + "x" + previewHeight; 955b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal WidgetCacheKey key = getObjectKey(o, size); 9605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 975b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal PreviewLoadTask task = new PreviewLoadTask(key, o, previewWidth, previewHeight, caller); 985b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 99559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song return new PreviewLoadRequest(task); 10005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 10105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1025b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal /** 1035b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * The DB holds the generated previews for various components. Previews can also have different 1045b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * sizes (landscape vs portrait). 1055b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 1065b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static class CacheDb extends SQLiteOpenHelper { 1075b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final int DB_VERSION = 3; 1085b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 1095b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String TABLE_NAME = "shortcut_and_widget_previews"; 1105b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_COMPONENT = "componentName"; 1115b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_USER = "profileId"; 1125b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_SIZE = "size"; 1135b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_PACKAGE = "packageName"; 1145b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_LAST_UPDATED = "lastUpdated"; 1155b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_VERSION = "version"; 1165b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_PREVIEW_BITMAP = "preview_bitmap"; 11705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 118d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka public CacheDb(Context context) { 1195b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal super(context, LauncherFiles.WIDGET_PREVIEWS_DB, null, DB_VERSION); 12005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 12105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 12205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 12305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public void onCreate(SQLiteDatabase database) { 12432b7a097338b77d8999c706c42f19e8ba060ba62Michael Jurka database.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + 1255b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_COMPONENT + " TEXT NOT NULL, " + 1265b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_USER + " INTEGER NOT NULL, " + 12705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka COLUMN_SIZE + " TEXT NOT NULL, " + 1285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_PACKAGE + " TEXT NOT NULL, " + 1295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, " + 1305b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, " + 1315b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_PREVIEW_BITMAP + " BLOB, " + 1325b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ", " + COLUMN_SIZE + ") " + 13332b7a097338b77d8999c706c42f19e8ba060ba62Michael Jurka ");"); 13405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 13505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 13605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 13705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 138e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka if (oldVersion != newVersion) { 1395b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal clearDB(db); 140e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka } 14105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 14205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1435b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 1445b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { 1455b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (oldVersion != newVersion) { 1465b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal clearDB(db); 1475b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 1485b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 14905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1505b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private void clearDB(SQLiteDatabase db) { 1515b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); 1525b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal onCreate(db); 15305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 15405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 15505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1565b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private WidgetCacheKey getObjectKey(Object o, String size) { 1575b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // should cache the string builder 1585b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (o instanceof LauncherAppWidgetProviderInfo) { 1595b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) o; 1605b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return new WidgetCacheKey(info.provider, mManager.getUser(info), size); 16105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 16205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ResolveInfo info = (ResolveInfo) o; 1635b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return new WidgetCacheKey( 1645b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal new ComponentName(info.activityInfo.packageName, info.activityInfo.name), 1655b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal UserHandleCompat.myUserHandle(), size); 16605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 16705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 16805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1695b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Thunk void writeToDb(WidgetCacheKey key, long[] versions, Bitmap preview) { 17005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ContentValues values = new ContentValues(); 1715b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_COMPONENT, key.componentName.flattenToShortString()); 1725b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_USER, mUserManager.getSerialNumberForUser(key.user)); 1735b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_SIZE, key.size); 1745b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_PACKAGE, key.componentName.getPackageName()); 1755b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_VERSION, versions[0]); 1765b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_LAST_UPDATED, versions[1]); 1775b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_PREVIEW_BITMAP, Utilities.flattenBitmap(preview)); 17805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1796e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 1805b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mDb.getWritableDatabase().insertWithOnConflict(CacheDb.TABLE_NAME, null, values, 1815b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal SQLiteDatabase.CONFLICT_REPLACE); 1825b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (SQLException e) { 1835b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.e(TAG, "Error saving image to DB", e); 1846e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 18505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 18605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1875b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public void removePackage(String packageName, UserHandleCompat user) { 1885b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal removePackage(packageName, user, mUserManager.getSerialNumberForUser(user)); 1895b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 1905b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 1915b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private void removePackage(String packageName, UserHandleCompat user, long userSerial) { 1925b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal synchronized(mPackageVersions) { 1935b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mPackageVersions.remove(packageName); 1945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 1955b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 1966e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 1975b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mDb.getWritableDatabase().delete(CacheDb.TABLE_NAME, 1985b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal CacheDb.COLUMN_PACKAGE + " = ? AND " + CacheDb.COLUMN_USER + " = ?", 1995b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal new String[] {packageName, Long.toString(userSerial)}); 2005b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (SQLException e) { 2015b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.e(TAG, "Unable to delete items from DB", e); 2026e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 2038ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka } 2048ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka 2055b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal /** 2065b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * Updates the persistent DB: 2075b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * 1. Any preview generated for an old package version is removed 2085b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * 2. Any preview for an absent package is removed 2095b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * This ensures that we remove entries for packages which changed while the launcher was dead. 2105b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 2118821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Song public void removeObsoletePreviews(ArrayList<Object> list) { 2122bd3d7d1cb5e4d8d826982d11b456739fed6b817Hyunyoung Song Utilities.assertWorkerThread(); 2138821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Song 2145b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal LongSparseArray<UserHandleCompat> userIdCache = new LongSparseArray<>(); 2155b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal LongSparseArray<HashSet<String>> validPackages = new LongSparseArray<>(); 2165b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2178821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Song for (Object obj : list) { 2185b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal final UserHandleCompat user; 2195b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal final String pkg; 2205b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (obj instanceof ResolveInfo) { 2215b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal user = UserHandleCompat.myUserHandle(); 2225b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal pkg = ((ResolveInfo) obj).activityInfo.packageName; 2235b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } else { 2245b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) obj; 2255b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal user = mManager.getUser(info); 2265b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal pkg = info.provider.getPackageName(); 2275b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal int userIdIndex = userIdCache.indexOfValue(user); 2305b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal final long userId; 2315b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (userIdIndex < 0) { 2325b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal userId = mUserManager.getSerialNumberForUser(user); 2335b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal userIdCache.put(userId, user); 2345b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } else { 2355b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal userId = userIdCache.keyAt(userIdIndex); 2365b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2375b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2385b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal HashSet<String> packages = validPackages.get(userId); 2395b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (packages == null) { 2405b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages = new HashSet<>(); 2415b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal validPackages.put(userId, packages); 2425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2435b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages.add(pkg); 24405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 2455b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2465b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal LongSparseArray<HashSet<String>> packagesToDelete = new LongSparseArray<>(); 2475b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Cursor c = null; 2485b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal try { 2495b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal c = mDb.getReadableDatabase().query(CacheDb.TABLE_NAME, 2505b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal new String[] {CacheDb.COLUMN_USER, CacheDb.COLUMN_PACKAGE, 2515b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal CacheDb.COLUMN_LAST_UPDATED, CacheDb.COLUMN_VERSION}, 2525b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal null, null, null, null, null); 2535b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal while (c.moveToNext()) { 2545b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long userId = c.getLong(0); 2555b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal String pkg = c.getString(1); 2565b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long lastUpdated = c.getLong(2); 2575b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long version = c.getLong(3); 2585b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2595b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal HashSet<String> packages = validPackages.get(userId); 2605b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (packages != null && packages.contains(pkg)) { 2615b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long[] versions = getPackageVersion(pkg); 2625b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (versions[0] == version && versions[1] == lastUpdated) { 2635b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // Every thing checks out 2645b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal continue; 2655b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2666e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 2675b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2685b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // We need to delete this package. 2695b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages = packagesToDelete.get(userId); 2705b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (packages == null) { 2715b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages = new HashSet<>(); 2725b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packagesToDelete.put(userId, packages); 27305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 2745b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages.add(pkg); 27505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 27605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 2775b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal for (int i = 0; i < packagesToDelete.size(); i++) { 2785b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long userId = packagesToDelete.keyAt(i); 2795b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal UserHandleCompat user = mUserManager.getUserForSerialNumber(userId); 2805b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal for (String pkg : packagesToDelete.valueAt(i)) { 2815b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal removePackage(pkg, user, userId); 2826e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 283eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 2845b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (SQLException e) { 2855b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.e(TAG, "Error updatating widget previews", e); 2865b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } finally { 2875b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (c != null) { 2885b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal c.close(); 2895b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2905b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 291eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 292eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka 29305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung /** 29405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung * Reads the preview bitmap from the DB or null if the preview is not in the DB. 29505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung */ 296316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk Bitmap readFromDb(WidgetCacheKey key, Bitmap recycle, PreviewLoadTask loadTask) { 2975b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Cursor cursor = null; 2986e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 2995b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal cursor = mDb.getReadableDatabase().query( 3005b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal CacheDb.TABLE_NAME, 3015b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal new String[] { CacheDb.COLUMN_PREVIEW_BITMAP }, 3025b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal CacheDb.COLUMN_COMPONENT + " = ? AND " + CacheDb.COLUMN_USER + " = ? AND " + CacheDb.COLUMN_SIZE + " = ?", 3035b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal new String[] { 3045b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal key.componentName.flattenToString(), 3055b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Long.toString(mUserManager.getSerialNumberForUser(key.user)), 3065b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal key.size 3075b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal }, 3085b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal null, null, null); 30905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If cancelled, skip getting the blob and decoding it into a bitmap 31005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (loadTask.isCancelled()) { 31105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung return null; 31205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 3135b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (cursor.moveToNext()) { 3145b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal byte[] blob = cursor.getBlob(0); 3155b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal BitmapFactory.Options opts = new BitmapFactory.Options(); 3165b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal opts.inBitmap = recycle; 3175b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal try { 31805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (!loadTask.isCancelled()) { 31905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung return BitmapFactory.decodeByteArray(blob, 0, blob.length, opts); 32005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 3215b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (Exception e) { 3225b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return null; 3235b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 3245b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 3255b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (SQLException e) { 3265b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.w(TAG, "Error loading preview from DB", e); 3275b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } finally { 3285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (cursor != null) { 3295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal cursor.close(); 330eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 33105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 3325b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return null; 33305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 33405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 335316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk Bitmap generatePreview(Launcher launcher, Object info, Bitmap recycle, 3362e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen int previewWidth, int previewHeight) { 3375940042d39b576553c2499bcf3d0641281e6ad52Adam Cohen if (info instanceof LauncherAppWidgetProviderInfo) { 3382e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen return generateWidgetPreview(launcher, (LauncherAppWidgetProviderInfo) info, 3392e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen previewWidth, recycle, null); 34005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 3412e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen return generateShortcutPreview(launcher, 3425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal (ResolveInfo) info, previewWidth, previewHeight, recycle); 34305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 34405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 34505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 3462e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen public Bitmap generateWidgetPreview(Launcher launcher, LauncherAppWidgetProviderInfo info, 3474cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int maxPreviewWidth, Bitmap preview, int[] preScaledWidthOut) { 34805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Load the preview image if possible 34905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE; 35005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 35105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable drawable = null; 352ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal if (info.previewImage != 0) { 353ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal drawable = mManager.loadPreview(info); 354fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos if (drawable != null) { 355fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos drawable = mutateOnMainThread(drawable); 356fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos } else { 35705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Log.w(TAG, "Can't load widget preview drawable 0x" + 358ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal Integer.toHexString(info.previewImage) + " for provider: " + info.provider); 35905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 36005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 36105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 3624cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final boolean widgetPreviewExists = (drawable != null); 3632e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen final int spanX = info.getSpanX(launcher) < 1 ? 1 : info.getSpanX(launcher); 3642e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen final int spanY = info.getSpanY(launcher) < 1 ? 1 : info.getSpanY(launcher); 3654cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 36605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int previewWidth; 36705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int previewHeight; 3684cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Bitmap tileBitmap = null; 3694cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 37005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (widgetPreviewExists) { 37105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewWidth = drawable.getIntrinsicWidth(); 37205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = drawable.getIntrinsicHeight(); 37305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 37405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Generate a preview image if we couldn't load one 3754cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal tileBitmap = ((BitmapDrawable) mContext.getResources().getDrawable( 3764cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal R.drawable.widget_tile)).getBitmap(); 3774cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal previewWidth = tileBitmap.getWidth() * spanX; 3784cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal previewHeight = tileBitmap.getHeight() * spanY; 37905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 38005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 38105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Scale to fit width only - let the widget preview be clipped in the 38205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // vertical dimension 38305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka float scale = 1f; 38405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preScaledWidthOut != null) { 38505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preScaledWidthOut[0] = previewWidth; 38605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 38705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (previewWidth > maxPreviewWidth) { 38805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka scale = maxPreviewWidth / (float) previewWidth; 38905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 39005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (scale != 1f) { 39105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewWidth = (int) (scale * previewWidth); 39205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = (int) (scale * previewHeight); 39305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 39405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 39505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // If a bitmap is passed in, we use it; otherwise, we create a bitmap of the right size 3964cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Canvas c = new Canvas(); 39705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview == null) { 39805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888); 3994cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 4004cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } else { 4014cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Reusing bitmap. Clear it. 4024cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 4034cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.drawColor(0, PorterDuff.Mode.CLEAR); 40405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 40505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 40605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Draw the scaled preview into the final bitmap 40741e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song int x = (preview.getWidth() - previewWidth - mProfileBadgeMargin) / 2; 40805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (widgetPreviewExists) { 4094cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal drawable.setBounds(x, 0, x + previewWidth, previewHeight); 4104cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal drawable.draw(c); 41105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 4124cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Paint p = new Paint(); 4134cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal p.setFilterBitmap(true); 4142e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen int appIconSize = launcher.getDeviceProfile().iconSizePx; 4154cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4164cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // draw the spanX x spanY tiles 4174cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Rect src = new Rect(0, 0, tileBitmap.getWidth(), tileBitmap.getHeight()); 4184cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4194cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float tileW = scale * tileBitmap.getWidth(); 4204cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float tileH = scale * tileBitmap.getHeight(); 4214cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final RectF dst = new RectF(0, 0, tileW, tileH); 4224cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4234cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float tx = x; 4244cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal for (int i = 0; i < spanX; i++, tx += tileW) { 4254cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float ty = 0; 4264cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal for (int j = 0; j < spanY; j++, ty += tileH) { 4274cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal dst.offsetTo(tx, ty); 4284cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.drawBitmap(tileBitmap, src, dst, p); 4294cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } 43005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 4314cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4324cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Draw the icon in the top left corner 4334cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // TODO: use top right for RTL 4345b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal int minOffset = (int) (appIconSize * WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE); 4354cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int smallestSide = Math.min(previewWidth, previewHeight); 4365b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal float iconScale = Math.min((float) smallestSide / (appIconSize + 2 * minOffset), scale); 4374cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4384cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal try { 4394cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Drawable icon = mutateOnMainThread(mManager.loadIcon(info, mIconCache)); 4404cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal if (icon != null) { 4415b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal int hoffset = (int) ((tileW - appIconSize * iconScale) / 2) + x; 4425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal int yoffset = (int) ((tileH - appIconSize * iconScale) / 2); 4434cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setBounds(hoffset, yoffset, 4445b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal hoffset + (int) (appIconSize * iconScale), 4455b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal yoffset + (int) (appIconSize * iconScale)); 4464cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.draw(c); 4474cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } 4484cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } catch (Resources.NotFoundException e) { } 44905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 45005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 45141e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song int imageHeight = Math.min(preview.getHeight(), previewHeight + mProfileBadgeMargin); 45241e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song return mManager.getBadgeBitmap(info, preview, imageHeight); 45305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 45405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 45505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private Bitmap generateShortcutPreview( 4562e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen Launcher launcher, ResolveInfo info, int maxWidth, int maxHeight, Bitmap preview) { 4574cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Canvas c = new Canvas(); 4584cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal if (preview == null) { 4594cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888); 4604cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 4614cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } else if (preview.getWidth() != maxWidth || preview.getHeight() != maxHeight) { 4624cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal throw new RuntimeException("Improperly sized bitmap passed as argument"); 46305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 4644cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Reusing bitmap. Clear it. 4654cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 46605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.drawColor(0, PorterDuff.Mode.CLEAR); 46705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 46805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4694cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info.activityInfo)); 4704cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setFilterBitmap(true); 47105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4724cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Draw a desaturated/scaled version of the icon in the background as a watermark 4734cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal ColorMatrix colorMatrix = new ColorMatrix(); 4744cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal colorMatrix.setSaturation(0); 4754cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); 4764cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setAlpha((int) (255 * 0.06f)); 4774cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4784cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Resources res = mContext.getResources(); 4794cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int paddingTop = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top); 4804cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int paddingLeft = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left); 4814cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int paddingRight = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right); 48205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int scaledIconWidth = (maxWidth - paddingLeft - paddingRight); 4834cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setBounds(paddingLeft, paddingTop, 4844cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal paddingLeft + scaledIconWidth, paddingTop + scaledIconWidth); 4854cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.draw(c); 48605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4874cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Draw the final icon at top left corner. 4884cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // TODO: use top right for RTL 4892e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen int appIconSize = launcher.getDeviceProfile().iconSizePx; 4902e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen 4914cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setAlpha(255); 4924cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setColorFilter(null); 4935b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal icon.setBounds(0, 0, appIconSize, appIconSize); 4944cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.draw(c); 49505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 49605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 49705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 49805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 49905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 50065d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos private Drawable mutateOnMainThread(final Drawable drawable) { 50165d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos try { 50265d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos return mMainThreadExecutor.submit(new Callable<Drawable>() { 50365d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos @Override 50465d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos public Drawable call() throws Exception { 50565d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos return drawable.mutate(); 50665d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 50765d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos }).get(); 50865d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } catch (InterruptedException e) { 50965d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos Thread.currentThread().interrupt(); 51065d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos throw new RuntimeException(e); 51165d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } catch (ExecutionException e) { 51265d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos throw new RuntimeException(e); 51365d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 51465d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 5151f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos 5161f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos /** 5175b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * @return an array of containing versionCode and lastUpdatedTime for the package. 5181f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos */ 519316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk long[] getPackageVersion(String packageName) { 5205b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal synchronized (mPackageVersions) { 5215b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long[] versions = mPackageVersions.get(packageName); 5225b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (versions == null) { 5235b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal versions = new long[2]; 5241f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos try { 5255b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0); 5265b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal versions[0] = info.versionCode; 5275b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal versions[1] = info.lastUpdateTime; 5285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (NameNotFoundException e) { 5295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.e(TAG, "PackageInfo not found", e); 5305b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5315b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mPackageVersions.put(packageName, versions); 5325b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5335b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return versions; 5345b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5355b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5365b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5375b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal /** 5385b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * A request Id which can be used by the client to cancel any request. 5395b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 5405b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public class PreviewLoadRequest { 5415b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final PreviewLoadTask mTask; 5435b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 544559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song public PreviewLoadRequest(PreviewLoadTask task) { 5455b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mTask = task; 5465b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5475b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 548559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song public void cleanup() { 5495b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (mTask != null) { 5505b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mTask.cancel(true); 5515b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5525b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 55305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // This only handles the case where the PreviewLoadTask is cancelled after the task has 55405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // successfully completed (including having written to disk when necessary). In the 55505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // other cases where it is cancelled while the task is running, it will be cleaned up 55605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // in the tasks's onCancelled() call, and if cancelled while the task is writing to 55705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // disk, it will be cancelled in the task's onPostExecute() call. 55805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (mTask.mBitmapToRecycle != null) { 559e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mWorkerHandler.post(new Runnable() { 560e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song @Override 561e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song public void run() { 562e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song synchronized (mUnusedBitmaps) { 563e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mUnusedBitmaps.add(mTask.mBitmapToRecycle); 564e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song } 565e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mTask.mBitmapToRecycle = null; 566e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song } 567e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song }); 5685b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5695b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5705b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5715b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5725b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public class PreviewLoadTask extends AsyncTask<Void, Void, Bitmap> { 573316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk final WidgetCacheKey mKey; 5745b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final Object mInfo; 5755b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final int mPreviewHeight; 5765b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final int mPreviewWidth; 5773f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song private final WidgetCell mCaller; 578316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk long[] mVersions; 579316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk Bitmap mBitmapToRecycle; 5805b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5815b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal PreviewLoadTask(WidgetCacheKey key, Object info, int previewWidth, 5823f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song int previewHeight, WidgetCell caller) { 5835b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mKey = key; 5845b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mInfo = info; 5855b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mPreviewHeight = previewHeight; 5865b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mPreviewWidth = previewWidth; 5875b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mCaller = caller; 5883f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song if (DEBUG) { 5893f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song Log.d(TAG, String.format("%s, %s, %d, %d", 5903f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song mKey, mInfo, mPreviewHeight, mPreviewWidth)); 5913f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song } 5925b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5935b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 5955b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal protected Bitmap doInBackground(Void... params) { 5965b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Bitmap unusedBitmap = null; 5973f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song 598f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song // If already cancelled before this gets to run in the background, then return early 599f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song if (isCancelled()) { 600f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song return null; 601f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song } 6025b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal synchronized (mUnusedBitmaps) { 603f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song // Check if we can re-use a bitmap 6045b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal for (Bitmap candidate : mUnusedBitmaps) { 6055b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (candidate != null && candidate.isMutable() && 6065b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal candidate.getWidth() == mPreviewWidth && 6075b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal candidate.getHeight() == mPreviewHeight) { 6085b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal unusedBitmap = candidate; 609f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song mUnusedBitmaps.remove(unusedBitmap); 6105b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal break; 6111f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 6125b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 613f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song } 6145b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 615f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song // creating a bitmap is expensive. Do not do this inside synchronized block. 616f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song if (unusedBitmap == null) { 617f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song unusedBitmap = Bitmap.createBitmap(mPreviewWidth, mPreviewHeight, Config.ARGB_8888); 6185b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 61905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If cancelled now, don't bother reading the preview from the DB 6205b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (isCancelled()) { 62105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung return unusedBitmap; 6225b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 62305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung Bitmap preview = readFromDb(mKey, unusedBitmap, this); 62405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // Only consider generating the preview if we have not cancelled the task already 6255b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (!isCancelled() && preview == null) { 6265b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // Fetch the version info before we generate the preview, so that, in-case the 6275b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // app was updated while we are generating the preview, we use the old version info, 6285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // which would gets re-written next time. 62905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mVersions = getPackageVersion(mKey.componentName.getPackageName()); 6305b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6312e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen Launcher launcher = (Launcher) mCaller.getContext(); 6322e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen 6335b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // it's not in the db... we need to generate it 6342e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen preview = generatePreview(launcher, mInfo, unusedBitmap, mPreviewWidth, mPreviewHeight); 6351f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 6365b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return preview; 6375b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 6385b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6395b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 64005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung protected void onPostExecute(final Bitmap preview) { 64105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mCaller.applyPreview(preview); 64205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung 64305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // Write the generated preview to the DB in the worker thread 64405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (mVersions != null) { 64505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mWorkerHandler.post(new Runnable() { 64605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung @Override 64705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung public void run() { 64805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (!isCancelled()) { 64905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If we are still using this preview, then write it to the DB and then 65005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // let the normal clear mechanism recycle the bitmap 65105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung writeToDb(mKey, mVersions, preview); 65205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mBitmapToRecycle = preview; 65305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } else { 65405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If we've already cancelled, then skip writing the bitmap to the DB 65505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // and manually add the bitmap back to the recycled set 65605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung synchronized (mUnusedBitmaps) { 65705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mUnusedBitmaps.add(preview); 65805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 65905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 66005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 66105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung }); 66205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } else { 66305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If we don't need to write to disk, then ensure the preview gets recycled by 66405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // the normal clear mechanism 66505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mBitmapToRecycle = preview; 66605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 66705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 66805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung 66905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung @Override 670e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song protected void onCancelled(final Bitmap preview) { 67105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If we've cancelled while the task is running, then can return the bitmap to the 67205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // recycled set immediately. Otherwise, it will be recycled after the preview is written 67305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // to disk. 67405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (preview != null) { 675e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mWorkerHandler.post(new Runnable() { 676e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song @Override 677e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song public void run() { 678e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song synchronized (mUnusedBitmaps) { 679e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mUnusedBitmaps.add(preview); 680e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song } 681e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song } 682e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song }); 68305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 6845b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 6855b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 6865b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6875b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final class WidgetCacheKey extends ComponentKey { 6885b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6895b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // TODO: remove dependency on size 690316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk final String size; 6915b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6925b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public WidgetCacheKey(ComponentName componentName, UserHandleCompat user, String size) { 6935b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal super(componentName, user); 6945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal this.size = size; 6955b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 6965b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6975b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 6985b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public int hashCode() { 6995b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return super.hashCode() ^ size.hashCode(); 7005b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 7015b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 7025b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 7035b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public boolean equals(Object o) { 7045b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return super.equals(o) && ((WidgetCacheKey) o).size.equals(size); 7051f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 7061f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 70705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 708