diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index 3f3cfd60b5639..052e68064f7c9 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -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 diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java index ff6b73b36f62f..4ec042f79052d 100644 --- a/services/core/java/com/android/server/pm/PreferredComponent.java +++ b/services/core/java/com/android/server/pm/PreferredComponent.java @@ -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 query, boolean excludeSetupWizardPackage) { + public boolean sameSet(List 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 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 userStates0 = mock(SparseArray.class); + final SparseArray 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 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 userStates0 = mock(SparseArray.class); + final SparseArray 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; + } +}