1 /* 2 * Copyright (C) 2020 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.media; 18 19 import static android.car.CarOccupantZoneManager.INVALID_USER_ID; 20 import static android.car.CarOccupantZoneManager.OccupantZoneInfo.INVALID_ZONE_ID; 21 import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_BROWSE; 22 import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_PLAYBACK; 23 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_INVISIBLE; 24 import static android.car.user.CarUserManager.USER_LIFECYCLE_EVENT_TYPE_VISIBLE; 25 26 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 27 import static com.android.internal.util.Preconditions.checkState; 28 29 import static com.google.common.truth.Truth.assertThat; 30 31 import static org.mockito.ArgumentMatchers.any; 32 import static org.mockito.ArgumentMatchers.anyInt; 33 import static org.mockito.ArgumentMatchers.anyLong; 34 import static org.mockito.ArgumentMatchers.anyString; 35 import static org.mockito.ArgumentMatchers.eq; 36 import static org.mockito.ArgumentMatchers.notNull; 37 import static org.mockito.Mockito.doAnswer; 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.verifyZeroInteractions; 43 import static org.mockito.Mockito.when; 44 45 import android.app.ActivityManager; 46 import android.app.usage.UsageStatsManager; 47 import android.car.Car; 48 import android.car.media.ICarMediaSourceListener; 49 import android.car.test.mocks.AbstractExtendedMockitoTestCase; 50 import android.car.test.mocks.AndroidMockitoHelper; 51 import android.car.user.CarUserManager.UserLifecycleEvent; 52 import android.car.user.CarUserManager.UserLifecycleListener; 53 import android.content.ComponentName; 54 import android.content.Context; 55 import android.content.SharedPreferences; 56 import android.content.pm.PackageManager; 57 import android.content.pm.ResolveInfo; 58 import android.content.pm.ServiceInfo; 59 import android.content.res.Resources; 60 import android.media.session.MediaController; 61 import android.media.session.MediaController.TransportControls; 62 import android.media.session.MediaSession; 63 import android.media.session.MediaSessionManager; 64 import android.media.session.PlaybackState; 65 import android.os.Binder; 66 import android.os.Bundle; 67 import android.os.IBinder; 68 import android.os.UserHandle; 69 import android.os.UserManager; 70 import android.view.KeyEvent; 71 72 import com.android.car.CarInputService; 73 import com.android.car.CarInputService.KeyEventListener; 74 import com.android.car.CarLocalServices; 75 import com.android.car.CarLog; 76 import com.android.car.CarMediaService; 77 import com.android.car.CarOccupantZoneService; 78 import com.android.car.R; 79 import com.android.car.power.CarPowerManagementService; 80 import com.android.car.user.CarUserService; 81 import com.android.car.user.UserHandleHelper; 82 83 import org.junit.After; 84 import org.junit.Before; 85 import org.junit.Test; 86 import org.mockito.ArgumentCaptor; 87 import org.mockito.Mock; 88 89 import java.util.ArrayList; 90 import java.util.List; 91 92 public final class CarMediaServiceTest extends AbstractExtendedMockitoTestCase { 93 94 private static final String MEDIA_PACKAGE = "test.package"; 95 private static final String MEDIA_PACKAGE2 = "test.package2"; 96 private static final String MEDIA_CLASS = "test_class"; 97 private static final String MEDIA_CLASS2 = "test_class2"; 98 99 private static final int TEST_USER_ID = 100; 100 private static final int ANOTHER_TEST_USER_ID = 333; 101 private static final int DISPLAY_TYPE_IGNORED = 314; 102 private static final int SEAT_NUMBER = 23; 103 private static final int OCCUPANT_ZONE_ID = 41; 104 private static final KeyEvent MEDIA_KEY_EVENT = 105 new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MEDIA_PLAY); 106 107 private static final ComponentName MEDIA_COMPONENT = 108 new ComponentName(MEDIA_PACKAGE, MEDIA_CLASS); 109 private static final ComponentName MEDIA_COMPONENT2 = 110 new ComponentName(MEDIA_PACKAGE2, MEDIA_CLASS2); 111 112 @Mock private Context mContext; 113 @Mock private Resources mResources; 114 @Mock private CarInputService mMockInputService; 115 @Mock private CarOccupantZoneService mMockOccupantZoneService; 116 @Mock private CarUserService mUserService; 117 @Mock private UserManager mUserManager; 118 @Mock private PackageManager mPackageManager; 119 @Mock private MediaSessionManager mMediaSessionManager; 120 @Mock private CarPowerManagementService mMockCarPowerManagementService; 121 @Mock private UserHandleHelper mUserHandleHelper; 122 @Mock private SharedPreferences mMockSharedPreferences; 123 @Mock private SharedPreferences.Editor mMockSharedPreferencesEditor; 124 @Mock private UsageStatsManager mMockUsageStatsManager; 125 126 private CarMediaService mCarMediaService; 127 128 private KeyEventListener mKeyEventListener; 129 private UserLifecycleListener mUserLifecycleListener; 130 CarMediaServiceTest()131 public CarMediaServiceTest() { 132 super(CarLog.TAG_MEDIA); 133 } 134 135 @Override onSessionBuilder(CustomMockitoSessionBuilder builder)136 protected void onSessionBuilder(CustomMockitoSessionBuilder builder) { 137 builder.spyStatic(ActivityManager.class).spyStatic(Binder.class); 138 } 139 140 @Before setUp()141 public void setUp() { 142 when(mContext.checkCallingOrSelfPermission(anyString())) 143 .thenReturn(PackageManager.PERMISSION_GRANTED); 144 when(mContext.getPackageManager()).thenReturn(mPackageManager); 145 when(mContext.createContextAsUser(any(), anyInt())).thenReturn(mContext); 146 when(mContext.getSharedPreferences(anyString(), anyInt())) 147 .thenReturn(mMockSharedPreferences); 148 when(mMockSharedPreferences.getString(anyString(), anyString())).thenReturn( 149 MEDIA_COMPONENT.flattenToString() + "," + MEDIA_COMPONENT2.flattenToString()); 150 when(mMockSharedPreferences.edit()).thenReturn(mMockSharedPreferencesEditor); 151 when(mMockSharedPreferencesEditor.putInt(anyString(), anyInt())) 152 .thenReturn(mMockSharedPreferencesEditor); 153 when(mMockSharedPreferencesEditor.putLong(anyString(), anyLong())) 154 .thenReturn(mMockSharedPreferencesEditor); 155 when(mMockSharedPreferencesEditor.putString(anyString(), anyString())) 156 .thenReturn(mMockSharedPreferencesEditor); 157 when(mMockOccupantZoneService.getOccupantZoneIdForSeat(SEAT_NUMBER)) 158 .thenReturn(OCCUPANT_ZONE_ID); 159 when(mMockOccupantZoneService.getUserForOccupant(OCCUPANT_ZONE_ID)) 160 .thenReturn(TEST_USER_ID); 161 162 doReturn(mResources).when(mContext).getResources(); 163 doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); 164 AndroidMockitoHelper.mockAmGetCurrentUser(TEST_USER_ID); 165 mockGetCallingUserHandle(TEST_USER_ID); 166 when(mUserHandleHelper.isEphemeralUser(UserHandle.of(TEST_USER_ID))).thenReturn(false); 167 doReturn(mMediaSessionManager).when(mContext).getSystemService(MediaSessionManager.class); 168 doReturn(mMockUsageStatsManager).when(mContext).getSystemService(UsageStatsManager.class); 169 mCarMediaService = new CarMediaService(mContext, mMockOccupantZoneService, mUserService, 170 mUserHandleHelper); 171 CarLocalServices.removeServiceForTest(CarPowerManagementService.class); 172 CarLocalServices.addService(CarPowerManagementService.class, 173 mMockCarPowerManagementService); 174 CarLocalServices.removeServiceForTest(CarInputService.class); 175 CarLocalServices.addService(CarInputService.class, mMockInputService); 176 mockUserLifecycleEvents(); 177 } 178 179 @After tearDown()180 public void tearDown() { 181 CarLocalServices.removeServiceForTest(CarPowerManagementService.class); 182 CarLocalServices.removeServiceForTest(CarInputService.class); 183 } 184 185 @Test testSetMediaSource_ModePlaybackIndependent()186 public void testSetMediaSource_ModePlaybackIndependent() { 187 mCarMediaService.setIndependentPlaybackConfig(true); 188 initMediaService(); 189 190 mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK); 191 192 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 193 .isEqualTo(MEDIA_COMPONENT); 194 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE)) 195 .isNotEqualTo(MEDIA_COMPONENT); 196 } 197 198 @Test testSetMediaSource_ModeBrowseIndependent()199 public void testSetMediaSource_ModeBrowseIndependent() { 200 mCarMediaService.setIndependentPlaybackConfig(true); 201 initMediaService(); 202 203 mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE); 204 205 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE)) 206 .isEqualTo(MEDIA_COMPONENT); 207 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 208 .isNotEqualTo(MEDIA_COMPONENT); 209 } 210 211 @Test testSetMediaSource_ModePlaybackAndBrowseIndependent()212 public void testSetMediaSource_ModePlaybackAndBrowseIndependent() { 213 mCarMediaService.setIndependentPlaybackConfig(true); 214 initMediaService(); 215 216 mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE); 217 mCarMediaService.setMediaSource(MEDIA_COMPONENT2, MEDIA_SOURCE_MODE_PLAYBACK); 218 219 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE)) 220 .isEqualTo(MEDIA_COMPONENT); 221 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 222 .isEqualTo(MEDIA_COMPONENT2); 223 } 224 225 @Test testSetMediaSource_Dependent()226 public void testSetMediaSource_Dependent() { 227 mCarMediaService.setIndependentPlaybackConfig(false); 228 initMediaService(); 229 230 mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK); 231 232 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE)) 233 .isEqualTo(MEDIA_COMPONENT); 234 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 235 .isEqualTo(MEDIA_COMPONENT); 236 237 mCarMediaService.setMediaSource(MEDIA_COMPONENT2, MEDIA_SOURCE_MODE_BROWSE); 238 239 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE)) 240 .isEqualTo(MEDIA_COMPONENT2); 241 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 242 .isEqualTo(MEDIA_COMPONENT2); 243 } 244 245 @Test testSetMediaSource_settingPlaybackSourcePausesAndStopsPreviousMedia()246 public void testSetMediaSource_settingPlaybackSourcePausesAndStopsPreviousMedia() { 247 MediaController mockController = mock(MediaController.class); 248 TransportControls mockTransportControls = mock(TransportControls.class); 249 when(mockController.getTransportControls()).thenReturn(mockTransportControls); 250 when(mockController.getPackageName()).thenReturn(MEDIA_PACKAGE); 251 when(mockController.getPlaybackState()).thenReturn( 252 createPlaybackState(PlaybackState.STATE_PLAYING, PlaybackState.ACTION_PAUSE)); 253 when(mMediaSessionManager.getActiveSessionsForUser(any(), eq(UserHandle.of(TEST_USER_ID)))) 254 .thenReturn(List.of(mockController)); 255 initMediaService(); 256 257 // Set the playback media source to MEDIA_COMPONENT, and then to MEDIA_COMPONENT2 258 mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK); 259 mCarMediaService.setMediaSource(MEDIA_COMPONENT2, MEDIA_SOURCE_MODE_PLAYBACK); 260 261 verify(mockController).unregisterCallback(any()); 262 verify(mockTransportControls).pause(); 263 verify(mockTransportControls).stop(); 264 } 265 266 @Test testSetMediaSource_multiUsers()267 public void testSetMediaSource_multiUsers() { 268 // Set a media source for one user. 269 mockGetCallingUserHandle(TEST_USER_ID); 270 initMediaService(); 271 mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK); 272 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 273 .isEqualTo(MEDIA_COMPONENT); 274 275 // Set a different media source for another user. 276 mockGetCallingUserHandle(ANOTHER_TEST_USER_ID); 277 sendUserLifecycleEvent(new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_VISIBLE, 278 ANOTHER_TEST_USER_ID)); 279 mCarMediaService.setMediaSource(MEDIA_COMPONENT2, MEDIA_SOURCE_MODE_PLAYBACK); 280 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 281 .isEqualTo(MEDIA_COMPONENT2); 282 283 // Setting a media source for a user should not affect other users. 284 mockGetCallingUserHandle(TEST_USER_ID); 285 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 286 .isEqualTo(MEDIA_COMPONENT); 287 } 288 289 @Test testDefaultMediaSource_currentUserInitialized()290 public void testDefaultMediaSource_currentUserInitialized() { 291 mockGetCallingUserHandle(TEST_USER_ID); 292 initMediaService(MEDIA_CLASS); 293 294 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE)) 295 .isEqualTo(MEDIA_COMPONENT); 296 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 297 .isEqualTo(MEDIA_COMPONENT); 298 } 299 300 @Test testDefaultMediaSource_backgroundUserUninitialized()301 public void testDefaultMediaSource_backgroundUserUninitialized() { 302 mockGetCallingUserHandle(TEST_USER_ID); 303 initMediaService(MEDIA_CLASS); 304 305 mockGetCallingUserHandle(ANOTHER_TEST_USER_ID); 306 307 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE)).isNull(); 308 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)).isNull(); 309 } 310 311 @Test testDefaultMediaSource_backgroundUserInitialized()312 public void testDefaultMediaSource_backgroundUserInitialized() { 313 mockGetCallingUserHandle(TEST_USER_ID); 314 initMediaService(MEDIA_CLASS); 315 316 mockGetCallingUserHandle(ANOTHER_TEST_USER_ID); 317 sendUserLifecycleEvent(new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_VISIBLE, 318 ANOTHER_TEST_USER_ID)); 319 320 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE)) 321 .isEqualTo(MEDIA_COMPONENT); 322 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 323 .isEqualTo(MEDIA_COMPONENT); 324 } 325 326 @Test testDefaultMediaSource_userDataRemoved()327 public void testDefaultMediaSource_userDataRemoved() { 328 mockGetCallingUserHandle(TEST_USER_ID); 329 initMediaService(MEDIA_CLASS); 330 331 // Set a different media source for another user. 332 mockGetCallingUserHandle(ANOTHER_TEST_USER_ID); 333 sendUserLifecycleEvent(new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_VISIBLE, 334 ANOTHER_TEST_USER_ID)); 335 mCarMediaService.setMediaSource(MEDIA_COMPONENT2, MEDIA_SOURCE_MODE_PLAYBACK); 336 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 337 .isEqualTo(MEDIA_COMPONENT2); 338 339 // Background user becomes invisible. 340 sendUserLifecycleEvent(new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_INVISIBLE, 341 ANOTHER_TEST_USER_ID)); 342 343 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE)).isNull(); 344 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)).isNull(); 345 } 346 347 @Test testMediaSourceListener_Independent()348 public void testMediaSourceListener_Independent() throws Exception { 349 mCarMediaService.setIndependentPlaybackConfig(true); 350 initMediaService(); 351 ICarMediaSourceListener listenerPlayback = mockMediaSourceListener(); 352 ICarMediaSourceListener listenerBrowse = mockMediaSourceListener(); 353 354 mCarMediaService.registerMediaSourceListener(listenerPlayback, MEDIA_SOURCE_MODE_PLAYBACK); 355 mCarMediaService.registerMediaSourceListener(listenerBrowse, MEDIA_SOURCE_MODE_BROWSE); 356 mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK); 357 358 verify(listenerPlayback).onMediaSourceChanged(MEDIA_COMPONENT); 359 verify(listenerBrowse, never()).onMediaSourceChanged(any()); 360 } 361 362 @Test testMediaSourceListener_IndependentBrowse()363 public void testMediaSourceListener_IndependentBrowse() throws Exception { 364 mCarMediaService.setIndependentPlaybackConfig(true); 365 initMediaService(); 366 ICarMediaSourceListener listenerPlayback = mockMediaSourceListener(); 367 ICarMediaSourceListener listenerBrowse = mockMediaSourceListener(); 368 369 mCarMediaService.registerMediaSourceListener(listenerPlayback, MEDIA_SOURCE_MODE_PLAYBACK); 370 mCarMediaService.registerMediaSourceListener(listenerBrowse, MEDIA_SOURCE_MODE_BROWSE); 371 mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE); 372 373 verify(listenerBrowse).onMediaSourceChanged(MEDIA_COMPONENT); 374 verify(listenerPlayback, never()).onMediaSourceChanged(any()); 375 } 376 377 @Test testMediaSourceListener_Dependent()378 public void testMediaSourceListener_Dependent() throws Exception { 379 mCarMediaService.setIndependentPlaybackConfig(false); 380 initMediaService(); 381 ICarMediaSourceListener listenerPlayback = mockMediaSourceListener(); 382 ICarMediaSourceListener listenerBrowse = mockMediaSourceListener(); 383 384 mCarMediaService.registerMediaSourceListener(listenerPlayback, MEDIA_SOURCE_MODE_PLAYBACK); 385 mCarMediaService.registerMediaSourceListener(listenerBrowse, MEDIA_SOURCE_MODE_BROWSE); 386 mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK); 387 388 verify(listenerPlayback).onMediaSourceChanged(MEDIA_COMPONENT); 389 verify(listenerBrowse).onMediaSourceChanged(MEDIA_COMPONENT); 390 391 mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE); 392 393 verify(listenerPlayback).onMediaSourceChanged(MEDIA_COMPONENT); 394 verify(listenerBrowse).onMediaSourceChanged(MEDIA_COMPONENT); 395 } 396 397 @Test testMediaSourceListener_Unregister()398 public void testMediaSourceListener_Unregister() throws Exception { 399 initMediaService(); 400 ICarMediaSourceListener listener = mockMediaSourceListener(); 401 402 mCarMediaService.registerMediaSourceListener(listener, MEDIA_SOURCE_MODE_PLAYBACK); 403 mCarMediaService.unregisterMediaSourceListener(listener, MEDIA_SOURCE_MODE_PLAYBACK); 404 mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK); 405 406 verify(listener, never()).onMediaSourceChanged(MEDIA_COMPONENT); 407 } 408 409 @Test testMediaSourceListener_multiUsers()410 public void testMediaSourceListener_multiUsers() throws Exception { 411 mockGetCallingUserHandle(TEST_USER_ID); 412 initMediaService(); 413 ICarMediaSourceListener user1Listener = mockMediaSourceListener(); 414 mCarMediaService.registerMediaSourceListener(user1Listener, MEDIA_SOURCE_MODE_PLAYBACK); 415 416 mockGetCallingUserHandle(ANOTHER_TEST_USER_ID); 417 sendUserLifecycleEvent(new UserLifecycleEvent(USER_LIFECYCLE_EVENT_TYPE_VISIBLE, 418 ANOTHER_TEST_USER_ID)); 419 ICarMediaSourceListener user2Listener = mockMediaSourceListener(); 420 mCarMediaService.registerMediaSourceListener(user2Listener, MEDIA_SOURCE_MODE_PLAYBACK); 421 422 // Set a media source for user2. Only the user2 callback is invoked. 423 mCarMediaService.setMediaSource(MEDIA_COMPONENT2, MEDIA_SOURCE_MODE_PLAYBACK); 424 verify(user1Listener, never()).onMediaSourceChanged(any()); 425 verify(user2Listener).onMediaSourceChanged(MEDIA_COMPONENT2); 426 427 // Set a media source for user1. Only the user1 callback is invoked. 428 mockGetCallingUserHandle(TEST_USER_ID); 429 mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK); 430 verify(user1Listener).onMediaSourceChanged(MEDIA_COMPONENT); 431 verify(user2Listener).onMediaSourceChanged(MEDIA_COMPONENT2); 432 } 433 434 @Test testGetLastMediaSources()435 public void testGetLastMediaSources() { 436 initMediaService(); 437 438 assertThat(mCarMediaService.getLastMediaSources(MEDIA_SOURCE_MODE_PLAYBACK)) 439 .containsExactly(MEDIA_COMPONENT, MEDIA_COMPONENT2); 440 } 441 442 @Test testIsIndependentPlaybackConfig_true()443 public void testIsIndependentPlaybackConfig_true() { 444 mCarMediaService.setIndependentPlaybackConfig(true); 445 446 assertThat(mCarMediaService.isIndependentPlaybackConfig()).isTrue(); 447 } 448 449 @Test testIsIndependentPlaybackConfig_false()450 public void testIsIndependentPlaybackConfig_false() { 451 mCarMediaService.setIndependentPlaybackConfig(false); 452 453 assertThat(mCarMediaService.isIndependentPlaybackConfig()).isFalse(); 454 } 455 456 @Test testIsIndependentPlaybackConfig_multiUsers()457 public void testIsIndependentPlaybackConfig_multiUsers() { 458 // Set a value for one user. 459 mockGetCallingUserHandle(TEST_USER_ID); 460 mCarMediaService.setIndependentPlaybackConfig(false); 461 assertThat(mCarMediaService.isIndependentPlaybackConfig()).isFalse(); 462 463 // Set a different value for another user. 464 mockGetCallingUserHandle(ANOTHER_TEST_USER_ID); 465 mCarMediaService.setIndependentPlaybackConfig(true); 466 assertThat(mCarMediaService.isIndependentPlaybackConfig()).isTrue(); 467 468 // Setting a value for a user should not affect other users. 469 mockGetCallingUserHandle(TEST_USER_ID); 470 assertThat(mCarMediaService.isIndependentPlaybackConfig()).isFalse(); 471 } 472 473 @Test testDefaultMediaSource()474 public void testDefaultMediaSource() { 475 initMediaService(MEDIA_CLASS); 476 477 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 478 .isEqualTo(MEDIA_COMPONENT); 479 } 480 481 @Test testUnresolvedMediaPackage()482 public void testUnresolvedMediaPackage() { 483 initializeMockPackageManager(); 484 485 assertThat(mCarMediaService.isMediaService(MEDIA_COMPONENT, TEST_USER_ID)).isFalse(); 486 } 487 488 /** 489 * Tests that PlaybackState changing to PlaybackState#isActive 490 * will result the media source changing 491 */ 492 @Test testActiveSessionListener_StateActiveChangesSource()493 public void testActiveSessionListener_StateActiveChangesSource() { 494 mockPlaybackStateChange( 495 createPlaybackState(PlaybackState.STATE_BUFFERING, /* actions= */ 0)); 496 497 initMediaService(MEDIA_CLASS, MEDIA_CLASS2); 498 499 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 500 .isEqualTo(MEDIA_COMPONENT2); 501 verify(mContext, times(2)).startForegroundService(any()); 502 } 503 504 // Tests that PlaybackState changing to STATE_PLAYING will result the media source changing 505 @Test testActiveSessionListener_StatePlayingChangesSource()506 public void testActiveSessionListener_StatePlayingChangesSource() { 507 mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING, /* actions= */ 0)); 508 509 initMediaService(MEDIA_CLASS, MEDIA_CLASS2); 510 511 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 512 .isEqualTo(MEDIA_COMPONENT2); 513 verify(mContext, times(2)).startForegroundService(any()); 514 } 515 516 @Test testActiveSessionListener_StatePlayingNonMediaAppDoesntChangesSource()517 public void testActiveSessionListener_StatePlayingNonMediaAppDoesntChangesSource() { 518 mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING, /* actions= */ 0)); 519 520 // setup media source info only for MEDIA Component 521 // second one will stay null 522 initMediaService(MEDIA_CLASS); 523 524 // New Media source should be null 525 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)).isNull(); 526 // service start should happen on init but not on media source change 527 verify(mContext).startForegroundService(any()); 528 } 529 530 @Test testActiveSessionListener_IndependentBrowseUnchanged()531 public void testActiveSessionListener_IndependentBrowseUnchanged() { 532 mCarMediaService.setIndependentPlaybackConfig(true); 533 mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING, /* actions= */ 0)); 534 535 initMediaService(MEDIA_CLASS, MEDIA_CLASS2); 536 537 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 538 .isEqualTo(MEDIA_COMPONENT2); 539 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE)) 540 .isEqualTo(MEDIA_COMPONENT); 541 verify(mContext, times(2)).startForegroundService(any()); 542 } 543 544 @Test testActiveSessionListener_DependentBrowseChanged()545 public void testActiveSessionListener_DependentBrowseChanged() { 546 mCarMediaService.setIndependentPlaybackConfig(false); 547 mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING, /* actions= */ 0)); 548 549 initMediaService(MEDIA_CLASS, MEDIA_CLASS2); 550 551 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 552 .isEqualTo(MEDIA_COMPONENT2); 553 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE)) 554 .isEqualTo(MEDIA_COMPONENT2); 555 verify(mContext, times(2)).startForegroundService(any()); 556 } 557 558 @Test testActiveSessionListener_StatePaused()559 public void testActiveSessionListener_StatePaused() { 560 mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PAUSED, /* actions= */ 0)); 561 562 initMediaService(MEDIA_CLASS, MEDIA_CLASS2); 563 564 assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)) 565 .isEqualTo(MEDIA_COMPONENT); 566 verify(mContext).startForegroundService(any()); 567 } 568 569 @Test testMediaKeyEventListenerOnKeyEvent_ignoresInvalidOccupantZone()570 public void testMediaKeyEventListenerOnKeyEvent_ignoresInvalidOccupantZone() { 571 when(mMockOccupantZoneService.getOccupantZoneIdForSeat(SEAT_NUMBER)) 572 .thenReturn(INVALID_ZONE_ID); 573 mCarMediaService.init(); 574 mockInputServiceKeyEvents(); 575 576 sendKeyEvent(MEDIA_KEY_EVENT, DISPLAY_TYPE_IGNORED, SEAT_NUMBER); 577 578 verifyZeroInteractions(mMediaSessionManager); 579 } 580 581 @Test testMediaKeyEventListenerOnKeyEvent_ignoresInvalidUser()582 public void testMediaKeyEventListenerOnKeyEvent_ignoresInvalidUser() { 583 when(mMockOccupantZoneService.getUserForOccupant(OCCUPANT_ZONE_ID)) 584 .thenReturn(INVALID_USER_ID); 585 mCarMediaService.init(); 586 mockInputServiceKeyEvents(); 587 588 sendKeyEvent(MEDIA_KEY_EVENT, DISPLAY_TYPE_IGNORED, SEAT_NUMBER); 589 590 verifyZeroInteractions(mMediaSessionManager); 591 } 592 593 @Test testMediaKeyEventListenerOnKeyEvent_stopsAfterFirstDelivery()594 public void testMediaKeyEventListenerOnKeyEvent_stopsAfterFirstDelivery() { 595 MediaController mockController1 = createMockMediaController(/* dispatchResult== */ false); 596 MediaController mockController2 = createMockMediaController(/* dispatchResult== */ true); 597 MediaController mockController3 = createMockMediaController(/* dispatchResult== */ true); 598 when(mMediaSessionManager.getActiveSessionsForUser(any(), eq(UserHandle.of(TEST_USER_ID)))) 599 .thenReturn(List.of(mockController1, mockController2, mockController3)); 600 mCarMediaService.init(); 601 mockInputServiceKeyEvents(); 602 603 sendKeyEvent(MEDIA_KEY_EVENT, DISPLAY_TYPE_IGNORED, SEAT_NUMBER); 604 605 verify(mockController1).dispatchMediaButtonEvent(MEDIA_KEY_EVENT); 606 verify(mockController2).dispatchMediaButtonEvent(MEDIA_KEY_EVENT); 607 verify(mockController3, never()).dispatchMediaButtonEvent(any()); 608 } 609 initMediaService(String... classesToResolve)610 private void initMediaService(String... classesToResolve) { 611 initializeMockPackageManager(classesToResolve); 612 mockUserUnlocked(true); 613 614 mCarMediaService.init(); 615 } 616 mockUserUnlocked(boolean unlocked)617 private void mockUserUnlocked(boolean unlocked) { 618 when(mUserManager.isUserUnlocked(any())).thenReturn(unlocked); 619 } 620 621 /** Sets {@code mKeyEventListener} to the key event listener that is being registered. */ mockInputServiceKeyEvents()622 private void mockInputServiceKeyEvents() { 623 ArgumentCaptor<KeyEventListener> keyEventListenerCaptor = 624 ArgumentCaptor.forClass(KeyEventListener.class); 625 verify(mMockInputService).registerKeyEventListener(keyEventListenerCaptor.capture(), 626 notNull()); 627 mKeyEventListener = keyEventListenerCaptor.getValue(); 628 } 629 630 /** Sends the given {@code keyEvent} to the listener stored in {@code mKeyEventListener}. */ sendKeyEvent(KeyEvent keyEvent, int displayType, int seat)631 private void sendKeyEvent(KeyEvent keyEvent, int displayType, int seat) { 632 checkState(mKeyEventListener != null, 633 "KeyEventListener has not been registered to CarInputService."); 634 mKeyEventListener.onKeyEvent(keyEvent, displayType, seat); 635 } 636 637 /** Sets {@code mUserLifecycleListener} to the listener that is being registered. */ mockUserLifecycleEvents()638 private void mockUserLifecycleEvents() { 639 ArgumentCaptor<UserLifecycleListener> userLifecycleListenerCaptor = 640 ArgumentCaptor.forClass(UserLifecycleListener.class); 641 verify(mUserService).addUserLifecycleListener(notNull(), 642 userLifecycleListenerCaptor.capture()); 643 mUserLifecycleListener = userLifecycleListenerCaptor.getValue(); 644 } 645 646 /** Sends the given {@code event} to the listener stored in {@code mUserLifecycleListener}. */ sendUserLifecycleEvent(UserLifecycleEvent event)647 private void sendUserLifecycleEvent(UserLifecycleEvent event) { 648 checkState(mUserLifecycleListener != null, 649 "UserLifeCycleListener has not been registered to CarUserService."); 650 mUserLifecycleListener.onEvent(event); 651 } 652 createMockMediaController(boolean dispatchResult)653 private MediaController createMockMediaController(boolean dispatchResult) { 654 MediaController mockController = mock(MediaController.class); 655 when(mockController.dispatchMediaButtonEvent(any())).thenReturn(dispatchResult); 656 657 return mockController; 658 } 659 mockMediaSourceListener()660 private ICarMediaSourceListener mockMediaSourceListener() { 661 ICarMediaSourceListener listener = mock(ICarMediaSourceListener.class); 662 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 663 return listener; 664 } 665 666 // This method invokes a playback state changed callback on a mock MediaController mockPlaybackStateChange(PlaybackState newState)667 private void mockPlaybackStateChange(PlaybackState newState) { 668 List<MediaController> controllers = new ArrayList<>(); 669 MediaController mockController = mock(MediaController.class); 670 when(mockController.getPackageName()).thenReturn(MEDIA_PACKAGE2); 671 MediaSession.Token mockSessionToken = mock(MediaSession.Token.class); 672 when(mockController.getSessionToken()).thenReturn(mockSessionToken); 673 when(mockSessionToken.getUid()).thenReturn(TEST_USER_ID * UserHandle.PER_USER_RANGE); 674 Bundle sessionExtras = new Bundle(); 675 sessionExtras.putString(Car.CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION, MEDIA_CLASS2); 676 when(mockController.getExtras()).thenReturn(sessionExtras); 677 678 doAnswer(invocation -> { 679 MediaController.Callback callback = invocation.getArgument(0); 680 callback.onPlaybackStateChanged(newState); 681 return null; 682 }).when(mockController).registerCallback(notNull()); 683 controllers.add(mockController); 684 685 doAnswer(invocation -> { 686 MediaSessionManager.OnActiveSessionsChangedListener callback = 687 invocation.getArgument(3); 688 callback.onActiveSessionsChanged(controllers); 689 return null; 690 }).when(mMediaSessionManager).addOnActiveSessionsChangedListener(any(), any(), any(), 691 any(MediaSessionManager.OnActiveSessionsChangedListener.class)); 692 } 693 694 // This method sets up PackageManager queries to return mocked media components if specified initializeMockPackageManager(String... classesToResolve)695 private void initializeMockPackageManager(String... classesToResolve) { 696 when(mContext.getString(R.string.config_defaultMediaSource)) 697 .thenReturn(MEDIA_COMPONENT.flattenToShortString()); 698 List<ResolveInfo> packageList = new ArrayList(); 699 for (String className : classesToResolve) { 700 ResolveInfo info = new ResolveInfo(); 701 ServiceInfo serviceInfo = new ServiceInfo(); 702 serviceInfo.name = className; 703 info.serviceInfo = serviceInfo; 704 packageList.add(info); 705 } 706 when(mPackageManager.queryIntentServicesAsUser(any(), anyInt(), any())) 707 .thenReturn(packageList); 708 } 709 createPlaybackState( @laybackState.State int state, @PlaybackState.Actions long actions)710 private PlaybackState createPlaybackState( 711 @PlaybackState.State int state, @PlaybackState.Actions long actions) { 712 return new PlaybackState.Builder().setState(state, 0, 0).setActions(actions).build(); 713 } 714 } 715