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

Commit 3023df58 authored by Matías Hernández's avatar Matías Hernández Committed by Android (Google) Code Review
Browse files

Merge "Fix app icon of notifications posted by direct-boot-aware packages" into main

parents 47b19e66 ef177d86
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -302,13 +302,23 @@ public class ApplicationPackageManager extends PackageManager {

    @Override
    public Intent getLaunchIntentForPackage(String packageName) {
        return getLaunchIntentForPackage(packageName, false);
    }

    @Override
    @Nullable
    public Intent getLaunchIntentForPackage(@NonNull String packageName,
            boolean includeDirectBootUnaware) {
        ResolveInfoFlags queryFlags = ResolveInfoFlags.of(
                includeDirectBootUnaware ? MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE : 0);

        // First see if the package has an INFO activity; the existence of
        // such an activity is implied to be the desired front-door for the
        // overall package (such as if it has multiple launcher entries).
        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
        intentToResolve.addCategory(Intent.CATEGORY_INFO);
        intentToResolve.setPackage(packageName);
        List<ResolveInfo> ris = queryIntentActivities(intentToResolve, 0);
        List<ResolveInfo> ris = queryIntentActivities(intentToResolve, queryFlags);

        // Otherwise, try to find a main launcher activity.
        if (ris == null || ris.size() <= 0) {
@@ -316,7 +326,7 @@ public class ApplicationPackageManager extends PackageManager {
            intentToResolve.removeCategory(Intent.CATEGORY_INFO);
            intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
            intentToResolve.setPackage(packageName);
            ris = queryIntentActivities(intentToResolve, 0);
            ris = queryIntentActivities(intentToResolve, queryFlags);
        }
        if (ris == null || ris.size() <= 0) {
            return null;
+33 −1
Original line number Diff line number Diff line
@@ -5966,6 +5966,38 @@ public abstract class PackageManager {
     */
     public abstract @Nullable Intent getLaunchIntentForPackage(@NonNull String packageName);

    /**
     * Returns a "good" intent to launch a front-door activity in a package.
     * This is used, for example, to implement an "open" button when browsing
     * through packages.  The current implementation looks first for a main
     * activity in the category {@link Intent#CATEGORY_INFO}, and next for a
     * main activity in the category {@link Intent#CATEGORY_LAUNCHER}. Returns
     * <code>null</code> if neither are found.
     *
     * <p>Consider using {@link #getLaunchIntentSenderForPackage(String)} if
     * the caller is not allowed to query for the <code>packageName</code>.
     *
     * @param packageName The name of the package to inspect.
     * @param includeDirectBootUnaware When {@code true}, activities that are direct-boot-unaware
     *    will be considered even if the device hasn't been unlocked (i.e. querying will be done
     *    with {@code MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE}).
     *
     * @return A fully-qualified {@link Intent} that can be used to launch the
     * main activity in the package. Returns <code>null</code> if the package
     * does not contain such an activity, or if <em>packageName</em> is not
     * recognized.
     *
     * @see #getLaunchIntentSenderForPackage(String)
     *
     * @hide
     */
    public @Nullable Intent getLaunchIntentForPackage(@NonNull String packageName,
            boolean includeDirectBootUnaware) {
        throw new UnsupportedOperationException(
                "getLaunchIntentForPackage(packageName, includeDirectBootUnaware) not implemented"
                        + " in subclass");
    }

    /**
     * Return a "good" intent to launch a front-door Leanback activity in a
     * package, for use for example to implement an "open" button when browsing
+157 −19
Original line number Diff line number Diff line
@@ -16,19 +16,37 @@

package android.app;

import static android.content.Intent.ACTION_MAIN;
import static android.content.Intent.CATEGORY_INFO;
import static android.content.Intent.CATEGORY_LAUNCHER;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.os.storage.VolumeInfo.STATE_MOUNTED;
import static android.os.storage.VolumeInfo.STATE_UNMOUNTED;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager.ResolveInfoFlags;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -44,6 +62,7 @@ import com.android.internal.annotations.VisibleForTesting;

import junit.framework.TestCase;

import org.mockito.ArgumentMatcher;
import org.mockito.Mockito;
import org.xmlpull.v1.XmlPullParser;

@@ -102,14 +121,14 @@ public class ApplicationPackageManagerTest extends TestCase {
        sVolumes.add(sPrivateUnmountedVol);
    }

    private static final class MockedApplicationPackageManager extends ApplicationPackageManager {
    public static class MockedApplicationPackageManager extends ApplicationPackageManager {
        private boolean mForceAllowOnExternal = false;
        private boolean mAllow3rdPartyOnInternal = true;
        private HashMap<ApplicationInfo, Resources> mResourcesMap;

        public MockedApplicationPackageManager() {
            super(null, null);
            mResourcesMap = new HashMap<ApplicationInfo, Resources>();
            mResourcesMap = new HashMap<>();
        }

        public void setForceAllowOnExternal(boolean forceAllowOnExternal) {
@@ -153,7 +172,7 @@ public class ApplicationPackageManagerTest extends TestCase {
    }

    private StorageManager getMockedStorageManager() {
        StorageManager storageManager = Mockito.mock(StorageManager.class);
        StorageManager storageManager = mock(StorageManager.class);
        Mockito.when(storageManager.getVolumes()).thenReturn(sVolumes);
        Mockito.when(storageManager.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL))
                .thenReturn(sInternalVol);
@@ -190,7 +209,7 @@ public class ApplicationPackageManagerTest extends TestCase {
        sysAppInfo.flags = ApplicationInfo.FLAG_SYSTEM;

        StorageManager storageManager = getMockedStorageManager();
        IPackageManager pm = Mockito.mock(IPackageManager.class);
        IPackageManager pm = mock(IPackageManager.class);

        MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager();

@@ -220,7 +239,7 @@ public class ApplicationPackageManagerTest extends TestCase {
        ApplicationInfo appInfo = new ApplicationInfo();
        StorageManager storageManager = getMockedStorageManager();

        IPackageManager pm = Mockito.mock(IPackageManager.class);
        IPackageManager pm = mock(IPackageManager.class);
        Mockito.when(pm.isPackageDeviceAdminOnAnyUser(Mockito.anyString())).thenReturn(false);

        MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager();
@@ -249,7 +268,7 @@ public class ApplicationPackageManagerTest extends TestCase {
        ApplicationInfo appInfo = new ApplicationInfo();
        StorageManager storageManager = getMockedStorageManager();

        IPackageManager pm = Mockito.mock(IPackageManager.class);
        IPackageManager pm = mock(IPackageManager.class);

        MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager();
        appPkgMgr.setForceAllowOnExternal(true);
@@ -291,15 +310,15 @@ public class ApplicationPackageManagerTest extends TestCase {

    public void testExtractPackageItemInfoAttributes_noMetaData() {
        final MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager();
        final PackageItemInfo packageItemInfo = Mockito.mock(PackageItemInfo.class);
        final PackageItemInfo packageItemInfo = mock(PackageItemInfo.class);
        assertThat(appPkgMgr.extractPackageItemInfoAttributes(packageItemInfo, null, null,
                new int[]{})).isNull();
    }

    public void testExtractPackageItemInfoAttributes_noParser() {
        final MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager();
        final PackageItemInfo packageItemInfo = Mockito.mock(PackageItemInfo.class);
        final ApplicationInfo applicationInfo = Mockito.mock(ApplicationInfo.class);
        final PackageItemInfo packageItemInfo = mock(PackageItemInfo.class);
        final ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
        when(packageItemInfo.getApplicationInfo()).thenReturn(applicationInfo);
        assertThat(appPkgMgr.extractPackageItemInfoAttributes(packageItemInfo, null, null,
                new int[]{})).isNull();
@@ -307,8 +326,8 @@ public class ApplicationPackageManagerTest extends TestCase {

    public void testExtractPackageItemInfoAttributes_noMetaDataXml() {
        final MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager();
        final PackageItemInfo packageItemInfo = Mockito.mock(PackageItemInfo.class);
        final ApplicationInfo applicationInfo = Mockito.mock(ApplicationInfo.class);
        final PackageItemInfo packageItemInfo = mock(PackageItemInfo.class);
        final ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
        when(packageItemInfo.getApplicationInfo()).thenReturn(applicationInfo);
        when(packageItemInfo.loadXmlMetaData(any(), any())).thenReturn(null);
        assertThat(appPkgMgr.extractPackageItemInfoAttributes(packageItemInfo, null, null,
@@ -318,9 +337,9 @@ public class ApplicationPackageManagerTest extends TestCase {
    public void testExtractPackageItemInfoAttributes_nonMatchingRootTag() throws Exception {
        final String rootTag = "rootTag";
        final MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager();
        final PackageItemInfo packageItemInfo = Mockito.mock(PackageItemInfo.class);
        final ApplicationInfo applicationInfo = Mockito.mock(ApplicationInfo.class);
        final XmlResourceParser parser = Mockito.mock(XmlResourceParser.class);
        final PackageItemInfo packageItemInfo = mock(PackageItemInfo.class);
        final ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
        final XmlResourceParser parser = mock(XmlResourceParser.class);

        when(packageItemInfo.getApplicationInfo()).thenReturn(applicationInfo);
        packageItemInfo.metaData = new Bundle();
@@ -334,11 +353,11 @@ public class ApplicationPackageManagerTest extends TestCase {
    public void testExtractPackageItemInfoAttributes_successfulExtraction() throws Exception {
        final String rootTag = "rootTag";
        final MockedApplicationPackageManager appPkgMgr = new MockedApplicationPackageManager();
        final PackageItemInfo packageItemInfo = Mockito.mock(PackageItemInfo.class);
        final ApplicationInfo applicationInfo = Mockito.mock(ApplicationInfo.class);
        final XmlResourceParser parser = Mockito.mock(XmlResourceParser.class);
        final Resources resources = Mockito.mock(Resources.class);
        final TypedArray attributes = Mockito.mock(TypedArray.class);
        final PackageItemInfo packageItemInfo = mock(PackageItemInfo.class);
        final ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
        final XmlResourceParser parser = mock(XmlResourceParser.class);
        final Resources resources = mock(Resources.class);
        final TypedArray attributes = mock(TypedArray.class);

        when(packageItemInfo.getApplicationInfo()).thenReturn(applicationInfo);
        packageItemInfo.metaData = new Bundle();
@@ -351,4 +370,123 @@ public class ApplicationPackageManagerTest extends TestCase {
        assertThat(appPkgMgr.extractPackageItemInfoAttributes(packageItemInfo, null, rootTag,
                new int[]{})).isEqualTo(attributes);
    }

    public void testGetLaunchIntentForPackage_categoryInfoActivity_returnsIt() throws Exception {
        String pkg = "com.some.package";
        int userId = 42;
        ResolveInfo categoryInfoResolveInfo = new ResolveInfo();
        categoryInfoResolveInfo.activityInfo = new ActivityInfo();
        categoryInfoResolveInfo.activityInfo.packageName = pkg;
        categoryInfoResolveInfo.activityInfo.name = "activity";
        Intent baseIntent = new Intent(ACTION_MAIN).setPackage(pkg);

        final MockedApplicationPackageManager pm = spy(new MockedApplicationPackageManager());
        doReturn(userId).when(pm).getUserId();
        doReturn(List.of(categoryInfoResolveInfo))
                .when(pm).queryIntentActivitiesAsUser(
                        eqIntent(new Intent(baseIntent).addCategory(CATEGORY_INFO)),
                        any(ResolveInfoFlags.class),
                        anyInt());
        doReturn(
                List.of())
                .when(pm).queryIntentActivitiesAsUser(
                        eqIntent(new Intent(baseIntent).addCategory(CATEGORY_LAUNCHER)),
                        any(ResolveInfoFlags.class),
                        anyInt());

        Intent intent = pm.getLaunchIntentForPackage(pkg, true);

        assertThat(intent).isNotNull();
        assertThat(intent.getComponent()).isEqualTo(new ComponentName(pkg, "activity"));
        assertThat(intent.getCategories()).containsExactly(CATEGORY_INFO);
        assertThat(intent.getFlags()).isEqualTo(FLAG_ACTIVITY_NEW_TASK);
        verify(pm).queryIntentActivitiesAsUser(
                eqIntent(new Intent(ACTION_MAIN).addCategory(CATEGORY_INFO).setPackage(pkg)),
                eqResolveInfoFlags(MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE),
                eq(userId));
    }

    public void testGetLaunchIntentForPackage_categoryLauncherActivity_returnsIt() {
        String pkg = "com.some.package";
        int userId = 42;
        ResolveInfo categoryLauncherResolveInfo1 = new ResolveInfo();
        categoryLauncherResolveInfo1.activityInfo = new ActivityInfo();
        categoryLauncherResolveInfo1.activityInfo.packageName = pkg;
        categoryLauncherResolveInfo1.activityInfo.name = "activity1";
        ResolveInfo categoryLauncherResolveInfo2 = new ResolveInfo();
        categoryLauncherResolveInfo2.activityInfo = new ActivityInfo();
        categoryLauncherResolveInfo2.activityInfo.packageName = pkg;
        categoryLauncherResolveInfo2.activityInfo.name = "activity2";
        Intent baseIntent = new Intent(ACTION_MAIN).setPackage(pkg);

        final MockedApplicationPackageManager pm = spy(new MockedApplicationPackageManager());
        doReturn(userId).when(pm).getUserId();
        doReturn(List.of())
                .when(pm).queryIntentActivitiesAsUser(
                        eqIntent(new Intent(baseIntent).addCategory(CATEGORY_INFO)),
                        any(ResolveInfoFlags.class),
                        anyInt());
        doReturn(
                List.of(categoryLauncherResolveInfo1, categoryLauncherResolveInfo2))
                .when(pm).queryIntentActivitiesAsUser(
                        eqIntent(new Intent(baseIntent).addCategory(CATEGORY_LAUNCHER)),
                        any(ResolveInfoFlags.class),
                        anyInt());

        Intent intent = pm.getLaunchIntentForPackage(pkg, true);

        assertThat(intent).isNotNull();
        assertThat(intent.getComponent()).isEqualTo(new ComponentName(pkg, "activity1"));
        assertThat(intent.getCategories()).containsExactly(CATEGORY_LAUNCHER);
        assertThat(intent.getFlags()).isEqualTo(FLAG_ACTIVITY_NEW_TASK);
    }

    public void testGetLaunchIntentForPackage_noSuitableActivity_returnsNull() throws Exception {
        String pkg = "com.some.package";
        int userId = 42;

        final MockedApplicationPackageManager pm = spy(new MockedApplicationPackageManager());
        doReturn(userId).when(pm).getUserId();
        doReturn(List.of())
                .when(pm).queryIntentActivitiesAsUser(
                        any(),
                        any(ResolveInfoFlags.class),
                        anyInt());

        Intent intent = pm.getLaunchIntentForPackage(pkg, true);

        assertThat(intent).isNull();
    }

    /** Equality check for intents -- ignoring extras */
    private static Intent eqIntent(Intent wanted) {
        return argThat(
                new ArgumentMatcher<>() {
                    @Override
                    public boolean matches(Intent argument) {
                        return wanted.filterEquals(argument)
                                && wanted.getFlags() == argument.getFlags();
                    }

                    @Override
                    public String toString() {
                        return wanted.toString();
                    }
                });
    }

    private static ResolveInfoFlags eqResolveInfoFlags(long flagsWanted) {
        return argThat(
                new ArgumentMatcher<>() {
                    @Override
                    public boolean matches(ResolveInfoFlags argument) {
                        return argument.getValue() == flagsWanted;
                    }

                    @Override
                    public String toString() {
                        return String.valueOf(flagsWanted);
                    }
                });
    }
}
+9 −3
Original line number Diff line number Diff line
@@ -87,9 +87,15 @@ constructor(private val userManager: UserManager, dumpManager: DumpManager) :
                // It's not a system app at all.
                return false
            } else {
                // If there's no launch intent, it's probably a headless app.
                val pm = context.packageManager
                return (pm.getLaunchIntentForPackage(info.packageName) == null)
                // If there's no launch intent, it's probably a headless app. Check for both
                // direct-aware and -unaware intents; otherwise this will almost certainly fail
                // for notifications posted before unlocking.
                val packageLaunchIntent =
                    context.packageManager.getLaunchIntentForPackage(
                        info.packageName,
                        /* includeDirectBootUnaware= */ true,
                    )
                return packageLaunchIntent == null
            }
        } else {
            // If for some reason we don't have the app info, we don't know; best assume it's