Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 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 |
Tadashi G. Takaoka | b6e148c | 2018-11-03 02:59:06 -0700 | [diff] [blame] | 14 | * limitations under the License. |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 15 | */ |
| 16 | |
| 17 | package com.android.server.wm; |
| 18 | |
Louis Chang | 6c5d725 | 2020-03-30 15:42:01 +0800 | [diff] [blame] | 19 | import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; |
| 20 | import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM; |
| 21 | import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; |
| 22 | import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; |
Wale Ogunwale | 44f036f | 2017-09-29 05:09:09 -0700 | [diff] [blame] | 23 | import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; |
Louis Chang | 6c5d725 | 2020-03-30 15:42:01 +0800 | [diff] [blame] | 24 | import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; |
| 25 | import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; |
| 26 | import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; |
Wale Ogunwale | 6827856 | 2017-09-23 17:13:55 -0700 | [diff] [blame] | 27 | import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; |
Louis Chang | 6c5d725 | 2020-03-30 15:42:01 +0800 | [diff] [blame] | 28 | import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; |
| 29 | import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; |
| 30 | import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; |
Brett Chabot | a26eda9 | 2018-07-23 13:08:30 -0700 | [diff] [blame] | 31 | |
lumark | d0b5c8f | 2019-09-29 11:30:37 +0800 | [diff] [blame] | 32 | import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; |
| 33 | import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; |
| 34 | |
Tadashi G. Takaoka | c98f682 | 2018-10-11 17:11:49 +0900 | [diff] [blame] | 35 | import static com.google.common.truth.Truth.assertThat; |
| 36 | |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 37 | import static org.junit.Assert.assertEquals; |
| 38 | import static org.junit.Assert.assertFalse; |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 39 | import static org.junit.Assert.assertTrue; |
Louis Chang | 6c5d725 | 2020-03-30 15:42:01 +0800 | [diff] [blame] | 40 | import static org.mockito.ArgumentMatchers.any; |
| 41 | import static org.mockito.ArgumentMatchers.anyBoolean; |
| 42 | import static org.mockito.ArgumentMatchers.anyInt; |
Chris Li | ae1617f | 2020-05-20 16:21:42 -0700 | [diff] [blame] | 43 | import static org.mockito.ArgumentMatchers.eq; |
| 44 | import static org.mockito.Mockito.never; |
| 45 | import static org.mockito.Mockito.verify; |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 46 | |
Brett Chabot | a26eda9 | 2018-07-23 13:08:30 -0700 | [diff] [blame] | 47 | import android.platform.test.annotations.Presubmit; |
| 48 | |
Tadashi G. Takaoka | b6e148c | 2018-11-03 02:59:06 -0700 | [diff] [blame] | 49 | import androidx.test.filters.SmallTest; |
| 50 | |
Brett Chabot | a26eda9 | 2018-07-23 13:08:30 -0700 | [diff] [blame] | 51 | import org.junit.After; |
| 52 | import org.junit.Before; |
Wale Ogunwale | 44f036f | 2017-09-29 05:09:09 -0700 | [diff] [blame] | 53 | import org.junit.Test; |
Riddle Hsu | 73f5357 | 2019-09-23 23:13:01 +0800 | [diff] [blame] | 54 | import org.junit.runner.RunWith; |
Tadashi G. Takaoka | c8f2c14 | 2018-10-11 16:30:28 +0900 | [diff] [blame] | 55 | |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 56 | /** |
Andrii Kulian | 44b3c56 | 2020-04-01 12:49:56 -0700 | [diff] [blame] | 57 | * Tests for the {@link TaskDisplayArea} container. |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 58 | * |
| 59 | * Build/Install/Run: |
Andrii Kulian | 44b3c56 | 2020-04-01 12:49:56 -0700 | [diff] [blame] | 60 | * atest WmTests:TaskDisplayAreaTests |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 61 | */ |
| 62 | @SmallTest |
| 63 | @Presubmit |
Riddle Hsu | 73f5357 | 2019-09-23 23:13:01 +0800 | [diff] [blame] | 64 | @RunWith(WindowTestRunner.class) |
Andrii Kulian | 86d676c | 2020-03-27 19:34:54 -0700 | [diff] [blame] | 65 | public class TaskDisplayAreaTests extends WindowTestsBase { |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 66 | |
Wale Ogunwale | bebd8cd | 2019-10-28 15:53:31 -0700 | [diff] [blame] | 67 | private ActivityStack mPinnedStack; |
Wale Ogunwale | 1666e31 | 2016-12-16 11:27:18 -0800 | [diff] [blame] | 68 | |
| 69 | @Before |
| 70 | public void setUp() throws Exception { |
Yunfan Chen | 279f558 | 2018-12-12 15:24:50 -0800 | [diff] [blame] | 71 | mPinnedStack = createTaskStackOnDisplay( |
| 72 | WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, mDisplayContent); |
Wale Ogunwale | 1666e31 | 2016-12-16 11:27:18 -0800 | [diff] [blame] | 73 | // Stack should contain visible app window to be considered visible. |
| 74 | final Task pinnedTask = createTaskInStack(mPinnedStack, 0 /* userId */); |
| 75 | assertFalse(mPinnedStack.isVisible()); |
Wale Ogunwale | 3198da4 | 2019-10-10 14:45:03 +0200 | [diff] [blame] | 76 | final ActivityRecord pinnedApp = |
Garfield Tan | e8d84ab | 2019-10-11 09:49:40 -0700 | [diff] [blame] | 77 | WindowTestUtils.createTestActivityRecord(mDisplayContent); |
Wale Ogunwale | 1666e31 | 2016-12-16 11:27:18 -0800 | [diff] [blame] | 78 | pinnedTask.addChild(pinnedApp, 0 /* addPos */); |
| 79 | assertTrue(mPinnedStack.isVisible()); |
| 80 | } |
| 81 | |
| 82 | @After |
| 83 | public void tearDown() throws Exception { |
| 84 | mPinnedStack.removeImmediately(); |
| 85 | } |
| 86 | |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 87 | @Test |
Chris Li | ae1617f | 2020-05-20 16:21:42 -0700 | [diff] [blame] | 88 | public void testActivityWithZBoost_taskDisplayAreaDoesNotMoveUp() { |
| 89 | final ActivityStack stack = createTaskStackOnDisplay( |
| 90 | WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, mDisplayContent); |
| 91 | final Task task = createTaskInStack(stack, 0 /* userId */); |
| 92 | final ActivityRecord activity = WindowTestUtils.createTestActivityRecord(mDisplayContent); |
| 93 | task.addChild(activity, 0 /* addPos */); |
| 94 | final TaskDisplayArea taskDisplayArea = activity.getDisplayArea(); |
| 95 | activity.mNeedsAnimationBoundsLayer = true; |
| 96 | activity.mNeedsZBoost = true; |
| 97 | spyOn(taskDisplayArea.mSurfaceAnimator); |
| 98 | |
| 99 | mDisplayContent.assignChildLayers(mTransaction); |
| 100 | |
| 101 | assertThat(activity.needsZBoost()).isTrue(); |
| 102 | assertThat(taskDisplayArea.needsZBoost()).isFalse(); |
| 103 | verify(taskDisplayArea.mSurfaceAnimator, never()).setLayer(eq(mTransaction), anyInt()); |
| 104 | } |
| 105 | |
| 106 | @Test |
Tadashi G. Takaoka | c98f682 | 2018-10-11 17:11:49 +0900 | [diff] [blame] | 107 | public void testStackPositionChildAt() { |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 108 | // Test that always-on-top stack can't be moved to position other than top. |
Louis Chang | dc07727 | 2019-11-12 16:52:56 +0800 | [diff] [blame] | 109 | final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); |
| 110 | final ActivityStack stack2 = createTaskStackOnDisplay(mDisplayContent); |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 111 | |
| 112 | final WindowContainer taskStackContainer = stack1.getParent(); |
| 113 | |
| 114 | final int stack1Pos = taskStackContainer.mChildren.indexOf(stack1); |
| 115 | final int stack2Pos = taskStackContainer.mChildren.indexOf(stack2); |
Wale Ogunwale | 1666e31 | 2016-12-16 11:27:18 -0800 | [diff] [blame] | 116 | final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedStack); |
Tadashi G. Takaoka | c98f682 | 2018-10-11 17:11:49 +0900 | [diff] [blame] | 117 | assertThat(pinnedStackPos).isGreaterThan(stack2Pos); |
| 118 | assertThat(stack2Pos).isGreaterThan(stack1Pos); |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 119 | |
Wale Ogunwale | 1666e31 | 2016-12-16 11:27:18 -0800 | [diff] [blame] | 120 | taskStackContainer.positionChildAt(WindowContainer.POSITION_BOTTOM, mPinnedStack, false); |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 121 | assertEquals(taskStackContainer.mChildren.get(stack1Pos), stack1); |
| 122 | assertEquals(taskStackContainer.mChildren.get(stack2Pos), stack2); |
Wale Ogunwale | 1666e31 | 2016-12-16 11:27:18 -0800 | [diff] [blame] | 123 | assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedStack); |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 124 | |
Wale Ogunwale | 1666e31 | 2016-12-16 11:27:18 -0800 | [diff] [blame] | 125 | taskStackContainer.positionChildAt(1, mPinnedStack, false); |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 126 | assertEquals(taskStackContainer.mChildren.get(stack1Pos), stack1); |
| 127 | assertEquals(taskStackContainer.mChildren.get(stack2Pos), stack2); |
Wale Ogunwale | 1666e31 | 2016-12-16 11:27:18 -0800 | [diff] [blame] | 128 | assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedStack); |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 129 | } |
Wale Ogunwale | 1666e31 | 2016-12-16 11:27:18 -0800 | [diff] [blame] | 130 | |
Andrii Kulian | cd5dcb8b | 2017-01-03 17:09:45 -0800 | [diff] [blame] | 131 | @Test |
Tadashi G. Takaoka | c98f682 | 2018-10-11 17:11:49 +0900 | [diff] [blame] | 132 | public void testStackPositionBelowPinnedStack() { |
Andrii Kulian | cd5dcb8b | 2017-01-03 17:09:45 -0800 | [diff] [blame] | 133 | // Test that no stack can be above pinned stack. |
Louis Chang | dc07727 | 2019-11-12 16:52:56 +0800 | [diff] [blame] | 134 | final ActivityStack stack1 = createTaskStackOnDisplay(mDisplayContent); |
Andrii Kulian | cd5dcb8b | 2017-01-03 17:09:45 -0800 | [diff] [blame] | 135 | |
| 136 | final WindowContainer taskStackContainer = stack1.getParent(); |
| 137 | |
| 138 | final int stackPos = taskStackContainer.mChildren.indexOf(stack1); |
Wale Ogunwale | 1666e31 | 2016-12-16 11:27:18 -0800 | [diff] [blame] | 139 | final int pinnedStackPos = taskStackContainer.mChildren.indexOf(mPinnedStack); |
Tadashi G. Takaoka | c98f682 | 2018-10-11 17:11:49 +0900 | [diff] [blame] | 140 | assertThat(pinnedStackPos).isGreaterThan(stackPos); |
Andrii Kulian | cd5dcb8b | 2017-01-03 17:09:45 -0800 | [diff] [blame] | 141 | |
| 142 | taskStackContainer.positionChildAt(WindowContainer.POSITION_TOP, stack1, false); |
| 143 | assertEquals(taskStackContainer.mChildren.get(stackPos), stack1); |
Wale Ogunwale | 1666e31 | 2016-12-16 11:27:18 -0800 | [diff] [blame] | 144 | assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedStack); |
Andrii Kulian | cd5dcb8b | 2017-01-03 17:09:45 -0800 | [diff] [blame] | 145 | |
| 146 | taskStackContainer.positionChildAt(taskStackContainer.mChildren.size() - 1, stack1, false); |
| 147 | assertEquals(taskStackContainer.mChildren.get(stackPos), stack1); |
Wale Ogunwale | 1666e31 | 2016-12-16 11:27:18 -0800 | [diff] [blame] | 148 | assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), mPinnedStack); |
Andrii Kulian | cd5dcb8b | 2017-01-03 17:09:45 -0800 | [diff] [blame] | 149 | } |
Riddle Hsu | 2f6e174 | 2018-08-23 22:44:36 +0800 | [diff] [blame] | 150 | |
| 151 | @Test |
| 152 | public void testDisplayPositionWithPinnedStack() { |
Charles Chen | b28fb72 | 2020-05-21 17:19:32 +0800 | [diff] [blame] | 153 | // Make sure the display is trusted display which capable to move the stack to top. |
lumark | d0b5c8f | 2019-09-29 11:30:37 +0800 | [diff] [blame] | 154 | spyOn(mDisplayContent); |
Charles Chen | b28fb72 | 2020-05-21 17:19:32 +0800 | [diff] [blame] | 155 | doReturn(true).when(mDisplayContent).isTrusted(); |
lumark | d0b5c8f | 2019-09-29 11:30:37 +0800 | [diff] [blame] | 156 | |
Riddle Hsu | 2f6e174 | 2018-08-23 22:44:36 +0800 | [diff] [blame] | 157 | // The display contains pinned stack that was added in {@link #setUp}. |
Wale Ogunwale | bebd8cd | 2019-10-28 15:53:31 -0700 | [diff] [blame] | 158 | final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent); |
Riddle Hsu | 2f6e174 | 2018-08-23 22:44:36 +0800 | [diff] [blame] | 159 | final Task task = createTaskInStack(stack, 0 /* userId */); |
| 160 | |
| 161 | // Add another display at top. |
Tadashi G. Takaoka | b6e148c | 2018-11-03 02:59:06 -0700 | [diff] [blame] | 162 | mWm.mRoot.positionChildAt(WindowContainer.POSITION_TOP, createNewDisplay(), |
Riddle Hsu | 2f6e174 | 2018-08-23 22:44:36 +0800 | [diff] [blame] | 163 | false /* includingParents */); |
| 164 | |
| 165 | // Move the task of {@code mDisplayContent} to top. |
Louis Chang | cdec080 | 2019-11-11 11:45:07 +0800 | [diff] [blame] | 166 | stack.positionChildAt(WindowContainer.POSITION_TOP, task, true /* includingParents */); |
Tadashi G. Takaoka | b6e148c | 2018-11-03 02:59:06 -0700 | [diff] [blame] | 167 | final int indexOfDisplayWithPinnedStack = mWm.mRoot.mChildren.indexOf(mDisplayContent); |
Riddle Hsu | 2f6e174 | 2018-08-23 22:44:36 +0800 | [diff] [blame] | 168 | |
| 169 | assertEquals("The testing DisplayContent should be moved to top with task", |
Tadashi G. Takaoka | b6e148c | 2018-11-03 02:59:06 -0700 | [diff] [blame] | 170 | mWm.mRoot.getChildCount() - 1, indexOfDisplayWithPinnedStack); |
Riddle Hsu | 2f6e174 | 2018-08-23 22:44:36 +0800 | [diff] [blame] | 171 | } |
Louis Chang | 6c5d725 | 2020-03-30 15:42:01 +0800 | [diff] [blame] | 172 | |
| 173 | @Test |
| 174 | public void testReuseTaskAsStack() { |
| 175 | final Task candidateTask = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, |
| 176 | ACTIVITY_TYPE_STANDARD, mDisplayContent); |
| 177 | final Task newStack = createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, |
| 178 | ACTIVITY_TYPE_STANDARD, mDisplayContent); |
Andrii Kulian | 44b3c56 | 2020-04-01 12:49:56 -0700 | [diff] [blame] | 179 | final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea(); |
| 180 | doReturn(newStack).when(taskDisplayArea).createStack(anyInt(), anyInt(), anyBoolean(), |
| 181 | any(), any(), anyBoolean()); |
Louis Chang | 6c5d725 | 2020-03-30 15:42:01 +0800 | [diff] [blame] | 182 | |
| 183 | final int type = ACTIVITY_TYPE_STANDARD; |
| 184 | assertGetOrCreateStack(WINDOWING_MODE_FULLSCREEN, type, candidateTask, |
| 185 | true /* reuseCandidate */); |
| 186 | assertGetOrCreateStack(WINDOWING_MODE_UNDEFINED, type, candidateTask, |
| 187 | true /* reuseCandidate */); |
| 188 | assertGetOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, type, candidateTask, |
| 189 | true /* reuseCandidate */); |
| 190 | assertGetOrCreateStack(WINDOWING_MODE_FREEFORM, type, candidateTask, |
| 191 | true /* reuseCandidate */); |
| 192 | assertGetOrCreateStack(WINDOWING_MODE_MULTI_WINDOW, type, candidateTask, |
| 193 | true /* reuseCandidate */); |
| 194 | assertGetOrCreateStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, type, candidateTask, |
| 195 | false /* reuseCandidate */); |
| 196 | assertGetOrCreateStack(WINDOWING_MODE_PINNED, type, candidateTask, |
Evan Rosky | 688c838 | 2020-04-03 17:27:08 -0700 | [diff] [blame] | 197 | true /* reuseCandidate */); |
Louis Chang | 6c5d725 | 2020-03-30 15:42:01 +0800 | [diff] [blame] | 198 | |
| 199 | final int windowingMode = WINDOWING_MODE_FULLSCREEN; |
| 200 | assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_HOME, candidateTask, |
| 201 | false /* reuseCandidate */); |
| 202 | assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_RECENTS, candidateTask, |
| 203 | false /* reuseCandidate */); |
| 204 | assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_ASSISTANT, candidateTask, |
| 205 | false /* reuseCandidate */); |
| 206 | assertGetOrCreateStack(windowingMode, ACTIVITY_TYPE_DREAM, candidateTask, |
| 207 | false /* reuseCandidate */); |
| 208 | } |
| 209 | |
| 210 | private void assertGetOrCreateStack(int windowingMode, int activityType, Task candidateTask, |
| 211 | boolean reuseCandidate) { |
Andrii Kulian | 44b3c56 | 2020-04-01 12:49:56 -0700 | [diff] [blame] | 212 | final TaskDisplayArea taskDisplayArea = candidateTask.getDisplayArea(); |
Louis Chang | 6c5d725 | 2020-03-30 15:42:01 +0800 | [diff] [blame] | 213 | final ActivityStack stack = taskDisplayArea.getOrCreateStack(windowingMode, activityType, |
| 214 | false /* onTop */, null /* intent */, candidateTask /* candidateTask */); |
| 215 | assertEquals(reuseCandidate, stack == candidateTask); |
| 216 | } |
Andrii Kulian | d276563 | 2016-12-12 22:26:34 -0800 | [diff] [blame] | 217 | } |