mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-27 15:26:58 +00:00
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
This commit is contained in:
@@ -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<T> {
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<ComponentWithLabel> mComponentWithLabelCachingLogic;
|
||||
private final CachingLogic<LauncherActivityInfo> mLauncherActivityInfoCachingLogic;
|
||||
private final CachingLogic<ShortcutInfo> 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.
|
||||
|
||||
@@ -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<ItemInfoWithIcon> fallbackIconProvider) {
|
||||
public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged,
|
||||
@Nullable Supplier<ItemInfoWithIcon> 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<ItemInfoWithIcon> 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<ItemInfoWithIcon> 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();
|
||||
|
||||
79
src/com/android/launcher3/icons/ShortcutCachingLogic.java
Normal file
79
src/com/android/launcher3/icons/ShortcutCachingLogic.java
Normal file
@@ -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<ShortcutInfo> {
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
@@ -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<ShortcutInfo> 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<ShortcutInfo> 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<ShortcutInfo> 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<ShortcutInfo> loadDeepShortcuts() {
|
||||
List<ShortcutInfo> 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<ShortcutInfo> shortcuts =
|
||||
mShortcutManager.queryForAllShortcuts(user);
|
||||
allShortcuts.addAll(shortcuts);
|
||||
mBgDataModel.updateDeepShortcutCounts(null, user, shortcuts);
|
||||
}
|
||||
}
|
||||
}
|
||||
return allShortcuts;
|
||||
}
|
||||
|
||||
public static boolean isValidProvider(AppWidgetProviderInfo provider) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user