• 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.media.CarMediaManager.MEDIA_SOURCE_MODE_BROWSE;
20 import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_PLAYBACK;
21 
22 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
23 
24 import static com.google.common.truth.Truth.assertThat;
25 
26 import static org.mockito.ArgumentMatchers.any;
27 import static org.mockito.ArgumentMatchers.anyInt;
28 import static org.mockito.ArgumentMatchers.anyLong;
29 import static org.mockito.ArgumentMatchers.anyString;
30 import static org.mockito.ArgumentMatchers.notNull;
31 import static org.mockito.Mockito.doAnswer;
32 import static org.mockito.Mockito.mock;
33 import static org.mockito.Mockito.never;
34 import static org.mockito.Mockito.times;
35 import static org.mockito.Mockito.verify;
36 import static org.mockito.Mockito.when;
37 
38 import android.app.ActivityManager;
39 import android.car.Car;
40 import android.car.media.ICarMediaSourceListener;
41 import android.car.test.mocks.AbstractExtendedMockitoTestCase;
42 import android.car.test.mocks.AndroidMockitoHelper;
43 import android.content.ComponentName;
44 import android.content.Context;
45 import android.content.SharedPreferences;
46 import android.content.pm.PackageManager;
47 import android.content.pm.ResolveInfo;
48 import android.content.pm.ServiceInfo;
49 import android.content.res.Resources;
50 import android.media.session.MediaController;
51 import android.media.session.MediaSession;
52 import android.media.session.MediaSessionManager;
53 import android.media.session.PlaybackState;
54 import android.os.Bundle;
55 import android.os.IBinder;
56 import android.os.UserHandle;
57 import android.os.UserManager;
58 
59 import com.android.car.CarLocalServices;
60 import com.android.car.CarLog;
61 import com.android.car.CarMediaService;
62 import com.android.car.R;
63 import com.android.car.power.CarPowerManagementService;
64 import com.android.car.systeminterface.SystemInterface;
65 import com.android.car.user.CarUserService;
66 import com.android.car.user.UserHandleHelper;
67 import com.android.internal.app.IVoiceInteractionManagerService;
68 
69 import org.junit.After;
70 import org.junit.Before;
71 import org.junit.Test;
72 import org.mockito.Mock;
73 
74 import java.util.ArrayList;
75 import java.util.List;
76 
77 public final class CarMediaServiceTest extends AbstractExtendedMockitoTestCase {
78 
79     private static final String MEDIA_PACKAGE = "test.package";
80     private static final String MEDIA_PACKAGE2 = "test.package2";
81     private static final String MEDIA_CLASS = "test_class";
82     private static final String MEDIA_CLASS2 = "test_class2";
83 
84     private static final int TEST_USER_ID = 100;
85 
86     private static final ComponentName MEDIA_COMPONENT =
87             new ComponentName(MEDIA_PACKAGE, MEDIA_CLASS);
88     private static final ComponentName MEDIA_COMPONENT2 =
89             new ComponentName(MEDIA_PACKAGE2, MEDIA_CLASS2);
90 
91     @Mock private Context mContext;
92     @Mock private Resources mResources;
93     @Mock private CarUserService mUserService;
94     @Mock private UserManager mUserManager;
95     @Mock private PackageManager mPackageManager;
96     @Mock private MediaSessionManager mMediaSessionManager;
97     @Mock private SystemInterface mMockSystemInterface;
98     @Mock private IVoiceInteractionManagerService mMockVoiceService;
99     @Mock private CarPowerManagementService mMockCarPowerManagementService;
100     @Mock private UserHandleHelper mUserHandleHelper;
101     @Mock private SharedPreferences mMockSharedPreferences;
102     @Mock private SharedPreferences.Editor mMockSharedPreferencesEditor;
103 
104     private CarMediaService mCarMediaService;
105 
CarMediaServiceTest()106     public CarMediaServiceTest() {
107         super(CarLog.TAG_MEDIA);
108     }
109 
110     @Override
onSessionBuilder(CustomMockitoSessionBuilder builder)111     protected void onSessionBuilder(CustomMockitoSessionBuilder builder) {
112         builder.spyStatic(ActivityManager.class);
113     }
114 
115     @Before
setUp()116     public void setUp() {
117         when(mContext.checkCallingOrSelfPermission(anyString()))
118                 .thenReturn(PackageManager.PERMISSION_GRANTED);
119         when(mContext.getPackageManager()).thenReturn(mPackageManager);
120         when(mContext.createContextAsUser(any(), anyInt())).thenReturn(mContext);
121         when(mContext.getSharedPreferences(anyString(), anyInt()))
122                 .thenReturn(mMockSharedPreferences);
123         when(mMockSharedPreferences.edit()).thenReturn(mMockSharedPreferencesEditor);
124         when(mMockSharedPreferencesEditor.putInt(anyString(), anyInt()))
125                 .thenReturn(mMockSharedPreferencesEditor);
126         when(mMockSharedPreferencesEditor.putLong(anyString(), anyLong()))
127                 .thenReturn(mMockSharedPreferencesEditor);
128         when(mMockSharedPreferencesEditor.putString(anyString(), anyString()))
129                 .thenReturn(mMockSharedPreferencesEditor);
130 
131         doReturn(mResources).when(mContext).getResources();
132         doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
133         UserHandle user = UserHandle.of(TEST_USER_ID);
134         AndroidMockitoHelper.mockAmGetCurrentUser(TEST_USER_ID);
135         when(mUserHandleHelper.isEphemeralUser(UserHandle.of(TEST_USER_ID))).thenReturn(false);
136         doReturn(mMediaSessionManager).when(mContext).getSystemService(MediaSessionManager.class);
137 
138         mCarMediaService = new CarMediaService(mContext, mUserService, mUserHandleHelper);
139         CarLocalServices.addService(CarPowerManagementService.class,
140                 mMockCarPowerManagementService);
141     }
142 
143     @After
tearDown()144     public void tearDown() {
145         CarLocalServices.removeServiceForTest(CarPowerManagementService.class);
146     }
147 
148     @Test
testSetMediaSource_ModePlaybackIndependent()149     public void testSetMediaSource_ModePlaybackIndependent() {
150         mCarMediaService.setIndependentPlaybackConfig(true);
151         initMediaService();
152 
153         mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
154 
155         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
156                 .isEqualTo(MEDIA_COMPONENT);
157         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
158                 .isNotEqualTo(MEDIA_COMPONENT);
159     }
160 
161     @Test
testSetMediaSource_ModeBrowseIndependent()162     public void testSetMediaSource_ModeBrowseIndependent() {
163         mCarMediaService.setIndependentPlaybackConfig(true);
164         initMediaService();
165 
166         mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE);
167 
168         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
169                 .isEqualTo(MEDIA_COMPONENT);
170         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
171                 .isNotEqualTo(MEDIA_COMPONENT);
172     }
173 
174     @Test
testSetMediaSource_ModePlaybackAndBrowseIndependent()175     public void testSetMediaSource_ModePlaybackAndBrowseIndependent() {
176         mCarMediaService.setIndependentPlaybackConfig(true);
177         initMediaService();
178 
179         mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE);
180         mCarMediaService.setMediaSource(MEDIA_COMPONENT2, MEDIA_SOURCE_MODE_PLAYBACK);
181 
182         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
183                 .isEqualTo(MEDIA_COMPONENT);
184         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
185                 .isEqualTo(MEDIA_COMPONENT2);
186     }
187 
188     @Test
testSetMediaSource_Dependent()189     public void testSetMediaSource_Dependent() {
190         mCarMediaService.setIndependentPlaybackConfig(false);
191         initMediaService();
192 
193         mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
194 
195         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
196                 .isEqualTo(MEDIA_COMPONENT);
197         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
198                 .isEqualTo(MEDIA_COMPONENT);
199 
200         mCarMediaService.setMediaSource(MEDIA_COMPONENT2, MEDIA_SOURCE_MODE_BROWSE);
201 
202         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
203                 .isEqualTo(MEDIA_COMPONENT2);
204         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
205                 .isEqualTo(MEDIA_COMPONENT2);
206     }
207 
208     @Test
testMediaSourceListener_Independent()209     public void testMediaSourceListener_Independent() throws Exception {
210         mCarMediaService.setIndependentPlaybackConfig(true);
211         initMediaService();
212         ICarMediaSourceListener listenerPlayback = mockMediaSourceListener();
213         ICarMediaSourceListener listenerBrowse = mockMediaSourceListener();
214 
215         mCarMediaService.registerMediaSourceListener(listenerPlayback, MEDIA_SOURCE_MODE_PLAYBACK);
216         mCarMediaService.registerMediaSourceListener(listenerBrowse, MEDIA_SOURCE_MODE_BROWSE);
217         mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
218 
219         verify(listenerPlayback).onMediaSourceChanged(MEDIA_COMPONENT);
220         verify(listenerBrowse, never()).onMediaSourceChanged(any());
221     }
222 
223     @Test
testMediaSourceListener_IndependentBrowse()224     public void testMediaSourceListener_IndependentBrowse() throws Exception {
225         mCarMediaService.setIndependentPlaybackConfig(true);
226         initMediaService();
227         ICarMediaSourceListener listenerPlayback = mockMediaSourceListener();
228         ICarMediaSourceListener listenerBrowse = mockMediaSourceListener();
229 
230         mCarMediaService.registerMediaSourceListener(listenerPlayback, MEDIA_SOURCE_MODE_PLAYBACK);
231         mCarMediaService.registerMediaSourceListener(listenerBrowse, MEDIA_SOURCE_MODE_BROWSE);
232         mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE);
233 
234         verify(listenerBrowse).onMediaSourceChanged(MEDIA_COMPONENT);
235         verify(listenerPlayback, never()).onMediaSourceChanged(any());
236     }
237 
238     @Test
testMediaSourceListener_Dependent()239     public void testMediaSourceListener_Dependent() throws Exception {
240         mCarMediaService.setIndependentPlaybackConfig(false);
241         initMediaService();
242         ICarMediaSourceListener listenerPlayback = mockMediaSourceListener();
243         ICarMediaSourceListener listenerBrowse = mockMediaSourceListener();
244 
245         mCarMediaService.registerMediaSourceListener(listenerPlayback, MEDIA_SOURCE_MODE_PLAYBACK);
246         mCarMediaService.registerMediaSourceListener(listenerBrowse, MEDIA_SOURCE_MODE_BROWSE);
247         mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
248 
249         verify(listenerPlayback).onMediaSourceChanged(MEDIA_COMPONENT);
250         verify(listenerBrowse).onMediaSourceChanged(MEDIA_COMPONENT);
251 
252         mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_BROWSE);
253 
254         verify(listenerPlayback).onMediaSourceChanged(MEDIA_COMPONENT);
255         verify(listenerBrowse).onMediaSourceChanged(MEDIA_COMPONENT);
256     }
257 
258     @Test
testMediaSourceListener_Unregister()259     public void testMediaSourceListener_Unregister() throws Exception {
260         initMediaService();
261         ICarMediaSourceListener listener = mockMediaSourceListener();
262 
263         mCarMediaService.registerMediaSourceListener(listener, MEDIA_SOURCE_MODE_PLAYBACK);
264         mCarMediaService.unregisterMediaSourceListener(listener, MEDIA_SOURCE_MODE_PLAYBACK);
265         mCarMediaService.setMediaSource(MEDIA_COMPONENT, MEDIA_SOURCE_MODE_PLAYBACK);
266 
267         verify(listener, never()).onMediaSourceChanged(MEDIA_COMPONENT);
268     }
269 
270     @Test
testDefaultMediaSource()271     public void testDefaultMediaSource() {
272         initMediaService(MEDIA_CLASS);
273 
274         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
275                 .isEqualTo(MEDIA_COMPONENT);
276     }
277 
278     @Test
testUnresolvedMediaPackage()279     public void testUnresolvedMediaPackage() {
280         initializeMockPackageManager();
281 
282         assertThat(mCarMediaService.isMediaService(MEDIA_COMPONENT)).isFalse();
283     }
284 
285     /**
286      * Tests that PlaybackState changing to PlaybackState#isActive
287      * will result the media source changing
288      */
289     @Test
testActiveSessionListener_StateActiveChangesSource()290     public void testActiveSessionListener_StateActiveChangesSource() {
291         mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_BUFFERING));
292 
293         initMediaService(MEDIA_CLASS, MEDIA_CLASS2);
294 
295         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
296                 .isEqualTo(MEDIA_COMPONENT2);
297         verify(mContext, times(2)).startForegroundService(any());
298     }
299 
300     // Tests that PlaybackState changing to STATE_PLAYING will result the media source changing
301     @Test
testActiveSessionListener_StatePlayingChangesSource()302     public void testActiveSessionListener_StatePlayingChangesSource() {
303         mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING));
304 
305         initMediaService(MEDIA_CLASS, MEDIA_CLASS2);
306 
307         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
308                 .isEqualTo(MEDIA_COMPONENT2);
309         verify(mContext, times(2)).startForegroundService(any());
310     }
311 
312     @Test
testActiveSessionListener_StatePlayingNonMediaAppDoesntChangesSource()313     public void testActiveSessionListener_StatePlayingNonMediaAppDoesntChangesSource() {
314         mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING));
315 
316         // setup media source info only for MEDIA Component
317         // second one will stay null
318         initMediaService(MEDIA_CLASS);
319 
320         // New Media source should be null
321         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK)).isNull();
322         // service start should happen on init but not on media source change
323         verify(mContext, times(1)).startForegroundService(any());
324     }
325 
326     @Test
testActiveSessionListener_IndependentBrowseUnchanged()327     public void testActiveSessionListener_IndependentBrowseUnchanged() {
328         mCarMediaService.setIndependentPlaybackConfig(true);
329         mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING));
330 
331         initMediaService(MEDIA_CLASS, MEDIA_CLASS2);
332 
333         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
334                 .isEqualTo(MEDIA_COMPONENT2);
335         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
336                 .isEqualTo(MEDIA_COMPONENT);
337         verify(mContext, times(2)).startForegroundService(any());
338     }
339 
340     @Test
testActiveSessionListener_DependentBrowseChanged()341     public void testActiveSessionListener_DependentBrowseChanged() {
342         mCarMediaService.setIndependentPlaybackConfig(false);
343         mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PLAYING));
344 
345         initMediaService(MEDIA_CLASS, MEDIA_CLASS2);
346 
347         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
348                 .isEqualTo(MEDIA_COMPONENT2);
349         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_BROWSE))
350                 .isEqualTo(MEDIA_COMPONENT2);
351         verify(mContext, times(2)).startForegroundService(any());
352     }
353 
354     @Test
testActiveSessionListener_StatePaused()355     public void testActiveSessionListener_StatePaused() {
356         mockPlaybackStateChange(createPlaybackState(PlaybackState.STATE_PAUSED));
357 
358         initMediaService(MEDIA_CLASS, MEDIA_CLASS2);
359 
360         assertThat(mCarMediaService.getMediaSource(MEDIA_SOURCE_MODE_PLAYBACK))
361                 .isEqualTo(MEDIA_COMPONENT);
362         verify(mContext, times(1)).startForegroundService(any());
363     }
364 
initMediaService(String... classesToResolve)365     private void initMediaService(String... classesToResolve) {
366         initializeMockPackageManager(classesToResolve);
367         mockUserUnlocked(true);
368 
369         mCarMediaService.init();
370     }
371 
mockUserUnlocked(boolean unlocked)372     private void mockUserUnlocked(boolean unlocked) {
373         when(mUserManager.isUserUnlocked(any())).thenReturn(unlocked);
374     }
375 
mockMediaSourceListener()376     private ICarMediaSourceListener mockMediaSourceListener() {
377         ICarMediaSourceListener listener = mock(ICarMediaSourceListener.class);
378         when(listener.asBinder()).thenReturn(mock(IBinder.class));
379         return listener;
380     }
381 
382     // This method invokes a playback state changed callback on a mock MediaController
mockPlaybackStateChange(PlaybackState newState)383     private void mockPlaybackStateChange(PlaybackState newState) {
384         List<MediaController> controllers = new ArrayList<>();
385         MediaController mockController = mock(MediaController.class);
386         when(mockController.getPackageName()).thenReturn(MEDIA_PACKAGE2);
387         when(mockController.getSessionToken()).thenReturn(mock(MediaSession.Token.class));
388         Bundle sessionExtras = new Bundle();
389         sessionExtras.putString(Car.CAR_EXTRA_BROWSE_SERVICE_FOR_SESSION, MEDIA_CLASS2);
390         when(mockController.getExtras()).thenReturn(sessionExtras);
391 
392         doAnswer(invocation -> {
393             MediaController.Callback callback = invocation.getArgument(0);
394             callback.onPlaybackStateChanged(newState);
395             return null;
396         }).when(mockController).registerCallback(notNull());
397         controllers.add(mockController);
398 
399         doAnswer(invocation -> {
400             MediaSessionManager.OnActiveSessionsChangedListener callback =
401                     invocation.getArgument(3);
402             callback.onActiveSessionsChanged(controllers);
403             return null;
404         }).when(mMediaSessionManager).addOnActiveSessionsChangedListener(any(), any(), any(),
405                 any(MediaSessionManager.OnActiveSessionsChangedListener.class));
406     }
407 
408     // This method sets up PackageManager queries to return mocked media components if specified
initializeMockPackageManager(String... classesToResolve)409     private void initializeMockPackageManager(String... classesToResolve) {
410         when(mContext.getString(R.string.config_defaultMediaSource))
411                 .thenReturn(MEDIA_COMPONENT.flattenToShortString());
412         List<ResolveInfo> packageList = new ArrayList();
413         for (String className : classesToResolve) {
414             ResolveInfo info = new ResolveInfo();
415             ServiceInfo serviceInfo = new ServiceInfo();
416             serviceInfo.name = className;
417             info.serviceInfo = serviceInfo;
418             packageList.add(info);
419         }
420         when(mPackageManager.queryIntentServicesAsUser(any(), anyInt(), any()))
421                 .thenReturn(packageList);
422     }
423 
createPlaybackState(@laybackState.State int state)424     private PlaybackState createPlaybackState(@PlaybackState.State int state) {
425         return new PlaybackState.Builder().setState(state, 0, 0).build();
426     }
427 }
428