1 /*
2  * Copyright (C) 2016 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.server.wm;
18 
19 import static android.server.wm.ComponentNameUtils.getActivityName;
20 import static android.server.wm.app.Components.ALT_LAUNCHING_ACTIVITY;
21 import static android.server.wm.app.Components.LAUNCHING_ACTIVITY;
22 import static android.server.wm.app.Components.RESIZEABLE_ACTIVITY;
23 import static android.server.wm.app.Components.VR_TEST_ACTIVITY;
24 import static android.view.Display.DEFAULT_DISPLAY;
25 
26 import static org.junit.Assert.assertEquals;
27 import static org.junit.Assert.assertNotNull;
28 import static org.junit.Assume.assumeFalse;
29 import static org.junit.Assume.assumeTrue;
30 
31 import android.content.ComponentName;
32 import android.platform.test.annotations.FlakyTest;
33 import android.platform.test.annotations.Presubmit;
34 import android.provider.Settings;
35 import android.server.wm.WindowManagerState.DisplayContent;
36 import android.server.wm.settings.SettingsSession;
37 
38 import com.android.cts.verifier.vr.MockVrListenerService;
39 
40 import org.junit.Before;
41 import org.junit.Test;
42 
43 import java.util.List;
44 
45 /**
46  * Build/Install/Run:
47  *     atest CtsWindowManagerDeviceTestCases:VrDisplayTests
48  */
49 @Presubmit
50 @FlakyTest
51 @android.server.wm.annotation.Group3
52 public class VrDisplayTests extends MultiDisplayTestBase {
53     private static final int VR_VIRTUAL_DISPLAY_WIDTH = 700;
54     private static final int VR_VIRTUAL_DISPLAY_HEIGHT = 900;
55     private static final int VR_VIRTUAL_DISPLAY_DPI = 320;
56 
57 
58     @Before
59     @Override
setUp()60     public void setUp() throws Exception {
61         super.setUp();
62 
63         assumeTrue(supportsVrMode());
64     }
65 
66     /**
67      * VrModeSession is used to enable or disable persistent vr mode and the vr virtual display. For
68      * standalone vr devices, VrModeSession has no effect, because the device is already in
69      * persistent vr mode whenever it's on, and turning off persistent vr mode on a standalone vr
70      * device puts the device in a bad state.
71      */
72     private static class VrModeSession implements AutoCloseable {
73         private boolean applyVrModeChanges = !ActivityManagerTestBase.isUiModeLockedToVrHeadset();
74 
enablePersistentVrMode()75         void enablePersistentVrMode() {
76             if (!applyVrModeChanges) { return; }
77             executeShellCommand("setprop vr_virtualdisplay true");
78             executeShellCommand("vr set-persistent-vr-mode-enabled true");
79         }
80 
81         @Override
close()82         public void close() {
83             if (!applyVrModeChanges) { return; }
84             executeShellCommand("vr set-persistent-vr-mode-enabled false");
85             executeShellCommand("setprop vr_virtualdisplay false");
86         }
87     }
88 
89     /**
90      * Helper class to enable vr listener.
91      * VrManagerService uses SettingChangeListener to monitor ENABLED_VR_LISTENERS changed.
92      * We need to update Settings to let Vr service know if MockVrListenerService is enabled.
93      */
94     private static class EnableVrListenerSession extends SettingsSession<String> {
EnableVrListenerSession()95         public EnableVrListenerSession() {
96             super(Settings.Secure.getUriFor(Settings.Secure.ENABLED_VR_LISTENERS),
97                     Settings.Secure::getString,
98                     Settings.Secure::putString);
99         }
100 
enableVrListener(ComponentName targetVrComponent)101         public void enableVrListener(ComponentName targetVrComponent) {
102             ComponentName component = new ComponentName(targetVrComponent.getPackageName(),
103                     MockVrListenerService.class.getName());
104             set(component.flattenToString());
105         }
106     }
107 
108     /**
109      * Tests that any new activity launch in Vr mode is in Vr display.
110      */
111     @Test
testVrActivityLaunch()112     public void testVrActivityLaunch() {
113         assumeTrue(supportsMultiDisplay());
114 
115         final VrModeSession vrModeSession = mObjectTracker.manage(new VrModeSession());
116         final EnableVrListenerSession enableVrListenerSession =
117                 mObjectTracker.manage(new EnableVrListenerSession());
118 
119         // Put the device in persistent vr mode.
120         vrModeSession.enablePersistentVrMode();
121         enableVrListenerSession.enableVrListener(VR_TEST_ACTIVITY);
122 
123         // Launch the VR activity.
124         launchActivity(VR_TEST_ACTIVITY);
125         mWmState.computeState(VR_TEST_ACTIVITY);
126         mWmState.assertVisibility(VR_TEST_ACTIVITY, true /* visible */);
127 
128         // Launch the non-VR 2D activity and check where it ends up.
129         launchActivity(LAUNCHING_ACTIVITY);
130         mWmState.computeState(LAUNCHING_ACTIVITY);
131 
132         // Ensure that the subsequent activity is visible
133         mWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
134 
135         // Check that activity is launched in focused stack on primary display.
136         mWmState.assertFocusedActivity("Launched activity must be focused",
137                 LAUNCHING_ACTIVITY);
138         final int focusedStackId = mWmState.getFocusedStackId();
139         final WindowManagerState.ActivityTask focusedStack
140                 = mWmState.getRootTask(focusedStackId);
141         assertEquals("Launched activity must be resumed in focused stack",
142                 getActivityName(LAUNCHING_ACTIVITY), focusedStack.mResumedActivity);
143 
144         // Check if the launch activity is in Vr virtual display id.
145         final List<DisplayContent> reportedDisplays = getDisplaysStates();
146         final DisplayContent vrDisplay = getDisplayState(reportedDisplays,
147                 VR_VIRTUAL_DISPLAY_WIDTH, VR_VIRTUAL_DISPLAY_HEIGHT, VR_VIRTUAL_DISPLAY_DPI);
148         assertNotNull("Vr mode should have a virtual display", vrDisplay);
149 
150         // Check if the focused activity is on this virtual stack.
151         assertEquals("Launch in Vr mode should be in virtual stack", vrDisplay.mId,
152                 focusedStack.mDisplayId);
153     }
154 
155     /**
156      * Tests that any activity already present is re-launched in Vr display in vr mode.
157      */
158     @Test
testVrActivityReLaunch()159     public void testVrActivityReLaunch() {
160         assumeTrue(supportsMultiDisplay());
161 
162         // Launch a 2D activity.
163         launchActivity(LAUNCHING_ACTIVITY);
164 
165         final VrModeSession vrModeSession = mObjectTracker.manage(new VrModeSession());
166         final EnableVrListenerSession enableVrListenerSession =
167                 mObjectTracker.manage(new EnableVrListenerSession());
168 
169         // Put the device in persistent vr mode.
170         vrModeSession.enablePersistentVrMode();
171         enableVrListenerSession.enableVrListener(VR_TEST_ACTIVITY);
172 
173         // Launch the VR activity.
174         launchActivity(VR_TEST_ACTIVITY);
175         mWmState.computeState(VR_TEST_ACTIVITY);
176         mWmState.assertVisibility(VR_TEST_ACTIVITY, true /* visible */);
177 
178         // Re-launch the non-VR 2D activity and check where it ends up.
179         launchActivity(LAUNCHING_ACTIVITY);
180         mWmState.computeState(LAUNCHING_ACTIVITY);
181 
182         // Ensure that the subsequent activity is visible
183         mWmState.assertVisibility(LAUNCHING_ACTIVITY, true /* visible */);
184 
185         // Check that activity is launched in focused stack on primary display.
186         mWmState.assertFocusedActivity("Launched activity must be focused",
187                 LAUNCHING_ACTIVITY);
188         final int focusedStackId = mWmState.getFocusedStackId();
189         final WindowManagerState.ActivityTask focusedStack
190                 = mWmState.getRootTask(focusedStackId);
191         assertEquals("Launched activity must be resumed in focused stack",
192                 getActivityName(LAUNCHING_ACTIVITY), focusedStack.mResumedActivity);
193 
194         // Check if the launch activity is in Vr virtual display id.
195         final List<DisplayContent> reportedDisplays = getDisplaysStates();
196         final DisplayContent vrDisplay = getDisplayState(reportedDisplays,
197                 VR_VIRTUAL_DISPLAY_WIDTH, VR_VIRTUAL_DISPLAY_HEIGHT, VR_VIRTUAL_DISPLAY_DPI);
198         assertNotNull("Vr mode should have a virtual display", vrDisplay);
199 
200         // Check if the focused activity is on this virtual stack.
201         assertEquals("Launch in Vr mode should be in virtual stack", vrDisplay.mId,
202                 focusedStack.mDisplayId);
203     }
204 
205     /**
206      * Tests that any new activity launch post Vr mode is in the main display.
207      */
208     @Test
testActivityLaunchPostVr()209     public void testActivityLaunchPostVr() throws Exception {
210         assumeTrue(supportsMultiDisplay());
211         // This test doesn't apply to a standalone vr device, since vr is always enabled, and
212         // there is no "post vr" behavior to verify.
213         assumeFalse(isUiModeLockedToVrHeadset());
214 
215         try (final VrModeSession vrModeSession = new VrModeSession();
216              final EnableVrListenerSession enableVrListenerSession =
217                      new EnableVrListenerSession()) {
218             // Put the device in persistent vr mode.
219             vrModeSession.enablePersistentVrMode();
220             enableVrListenerSession.enableVrListener(VR_TEST_ACTIVITY);
221 
222             // Launch the VR activity.
223             launchActivity(VR_TEST_ACTIVITY);
224             mWmState.computeState(VR_TEST_ACTIVITY);
225             mWmState.assertVisibility(VR_TEST_ACTIVITY, true /* visible */);
226 
227             // Launch the non-VR 2D activity and check where it ends up.
228             launchActivity(ALT_LAUNCHING_ACTIVITY);
229             mWmState.computeState(ALT_LAUNCHING_ACTIVITY);
230 
231             // Ensure that the subsequent activity is visible
232             mWmState.assertVisibility(ALT_LAUNCHING_ACTIVITY, true /* visible */);
233 
234             // Check that activity is launched in focused stack on primary display.
235             mWmState.assertFocusedActivity("Launched activity must be focused",
236                     ALT_LAUNCHING_ACTIVITY);
237             final int focusedStackId = mWmState.getFocusedStackId();
238             final WindowManagerState.ActivityTask focusedStack
239                     = mWmState.getRootTask(focusedStackId);
240             assertEquals("Launched activity must be resumed in focused stack",
241                     getActivityName(ALT_LAUNCHING_ACTIVITY),
242                     focusedStack.mResumedActivity);
243 
244             // Check if the launch activity is in Vr virtual display id.
245             final List<DisplayContent> reportedDisplays = getDisplaysStates();
246             final DisplayContent vrDisplay = getDisplayState(reportedDisplays,
247                     VR_VIRTUAL_DISPLAY_WIDTH, VR_VIRTUAL_DISPLAY_HEIGHT,
248                     VR_VIRTUAL_DISPLAY_DPI);
249             assertNotNull("Vr mode should have a virtual display", vrDisplay);
250 
251             // Check if the focused activity is on this virtual stack.
252             assertEquals("Launch in Vr mode should be in virtual stack", vrDisplay.mId,
253                     focusedStack.mDisplayId);
254 
255         }
256 
257         // There isn't a direct launch of activity which can take an user out of persistent VR mode.
258         // This sleep is to account for that delay and let device settle once it comes out of VR
259         // mode.
260         try {
261             Thread.sleep(2000);
262         } catch (Exception e) {
263             e.printStackTrace();
264         }
265 
266         // Launch the non-VR 2D activity and check where it ends up.
267         launchActivity(RESIZEABLE_ACTIVITY);
268         mWmState.computeState(RESIZEABLE_ACTIVITY);
269 
270         // Ensure that the subsequent activity is visible
271         mWmState.assertVisibility(RESIZEABLE_ACTIVITY, true /* visible */);
272 
273         // Check that activity is launched in focused stack on primary display.
274         mWmState.assertFocusedActivity("Launched activity must be focused", RESIZEABLE_ACTIVITY);
275         final int frontStackId = mWmState.getFrontRootTaskId(DEFAULT_DISPLAY);
276         final WindowManagerState.ActivityTask frontStack
277                 = mWmState.getRootTask(frontStackId);
278         assertEquals("Launched activity must be resumed in front stack",
279                 getActivityName(RESIZEABLE_ACTIVITY), frontStack.mResumedActivity);
280         assertEquals("Front stack must be on primary display",
281                 DEFAULT_DISPLAY, frontStack.mDisplayId);
282     }
283 }
284