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
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index 8ebf464..0b79dd2 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 @@
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 c6949af..0f5d290 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -24,6 +24,7 @@
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.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 @@
}
// 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<ItemInfoWithIcon> fallbackIconProvider) {
+ @WorkerThread
+ public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged,
+ @Nullable Supplier<ItemInfoWithIcon> fallbackIconProvider) {
+ return createShortcutIcon(shortcutInfo, badged, true, fallbackIconProvider);
+ }
+
+ @WorkerThread
+ public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged,
+ boolean useCache, @Nullable Supplier<ItemInfoWithIcon> 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 68ea6c4..5b6b56d 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 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 @@
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 ee97641..408ced2 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java
@@ -26,6 +26,7 @@
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 @@
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 49c97da..a69cd6c 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 @@
&& 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();