From 4ec390e490dfb1503909853eb55df85f79e9813a Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Tue, 1 Oct 2019 14:28:05 -0700 Subject: [PATCH] fetch and update shortcut icons in background thread Bug: 141568904 Test: Manually verified use cases from following call-site (with and without delay) LauncherAppsCompatVO 1. (Custom Shortcut) Long click on google maps -> widgets -> drag driving mode to workspace. 2. Open chrome -> add to home screen -> add -> add automatically. InstallShortcutReceiver Removed the line that trigger above flow for android O and above, then open chrome -> add to home screen -> add -> add automatically. ShortcutDragPreviewProvider qdb -> long press on suggested app that has deep shortcut -> drag to workspace. Change-Id: I59a4d004913a8df697af1fcfe0a080b6da01eefd --- .../launcher3/InstallShortcutReceiver.java | 5 ++-- .../launcher3/icons/LauncherIcons.java | 28 ++++++++++++----- .../launcher3/pm/PinRequestHelper.java | 9 ++---- .../ShortcutDragPreviewProvider.java | 21 ++++++------- .../android/launcher3/util/ShortcutUtil.java | 30 +++++++++++++++++++ 5 files changed, 66 insertions(+), 27 deletions(-) diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index 8ebf46442f..0b79dd2835 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -17,6 +17,7 @@ package com.android.launcher3; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import static com.android.launcher3.util.ShortcutUtil.fetchAndUpdateShortcutIconAsync; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; @@ -482,9 +483,7 @@ public class InstallShortcutReceiver extends BroadcastReceiver { return Pair.create(si, null); } else if (shortcutInfo != null) { WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(shortcutInfo, mContext); - LauncherIcons li = LauncherIcons.obtain(mContext); - itemInfo.applyFrom(li.createShortcutIcon(shortcutInfo)); - li.recycle(); + fetchAndUpdateShortcutIconAsync(mContext, itemInfo, shortcutInfo, true); return Pair.create(itemInfo, shortcutInfo); } else if (providerInfo != null) { LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java index c6949afc37..0f5d2903ce 100644 --- a/src/com/android/launcher3/icons/LauncherIcons.java +++ b/src/com/android/launcher3/icons/LauncherIcons.java @@ -24,6 +24,7 @@ import android.graphics.Bitmap; import android.os.Process; import androidx.annotation.Nullable; +import androidx.annotation.WorkerThread; import com.android.launcher3.AppInfo; import com.android.launcher3.FastBitmapDrawable; @@ -32,7 +33,6 @@ import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.graphics.IconShape; -import com.android.launcher3.icons.cache.BaseIconCache; import com.android.launcher3.model.PackageItemInfo; import com.android.launcher3.util.Themes; @@ -114,23 +114,37 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { } // below methods should also migrate to BaseIconFactory - + @WorkerThread public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo) { return createShortcutIcon(shortcutInfo, true /* badged */); } + @WorkerThread public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged) { return createShortcutIcon(shortcutInfo, badged, null); } - public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, - boolean badged, @Nullable Supplier fallbackIconProvider) { + @WorkerThread + public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged, + @Nullable Supplier fallbackIconProvider) { + return createShortcutIcon(shortcutInfo, badged, true, fallbackIconProvider); + } + + @WorkerThread + public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged, + boolean useCache, @Nullable Supplier fallbackIconProvider) { IconCache cache = LauncherAppState.getInstance(mContext).getIconCache(); - BaseIconCache.CacheEntry entry = cache.getDeepShortcutTitleAndIcon(shortcutInfo); + final BitmapInfo bitmapInfo; + if (useCache) { + bitmapInfo = cache.getDeepShortcutTitleAndIcon(shortcutInfo); + } else { + bitmapInfo = new BitmapInfo(); + new ShortcutCachingLogic().loadIcon(mContext, shortcutInfo, bitmapInfo); + } final Bitmap unbadgedBitmap; - if (entry.icon != null) { - unbadgedBitmap = entry.icon; + if (bitmapInfo.icon != null) { + unbadgedBitmap = bitmapInfo.icon; } else { if (fallbackIconProvider != null) { // Fallback icons are already badged and with appropriate shadow diff --git a/src/com/android/launcher3/pm/PinRequestHelper.java b/src/com/android/launcher3/pm/PinRequestHelper.java index 68ea6c43ad..5b6b56d858 100644 --- a/src/com/android/launcher3/pm/PinRequestHelper.java +++ b/src/com/android/launcher3/pm/PinRequestHelper.java @@ -17,6 +17,7 @@ package com.android.launcher3.pm; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import static com.android.launcher3.util.ShortcutUtil.fetchAndUpdateShortcutIconAsync; import android.annotation.TargetApi; import android.content.Context; @@ -29,9 +30,7 @@ import android.os.Parcelable; import androidx.annotation.Nullable; -import com.android.launcher3.LauncherAppState; import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.icons.LauncherIcons; public class PinRequestHelper { @@ -81,11 +80,7 @@ public class PinRequestHelper { ShortcutInfo si = request.getShortcutInfo(); WorkspaceItemInfo info = new WorkspaceItemInfo(si, context); // Apply the unbadged icon and fetch the actual icon asynchronously. - LauncherIcons li = LauncherIcons.obtain(context); - info.applyFrom(li.createShortcutIcon(si, false /* badged */)); - li.recycle(); - LauncherAppState.getInstance(context).getModel() - .updateAndBindWorkspaceItem(info, si); + fetchAndUpdateShortcutIconAsync(context, info, si, false); return info; } else { return null; diff --git a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java index ee97641109..408ced20e2 100644 --- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java +++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java @@ -26,6 +26,7 @@ import android.view.View; import com.android.launcher3.Launcher; import com.android.launcher3.Utilities; import com.android.launcher3.graphics.DragPreviewProvider; +import com.android.launcher3.icons.BitmapRenderer; /** * Extension of {@link DragPreviewProvider} which generates bitmaps scaled to the default icon size. @@ -39,22 +40,22 @@ public class ShortcutDragPreviewProvider extends DragPreviewProvider { mPositionShift = shift; } + @Override public Bitmap createDragBitmap() { + int size = Launcher.getLauncher(mView.getContext()).getDeviceProfile().iconSizePx; + return BitmapRenderer.createHardwareBitmap( + size + blurSizeOutline, + size + blurSizeOutline, + (c) -> drawDragViewOnBackground(c, size)); + } + + private void drawDragViewOnBackground(Canvas canvas, float size) { Drawable d = mView.getBackground(); Rect bounds = getDrawableBounds(d); - - int size = Launcher.getLauncher(mView.getContext()).getDeviceProfile().iconSizePx; - final Bitmap b = Bitmap.createBitmap( - size + blurSizeOutline, - size + blurSizeOutline, - Bitmap.Config.ARGB_8888); - - Canvas canvas = new Canvas(b); canvas.translate(blurSizeOutline / 2, blurSizeOutline / 2); - canvas.scale(((float) size) / bounds.width(), ((float) size) / bounds.height(), 0, 0); + canvas.scale(size / bounds.width(), size / bounds.height(), 0, 0); canvas.translate(bounds.left, bounds.top); d.draw(canvas); - return b; } @Override diff --git a/src/com/android/launcher3/util/ShortcutUtil.java b/src/com/android/launcher3/util/ShortcutUtil.java index 49c97daf35..a69cd6c085 100644 --- a/src/com/android/launcher3/util/ShortcutUtil.java +++ b/src/com/android/launcher3/util/ShortcutUtil.java @@ -15,10 +15,20 @@ */ package com.android.launcher3.util; +import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; + +import android.content.Context; +import android.content.pm.ShortcutInfo; + +import androidx.annotation.NonNull; + import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.Utilities; import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.icons.BitmapInfo; +import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.shortcuts.ShortcutKey; @@ -61,6 +71,26 @@ public class ShortcutUtil { && info instanceof WorkspaceItemInfo; } + /** + * Fetch the shortcut icon in background, then update the UI. + */ + public static void fetchAndUpdateShortcutIconAsync( + @NonNull Context context, @NonNull WorkspaceItemInfo info, @NonNull ShortcutInfo si, + boolean badged) { + if (info.iconBitmap == null) { + // use low res icon as placeholder while the actual icon is being fetched. + info.iconBitmap = BitmapInfo.LOW_RES_ICON; + info.iconColor = Themes.getColorAccent(context); + } + MODEL_EXECUTOR.execute(() -> { + LauncherIcons li = LauncherIcons.obtain(context); + BitmapInfo bitmapInfo = li.createShortcutIcon(si, badged, true, null); + info.applyFrom(bitmapInfo); + li.recycle(); + LauncherAppState.getInstance(context).getModel().updateAndBindWorkspaceItem(info, si); + }); + } + private static boolean isActive(ItemInfo info) { boolean isLoading = info instanceof WorkspaceItemInfo && ((WorkspaceItemInfo) info).hasPromiseIconUi();