1325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3; 205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.ComponentName; 405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.ContentValues; 505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.Context; 64ddc40130aa0460924364eab3557088421eebe0cSunny Goyalimport android.content.pm.ActivityInfo; 75b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport android.content.pm.PackageInfo; 84ddc40130aa0460924364eab3557088421eebe0cSunny Goyalimport android.content.pm.PackageManager; 95b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport android.content.pm.PackageManager.NameNotFoundException; 1005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.content.res.Resources; 1105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.Cursor; 125b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport android.database.SQLException; 1305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport android.database.sqlite.SQLiteDatabase; 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; 344ddc40130aa0460924364eab3557088421eebe0cSunny Goyalimport com.android.launcher3.model.WidgetItem; 355b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport com.android.launcher3.util.ComponentKey; 366388b2c61b17bd6988f4243ad206c193a1e567c1Sunny Goyalimport com.android.launcher3.util.Preconditions; 376f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyalimport com.android.launcher3.util.SQLiteCacheHelper; 38091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk; 393f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Songimport com.android.launcher3.widget.WidgetCell; 408821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Song 418821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Songimport java.util.ArrayList; 425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport java.util.Collections; 4305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.HashMap; 4405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurkaimport java.util.HashSet; 455b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport java.util.Set; 465b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport java.util.WeakHashMap; 4765d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roosimport java.util.concurrent.Callable; 4865d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roosimport java.util.concurrent.ExecutionException; 4905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 50ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyalpublic class WidgetPreviewLoader { 5105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 52ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private static final String TAG = "WidgetPreviewLoader"; 533f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song private static final boolean DEBUG = false; 54ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 55ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private static final float WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE = 0.25f; 56ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 575b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final HashMap<String, long[]> mPackageVersions = new HashMap<>(); 58559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song 59559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song /** 60559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song * Weak reference objects, do not prevent their referents from being made finalizable, 61559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song * finalized, and then reclaimed. 62e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song * Note: synchronized block used for this variable is expensive and the block should always 63e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song * be posted to a background thread. 64559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song */ 65b4cbea4ad4ce06b591603a47f86cfd9df838ccb1Sunny Goyal @Thunk final Set<Bitmap> mUnusedBitmaps = 66559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song Collections.newSetFromMap(new WeakHashMap<Bitmap, Boolean>()); 674cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 684cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal private final Context mContext; 69ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal private final IconCache mIconCache; 705b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final UserManagerCompat mUserManager; 713e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song private final AppWidgetManagerCompat mWidgetManager; 725b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final CacheDb mDb; 7341e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song private final int mProfileBadgeMargin; 7405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 7565d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos private final MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor(); 76316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk final Handler mWorkerHandler; 7765d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos 78383c507c47a5abf3258fc04220f37c366f983a97Sunny Goyal public WidgetPreviewLoader(Context context, IconCache iconCache) { 79fd13c714f412dfa8130fa7a664cb1692a565c539Chris Wren mContext = context; 805b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mIconCache = iconCache; 813e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song mWidgetManager = AppWidgetManagerCompat.getInstance(context); 825b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mUserManager = UserManagerCompat.getInstance(context); 835b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mDb = new CacheDb(context); 8405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mWorkerHandler = new Handler(LauncherModel.getWorkerLooper()); 8541e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song mProfileBadgeMargin = context.getResources() 8641e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song .getDimensionPixelSize(R.dimen.profile_badge_margin); 873f4e070aa58d51dd136885b4d3e2e6c5d9f93ea0Michael Jurka } 88ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal 895b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal /** 905b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * Generates the widget preview on {@link AsyncTask#THREAD_POOL_EXECUTOR}. Must be 915b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * called on UI thread 925b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * 935b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * @return a request id which can be used to cancel the request. 945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 954ddc40130aa0460924364eab3557088421eebe0cSunny Goyal public PreviewLoadRequest getPreview(WidgetItem item, int previewWidth, 962e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen int previewHeight, WidgetCell caller) { 975b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal String size = previewWidth + "x" + previewHeight; 984ddc40130aa0460924364eab3557088421eebe0cSunny Goyal WidgetCacheKey key = new WidgetCacheKey(item.componentName, item.user, size); 9905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1004ddc40130aa0460924364eab3557088421eebe0cSunny Goyal PreviewLoadTask task = new PreviewLoadTask(key, item, previewWidth, previewHeight, caller); 1018ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal task.executeOnExecutor(Utilities.THREAD_POOL_EXECUTOR); 102559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song return new PreviewLoadRequest(task); 10305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 10405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1055b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal /** 1065b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * The DB holds the generated previews for various components. Previews can also have different 1075b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * sizes (landscape vs portrait). 1085b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 1096f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal private static class CacheDb extends SQLiteCacheHelper { 1102d648b057fa2d6410b1472c1b9dd5b65cd9c9414Sunny Goyal private static final int DB_VERSION = 4; 1115b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 1125b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String TABLE_NAME = "shortcut_and_widget_previews"; 1135b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_COMPONENT = "componentName"; 1145b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_USER = "profileId"; 1155b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_SIZE = "size"; 1165b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_PACKAGE = "packageName"; 1175b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_LAST_UPDATED = "lastUpdated"; 1185b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_VERSION = "version"; 1195b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final String COLUMN_PREVIEW_BITMAP = "preview_bitmap"; 12005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 121d9cb4a124ac5c83080ace5ac92980df9c6f49e8eMichael Jurka public CacheDb(Context context) { 1226f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal super(context, LauncherFiles.WIDGET_PREVIEWS_DB, DB_VERSION, TABLE_NAME); 12305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 12405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 12505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka @Override 1266f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal public void onCreateTable(SQLiteDatabase database) { 12732b7a097338b77d8999c706c42f19e8ba060ba62Michael Jurka database.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + 1285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_COMPONENT + " TEXT NOT NULL, " + 1295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_USER + " INTEGER NOT NULL, " + 13005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka COLUMN_SIZE + " TEXT NOT NULL, " + 1315b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_PACKAGE + " TEXT NOT NULL, " + 1325b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, " + 1335b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, " + 1345b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal COLUMN_PREVIEW_BITMAP + " BLOB, " + 1355b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ", " + COLUMN_SIZE + ") " + 13632b7a097338b77d8999c706c42f19e8ba060ba62Michael Jurka ");"); 13705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 13805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 13905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1405b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Thunk void writeToDb(WidgetCacheKey key, long[] versions, Bitmap preview) { 14105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka ContentValues values = new ContentValues(); 1425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_COMPONENT, key.componentName.flattenToShortString()); 1435b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_USER, mUserManager.getSerialNumberForUser(key.user)); 1445b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_SIZE, key.size); 1455b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_PACKAGE, key.componentName.getPackageName()); 1465b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_VERSION, versions[0]); 1475b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_LAST_UPDATED, versions[1]); 1485b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal values.put(CacheDb.COLUMN_PREVIEW_BITMAP, Utilities.flattenBitmap(preview)); 1496f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal mDb.insertOrReplace(values); 15005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 15105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 1525b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public void removePackage(String packageName, UserHandleCompat user) { 1535b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal removePackage(packageName, user, mUserManager.getSerialNumberForUser(user)); 1545b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 1555b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 1565b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private void removePackage(String packageName, UserHandleCompat user, long userSerial) { 1575b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal synchronized(mPackageVersions) { 1585b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mPackageVersions.remove(packageName); 1595b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 1605b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 1616f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal mDb.delete( 1626f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal CacheDb.COLUMN_PACKAGE + " = ? AND " + CacheDb.COLUMN_USER + " = ?", 1636f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal new String[]{packageName, Long.toString(userSerial)}); 1648ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka } 1658ff02cac07a9c7fb0f321e93d67ad75cc588fbaeMichael Jurka 1665b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal /** 1675b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * Updates the persistent DB: 1685b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * 1. Any preview generated for an old package version is removed 1695b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * 2. Any preview for an absent package is removed 1705b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * This ensures that we remove entries for packages which changed while the launcher was dead. 1715b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 1724ddc40130aa0460924364eab3557088421eebe0cSunny Goyal public void removeObsoletePreviews(ArrayList<? extends ComponentKey> list) { 1736388b2c61b17bd6988f4243ad206c193a1e567c1Sunny Goyal Preconditions.assertWorkerThread(); 1748821ca9a6a5bf34308f9b70c2cabf9da17330497Hyunyoung Song 1755b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal LongSparseArray<HashSet<String>> validPackages = new LongSparseArray<>(); 1765b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 1774ddc40130aa0460924364eab3557088421eebe0cSunny Goyal for (ComponentKey key : list) { 1784ddc40130aa0460924364eab3557088421eebe0cSunny Goyal final long userId = mUserManager.getSerialNumberForUser(key.user); 1795b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal HashSet<String> packages = validPackages.get(userId); 1805b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (packages == null) { 1815b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages = new HashSet<>(); 1825b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal validPackages.put(userId, packages); 1835b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 1844ddc40130aa0460924364eab3557088421eebe0cSunny Goyal packages.add(key.componentName.getPackageName()); 18505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 1865b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 1875b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal LongSparseArray<HashSet<String>> packagesToDelete = new LongSparseArray<>(); 1885b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Cursor c = null; 1895b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal try { 1906f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal c = mDb.query( 1916f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal new String[]{CacheDb.COLUMN_USER, CacheDb.COLUMN_PACKAGE, 1926f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal CacheDb.COLUMN_LAST_UPDATED, CacheDb.COLUMN_VERSION}, 1936f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal null, null); 1945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal while (c.moveToNext()) { 1955b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long userId = c.getLong(0); 1965b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal String pkg = c.getString(1); 1975b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long lastUpdated = c.getLong(2); 1985b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long version = c.getLong(3); 1995b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2005b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal HashSet<String> packages = validPackages.get(userId); 2015b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (packages != null && packages.contains(pkg)) { 2025b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long[] versions = getPackageVersion(pkg); 2035b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (versions[0] == version && versions[1] == lastUpdated) { 2045b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // Every thing checks out 2055b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal continue; 2065b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2076e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 2085b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 2095b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // We need to delete this package. 2105b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages = packagesToDelete.get(userId); 2115b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (packages == null) { 2125b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages = new HashSet<>(); 2135b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packagesToDelete.put(userId, packages); 21405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 2155b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal packages.add(pkg); 21605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 21705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 2185b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal for (int i = 0; i < packagesToDelete.size(); i++) { 2195b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long userId = packagesToDelete.keyAt(i); 2205b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal UserHandleCompat user = mUserManager.getUserForSerialNumber(userId); 2215b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal for (String pkg : packagesToDelete.valueAt(i)) { 2225b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal removePackage(pkg, user, userId); 2236e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka } 224eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 2255b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (SQLException e) { 2266f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal Log.e(TAG, "Error updating widget previews", e); 2275b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } finally { 2285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (c != null) { 2295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal c.close(); 2305b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2315b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 232eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 233eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka 23405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung /** 23505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung * Reads the preview bitmap from the DB or null if the preview is not in the DB. 23605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung */ 237316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk Bitmap readFromDb(WidgetCacheKey key, Bitmap recycle, PreviewLoadTask loadTask) { 2385b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Cursor cursor = null; 2396e27f642ae66dd1920b25b527fced7268943d11aMichael Jurka try { 2406f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal cursor = mDb.query( 2416f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal new String[]{CacheDb.COLUMN_PREVIEW_BITMAP}, 2426f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal CacheDb.COLUMN_COMPONENT + " = ? AND " + CacheDb.COLUMN_USER + " = ? AND " 2436f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal + CacheDb.COLUMN_SIZE + " = ?", 2446f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal new String[]{ 2455b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal key.componentName.flattenToString(), 2465b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Long.toString(mUserManager.getSerialNumberForUser(key.user)), 2475b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal key.size 2486f70936f7fb7cb45ef6a2a3d1019b6ecf3e49440Sunny Goyal }); 24905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If cancelled, skip getting the blob and decoding it into a bitmap 25005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (loadTask.isCancelled()) { 25105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung return null; 25205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 2535b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (cursor.moveToNext()) { 2545b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal byte[] blob = cursor.getBlob(0); 2555b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal BitmapFactory.Options opts = new BitmapFactory.Options(); 2565b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal opts.inBitmap = recycle; 2575b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal try { 25805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (!loadTask.isCancelled()) { 25905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung return BitmapFactory.decodeByteArray(blob, 0, blob.length, opts); 26005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 2615b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (Exception e) { 2625b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return null; 2635b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2645b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 2655b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (SQLException e) { 2665b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.w(TAG, "Error loading preview from DB", e); 2675b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } finally { 2685b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (cursor != null) { 2695b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal cursor.close(); 270eb1bb920507fe7f27b2ecece5b67749dac7850f3Michael Jurka } 27105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 2725b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return null; 27305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 27405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 2754ddc40130aa0460924364eab3557088421eebe0cSunny Goyal private Bitmap generatePreview(Launcher launcher, WidgetItem item, Bitmap recycle, 2762e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen int previewWidth, int previewHeight) { 2774ddc40130aa0460924364eab3557088421eebe0cSunny Goyal if (item.widgetInfo != null) { 2784ddc40130aa0460924364eab3557088421eebe0cSunny Goyal return generateWidgetPreview(launcher, item.widgetInfo, 2792e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen previewWidth, recycle, null); 28005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 2814ddc40130aa0460924364eab3557088421eebe0cSunny Goyal return generateShortcutPreview(launcher, item.activityInfo, 2824ddc40130aa0460924364eab3557088421eebe0cSunny Goyal previewWidth, previewHeight, recycle); 28305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 28405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 28505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 2863e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song /** 2873e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song * Generates the widget preview from either the {@link AppWidgetManagerCompat} or cache 2883e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song * and add badge at the bottom right corner. 2893e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song * 2903e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song * @param launcher 2913e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song * @param info information about the widget 2923e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song * @param maxPreviewWidth width of the preview on either workspace or tray 2933e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song * @param preview bitmap that can be recycled 2943e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song * @param preScaledWidthOut return the width of the returned bitmap 2953e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song * @return 2963e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song */ 2972e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen public Bitmap generateWidgetPreview(Launcher launcher, LauncherAppWidgetProviderInfo info, 2984cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int maxPreviewWidth, Bitmap preview, int[] preScaledWidthOut) { 29905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Load the preview image if possible 30005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (maxPreviewWidth < 0) maxPreviewWidth = Integer.MAX_VALUE; 30105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 30205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Drawable drawable = null; 303ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal if (info.previewImage != 0) { 3043e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song drawable = mWidgetManager.loadPreview(info); 305fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos if (drawable != null) { 306fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos drawable = mutateOnMainThread(drawable); 307fa9ffc28fd4d230cf38b55840238f5595716abc8Adrian Roos } else { 30805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka Log.w(TAG, "Can't load widget preview drawable 0x" + 309ffe83f13319cdb833a25596d47cf1af098cc4c60Sunny Goyal Integer.toHexString(info.previewImage) + " for provider: " + info.provider); 31005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 31105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 31205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 3134cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final boolean widgetPreviewExists = (drawable != null); 314233ee964a9ecf419a3e8330a67456d422879132dSunny Goyal final int spanX = info.spanX; 315233ee964a9ecf419a3e8330a67456d422879132dSunny Goyal final int spanY = info.spanY; 3164cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 31705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int previewWidth; 31805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int previewHeight; 3193e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song 3204cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Bitmap tileBitmap = null; 3214cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 32205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (widgetPreviewExists) { 32305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewWidth = drawable.getIntrinsicWidth(); 32405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = drawable.getIntrinsicHeight(); 32505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 32605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Generate a preview image if we couldn't load one 3274cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal tileBitmap = ((BitmapDrawable) mContext.getResources().getDrawable( 3284cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal R.drawable.widget_tile)).getBitmap(); 3294cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal previewWidth = tileBitmap.getWidth() * spanX; 3304cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal previewHeight = tileBitmap.getHeight() * spanY; 33105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 33205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 33305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Scale to fit width only - let the widget preview be clipped in the 33405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // vertical dimension 33505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka float scale = 1f; 33605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preScaledWidthOut != null) { 33705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preScaledWidthOut[0] = previewWidth; 33805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 33905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (previewWidth > maxPreviewWidth) { 340b9f932e08902c21020b6a98372c1a68548b8de59Hyunyoung Song scale = (maxPreviewWidth - 2 * mProfileBadgeMargin) / (float) (previewWidth); 34105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 34205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (scale != 1f) { 34305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewWidth = (int) (scale * previewWidth); 34405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka previewHeight = (int) (scale * previewHeight); 34505713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 34605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 34705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // If a bitmap is passed in, we use it; otherwise, we create a bitmap of the right size 3484cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Canvas c = new Canvas(); 34905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (preview == null) { 35005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka preview = Bitmap.createBitmap(previewWidth, previewHeight, Config.ARGB_8888); 3514cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 3524cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } else { 3534cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Reusing bitmap. Clear it. 3544cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 3554cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.drawColor(0, PorterDuff.Mode.CLEAR); 35605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 35705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 35805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka // Draw the scaled preview into the final bitmap 359b9f932e08902c21020b6a98372c1a68548b8de59Hyunyoung Song int x = (preview.getWidth() - previewWidth) / 2; 36005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka if (widgetPreviewExists) { 3614cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal drawable.setBounds(x, 0, x + previewWidth, previewHeight); 3624cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal drawable.draw(c); 36305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 3644cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Paint p = new Paint(); 3654cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal p.setFilterBitmap(true); 3662e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen int appIconSize = launcher.getDeviceProfile().iconSizePx; 3674cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 3684cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // draw the spanX x spanY tiles 3694cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Rect src = new Rect(0, 0, tileBitmap.getWidth(), tileBitmap.getHeight()); 3704cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 3714cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float tileW = scale * tileBitmap.getWidth(); 3724cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float tileH = scale * tileBitmap.getHeight(); 3734cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final RectF dst = new RectF(0, 0, tileW, tileH); 3744cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 3754cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float tx = x; 3764cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal for (int i = 0; i < spanX; i++, tx += tileW) { 3774cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal float ty = 0; 3784cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal for (int j = 0; j < spanY; j++, ty += tileH) { 3794cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal dst.offsetTo(tx, ty); 3804cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.drawBitmap(tileBitmap, src, dst, p); 3814cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } 38205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 3834cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 3844cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Draw the icon in the top left corner 3854cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // TODO: use top right for RTL 3865b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal int minOffset = (int) (appIconSize * WIDGET_PREVIEW_ICON_PADDING_PERCENTAGE); 3874cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int smallestSide = Math.min(previewWidth, previewHeight); 3885b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal float iconScale = Math.min((float) smallestSide / (appIconSize + 2 * minOffset), scale); 3894cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 3904cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal try { 3913e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song Drawable icon = mWidgetManager.loadIcon(info, mIconCache); 3924cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal if (icon != null) { 3931ba7e36cc8901b34b91d06fdc868a63f9a8fad2dSunny Goyal icon = mutateOnMainThread(icon); 3945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal int hoffset = (int) ((tileW - appIconSize * iconScale) / 2) + x; 3955b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal int yoffset = (int) ((tileH - appIconSize * iconScale) / 2); 3964cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setBounds(hoffset, yoffset, 3975b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal hoffset + (int) (appIconSize * iconScale), 3985b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal yoffset + (int) (appIconSize * iconScale)); 3994cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.draw(c); 4004cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } 4013e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song } catch (Resources.NotFoundException e) { 4023e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song } 40305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 40405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 4053e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song int imageWidth = Math.min(preview.getWidth(), previewWidth + mProfileBadgeMargin); 40641e3369d5fffb2e8dfa33bfcb14386ad339b0f2fHyunyoung Song int imageHeight = Math.min(preview.getHeight(), previewHeight + mProfileBadgeMargin); 4073e840f4343086ed78a8ae44fd543a9863d868dc9Hyunyoung Song return mWidgetManager.getBadgeBitmap(info, preview, imageWidth, imageHeight); 40805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 40905713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 41005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka private Bitmap generateShortcutPreview( 4114ddc40130aa0460924364eab3557088421eebe0cSunny Goyal Launcher launcher, ActivityInfo info, int maxWidth, int maxHeight, Bitmap preview) { 4124cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal final Canvas c = new Canvas(); 4134cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal if (preview == null) { 4144cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal preview = Bitmap.createBitmap(maxWidth, maxHeight, Config.ARGB_8888); 4154cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 4164cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal } else if (preview.getWidth() != maxWidth || preview.getHeight() != maxHeight) { 4174cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal throw new RuntimeException("Improperly sized bitmap passed as argument"); 41805713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } else { 4194cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Reusing bitmap. Clear it. 4204cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal c.setBitmap(preview); 42105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.drawColor(0, PorterDuff.Mode.CLEAR); 42205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 42305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4244ddc40130aa0460924364eab3557088421eebe0cSunny Goyal Drawable icon = mutateOnMainThread(mIconCache.getFullResIcon(info)); 4254cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setFilterBitmap(true); 42605713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4274cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Draw a desaturated/scaled version of the icon in the background as a watermark 4284cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal ColorMatrix colorMatrix = new ColorMatrix(); 4294cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal colorMatrix.setSaturation(0); 4304cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setColorFilter(new ColorMatrixColorFilter(colorMatrix)); 4314cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setAlpha((int) (255 * 0.06f)); 4324cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal 4334cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal Resources res = mContext.getResources(); 4344cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int paddingTop = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_top); 4354cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int paddingLeft = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_left); 4364cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal int paddingRight = res.getDimensionPixelOffset(R.dimen.shortcut_preview_padding_right); 43705713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka int scaledIconWidth = (maxWidth - paddingLeft - paddingRight); 4384cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setBounds(paddingLeft, paddingTop, 4394cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal paddingLeft + scaledIconWidth, paddingTop + scaledIconWidth); 4404cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.draw(c); 44105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 4424cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // Draw the final icon at top left corner. 4434cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal // TODO: use top right for RTL 4442e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen int appIconSize = launcher.getDeviceProfile().iconSizePx; 4452e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen 4464cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setAlpha(255); 4474cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.setColorFilter(null); 4485b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal icon.setBounds(0, 0, appIconSize, appIconSize); 4494cad7538c9615303d291f5b52e960aaf0985828fSunny Goyal icon.draw(c); 45005713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 45105713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka c.setBitmap(null); 45205713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka return preview; 45305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka } 45405713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka 45565d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos private Drawable mutateOnMainThread(final Drawable drawable) { 45665d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos try { 45765d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos return mMainThreadExecutor.submit(new Callable<Drawable>() { 45865d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos @Override 45965d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos public Drawable call() throws Exception { 46065d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos return drawable.mutate(); 46165d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 46265d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos }).get(); 46365d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } catch (InterruptedException e) { 46465d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos Thread.currentThread().interrupt(); 46565d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos throw new RuntimeException(e); 46665d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } catch (ExecutionException e) { 46765d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos throw new RuntimeException(e); 46865d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 46965d60e21ec22e3bf03ba39f7a0be24df2cc914a2Adrian Roos } 4701f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos 4711f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos /** 4725b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * @return an array of containing versionCode and lastUpdatedTime for the package. 4731f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos */ 474316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk long[] getPackageVersion(String packageName) { 4755b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal synchronized (mPackageVersions) { 4765b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal long[] versions = mPackageVersions.get(packageName); 4775b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (versions == null) { 4785b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal versions = new long[2]; 4791f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos try { 4804ddc40130aa0460924364eab3557088421eebe0cSunny Goyal PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 4814ddc40130aa0460924364eab3557088421eebe0cSunny Goyal PackageManager.GET_UNINSTALLED_PACKAGES); 4825b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal versions[0] = info.versionCode; 4835b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal versions[1] = info.lastUpdateTime; 4845b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (NameNotFoundException e) { 4855b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.e(TAG, "PackageInfo not found", e); 4865b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 4875b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mPackageVersions.put(packageName, versions); 4885b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 4895b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return versions; 4905b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 4915b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 4925b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 4935b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal /** 4945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * A request Id which can be used by the client to cancel any request. 4955b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 4965b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public class PreviewLoadRequest { 4975b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 498b4cbea4ad4ce06b591603a47f86cfd9df838ccb1Sunny Goyal @Thunk final PreviewLoadTask mTask; 4995b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 500559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song public PreviewLoadRequest(PreviewLoadTask task) { 5015b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mTask = task; 5025b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5035b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 504559d90d0dafbac1d97a1e6f18062309831a25d51Hyunyoung Song public void cleanup() { 5055b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (mTask != null) { 5065b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mTask.cancel(true); 5075b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5085b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 50905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // This only handles the case where the PreviewLoadTask is cancelled after the task has 51005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // successfully completed (including having written to disk when necessary). In the 51105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // other cases where it is cancelled while the task is running, it will be cleaned up 51205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // in the tasks's onCancelled() call, and if cancelled while the task is writing to 51305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // disk, it will be cancelled in the task's onPostExecute() call. 51405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (mTask.mBitmapToRecycle != null) { 515e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mWorkerHandler.post(new Runnable() { 516e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song @Override 517e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song public void run() { 518e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song synchronized (mUnusedBitmaps) { 519e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mUnusedBitmaps.add(mTask.mBitmapToRecycle); 520e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song } 521e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mTask.mBitmapToRecycle = null; 522e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song } 523e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song }); 5245b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5255b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5265b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5275b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public class PreviewLoadTask extends AsyncTask<Void, Void, Bitmap> { 529316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk final WidgetCacheKey mKey; 5304ddc40130aa0460924364eab3557088421eebe0cSunny Goyal private final WidgetItem mInfo; 5315b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final int mPreviewHeight; 5325b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private final int mPreviewWidth; 5333f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song private final WidgetCell mCaller; 534316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk long[] mVersions; 535316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk Bitmap mBitmapToRecycle; 5365b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5374ddc40130aa0460924364eab3557088421eebe0cSunny Goyal PreviewLoadTask(WidgetCacheKey key, WidgetItem info, int previewWidth, 5383f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song int previewHeight, WidgetCell caller) { 5395b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mKey = key; 5405b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mInfo = info; 5415b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mPreviewHeight = previewHeight; 5425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mPreviewWidth = previewWidth; 5435b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal mCaller = caller; 5443f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song if (DEBUG) { 5453f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song Log.d(TAG, String.format("%s, %s, %d, %d", 5463f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song mKey, mInfo, mPreviewHeight, mPreviewWidth)); 5473f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song } 5485b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5495b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5505b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 5515b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal protected Bitmap doInBackground(Void... params) { 5525b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Bitmap unusedBitmap = null; 5533f471440a8b6b71d4c15501a96befd3b715c9e8fHyunyoung Song 554f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song // If already cancelled before this gets to run in the background, then return early 555f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song if (isCancelled()) { 556f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song return null; 557f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song } 5585b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal synchronized (mUnusedBitmaps) { 559f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song // Check if we can re-use a bitmap 5605b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal for (Bitmap candidate : mUnusedBitmaps) { 5615b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (candidate != null && candidate.isMutable() && 5625b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal candidate.getWidth() == mPreviewWidth && 5635b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal candidate.getHeight() == mPreviewHeight) { 5645b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal unusedBitmap = candidate; 565f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song mUnusedBitmaps.remove(unusedBitmap); 5665b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal break; 5671f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 5685b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 569f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song } 5705b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 571f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song // creating a bitmap is expensive. Do not do this inside synchronized block. 572f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song if (unusedBitmap == null) { 573f00d02b254d94eeaf52742e0640e9eacd63fafcaHyunyoung Song unusedBitmap = Bitmap.createBitmap(mPreviewWidth, mPreviewHeight, Config.ARGB_8888); 5745b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 57505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If cancelled now, don't bother reading the preview from the DB 5765b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (isCancelled()) { 57705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung return unusedBitmap; 5785b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 57905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung Bitmap preview = readFromDb(mKey, unusedBitmap, this); 58005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // Only consider generating the preview if we have not cancelled the task already 5815b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal if (!isCancelled() && preview == null) { 5825b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // Fetch the version info before we generate the preview, so that, in-case the 5835b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // app was updated while we are generating the preview, we use the old version info, 5845b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // which would gets re-written next time. 58505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mVersions = getPackageVersion(mKey.componentName.getPackageName()); 5865b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 587abef55a1c1f1fda4f42e4b4223534dd21f3dc19fAndrew Sapperstein Launcher launcher = Launcher.getLauncher(mCaller.getContext()); 5882e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen 5895b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // it's not in the db... we need to generate it 5902e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen preview = generatePreview(launcher, mInfo, unusedBitmap, mPreviewWidth, mPreviewHeight); 5911f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 5925b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return preview; 5935b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 5945b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 5955b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 59605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung protected void onPostExecute(final Bitmap preview) { 59705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mCaller.applyPreview(preview); 59805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung 59905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // Write the generated preview to the DB in the worker thread 60005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (mVersions != null) { 60105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mWorkerHandler.post(new Runnable() { 60205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung @Override 60305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung public void run() { 60405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (!isCancelled()) { 60505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If we are still using this preview, then write it to the DB and then 60605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // let the normal clear mechanism recycle the bitmap 60705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung writeToDb(mKey, mVersions, preview); 60805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mBitmapToRecycle = preview; 60905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } else { 61005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If we've already cancelled, then skip writing the bitmap to the DB 61105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // and manually add the bitmap back to the recycled set 61205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung synchronized (mUnusedBitmaps) { 61305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mUnusedBitmaps.add(preview); 61405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 61505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 61605304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 61705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung }); 61805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } else { 61905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If we don't need to write to disk, then ensure the preview gets recycled by 62005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // the normal clear mechanism 62105304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung mBitmapToRecycle = preview; 62205304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 62305304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 62405304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung 62505304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung @Override 626e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song protected void onCancelled(final Bitmap preview) { 62705304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // If we've cancelled while the task is running, then can return the bitmap to the 62805304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // recycled set immediately. Otherwise, it will be recycled after the preview is written 62905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung // to disk. 63005304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung if (preview != null) { 631e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mWorkerHandler.post(new Runnable() { 632e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song @Override 633e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song public void run() { 634e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song synchronized (mUnusedBitmaps) { 635e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song mUnusedBitmaps.add(preview); 636e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song } 637e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song } 638e98f4a4d6dac0aa4fc6b35b46ab10aff06251ffcHyunyoung Song }); 63905304db9053b4794bd7e776ff6e80cd1ae653110Winson Chung } 6405b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 6415b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 6425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6435b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal private static final class WidgetCacheKey extends ComponentKey { 6445b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6455b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // TODO: remove dependency on size 646316490e636aad788fcfbfc2e04dd4f0e145bdd00Sunny Goyal @Thunk final String size; 6475b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6485b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public WidgetCacheKey(ComponentName componentName, UserHandleCompat user, String size) { 6495b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal super(componentName, user); 6505b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal this.size = size; 6515b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 6525b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6535b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 6545b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public int hashCode() { 6555b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return super.hashCode() ^ size.hashCode(); 6565b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 6575b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 6585b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal @Override 6595b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public boolean equals(Object o) { 6605b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return super.equals(o) && ((WidgetCacheKey) o).size.equals(size); 6611f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 6621f375ab63339359e1f8cd44cede466adedcdcc62Adrian Roos } 66305713af127d765cc28a8b2fd548a90347c90d6cbMichael Jurka} 664