| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License |
| */ |
| |
| package android.server.am; |
| |
| import static android.app.ActivityManager.StackId.INVALID_STACK_ID; |
| import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; |
| import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; |
| import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; |
| import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; |
| import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; |
| import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; |
| import static android.server.am.ActivityManagerState.STATE_PAUSED; |
| import static android.server.am.ActivityManagerState.STATE_RESUMED; |
| import static android.server.am.ActivityManagerState.STATE_STOPPED; |
| import static android.server.am.ComponentNameUtils.getActivityName; |
| import static android.server.am.Components.ALT_LAUNCHING_ACTIVITY; |
| import static android.server.am.Components.ALWAYS_FOCUSABLE_PIP_ACTIVITY; |
| import static android.server.am.Components.BROADCAST_RECEIVER_ACTIVITY; |
| import static android.server.am.Components.BroadcastReceiverActivity.ACTION_TRIGGER_BROADCAST; |
| import static android.server.am.Components.BroadcastReceiverActivity.EXTRA_FINISH_BROADCAST; |
| import static android.server.am.Components.DOCKED_ACTIVITY; |
| import static android.server.am.Components.LAUNCHING_ACTIVITY; |
| import static android.server.am.Components.LAUNCH_PIP_ON_PIP_ACTIVITY; |
| import static android.server.am.Components.MOVE_TASK_TO_BACK_ACTIVITY; |
| import static android.server.am.Components.MoveTaskToBackActivity.EXTRA_FINISH_POINT; |
| import static android.server.am.Components.MoveTaskToBackActivity.FINISH_POINT_ON_PAUSE; |
| import static android.server.am.Components.MoveTaskToBackActivity.FINISH_POINT_ON_STOP; |
| import static android.server.am.Components.NO_HISTORY_ACTIVITY; |
| import static android.server.am.Components.SWIPE_REFRESH_ACTIVITY; |
| import static android.server.am.Components.TEST_ACTIVITY; |
| import static android.server.am.Components.TRANSLUCENT_ACTIVITY; |
| import static android.server.am.Components.TURN_SCREEN_ON_ACTIVITY; |
| import static android.server.am.Components.TURN_SCREEN_ON_ATTR_ACTIVITY; |
| import static android.server.am.Components.TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY; |
| import static android.server.am.Components.TURN_SCREEN_ON_SHOW_ON_LOCK_ACTIVITY; |
| import static android.server.am.Components.TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY; |
| import static android.server.am.Components.TURN_SCREEN_ON_WITH_RELAYOUT_ACTIVITY; |
| import static android.server.am.UiDeviceUtils.pressBackButton; |
| |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotEquals; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assume.assumeTrue; |
| |
| import android.platform.test.annotations.Presubmit; |
| |
| import org.junit.Rule; |
| import org.junit.Test; |
| |
| /** |
| * Build/Install/Run: |
| * atest CtsActivityManagerDeviceTestCases:ActivityManagerActivityVisibilityTests |
| */ |
| public class ActivityManagerActivityVisibilityTests extends ActivityManagerTestBase { |
| |
| @Rule |
| public final DisableScreenDozeRule mDisableScreenDozeRule = new DisableScreenDozeRule(); |
| |
| @Presubmit |
| @Test |
| public void testTranslucentActivityOnTopOfPinnedStack() throws Exception { |
| if (!supportsPip()) { |
| return; |
| } |
| |
| executeShellCommand(getAmStartCmdOverHome(LAUNCH_PIP_ON_PIP_ACTIVITY)); |
| mAmWmState.waitForValidState(LAUNCH_PIP_ON_PIP_ACTIVITY); |
| // NOTE: moving to pinned stack will trigger the pip-on-pip activity to launch the |
| // translucent activity. |
| final int stackId = mAmWmState.getAmState().getStackIdByActivity( |
| LAUNCH_PIP_ON_PIP_ACTIVITY); |
| |
| assertNotEquals(stackId, INVALID_STACK_ID); |
| executeShellCommand(getMoveToPinnedStackCommand(stackId)); |
| mAmWmState.waitForValidState( |
| new WaitForValidActivityState.Builder(ALWAYS_FOCUSABLE_PIP_ACTIVITY) |
| .setWindowingMode(WINDOWING_MODE_PINNED) |
| .setActivityType(ACTIVITY_TYPE_STANDARD) |
| .build()); |
| |
| mAmWmState.assertFrontStack("Pinned stack must be the front stack.", |
| WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD); |
| mAmWmState.assertVisibility(LAUNCH_PIP_ON_PIP_ACTIVITY, true); |
| mAmWmState.assertVisibility(ALWAYS_FOCUSABLE_PIP_ACTIVITY, true); |
| } |
| |
| /** |
| * Asserts that the home activity is visible when a translucent activity is launched in the |
| * fullscreen stack over the home activity. |
| */ |
| @Test |
| public void testTranslucentActivityOnTopOfHome() throws Exception { |
| if (!hasHomeScreen()) { |
| return; |
| } |
| |
| launchHomeActivity(); |
| launchActivity(ALWAYS_FOCUSABLE_PIP_ACTIVITY); |
| |
| mAmWmState.assertFrontStack("Fullscreen stack must be the front stack.", |
| WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD); |
| mAmWmState.assertVisibility(ALWAYS_FOCUSABLE_PIP_ACTIVITY, true); |
| mAmWmState.assertHomeActivityVisible(true); |
| } |
| |
| /** |
| * Assert that the home activity is visible if a task that was launched from home is pinned |
| * and also assert the next task in the fullscreen stack isn't visible. |
| */ |
| @Presubmit |
| @Test |
| public void testHomeVisibleOnActivityTaskPinned() throws Exception { |
| if (!supportsPip()) { |
| return; |
| } |
| |
| launchHomeActivity(); |
| launchActivity(TEST_ACTIVITY); |
| launchHomeActivity(); |
| launchActivity(ALWAYS_FOCUSABLE_PIP_ACTIVITY); |
| final int stackId = mAmWmState.getAmState().getStackIdByActivity( |
| ALWAYS_FOCUSABLE_PIP_ACTIVITY); |
| |
| assertNotEquals(stackId, INVALID_STACK_ID); |
| executeShellCommand(getMoveToPinnedStackCommand(stackId)); |
| mAmWmState.waitForValidState( |
| new WaitForValidActivityState.Builder(ALWAYS_FOCUSABLE_PIP_ACTIVITY) |
| .setWindowingMode(WINDOWING_MODE_PINNED) |
| .setActivityType(ACTIVITY_TYPE_STANDARD) |
| .build()); |
| |
| mAmWmState.assertVisibility(ALWAYS_FOCUSABLE_PIP_ACTIVITY, true); |
| mAmWmState.assertVisibility(TEST_ACTIVITY, false); |
| mAmWmState.assertHomeActivityVisible(true); |
| } |
| |
| @Presubmit |
| @Test |
| public void testTranslucentActivityOverDockedStack() throws Exception { |
| if (!supportsSplitScreenMultiWindow()) { |
| // Skipping test: no multi-window support |
| return; |
| } |
| |
| launchActivitiesInSplitScreen( |
| getLaunchActivityBuilder().setTargetActivity(DOCKED_ACTIVITY), |
| getLaunchActivityBuilder().setTargetActivity(TEST_ACTIVITY)); |
| launchActivity(TRANSLUCENT_ACTIVITY, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); |
| mAmWmState.computeState(false /* compareTaskAndStackBounds */, |
| new WaitForValidActivityState(TEST_ACTIVITY), |
| new WaitForValidActivityState(DOCKED_ACTIVITY), |
| new WaitForValidActivityState(TRANSLUCENT_ACTIVITY)); |
| mAmWmState.assertContainsStack("Must contain fullscreen stack.", |
| WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_STANDARD); |
| mAmWmState.assertContainsStack("Must contain docked stack.", |
| WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD); |
| mAmWmState.assertVisibility(DOCKED_ACTIVITY, true); |
| mAmWmState.assertVisibility(TEST_ACTIVITY, true); |
| mAmWmState.assertVisibility(TRANSLUCENT_ACTIVITY, true); |
| } |
| |
| @Presubmit |
| @Test |
| public void testTurnScreenOnActivity() throws Exception { |
| try (final LockScreenSession lockScreenSession = new LockScreenSession()) { |
| lockScreenSession.sleepDevice(); |
| launchActivity(TURN_SCREEN_ON_ACTIVITY); |
| |
| mAmWmState.assertVisibility(TURN_SCREEN_ON_ACTIVITY, true); |
| assertTrue("Display turns on", isDisplayOn()); |
| } |
| } |
| |
| @Presubmit |
| @Test |
| public void testFinishActivityInNonFocusedStack() throws Exception { |
| if (!supportsSplitScreenMultiWindow()) { |
| // Skipping test: no multi-window support |
| return; |
| } |
| |
| // Launch two activities in docked stack. |
| launchActivityInSplitScreenWithRecents(LAUNCHING_ACTIVITY); |
| getLaunchActivityBuilder() |
| .setTargetActivity(BROADCAST_RECEIVER_ACTIVITY) |
| .setWaitForLaunched(true) |
| .execute(); |
| mAmWmState.assertVisibility(BROADCAST_RECEIVER_ACTIVITY, true); |
| // Launch something to fullscreen stack to make it focused. |
| launchActivity(TEST_ACTIVITY, WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY); |
| mAmWmState.assertVisibility(TEST_ACTIVITY, true); |
| // Finish activity in non-focused (docked) stack. |
| executeShellCommand(FINISH_ACTIVITY_BROADCAST); |
| |
| mAmWmState.waitForActivityState(LAUNCHING_ACTIVITY, STATE_PAUSED); |
| mAmWmState.waitForAllExitingWindows(); |
| |
| mAmWmState.computeState(LAUNCHING_ACTIVITY); |
| mAmWmState.assertVisibility(LAUNCHING_ACTIVITY, true); |
| mAmWmState.assertVisibility(BROADCAST_RECEIVER_ACTIVITY, false); |
| } |
| |
| @Test |
| public void testFinishActivityWithMoveTaskToBackAfterPause() throws Exception { |
| performFinishActivityWithMoveTaskToBack(FINISH_POINT_ON_PAUSE); |
| } |
| |
| @Test |
| public void testFinishActivityWithMoveTaskToBackAfterStop() throws Exception { |
| performFinishActivityWithMoveTaskToBack(FINISH_POINT_ON_STOP); |
| } |
| |
| private void performFinishActivityWithMoveTaskToBack(String finishPoint) throws Exception { |
| // Make sure home activity is visible. |
| launchHomeActivity(); |
| if (hasHomeScreen()) { |
| mAmWmState.assertHomeActivityVisible(true /* visible */); |
| } |
| |
| // Launch an activity that calls "moveTaskToBack" to finish itself. |
| launchActivity(MOVE_TASK_TO_BACK_ACTIVITY, EXTRA_FINISH_POINT, finishPoint); |
| mAmWmState.assertVisibility(MOVE_TASK_TO_BACK_ACTIVITY, true); |
| |
| // Launch a different activity on top. |
| launchActivity(BROADCAST_RECEIVER_ACTIVITY); |
| mAmWmState.waitForActivityState(BROADCAST_RECEIVER_ACTIVITY, STATE_RESUMED); |
| // Wait for transition complete. |
| mAmWmState.waitForValidState(MOVE_TASK_TO_BACK_ACTIVITY); |
| final boolean shouldBeVisible = |
| !mAmWmState.getAmState().isBehindOpaqueActivities(MOVE_TASK_TO_BACK_ACTIVITY); |
| mAmWmState.assertVisibility(MOVE_TASK_TO_BACK_ACTIVITY, shouldBeVisible); |
| mAmWmState.assertVisibility(BROADCAST_RECEIVER_ACTIVITY, true); |
| |
| // Finish the top-most activity. |
| executeShellCommand(FINISH_ACTIVITY_BROADCAST); |
| //TODO: BUG: MoveTaskToBackActivity returns to the top of the stack when |
| // BroadcastActivity finishes, so homeActivity is not visible afterwards |
| |
| // Home must be visible. |
| if (hasHomeScreen()) { |
| mAmWmState.waitForHomeActivityVisible(); |
| mAmWmState.assertHomeActivityVisible(true /* visible */); |
| } |
| } |
| |
| /** |
| * Asserts that launching between reorder to front activities exhibits the correct backstack |
| * behavior. |
| */ |
| @Test |
| public void testReorderToFrontBackstack() throws Exception { |
| // Start with home on top |
| launchHomeActivity(); |
| if (hasHomeScreen()) { |
| mAmWmState.assertHomeActivityVisible(true /* visible */); |
| } |
| |
| // Launch the launching activity to the foreground |
| launchActivity(LAUNCHING_ACTIVITY); |
| |
| // Launch the alternate launching activity from launching activity with reorder to front. |
| getLaunchActivityBuilder().setTargetActivity(ALT_LAUNCHING_ACTIVITY) |
| .setReorderToFront(true).execute(); |
| |
| // Launch the launching activity from the alternate launching activity with reorder to |
| // front. |
| getLaunchActivityBuilder().setTargetActivity(LAUNCHING_ACTIVITY) |
| .setLaunchingActivity(ALT_LAUNCHING_ACTIVITY) |
| .setReorderToFront(true) |
| .execute(); |
| |
| // Press back |
| pressBackButton(); |
| |
| mAmWmState.waitForValidState(ALT_LAUNCHING_ACTIVITY); |
| |
| // Ensure the alternate launching activity is in focus |
| mAmWmState.assertFocusedActivity("Alt Launching Activity must be focused", |
| ALT_LAUNCHING_ACTIVITY); |
| } |
| |
| /** |
| * Asserts that the activity focus and history is preserved moving between the activity and |
| * home stack. |
| */ |
| @Test |
| public void testReorderToFrontChangingStack() throws Exception { |
| // Start with home on top |
| launchHomeActivity(); |
| if (hasHomeScreen()) { |
| mAmWmState.assertHomeActivityVisible(true /* visible */); |
| } |
| |
| // Launch the launching activity to the foreground |
| launchActivity(LAUNCHING_ACTIVITY); |
| |
| // Launch the alternate launching activity from launching activity with reorder to front. |
| getLaunchActivityBuilder().setTargetActivity(ALT_LAUNCHING_ACTIVITY) |
| .setReorderToFront(true) |
| .execute(); |
| |
| // Return home |
| launchHomeActivity(); |
| if (hasHomeScreen()) { |
| mAmWmState.assertHomeActivityVisible(true /* visible */); |
| } |
| // Launch the launching activity from the alternate launching activity with reorder to |
| // front. |
| |
| // Bring launching activity back to the foreground |
| launchActivityNoWait(LAUNCHING_ACTIVITY); |
| // Wait for the most front activity of the task. |
| mAmWmState.waitForValidState(ALT_LAUNCHING_ACTIVITY); |
| |
| // Ensure the alternate launching activity is still in focus. |
| mAmWmState.assertFocusedActivity("Alt Launching Activity must be focused", |
| ALT_LAUNCHING_ACTIVITY); |
| |
| pressBackButton(); |
| |
| // Wait for the bottom activity back to the foreground. |
| mAmWmState.waitForValidState(LAUNCHING_ACTIVITY); |
| |
| // Ensure launching activity was brought forward. |
| mAmWmState.assertFocusedActivity("Launching Activity must be focused", |
| LAUNCHING_ACTIVITY); |
| } |
| |
| /** |
| * Asserts that a nohistory activity is stopped and removed immediately after a resumed activity |
| * above becomes visible and does not idle. |
| */ |
| @Test |
| public void testNoHistoryActivityFinishedResumedActivityNotIdle() throws Exception { |
| if (!hasHomeScreen()) { |
| return; |
| } |
| |
| // Start with home on top |
| launchHomeActivity(); |
| |
| // Launch no history activity |
| launchActivity(NO_HISTORY_ACTIVITY); |
| |
| // Launch an activity with a swipe refresh layout configured to prevent idle. |
| launchActivity(SWIPE_REFRESH_ACTIVITY); |
| |
| pressBackButton(); |
| mAmWmState.waitForHomeActivityVisible(); |
| mAmWmState.assertHomeActivityVisible(true); |
| } |
| |
| @Test |
| public void testTurnScreenOnAttrNoLockScreen() throws Exception { |
| try (final LockScreenSession lockScreenSession = new LockScreenSession()) { |
| lockScreenSession.disableLockScreen() |
| .sleepDevice(); |
| final LogSeparator logSeparator = separateLogs(); |
| launchActivity(TURN_SCREEN_ON_ATTR_ACTIVITY); |
| mAmWmState.assertVisibility(TURN_SCREEN_ON_ATTR_ACTIVITY, true); |
| assertTrue("Display turns on", isDisplayOn()); |
| assertSingleLaunch(TURN_SCREEN_ON_ATTR_ACTIVITY, logSeparator); |
| } |
| } |
| |
| @Test |
| public void testTurnScreenOnAttrWithLockScreen() throws Exception { |
| if (!supportsSecureLock()) { |
| return; |
| } |
| |
| try (final LockScreenSession lockScreenSession = new LockScreenSession()) { |
| lockScreenSession.setLockCredential() |
| .sleepDevice(); |
| final LogSeparator logSeparator = separateLogs(); |
| launchActivityNoWait(TURN_SCREEN_ON_ATTR_ACTIVITY); |
| // Wait for the activity stopped because lock screen prevent showing the activity. |
| mAmWmState.waitForActivityState(TURN_SCREEN_ON_ATTR_ACTIVITY, STATE_STOPPED); |
| assertFalse("Display keeps off", isDisplayOn()); |
| assertSingleLaunchAndStop(TURN_SCREEN_ON_ATTR_ACTIVITY, logSeparator); |
| } |
| } |
| |
| @Test |
| public void testTurnScreenOnShowOnLockAttr() throws Exception { |
| try (final LockScreenSession lockScreenSession = new LockScreenSession()) { |
| lockScreenSession.sleepDevice(); |
| mAmWmState.waitForAllStoppedActivities(); |
| final LogSeparator logSeparator = separateLogs(); |
| launchActivity(TURN_SCREEN_ON_SHOW_ON_LOCK_ACTIVITY); |
| mAmWmState.assertVisibility(TURN_SCREEN_ON_SHOW_ON_LOCK_ACTIVITY, true); |
| assertTrue("Display turns on", isDisplayOn()); |
| assertSingleLaunch(TURN_SCREEN_ON_SHOW_ON_LOCK_ACTIVITY, logSeparator); |
| } |
| } |
| |
| @Test |
| public void testTurnScreenOnAttrRemove() throws Exception { |
| try (final LockScreenSession lockScreenSession = new LockScreenSession()) { |
| lockScreenSession.sleepDevice(); |
| mAmWmState.waitForAllStoppedActivities(); |
| LogSeparator logSeparator = separateLogs(); |
| launchActivity(TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY); |
| assertTrue("Display turns on", isDisplayOn()); |
| assertSingleLaunch(TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY, logSeparator); |
| |
| lockScreenSession.sleepDevice(); |
| mAmWmState.waitForAllStoppedActivities(); |
| logSeparator = separateLogs(); |
| launchActivity(TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY); |
| // Display should keep off, because setTurnScreenOn(false) has been called at |
| // {@link TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY}'s onStop. |
| assertFalse("Display keeps off", isDisplayOn()); |
| assertSingleStartAndStop(TURN_SCREEN_ON_ATTR_REMOVE_ATTR_ACTIVITY, logSeparator); |
| } |
| } |
| |
| @Test |
| @Presubmit |
| public void testTurnScreenOnSingleTask() throws Exception { |
| try (final LockScreenSession lockScreenSession = new LockScreenSession()) { |
| lockScreenSession.sleepDevice(); |
| LogSeparator logSeparator = separateLogs(); |
| launchActivity(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY); |
| mAmWmState.assertVisibility(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY, true); |
| assertTrue("Display turns on", isDisplayOn()); |
| assertSingleLaunch(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY, logSeparator); |
| |
| lockScreenSession.sleepDevice(); |
| logSeparator = separateLogs(); |
| launchActivity(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY); |
| mAmWmState.assertVisibility(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY, true); |
| assertTrue("Display turns on", isDisplayOn()); |
| assertSingleStart(TURN_SCREEN_ON_SINGLE_TASK_ACTIVITY, logSeparator); |
| } |
| } |
| |
| @Test |
| public void testTurnScreenOnActivity_withRelayout() throws Exception { |
| try (final LockScreenSession lockScreenSession = new LockScreenSession()) { |
| lockScreenSession.sleepDevice(); |
| launchActivity(TURN_SCREEN_ON_WITH_RELAYOUT_ACTIVITY); |
| mAmWmState.assertVisibility(TURN_SCREEN_ON_WITH_RELAYOUT_ACTIVITY, true); |
| |
| lockScreenSession.sleepDevice(); |
| mAmWmState.waitForActivityState(TURN_SCREEN_ON_WITH_RELAYOUT_ACTIVITY, STATE_STOPPED); |
| |
| // Ensure there was an actual stop if the waitFor timed out. |
| assertTrue(getActivityName(TURN_SCREEN_ON_WITH_RELAYOUT_ACTIVITY) + " stopped", |
| mAmWmState.getAmState().hasActivityState( |
| TURN_SCREEN_ON_WITH_RELAYOUT_ACTIVITY, STATE_STOPPED)); |
| assertFalse("Display keeps off", isDisplayOn()); |
| } |
| } |
| } |