From 899bf30fe8f20467d1fef926859e6b83d8920af2 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 31 Mar 2023 09:08:27 -0700 Subject: [PATCH] Ensuring that badge override is respected even if component name is set on the Shortcut Bug: 276319271 Test: atest IconCacheTest Flag: N/A Change-Id: I33802ecd23485ba092f842ec3c3d58e2fc286f92 --- .../android/launcher3/icons/IconCache.java | 55 ++++---- .../launcher3/pm/InstallSessionHelper.java | 7 +- .../launcher3/icons/IconCacheTest.java | 131 ++++++++++++++++++ 3 files changed, 164 insertions(+), 29 deletions(-) create mode 100644 tests/src/com/android/launcher3/icons/IconCacheTest.java diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 3c63f26ec4..1e3b0030b8 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -46,10 +46,10 @@ import android.util.SparseArray; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import androidx.core.util.Pair; import com.android.launcher3.InvariantDeviceProfile; -import com.android.launcher3.LauncherFiles; import com.android.launcher3.Utilities; import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; import com.android.launcher3.icons.cache.BaseIconCache; @@ -105,10 +105,6 @@ public class IconCache extends BaseIconCache { private int mPendingIconRequestCount = 0; - public IconCache(Context context, InvariantDeviceProfile idp) { - this(context, idp, LauncherFiles.APP_ICONS_DB, new IconProvider(context)); - } - public IconCache(Context context, InvariantDeviceProfile idp, String dbFileName, IconProvider iconProvider) { super(context, dbFileName, MODEL_EXECUTOR.getLooper(), @@ -254,30 +250,37 @@ public class IconCache extends BaseIconCache { * 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; + return getShortcutInfoBadgeItem(shortcutInfo).bitmap; + } + + @VisibleForTesting + protected ItemInfoWithIcon getShortcutInfoBadgeItem(ShortcutInfo shortcutInfo) { + // Check for badge override first. + String pkg = shortcutInfo.getPackage(); + String override = shortcutInfo.getExtras() == null ? null + : shortcutInfo.getExtras().getString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE); + if (!TextUtils.isEmpty(override) + && InstallSessionHelper.INSTANCE.get(mContext) + .isTrustedPackage(pkg, shortcutInfo.getUserHandle())) { + pkg = override; } else { - String pkg = shortcutInfo.getPackage(); - String override = shortcutInfo.getExtras() == null ? null - : shortcutInfo.getExtras().getString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE); - if (!TextUtils.isEmpty(override) - && InstallSessionHelper.INSTANCE.get(mContext) - .isTrustedPackage(pkg, shortcutInfo.getUserHandle())) { - pkg = override; + // Try component based badge before trying the normal package badge + 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; } - PackageItemInfo pkgInfo = new PackageItemInfo(pkg, shortcutInfo.getUserHandle()); - getTitleAndIconForApp(pkgInfo, false); - return pkgInfo.bitmap; } + PackageItemInfo pkgInfo = new PackageItemInfo(pkg, shortcutInfo.getUserHandle()); + getTitleAndIconForApp(pkgInfo, false); + return pkgInfo; } /** diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java index 7ca3b11001..125b4cef61 100644 --- a/src/com/android/launcher3/pm/InstallSessionHelper.java +++ b/src/com/android/launcher3/pm/InstallSessionHelper.java @@ -181,9 +181,10 @@ public class InstallSessionHelper { public boolean isTrustedPackage(String pkg, UserHandle user) { synchronized (mSessionVerifiedMap) { if (!mSessionVerifiedMap.containsKey(pkg)) { - boolean hasSystemFlag = new PackageManagerHelper(mAppContext).getApplicationInfo( - pkg, user, ApplicationInfo.FLAG_SYSTEM) != null; - mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag); + boolean hasSystemFlag = DEBUG || mAppContext.getPackageName().equals(pkg) + || new PackageManagerHelper(mAppContext) + .getApplicationInfo(pkg, user, ApplicationInfo.FLAG_SYSTEM) != null; + mSessionVerifiedMap.put(pkg, hasSystemFlag); } } return mSessionVerifiedMap.get(pkg); diff --git a/tests/src/com/android/launcher3/icons/IconCacheTest.java b/tests/src/com/android/launcher3/icons/IconCacheTest.java new file mode 100644 index 0000000000..08d6df37ad --- /dev/null +++ b/tests/src/com/android/launcher3/icons/IconCacheTest.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2023 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 static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; + +import static com.android.launcher3.icons.IconCache.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE; +import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import android.content.ComponentName; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.Intent; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutInfo.Builder; +import android.os.PersistableBundle; +import android.text.TextUtils; + +import androidx.annotation.Nullable; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.model.data.AppInfo; +import com.android.launcher3.model.data.ItemInfoWithIcon; +import com.android.launcher3.model.data.PackageItemInfo; +import com.android.launcher3.settings.SettingsActivity; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@RunWith(AndroidJUnit4.class) +public class IconCacheTest { + + private Context mContext; + private IconCache mIconCache; + + private ComponentName mMyComponent; + + @Before + public void setup() { + mContext = getInstrumentation().getTargetContext(); + mMyComponent = new ComponentName(mContext, SettingsActivity.class); + + // In memory icon cache + mIconCache = new IconCache(mContext, + InvariantDeviceProfile.INSTANCE.get(mContext), null, + new LauncherIconProvider(mContext)); + } + + @Test + public void getShortcutInfoBadge_nullComponent_overrideAllowed() throws Exception { + String overridePackage = "com.android.settings"; + ItemInfoWithIcon item = getBadgingInfo(mContext, null, overridePackage); + assertTrue(item instanceof PackageItemInfo); + assertEquals(((PackageItemInfo) item).packageName, overridePackage); + } + + @Test + public void getShortcutInfoBadge_withComponent_overrideAllowed() throws Exception { + String overridePackage = "com.android.settings"; + ItemInfoWithIcon item = getBadgingInfo(mContext, mMyComponent, overridePackage); + assertTrue(item instanceof PackageItemInfo); + assertEquals(((PackageItemInfo) item).packageName, overridePackage); + } + + @Test + public void getShortcutInfoBadge_nullComponent() throws Exception { + ItemInfoWithIcon item = getBadgingInfo(mContext, null, null); + assertTrue(item instanceof PackageItemInfo); + assertEquals(((PackageItemInfo) item).packageName, mContext.getPackageName()); + } + + @Test + public void getShortcutInfoBadge_withComponent() throws Exception { + ItemInfoWithIcon item = getBadgingInfo(mContext, mMyComponent, null); + assertTrue(item instanceof AppInfo); + assertEquals(((AppInfo) item).componentName, mMyComponent); + } + + @Test + public void getShortcutInfoBadge_overrideNotAllowed() throws Exception { + String overridePackage = "com.android.settings"; + String otherPackage = mContext.getPackageName() + ".does.not.exist"; + Context otherContext = new ContextWrapper(mContext) { + @Override + public String getPackageName() { + return otherPackage; + } + }; + ItemInfoWithIcon item = getBadgingInfo(otherContext, null, overridePackage); + assertTrue(item instanceof PackageItemInfo); + // Badge is set to the original package, and not the override package + assertEquals(((PackageItemInfo) item).packageName, otherPackage); + } + + private ItemInfoWithIcon getBadgingInfo(Context context, + @Nullable ComponentName cn, @Nullable String badgeOverride) throws Exception { + Builder builder = new Builder(context, "test-shortcut") + .setIntent(new Intent(Intent.ACTION_VIEW)) + .setTitle("Test"); + if (cn != null) { + builder.setActivity(cn); + } + if (!TextUtils.isEmpty(badgeOverride)) { + PersistableBundle extras = new PersistableBundle(); + extras.putString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE, badgeOverride); + builder.setExtras(extras); + } + ShortcutInfo info = builder.build(); + return MODEL_EXECUTOR.submit(() -> mIconCache.getShortcutInfoBadgeItem(info)).get(); + } +}