1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.settings.applications; 18 19 import static com.android.settings.testutils.ApplicationTestUtils.buildInfo; 20 import static com.google.common.truth.Truth.assertThat; 21 import static org.mockito.Matchers.anyInt; 22 import static org.mockito.Matchers.anyObject; 23 import static org.mockito.Matchers.argThat; 24 import static org.mockito.Matchers.eq; 25 import static org.mockito.Mockito.atLeast; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.when; 28 29 import android.content.Intent; 30 import android.content.pm.ApplicationInfo; 31 import android.content.pm.PackageManager; 32 import android.content.pm.ResolveInfo; 33 import android.content.pm.UserInfo; 34 import android.os.UserHandle; 35 import android.os.UserManager; 36 37 import com.android.settings.testutils.SettingsRobolectricTestRunner; 38 import com.android.settingslib.wrapper.PackageManagerWrapper; 39 40 import org.junit.Before; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 import org.mockito.ArgumentMatcher; 44 import org.mockito.Mock; 45 import org.mockito.MockitoAnnotations; 46 import org.robolectric.shadows.ShadowApplication; 47 48 import java.util.Arrays; 49 import java.util.Collections; 50 import java.util.HashSet; 51 import java.util.List; 52 import java.util.Set; 53 54 @RunWith(SettingsRobolectricTestRunner.class) 55 public final class InstalledAppListerTest { 56 57 private final String APP_1 = "app1"; 58 private final String APP_2 = "app2"; 59 private final String APP_3 = "app3"; 60 private final String APP_4 = "app4"; 61 private final String APP_5 = "app5"; 62 private final String APP_6 = "app6"; 63 64 private final int MAIN_USER_ID = 0; 65 private final int MANAGED_PROFILE_ID = 10; 66 67 private final int PER_USER_UID_RANGE = 100000; 68 private final int MAIN_USER_APP_UID = MAIN_USER_ID * PER_USER_UID_RANGE; 69 private final int MANAGED_PROFILE_APP_UID = MANAGED_PROFILE_ID * PER_USER_UID_RANGE; 70 71 @Mock 72 private UserManager mUserManager; 73 @Mock 74 private PackageManagerWrapper mPackageManager; 75 76 private List<UserAppInfo> mInstalledAppList = Collections.emptyList(); 77 78 @Before 79 public void setUp() { 80 MockitoAnnotations.initMocks(this); 81 } 82 83 private void expectQueryIntentActivities(int userId, String packageName, boolean launchable) { 84 when(mPackageManager.queryIntentActivitiesAsUser( 85 argThat(isLaunchIntentFor(packageName)), 86 eq(PackageManager.GET_DISABLED_COMPONENTS | PackageManager.MATCH_DIRECT_BOOT_AWARE 87 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE), 88 eq(userId))).thenReturn(launchable 89 ? Collections.singletonList(new ResolveInfo()) 90 : Collections.emptyList()); 91 } 92 93 @Test 94 public void testCountInstalledAppsAcrossAllUsers() { 95 // There are two users. 96 when(mUserManager.getProfiles(UserHandle.myUserId())).thenReturn(Arrays.asList( 97 new UserInfo(MAIN_USER_ID, "main", UserInfo.FLAG_ADMIN), 98 new UserInfo(MANAGED_PROFILE_ID, "managed profile", 0))); 99 100 // The first user has four apps installed: 101 // * app1 is an updated system app. It should be listed. 102 // * app2 is a user-installed app. It should be listed. 103 // * app3 is a system app that provides a launcher icon. It should be listed. 104 // * app4 is a system app that provides no launcher icon. It should not be listed. 105 when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS 106 | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS 107 | PackageManager.MATCH_ANY_USER, 108 MAIN_USER_ID)).thenReturn(Arrays.asList( 109 buildInfo(MAIN_USER_APP_UID, APP_1, 110 ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, 0 /* targetSdkVersion */), 111 buildInfo(MAIN_USER_APP_UID, APP_2, 0 /* flags */, 112 0 /* targetSdkVersion */), 113 buildInfo(MAIN_USER_APP_UID, APP_3, ApplicationInfo.FLAG_SYSTEM, 114 0 /* targetSdkVersion */), 115 buildInfo(MAIN_USER_APP_UID, APP_4, ApplicationInfo.FLAG_SYSTEM, 116 0 /* targetSdkVersion */))); 117 // For system apps, InstalledAppLister checks whether they handle the default launcher 118 // intent to decide whether to include them in the list of installed apps or not. 119 expectQueryIntentActivities(MAIN_USER_ID, APP_3, true /* launchable */); 120 expectQueryIntentActivities(MAIN_USER_ID, APP_4, false /* launchable */); 121 122 // app1, app3 and app4 are installed by enterprise policy. 123 final UserHandle mainUser = new UserHandle(MAIN_USER_ID); 124 when(mPackageManager.getInstallReason(APP_1, mainUser)) 125 .thenReturn(PackageManager.INSTALL_REASON_POLICY); 126 when(mPackageManager.getInstallReason(APP_2, mainUser)) 127 .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN); 128 when(mPackageManager.getInstallReason(APP_3, mainUser)) 129 .thenReturn(PackageManager.INSTALL_REASON_POLICY); 130 when(mPackageManager.getInstallReason(APP_4, mainUser)) 131 .thenReturn(PackageManager.INSTALL_REASON_POLICY); 132 133 // The second user has two apps installed: 134 // * app5 is a user-installed app. It should be listed. 135 // * app6 is a system app that provides a launcher icon. It should be listed. 136 when(mPackageManager.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS 137 | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, 138 MANAGED_PROFILE_ID)).thenReturn(Arrays.asList( 139 buildInfo(MANAGED_PROFILE_APP_UID, APP_5, 0 /* flags */, 140 0 /* targetSdkVersion */), 141 buildInfo(MANAGED_PROFILE_APP_UID, APP_6, ApplicationInfo.FLAG_SYSTEM, 142 0 /* targetSdkVersion */))); 143 expectQueryIntentActivities(MANAGED_PROFILE_ID, APP_6, true /* launchable */); 144 145 // app5 is installed by enterprise policy. 146 final UserHandle managedProfileUser = new UserHandle(MANAGED_PROFILE_ID); 147 when(mPackageManager.getInstallReason(APP_5, managedProfileUser)) 148 .thenReturn(PackageManager.INSTALL_REASON_POLICY); 149 when(mPackageManager.getInstallReason(APP_6, managedProfileUser)) 150 .thenReturn(PackageManager.INSTALL_REASON_UNKNOWN); 151 152 // List apps, considering apps installed by enterprise policy only. 153 mInstalledAppList = Collections.emptyList(); 154 final InstalledAppListerTestable counter = new InstalledAppListerTestable(); 155 counter.execute(); 156 // Wait for the background task to finish. 157 ShadowApplication.runBackgroundTasks(); 158 159 assertThat(mInstalledAppList.size()).isEqualTo(3); 160 161 assertThat(checkAppFound(mInstalledAppList, APP_1, MAIN_USER_ID)).isTrue(); 162 assertThat(checkAppFound(mInstalledAppList, APP_2, MAIN_USER_ID)).isFalse(); 163 assertThat(checkAppFound(mInstalledAppList, APP_3, MAIN_USER_ID)).isTrue(); 164 assertThat(checkAppFound(mInstalledAppList, APP_4, MAIN_USER_ID)).isFalse(); 165 assertThat(checkAppFound(mInstalledAppList, APP_5, MANAGED_PROFILE_ID)).isTrue(); 166 assertThat(checkAppFound(mInstalledAppList, APP_6, MANAGED_PROFILE_ID)).isFalse(); 167 168 // Verify that installed packages were retrieved for the current user and the user's 169 // managed profile. 170 verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(), eq(MAIN_USER_ID)); 171 verify(mPackageManager).getInstalledApplicationsAsUser(anyInt(), eq(MANAGED_PROFILE_ID)); 172 verify(mPackageManager, atLeast(0)) 173 .queryIntentActivitiesAsUser(anyObject(), anyInt(), anyInt()); 174 } 175 176 public static boolean checkAppFound(List<UserAppInfo> mInstalledAppList, String appId, 177 int userId) { 178 for (UserAppInfo info : mInstalledAppList) { 179 if (appId.equals(info.appInfo.packageName) && (info.userInfo.id == userId)) { 180 return true; 181 } 182 } 183 return false; 184 } 185 186 public static void verifyListUniqueness(List<UserAppInfo> list) { 187 assertThat((new HashSet<>(list)).size()).isEqualTo(list.size()); 188 } 189 190 private class InstalledAppListerTestable extends InstalledAppLister { 191 public InstalledAppListerTestable() { 192 super(mPackageManager, mUserManager); 193 } 194 195 @Override 196 protected void onAppListBuilt(List<UserAppInfo> list) { 197 mInstalledAppList = list; 198 } 199 } 200 201 private static ArgumentMatcher<Intent> isLaunchIntentFor(String packageName) { 202 return intent -> { 203 if (intent == null) { 204 return false; 205 } 206 if (!Intent.ACTION_MAIN.equals(intent.getAction())) { 207 return false; 208 } 209 final Set<String> categories = intent.getCategories(); 210 if (categories == null || categories.size() != 1 || 211 !categories.contains(Intent.CATEGORY_LAUNCHER)) { 212 return false; 213 } 214 if (!packageName.equals(intent.getPackage())) { 215 return false; 216 } 217 return true; 218 }; 219 } 220 } 221