WidgetPreviewLoader.java revision b9f932e08902c21020b6a98372c1a68548b8de59
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; 30383c507c47a5abf3258fc04220f37c366f983a97Sunny Goyal 31ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyalimport com.android.launcher3.compat.AppWidgetManagerCompat; 325b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport com.android.launcher3.compat.UserHandleCompat; 335b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport com.android.launcher3.compat.UserManagerCompat; 345b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport com.android.launcher3.util.ComponentKey; 35091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk; 363f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.widget.WidgetCell; 378821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Song 388821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Songimport java.util.ArrayList; 395b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport java.util.Collections; 4005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.HashMap; 4105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.HashSet; 425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport java.util.Set; 435b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport java.util.WeakHashMap; 4465d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roosimport java.util.concurrent.Callable; 4565d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roosimport java.util.concurrent.ExecutionException; 4605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 47ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyalpublic class WidgetPreviewLoader { 4805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 49ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private static final String TAG = "WidgetPreviewLoader"; 503f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song private static final boolean DEBUG = false; 51ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 52ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f; 53ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 545b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final HashMap<String, long[]> mPackageVersions = new HashMap<>(); 55559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song 56559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song /** 57559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song * Weak reference objects, do not prevent their referents from being made finalizable, 58559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song * finalized, and then reclaimed. 59e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song * Note: synchronized block used for this variable is expensive and the block should always 60e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song * be posted to a background thread. 61559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song */ 62b4cbea4ad4ce06b591603a47f86cfd9df838ccb1Sunny Goyal @Thunk final Set<Bitmap> mUnusedBitmaps = 63559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>()); 644cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 654cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal private final Context mContext; 66ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private final IconCache mIconCache; 675b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final UserManagerCompat mUserManager; 68ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private final AppWidgetManagerCompat mManager; 695b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final CacheDb mDb; 7041e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song private final int mProfileBadgeMargin; 7105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 7265d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor(); 73316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk final Handler mWorkerHandler; 7465d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos 75383c507c47a5abf3258fc04220f37c366f983a97Sunny Goyal public WidgetPreviewLoader(Context context, IconCache iconCache) { 76fd13c714f412dfa8130fa7a664cb1692a565c539Chris Wren mContext = context; 775b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mIconCache = iconCache; 78ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal mManager = AppWidgetManagerCompat.getInstance(context); 795b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mUserManager = UserManagerCompat.getInstance(context); 805b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mDb = new CacheDb(context); 8105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mWorkerHandler = new Handler(LauncherModel.getWorkerLooper()); 8241e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song mProfileBadgeMargin = context.getResources() 8341e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song .getDimensionPixelSize(R.dimen.profile_badge_margin); 843f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka } 85ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 865b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal /** 875b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * Generates the widget preview on {@link AsyncTask#THREAD_POOL_EXECUTOR}. Must be 885b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * called on UI thread 895b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * 905b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * @param o either {@link LauncherAppWidgetProviderInfo} or {@link ResolveInfo} 915b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * @return a request id which can be used to cancel the request. 925b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 932e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen public PreviewLoadRequest getPreview(final Object o, int previewWidth, 942e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen int previewHeight, WidgetCell caller) { 955b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal String size = previewWidth + "x" + previewHeight; 965b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal WidgetCacheKey key = getObjectKey(o, size); 9705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 985b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal PreviewLoadTask task = new PreviewLoadTask(key, o, previewWidth, previewHeight, caller); 995b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 100559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song return new PreviewLoadRequest(task); 10105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 10205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1035b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal /** 1045b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * The DB holds the generated previews for various components. Previews can also have different 1055b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * sizes (landscape vs portrait). 1065b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 1075b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static class CacheDb extends SQLiteOpenHelper { 1085b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final int DB_VERSION = 3; 1095b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 1105b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String TABLE_NAME = "shortcut_and_widget_previews"; 1115b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_COMPONENT = "componentName"; 1125b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_USER = "profileId"; 1135b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_SIZE = "size"; 1145b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_PACKAGE = "packageName"; 1155b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_LAST_UPDATED = "lastUpdated"; 1165b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_VERSION = "version"; 1175b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_PREVIEW_BITMAP = "preview_bitmap"; 11805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 119d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka public CacheDb(Context context) { 1205b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal super(context, LauncherFiles.WIDGET_PREVIEWS_DB, null, DB_VERSION); 12105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 12205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 12305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 12405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public void onCreate(SQLiteDatabase database) { 12532b7a097338b77d8999c706c42f19e8ba060ba62Michael Jurka database.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + 1265b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_COMPONENT + " TEXT NOT NULL, " + 1275b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_USER + " INTEGER NOT NULL, " + 12805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka COLUMN_SIZE + " TEXT NOT NULL, " + 1295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_PACKAGE + " TEXT NOT NULL, " + 1305b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, " + 1315b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, " + 1325b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_PREVIEW_BITMAP + " BLOB, " + 1335b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ", " + COLUMN_SIZE + ") " + 13432b7a097338b77d8999c706c42f19e8ba060ba62Michael Jurka ");"); 13505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 13605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 13705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 13805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 139e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka if (oldVersion != newVersion) { 1405b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal clearDB(db); 141e5919c5574ff09b88173b44558c6d325841511d6Michael Jurka } 14205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 14305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1445b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 1455b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { 1465b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (oldVersion != newVersion) { 1475b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal clearDB(db); 1485b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 1495b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 15005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1515b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private void clearDB(SQLiteDatabase db) { 1525b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME); 1535b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal onCreate(db); 15405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 15505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 15605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1575b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private WidgetCacheKey getObjectKey(Object o, String size) { 1585b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // should cache the string builder 1595b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (o instanceof LauncherAppWidgetProviderInfo) { 1605b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) o; 1615b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return new WidgetCacheKey(info.provider, mManager.getUser(info), size); 16205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 16305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ResolveInfo info = (ResolveInfo) o; 1645b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return new WidgetCacheKey( 1655b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal new ComponentName(info.activityInfo.packageName, info.activityInfo.name), 1665b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal UserHandleCompat.myUserHandle(), size); 16705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 16805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 16905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1705b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Thunk void writeToDb(WidgetCacheKey key, long[] versions, Bitmap preview) { 17105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ContentValues values = new ContentValues(); 1725b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_COMPONENT, key.componentName.flattenToShortString()); 1735b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_USER, mUserManager.getSerialNumberForUser(key.user)); 1745b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_SIZE, key.size); 1755b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_PACKAGE, key.componentName.getPackageName()); 1765b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_VERSION, versions[0]); 1775b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_LAST_UPDATED, versions[1]); 1785b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_PREVIEW_BITMAP, Utilities.flattenBitmap(preview)); 17905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1806e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 1815b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mDb.getWritableDatabase().insertWithOnConflict(CacheDb.TABLE_NAME, null, values, 1825b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal SQLiteDatabase.CONFLICT_REPLACE); 1835b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (SQLException e) { 1845b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.e(TAG, "Error saving image to DB", e); 1856e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 18605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 18705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1885b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public void removePackage(String packageName, UserHandleCompat user) { 1895b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal removePackage(packageName, user, mUserManager.getSerialNumberForUser(user)); 1905b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 1915b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 1925b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private void removePackage(String packageName, UserHandleCompat user, long userSerial) { 1935b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal synchronized(mPackageVersions) { 1945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mPackageVersions.remove(packageName); 1955b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 1965b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 1976e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 1985b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mDb.getWritableDatabase().delete(CacheDb.TABLE_NAME, 1995b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal CacheDb.COLUMN_PACKAGE + " = ? AND " + CacheDb.COLUMN_USER + " = ?", 2005b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal new String[] {packageName, Long.toString(userSerial)}); 2015b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (SQLException e) { 2025b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.e(TAG, "Unable to delete items from DB", e); 2036e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 2048ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka } 2058ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka 2065b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal /** 2075b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * Updates the persistent DB: 2085b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * 1. Any preview generated for an old package version is removed 2095b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * 2. Any preview for an absent package is removed 2105b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * This ensures that we remove entries for packages which changed while the launcher was dead. 2115b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 2128821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Song public void removeObsoletePreviews(ArrayList<Object> list) { 2132bd3d7d1cb5e4d8d826982d11b456739fed6b817Hyunyoung Song Utilities.assertWorkerThread(); 2148821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Song 2155b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal LongSparseArray<UserHandleCompat> userIdCache = new LongSparseArray<>(); 2165b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal LongSparseArray<HashSet<String>> validPackages = new LongSparseArray<>(); 2175b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2188821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Song for (Object obj : list) { 2195b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal final UserHandleCompat user; 2205b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal final String pkg; 2215b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (obj instanceof ResolveInfo) { 2225b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal user = UserHandleCompat.myUserHandle(); 2235b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal pkg = ((ResolveInfo) obj).activityInfo.packageName; 2245b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } else { 2255b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal LauncherAppWidgetProviderInfo info = (LauncherAppWidgetProviderInfo) obj; 2265b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal user = mManager.getUser(info); 2275b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal pkg = info.provider.getPackageName(); 2285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2305b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal int userIdIndex = userIdCache.indexOfValue(user); 2315b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal final long userId; 2325b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (userIdIndex < 0) { 2335b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal userId = mUserManager.getSerialNumberForUser(user); 2345b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal userIdCache.put(userId, user); 2355b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } else { 2365b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal userId = userIdCache.keyAt(userIdIndex); 2375b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2385b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2395b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal HashSet<String> packages = validPackages.get(userId); 2405b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (packages == null) { 2415b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages = new HashSet<>(); 2425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal validPackages.put(userId, packages); 2435b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2445b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages.add(pkg); 24505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 2465b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2475b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal LongSparseArray<HashSet<String>> packagesToDelete = new LongSparseArray<>(); 2485b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Cursor c = null; 2495b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal try { 2505b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal c = mDb.getReadableDatabase().query(CacheDb.TABLE_NAME, 2515b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal new String[] {CacheDb.COLUMN_USER, CacheDb.COLUMN_PACKAGE, 2525b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal CacheDb.COLUMN_LAST_UPDATED, CacheDb.COLUMN_VERSION}, 2535b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal null, null, null, null, null); 2545b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal while (c.moveToNext()) { 2555b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long userId = c.getLong(0); 2565b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal String pkg = c.getString(1); 2575b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long lastUpdated = c.getLong(2); 2585b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long version = c.getLong(3); 2595b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2605b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal HashSet<String> packages = validPackages.get(userId); 2615b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (packages != null && packages.contains(pkg)) { 2625b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long[] versions = getPackageVersion(pkg); 2635b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (versions[0] == version && versions[1] == lastUpdated) { 2645b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // Every thing checks out 2655b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal continue; 2665b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2676e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 2685b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2695b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // We need to delete this package. 2705b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages = packagesToDelete.get(userId); 2715b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (packages == null) { 2725b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages = new HashSet<>(); 2735b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packagesToDelete.put(userId, packages); 27405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 2755b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages.add(pkg); 27605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 27705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 2785b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal for (int i = 0; i < packagesToDelete.size(); i++) { 2795b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long userId = packagesToDelete.keyAt(i); 2805b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal UserHandleCompat user = mUserManager.getUserForSerialNumber(userId); 2815b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal for (String pkg : packagesToDelete.valueAt(i)) { 2825b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal removePackage(pkg, user, userId); 2836e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 284eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 2855b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (SQLException e) { 2865b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.e(TAG, "Error updatating widget previews", e); 2875b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } finally { 2885b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (c != null) { 2895b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal c.close(); 2905b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2915b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 292eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 293eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka 29405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung /** 29505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung * Reads the preview bitmap from the DB or null if the preview is not in the DB. 29605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung */ 297316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk Bitmap readFromDb(WidgetCacheKey key, Bitmap recycle, PreviewLoadTask loadTask) { 2985b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Cursor cursor = null; 2996e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 3005b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal cursor = mDb.getReadableDatabase().query( 3015b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal CacheDb.TABLE_NAME, 3025b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal new String[] { CacheDb.COLUMN_PREVIEW_BITMAP }, 3035b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal CacheDb.COLUMN_COMPONENT + " = ? AND " + CacheDb.COLUMN_USER + " = ? AND " + CacheDb.COLUMN_SIZE + " = ?", 3045b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal new String[] { 3055b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal key.componentName.flattenToString(), 3065b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Long.toString(mUserManager.getSerialNumberForUser(key.user)), 3075b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal key.size 3085b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal }, 3095b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal null, null, null); 31005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If cancelled, skip getting the blob and decoding it into a bitmap 31105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (loadTask.isCancelled()) { 31205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung return null; 31305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 3145b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (cursor.moveToNext()) { 3155b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal byte[] blob = cursor.getBlob(0); 3165b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal BitmapFactory.Options opts = new BitmapFactory.Options(); 3175b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal opts.inBitmap = recycle; 3185b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal try { 31905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (!loadTask.isCancelled()) { 32005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung return BitmapFactory.decodeByteArray(blob, 0, blob.length, opts); 32105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 3225b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (Exception e) { 3235b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return null; 3245b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 3255b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 3265b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (SQLException e) { 3275b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.w(TAG, "Error loading preview from DB", e); 3285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } finally { 3295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (cursor != null) { 3305b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal cursor.close(); 331eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 33205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 3335b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return null; 33405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 33505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 336316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk Bitmap generatePreview(Launcher launcher, Object info, Bitmap recycle, 3372e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen int previewWidth, int previewHeight) { 3385940042d39b576553c2499bcf3d0641281e6ad52Adam Cohen if (info instanceof LauncherAppWidgetProviderInfo) { 3392e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen return generateWidgetPreview(launcher, (LauncherAppWidgetProviderInfo) info, 3402e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen previewWidth, recycle, null); 34105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 3422e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen return generateShortcutPreview(launcher, 3435b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal (ResolveInfo) info, previewWidth, previewHeight, recycle); 34405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 34505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 34605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 3472e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen public Bitmap generateWidgetPreview(Launcher launcher, LauncherAppWidgetProviderInfo info, 3484cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int maxPreviewWidth, Bitmap preview, int[] preScaledWidthOut) { 34905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Load the preview image if possible 35005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE; 35105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 35205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable drawable = null; 353ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal if (info.previewImage != 0) { 354ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal drawable = mManager.loadPreview(info); 355fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos if (drawable != null) { 356fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos drawable = mutateOnMainThread(drawable); 357fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos } else { 35805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Log.w(TAG, "Can't load widget preview drawable 0x" + 359ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal Integer.toHexString(info.previewImage) + " for provider: " + info.provider); 36005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 36105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 36205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 3634cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final boolean widgetPreviewExists = (drawable != null); 3642e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen final int spanX = info.getSpanX(launcher) < 1 ? 1 : info.getSpanX(launcher); 3652e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen final int spanY = info.getSpanY(launcher) < 1 ? 1 : info.getSpanY(launcher); 3664cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 36705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int previewWidth; 36805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int previewHeight; 3694cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Bitmap tileBitmap = null; 3704cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 37105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (widgetPreviewExists) { 37205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewWidth = drawable.getIntrinsicWidth(); 37305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = drawable.getIntrinsicHeight(); 37405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 37505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Generate a preview image if we couldn't load one 3764cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal tileBitmap = ((BitmapDrawable) mContext.getResources().getDrawable( 3774cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal R.drawable.widget_tile)).getBitmap(); 3784cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal previewWidth = tileBitmap.getWidth() * spanX; 3794cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal previewHeight = tileBitmap.getHeight() * spanY; 38005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 38105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 38205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Scale to fit width only - let the widget preview be clipped in the 38305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // vertical dimension 38405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka float scale = 1f; 38505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preScaledWidthOut != null) { 38605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preScaledWidthOut[0] = previewWidth; 38705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 38805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (previewWidth > maxPreviewWidth) { 389b9f932e08902c21020b6a98372c1a68548b8de59Hyunyoung Song scale = (maxPreviewWidth - 2 * mProfileBadgeMargin) / (float) (previewWidth); 39005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 39105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (scale != 1f) { 39205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewWidth = (int) (scale * previewWidth); 39305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = (int) (scale * previewHeight); 39405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 39505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 39605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // If a bitmap is passed in, we use it; otherwise, we create a bitmap of the right size 3974cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Canvas c = new Canvas(); 39805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview == null) { 39905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888); 4004cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 4014cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } else { 4024cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Reusing bitmap. Clear it. 4034cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 4044cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.drawColor(0, PorterDuff.Mode.CLEAR); 40505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 40605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 40705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Draw the scaled preview into the final bitmap 408b9f932e08902c21020b6a98372c1a68548b8de59Hyunyoung Song int x = (preview.getWidth() - previewWidth) / 2; 40905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (widgetPreviewExists) { 4104cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal drawable.setBounds(x, 0, x + previewWidth, previewHeight); 4114cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal drawable.draw(c); 41205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 4134cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Paint p = new Paint(); 4144cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal p.setFilterBitmap(true); 4152e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen int appIconSize = launcher.getDeviceProfile().iconSizePx; 4164cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4174cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // draw the spanX x spanY tiles 4184cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Rect src = new Rect(0, 0, tileBitmap.getWidth(), tileBitmap.getHeight()); 4194cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4204cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float tileW = scale * tileBitmap.getWidth(); 4214cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float tileH = scale * tileBitmap.getHeight(); 4224cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final RectF dst = new RectF(0, 0, tileW, tileH); 4234cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4244cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float tx = x; 4254cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal for (int i = 0; i < spanX; i++, tx += tileW) { 4264cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float ty = 0; 4274cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal for (int j = 0; j < spanY; j++, ty += tileH) { 4284cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal dst.offsetTo(tx, ty); 4294cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.drawBitmap(tileBitmap, src, dst, p); 4304cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } 43105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 4324cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4334cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Draw the icon in the top left corner 4344cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // TODO: use top right for RTL 4355b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal int minOffset = (int) (appIconSize * WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE); 4364cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int smallestSide = Math.min(previewWidth, previewHeight); 4375b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal float iconScale = Math.min((float) smallestSide / (appIconSize + 2 * minOffset), scale); 4384cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4394cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal try { 4404cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Drawable icon = mutateOnMainThread(mManager.loadIcon(info, mIconCache)); 4414cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal if (icon != null) { 4425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal int hoffset = (int) ((tileW - appIconSize * iconScale) / 2) + x; 4435b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal int yoffset = (int) ((tileH - appIconSize * iconScale) / 2); 4444cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setBounds(hoffset, yoffset, 4455b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal hoffset + (int) (appIconSize * iconScale), 4465b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal yoffset + (int) (appIconSize * iconScale)); 4474cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.draw(c); 4484cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } 4494cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } catch (Resources.NotFoundException e) { } 45005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 45105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 45241e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song int imageHeight = Math.min(preview.getHeight(), previewHeight + mProfileBadgeMargin); 45341e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song return mManager.getBadgeBitmap(info, preview, imageHeight); 45405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 45505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 45605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private Bitmap generateShortcutPreview( 4572e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen Launcher launcher, ResolveInfo info, int maxWidth, int maxHeight, Bitmap preview) { 4584cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Canvas c = new Canvas(); 4594cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal if (preview == null) { 4604cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888); 4614cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 4624cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } else if (preview.getWidth() != maxWidth || preview.getHeight() != maxHeight) { 4634cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal throw new RuntimeException("Improperly sized bitmap passed as argument"); 46405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 4654cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Reusing bitmap. Clear it. 4664cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 46705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.drawColor(0, PorterDuff.Mode.CLEAR); 46805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 46905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4704cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info.activityInfo)); 4714cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setFilterBitmap(true); 47205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4734cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Draw a desaturated/scaled version of the icon in the background as a watermark 4744cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal ColorMatrix colorMatrix = new ColorMatrix(); 4754cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal colorMatrix.setSaturation(0); 4764cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); 4774cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setAlpha((int) (255 * 0.06f)); 4784cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4794cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Resources res = mContext.getResources(); 4804cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int paddingTop = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top); 4814cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int paddingLeft = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left); 4824cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int paddingRight = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right); 48305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int scaledIconWidth = (maxWidth - paddingLeft - paddingRight); 4844cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setBounds(paddingLeft, paddingTop, 4854cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal paddingLeft + scaledIconWidth, paddingTop + scaledIconWidth); 4864cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.draw(c); 48705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4884cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Draw the final icon at top left corner. 4894cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // TODO: use top right for RTL 4902e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen int appIconSize = launcher.getDeviceProfile().iconSizePx; 4912e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen 4924cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setAlpha(255); 4934cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setColorFilter(null); 4945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal icon.setBounds(0, 0, appIconSize, appIconSize); 4954cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.draw(c); 49605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 49705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 49805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 49905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 50005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 50165d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos private Drawable mutateOnMainThread(final Drawable drawable) { 50265d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos try { 50365d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos return mMainThreadExecutor.submit(new Callable<Drawable>() { 50465d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos @Override 50565d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos public Drawable call() throws Exception { 50665d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos return drawable.mutate(); 50765d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 50865d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos }).get(); 50965d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } catch (InterruptedException e) { 51065d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos Thread.currentThread().interrupt(); 51165d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos throw new RuntimeException(e); 51265d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } catch (ExecutionException e) { 51365d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos throw new RuntimeException(e); 51465d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 51565d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 5161f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos 5171f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos /** 5185b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * @return an array of containing versionCode and lastUpdatedTime for the package. 5191f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos */ 520316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk long[] getPackageVersion(String packageName) { 5215b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal synchronized (mPackageVersions) { 5225b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long[] versions = mPackageVersions.get(packageName); 5235b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (versions == null) { 5245b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal versions = new long[2]; 5251f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos try { 5265b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0); 5275b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal versions[0] = info.versionCode; 5285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal versions[1] = info.lastUpdateTime; 5295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (NameNotFoundException e) { 5305b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.e(TAG, "PackageInfo not found", e); 5315b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5325b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mPackageVersions.put(packageName, versions); 5335b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5345b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return versions; 5355b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5365b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5375b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5385b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal /** 5395b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * A request Id which can be used by the client to cancel any request. 5405b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 5415b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public class PreviewLoadRequest { 5425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 543b4cbea4ad4ce06b591603a47f86cfd9df838ccb1Sunny Goyal @Thunk final PreviewLoadTask mTask; 5445b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 545559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song public PreviewLoadRequest(PreviewLoadTask task) { 5465b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mTask = task; 5475b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5485b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 549559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song public void cleanup() { 5505b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (mTask != null) { 5515b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mTask.cancel(true); 5525b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5535b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 55405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // This only handles the case where the PreviewLoadTask is cancelled after the task has 55505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // successfully completed (including having written to disk when necessary). In the 55605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // other cases where it is cancelled while the task is running, it will be cleaned up 55705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // in the tasks's onCancelled() call, and if cancelled while the task is writing to 55805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // disk, it will be cancelled in the task's onPostExecute() call. 55905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (mTask.mBitmapToRecycle != null) { 560e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mWorkerHandler.post(new Runnable() { 561e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song @Override 562e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song public void run() { 563e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song synchronized (mUnusedBitmaps) { 564e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mUnusedBitmaps.add(mTask.mBitmapToRecycle); 565e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song } 566e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mTask.mBitmapToRecycle = null; 567e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song } 568e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song }); 5695b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5705b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5715b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5725b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5735b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public class PreviewLoadTask extends AsyncTask<Void, Void, Bitmap> { 574316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk final WidgetCacheKey mKey; 5755b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final Object mInfo; 5765b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final int mPreviewHeight; 5775b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final int mPreviewWidth; 5783f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song private final WidgetCell mCaller; 579316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk long[] mVersions; 580316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk Bitmap mBitmapToRecycle; 5815b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5825b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal PreviewLoadTask(WidgetCacheKey key, Object info, int previewWidth, 5833f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song int previewHeight, WidgetCell caller) { 5845b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mKey = key; 5855b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mInfo = info; 5865b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mPreviewHeight = previewHeight; 5875b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mPreviewWidth = previewWidth; 5885b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mCaller = caller; 5893f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song if (DEBUG) { 5903f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song Log.d(TAG, String.format("%s, %s, %d, %d", 5913f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song mKey, mInfo, mPreviewHeight, mPreviewWidth)); 5923f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song } 5935b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5955b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 5965b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal protected Bitmap doInBackground(Void... params) { 5975b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Bitmap unusedBitmap = null; 5983f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song 599f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song // If already cancelled before this gets to run in the background, then return early 600f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song if (isCancelled()) { 601f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song return null; 602f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song } 6035b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal synchronized (mUnusedBitmaps) { 604f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song // Check if we can re-use a bitmap 6055b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal for (Bitmap candidate : mUnusedBitmaps) { 6065b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (candidate != null && candidate.isMutable() && 6075b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal candidate.getWidth() == mPreviewWidth && 6085b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal candidate.getHeight() == mPreviewHeight) { 6095b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal unusedBitmap = candidate; 610f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song mUnusedBitmaps.remove(unusedBitmap); 6115b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal break; 6121f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 6135b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 614f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song } 6155b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 616f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song // creating a bitmap is expensive. Do not do this inside synchronized block. 617f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song if (unusedBitmap == null) { 618f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song unusedBitmap = Bitmap.createBitmap(mPreviewWidth, mPreviewHeight, Config.ARGB_8888); 6195b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 62005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If cancelled now, don't bother reading the preview from the DB 6215b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (isCancelled()) { 62205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung return unusedBitmap; 6235b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 62405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung Bitmap preview = readFromDb(mKey, unusedBitmap, this); 62505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // Only consider generating the preview if we have not cancelled the task already 6265b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (!isCancelled() && preview == null) { 6275b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // Fetch the version info before we generate the preview, so that, in-case the 6285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // app was updated while we are generating the preview, we use the old version info, 6295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // which would gets re-written next time. 63005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mVersions = getPackageVersion(mKey.componentName.getPackageName()); 6315b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6322e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen Launcher launcher = (Launcher) mCaller.getContext(); 6332e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen 6345b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // it's not in the db... we need to generate it 6352e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen preview = generatePreview(launcher, mInfo, unusedBitmap, mPreviewWidth, mPreviewHeight); 6361f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 6375b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return preview; 6385b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 6395b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6405b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 64105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung protected void onPostExecute(final Bitmap preview) { 64205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mCaller.applyPreview(preview); 64305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung 64405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // Write the generated preview to the DB in the worker thread 64505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (mVersions != null) { 64605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mWorkerHandler.post(new Runnable() { 64705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung @Override 64805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung public void run() { 64905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (!isCancelled()) { 65005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If we are still using this preview, then write it to the DB and then 65105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // let the normal clear mechanism recycle the bitmap 65205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung writeToDb(mKey, mVersions, preview); 65305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mBitmapToRecycle = preview; 65405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } else { 65505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If we've already cancelled, then skip writing the bitmap to the DB 65605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // and manually add the bitmap back to the recycled set 65705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung synchronized (mUnusedBitmaps) { 65805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mUnusedBitmaps.add(preview); 65905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 66005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 66105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 66205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung }); 66305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } else { 66405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If we don't need to write to disk, then ensure the preview gets recycled by 66505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // the normal clear mechanism 66605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mBitmapToRecycle = preview; 66705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 66805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 66905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung 67005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung @Override 671e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song protected void onCancelled(final Bitmap preview) { 67205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If we've cancelled while the task is running, then can return the bitmap to the 67305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // recycled set immediately. Otherwise, it will be recycled after the preview is written 67405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // to disk. 67505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (preview != null) { 676e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mWorkerHandler.post(new Runnable() { 677e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song @Override 678e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song public void run() { 679e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song synchronized (mUnusedBitmaps) { 680e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mUnusedBitmaps.add(preview); 681e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song } 682e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song } 683e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song }); 68405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 6855b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 6865b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 6875b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6885b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final class WidgetCacheKey extends ComponentKey { 6895b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6905b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // TODO: remove dependency on size 691316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk final String size; 6925b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6935b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public WidgetCacheKey(ComponentName componentName, UserHandleCompat user, String size) { 6945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal super(componentName, user); 6955b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal this.size = size; 6965b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 6975b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6985b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 6995b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public int hashCode() { 7005b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return super.hashCode() ^ size.hashCode(); 7015b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 7025b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 7035b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 7045b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public boolean equals(Object o) { 7055b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return super.equals(o) && ((WidgetCacheKey) o).size.equals(size); 7061f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 7071f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 70805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 709