From c1a1ced33ad52f020cfa20dc5630934519ea4dc6 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Wed, 23 Oct 2019 17:47:28 +0000 Subject: [PATCH] Add IconCache support for deep shortcuts, loads deepshortcut on background thread. Added a feature flag to toggle on/off this feature. Bug: 140242324 Test: 1. (Custom Shortcut) Long click on google maps -> widgets -> drag driving mode to workspace. 2. Open chrome -> add to home screen -> add -> add automatically. 3. InstallShortcutReceiver In Launcher.completeAddShortcut, commend out the code that calls PinRequestHelper.createWorkspaceItemFromPinItemRequest, then open chrome -> add to home screen -> add -> add automatically. 4. ShortcutDragPreviewProvider qdb -> long press on suggested app that has deep shortcut -> drag to workspace. Change-Id: If7babe4eddf5434909bf686b4e9bde15e444d9fd --- .../launcher3/icons/cache/CachingLogic.java | 8 ++ .../icons/cache/IconCacheUpdateHandler.java | 4 +- .../launcher3/InstallShortcutReceiver.java | 12 ++- .../launcher3/config/FeatureFlags.java | 3 + .../android/launcher3/icons/IconCache.java | 12 +++ .../launcher3/icons/LauncherIcons.java | 55 ++++++++++++- .../launcher3/icons/ShortcutCachingLogic.java | 79 +++++++++++++++++++ .../android/launcher3/model/LoaderTask.java | 29 +++++-- .../launcher3/pm/PinRequestHelper.java | 16 ++-- .../ShortcutDragPreviewProvider.java | 27 ++++++- .../android/launcher3/util/ShortcutUtil.java | 24 ++++++ 11 files changed, 248 insertions(+), 21 deletions(-) create mode 100644 src/com/android/launcher3/icons/ShortcutCachingLogic.java diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java index ea1ca536fc..a89ede7b34 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java @@ -17,6 +17,7 @@ package com.android.launcher3.icons.cache; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageInfo; import android.os.LocaleList; import android.os.UserHandle; @@ -44,6 +45,13 @@ public interface CachingLogic { return null; } + /** + * Returns the timestamp the entry was last updated in cache. + */ + default long getLastUpdatedTime(T object, PackageInfo info) { + return info.lastUpdateTime; + } + /** * Returns true the object should be added to mem cache; otherwise returns false. */ diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java index 8224966d87..bcdbce5e29 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java @@ -171,7 +171,8 @@ public class IconCacheUpdateHandler { long updateTime = c.getLong(indexLastUpdate); int version = c.getInt(indexVersion); T app = componentMap.remove(component); - if (version == info.versionCode && updateTime == info.lastUpdateTime + if (version == info.versionCode + && updateTime == cachingLogic.getLastUpdatedTime(app, info) && TextUtils.equals(c.getString(systemStateIndex), mIconCache.getIconSystemState(info.packageName))) { @@ -231,7 +232,6 @@ public class IconCacheUpdateHandler { } } - /** * A runnable that updates invalid icons and adds missing icons in the DB for the provided * LauncherActivityInfo list. Items are updated/added one at a time, so that the diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index 125332d5b3..21359f1dc3 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; @@ -44,6 +45,7 @@ import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.GraphicsUtils; import com.android.launcher3.icons.LauncherIcons; @@ -489,9 +491,13 @@ 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.bitmap = li.createShortcutIcon(shortcutInfo); - li.recycle(); + if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) { + fetchAndUpdateShortcutIconAsync(mContext, itemInfo, shortcutInfo, true); + } else { + LauncherIcons li = LauncherIcons.obtain(mContext); + itemInfo.bitmap = li.createShortcutIcon(shortcutInfo); + li.recycle(); + } return Pair.create(itemInfo, shortcutInfo); } else if (providerInfo != null) { LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 5689846b4b..d622037663 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -127,6 +127,9 @@ public final class FeatureFlags { public static final TogglableFlag ENABLE_HYBRID_HOTSEAT = new TogglableFlag( "ENABLE_HYBRID_HOTSEAT", false, "Fill gaps in hotseat with predicted apps"); + public static final TogglableFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = new TogglableFlag( + "ENABLE_DEEP_SHORTCUT_ICON_CACHE", true, "R/W deep shortcut in IconCache"); + public static void initialize(Context context) { // Avoid the disk read for user builds if (Utilities.IS_DEBUG_DEVICE) { diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index f7faca6899..4ac6ff4840 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -28,6 +28,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ShortcutInfo; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Process; @@ -49,6 +50,7 @@ import com.android.launcher3.icons.cache.BaseIconCache; import com.android.launcher3.icons.cache.CachingLogic; import com.android.launcher3.icons.cache.HandlerRunnable; import com.android.launcher3.model.PackageItemInfo; +import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.PackageUserKey; @@ -65,6 +67,7 @@ public class IconCache extends BaseIconCache { private final CachingLogic mComponentWithLabelCachingLogic; private final CachingLogic mLauncherActivityInfoCachingLogic; + private final CachingLogic mShortcutCachingLogic; private final LauncherApps mLauncherApps; private final UserManagerCompat mUserManager; @@ -78,6 +81,7 @@ public class IconCache extends BaseIconCache { inv.fillResIconDpi, inv.iconBitmapSize, true /* inMemoryCache */); mComponentWithLabelCachingLogic = new ComponentCachingLogic(context, false); mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.newInstance(context); + mShortcutCachingLogic = new ShortcutCachingLogic(); mLauncherApps = mContext.getSystemService(LauncherApps.class); mUserManager = UserManagerCompat.getInstance(mContext); mInstantAppResolver = InstantAppResolver.newInstance(mContext); @@ -175,6 +179,14 @@ public class IconCache extends BaseIconCache { getTitleAndIcon(info, () -> activityInfo, false, useLowResIcon); } + /** + * Fill in info with the icon and label for deep shortcut. + */ + public synchronized CacheEntry getDeepShortcutTitleAndIcon(ShortcutInfo info) { + return cacheLocked(ShortcutKey.fromInfo(info).componentName, info.getUserHandle(), + () -> info, mShortcutCachingLogic, false, false); + } + /** * Fill in {@param info} with the icon and label. If the * corresponding activity is not found, it reverts to the package icon. diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java index 3c4041a1df..4d3599e4d1 100644 --- a/src/com/android/launcher3/icons/LauncherIcons.java +++ b/src/com/android/launcher3/icons/LauncherIcons.java @@ -25,12 +25,14 @@ import android.graphics.drawable.Drawable; import android.os.Process; import androidx.annotation.Nullable; +import androidx.annotation.WorkerThread; import com.android.launcher3.AppInfo; import com.android.launcher3.FastBitmapDrawable; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.LauncherAppState; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.graphics.IconShape; import com.android.launcher3.model.PackageItemInfo; import com.android.launcher3.shortcuts.DeepShortcutManager; @@ -112,7 +114,6 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { } // below methods should also migrate to BaseIconFactory - public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo) { return createShortcutIcon(shortcutInfo, true /* badged */); } @@ -121,12 +122,20 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { return createShortcutIcon(shortcutInfo, badged, null); } - public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, - boolean badged, @Nullable Supplier fallbackIconProvider) { + public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged, + @Nullable Supplier fallbackIconProvider) { + if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) { + return createShortcutIconCached(shortcutInfo, badged, true, fallbackIconProvider); + } else { + return createShortcutIconLegacy(shortcutInfo, badged, fallbackIconProvider); + } + } + + public BitmapInfo createShortcutIconLegacy(ShortcutInfo shortcutInfo, boolean badged, + @Nullable Supplier fallbackIconProvider) { Drawable unbadgedDrawable = DeepShortcutManager.getInstance(mContext) .getShortcutIconDrawable(shortcutInfo, mFillResIconDpi); IconCache cache = LauncherAppState.getInstance(mContext).getIconCache(); - final Bitmap unbadgedBitmap; if (unbadgedDrawable != null) { unbadgedBitmap = createScaledBitmapWithoutShadow(unbadgedDrawable, 0); @@ -155,6 +164,44 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { return BitmapInfo.of(icon, badge.bitmap.color); } + @WorkerThread + public BitmapInfo createShortcutIconCached(ShortcutInfo shortcutInfo, boolean badged, + boolean useCache, @Nullable Supplier fallbackIconProvider) { + IconCache cache = LauncherAppState.getInstance(mContext).getIconCache(); + final BitmapInfo bitmapInfo; + if (useCache) { + bitmapInfo = cache.getDeepShortcutTitleAndIcon(shortcutInfo).bitmap; + } else { + bitmapInfo = new ShortcutCachingLogic().loadIcon(mContext, shortcutInfo); + } + final Bitmap unbadgedBitmap; + if (bitmapInfo.icon != null) { + unbadgedBitmap = bitmapInfo.icon; + } else { + if (fallbackIconProvider != null) { + // Fallback icons are already badged and with appropriate shadow + ItemInfoWithIcon fullIcon = fallbackIconProvider.get(); + if (fullIcon != null && fullIcon.bitmap != null) { + return fullIcon.bitmap; + } + } + unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle()).icon; + } + + if (!badged) { + return BitmapInfo.of(unbadgedBitmap, Themes.getColorAccent(mContext)); + } + + final Bitmap unbadgedfinal = unbadgedBitmap; + final ItemInfoWithIcon badge = getShortcutInfoBadge(shortcutInfo, cache); + + Bitmap icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> { + getShadowGenerator().recreateIcon(unbadgedfinal, c); + badgeWithDrawable(c, new FastBitmapDrawable(badge.bitmap)); + }); + return BitmapInfo.of(icon, badge.bitmap.color); + } + public ItemInfoWithIcon getShortcutInfoBadge(ShortcutInfo shortcutInfo, IconCache cache) { ComponentName cn = shortcutInfo.getActivity(); String badgePkg = shortcutInfo.getPackage(); diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java new file mode 100644 index 0000000000..5c214704a3 --- /dev/null +++ b/src/com/android/launcher3/icons/ShortcutCachingLogic.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3.icons; + +import android.content.ComponentName; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.ShortcutInfo; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; + +import androidx.annotation.NonNull; + +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.icons.cache.CachingLogic; +import com.android.launcher3.shortcuts.DeepShortcutManager; +import com.android.launcher3.shortcuts.ShortcutKey; +import com.android.launcher3.util.Themes; + +/** + * Caching logic for shortcuts. + */ +public class ShortcutCachingLogic implements CachingLogic { + + @Override + public ComponentName getComponent(ShortcutInfo info) { + return ShortcutKey.fromInfo(info).componentName; + } + + @Override + public UserHandle getUser(ShortcutInfo info) { + return info.getUserHandle(); + } + + @Override + public CharSequence getLabel(ShortcutInfo info) { + return info.getShortLabel(); + } + + @NonNull + @Override + public BitmapInfo loadIcon(Context context, ShortcutInfo info) { + try (LauncherIcons li = LauncherIcons.obtain(context)) { + Drawable unbadgedDrawable = DeepShortcutManager.getInstance(context) + .getShortcutIconDrawable(info, LauncherAppState.getIDP(context).fillResIconDpi); + if (unbadgedDrawable == null) return BitmapInfo.LOW_RES_INFO; + return new BitmapInfo(li.createScaledBitmapWithoutShadow( + unbadgedDrawable, 0), Themes.getColorAccent(context)); + } + } + + @Override + public long getLastUpdatedTime(ShortcutInfo shortcutInfo, PackageInfo info) { + if (shortcutInfo == null || !FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) { + return info.lastUpdateTime; + } + return Math.max(shortcutInfo.getLastChangedTimestamp(), info.lastUpdateTime); + } + + @Override + public boolean addToMemCache() { + return false; + } +} diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 6383a5f480..3a4085c89c 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -63,6 +63,7 @@ import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; import com.android.launcher3.icons.IconCache; import com.android.launcher3.icons.LauncherActivityCachingLogic; import com.android.launcher3.icons.LauncherIcons; +import com.android.launcher3.icons.ShortcutCachingLogic; import com.android.launcher3.icons.cache.IconCacheUpdateHandler; import com.android.launcher3.logging.FileLog; import com.android.launcher3.pm.PackageInstallInfo; @@ -71,7 +72,6 @@ import com.android.launcher3.provider.ImportDataTask; import com.android.launcher3.qsb.QsbContainerView; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.shortcuts.ShortcutKey; -import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.IOUtils; import com.android.launcher3.util.LooperIdleLock; @@ -174,7 +174,8 @@ public class LoaderTask implements Runnable { Object traceToken = TraceHelper.INSTANCE.beginSection(TAG); TimingLogger logger = new TimingLogger(TAG, "run"); try (LauncherModel.LoaderTransaction transaction = mApp.getModel().beginLoader(this)) { - loadWorkspace(); + List allShortcuts = new ArrayList<>(); + loadWorkspace(allShortcuts); logger.addSplit("loadWorkspace"); verifyNotStopped(); @@ -206,19 +207,33 @@ public class LoaderTask implements Runnable { mApp.getModel()::onPackageIconsUpdated); logger.addSplit("update icon cache"); + if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) { + verifyNotStopped(); + logger.addSplit("save shortcuts in icon cache"); + updateHandler.updateIcons(allShortcuts, new ShortcutCachingLogic(), + mApp.getModel()::onPackageIconsUpdated); + } + // Take a break waitForIdle(); logger.addSplit("step 2 complete"); verifyNotStopped(); // third step - loadDeepShortcuts(); + List allDeepShortcuts = loadDeepShortcuts(); logger.addSplit("loadDeepShortcuts"); verifyNotStopped(); mResults.bindDeepShortcuts(); logger.addSplit("bindDeepShortcuts"); + if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) { + verifyNotStopped(); + logger.addSplit("save deep shortcuts in icon cache"); + updateHandler.updateIcons(allDeepShortcuts, + new ShortcutCachingLogic(), (pkgs, user) -> { }); + } + // Take a break waitForIdle(); logger.addSplit("step 3 complete"); @@ -256,7 +271,7 @@ public class LoaderTask implements Runnable { this.notify(); } - private void loadWorkspace() { + private void loadWorkspace(List allDeepShortcuts) { final Context context = mApp.getContext(); final ContentResolver contentResolver = context.getContentResolver(); final PackageManagerHelper pmHelper = new PackageManagerHelper(context); @@ -512,6 +527,7 @@ public class LoaderTask implements Runnable { info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED; } intent = info.intent; + allDeepShortcuts.add(pinnedShortcut); } else { // Create a shortcut info in disabled mode for now. info = c.loadSimpleWorkspaceItem(); @@ -860,7 +876,8 @@ public class LoaderTask implements Runnable { return allActivityList; } - private void loadDeepShortcuts() { + private List loadDeepShortcuts() { + List allShortcuts = new ArrayList<>(); mBgDataModel.deepShortcutMap.clear(); mBgDataModel.hasShortcutHostPermission = mShortcutManager.hasHostPermission(); if (mBgDataModel.hasShortcutHostPermission) { @@ -868,10 +885,12 @@ public class LoaderTask implements Runnable { if (mUserManager.isUserUnlocked(user)) { List shortcuts = mShortcutManager.queryForAllShortcuts(user); + allShortcuts.addAll(shortcuts); mBgDataModel.updateDeepShortcutCounts(null, user, shortcuts); } } } + return allShortcuts; } public static boolean isValidProvider(AppWidgetProviderInfo provider) { diff --git a/src/com/android/launcher3/pm/PinRequestHelper.java b/src/com/android/launcher3/pm/PinRequestHelper.java index e13645c42b..a15399d042 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; @@ -31,6 +32,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.LauncherAppState; import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.LauncherIcons; public class PinRequestHelper { @@ -81,11 +83,15 @@ 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.bitmap = li.createShortcutIcon(si, false /* badged */); - li.recycle(); - LauncherAppState.getInstance(context).getModel() - .updateAndBindWorkspaceItem(info, si); + if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) { + fetchAndUpdateShortcutIconAsync(context, info, si, false); + } else { + LauncherIcons li = LauncherIcons.obtain(context); + info.bitmap = li.createShortcutIcon(si, false /* badged */); + li.recycle(); + LauncherAppState.getInstance(context).getModel() + .updateAndBindWorkspaceItem(info, si); + } 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..3e59b612cf 100644 --- a/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java +++ b/src/com/android/launcher3/shortcuts/ShortcutDragPreviewProvider.java @@ -25,7 +25,9 @@ import android.view.View; import com.android.launcher3.Launcher; import com.android.launcher3.Utilities; +import com.android.launcher3.config.FeatureFlags; 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,16 +41,27 @@ public class ShortcutDragPreviewProvider extends DragPreviewProvider { mPositionShift = shift; } + @Override public Bitmap createDragBitmap() { + if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) { + int size = Launcher.getLauncher(mView.getContext()).getDeviceProfile().iconSizePx; + return BitmapRenderer.createHardwareBitmap( + size + blurSizeOutline, + size + blurSizeOutline, + (c) -> drawDragViewOnBackground(c, size)); + } else { + return createDragBitmapLegacy(); + } + } + + private Bitmap createDragBitmapLegacy() { 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); @@ -57,6 +70,16 @@ public class ShortcutDragPreviewProvider extends DragPreviewProvider { return b; } + private void drawDragViewOnBackground(Canvas canvas, float size) { + Drawable d = mView.getBackground(); + Rect bounds = getDrawableBounds(d); + + canvas.translate(blurSizeOutline / 2, blurSizeOutline / 2); + canvas.scale(size / bounds.width(), size / bounds.height(), 0, 0); + canvas.translate(bounds.left, bounds.top); + d.draw(canvas); + } + @Override public float getScaleAndPosition(Bitmap preview, int[] outPos) { Launcher launcher = Launcher.getLauncher(mView.getContext()); diff --git a/src/com/android/launcher3/util/ShortcutUtil.java b/src/com/android/launcher3/util/ShortcutUtil.java index 49c97daf35..a03b743233 100644 --- a/src/com/android/launcher3/util/ShortcutUtil.java +++ b/src/com/android/launcher3/util/ShortcutUtil.java @@ -15,10 +15,19 @@ */ 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.LauncherIcons; import com.android.launcher3.model.WidgetsModel; import com.android.launcher3.shortcuts.ShortcutKey; @@ -61,6 +70,21 @@ 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) { + MODEL_EXECUTOR.execute(() -> { + try (LauncherIcons li = LauncherIcons.obtain(context)) { + info.bitmap = li.createShortcutIcon(si, badged, null); + LauncherAppState.getInstance(context).getModel() + .updateAndBindWorkspaceItem(info, si); + } + }); + } + private static boolean isActive(ItemInfo info) { boolean isLoading = info instanceof WorkspaceItemInfo && ((WorkspaceItemInfo) info).hasPromiseIconUi();