• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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