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 18package com.android.settings.search; 19 20import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; 21import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; 22import static com.google.common.truth.Truth.assertThat; 23import static org.mockito.Matchers.any; 24import static org.mockito.Matchers.anyInt; 25import static org.mockito.Matchers.anyList; 26import static org.mockito.Matchers.anyString; 27import static org.mockito.Matchers.eq; 28import static org.mockito.Mockito.mock; 29import static org.mockito.Mockito.never; 30import static org.mockito.Mockito.spy; 31import static org.mockito.Mockito.verify; 32import static org.mockito.Mockito.when; 33 34import android.content.Context; 35import android.content.Intent; 36import android.content.pm.ActivityInfo; 37import android.content.pm.ResolveInfo; 38import android.content.pm.UserInfo; 39import android.os.UserHandle; 40import android.os.UserManager; 41 42import com.android.settings.R; 43import com.android.settings.TestConfig; 44import com.android.settings.applications.PackageManagerWrapper; 45import com.android.settings.dashboard.SiteMapManager; 46import com.android.settings.testutils.ApplicationTestUtils; 47import com.android.settings.testutils.FakeFeatureFactory; 48import com.android.settings.testutils.SettingsRobolectricTestRunner; 49 50import org.junit.Before; 51import org.junit.Test; 52import org.junit.runner.RunWith; 53import org.mockito.Answers; 54import org.mockito.Mock; 55import org.mockito.MockitoAnnotations; 56import org.mockito.invocation.InvocationOnMock; 57import org.mockito.stubbing.Answer; 58import org.robolectric.annotation.Config; 59 60import java.util.ArrayList; 61import java.util.Arrays; 62import java.util.HashSet; 63import java.util.List; 64import java.util.Set; 65import java.util.stream.Collectors; 66 67@RunWith(SettingsRobolectricTestRunner.class) 68@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) 69public class InstalledAppResultLoaderTest { 70 71 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 72 private Context mContext; 73 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 74 private PackageManagerWrapper mPackageManagerWrapper; 75 @Mock 76 private UserManager mUserManager; 77 @Mock 78 private SiteMapManager mSiteMapManager; 79 80 private InstalledAppResultLoader mLoader; 81 82 @Before 83 public void setUp() { 84 MockitoAnnotations.initMocks(this); 85 86 final FakeFeatureFactory factory = FakeFeatureFactory.setupForTest(mContext); 87 when(factory.searchFeatureProvider.getSiteMapManager()) 88 .thenReturn(mSiteMapManager); 89 final List<UserInfo> infos = new ArrayList<>(); 90 infos.add(new UserInfo(1, "user 1", 0)); 91 when(mUserManager.getProfiles(anyInt())).thenReturn(infos); 92 when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); 93 when(mContext.getString(R.string.applications_settings)) 94 .thenReturn("app"); 95 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 96 .thenReturn(Arrays.asList( 97 ApplicationTestUtils.buildInfo(0 /* uid */, "app1", FLAG_SYSTEM, 98 0 /* targetSdkVersion */), 99 ApplicationTestUtils.buildInfo(0 /* uid */, "app2", FLAG_SYSTEM, 100 0 /* targetSdkVersion */), 101 ApplicationTestUtils.buildInfo(0 /* uid */, "app3", FLAG_SYSTEM, 102 0 /* targetSdkVersion */), 103 ApplicationTestUtils.buildInfo(0 /* uid */, "app4", 0 /* flags */, 104 0 /* targetSdkVersion */), 105 ApplicationTestUtils.buildInfo(0 /* uid */, "app", 0 /* flags */, 106 0 /* targetSdkVersion */), 107 ApplicationTestUtils.buildInfo(0 /* uid */, "appBuffer", 0 /* flags */, 108 0 /* targetSdkVersion */))); 109 } 110 111 @Test 112 public void query_noMatchingQuery_shouldReturnEmptyResult() { 113 final String query = "abc"; 114 115 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 116 mSiteMapManager); 117 118 assertThat(mLoader.loadInBackground()).isEmpty(); 119 } 120 121 @Test 122 public void query_matchingQuery_shouldReturnNonSystemApps() { 123 final String query = "app"; 124 125 mLoader = spy(new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 126 mSiteMapManager)); 127 when(mLoader.getContext()).thenReturn(mContext); 128 when(mSiteMapManager.buildBreadCrumb(eq(mContext), anyString(), anyString())) 129 .thenReturn(Arrays.asList(new String[]{"123"})); 130 131 assertThat(mLoader.loadInBackground().size()).isEqualTo(3); 132 verify(mSiteMapManager) 133 .buildBreadCrumb(eq(mContext), anyString(), anyString()); 134 } 135 136 @Test 137 public void query_matchingQuery_shouldReturnSystemAppUpdates() { 138 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 139 .thenReturn(Arrays.asList( 140 ApplicationTestUtils.buildInfo(0 /* uid */, "app1", FLAG_UPDATED_SYSTEM_APP, 141 0 /* targetSdkVersion */))); 142 final String query = "app"; 143 144 mLoader = spy(new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 145 mSiteMapManager)); 146 when(mLoader.getContext()).thenReturn(mContext); 147 148 assertThat(mLoader.loadInBackground().size()).isEqualTo(1); 149 verify(mSiteMapManager) 150 .buildBreadCrumb(eq(mContext), anyString(), anyString()); 151 } 152 153 @Test 154 public void query_matchingQuery_shouldReturnSystemAppIfLaunchable() { 155 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 156 .thenReturn(Arrays.asList( 157 ApplicationTestUtils.buildInfo(0 /* uid */, "app1", FLAG_SYSTEM, 158 0 /* targetSdkVersion */))); 159 final List<ResolveInfo> list = mock(List.class); 160 when(list.size()).thenReturn(1); 161 when(mPackageManagerWrapper.queryIntentActivitiesAsUser( 162 any(Intent.class), anyInt(), anyInt())) 163 .thenReturn(list); 164 165 final String query = "app"; 166 167 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 168 mSiteMapManager); 169 170 assertThat(mLoader.loadInBackground().size()).isEqualTo(1); 171 } 172 173 @Test 174 public void query_matchingQuery_shouldReturnSystemAppIfHomeApp() { 175 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 176 .thenReturn(Arrays.asList( 177 ApplicationTestUtils.buildInfo(0 /* uid */, "app1", FLAG_SYSTEM, 178 0 /* targetSdkVersion */))); 179 when(mPackageManagerWrapper.queryIntentActivitiesAsUser( 180 any(Intent.class), anyInt(), anyInt())) 181 .thenReturn(null); 182 183 when(mPackageManagerWrapper.getHomeActivities(anyList())).thenAnswer(new Answer<Object>() { 184 @Override 185 public Object answer(InvocationOnMock invocation) throws Throwable { 186 final List<ResolveInfo> list = (List<ResolveInfo>) invocation.getArguments()[0]; 187 final ResolveInfo info = new ResolveInfo(); 188 info.activityInfo = new ActivityInfo(); 189 info.activityInfo.packageName = "app1"; 190 list.add(info); 191 return null; 192 } 193 }); 194 195 final String query = "app"; 196 197 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 198 mSiteMapManager); 199 200 assertThat(mLoader.loadInBackground().size()).isEqualTo(1); 201 } 202 203 @Test 204 public void query_matchingQuery_shouldNotReturnSystemAppIfNotLaunchable() { 205 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 206 .thenReturn(Arrays.asList( 207 ApplicationTestUtils.buildInfo(0 /* uid */, "app1", FLAG_SYSTEM, 208 0 /* targetSdkVersion */))); 209 when(mPackageManagerWrapper.queryIntentActivitiesAsUser( 210 any(Intent.class), anyInt(), anyInt())) 211 .thenReturn(null); 212 213 final String query = "app"; 214 215 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 216 mSiteMapManager); 217 218 assertThat(mLoader.loadInBackground()).isEmpty(); 219 verify(mSiteMapManager, never()) 220 .buildBreadCrumb(eq(mContext), anyString(), anyString()); 221 } 222 223 @Test 224 public void query_matchingQuery_multipleResults() { 225 final String query = "app"; 226 227 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 228 mSiteMapManager); 229 final Set<? extends SearchResult> results = mLoader.loadInBackground(); 230 231 Set<CharSequence> expectedTitles = new HashSet<>(Arrays.asList("app4", "app", "appBuffer")); 232 Set<CharSequence> actualTitles = new HashSet<>(); 233 for (SearchResult result : results) { 234 actualTitles.add(result.title); 235 } 236 assertThat(actualTitles).isEqualTo(expectedTitles); 237 } 238 239 @Test 240 public void query_normalWord_MatchPrefix() { 241 final String query = "ba"; 242 final String packageName = "Bananas"; 243 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 244 .thenReturn(Arrays.asList( 245 ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */, 246 0 /* targetSdkVersion */))); 247 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 248 mSiteMapManager); 249 250 assertThat(mLoader.loadInBackground().size()).isEqualTo(1); 251 } 252 253 @Test 254 public void query_CapitalCase_DoestMatchSecondWord() { 255 final String query = "Apples"; 256 final String packageName = "BananasApples"; 257 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 258 .thenReturn(Arrays.asList( 259 ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */, 260 0 /* targetSdkVersion */))); 261 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 262 mSiteMapManager); 263 264 assertThat(mLoader.loadInBackground().size()).isEqualTo(0); 265 } 266 267 @Test 268 public void query_TwoWords_MatchesFirstWord() { 269 final String query = "Banana"; 270 final String packageName = "Bananas Apples"; 271 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 272 .thenReturn(Arrays.asList( 273 ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */, 274 0 /* targetSdkVersion */))); 275 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 276 mSiteMapManager); 277 278 assertThat(mLoader.loadInBackground().size()).isEqualTo(1); 279 } 280 281 @Test 282 public void query_TwoWords_MatchesSecondWord() { 283 final String query = "Apple"; 284 final String packageName = "Bananas Apples"; 285 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 286 .thenReturn(Arrays.asList( 287 ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */, 288 0 /* targetSdkVersion */))); 289 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 290 mSiteMapManager); 291 292 assertThat(mLoader.loadInBackground().size()).isEqualTo(1); 293 } 294 295 @Test 296 public void query_ThreeWords_MatchesThirdWord() { 297 final String query = "Pear"; 298 final String packageName = "Bananas Apples Pears"; 299 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 300 .thenReturn(Arrays.asList( 301 ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */, 302 0 /* targetSdkVersion */))); 303 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 304 mSiteMapManager); 305 306 assertThat(mLoader.loadInBackground().size()).isEqualTo(1); 307 } 308 309 @Test 310 public void query_DoubleSpacedWords_MatchesSecondWord() { 311 final String query = "Apple"; 312 final String packageName = "Bananas Apples"; 313 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 314 .thenReturn(Arrays.asList( 315 ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */, 316 0 /* targetSdkVersion */))); 317 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 318 mSiteMapManager); 319 320 assertThat(mLoader.loadInBackground().size()).isEqualTo(1); 321 } 322 323 @Test 324 public void query_SpecialChar_MatchesSecondWord() { 325 final String query = "Apple"; 326 final String packageName = "Bananas & Apples"; 327 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 328 .thenReturn(Arrays.asList( 329 ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */, 330 0 /* targetSdkVersion */))); 331 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 332 mSiteMapManager); 333 334 assertThat(mLoader.loadInBackground().size()).isEqualTo(1); 335 } 336 337 @Test 338 public void query_TabSeparated_MatchesSecondWord() { 339 final String query = "Apple"; 340 final String packageName = "Bananas\tApples"; 341 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 342 .thenReturn(Arrays.asList( 343 ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */, 344 0 /* targetSdkVersion */))); 345 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 346 mSiteMapManager); 347 348 assertThat(mLoader.loadInBackground().size()).isEqualTo(1); 349 } 350 351 @Test 352 public void query_LeadingNumber_MatchesWord() { 353 final String query = "4"; 354 final String packageName = "4Bananas"; 355 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 356 .thenReturn(Arrays.asList( 357 ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */, 358 0 /* targetSdkVersion */))); 359 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 360 mSiteMapManager); 361 362 assertThat(mLoader.loadInBackground().size()).isEqualTo(1); 363 } 364 365 @Test 366 public void query_FirstWordPrefixOfQuery_NoMatch() { 367 final String query = "Bananass"; 368 final String packageName = "Bananas Apples"; 369 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 370 .thenReturn(Arrays.asList( 371 ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */, 372 0 /* targetSdkVersion */))); 373 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 374 mSiteMapManager); 375 376 assertThat(mLoader.loadInBackground().size()).isEqualTo(0); 377 } 378 379 @Test 380 public void query_QueryLongerThanAppName_NoMatch() { 381 final String query = "BananasApples"; 382 final String packageName = "Bananas"; 383 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), anyInt())) 384 .thenReturn(Arrays.asList( 385 ApplicationTestUtils.buildInfo(0 /* uid */, packageName, 0 /* flags */, 386 0 /* targetSdkVersion */))); 387 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 388 mSiteMapManager); 389 390 assertThat(mLoader.loadInBackground().size()).isEqualTo(0); 391 } 392 393 @Test 394 public void query_appExistsInBothProfiles() { 395 final String query = "carrot"; 396 final String packageName = "carrot"; 397 final int user1 = 0; 398 final int user2 = 10; 399 final int uid = 67672; 400 List<UserInfo> infos = new ArrayList<>(); 401 infos.add(new UserInfo(user1, "user 1", 0)); 402 infos.add(new UserInfo(user2, "user 2", UserInfo.FLAG_MANAGED_PROFILE)); 403 404 when(mUserManager.getProfiles(anyInt())).thenReturn(infos); 405 406 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), eq(user1))) 407 .thenReturn(Arrays.asList( 408 ApplicationTestUtils.buildInfo(UserHandle.getUid(user1, uid) /* uid */, 409 packageName, 0 /* flags */, 410 0 /* targetSdkVersion */))); 411 when(mPackageManagerWrapper.getInstalledApplicationsAsUser(anyInt(), eq(user2))) 412 .thenReturn(Arrays.asList( 413 ApplicationTestUtils.buildInfo(UserHandle.getUid(user2, uid) /* uid */, 414 packageName, 0 /* flags */, 415 0 /* targetSdkVersion */))); 416 417 mLoader = new InstalledAppResultLoader(mContext, mPackageManagerWrapper, query, 418 mSiteMapManager); 419 420 Set<AppSearchResult> searchResults = (Set<AppSearchResult>) mLoader.loadInBackground(); 421 assertThat(searchResults).hasSize(2); 422 423 Set<Integer> uidResults = searchResults.stream().map(result -> result.info.uid).collect( 424 Collectors.toSet()); 425 assertThat(uidResults).containsExactly( 426 UserHandle.getUid(user1, uid), 427 UserHandle.getUid(user2, uid)); 428 } 429} 430