1 /* 2 * Copyright (C) 2015 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.cts; 18 19 import java.awt.Rectangle; 20 21 public class ActivityManagerDockedStackTests extends ActivityManagerTestBase { 22 23 private static final String TEST_ACTIVITY_NAME = "TestActivity"; 24 private static final String NON_RESIZEABLE_ACTIVITY_NAME = "NonResizeableActivity"; 25 private static final String DOCKED_ACTIVITY_NAME = "DockedActivity"; 26 private static final String LAUNCH_TO_SIDE_ACTIVITY_NAME = "LaunchToSideActivity"; 27 private static final String NO_RELAUNCH_ACTIVITY_NAME = "NoRelaunchActivity"; 28 private static final String SINGLE_INSTANCE_ACTIVITY_NAME = "SingleInstanceActivity"; 29 private static final String SINGLE_TASK_ACTIVITY_NAME = "SingleTaskActivity"; 30 31 private static final int TASK_SIZE = 600; 32 private static final int STACK_SIZE = 300; 33 34 public void testStackList() throws Exception { 35 executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME)); 36 mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME}); 37 mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID); 38 mAmWmState.assertContainsStack( 39 "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID); 40 mAmWmState.assertDoesNotContainStack("Must not contain docked stack.", DOCKED_STACK_ID); 41 } 42 43 public void testDockActivity() throws Exception { 44 launchActivityInDockStack(TEST_ACTIVITY_NAME); 45 mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME}); 46 mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID); 47 mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID); 48 } 49 50 public void testNonResizeableNotDocked() throws Exception { 51 launchActivityInDockStack(NON_RESIZEABLE_ACTIVITY_NAME); 52 mAmWmState.computeState(mDevice, new String[] {NON_RESIZEABLE_ACTIVITY_NAME}); 53 54 mAmWmState.assertContainsStack("Must contain home stack.", HOME_STACK_ID); 55 mAmWmState.assertDoesNotContainStack("Must not contain docked stack.", DOCKED_STACK_ID); 56 mAmWmState.assertFrontStack( 57 "Fullscreen stack must be front stack.", FULLSCREEN_WORKSPACE_STACK_ID); 58 } 59 60 public void testLaunchToSide() throws Exception { 61 launchActivityInDockStack(LAUNCH_TO_SIDE_ACTIVITY_NAME); 62 launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME); 63 mAmWmState.computeState(mDevice, new String[] {LAUNCH_TO_SIDE_ACTIVITY_NAME}); 64 65 mAmWmState.assertContainsStack( 66 "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID); 67 mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID); 68 } 69 70 public void testLaunchToSideAndBringToFront() throws Exception { 71 launchActivityInDockStack(LAUNCH_TO_SIDE_ACTIVITY_NAME); 72 final String[] waitForFirstVisible = new String[] {TEST_ACTIVITY_NAME}; 73 final String[] waitForSecondVisible = new String[] {NO_RELAUNCH_ACTIVITY_NAME}; 74 75 // Launch activity to side. 76 launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME); 77 mAmWmState.computeState(mDevice, waitForFirstVisible); 78 int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID) 79 .getTasks().size(); 80 mAmWmState.assertFocusedActivity("Launched to side activity must be in front.", 81 TEST_ACTIVITY_NAME); 82 83 // Launch another activity to side to cover first one. 84 launchActivityInStack(NO_RELAUNCH_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID); 85 mAmWmState.computeState(mDevice, waitForSecondVisible); 86 int taskNumberCovered = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID) 87 .getTasks().size(); 88 mAmWmState.assertEquals("Fullscreen stack must have one task added.", 89 taskNumberInitial + 1, taskNumberCovered); 90 mAmWmState.assertFocusedActivity("Launched to side covering activity must be in front.", 91 NO_RELAUNCH_ACTIVITY_NAME); 92 93 // Launch activity that was first launched to side. It should be brought to front. 94 launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME); 95 mAmWmState.computeState(mDevice, waitForFirstVisible); 96 int taskNumberFinal = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID) 97 .getTasks().size(); 98 mAmWmState.assertEquals("Task number in fullscreen stack must remain the same.", 99 taskNumberCovered, taskNumberFinal); 100 mAmWmState.assertFocusedActivity("Launched to side covering activity must be in front.", 101 TEST_ACTIVITY_NAME); 102 } 103 104 public void testLaunchToSideMultiple() throws Exception { 105 launchActivityInDockStack(LAUNCH_TO_SIDE_ACTIVITY_NAME); 106 final String[] waitForActivitiesVisible = new String[] {TEST_ACTIVITY_NAME}; 107 108 // Launch activity to side. 109 launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME); 110 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 111 int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID) 112 .getTasks().size(); 113 mAmWmState.assertNotNull("Launched to side activity must be in fullscreen stack.", 114 mAmWmState.getAmState() 115 .getTaskByActivityName(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID)); 116 117 // Try to launch to side same activity again. 118 launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME); 119 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 120 int taskNumberFinal = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID) 121 .getTasks().size(); 122 mAmWmState.assertEquals("Task number mustn't change.", taskNumberInitial, taskNumberFinal); 123 mAmWmState.assertFocusedActivity("Launched to side activity must remain in front.", 124 TEST_ACTIVITY_NAME); 125 mAmWmState.assertNotNull("Launched to side activity must remain in fullscreen stack.", 126 mAmWmState.getAmState() 127 .getTaskByActivityName(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID)); 128 } 129 130 public void testLaunchToSideSingleInstance() throws Exception { 131 launchTargetToSide(SINGLE_INSTANCE_ACTIVITY_NAME, false); 132 } 133 134 public void testLaunchToSideSingleTask() throws Exception { 135 launchTargetToSide(SINGLE_TASK_ACTIVITY_NAME, false); 136 } 137 138 public void testLaunchToSideMultipleWithDifferentIntent() throws Exception { 139 launchTargetToSide(TEST_ACTIVITY_NAME, true); 140 } 141 142 private void launchTargetToSide(String targetActivityName, 143 boolean taskCountMustIncrement) throws Exception { 144 launchActivityInDockStack(LAUNCH_TO_SIDE_ACTIVITY_NAME); 145 final String[] waitForActivitiesVisible = new String[] {targetActivityName}; 146 147 // Launch activity to side with data. 148 launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME, true, false, targetActivityName); 149 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 150 int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID) 151 .getTasks().size(); 152 mAmWmState.assertNotNull("Launched to side activity must be in fullscreen stack.", 153 mAmWmState.getAmState() 154 .getTaskByActivityName(targetActivityName, FULLSCREEN_WORKSPACE_STACK_ID)); 155 156 // Try to launch to side same activity again with different data. 157 launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME, true, false, targetActivityName); 158 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 159 int taskNumberSecondLaunch = mAmWmState.getAmState() 160 .getStackById(FULLSCREEN_WORKSPACE_STACK_ID).getTasks().size(); 161 if (taskCountMustIncrement) { 162 mAmWmState.assertEquals("Task number must be incremented.", taskNumberInitial + 1, 163 taskNumberSecondLaunch); 164 } else { 165 mAmWmState.assertEquals("Task number must not change.", taskNumberInitial, 166 taskNumberSecondLaunch); 167 } 168 mAmWmState.assertFocusedActivity("Launched to side activity must be in front.", 169 targetActivityName); 170 mAmWmState.assertNotNull("Launched to side activity must be launched in fullscreen stack.", 171 mAmWmState.getAmState() 172 .getTaskByActivityName(targetActivityName, FULLSCREEN_WORKSPACE_STACK_ID)); 173 174 // Try to launch to side same activity again with no data. 175 launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME, false, false, targetActivityName); 176 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 177 int taskNumberFinal = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID) 178 .getTasks().size(); 179 if (taskCountMustIncrement) { 180 mAmWmState.assertEquals("Task number must be incremented.", taskNumberSecondLaunch + 1, 181 taskNumberFinal); 182 } else { 183 mAmWmState.assertEquals("Task number must not change.", taskNumberSecondLaunch, 184 taskNumberFinal); 185 } 186 mAmWmState.assertFocusedActivity("Launched to side activity must be in front.", 187 targetActivityName); 188 mAmWmState.assertNotNull("Launched to side activity must be launched in fullscreen stack.", 189 mAmWmState.getAmState() 190 .getTaskByActivityName(targetActivityName, FULLSCREEN_WORKSPACE_STACK_ID)); 191 } 192 193 public void testLaunchToSideMultipleWithFlag() throws Exception { 194 launchActivityInDockStack(LAUNCH_TO_SIDE_ACTIVITY_NAME); 195 final String[] waitForActivitiesVisible = new String[] {TEST_ACTIVITY_NAME}; 196 197 // Launch activity to side. 198 launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME); 199 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 200 int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID) 201 .getTasks().size(); 202 mAmWmState.assertNotNull("Launched to side activity must be in fullscreen stack.", 203 mAmWmState.getAmState() 204 .getTaskByActivityName(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID)); 205 206 // Try to launch to side same activity again, but with Intent#FLAG_ACTIVITY_MULTIPLE_TASK. 207 launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME, false, true); 208 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 209 int taskNumberFinal = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID) 210 .getTasks().size(); 211 mAmWmState.assertEquals("Task number must be incremented.", taskNumberInitial + 1, 212 taskNumberFinal); 213 mAmWmState.assertFocusedActivity("Launched to side activity must be in front.", 214 TEST_ACTIVITY_NAME); 215 mAmWmState.assertNotNull("Launched to side activity must remain in fullscreen stack.", 216 mAmWmState.getAmState() 217 .getTaskByActivityName(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID)); 218 } 219 220 public void testRotationWhenDocked() throws Exception { 221 launchActivityInDockStack(LAUNCH_TO_SIDE_ACTIVITY_NAME); 222 launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME); 223 final String[] waitForActivitiesVisible = new String[] {LAUNCH_TO_SIDE_ACTIVITY_NAME}; 224 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 225 mAmWmState.assertContainsStack( 226 "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID); 227 mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID); 228 229 // Rotate device single steps (90) 0-1-2-3. 230 // Each time we compute the state we implicitly assert valid bounds. 231 setDeviceRotation(0); 232 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 233 setDeviceRotation(1); 234 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 235 setDeviceRotation(2); 236 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 237 setDeviceRotation(3); 238 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 239 // Double steps (180) We ended the single step at 3. So, we jump directly to 1 for double 240 // step. So, we are testing 3-1-3 for one side and 0-2-0 for the other side. 241 setDeviceRotation(1); 242 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 243 setDeviceRotation(3); 244 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 245 setDeviceRotation(0); 246 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 247 setDeviceRotation(2); 248 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 249 setDeviceRotation(0); 250 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 251 } 252 253 public void testRotationWhenDockedWhileLocked() throws Exception { 254 launchActivityInDockStack(LAUNCH_TO_SIDE_ACTIVITY_NAME); 255 launchActivityToSide(LAUNCH_TO_SIDE_ACTIVITY_NAME); 256 final String[] waitForActivitiesVisible = new String[] {LAUNCH_TO_SIDE_ACTIVITY_NAME}; 257 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 258 mAmWmState.assertSanity(); 259 mAmWmState.assertContainsStack( 260 "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID); 261 mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID); 262 263 lockDevice(); 264 setDeviceRotation(0); 265 unlockDevice(); 266 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 267 268 lockDevice(); 269 setDeviceRotation(1); 270 unlockDevice(); 271 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 272 273 lockDevice(); 274 setDeviceRotation(2); 275 unlockDevice(); 276 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 277 278 lockDevice(); 279 setDeviceRotation(3); 280 unlockDevice(); 281 mAmWmState.computeState(mDevice, waitForActivitiesVisible); 282 } 283 284 public void testResizeDockedStack() throws Exception { 285 launchActivityInDockStack(DOCKED_ACTIVITY_NAME); 286 launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID); 287 resizeDockedStack(STACK_SIZE, STACK_SIZE, TASK_SIZE, TASK_SIZE); 288 mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME}, 289 false /* compareTaskAndStackBounds */); 290 mAmWmState.assertContainsStack("Must contain docked stack", DOCKED_STACK_ID); 291 mAmWmState.assertContainsStack("Must contain fullscreen stack", 292 FULLSCREEN_WORKSPACE_STACK_ID); 293 assertEquals(new Rectangle(0, 0, STACK_SIZE, STACK_SIZE), 294 mAmWmState.getAmState().getStackById(DOCKED_STACK_ID).getBounds()); 295 mAmWmState.assertDockedTaskBounds(TASK_SIZE, DOCKED_ACTIVITY_NAME); 296 mAmWmState.assertVisibility(DOCKED_ACTIVITY_NAME, true); 297 mAmWmState.assertVisibility(TEST_ACTIVITY_NAME, true); 298 } 299 300 public void testActivityLifeCycleOnResizeDockedStack() throws Exception { 301 executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME)); 302 mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME}); 303 final Rectangle fullScreenBounds = 304 mAmWmState.getWmState().getStack(FULLSCREEN_WORKSPACE_STACK_ID).getBounds(); 305 306 moveActivityToDockStack(TEST_ACTIVITY_NAME); 307 launchActivityInStack(NO_RELAUNCH_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID); 308 309 mAmWmState.computeState(mDevice, 310 new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME}); 311 final Rectangle initialDockBounds = 312 mAmWmState.getWmState().getStack(DOCKED_STACK_ID).getBounds(); 313 314 clearLogcat(); 315 316 Rectangle newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, true); 317 resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height); 318 319 // We resize twice to make sure we cross an orientation change threshold for both 320 // activities. 321 newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, false); 322 resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height); 323 324 mAmWmState.computeState(mDevice, 325 new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME}); 326 327 assertActivityLifecycle(TEST_ACTIVITY_NAME, true); 328 assertActivityLifecycle(NO_RELAUNCH_ACTIVITY_NAME, false); 329 } 330 331 private Rectangle computeNewDockBounds( 332 Rectangle fullscreenBounds, Rectangle dockBounds, boolean reduceSize) { 333 final boolean inLandscape = fullscreenBounds.width > dockBounds.width; 334 // We are either increasing size or reducing it. 335 final float sizeChangeFactor = reduceSize ? 0.5f : 1.5f; 336 final Rectangle newBounds = new Rectangle(dockBounds); 337 if (inLandscape) { 338 // In landscape we change the width. 339 newBounds.width *= sizeChangeFactor; 340 } else { 341 // In portrait we change the height 342 newBounds.height *= sizeChangeFactor; 343 } 344 345 return newBounds; 346 } 347 348 private void launchActivityToSide(String activityName) throws Exception { 349 launchActivityToSide(activityName, false, false); 350 } 351 352 private void launchActivityToSide(String activityName, boolean randomData, 353 boolean multipleTaskFlag) throws Exception { 354 launchActivityToSide(activityName, randomData, multipleTaskFlag, null); 355 } 356 357 private void launchActivityToSide(String activityName, boolean randomData, 358 boolean multipleTaskFlag, String targetActivityName) 359 throws Exception { 360 StringBuilder commandBuilder = new StringBuilder(getAmStartCmd(activityName)); 361 commandBuilder.append(" -f 0x20000000 --ez launch_to_the_side true"); 362 if (randomData) { 363 commandBuilder.append(" --ez random_data true"); 364 } 365 if (multipleTaskFlag) { 366 commandBuilder.append(" --ez multiple_task true"); 367 } 368 if (targetActivityName != null) { 369 commandBuilder.append(" --es target_activity ").append(targetActivityName); 370 } 371 executeShellCommand(commandBuilder.toString()); 372 } 373 } 374