1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.media.session.cts;
18 
19 import static android.media.cts.MediaSessionTestHelperConstants.FLAG_CREATE_MEDIA_SESSION;
20 import static android.media.cts.MediaSessionTestHelperConstants.FLAG_CREATE_MEDIA_SESSION2;
21 import static android.media.cts.MediaSessionTestHelperConstants.FLAG_SET_MEDIA_SESSION_ACTIVE;
22 import static android.media.cts.MediaSessionTestHelperConstants.MEDIA_SESSION_TEST_HELPER_APK;
23 import static android.media.cts.MediaSessionTestHelperConstants.MEDIA_SESSION_TEST_HELPER_PKG;
24 
25 import static com.google.common.truth.Truth.assertWithMessage;
26 
27 import android.media.cts.BaseMultiUserTest;
28 import android.media.cts.MediaSessionTestHelperConstants;
29 import android.platform.test.annotations.AppModeFull;
30 import android.platform.test.annotations.AppModeInstant;
31 import android.platform.test.annotations.RequiresDevice;
32 
33 import com.android.ddmlib.Log.LogLevel;
34 import com.android.tradefed.device.DeviceNotAvailableException;
35 import com.android.tradefed.device.ITestDevice;
36 import com.android.tradefed.log.LogUtil.CLog;
37 import com.android.tradefed.util.RunUtil;
38 
39 import java.util.ArrayList;
40 import java.util.List;
41 
42 /**
43  * Host-side test for the media session manager that installs and runs device-side tests after the
44  * proper device setup.
45  * <p>Corresponding device-side tests are written in the {@link #DEVICE_SIDE_TEST_CLASS}
46  * which is in the {@link #DEVICE_SIDE_TEST_APK}.
47  */
48 public class MediaSessionManagerHostTest extends BaseMultiUserTest {
49     /**
50      * Package name of the device-side tests.
51      */
52     private static final String DEVICE_SIDE_TEST_PKG = "android.media.session.cts";
53     /**
54      * Package file name (.apk) for the device-side tests.
55      */
56     private static final String DEVICE_SIDE_TEST_APK = "CtsMediaSessionHostTestApp.apk";
57     /**
58      * Fully qualified class name for the device-side tests.
59      */
60     private static final String DEVICE_SIDE_TEST_CLASS =
61             "android.media.session.cts.MediaSessionManagerTest";
62 
63     private static final int TIMEOUT_MS = 1000;
64 
65     /**
66      * Returned by {@link ITestDevice#getCurrentUser()} when there is an error retrieving the
67      * current user id.
68      */
69     private static final int INVALID_USER_ID = -10000;
70 
71     private final List<Integer> mNotificationListeners = new ArrayList<>();
72 
73     @Override
setUp()74     public void setUp() throws Exception {
75         super.setUp();
76         mNotificationListeners.clear();
77     }
78 
79     @Override
tearDown()80     public void tearDown() throws Exception {
81         getDevice().uninstallPackage(MEDIA_SESSION_TEST_HELPER_PKG);
82         getDevice().uninstallPackage(DEVICE_SIDE_TEST_PKG);
83         for (int userId : mNotificationListeners) {
84             setAllowGetActiveSessionForTest(false, userId);
85         }
86         super.tearDown();
87     }
88 
89     /**
90      * Tests {@link MediaSessionManager#getActiveSessions} with the primary user.
91      */
92     @AppModeInstant
93     @RequiresDevice
testGetActiveSessionsInstant_primaryUser()94     public void testGetActiveSessionsInstant_primaryUser() throws Exception {
95         testGetActiveSessions_primaryUser(true);
96     }
97 
98     /**
99      * Tests {@link MediaSessionManager#getActiveSessions} with the primary user.
100      */
101     @AppModeFull
102     @RequiresDevice
testGetActiveSessionsFull_primaryUser()103     public void testGetActiveSessionsFull_primaryUser() throws Exception {
104         testGetActiveSessions_primaryUser(false);
105     }
106 
testGetActiveSessions_primaryUser(boolean instant)107     private void testGetActiveSessions_primaryUser(boolean instant) throws Exception {
108         int userIdForTesting = getUserIdForTesting();
109 
110         setAllowGetActiveSessionForTest(true, userIdForTesting);
111         installAppAsUser(DEVICE_SIDE_TEST_APK, DEVICE_SIDE_TEST_PKG, userIdForTesting, instant);
112         runTest("testGetActiveSessions_noMediaSessionFromMediaSessionTestHelper");
113 
114         installAppAsUser(
115                 MEDIA_SESSION_TEST_HELPER_APK,
116                 MEDIA_SESSION_TEST_HELPER_PKG,
117                 userIdForTesting,
118                 false);
119         sendControlCommand(userIdForTesting, FLAG_CREATE_MEDIA_SESSION);
120         runTest("testGetActiveSessions_noMediaSessionFromMediaSessionTestHelper");
121 
122         sendControlCommand(userIdForTesting, FLAG_SET_MEDIA_SESSION_ACTIVE);
123         runTest("testGetActiveSessions_hasMediaSessionFromMediaSessionTestHelper");
124     }
125 
126     /**
127      * Tests {@link MediaSessionManager#getActiveSessions} with additional users.
128      */
129     @AppModeInstant
130     @RequiresDevice
testGetActiveSessionsInstant_additionalUser()131     public void testGetActiveSessionsInstant_additionalUser() throws Exception {
132         testGetActiveSessions_additionalUser(true);
133     }
134 
135     /**
136      * Tests {@link MediaSessionManager#getActiveSessions} with additional users.
137      */
138     @AppModeFull
139     @RequiresDevice
testGetActiveSessionsFull_additionalUser()140     public void testGetActiveSessionsFull_additionalUser() throws Exception {
141         testGetActiveSessions_additionalUser(false);
142     }
143 
testGetActiveSessions_additionalUser(boolean instant)144     private void testGetActiveSessions_additionalUser(boolean instant) throws Exception {
145         if (!canCreateAdditionalUsers(1)) {
146             CLog.logAndDisplay(LogLevel.INFO,
147                     "Cannot create a new user. Skipping multi-user test cases.");
148             return;
149         }
150 
151         // Test if another user can get the session.
152         int newUser = createAndStartUser();
153         installAppAsUser(DEVICE_SIDE_TEST_APK, DEVICE_SIDE_TEST_PKG, newUser, instant);
154         setAllowGetActiveSessionForTest(true, newUser);
155         runTestAsUser("testGetActiveSessions_noMediaSession", newUser);
156         removeUser(newUser);
157     }
158 
159     /**
160      * Tests {@link MediaSessionManager#getActiveSessions} with restricted profiles.
161      */
162     @AppModeInstant
163     @RequiresDevice
testGetActiveSessionsInstant_restrictedProfiles()164     public void testGetActiveSessionsInstant_restrictedProfiles() throws Exception {
165         testGetActiveSessions_restrictedProfiles(true);
166     }
167 
168     /**
169      * Tests {@link MediaSessionManager#getActiveSessions} with restricted profiles.
170      */
171     @AppModeFull
172     @RequiresDevice
testGetActiveSessionsFull_restrictedProfiles()173     public void testGetActiveSessionsFull_restrictedProfiles() throws Exception {
174         testGetActiveSessions_restrictedProfiles(false);
175     }
176 
testGetActiveSessions_restrictedProfiles(boolean instant)177     private void testGetActiveSessions_restrictedProfiles(boolean instant)
178             throws Exception {
179         if (!canCreateAdditionalUsers(1)) {
180             CLog.logAndDisplay(LogLevel.INFO,
181                     "Cannot create a new user. Skipping multi-user test cases.");
182             return;
183         }
184 
185         // Test if another restricted profile can get the session.
186         // Remove the created user first not to exceed system's user number limit.
187         // Restricted profile's parent must be the primary user (the system user).
188         int newUser = createAndStartRestrictedProfile(getDevice().getPrimaryUserId());
189         installAppAsUser(DEVICE_SIDE_TEST_APK, DEVICE_SIDE_TEST_PKG, newUser, instant);
190         setAllowGetActiveSessionForTest(true, newUser);
191         runTestAsUser("testGetActiveSessions_noMediaSession", newUser);
192         removeUser(newUser);
193     }
194 
195     /**
196      * Tests {@link MediaSessionManager#getActiveSessions} with managed profiles.
197      */
198     @AppModeInstant
199     @RequiresDevice
testGetActiveSessionsInstant_managedProfiles()200     public void testGetActiveSessionsInstant_managedProfiles() throws Exception {
201         testGetActiveSessions_managedProfiles(true);
202     }
203 
204     /**
205      * Tests {@link MediaSessionManager#getActiveSessions} with managed profiles.
206      */
207     @AppModeFull
208     @RequiresDevice
testGetActiveSessionsFull_managedProfiles()209     public void testGetActiveSessionsFull_managedProfiles() throws Exception {
210         testGetActiveSessions_managedProfiles(false);
211     }
212 
testGetActiveSessions_managedProfiles(boolean instant)213     private void testGetActiveSessions_managedProfiles(boolean instant)
214             throws Exception {
215         if (!hasDeviceFeature("android.software.managed_users")) {
216             CLog.logAndDisplay(LogLevel.INFO,
217                     "Device doesn't support managed profiles. Test won't run.");
218             return;
219         }
220 
221         // Test if another managed profile can get the session.
222         // Remove the created user first not to exceed system's user number limit.
223         // Managed profile's parent must not be the primary user (in the context of this test, we
224         // use the main user).
225         int newUser = createAndStartManagedProfile(getUserIdForTesting());
226         installAppAsUser(DEVICE_SIDE_TEST_APK, DEVICE_SIDE_TEST_PKG, newUser, instant);
227         setAllowGetActiveSessionForTest(true, newUser);
228         runTestAsUser("testGetActiveSessions_noMediaSession", newUser);
229         removeUser(newUser);
230     }
231 
232     @AppModeFull
233     @RequiresDevice
testGetActiveSessions_noSession2()234     public void testGetActiveSessions_noSession2() throws Exception {
235         int userIdForTesting = getUserIdForTesting();
236 
237         setAllowGetActiveSessionForTest(true, userIdForTesting);
238         installAppAsUser(DEVICE_SIDE_TEST_APK, DEVICE_SIDE_TEST_PKG, userIdForTesting, false);
239         runTest("testGetActiveSessions_noMediaSessionFromMediaSessionTestHelper");
240 
241         installAppAsUser(
242                 MEDIA_SESSION_TEST_HELPER_APK,
243                 MEDIA_SESSION_TEST_HELPER_PKG,
244                 userIdForTesting,
245                 false);
246         sendControlCommand(userIdForTesting, FLAG_CREATE_MEDIA_SESSION2);
247 
248         // Wait for a second for framework to recognize media session2.
249         RunUtil.getDefault().sleep(TIMEOUT_MS);
250         runTest("testGetActiveSessions_noMediaSessionFromMediaSessionTestHelper");
251     }
252 
253     @AppModeFull
254     @RequiresDevice
testGetActiveSessions_withSession2()255     public void testGetActiveSessions_withSession2() throws Exception {
256         int userIdForTesting = getUserIdForTesting();
257 
258         setAllowGetActiveSessionForTest(true, userIdForTesting);
259         installAppAsUser(DEVICE_SIDE_TEST_APK, DEVICE_SIDE_TEST_PKG, userIdForTesting, false);
260         runTest("testGetActiveSessions_noMediaSessionFromMediaSessionTestHelper");
261 
262         installAppAsUser(
263                 MEDIA_SESSION_TEST_HELPER_APK,
264                 MEDIA_SESSION_TEST_HELPER_PKG,
265                 userIdForTesting,
266                 false);
267         sendControlCommand(
268                 userIdForTesting,
269                 FLAG_CREATE_MEDIA_SESSION
270                         | FLAG_CREATE_MEDIA_SESSION2
271                         | FLAG_SET_MEDIA_SESSION_ACTIVE);
272 
273         // Wait for a second for framework to recognize media session2.
274         RunUtil.getDefault().sleep(TIMEOUT_MS);
275 
276         runTest("testGetActiveSessions_hasMediaSessionFromMediaSessionTestHelper");
277     }
278 
279     @AppModeFull
280     @RequiresDevice
testOnMediaKeyEventSessionChangedListener()281     public void testOnMediaKeyEventSessionChangedListener() throws Exception {
282         int userIdForTesting = getUserIdForTesting();
283 
284         setAllowGetActiveSessionForTest(true, userIdForTesting);
285         installAppAsUser(DEVICE_SIDE_TEST_APK, DEVICE_SIDE_TEST_PKG, userIdForTesting, false);
286         runTest("testOnMediaKeyEventSessionChangedListener");
287     }
288 
289     @AppModeFull
290     @RequiresDevice
testOnMediaKeyEventSessionChangedListener_whenSessionIsReleased()291     public void testOnMediaKeyEventSessionChangedListener_whenSessionIsReleased() throws Exception {
292         int userIdForTesting = getUserIdForTesting();
293 
294         setAllowGetActiveSessionForTest(true, userIdForTesting);
295         installAppAsUser(DEVICE_SIDE_TEST_APK, DEVICE_SIDE_TEST_PKG, userIdForTesting, false);
296         runTest("testOnMediaKeyEventSessionChangedListener_whenSessionIsReleased");
297     }
298 
299     @AppModeFull
300     @RequiresDevice
testIsTrusted_withEnabledNotificationListener_returnsTrue()301     public void testIsTrusted_withEnabledNotificationListener_returnsTrue() throws Exception {
302         if (!canCreateAdditionalUsers(1)) {
303             CLog.logAndDisplay(LogLevel.INFO,
304                     "Cannot create a new user. Skipping multi-user test cases.");
305             return;
306         }
307 
308         int newUserId = createAndStartUser();
309         setAllowGetActiveSessionForTest(true, newUserId);
310         installAppAsUser(DEVICE_SIDE_TEST_APK, DEVICE_SIDE_TEST_PKG, newUserId, false);
311         runTestAsUser("testIsTrusted_returnsTrue", newUserId);
312     }
313 
314     @AppModeFull
315     @RequiresDevice
testIsTrusted_withoutEnabledNotificationListener_returnsFalse()316     public void testIsTrusted_withoutEnabledNotificationListener_returnsFalse()
317             throws Exception {
318         if (!canCreateAdditionalUsers(1)) {
319             CLog.logAndDisplay(LogLevel.INFO,
320                     "Cannot create a new user. Skipping multi-user test cases.");
321             return;
322         }
323 
324         int newUserId = createAndStartUser();
325         setAllowGetActiveSessionForTest(false, newUserId);
326         installAppAsUser(DEVICE_SIDE_TEST_APK, DEVICE_SIDE_TEST_PKG, newUserId, false);
327         runTestAsUser("testIsTrusted_returnsFalse", newUserId);
328     }
329 
runTest(String testMethodName)330     private void runTest(String testMethodName) throws DeviceNotAvailableException {
331         runTestAsUser(testMethodName, getUserIdForTesting());
332     }
333 
runTestAsUser(String testMethodName, int userId)334     private void runTestAsUser(String testMethodName, int userId)
335             throws DeviceNotAvailableException {
336         runDeviceTests(DEVICE_SIDE_TEST_PKG, DEVICE_SIDE_TEST_CLASS, testMethodName, userId);
337     }
338 
339     /**
340      * If running headless system user mode, returns the current user. Otherwise, returns the main
341      * user.
342      *
343      * <p>Historically, some tests in this class would use the main user for running device-side
344      * tests. Headless surfaces (like Android Auto) do not have a main user. As a result, on
345      * headless surfaces, we use the current user in replacement of the missing main user.
346      */
getUserIdForTesting()347     private int getUserIdForTesting() throws DeviceNotAvailableException {
348         if (getDevice().isHeadlessSystemUserMode()) {
349             int currentUserId = getDevice().getCurrentUser();
350             assertWithMessage(
351                             "Unable to fetch a valid current user id in headless system user mode.")
352                     .that(currentUserId)
353                     .isNotEqualTo(INVALID_USER_ID);
354             return currentUserId;
355         } else {
356             return getDevice().getMainUserId();
357         }
358     }
359 
360     /**
361      * Sets to allow or disallow the {@link #DEVICE_SIDE_TEST_CLASS}
362      * to call {@link MediaSessionManager#getActiveSessions} for testing.
363      * <p>{@link MediaSessionManager#getActiveSessions} bypasses the permission check if the
364      * caller is the enabled notification listener. This method uses the behavior by allowing
365      * this class as the notification listener service.
366      * <p>Note that the device-side test {@link android.media.cts.MediaSessionManagerTest} already
367      * covers the test for failing {@link MediaSessionManager#getActiveSessions} without the
368      * permission nor the notification listener.
369      */
setAllowGetActiveSessionForTest(boolean allow, int userId)370     private void setAllowGetActiveSessionForTest(boolean allow, int userId) throws Exception {
371         String notificationListener = DEVICE_SIDE_TEST_PKG + "/" + DEVICE_SIDE_TEST_CLASS;
372         String command = "cmd notification "
373                 + ((allow) ? "allow_listener " : "disallow_listener ")
374                 + notificationListener + " " + userId;
375         executeShellCommand(command);
376         if (allow) {
377             mNotificationListeners.add(userId);
378         }
379     }
380 
sendControlCommand(int userId, int flag)381     private void sendControlCommand(int userId, int flag) throws Exception {
382         executeShellCommand(MediaSessionTestHelperConstants.buildControlCommand(userId, flag));
383     }
384 }
385