diff --git a/go/src/com/android/launcher3/model/WidgetsModel.java b/go/src/com/android/launcher3/model/WidgetsModel.java index 7269b417e4..7690b9d57c 100644 --- a/go/src/com/android/launcher3/model/WidgetsModel.java +++ b/go/src/com/android/launcher3/model/WidgetsModel.java @@ -22,7 +22,7 @@ import android.os.UserHandle; import androidx.annotation.Nullable; import com.android.launcher3.LauncherAppState; -import com.android.launcher3.icons.ComponentWithLabel; +import com.android.launcher3.icons.ComponentWithLabelAndIcon; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.widget.WidgetListRowEntry; @@ -59,7 +59,7 @@ public class WidgetsModel { * @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise * only widgets and shortcuts associated with the package/user are. */ - public List update(LauncherAppState app, + public List update(LauncherAppState app, @Nullable PackageUserKey packageUser) { return Collections.emptyList(); } diff --git a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java index bce4e0f330..31a923e314 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java +++ b/iconloaderlib/src/com/android/launcher3/icons/BaseIconFactory.java @@ -350,6 +350,17 @@ public class BaseIconFactory implements AutoCloseable { iconDpi); } + /** + * Badges the provided source with the badge info + */ + public BitmapInfo badgeBitmap(Bitmap source, BitmapInfo badgeInfo) { + Bitmap icon = BitmapRenderer.createHardwareBitmap(mIconBitmapSize, mIconBitmapSize, (c) -> { + getShadowGenerator().recreateIcon(source, c); + badgeWithDrawable(c, new FixedSizeBitmapDrawable(badgeInfo.icon)); + }); + return BitmapInfo.of(icon, badgeInfo.color); + } + private int extractColor(Bitmap bitmap) { return mDisableColorExtractor ? 0 : mColorExtractor.findDominantColorByHue(bitmap); } diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java index e807791d94..4c634cbc26 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java @@ -281,7 +281,8 @@ public abstract class BaseIconCache { ContentValues values = newContentValues(entry.bitmap, entry.title.toString(), componentName.getPackageName(), cachingLogic.getKeywords(object, mLocaleList)); - addIconToDB(values, componentName, info, userSerial); + addIconToDB(values, componentName, info, userSerial, + cachingLogic.getLastUpdatedTime(object, info)); } /** @@ -289,10 +290,10 @@ public abstract class BaseIconCache { * @param values {@link ContentValues} containing icon & title */ private void addIconToDB(ContentValues values, ComponentName key, - PackageInfo info, long userSerial) { + PackageInfo info, long userSerial, long lastUpdateTime) { values.put(IconDB.COLUMN_COMPONENT, key.flattenToString()); values.put(IconDB.COLUMN_USER, userSerial); - values.put(IconDB.COLUMN_LAST_UPDATED, info.lastUpdateTime); + values.put(IconDB.COLUMN_LAST_UPDATED, lastUpdateTime); values.put(IconDB.COLUMN_VERSION, info.versionCode); mIconDb.insertOrReplace(values); } @@ -362,7 +363,8 @@ public abstract class BaseIconCache { } if (object != null) { entry.title = cachingLogic.getLabel(object); - entry.contentDescription = mPackageManager.getUserBadgedLabel(entry.title, user); + entry.contentDescription = mPackageManager.getUserBadgedLabel( + cachingLogic.getDescription(object, entry.title), user); } } } @@ -449,7 +451,8 @@ public abstract class BaseIconCache { // package updates. ContentValues values = newContentValues( iconInfo, entry.title.toString(), packageName, null); - addIconToDB(values, cacheKey.componentName, info, getSerialNumberForUser(user)); + addIconToDB(values, cacheKey.componentName, info, getSerialNumberForUser(user), + info.lastUpdateTime); } catch (NameNotFoundException e) { if (DEBUG) Log.d(TAG, "Application not installed " + packageName); diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java index a89ede7b34..c12e9dcc15 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java @@ -34,6 +34,10 @@ public interface CachingLogic { CharSequence getLabel(T object); + default CharSequence getDescription(T object, CharSequence fallback) { + return fallback; + } + @NonNull BitmapInfo loadIcon(Context context, T object); diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java index bcdbce5e29..aec1cddce4 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/IconCacheUpdateHandler.java @@ -24,6 +24,7 @@ import android.database.sqlite.SQLiteException; import android.os.SystemClock; import android.os.UserHandle; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Log; import android.util.SparseBooleanArray; @@ -61,7 +62,7 @@ public class IconCacheUpdateHandler { private final HashMap mPkgInfoMap; private final BaseIconCache mIconCache; - private final HashMap> mPackagesToIgnore = new HashMap<>(); + private final ArrayMap> mPackagesToIgnore = new ArrayMap<>(); private final SparseBooleanArray mItemsToDelete = new SparseBooleanArray(); private boolean mFilterMode = MODE_SET_INVALID_ITEMS; @@ -77,8 +78,16 @@ public class IconCacheUpdateHandler { createPackageInfoMap(); } - public void setPackagesToIgnore(UserHandle userHandle, Set packages) { - mPackagesToIgnore.put(userHandle, packages); + /** + * Sets a package to ignore for processing + */ + public void addPackagesToIgnore(UserHandle userHandle, String packageName) { + Set packages = mPackagesToIgnore.get(userHandle); + if (packages == null) { + packages = new HashSet<>(); + mPackagesToIgnore.put(userHandle, packages); + } + packages.add(packageName); } private void createPackageInfoMap() { @@ -181,6 +190,7 @@ public class IconCacheUpdateHandler { } continue; } + if (app == null) { if (mFilterMode == MODE_SET_INVALID_ITEMS) { mIconCache.remove(component, user); @@ -263,6 +273,7 @@ public class IconCacheUpdateHandler { T app = mAppsToUpdate.pop(); String pkg = mCachingLogic.getComponent(app).getPackageName(); PackageInfo info = mPkgInfoMap.get(pkg); + mIconCache.addIconToDBAndMemCache( app, mCachingLogic, info, mUserSerial, true /*replace existing*/); mUpdatedPackages.add(pkg); diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java index 76972aff41..54f58e2081 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java @@ -43,7 +43,6 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.icons.IconCache; -import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.util.InstantAppResolver; @@ -170,14 +169,7 @@ public class DynamicItemCache { List details = shortcutKey.buildRequest(mContext).query(ShortcutRequest.ALL); if (!details.isEmpty()) { WorkspaceItemInfo si = new WorkspaceItemInfo(details.get(0), mContext); - try (LauncherIcons li = LauncherIcons.obtain(mContext)) { - si.bitmap = li.createShortcutIcon(details.get(0), true /* badged */, null); - } catch (Exception e) { - if (DEBUG) { - Log.e(TAG, "Error loading shortcut icon for " + shortcutKey.toString()); - } - return null; - } + mIconCache.getShortcutIcon(si, details.get(0)); return si; } if (DEBUG) { diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java index 3eb02b3dae..a5142d815c 100644 --- a/src/com/android/launcher3/InstallShortcutReceiver.java +++ b/src/com/android/launcher3/InstallShortcutReceiver.java @@ -17,7 +17,6 @@ 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,7 +43,6 @@ import android.util.Pair; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.GraphicsUtils; import com.android.launcher3.icons.LauncherIcons; @@ -61,7 +59,6 @@ import org.json.JSONStringer; import java.net.URISyntaxException; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; @@ -491,13 +488,8 @@ public class InstallShortcutReceiver extends BroadcastReceiver { return Pair.create(si, null); } else if (shortcutInfo != null) { WorkspaceItemInfo itemInfo = new WorkspaceItemInfo(shortcutInfo, mContext); - 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(); - } + LauncherAppState.getInstance(mContext).getIconCache().getShortcutIcon( + itemInfo, shortcutInfo); return Pair.create(itemInfo, shortcutInfo); } else if (providerInfo != null) { LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo diff --git a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java index 228c07ec43..56cce78659 100644 --- a/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java +++ b/src/com/android/launcher3/LauncherAppWidgetProviderInfo.java @@ -7,10 +7,12 @@ import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Point; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.UserHandle; -import com.android.launcher3.icons.ComponentWithLabel; +import com.android.launcher3.icons.ComponentWithLabelAndIcon; +import com.android.launcher3.icons.IconCache; /** * This class is a thin wrapper around the framework AppWidgetProviderInfo class. This class affords @@ -19,7 +21,7 @@ import com.android.launcher3.icons.ComponentWithLabel; * as opposed to a widget instance, and so should not be confused with {@link LauncherAppWidgetInfo} */ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo - implements ComponentWithLabel { + implements ComponentWithLabelAndIcon { public static final String CLS_CUSTOM_WIDGET_PREFIX = "#custom-widget-"; @@ -111,4 +113,9 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo public final UserHandle getUser() { return getProfile(); } + + @Override + public Drawable getFullResIcon(IconCache cache) { + return cache.getFullResIcon(provider.getPackageName(), icon); + } } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 04a7ecd826..efe85c7f7c 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -37,7 +37,6 @@ import androidx.annotation.WorkerThread; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.IconCache; -import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.AddWorkspaceItemsTask; import com.android.launcher3.model.AllAppsList; @@ -573,9 +572,7 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi public void updateAndBindWorkspaceItem(WorkspaceItemInfo si, ShortcutInfo info) { updateAndBindWorkspaceItem(() -> { si.updateFromDeepShortcutInfo(info, mApp.getContext()); - LauncherIcons li = LauncherIcons.obtain(mApp.getContext()); - si.bitmap = li.createShortcutIcon(info); - li.recycle(); + mApp.getIconCache().getShortcutIcon(si, info); return si; }); } diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index 7f443b60b8..e0e4cc0ce4 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -584,9 +584,8 @@ public final class Utilities { return new FixedSizeEmptyDrawable(iconSize); } ShortcutInfo si = (ShortcutInfo) obj; - LauncherIcons li = LauncherIcons.obtain(appState.getContext()); - Bitmap badge = li.getShortcutInfoBadge(si, appState.getIconCache()).bitmap.icon; - li.recycle(); + Bitmap badge = LauncherAppState.getInstance(appState.getContext()) + .getIconCache().getShortcutInfoBadge(si).icon; float badgeSize = LauncherIcons.getBadgeSizeForIconSize(iconSize); float insetFraction = (iconSize - badgeSize) / iconSize; return new InsetDrawable(new FastBitmapDrawable(badge), diff --git a/src/com/android/launcher3/icons/ComponentWithLabel.java b/src/com/android/launcher3/icons/ComponentWithLabel.java index f7ee5f9329..372c59166e 100644 --- a/src/com/android/launcher3/icons/ComponentWithLabel.java +++ b/src/com/android/launcher3/icons/ComponentWithLabel.java @@ -31,7 +31,7 @@ public interface ComponentWithLabel { CharSequence getLabel(PackageManager pm); - class ComponentCachingLogic implements CachingLogic { + class ComponentCachingLogic implements CachingLogic { private final PackageManager mPackageManager; private final boolean mAddToMemCache; @@ -42,22 +42,22 @@ public interface ComponentWithLabel { } @Override - public ComponentName getComponent(ComponentWithLabel object) { + public ComponentName getComponent(T object) { return object.getComponent(); } @Override - public UserHandle getUser(ComponentWithLabel object) { + public UserHandle getUser(T object) { return object.getUser(); } @Override - public CharSequence getLabel(ComponentWithLabel object) { + public CharSequence getLabel(T object) { return object.getLabel(mPackageManager); } @Override - public BitmapInfo loadIcon(Context context, ComponentWithLabel object) { + public BitmapInfo loadIcon(Context context, T object) { return BitmapInfo.LOW_RES_INFO; } diff --git a/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java b/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java new file mode 100644 index 0000000000..248a57d2fd --- /dev/null +++ b/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2020 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.Context; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; + +import com.android.launcher3.LauncherAppState; + +/** + * Extension of ComponentWithLabel to also support loading icons + */ +public interface ComponentWithLabelAndIcon extends ComponentWithLabel { + + /** + * Provide an icon for this object + */ + Drawable getFullResIcon(IconCache cache); + + class ComponentWithIconCachingLogic extends ComponentCachingLogic { + + public ComponentWithIconCachingLogic(Context context, boolean addToMemCache) { + super(context, addToMemCache); + } + + @NonNull + @Override + public BitmapInfo loadIcon(Context context, ComponentWithLabelAndIcon object) { + Drawable d = object.getFullResIcon(LauncherAppState.getInstance(context) + .getIconCache()); + if (d == null) { + return super.loadIcon(context, object); + } + try (LauncherIcons li = LauncherIcons.obtain(context)) { + return li.createBadgedIconBitmap(d, object.getUser(), 0); + } + } + } +} diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 69b812541e..804acc3d8c 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -19,6 +19,7 @@ package com.android.launcher3.icons; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -56,6 +57,7 @@ import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.Preconditions; +import java.util.function.Predicate; import java.util.function.Supplier; /** @@ -65,6 +67,9 @@ public class IconCache extends BaseIconCache { private static final String TAG = "Launcher.IconCache"; + private final Predicate mIsUsingFallbackIconCheck = w -> w.bitmap != null + && w.bitmap.isNullOrLowRes() && !isDefaultIcon(w.bitmap, w.user); + private final CachingLogic mComponentWithLabelCachingLogic; private final CachingLogic mLauncherActivityInfoCachingLogic; private final CachingLogic mShortcutCachingLogic; @@ -179,6 +184,77 @@ public class IconCache extends BaseIconCache { getTitleAndIcon(info, () -> activityInfo, false, useLowResIcon); } + /** + * Fill in {@param info} with the icon for {@param si} + */ + public void getShortcutIcon(ItemInfoWithIcon info, ShortcutInfo si) { + getShortcutIcon(info, si, true, mIsUsingFallbackIconCheck); + } + + /** + * Fill in {@param info} with an unbadged icon for {@param si} + */ + public void getUnbadgedShortcutIcon(ItemInfoWithIcon info, ShortcutInfo si) { + getShortcutIcon(info, si, false, mIsUsingFallbackIconCheck); + } + + /** + * Fill in {@param info} with the icon and label for {@param si}. If the icon is not + * available, and fallback check returns true, it keeps the old icon. + */ + public void getShortcutIcon(T info, ShortcutInfo si, + @NonNull Predicate fallbackIconCheck) { + getShortcutIcon(info, si, true /* use badged */, fallbackIconCheck); + } + + private synchronized void getShortcutIcon(T info, ShortcutInfo si, + boolean useBadged, @NonNull Predicate fallbackIconCheck) { + BitmapInfo bitmapInfo; + if (FeatureFlags.ENABLE_DEEP_SHORTCUT_ICON_CACHE.get()) { + bitmapInfo = cacheLocked(ShortcutKey.fromInfo(si).componentName, si.getUserHandle(), + () -> si, mShortcutCachingLogic, false, false).bitmap; + } else { + // If caching is disabled, load the full icon + bitmapInfo = mShortcutCachingLogic.loadIcon(mContext, si); + } + if (bitmapInfo.isNullOrLowRes()) { + bitmapInfo = getDefaultIcon(si.getUserHandle()); + } + + if (isDefaultIcon(bitmapInfo, si.getUserHandle()) && fallbackIconCheck.test(info)) { + return; + } + info.bitmap = bitmapInfo; + if (useBadged) { + BitmapInfo badgeInfo = getShortcutInfoBadge(si); + try (LauncherIcons li = LauncherIcons.obtain(mContext)) { + info.bitmap = li.badgeBitmap(info.bitmap.icon, badgeInfo); + } + } + } + + /** + * Returns the badging info for the shortcut + */ + public BitmapInfo getShortcutInfoBadge(ShortcutInfo shortcutInfo) { + ComponentName cn = shortcutInfo.getActivity(); + if (cn != null) { + // Get the app info for the source activity. + AppInfo appInfo = new AppInfo(); + appInfo.user = shortcutInfo.getUserHandle(); + appInfo.componentName = cn; + appInfo.intent = new Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_LAUNCHER) + .setComponent(cn); + getTitleAndIcon(appInfo, false); + return appInfo.bitmap; + } else { + PackageItemInfo pkgInfo = new PackageItemInfo(shortcutInfo.getPackage()); + getTitleAndIconForApp(pkgInfo, false); + return pkgInfo.bitmap; + } + } + /** * Fill in info with the icon and label for deep shortcut. */ diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java index e67d2445b7..cbd7c530c5 100644 --- a/src/com/android/launcher3/icons/LauncherIcons.java +++ b/src/com/android/launcher3/icons/LauncherIcons.java @@ -16,28 +16,11 @@ package com.android.launcher3.icons; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.pm.ShortcutInfo; -import android.graphics.Bitmap; -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.util.Themes; - -import java.util.function.Supplier; /** * Wrapper class to provide access to {@link BaseIconFactory} and also to provide pool of this class @@ -111,114 +94,4 @@ public class LauncherIcons extends BaseIconFactory implements AutoCloseable { public void close() { recycle(); } - - // below methods should also migrate to BaseIconFactory - public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo) { - return createShortcutIcon(shortcutInfo, true /* badged */); - } - - public BitmapInfo createShortcutIcon(ShortcutInfo shortcutInfo, boolean badged) { - return createShortcutIcon(shortcutInfo, badged, null); - } - - 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 = ShortcutCachingLogic.getIcon( - mContext, shortcutInfo, mFillResIconDpi); - IconCache cache = LauncherAppState.getInstance(mContext).getIconCache(); - final Bitmap unbadgedBitmap; - if (unbadgedDrawable != null) { - unbadgedBitmap = createScaledBitmapWithoutShadow(unbadgedDrawable, 0); - } 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); - } - - @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(); - boolean hasBadgePkgSet = !badgePkg.equals(shortcutInfo.getPackage()); - if (cn != null && !hasBadgePkgSet) { - // Get the app info for the source activity. - AppInfo appInfo = new AppInfo(); - appInfo.user = shortcutInfo.getUserHandle(); - appInfo.componentName = cn; - appInfo.intent = new Intent(Intent.ACTION_MAIN) - .addCategory(Intent.CATEGORY_LAUNCHER) - .setComponent(cn); - cache.getTitleAndIcon(appInfo, false); - return appInfo; - } else { - PackageItemInfo pkgInfo = new PackageItemInfo(badgePkg); - cache.getTitleAndIconForApp(pkgInfo, false); - return pkgInfo; - } - } } diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java index b856dd1318..d7eed06901 100644 --- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java +++ b/src/com/android/launcher3/icons/ShortcutCachingLogic.java @@ -25,6 +25,7 @@ import android.content.pm.PackageInfo; import android.content.pm.ShortcutInfo; import android.graphics.drawable.Drawable; import android.os.UserHandle; +import android.text.TextUtils; import android.util.Log; import androidx.annotation.NonNull; @@ -57,6 +58,12 @@ public class ShortcutCachingLogic implements CachingLogic { return info.getShortLabel(); } + @Override + public CharSequence getDescription(ShortcutInfo object, CharSequence fallback) { + CharSequence label = object.getLongLabel(); + return TextUtils.isEmpty(label) ? fallback : label; + } + @NonNull @Override public BitmapInfo loadIcon(Context context, ShortcutInfo info) { diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 95268d088e..49614327ff 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -16,6 +16,8 @@ package com.android.launcher3.model; +import static android.graphics.BitmapFactory.decodeByteArray; + import android.content.ComponentName; import android.content.ContentValues; import android.content.Context; @@ -26,7 +28,6 @@ import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.database.Cursor; import android.database.CursorWrapper; -import android.graphics.BitmapFactory; import android.os.UserHandle; import android.provider.BaseColumns; import android.text.TextUtils; @@ -166,37 +167,30 @@ public class LoaderCursor extends CursorWrapper { */ protected boolean loadIcon(WorkspaceItemInfo info) { try (LauncherIcons li = LauncherIcons.obtain(mContext)) { - return loadIcon(info, li); - } - } - - /** - * Loads the icon from the cursor and updates the {@param info} if the icon is an app resource. - */ - protected boolean loadIcon(WorkspaceItemInfo info, LauncherIcons li) { - if (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { - String packageName = getString(iconPackageIndex); - String resourceName = getString(iconResourceIndex); - if (!TextUtils.isEmpty(packageName) || !TextUtils.isEmpty(resourceName)) { - info.iconResource = new ShortcutIconResource(); - info.iconResource.packageName = packageName; - info.iconResource.resourceName = resourceName; - BitmapInfo iconInfo = li.createIconBitmap(info.iconResource); - if (iconInfo != null) { - info.bitmap = iconInfo; - return true; + if (itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT) { + String packageName = getString(iconPackageIndex); + String resourceName = getString(iconResourceIndex); + if (!TextUtils.isEmpty(packageName) || !TextUtils.isEmpty(resourceName)) { + info.iconResource = new ShortcutIconResource(); + info.iconResource.packageName = packageName; + info.iconResource.resourceName = resourceName; + BitmapInfo iconInfo = li.createIconBitmap(info.iconResource); + if (iconInfo != null) { + info.bitmap = iconInfo; + return true; + } } } - } - // Failed to load from resource, try loading from DB. - byte[] data = getBlob(iconIndex); - try { - info.bitmap = li.createIconBitmap(BitmapFactory.decodeByteArray(data, 0, data.length)); - return true; - } catch (Exception e) { - Log.e(TAG, "Failed to decode byte array for info " + info, e); - return false; + // Failed to load from resource, try loading from DB. + byte[] data = getBlob(iconIndex); + try { + info.bitmap = li.createIconBitmap(decodeByteArray(data, 0, data.length)); + return true; + } catch (Exception e) { + Log.e(TAG, "Failed to decode byte array for info " + info, e); + return false; + } } } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 23ec459602..8728b9387b 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -35,7 +35,6 @@ import android.content.pm.LauncherApps; import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.ShortcutInfo; -import android.os.Process; import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; @@ -50,7 +49,6 @@ import com.android.launcher3.AppInfo; import com.android.launcher3.FolderInfo; import com.android.launcher3.InstallShortcutReceiver; import com.android.launcher3.ItemInfo; -import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherModel; @@ -61,11 +59,10 @@ import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.folder.Folder; import com.android.launcher3.folder.FolderGridOrganizer; import com.android.launcher3.folder.FolderNameProvider; -import com.android.launcher3.icons.ComponentWithLabel; -import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; +import com.android.launcher3.icons.ComponentWithLabelAndIcon; +import com.android.launcher3.icons.ComponentWithLabelAndIcon.ComponentWithIconCachingLogic; 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; @@ -94,7 +91,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.CancellationException; -import java.util.function.Supplier; /** * Runnable for the thread that loads the contents of the launcher: @@ -263,7 +259,8 @@ public class LoaderTask implements Runnable { verifyNotStopped(); // fourth step - List allWidgetsList = mBgDataModel.widgetsModel.update(mApp, null); + List allWidgetsList = + mBgDataModel.widgetsModel.update(mApp, null); logger.addSplit("load widgets"); verifyNotStopped(); @@ -271,8 +268,9 @@ public class LoaderTask implements Runnable { logger.addSplit("bindWidgets"); verifyNotStopped(); - updateHandler.updateIcons(allWidgetsList, new ComponentCachingLogic( - mApp.getContext(), true), mApp.getModel()::onWidgetLabelsUpdated); + updateHandler.updateIcons(allWidgetsList, + new ComponentWithIconCachingLogic(mApp.getContext(), true), + mApp.getModel()::onWidgetLabelsUpdated); logger.addSplit("save widgets in icon cache"); // fifth step @@ -544,17 +542,10 @@ public class LoaderTask implements Runnable { continue; } info = new WorkspaceItemInfo(pinnedShortcut, context); - final WorkspaceItemInfo finalInfo = info; - - LauncherIcons li = LauncherIcons.obtain(context); // If the pinned deep shortcut is no longer published, // use the last saved icon instead of the default. - Supplier fallbackIconProvider = () -> - c.loadIcon(finalInfo, li) ? finalInfo : null; - info.bitmap = li.createShortcutIcon( - pinnedShortcut, true /* badged */, - fallbackIconProvider); - li.recycle(); + mIconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon); + if (pmHelper.isAppSuspended( pinnedShortcut.getPackage(), info.user)) { info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED; @@ -854,23 +845,23 @@ public class LoaderTask implements Runnable { private void setIgnorePackages(IconCacheUpdateHandler updateHandler) { // Ignore packages which have a promise icon. - HashSet packagesToIgnore = new HashSet<>(); synchronized (mBgDataModel) { for (ItemInfo info : mBgDataModel.itemsIdMap) { if (info instanceof WorkspaceItemInfo) { WorkspaceItemInfo si = (WorkspaceItemInfo) info; if (si.isPromise() && si.getTargetComponent() != null) { - packagesToIgnore.add(si.getTargetComponent().getPackageName()); + updateHandler.addPackagesToIgnore( + si.user, si.getTargetComponent().getPackageName()); } } else if (info instanceof LauncherAppWidgetInfo) { LauncherAppWidgetInfo lawi = (LauncherAppWidgetInfo) info; if (lawi.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_PROVIDER_NOT_READY)) { - packagesToIgnore.add(lawi.providerName.getPackageName()); + updateHandler.addPackagesToIgnore( + lawi.user, lawi.providerName.getPackageName()); } } } } - updateHandler.setPackagesToIgnore(Process.myUserHandle(), packagesToIgnore); } private List loadAllApps() { diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java index b0e7a69f81..3f79ad020d 100644 --- a/src/com/android/launcher3/model/ShortcutsChangedTask.java +++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java @@ -23,7 +23,6 @@ import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.util.ItemInfoMatcher; @@ -89,12 +88,7 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask { } for (final WorkspaceItemInfo workspaceItemInfo : workspaceItemInfos) { workspaceItemInfo.updateFromDeepShortcutInfo(fullDetails, context); - // If the shortcut is pinned but no longer has an icon in the system, - // keep the current icon instead of reverting to the default icon. - LauncherIcons li = LauncherIcons.obtain(context); - workspaceItemInfo.bitmap = li.createShortcutIcon( - fullDetails, true, () -> workspaceItemInfo); - li.recycle(); + app.getIconCache().getShortcutIcon(workspaceItemInfo, fullDetails); updatedWorkspaceItemInfos.add(workspaceItemInfo); } } diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java index d527423e42..a3adc823dd 100644 --- a/src/com/android/launcher3/model/UserLockStateChangedTask.java +++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java @@ -26,7 +26,6 @@ import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.shortcuts.ShortcutRequest; import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult; @@ -89,11 +88,7 @@ public class UserLockStateChangedTask extends BaseModelUpdateTask { } si.runtimeStatusFlags &= ~FLAG_DISABLED_LOCKED_USER; si.updateFromDeepShortcutInfo(shortcut, context); - // If the shortcut is pinned but no longer has an icon in the system, - // keep the current icon instead of reverting to the default icon. - LauncherIcons li = LauncherIcons.obtain(context); - si.bitmap = li.createShortcutIcon(shortcut, true, () -> si); - li.recycle(); + app.getIconCache().getShortcutIcon(si, shortcut); } else { si.runtimeStatusFlags |= FLAG_DISABLED_LOCKED_USER; } diff --git a/src/com/android/launcher3/pm/PinRequestHelper.java b/src/com/android/launcher3/pm/PinRequestHelper.java index a15399d042..74a5a31b60 100644 --- a/src/com/android/launcher3/pm/PinRequestHelper.java +++ b/src/com/android/launcher3/pm/PinRequestHelper.java @@ -17,7 +17,6 @@ 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; @@ -32,8 +31,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; +import com.android.launcher3.icons.ShortcutCachingLogic; public class PinRequestHelper { @@ -82,16 +80,10 @@ public class PinRequestHelper { ShortcutInfo si = request.getShortcutInfo(); WorkspaceItemInfo info = new WorkspaceItemInfo(si, context); - // Apply the unbadged icon and fetch the actual icon asynchronously. - 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); - } + // Apply the unbadged icon synchronously using the caching logic directly and + // fetch the actual icon asynchronously. + info.bitmap = new ShortcutCachingLogic().loadIcon(context, si); + LauncherAppState.getInstance(context).getModel().updateAndBindWorkspaceItem(info, si); return info; } else { return null; diff --git a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java index b563171bd1..ac0e0652c8 100644 --- a/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java +++ b/src/com/android/launcher3/pm/ShortcutConfigActivityInfo.java @@ -41,7 +41,7 @@ import com.android.launcher3.LauncherSettings; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.icons.ComponentWithLabel; +import com.android.launcher3.icons.ComponentWithLabelAndIcon; import com.android.launcher3.icons.IconCache; import com.android.launcher3.util.PackageUserKey; @@ -51,7 +51,7 @@ import java.util.List; /** * Wrapper class for representing a shortcut configure activity. */ -public abstract class ShortcutConfigActivityInfo implements ComponentWithLabel { +public abstract class ShortcutConfigActivityInfo implements ComponentWithLabelAndIcon { private static final String TAG = "SCActivityInfo"; @@ -77,6 +77,7 @@ public abstract class ShortcutConfigActivityInfo implements ComponentWithLabel { return LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; } + @Override public abstract Drawable getFullResIcon(IconCache cache); /** diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java index 9faeb4059c..fdcf04ff71 100644 --- a/src/com/android/launcher3/popup/PopupPopulator.java +++ b/src/com/android/launcher3/popup/PopupPopulator.java @@ -26,8 +26,9 @@ import androidx.annotation.VisibleForTesting; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.icons.LauncherIcons; +import com.android.launcher3.icons.IconCache; import com.android.launcher3.notification.NotificationInfo; import com.android.launcher3.notification.NotificationKeyData; import com.android.launcher3.notification.NotificationListener; @@ -153,13 +154,11 @@ public class PopupPopulator { String shortcutIdToDeDupe = notificationKeys.isEmpty() ? null : notificationKeys.get(0).shortcutId; shortcuts = PopupPopulator.sortAndFilterShortcuts(shortcuts, shortcutIdToDeDupe); + IconCache cache = LauncherAppState.getInstance(launcher).getIconCache(); for (int i = 0; i < shortcuts.size() && i < shortcutViews.size(); i++) { final ShortcutInfo shortcut = shortcuts.get(i); final WorkspaceItemInfo si = new WorkspaceItemInfo(shortcut, launcher); - // Use unbadged icon for the menu. - LauncherIcons li = LauncherIcons.obtain(launcher); - si.bitmap = li.createShortcutIcon(shortcut, false /* badged */); - li.recycle(); + cache.getUnbadgedShortcutIcon(si, shortcut); si.rank = i; final DeepShortcutView view = shortcutViews.get(i); diff --git a/src/com/android/launcher3/util/ShortcutUtil.java b/src/com/android/launcher3/util/ShortcutUtil.java index a03b743233..49c97daf35 100644 --- a/src/com/android/launcher3/util/ShortcutUtil.java +++ b/src/com/android/launcher3/util/ShortcutUtil.java @@ -15,19 +15,10 @@ */ 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; @@ -70,21 +61,6 @@ 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(); diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java index 22c087453a..5ebf8d397f 100644 --- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java +++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java @@ -21,7 +21,7 @@ import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.Utilities; import com.android.launcher3.compat.AlphabeticIndexCompat; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.icons.ComponentWithLabel; +import com.android.launcher3.icons.ComponentWithLabelAndIcon; import com.android.launcher3.icons.IconCache; import com.android.launcher3.pm.ShortcutConfigActivityInfo; import com.android.launcher3.util.MultiHashMap; @@ -85,12 +85,13 @@ public class WidgetsModel { * @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise * only widgets and shortcuts associated with the package/user are. */ - public List update(LauncherAppState app, @Nullable PackageUserKey packageUser) { + public List update( + LauncherAppState app, @Nullable PackageUserKey packageUser) { Preconditions.assertWorkerThread(); Context context = app.getContext(); final ArrayList widgetsAndShortcuts = new ArrayList<>(); - List updatedItems = new ArrayList<>(); + List updatedItems = new ArrayList<>(); try { InvariantDeviceProfile idp = app.getInvariantDeviceProfile(); PackageManager pm = app.getContext().getPackageManager();