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

Commit 1836c4ff authored by Jackal Guo's avatar Jackal Guo Committed by Android (Google) Code Review
Browse files

Merge "Avoid showing the disambiguation dialog"

parents 26d1fa7e 7cb34cc9
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -3121,7 +3121,7 @@ public class ComputerEngine implements Computer {
                final ResolveInfo ri = query.get(j);
                if (DEBUG_PREFERRED || debug) {
                    Slog.v(TAG, "Match for " + ri.activityInfo
                            + ": 0x" + Integer.toHexString(match));
                            + ": 0x" + Integer.toHexString(ri.match));
                }
                if (ri.match > match) {
                    match = ri.match;
@@ -3213,7 +3213,8 @@ public class ComputerEngine implements Computer {
                    // clear it and re-ask the user their preference, if we're looking for
                    // an "always" type entry.

                    if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) {
                    if (always
                            && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity, userId)) {
                        if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) {
                            if (allowSetMutation) {
                                // some components of the set are no longer present in
+13 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.pm;
import android.content.ComponentName;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.util.Slog;
@@ -27,6 +28,7 @@ import android.util.TypedXmlSerializer;

import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
import com.android.server.pm.pkg.PackageUserState;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -197,7 +199,7 @@ public class PreferredComponent {
        }
    }

    public boolean sameSet(List<ResolveInfo> query, boolean excludeSetupWizardPackage) {
    public boolean sameSet(List<ResolveInfo> query, boolean excludeSetupWizardPackage, int userId) {
        if (mSetPackages == null) {
            return query == null;
        }
@@ -206,6 +208,7 @@ public class PreferredComponent {
        }
        final int NQ = query.size();
        final int NS = mSetPackages.length;
        final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
        int numMatch = 0;
        for (int i=0; i<NQ; i++) {
            ResolveInfo ri = query.get(i);
@@ -218,6 +221,15 @@ public class PreferredComponent {
                continue;
            }

            // Avoid showing the disambiguation dialog if the package which is installed with
            // reason INSTALL_REASON_DEVICE_SETUP.
            final PackageUserState pkgUserState =
                    pmi.getPackageStateInternal(ai.packageName).getUserStates().get(userId);
            if (pkgUserState != null && pkgUserState.getInstallReason()
                    == PackageManager.INSTALL_REASON_DEVICE_SETUP) {
                continue;
            }

            for (int j=0; j<NS; j++) {
                if (mSetPackages[j].equals(ai.packageName)
                        && mSetClasses[j].equals(ai.name)) {
+7 −6
Original line number Diff line number Diff line
@@ -55,11 +55,7 @@ import android.content.pm.parsing.component.ParsedIntentInfo;
import android.content.pm.parsing.component.ParsedMainComponent;
import android.content.pm.parsing.component.ParsedPermission;
import android.content.pm.parsing.component.ParsedProcess;

import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
import android.content.pm.pkg.PackageUserStateUtils;
import com.android.server.pm.pkg.SuspendParams;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
@@ -117,6 +113,9 @@ import com.android.server.pm.permission.LegacyPermissionDataProvider;
import com.android.server.pm.permission.LegacyPermissionSettings;
import com.android.server.pm.permission.LegacyPermissionState;
import com.android.server.pm.permission.LegacyPermissionState.PermissionState;
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.SuspendParams;
import com.android.server.pm.verify.domain.DomainVerificationLegacySettings;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationPersistence;
@@ -3293,7 +3292,7 @@ public final class Settings implements Watchable, Snappable {
        int systemMatch = 0;
        int thirdPartyMatch = 0;
        final int numMatches = (ri == null ? 0 : ri.size());
        if (numMatches <= 1) {
        if (numMatches < 1) {
            Slog.w(TAG, "No potential matches found for " + intent
                    + " while setting preferred " + cn.flattenToShortString());
            return;
@@ -4762,7 +4761,9 @@ public final class Settings implements Watchable, Snappable {
            pw.print(" instant=");
            pw.print(ps.getInstantApp(user.id));
            pw.print(" virtual=");
            pw.println(ps.getVirtualPreload(user.id));
            pw.print(ps.getVirtualPreload(user.id));
            pw.print(" installReason=");
            pw.println(ps.getInstallReason(user.id));

            if (ps.getSuspended(user.id)) {
                pw.print(prefix);
+153 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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.server.pm;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;

import android.content.ComponentName;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
import android.util.SparseArray;

import com.android.server.LocalServices;
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateImpl;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.ArrayList;
import java.util.List;

@Presubmit
@RunWith(JUnit4.class)
public class PreferredComponentTest {

    private PackageManagerInternal mMockPackageManagerInternal;

    @Before
    public void setUp() {
        mMockPackageManagerInternal = mock(PackageManagerInternal.class);
        LocalServices.removeServiceForTest(PackageManagerInternal.class);
        LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
    }

    @Test
    public void testPreferredComponent_sameSet_withAppInstalledByDeviceSetup() {
        // Assume we have two ResolveInfos that handle the same Intent.
        final int userId = UserHandle.USER_SYSTEM;
        final List<ResolveInfo> query = new ArrayList<>();
        query.add(createResolveInfo(0, userId));
        query.add(createResolveInfo(1, userId));
        // ResolveInfo(0) is already set as the preferred one when only it exists.
        final ComponentName component = query.get(0).getComponentInfo().getComponentName();
        final PreferredActivity pa = new PreferredActivity(new IntentFilter("TEST_ACTION"),
                0 /* match */, new ComponentName[]{component}, component, true /* always */);

        // Assume ResolveInfo(0) is preinstalled, and ResolveInfo(1) is installed when device setup.
        final PackageUserState pkgUserState0 = new PackageUserStateImpl().setInstallReason(
                PackageManager.INSTALL_REASON_UNKNOWN);
        final PackageUserState pkgUserState1 = new PackageUserStateImpl().setInstallReason(
                PackageManager.INSTALL_REASON_DEVICE_SETUP);
        final PackageStateInternal psInt0 = mock(PackageStateInternal.class);
        final PackageStateInternal psInt1 = mock(PackageStateInternal.class);
        final SparseArray<Object> userStates0 = mock(SparseArray.class);
        final SparseArray<Object> userStates1 = mock(SparseArray.class);
        doReturn(psInt0).when(mMockPackageManagerInternal).getPackageStateInternal("foo_bar0");
        doReturn(psInt1).when(mMockPackageManagerInternal).getPackageStateInternal("foo_bar1");
        doReturn(userStates0).when(psInt0).getUserStates();
        doReturn(userStates1).when(psInt1).getUserStates();
        doReturn(pkgUserState0).when(userStates0).get(anyInt());
        doReturn(pkgUserState1).when(userStates1).get(anyInt());

        // Check if ResolveInfo(1) which is installed by device setup affects the preferred set and
        // this may trigger disambiguation dialog.
        assertTrue(pa.mPref.sameSet(query, true /* excludeSetupWizardPackage */, userId));
    }

    @Test
    public void testPreferredComponent_notSameSet_withAppNotInstalledByDeviceSetup() {
        // Assume we have two ResolveInfos that handle the same Intent.
        final int userId = UserHandle.USER_SYSTEM;
        final List<ResolveInfo> query = new ArrayList<>();
        query.add(createResolveInfo(0, userId));
        query.add(createResolveInfo(1, userId));
        // ResolveInfo(0) is already set as the preferred one when only it exists.
        final ComponentName component = query.get(0).getComponentInfo().getComponentName();
        final PreferredActivity pa = new PreferredActivity(new IntentFilter("TEST_ACTION"),
                0 /* match */, new ComponentName[]{component}, component, true /* always */);

        // Assume ResolveInfo(0) is preinstalled, and ResolveInfo(1) is installed by user.
        final PackageUserState pkgUserState0 = new PackageUserStateImpl().setInstallReason(
                PackageManager.INSTALL_REASON_UNKNOWN);
        final PackageUserState pkgUserState1 = new PackageUserStateImpl().setInstallReason(
                PackageManager.INSTALL_REASON_USER);
        final PackageStateInternal psInt0 = mock(PackageStateInternal.class);
        final PackageStateInternal psInt1 = mock(PackageStateInternal.class);
        final SparseArray<Object> userStates0 = mock(SparseArray.class);
        final SparseArray<Object> userStates1 = mock(SparseArray.class);
        doReturn(psInt0).when(mMockPackageManagerInternal).getPackageStateInternal("foo_bar0");
        doReturn(psInt1).when(mMockPackageManagerInternal).getPackageStateInternal("foo_bar1");
        doReturn(userStates0).when(psInt0).getUserStates();
        doReturn(userStates1).when(psInt1).getUserStates();
        doReturn(pkgUserState0).when(userStates0).get(anyInt());
        doReturn(pkgUserState1).when(userStates1).get(anyInt());

        // Check if ResolveInfo(1) which is installed by user affects the preferred set and
        // this may trigger disambiguation dialog.
        assertFalse(pa.mPref.sameSet(query, true /* excludeSetupWizardPackage */, userId));
    }

    private static ResolveInfo createResolveInfo(int i, int userId) {
        final ResolveInfo resolveInfo = new ResolveInfo();
        resolveInfo.activityInfo = createActivityInfo(i);
        resolveInfo.targetUserId = userId;
        return resolveInfo;
    }

    private static ActivityInfo createActivityInfo(int i) {
        final ActivityInfo ai = new ActivityInfo();
        ai.name = "activity_name" + i;
        ai.packageName = "foo_bar" + i;
        ai.enabled = true;
        ai.exported = true;
        ai.permission = null;
        ai.applicationInfo = createApplicationInfo(i, ai.packageName);
        return ai;
    }

    private static ApplicationInfo createApplicationInfo(int i, String packageName) {
        final ApplicationInfo ai = new ApplicationInfo();
        ai.name = "app_name" + i;
        ai.packageName = packageName;
        ai.enabled = true;
        return ai;
    }
}