Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ec390e4 authored by Pinyao Ting's avatar Pinyao Ting
Browse files

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
parent 28dc8de6
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -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
+21 −7
Original line number Diff line number Diff line
@@ -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<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
+2 −7
Original line number Diff line number Diff line
@@ -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;
+9 −8
Original line number Diff line number Diff line
@@ -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() {
        Drawable d = mView.getBackground();
        Rect bounds = getDrawableBounds(d);

        int size = Launcher.getLauncher(mView.getContext()).getDeviceProfile().iconSizePx;
        final Bitmap b = Bitmap.createBitmap(
        return BitmapRenderer.createHardwareBitmap(
                size + blurSizeOutline,
                size + blurSizeOutline,
                Bitmap.Config.ARGB_8888);
                (c) -> drawDragViewOnBackground(c, size));
    }

        Canvas canvas = new Canvas(b);
    private void drawDragViewOnBackground(Canvas canvas, float size) {
        Drawable d = mView.getBackground();
        Rect bounds = getDrawableBounds(d);
        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
+30 −0
Original line number Diff line number Diff line
@@ -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();