1 /* 2 * Copyright (C) 2023 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.car.carlauncher; 18 19 import static android.car.settings.CarSettings.Secure.KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE; 20 import static android.car.settings.CarSettings.Secure.KEY_UNACCEPTED_TOS_DISABLED_APPS; 21 import static android.content.pm.ApplicationInfo.CATEGORY_AUDIO; 22 import static android.content.pm.ApplicationInfo.CATEGORY_VIDEO; 23 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; 24 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; 25 import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; 26 27 import static com.android.car.carlauncher.AppLauncherUtils.APP_TYPE_LAUNCHABLES; 28 import static com.android.car.carlauncher.AppLauncherUtils.APP_TYPE_MEDIA_SERVICES; 29 import static com.android.car.carlauncher.AppLauncherUtils.PACKAGES_DISABLED_ON_RESOURCE_OVERUSE_SEPARATOR; 30 import static com.android.car.carlauncher.AppLauncherUtils.TOS_DISABLED_APPS_SEPARATOR; 31 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 32 33 import static org.junit.Assert.assertEquals; 34 import static org.mockito.ArgumentMatchers.any; 35 import static org.mockito.ArgumentMatchers.anyInt; 36 import static org.mockito.ArgumentMatchers.argThat; 37 import static org.mockito.ArgumentMatchers.eq; 38 import static org.mockito.Mockito.mock; 39 import static org.mockito.Mockito.never; 40 import static org.mockito.Mockito.times; 41 import static org.mockito.Mockito.verify; 42 import static org.mockito.Mockito.when; 43 44 import android.app.ActivityManager; 45 import android.car.Car; 46 import android.car.content.pm.CarPackageManager; 47 import android.car.media.CarMediaManager; 48 import android.car.test.mocks.AbstractExtendedMockitoTestCase; 49 import android.content.ComponentName; 50 import android.content.ContentResolver; 51 import android.content.Context; 52 import android.content.Intent; 53 import android.content.pm.ActivityInfo; 54 import android.content.pm.ApplicationInfo; 55 import android.content.pm.LauncherActivityInfo; 56 import android.content.pm.LauncherApps; 57 import android.content.pm.PackageManager; 58 import android.content.pm.ResolveInfo; 59 import android.content.pm.ServiceInfo; 60 import android.content.res.Resources; 61 import android.os.Bundle; 62 import android.os.UserHandle; 63 import android.provider.Settings; 64 import android.service.media.MediaBrowserService; 65 import android.util.ArraySet; 66 67 import androidx.test.ext.junit.runners.AndroidJUnit4; 68 import androidx.test.filters.SmallTest; 69 70 import org.junit.After; 71 import org.junit.Before; 72 import org.junit.Test; 73 import org.junit.runner.RunWith; 74 import org.mockito.ArgumentCaptor; 75 import org.mockito.Mock; 76 import org.mockito.Mockito; 77 78 import java.util.ArrayList; 79 import java.util.Arrays; 80 import java.util.Collections; 81 import java.util.List; 82 import java.util.Set; 83 import java.util.function.Consumer; 84 import java.util.stream.Collectors; 85 86 @RunWith(AndroidJUnit4.class) 87 @SmallTest 88 public final class AppLauncherUtilsTest extends AbstractExtendedMockitoTestCase { 89 private static final String TEST_DISABLED_APP_1 = "com.android.car.test.disabled1"; 90 private static final String TEST_DISABLED_APP_2 = "com.android.car.test.disabled2"; 91 private static final String TEST_ENABLED_APP = "com.android.car.test.enabled"; 92 private static final String TEST_TOS_DISABLED_APP_1 = "com.android.car.test.tosdisabled1"; 93 private static final String TEST_TOS_DISABLED_APP_2 = "com.android.car.test.tosdisabled2"; 94 private static final String TEST_VIDEO_APP = "com.android.car.test.video"; 95 // Default media app 96 private static final String TEST_MEDIA_TEMPLATE_MBS = "com.android.car.test.mbs"; 97 // Video app that has a MBS defined but has its own launch activity 98 private static final String TEST_VIDEO_MBS = "com.android.car.test.video.mbs"; 99 // NDO App that has opted in its MBS to launch in car 100 private static final String TEST_NDO_MBS_LAUNCHABLE = "com.android.car.test.mbs.launchable"; 101 // NDO App that has opted out its MBS to launch in car 102 private static final String TEST_NDO_MBS_NOT_LAUNCHABLE = 103 "com.android.car.test.mbs.notlaunchable"; 104 105 private static final String CUSTOM_MEDIA_PACKAGE = "com.android.car.radio"; 106 private static final String CUSTOM_MEDIA_CLASS = "com.android.car.radio.service"; 107 private static final String CUSTOM_MEDIA_COMPONENT = CUSTOM_MEDIA_PACKAGE 108 + "/" + CUSTOM_MEDIA_CLASS; 109 private static final String TEST_MIRROR_APP_PKG = "com.android.car.test.mirroring"; 110 private static final String TOS_INTENT_NAME = "intent:#Intent;action=" 111 + "com.android.car.SHOW_USER_TOS_ACTIVITY;B.show_value_prop=true;" 112 + "S.mini_flow_extra=GTOS_GATED_FLOW;end"; 113 private static final String TOS_INTENT_VERIFY = "#Intent;action=" 114 + "com.android.car.SHOW_USER_TOS_ACTIVITY;B.show_value_prop=true;" 115 + "S.mini_flow_extra=GTOS_GATED_FLOW;end"; 116 117 118 @Mock private Context mMockContext; 119 @Mock private LauncherApps mMockLauncherApps; 120 @Mock private PackageManager mMockPackageManager; 121 @Mock private AppLauncherUtils.ShortcutsListener mMockShortcutsListener; 122 123 @Mock private Resources mResources; 124 125 @Mock private LauncherActivityInfo mRadioLauncherActivityInfo; 126 127 private CarMediaManager mCarMediaManager; 128 private CarPackageManager mCarPackageManager; 129 private Car mCar; 130 131 @Before setUp()132 public void setUp() throws Exception { 133 // Need for CarMediaManager to get the user from the context. 134 when(mMockContext.getUser()).thenReturn(UserHandle.of(ActivityManager.getCurrentUser())); 135 136 mCar = Car.createCar(mMockContext, /* handler = */ null, Car.CAR_WAIT_TIMEOUT_WAIT_FOREVER, 137 (car, ready) -> { 138 if (!ready) { 139 mCarPackageManager = null; 140 mCarMediaManager = null; 141 return; 142 } 143 mCarPackageManager = (CarPackageManager) car.getCarManager(Car.PACKAGE_SERVICE); 144 mCarPackageManager = Mockito.spy(mCarPackageManager); 145 mCarMediaManager = (CarMediaManager) car.getCarManager(Car.CAR_MEDIA_SERVICE); 146 when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); 147 }); 148 } 149 150 @After tearDown()151 public void tearDown() throws Exception { 152 if (mCar != null && mCar.isConnected()) { 153 mCar.disconnect(); 154 mCar = null; 155 } 156 } 157 158 @Override onSessionBuilder(CustomMockitoSessionBuilder session)159 protected void onSessionBuilder(CustomMockitoSessionBuilder session) { 160 session.spyStatic(Settings.Secure.class); 161 } 162 163 @Test testGetLauncherApps_MediaCenterAppSwitcher()164 public void testGetLauncherApps_MediaCenterAppSwitcher() { 165 mockSettingsStringCalls(); 166 mockPackageManagerQueries(); 167 168 when(mMockContext.getResources()).thenReturn(mResources); 169 when(mResources.getStringArray(eq( 170 com.android.car.media.common.R.array.custom_media_packages))) 171 .thenReturn(new String[]{CUSTOM_MEDIA_COMPONENT}); 172 173 // Setup custom media component 174 when(mMockLauncherApps.getActivityList(any(), any())) 175 .thenReturn(List.of(mRadioLauncherActivityInfo)); 176 when(mRadioLauncherActivityInfo.getComponentName()) 177 .thenReturn(new ComponentName(CUSTOM_MEDIA_PACKAGE, CUSTOM_MEDIA_CLASS)); 178 when(mRadioLauncherActivityInfo.getName()) 179 .thenReturn(CUSTOM_MEDIA_CLASS); 180 181 AppLauncherUtils.LauncherAppsInfo launcherAppsInfo = AppLauncherUtils.getLauncherApps( 182 mMockContext, /* appsToHide= */ new ArraySet<>(), 183 /* appTypes= */ APP_TYPE_MEDIA_SERVICES, 184 /* openMediaCenter= */ false, mMockLauncherApps, mCarPackageManager, 185 mMockPackageManager, mCarMediaManager, mMockShortcutsListener, 186 TEST_MIRROR_APP_PKG, /* mirroringAppRedirect= */ null); 187 188 List<AppMetaData> appMetaData = launcherAppsInfo.getLaunchableComponentsList(); 189 190 // Only media apps should be present 191 assertEquals(Set.of( 192 TEST_MEDIA_TEMPLATE_MBS, 193 TEST_NDO_MBS_LAUNCHABLE, 194 CUSTOM_MEDIA_PACKAGE), 195 appMetaData.stream() 196 .map(am -> am.getComponentName().getPackageName()) 197 .collect(Collectors.toSet())); 198 199 // This should include all MBS discovered 200 assertEquals(5, launcherAppsInfo.getMediaServices().size()); 201 202 mockPmGetApplicationEnabledSetting(COMPONENT_ENABLED_STATE_ENABLED, TEST_DISABLED_APP_1, 203 TEST_DISABLED_APP_2); 204 205 launchAllApps(appMetaData); 206 207 // Media apps should do only switching and not launch activity 208 verify(mMockContext, never()).startActivity(any(), any()); 209 } 210 211 @Test testGetLauncherApps_Launcher()212 public void testGetLauncherApps_Launcher() { 213 mockSettingsStringCalls(); 214 mockPackageManagerQueries(); 215 216 when(mMockContext.getResources()).thenReturn(mResources); 217 when(mResources.getStringArray(eq( 218 com.android.car.media.common.R.array.custom_media_packages))) 219 .thenReturn(new String[]{CUSTOM_MEDIA_COMPONENT}); 220 221 // Setup custom media component 222 when(mMockLauncherApps.getActivityList(any(), any())) 223 .thenReturn(List.of(mRadioLauncherActivityInfo)); 224 when(mRadioLauncherActivityInfo.getComponentName()) 225 .thenReturn(new ComponentName(CUSTOM_MEDIA_PACKAGE, CUSTOM_MEDIA_CLASS)); 226 when(mRadioLauncherActivityInfo.getName()) 227 .thenReturn(CUSTOM_MEDIA_CLASS); 228 229 AppLauncherUtils.LauncherAppsInfo launcherAppsInfo = AppLauncherUtils.getLauncherApps( 230 mMockContext, /* appsToHide= */ new ArraySet<>(), 231 /* appTypes= */ APP_TYPE_LAUNCHABLES + APP_TYPE_MEDIA_SERVICES, 232 /* openMediaCenter= */ true, mMockLauncherApps, mCarPackageManager, 233 mMockPackageManager, mCarMediaManager, mMockShortcutsListener, 234 TEST_MIRROR_APP_PKG, /* mirroringAppRedirect= */ null); 235 236 List<AppMetaData> appMetaData = launcherAppsInfo.getLaunchableComponentsList(); 237 // mMockLauncherApps is never stubbed, only services & disabled activities are expected. 238 239 assertEquals(Set.of( 240 TEST_MEDIA_TEMPLATE_MBS, 241 TEST_NDO_MBS_LAUNCHABLE, 242 CUSTOM_MEDIA_PACKAGE, 243 TEST_DISABLED_APP_1, 244 TEST_DISABLED_APP_2), 245 appMetaData.stream() 246 .map(am -> am.getComponentName().getPackageName()) 247 .collect(Collectors.toSet())); 248 249 250 // This should include all MBS discovered 251 assertEquals(5, launcherAppsInfo.getMediaServices().size()); 252 253 mockPmGetApplicationEnabledSetting(COMPONENT_ENABLED_STATE_ENABLED, TEST_DISABLED_APP_1, 254 TEST_DISABLED_APP_2); 255 256 launchAllApps(appMetaData); 257 258 verify(mMockPackageManager).setApplicationEnabledSetting( 259 eq(TEST_DISABLED_APP_1), eq(COMPONENT_ENABLED_STATE_ENABLED), eq(0)); 260 261 verify(mMockPackageManager).setApplicationEnabledSetting( 262 eq(TEST_DISABLED_APP_2), eq(COMPONENT_ENABLED_STATE_ENABLED), eq(0)); 263 264 verify(mMockContext, times(5)).startActivity(any(), any()); 265 266 verify(mMockPackageManager, never()).setApplicationEnabledSetting( 267 eq(TEST_ENABLED_APP), anyInt(), eq(0)); 268 } 269 270 271 @Test testGetLauncherAppsWithEnableAndTosDisabledApps()272 public void testGetLauncherAppsWithEnableAndTosDisabledApps() { 273 mockSettingsStringCalls(); 274 mockTosPackageManagerQueries(); 275 276 when(mMockContext.getResources()).thenReturn(mResources); 277 when(mResources.getStringArray(eq( 278 com.android.car.media.common.R.array.custom_media_packages))) 279 .thenReturn(new String[]{CUSTOM_MEDIA_COMPONENT}); 280 281 AppLauncherUtils.LauncherAppsInfo launcherAppsInfo = AppLauncherUtils.getLauncherApps( 282 mMockContext, /* appsToHide= */ new ArraySet<>(), 283 /* appTypes= */ APP_TYPE_LAUNCHABLES + APP_TYPE_MEDIA_SERVICES, 284 /* openMediaCenter= */ false, mMockLauncherApps, mCarPackageManager, 285 mMockPackageManager, mCarMediaManager, mMockShortcutsListener, 286 TEST_MIRROR_APP_PKG, /* mirroringAppRedirect= */ null); 287 288 List<AppMetaData> appMetaData = launcherAppsInfo.getLaunchableComponentsList(); 289 290 // mMockLauncherApps is never stubbed, only services & disabled activities are expected. 291 assertEquals(3, appMetaData.size()); 292 293 Resources resources = mock(Resources.class); 294 when(mMockContext.getResources()).thenReturn(resources); 295 when(resources.getString(anyInt())).thenReturn(TOS_INTENT_NAME); 296 297 launchAllApps(appMetaData); 298 299 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 300 verify(mMockContext, times(2)).startActivity(intentCaptor.capture(), any()); 301 302 String intentUri = intentCaptor.getAllValues().get(0).toUri(0); 303 assertEquals(TOS_INTENT_VERIFY, intentUri); 304 } 305 306 @Test testGetLauncherAppsWithEnableAndTosDisabledDistractionOptimizedApps()307 public void testGetLauncherAppsWithEnableAndTosDisabledDistractionOptimizedApps() { 308 mockSettingsStringCalls(); 309 mockTosPackageManagerQueries(); 310 311 when(mMockContext.getResources()).thenReturn(mResources); 312 when(mResources.getStringArray(eq( 313 com.android.car.media.common.R.array.custom_media_packages))) 314 .thenReturn(new String[]{CUSTOM_MEDIA_COMPONENT}); 315 316 doReturn(true) 317 .when(mCarPackageManager) 318 .isActivityDistractionOptimized(eq(TEST_TOS_DISABLED_APP_1), any()); 319 doReturn(true) 320 .when(mCarPackageManager) 321 .isActivityDistractionOptimized(eq(TEST_TOS_DISABLED_APP_2), any()); 322 323 AppLauncherUtils.LauncherAppsInfo launcherAppsInfo = AppLauncherUtils.getLauncherApps( 324 mMockContext, /* appsToHide= */ new ArraySet<>(), 325 /* appTypes= */ APP_TYPE_LAUNCHABLES + APP_TYPE_MEDIA_SERVICES, 326 /* openMediaCenter= */ false, mMockLauncherApps, mCarPackageManager, 327 mMockPackageManager, mCarMediaManager, mMockShortcutsListener, 328 TEST_MIRROR_APP_PKG, /* mirroringAppRedirect= */ null); 329 330 List<AppMetaData> appMetaData = launcherAppsInfo.getLaunchableComponentsList(); 331 332 // mMockLauncherApps is never stubbed, only services & disabled activities are expected. 333 assertEquals(3, appMetaData.size()); 334 335 Resources resources = mock(Resources.class); 336 when(mMockContext.getResources()).thenReturn(resources); 337 when(resources.getString(anyInt())).thenReturn(TOS_INTENT_NAME); 338 339 launchAllApps(appMetaData); 340 341 ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); 342 verify(mMockContext, times(2)).startActivity(intentCaptor.capture(), any()); 343 344 String intentUri = intentCaptor.getAllValues().get(0).toUri(0); 345 assertEquals(TOS_INTENT_VERIFY, intentUri); 346 } 347 mockPackageManagerQueries()348 private void mockPackageManagerQueries() { 349 // setup a media template app that uses media service 350 ApplicationInfo mbsAppInfo = new ApplicationInfo(); 351 mbsAppInfo.category = CATEGORY_AUDIO; 352 ResolveInfo mbs = constructServiceResolveInfo(TEST_MEDIA_TEMPLATE_MBS); 353 354 try { 355 Intent mbsIntent = new Intent(); 356 mbsIntent.setComponent(mbs.getComponentInfo().getComponentName()); 357 mbsIntent.setAction(MediaBrowserService.SERVICE_INTERFACE); 358 359 when(mMockPackageManager.getApplicationInfo(mbs.getComponentInfo().packageName, 0)) 360 .thenReturn(mbsAppInfo); 361 362 doReturn(Arrays.asList(mbs)).when(mMockPackageManager).queryIntentServices( 363 argThat((Intent i) -> i != null 364 && mbs.getComponentInfo().getComponentName().equals(i.getComponent())), 365 eq(PackageManager.GET_META_DATA)); 366 367 when(mMockPackageManager.getLaunchIntentForPackage(mbs.getComponentInfo().packageName)) 368 .thenReturn(null); 369 } catch (PackageManager.NameNotFoundException e) { 370 throw new RuntimeException(e); 371 } 372 373 // setup a NDO Video app that has MBS but also its own activity, MBS won't be surfaced 374 ApplicationInfo videoAppInfo = new ApplicationInfo(); 375 videoAppInfo.category = CATEGORY_VIDEO; 376 ResolveInfo videoApp = constructServiceResolveInfo(TEST_VIDEO_MBS); 377 try { 378 Intent videoMbsIntent = new Intent(); 379 videoMbsIntent.setComponent(videoApp.getComponentInfo().getComponentName()); 380 videoMbsIntent.setAction(MediaBrowserService.SERVICE_INTERFACE); 381 382 when(mMockPackageManager.getApplicationInfo(videoApp.getComponentInfo().packageName, 383 0)) 384 .thenReturn(videoAppInfo); 385 386 doReturn(Arrays.asList(videoApp)).when(mMockPackageManager).queryIntentServices( 387 argThat((Intent i) -> i != null 388 && videoApp.getComponentInfo().getComponentName() 389 .equals(i.getComponent())), 390 eq(PackageManager.GET_META_DATA)); 391 392 when(mMockPackageManager.getLaunchIntentForPackage( 393 videoApp.getComponentInfo().packageName)) 394 .thenReturn(new Intent()); 395 } catch (PackageManager.NameNotFoundException e) { 396 throw new RuntimeException(e); 397 } 398 399 // setup a NDO app that has MBS opted out of launch in car 400 ApplicationInfo notlaunchableMBSInfo = new ApplicationInfo(); 401 notlaunchableMBSInfo.category = CATEGORY_VIDEO; 402 ResolveInfo notlaunchableMBSApp = constructServiceResolveInfo(TEST_NDO_MBS_NOT_LAUNCHABLE); 403 404 try { 405 Intent notlaunachableMbsIntent = new Intent(); 406 notlaunachableMbsIntent.setComponent( 407 notlaunchableMBSApp.getComponentInfo().getComponentName()); 408 notlaunachableMbsIntent.setAction(MediaBrowserService.SERVICE_INTERFACE); 409 410 when(mMockPackageManager.getApplicationInfo( 411 notlaunchableMBSApp.getComponentInfo().packageName, 0)) 412 .thenReturn(notlaunchableMBSInfo); 413 414 415 notlaunchableMBSApp.serviceInfo.metaData = new Bundle(); 416 notlaunchableMBSApp.serviceInfo.metaData 417 .putBoolean("androidx.car.app.launchable", false); 418 419 doReturn(Arrays.asList(notlaunchableMBSApp)) 420 .when(mMockPackageManager).queryIntentServices( 421 argThat((Intent i) -> i != null 422 && notlaunchableMBSApp.getComponentInfo().getComponentName() 423 .equals(i.getComponent())), 424 eq(PackageManager.GET_META_DATA)); 425 426 when(mMockPackageManager.getLaunchIntentForPackage( 427 notlaunchableMBSApp.getComponentInfo().packageName)) 428 .thenReturn(new Intent()); 429 } catch (PackageManager.NameNotFoundException e) { 430 throw new RuntimeException(e); 431 } 432 433 434 // setup a NDO app that has MBS opted in to launch in car 435 ApplicationInfo launchableMBSInfo = new ApplicationInfo(); 436 launchableMBSInfo.category = CATEGORY_VIDEO; 437 ResolveInfo launchableMBSApp = constructServiceResolveInfo(TEST_NDO_MBS_LAUNCHABLE); 438 try { 439 Intent mbsIntent = new Intent(); 440 mbsIntent.setComponent(launchableMBSApp.getComponentInfo().getComponentName()); 441 mbsIntent.setAction(MediaBrowserService.SERVICE_INTERFACE); 442 443 when(mMockPackageManager.getApplicationInfo( 444 launchableMBSApp.getComponentInfo().packageName, 445 0)) 446 .thenReturn(launchableMBSInfo); 447 448 449 launchableMBSApp.serviceInfo.metaData = new Bundle(); 450 launchableMBSApp.serviceInfo.metaData.putBoolean("androidx.car.app.launchable", true); 451 452 doReturn(Arrays.asList(launchableMBSApp)).when(mMockPackageManager).queryIntentServices( 453 argThat((Intent i) -> i != null 454 && launchableMBSApp.getComponentInfo().getComponentName() 455 .equals(i.getComponent())), 456 eq(PackageManager.GET_META_DATA)); 457 458 when(mMockPackageManager.getLaunchIntentForPackage( 459 launchableMBSApp.getComponentInfo().packageName)) 460 .thenReturn(new Intent()); 461 } catch (PackageManager.NameNotFoundException e) { 462 throw new RuntimeException(e); 463 } 464 465 when(mMockPackageManager.queryIntentServices(any(), eq(PackageManager.GET_RESOLVED_FILTER))) 466 .thenAnswer(args -> { 467 Intent intent = args.getArgument(0); 468 if (intent.getAction().equals(MediaBrowserService.SERVICE_INTERFACE)) { 469 return Arrays.asList(mbs, videoApp, notlaunchableMBSApp, launchableMBSApp, 470 constructServiceResolveInfo(CUSTOM_MEDIA_PACKAGE)); 471 } 472 return new ArrayList<>(); 473 }); 474 475 // setup activities 476 when(mMockPackageManager.queryIntentActivities(any(), any())).thenAnswer(args -> { 477 Intent intent = args.getArgument(0); 478 PackageManager.ResolveInfoFlags flags = args.getArgument(1); 479 List<ResolveInfo> resolveInfoList = new ArrayList<>(); 480 if (intent.getAction().equals(Intent.ACTION_MAIN)) { 481 if ((flags.getValue() & MATCH_DISABLED_UNTIL_USED_COMPONENTS) != 0) { 482 resolveInfoList.add(constructActivityResolveInfo(TEST_DISABLED_APP_1)); 483 resolveInfoList.add(constructActivityResolveInfo(TEST_DISABLED_APP_2)); 484 } 485 // Keep custom media component in both MBS and Activity with Launch Intent 486 resolveInfoList.add(constructActivityResolveInfo(CUSTOM_MEDIA_PACKAGE)); 487 // Add apps which will have their own Launcher Activity 488 resolveInfoList.add(constructActivityResolveInfo(TEST_VIDEO_MBS)); 489 resolveInfoList.add(constructActivityResolveInfo(TEST_NDO_MBS_LAUNCHABLE)); 490 resolveInfoList.add(constructActivityResolveInfo(TEST_NDO_MBS_NOT_LAUNCHABLE)); 491 } 492 493 return resolveInfoList; 494 }); 495 } 496 mockTosPackageManagerQueries()497 private void mockTosPackageManagerQueries() { 498 ResolveInfo resolveInfo = constructServiceResolveInfo(TEST_ENABLED_APP); 499 try { 500 when(mMockPackageManager.getServiceInfo( 501 resolveInfo 502 .getComponentInfo().getComponentName(), 503 PackageManager.GET_META_DATA)) 504 .thenReturn(new ServiceInfo()); 505 } catch (PackageManager.NameNotFoundException e) { 506 throw new RuntimeException(e); 507 } 508 when(mMockPackageManager.queryIntentServices(any(), anyInt())).thenAnswer(args -> { 509 Intent intent = args.getArgument(0); 510 if (intent.getAction().equals(MediaBrowserService.SERVICE_INTERFACE)) { 511 return Collections.singletonList(resolveInfo); 512 } 513 return new ArrayList<>(); 514 }); 515 when(mMockPackageManager.queryIntentActivities(any(), any())).thenAnswer(args -> { 516 Intent intent = args.getArgument(0); 517 PackageManager.ResolveInfoFlags flags = args.getArgument(1); 518 List<ResolveInfo> resolveInfoList = new ArrayList<>(); 519 if (intent.getAction().equals(Intent.ACTION_MAIN)) { 520 if ((flags.getValue() & MATCH_DISABLED_COMPONENTS) != 0) { 521 resolveInfoList.add(constructActivityResolveInfo(TEST_TOS_DISABLED_APP_1)); 522 resolveInfoList.add(constructActivityResolveInfo(TEST_TOS_DISABLED_APP_2)); 523 } 524 resolveInfoList.add(constructActivityResolveInfo(TEST_ENABLED_APP)); 525 } 526 return resolveInfoList; 527 }); 528 } 529 mockPmGetApplicationEnabledSetting(int enabledState, String... packages)530 private void mockPmGetApplicationEnabledSetting(int enabledState, String... packages) { 531 for (String pkg : packages) { 532 when(mMockPackageManager.getApplicationEnabledSetting(pkg)).thenReturn(enabledState); 533 } 534 } 535 mockSettingsStringCalls()536 private void mockSettingsStringCalls() { 537 when(mMockContext.createContextAsUser(any(UserHandle.class), anyInt())) 538 .thenAnswer(args -> { 539 Context context = mock(Context.class); 540 ContentResolver contentResolver = mock(ContentResolver.class); 541 when(context.getContentResolver()).thenReturn(contentResolver); 542 return context; 543 }); 544 545 doReturn(TEST_DISABLED_APP_1 + PACKAGES_DISABLED_ON_RESOURCE_OVERUSE_SEPARATOR 546 + TEST_DISABLED_APP_2) 547 .when(() -> Settings.Secure.getString(any(ContentResolver.class), 548 eq(KEY_PACKAGES_DISABLED_ON_RESOURCE_OVERUSE))); 549 550 doReturn(TEST_TOS_DISABLED_APP_1 + TOS_DISABLED_APPS_SEPARATOR 551 + TEST_TOS_DISABLED_APP_2) 552 .when(() -> Settings.Secure.getString(any(ContentResolver.class), 553 eq(KEY_UNACCEPTED_TOS_DISABLED_APPS))); 554 } 555 launchAllApps(List<AppMetaData> appMetaData)556 private void launchAllApps(List<AppMetaData> appMetaData) { 557 for (AppMetaData meta : appMetaData) { 558 Consumer<Context> launchCallback = meta.getLaunchCallback(); 559 launchCallback.accept(mMockContext); 560 } 561 } 562 constructActivityResolveInfo(String packageName)563 private static ResolveInfo constructActivityResolveInfo(String packageName) { 564 ResolveInfo info = new ResolveInfo(); 565 info.activityInfo = new ActivityInfo(); 566 info.activityInfo.packageName = packageName; 567 info.activityInfo.name = packageName + ".activity"; 568 info.activityInfo.applicationInfo = new ApplicationInfo(); 569 return info; 570 } 571 constructServiceResolveInfo(String packageName)572 private static ResolveInfo constructServiceResolveInfo(String packageName) { 573 ResolveInfo info = new ResolveInfo(); 574 info.serviceInfo = new ServiceInfo(); 575 info.serviceInfo.packageName = packageName; 576 info.serviceInfo.name = packageName + ".service"; 577 info.serviceInfo.applicationInfo = new ApplicationInfo(); 578 return info; 579 } 580 } 581