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