Include archived apps into the counter

Test: InstalledAppCounterTest

Bug: 304255511
Change-Id: If667acae249d248ce013a9dd370af41698266a45
This commit is contained in:
Mark Kim
2023-10-17 17:09:23 +00:00
parent db679c9100
commit 679b2626d8
3 changed files with 142 additions and 24 deletions

View File

@@ -16,33 +16,49 @@ package com.android.settings.applications;
import android.content.Context; import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureFlags;
import android.content.pm.FeatureFlagsImpl;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import java.util.List; import java.util.List;
public abstract class AppCounter extends AsyncTask<Void, Void, Integer> { public abstract class AppCounter extends AsyncTask<Void, Void, Integer> {
protected final PackageManager mPm; protected final PackageManager mPm;
protected final UserManager mUm; protected final UserManager mUm;
protected final FeatureFlags mFf;
public AppCounter(Context context, PackageManager packageManager) { @VisibleForTesting
AppCounter(@NonNull Context context, @NonNull PackageManager packageManager,
@NonNull FeatureFlags featureFlags) {
mPm = packageManager; mPm = packageManager;
mUm = (UserManager) context.getSystemService(Context.USER_SERVICE); mUm = context.getSystemService(UserManager.class);
mFf = featureFlags;
}
public AppCounter(@NonNull Context context, @NonNull PackageManager packageManager) {
this(context, packageManager, new FeatureFlagsImpl());
} }
@Override @Override
protected Integer doInBackground(Void... params) { protected Integer doInBackground(Void... params) {
int count = 0; int count = 0;
for (UserInfo user : mUm.getProfiles(UserHandle.myUserId())) { for (UserInfo user : mUm.getProfiles(UserHandle.myUserId())) {
long flags = PackageManager.GET_DISABLED_COMPONENTS
| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
| (mFf.archiving() ? PackageManager.MATCH_ARCHIVED_PACKAGES : 0)
| (user.isAdmin() ? PackageManager.MATCH_ANY_USER : 0);
ApplicationInfoFlags infoFlags = ApplicationInfoFlags.of(flags);
final List<ApplicationInfo> list = final List<ApplicationInfo> list =
mPm.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS mPm.getInstalledApplicationsAsUser(infoFlags, user.id);
| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
| (user.isAdmin() ? PackageManager.MATCH_ANY_USER : 0),
user.id);
for (ApplicationInfo info : list) { for (ApplicationInfo info : list) {
if (includeInCount(info)) { if (includeInCount(info)) {
count++; count++;
@@ -62,5 +78,6 @@ public abstract class AppCounter extends AsyncTask<Void, Void, Integer> {
} }
protected abstract void onCountComplete(int num); protected abstract void onCountComplete(int num);
protected abstract boolean includeInCount(ApplicationInfo info); protected abstract boolean includeInCount(ApplicationInfo info);
} }

View File

@@ -17,10 +17,15 @@ package com.android.settings.applications;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureFlags;
import android.content.pm.FeatureFlagsImpl;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.os.UserHandle; import android.os.UserHandle;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import java.util.List; import java.util.List;
public abstract class InstalledAppCounter extends AppCounter { public abstract class InstalledAppCounter extends AppCounter {
@@ -32,9 +37,15 @@ public abstract class InstalledAppCounter extends AppCounter {
private final int mInstallReason; private final int mInstallReason;
public InstalledAppCounter(Context context, int installReason, public InstalledAppCounter(@NonNull Context context, int installReason,
PackageManager packageManager) { @NonNull PackageManager packageManager) {
super(context, packageManager); this(context, installReason, packageManager, new FeatureFlagsImpl());
}
@VisibleForTesting
InstalledAppCounter(@NonNull Context context, int installReason,
@NonNull PackageManager packageManager, @NonNull FeatureFlags featureFlags) {
super(context, packageManager, featureFlags);
mInstallReason = installReason; mInstallReason = installReason;
} }

View File

@@ -32,7 +32,11 @@ import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.FakeFeatureFlagsImpl;
import android.content.pm.FeatureFlags;
import android.content.pm.Flags;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.os.UserHandle; import android.os.UserHandle;
@@ -51,18 +55,20 @@ import org.robolectric.shadows.ShadowApplication;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import java.util.Set; import java.util.Set;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@LooperMode(LooperMode.Mode.LEGACY) @LooperMode(LooperMode.Mode.LEGACY)
public final class InstalledAppCounterTest { public final class InstalledAppCounterTest {
private final String APP_1 = "app1"; private static final String APP_1 = "app1";
private final String APP_2 = "app2"; private static final String APP_2 = "app2";
private final String APP_3 = "app3"; private static final String APP_3 = "app3";
private final String APP_4 = "app4"; private static final String APP_4 = "app4";
private final String APP_5 = "app5"; private static final String APP_5 = "app5";
private final String APP_6 = "app6"; private static final String APP_6 = "app6";
private static final String APP_7 = "app7";
private final int MAIN_USER_ID = 0; private final int MAIN_USER_ID = 0;
private final int MANAGED_PROFILE_ID = 10; private final int MANAGED_PROFILE_ID = 10;
@@ -85,11 +91,16 @@ public final class InstalledAppCounterTest {
private ApplicationInfo mApp4; private ApplicationInfo mApp4;
private ApplicationInfo mApp5; private ApplicationInfo mApp5;
private ApplicationInfo mApp6; private ApplicationInfo mApp6;
private ApplicationInfo mApp7;
private FakeFeatureFlagsImpl mFakeFeatureFlags;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
mFakeFeatureFlags = new FakeFeatureFlagsImpl();
mFakeFeatureFlags.setFlag(Flags.FLAG_ARCHIVING, true);
mApp1 = buildInfo(MAIN_USER_APP_UID, APP_1, mApp1 = buildInfo(MAIN_USER_APP_UID, APP_1,
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, 0 /* targetSdkVersion */); ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, 0 /* targetSdkVersion */);
@@ -103,6 +114,9 @@ public final class InstalledAppCounterTest {
0 /* targetSdkVersion */); 0 /* targetSdkVersion */);
mApp6 = buildInfo(MANAGED_PROFILE_APP_UID, APP_6, ApplicationInfo.FLAG_SYSTEM, mApp6 = buildInfo(MANAGED_PROFILE_APP_UID, APP_6, ApplicationInfo.FLAG_SYSTEM,
0 /* targetSdkVersion */); 0 /* targetSdkVersion */);
mApp7 = buildInfo(MAIN_USER_APP_UID, APP_7, 0 /* flags */,
0 /* targetSdkVersion */);
mApp7.isArchived = true;
} }
private void expectQueryIntentActivities(int userId, String packageName, boolean launchable) { private void expectQueryIntentActivities(int userId, String packageName, boolean launchable) {
@@ -128,8 +142,14 @@ public final class InstalledAppCounterTest {
// Verify that installed packages were retrieved the current user and the user's managed // Verify that installed packages were retrieved the current user and the user's managed
// profile only. // profile only.
verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(), eq(MAIN_USER_ID)); verify(mPackageManager)
verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(), eq(MANAGED_PROFILE_ID)); .getInstalledApplicationsAsUser(
any(ApplicationInfoFlags.class),
eq(MAIN_USER_ID));
verify(mPackageManager)
.getInstalledApplicationsAsUser(
any(ApplicationInfoFlags.class),
eq(MANAGED_PROFILE_ID));
verify(mPackageManager, atLeast(0)) verify(mPackageManager, atLeast(0))
.queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt()); .queryIntentActivitiesAsUser(any(Intent.class), anyInt(), anyInt());
verifyNoMoreInteractions(mPackageManager); verifyNoMoreInteractions(mPackageManager);
@@ -179,6 +199,48 @@ public final class InstalledAppCounterTest {
testCountInstalledAppsAcrossAllUsers(true /* async */); testCountInstalledAppsAcrossAllUsers(true /* async */);
} }
@Test
public void testCountInstalledApps_archivingDisabled() {
when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(List.of(
new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN)));
// The user has four apps installed:
// * app2 is a user-installed app. It should be counted.
// * app7 is a user-archived app. It should not be counted.
when(mPackageManager.getInstalledApplicationsAsUser(
argThat(isApplicationInfoFlagsEqualTo(
ApplicationInfoFlags.of(
PackageManager.GET_DISABLED_COMPONENTS
| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
| PackageManager.MATCH_ANY_USER))),
eq(MAIN_USER_ID))).thenReturn(Arrays.asList(mApp2));
mFakeFeatureFlags.setFlag(Flags.FLAG_ARCHIVING, false);
// Count the number of all apps installed, irrespective of install reason.
count(InstalledAppCounter.IGNORE_INSTALL_REASON, mFakeFeatureFlags);
assertThat(mInstalledAppCount).isEqualTo(1);
}
@Test
public void testCountInstalledApps_archivingEnabled() {
when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(List.of(
new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN)));
// The user has four apps installed:
// * app2 is a user-installed app. It should be counted.
// * app7 is a user-archived app. It should be counted.
when(mPackageManager.getInstalledApplicationsAsUser(
argThat(isApplicationInfoFlagsEqualTo(
ApplicationInfoFlags.of(
PackageManager.GET_DISABLED_COMPONENTS
| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
| PackageManager.MATCH_ANY_USER
| PackageManager.MATCH_ARCHIVED_PACKAGES))),
eq(MAIN_USER_ID))).thenReturn(Arrays.asList(mApp2, mApp7));
// Count the number of all apps installed, irrespective of install reason.
count(InstalledAppCounter.IGNORE_INSTALL_REASON, mFakeFeatureFlags);
assertThat(mInstalledAppCount).isEqualTo(2);
}
private void count(int installReason, boolean async) { private void count(int installReason, boolean async) {
mInstalledAppCount = -1; mInstalledAppCount = -1;
final InstalledAppCounterTestable counter = new InstalledAppCounterTestable(installReason); final InstalledAppCounterTestable counter = new InstalledAppCounterTestable(installReason);
@@ -191,16 +253,27 @@ public final class InstalledAppCounterTest {
} }
} }
private void count(int installReason, FeatureFlags featureFlags) {
mInstalledAppCount = -1;
final InstalledAppCounterTestable counter =
new InstalledAppCounterTestable(installReason, featureFlags);
counter.executeInForeground();
}
private void configurePackageManager() { private void configurePackageManager() {
// The first user has four apps installed: // The first user has four apps installed:
// * app1 is an updated system app. It should be counted. // * app1 is an updated system app. It should be counted.
// * app2 is a user-installed app. It should be counted. // * app2 is a user-installed app. It should be counted.
// * app3 is a system app that provides a launcher icon. It should be counted. // * app3 is a system app that provides a launcher icon. It should be counted.
// * app4 is a system app that provides no launcher icon. It should not be counted. // * app4 is a system app that provides no launcher icon. It should not be counted.
when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS ApplicationInfoFlags infoFlags1 = ApplicationInfoFlags.of(
| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS PackageManager.GET_DISABLED_COMPONENTS
| PackageManager.MATCH_ANY_USER, | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
MAIN_USER_ID)).thenReturn(Arrays.asList(mApp1, mApp2, mApp3, mApp4)); | PackageManager.MATCH_ANY_USER);
when(mPackageManager.getInstalledApplicationsAsUser(
argThat(isApplicationInfoFlagsEqualTo(infoFlags1)),
eq(MAIN_USER_ID))
).thenReturn(Arrays.asList(mApp1, mApp2, mApp3, mApp4));
// For system apps, InstalledAppCounter checks whether they handle the default launcher // For system apps, InstalledAppCounter checks whether they handle the default launcher
// intent to decide whether to include them in the count of installed apps or not. // intent to decide whether to include them in the count of installed apps or not.
expectQueryIntentActivities(MAIN_USER_ID, APP_3, true /* launchable */); expectQueryIntentActivities(MAIN_USER_ID, APP_3, true /* launchable */);
@@ -220,9 +293,12 @@ public final class InstalledAppCounterTest {
// The second user has two apps installed: // The second user has two apps installed:
// * app5 is a user-installed app. It should be counted. // * app5 is a user-installed app. It should be counted.
// * app6 is a system app that provides a launcher icon. It should be counted. // * app6 is a system app that provides a launcher icon. It should be counted.
when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS ApplicationInfoFlags infoFlags2 = ApplicationInfoFlags.of(
| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,MANAGED_PROFILE_ID)) PackageManager.GET_DISABLED_COMPONENTS
.thenReturn(Arrays.asList(mApp5, mApp6)); | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
when(mPackageManager.getInstalledApplicationsAsUser(
argThat(isApplicationInfoFlagsEqualTo(infoFlags2)), eq(MANAGED_PROFILE_ID))
).thenReturn(Arrays.asList(mApp5, mApp6));
expectQueryIntentActivities(MANAGED_PROFILE_ID, APP_6, true /* launchable */); expectQueryIntentActivities(MANAGED_PROFILE_ID, APP_6, true /* launchable */);
// app5 is installed by enterprise policy. // app5 is installed by enterprise policy.
@@ -238,6 +314,10 @@ public final class InstalledAppCounterTest {
super(mContext, installReason, mPackageManager); super(mContext, installReason, mPackageManager);
} }
private InstalledAppCounterTestable(int installReason, FeatureFlags featureFlags) {
super(mContext, installReason, mPackageManager, featureFlags);
}
@Override @Override
protected void onCountComplete(int num) { protected void onCountComplete(int num) {
mInstalledAppCount = num; mInstalledAppCount = num;
@@ -263,4 +343,14 @@ public final class InstalledAppCounterTest {
return true; return true;
}; };
} }
private ArgumentMatcher<ApplicationInfoFlags> isApplicationInfoFlagsEqualTo(
ApplicationInfoFlags infoFlags) {
return flags -> {
if (flags == null) {
return false;
}
return flags.getValue() == infoFlags.getValue();
};
}
} }