blob: 39e788530eaeac9520467bd6b267b4a433be9fa7 [file] [log] [blame]
Garfield Tan9b1efea2017-12-05 16:43:46 -08001/*
Wale Ogunwale59507092018-10-29 09:00:30 -07002 * Copyright (C) 2018 The Android Open Source Project
Garfield Tan9b1efea2017-12-05 16:43:46 -08003 *
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
Wale Ogunwale59507092018-10-29 09:00:30 -070014 * limitations under the License
Garfield Tan9b1efea2017-12-05 16:43:46 -080015 */
16
Wale Ogunwale59507092018-10-29 09:00:30 -070017package com.android.server.wm;
Garfield Tan9b1efea2017-12-05 16:43:46 -080018
Andrii Kulian39f27442019-06-26 19:09:19 -070019import static android.app.ActivityTaskManager.INVALID_TASK_ID;
Evan Rosky1ac84462018-11-13 11:25:30 -080020import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
21import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
22import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
Bryce Lee1a990e52018-04-23 10:54:11 -070023import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
24import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
Andrii Kulian39f27442019-06-26 19:09:19 -070025import static android.content.pm.ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
Evan Rosky730f6e82018-12-03 17:40:11 -080026import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
27import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
28import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
Riddle Hsu88e3c8732019-02-18 19:15:12 +080029import static android.util.DisplayMetrics.DENSITY_DEFAULT;
Garfield Tana3f19032019-11-19 18:04:50 -080030import static android.view.IWindowManager.FIXED_TO_USER_ROTATION_ENABLED;
Riddle Hsu61987bc2019-04-03 13:08:47 +080031import static android.view.Surface.ROTATION_0;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070032import static android.view.Surface.ROTATION_90;
Evan Rosky730f6e82018-12-03 17:40:11 -080033
Riddle Hsu61987bc2019-04-03 13:08:47 +080034import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
35import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
Andrii Kulian39f27442019-06-26 19:09:19 -070036import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
37import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
38import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070039import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
Bryce Lee1a990e52018-04-23 10:54:11 -070040
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070041import static com.google.common.truth.Truth.assertThat;
42
Riddle Hsu2f9acd22018-11-06 23:44:43 +080043import static org.hamcrest.Matchers.not;
44import static org.hamcrest.Matchers.sameInstance;
Garfield Tan367b35a2017-12-13 12:16:21 -080045import static org.junit.Assert.assertEquals;
Garfield Tan9b1efea2017-12-05 16:43:46 -080046import static org.junit.Assert.assertFalse;
Evan Rosky70213702019-11-05 10:26:24 -080047import static org.junit.Assert.assertNotEquals;
Garfield Tan9b1efea2017-12-05 16:43:46 -080048import static org.junit.Assert.assertNotNull;
Andrii Kulian39f27442019-06-26 19:09:19 -070049import static org.junit.Assert.assertNull;
Riddle Hsu2f9acd22018-11-06 23:44:43 +080050import static org.junit.Assert.assertThat;
Garfield Tan9b1efea2017-12-05 16:43:46 -080051import static org.junit.Assert.assertTrue;
Riddle Hsu61987bc2019-04-03 13:08:47 +080052import static org.mockito.ArgumentMatchers.any;
Riddle Hsu74826262019-04-17 14:57:42 +080053import static org.mockito.ArgumentMatchers.anyInt;
Garfield Tan49dae102019-02-04 09:51:59 -080054import static org.mockito.Mockito.mock;
Garfield Tan9b1efea2017-12-05 16:43:46 -080055
56import android.app.ActivityManager;
Mark Renoufc808f062019-02-07 15:20:37 -050057import android.app.TaskInfo;
Garfield Tan9b1efea2017-12-05 16:43:46 -080058import android.content.ComponentName;
59import android.content.Intent;
60import android.content.pm.ActivityInfo;
Louis Chang96c7b832018-12-27 09:27:53 +080061import android.content.pm.ApplicationInfo;
Evan Rosky1ac84462018-11-13 11:25:30 -080062import android.content.res.Configuration;
Garfield Tan367b35a2017-12-13 12:16:21 -080063import android.graphics.Rect;
Andrii Kulian39f27442019-06-26 19:09:19 -070064import android.os.IBinder;
Garfield Tan9b1efea2017-12-05 16:43:46 -080065import android.platform.test.annotations.Presubmit;
66import android.service.voice.IVoiceInteractionSession;
Evan Rosky60dba2f2019-02-01 10:58:38 -080067import android.util.DisplayMetrics;
Garfield Tan367b35a2017-12-13 12:16:21 -080068import android.util.Xml;
Evan Rosky1ac84462018-11-13 11:25:30 -080069import android.view.DisplayInfo;
Garfield Tan9b1efea2017-12-05 16:43:46 -080070
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070071import androidx.test.filters.FlakyTest;
Brett Chabota26eda92018-07-23 13:08:30 -070072import androidx.test.filters.MediumTest;
Brett Chabota26eda92018-07-23 13:08:30 -070073
Garfield Tan9b1efea2017-12-05 16:43:46 -080074import com.android.internal.app.IVoiceInteractor;
Louis Changcdec0802019-11-11 11:45:07 +080075import com.android.server.wm.Task.TaskFactory;
Riddle Hsu74826262019-04-17 14:57:42 +080076import com.android.server.wm.utils.WmDisplayCutout;
Garfield Tan9b1efea2017-12-05 16:43:46 -080077
78import org.junit.Before;
79import org.junit.Test;
Riddle Hsu73f53572019-09-23 23:13:01 +080080import org.junit.runner.RunWith;
Garfield Tan9b1efea2017-12-05 16:43:46 -080081import org.xmlpull.v1.XmlPullParser;
82import org.xmlpull.v1.XmlPullParserException;
Garfield Tan367b35a2017-12-13 12:16:21 -080083import org.xmlpull.v1.XmlSerializer;
Garfield Tan9b1efea2017-12-05 16:43:46 -080084
Tadashi G. Takaoka88df5c32018-11-21 16:33:57 +090085import java.io.ByteArrayInputStream;
86import java.io.ByteArrayOutputStream;
Garfield Tan9b1efea2017-12-05 16:43:46 -080087import java.io.IOException;
Tadashi G. Takaoka88df5c32018-11-21 16:33:57 +090088import java.io.InputStreamReader;
Garfield Tan367b35a2017-12-13 12:16:21 -080089import java.io.Reader;
Garfield Tan9b1efea2017-12-05 16:43:46 -080090
91/**
Louis Changcdec0802019-11-11 11:45:07 +080092 * Tests for exercising {@link Task}.
Garfield Tan9b1efea2017-12-05 16:43:46 -080093 *
94 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090095 * atest WmTests:TaskRecordTests
Garfield Tan9b1efea2017-12-05 16:43:46 -080096 */
97@MediumTest
98@Presubmit
Riddle Hsu73f53572019-09-23 23:13:01 +080099@RunWith(WindowTestRunner.class)
Garfield Tan367b35a2017-12-13 12:16:21 -0800100public class TaskRecordTests extends ActivityTestsBase {
101
102 private static final String TASK_TAG = "task";
103
Evan Rosky1ac84462018-11-13 11:25:30 -0800104 private Rect mParentBounds;
105
Garfield Tan9b1efea2017-12-05 16:43:46 -0800106 @Before
107 public void setUp() throws Exception {
Louis Changcdec0802019-11-11 11:45:07 +0800108 Task.setTaskFactory(null);
Evan Rosky1ac84462018-11-13 11:25:30 -0800109 mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700110 removeGlobalMinSizeRestriction();
Garfield Tan367b35a2017-12-13 12:16:21 -0800111 }
112
113 @Test
114 public void testRestoreWindowedTask() throws Exception {
Louis Changcdec0802019-11-11 11:45:07 +0800115 final Task expected = createTask(64);
Garfield Tan367b35a2017-12-13 12:16:21 -0800116 expected.mLastNonFullscreenBounds = new Rect(50, 50, 100, 100);
117
Tadashi G. Takaoka88df5c32018-11-21 16:33:57 +0900118 final byte[] serializedBytes = serializeToBytes(expected);
Louis Changcdec0802019-11-11 11:45:07 +0800119 final Task actual = restoreFromBytes(serializedBytes);
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700120 assertEquals(expected.mTaskId, actual.mTaskId);
Tadashi G. Takaoka88df5c32018-11-21 16:33:57 +0900121 assertEquals(expected.mLastNonFullscreenBounds, actual.mLastNonFullscreenBounds);
Garfield Tan9b1efea2017-12-05 16:43:46 -0800122 }
123
124 @Test
125 public void testDefaultTaskFactoryNotNull() throws Exception {
Louis Changcdec0802019-11-11 11:45:07 +0800126 assertNotNull(Task.getTaskFactory());
Garfield Tan9b1efea2017-12-05 16:43:46 -0800127 }
128
Riddle Hsu2f9acd22018-11-06 23:44:43 +0800129 /** Ensure we have no chance to modify the original intent. */
130 @Test
131 public void testCopyBaseIntentForTaskInfo() {
Louis Changcdec0802019-11-11 11:45:07 +0800132 final Task task = createTask(1);
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200133 task.setTaskDescription(new ActivityManager.TaskDescription());
Mark Renoufc808f062019-02-07 15:20:37 -0500134 final TaskInfo info = task.getTaskInfo();
Riddle Hsu2f9acd22018-11-06 23:44:43 +0800135
136 // The intent of info should be a copy so assert that they are different instances.
137 assertThat(info.baseIntent, not(sameInstance(task.getBaseIntent())));
138 }
139
Garfield Tan9b1efea2017-12-05 16:43:46 -0800140 @Test
141 public void testCreateTestRecordUsingCustomizedFactory() throws Exception {
Louis Changcdec0802019-11-11 11:45:07 +0800142 TestTaskFactory factory = new TestTaskFactory();
143 Task.setTaskFactory(factory);
Garfield Tan9b1efea2017-12-05 16:43:46 -0800144
145 assertFalse(factory.mCreated);
146
Louis Changcdec0802019-11-11 11:45:07 +0800147 Task.create(null, 0, null, null, null, null);
Garfield Tan9b1efea2017-12-05 16:43:46 -0800148
149 assertTrue(factory.mCreated);
150 }
151
Bryce Lee1a990e52018-04-23 10:54:11 -0700152 @Test
153 public void testReturnsToHomeStack() throws Exception {
Louis Changcdec0802019-11-11 11:45:07 +0800154 final Task task = createTask(1);
Bryce Lee1a990e52018-04-23 10:54:11 -0700155 assertFalse(task.returnsToHomeStack());
156 task.intent = null;
157 assertFalse(task.returnsToHomeStack());
158 task.intent = new Intent();
159 assertFalse(task.returnsToHomeStack());
160 task.intent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME);
161 assertTrue(task.returnsToHomeStack());
162 }
163
Evan Rosky70213702019-11-05 10:26:24 -0800164 /** Ensures that empty bounds cause appBounds to inherit from parent. */
Evan Rosky1ac84462018-11-13 11:25:30 -0800165 @Test
166 public void testAppBounds_EmptyBounds() {
167 final Rect emptyBounds = new Rect();
168 testStackBoundsConfiguration(WINDOWING_MODE_FULLSCREEN, mParentBounds, emptyBounds,
Evan Rosky70213702019-11-05 10:26:24 -0800169 mParentBounds);
Evan Rosky1ac84462018-11-13 11:25:30 -0800170 }
171
172 /** Ensures that bounds on freeform stacks are not clipped. */
173 @Test
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700174 @FlakyTest(bugId = 137879065)
Evan Rosky1ac84462018-11-13 11:25:30 -0800175 public void testAppBounds_FreeFormBounds() {
176 final Rect freeFormBounds = new Rect(mParentBounds);
177 freeFormBounds.offset(10, 10);
178 testStackBoundsConfiguration(WINDOWING_MODE_FREEFORM, mParentBounds, freeFormBounds,
179 freeFormBounds);
180 }
181
182 /** Ensures that fully contained bounds are not clipped. */
183 @Test
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700184 @FlakyTest(bugId = 137879065)
Evan Rosky1ac84462018-11-13 11:25:30 -0800185 public void testAppBounds_ContainedBounds() {
186 final Rect insetBounds = new Rect(mParentBounds);
187 insetBounds.inset(5, 5, 5, 5);
188 testStackBoundsConfiguration(
Evan Rosky730f6e82018-12-03 17:40:11 -0800189 WINDOWING_MODE_FREEFORM, mParentBounds, insetBounds, insetBounds);
Evan Rosky1ac84462018-11-13 11:25:30 -0800190 }
191
Evan Rosky60dba2f2019-02-01 10:58:38 -0800192 @Test
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700193 @FlakyTest(bugId = 137879065)
Evan Rosky60dba2f2019-02-01 10:58:38 -0800194 public void testFitWithinBounds() {
195 final Rect parentBounds = new Rect(10, 10, 200, 200);
196 ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
197 ActivityStack stack = display.createStack(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD,
198 true /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800199 Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
Evan Rosky60dba2f2019-02-01 10:58:38 -0800200 final Configuration parentConfig = stack.getConfiguration();
201 parentConfig.windowConfiguration.setBounds(parentBounds);
202 parentConfig.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
203
204 // check top and left
205 Rect reqBounds = new Rect(-190, -190, 0, 0);
206 task.setBounds(reqBounds);
207 // Make sure part of it is exposed
208 assertTrue(task.getBounds().right > parentBounds.left);
209 assertTrue(task.getBounds().bottom > parentBounds.top);
210 // Should still be more-or-less in that corner
211 assertTrue(task.getBounds().left <= parentBounds.left);
212 assertTrue(task.getBounds().top <= parentBounds.top);
213
214 assertEquals(reqBounds.width(), task.getBounds().width());
215 assertEquals(reqBounds.height(), task.getBounds().height());
216
217 // check bottom and right
218 reqBounds = new Rect(210, 210, 400, 400);
219 task.setBounds(reqBounds);
220 // Make sure part of it is exposed
221 assertTrue(task.getBounds().left < parentBounds.right);
222 assertTrue(task.getBounds().top < parentBounds.bottom);
223 // Should still be more-or-less in that corner
224 assertTrue(task.getBounds().right >= parentBounds.right);
225 assertTrue(task.getBounds().bottom >= parentBounds.bottom);
226
227 assertEquals(reqBounds.width(), task.getBounds().width());
228 assertEquals(reqBounds.height(), task.getBounds().height());
229 }
230
Evan Rosky730f6e82018-12-03 17:40:11 -0800231 /** Tests that the task bounds adjust properly to changes between FULLSCREEN and FREEFORM */
Evan Rosky1ac84462018-11-13 11:25:30 -0800232 @Test
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700233 @FlakyTest(bugId = 137879065)
Evan Rosky730f6e82018-12-03 17:40:11 -0800234 public void testBoundsOnModeChangeFreeformToFullscreen() {
Evan Rosky1ac84462018-11-13 11:25:30 -0800235 ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
Evan Rosky730f6e82018-12-03 17:40:11 -0800236 ActivityStack stack = new StackBuilder(mRootActivityContainer).setDisplay(display)
237 .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900238 Task task = stack.getBottomMostTask();
Wale Ogunwaleda8b8272018-11-29 19:37:37 -0800239 task.getRootActivity().setOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
Evan Rosky1ac84462018-11-13 11:25:30 -0800240 DisplayInfo info = new DisplayInfo();
241 display.mDisplay.getDisplayInfo(info);
242 final Rect fullScreenBounds = new Rect(0, 0, info.logicalWidth, info.logicalHeight);
Evan Rosky730f6e82018-12-03 17:40:11 -0800243 final Rect freeformBounds = new Rect(fullScreenBounds);
244 freeformBounds.inset((int) (freeformBounds.width() * 0.2),
245 (int) (freeformBounds.height() * 0.2));
246 task.setBounds(freeformBounds);
247
248 assertEquals(freeformBounds, task.getBounds());
249
250 // FULLSCREEN inherits bounds
251 stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
252 assertEquals(fullScreenBounds, task.getBounds());
253 assertEquals(freeformBounds, task.mLastNonFullscreenBounds);
254
255 // FREEFORM restores bounds
256 stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
257 assertEquals(freeformBounds, task.getBounds());
258 }
259
260 /**
Evan Rosky730f6e82018-12-03 17:40:11 -0800261 * Tests that a task with forced orientation has orientation-consistent bounds within the
262 * parent.
263 */
264 @Test
265 public void testFullscreenBoundsForcedOrientation() {
266 final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
267 final Rect fullScreenBoundsPort = new Rect(0, 0, 1080, 1920);
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700268 ActivityDisplay display = new TestActivityDisplay.Builder(
269 mService, fullScreenBounds.width(), fullScreenBounds.height()).build();
Evan Rosky730f6e82018-12-03 17:40:11 -0800270 assertTrue(mRootActivityContainer.getActivityDisplay(display.mDisplayId) != null);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700271 // Fix the display orientation to landscape which is the natural rotation (0) for the test
272 // display.
273 final DisplayRotation dr = display.mDisplayContent.getDisplayRotation();
274 dr.setFixedToUserRotation(FIXED_TO_USER_ROTATION_ENABLED);
275 dr.setUserRotation(USER_ROTATION_FREE, ROTATION_0);
276
Evan Rosky730f6e82018-12-03 17:40:11 -0800277 ActivityStack stack = new StackBuilder(mRootActivityContainer)
278 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900279 Task task = stack.getBottomMostTask();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800280 ActivityRecord root = task.getTopNonFinishingActivity();
Evan Rosky730f6e82018-12-03 17:40:11 -0800281
282 assertEquals(fullScreenBounds, task.getBounds());
283
284 // Setting app to fixed portrait fits within parent
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700285 root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
Evan Rosky730f6e82018-12-03 17:40:11 -0800286 assertEquals(root, task.getRootActivity());
287 assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700288 assertThat(task.getBounds().width()).isLessThan(task.getBounds().height());
Evan Rosky730f6e82018-12-03 17:40:11 -0800289 assertEquals(fullScreenBounds.height(), task.getBounds().height());
290
Evan Rosky130d94f2019-01-15 10:18:17 -0800291 // Top activity gets used
292 ActivityRecord top = new ActivityBuilder(mService).setTask(task).setStack(stack).build();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800293 assertEquals(top, task.getTopNonFinishingActivity());
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700294 top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
295 assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
Evan Rosky130d94f2019-01-15 10:18:17 -0800296 assertEquals(task.getBounds().width(), fullScreenBounds.width());
Evan Rosky730f6e82018-12-03 17:40:11 -0800297
298 // Setting app to unspecified restores
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700299 top.setRequestedOrientation(SCREEN_ORIENTATION_UNSPECIFIED);
Evan Rosky730f6e82018-12-03 17:40:11 -0800300 assertEquals(fullScreenBounds, task.getBounds());
301
302 // Setting app to fixed landscape and changing display
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700303 top.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
304 // Fix the display orientation to portrait which is 90 degrees for the test display.
305 dr.setUserRotation(USER_ROTATION_FREE, ROTATION_90);
306
307 assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
Evan Rosky730f6e82018-12-03 17:40:11 -0800308 assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
309
310 // in FREEFORM, no constraint
311 final Rect freeformBounds = new Rect(display.getBounds());
312 freeformBounds.inset((int) (freeformBounds.width() * 0.2),
313 (int) (freeformBounds.height() * 0.2));
314 stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
315 task.setBounds(freeformBounds);
316 assertEquals(freeformBounds, task.getBounds());
317
318 // FULLSCREEN letterboxes bounds
319 stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700320 assertThat(task.getBounds().width()).isGreaterThan(task.getBounds().height());
Evan Rosky730f6e82018-12-03 17:40:11 -0800321 assertEquals(fullScreenBoundsPort.width(), task.getBounds().width());
322
323 // FREEFORM restores bounds as before
324 stack.setWindowingMode(WINDOWING_MODE_FREEFORM);
325 assertEquals(freeformBounds, task.getBounds());
Evan Rosky1ac84462018-11-13 11:25:30 -0800326 }
327
Yunfan Chenf93c06f2019-01-17 07:01:49 +0000328 @Test
Garfield Tan49dae102019-02-04 09:51:59 -0800329 public void testIgnoresForcedOrientationWhenParentHandles() {
330 final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
Evan Rosky4a51dbc02019-09-11 17:28:07 -0700331 ActivityDisplay display = new TestActivityDisplay.Builder(
332 mService, fullScreenBounds.width(), fullScreenBounds.height()).build();
Yunfan Chenf93c06f2019-01-17 07:01:49 +0000333
Garfield Tan49dae102019-02-04 09:51:59 -0800334 display.getRequestedOverrideConfiguration().orientation =
335 Configuration.ORIENTATION_LANDSCAPE;
336 display.onRequestedOverrideConfigurationChanged(
337 display.getRequestedOverrideConfiguration());
338 ActivityStack stack = new StackBuilder(mRootActivityContainer)
Yunfan Chenf93c06f2019-01-17 07:01:49 +0000339 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900340 Task task = stack.getBottomMostTask();
Wale Ogunwale21e06482019-11-18 05:14:15 -0800341 ActivityRecord root = task.getTopNonFinishingActivity();
Yunfan Chenf93c06f2019-01-17 07:01:49 +0000342
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200343 final WindowContainer parentWindowContainer =
344 new WindowContainer(mSystemServicesTestRule.getWindowManagerService());
345 spyOn(parentWindowContainer);
346 parentWindowContainer.setBounds(fullScreenBounds);
347 doReturn(parentWindowContainer).when(task).getParent();
348 doReturn(true).when(parentWindowContainer).handlesOrientationChangeFromDescendant();
Yunfan Chenf93c06f2019-01-17 07:01:49 +0000349
Louis Changcdec0802019-11-11 11:45:07 +0800350 // Setting app to fixed portrait fits within parent, but Task shouldn't adjust the
Garfield Tan49dae102019-02-04 09:51:59 -0800351 // bounds because its parent says it will handle it at a later time.
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700352 root.setRequestedOrientation(SCREEN_ORIENTATION_PORTRAIT);
Garfield Tan49dae102019-02-04 09:51:59 -0800353 assertEquals(root, task.getRootActivity());
354 assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
355 assertEquals(fullScreenBounds, task.getBounds());
Yunfan Chenf93c06f2019-01-17 07:01:49 +0000356 }
357
Riddle Hsu88e3c8732019-02-18 19:15:12 +0800358 @Test
359 public void testComputeConfigResourceOverrides() {
Louis Changcdec0802019-11-11 11:45:07 +0800360 final Task task = new TaskBuilder(mSupervisor).build();
Riddle Hsu88e3c8732019-02-18 19:15:12 +0800361 final Configuration inOutConfig = new Configuration();
362 final Configuration parentConfig = new Configuration();
363 final int longSide = 1200;
364 final int shortSide = 600;
365 parentConfig.densityDpi = 400;
366 parentConfig.screenHeightDp = 200; // 200 * 400 / 160 = 500px
367 parentConfig.screenWidthDp = 100; // 100 * 400 / 160 = 250px
Riddle Hsu61987bc2019-04-03 13:08:47 +0800368 parentConfig.windowConfiguration.setRotation(ROTATION_0);
Riddle Hsu88e3c8732019-02-18 19:15:12 +0800369
370 // Portrait bounds.
371 inOutConfig.windowConfiguration.getBounds().set(0, 0, shortSide, longSide);
372 // By default, the parent bounds should limit the existing input bounds.
373 task.computeConfigResourceOverrides(inOutConfig, parentConfig);
374
375 assertEquals(parentConfig.screenHeightDp, inOutConfig.screenHeightDp);
376 assertEquals(parentConfig.screenWidthDp, inOutConfig.screenWidthDp);
377 assertEquals(Configuration.ORIENTATION_PORTRAIT, inOutConfig.orientation);
378
379 inOutConfig.setToDefaults();
380 // Landscape bounds.
381 inOutConfig.windowConfiguration.getBounds().set(0, 0, longSide, shortSide);
Riddle Hsu61987bc2019-04-03 13:08:47 +0800382
383 // Setup the display with a top stable inset. The later assertion will ensure the inset is
384 // excluded from screenHeightDp.
385 final int statusBarHeight = 100;
386 final DisplayContent displayContent = mock(DisplayContent.class);
387 final DisplayPolicy policy = mock(DisplayPolicy.class);
388 doAnswer(invocationOnMock -> {
389 final Rect insets = invocationOnMock.<Rect>getArgument(0);
390 insets.top = statusBarHeight;
391 return null;
392 }).when(policy).convertNonDecorInsetsToStableInsets(any(), eq(ROTATION_0));
393 doReturn(policy).when(displayContent).getDisplayPolicy();
Riddle Hsu74826262019-04-17 14:57:42 +0800394 doReturn(mock(WmDisplayCutout.class)).when(displayContent)
395 .calculateDisplayCutoutForRotation(anyInt());
Riddle Hsu61987bc2019-04-03 13:08:47 +0800396
Riddle Hsu88e3c8732019-02-18 19:15:12 +0800397 // Without limiting to be inside the parent bounds, the out screen size should keep relative
398 // to the input bounds.
Riddle Hsu61987bc2019-04-03 13:08:47 +0800399 final ActivityRecord.CompatDisplayInsets compatIntsets =
Evan Rosky72f084d2019-09-11 17:05:16 -0700400 new ActivityRecord.CompatDisplayInsets(displayContent, new Rect(0, 0,
401 displayContent.mBaseDisplayWidth, displayContent.mBaseDisplayHeight),
402 false);
Riddle Hsu61987bc2019-04-03 13:08:47 +0800403 task.computeConfigResourceOverrides(inOutConfig, parentConfig, compatIntsets);
Riddle Hsu88e3c8732019-02-18 19:15:12 +0800404
Riddle Hsu61987bc2019-04-03 13:08:47 +0800405 assertEquals((shortSide - statusBarHeight) * DENSITY_DEFAULT / parentConfig.densityDpi,
Riddle Hsu88e3c8732019-02-18 19:15:12 +0800406 inOutConfig.screenHeightDp);
407 assertEquals(longSide * DENSITY_DEFAULT / parentConfig.densityDpi,
408 inOutConfig.screenWidthDp);
409 assertEquals(Configuration.ORIENTATION_LANDSCAPE, inOutConfig.orientation);
410 }
411
Evan Rosky70213702019-11-05 10:26:24 -0800412 @Test
413 public void testComputeNestedConfigResourceOverrides() {
414 final Task task = new TaskBuilder(mSupervisor).build();
415 assertTrue(task.getResolvedOverrideBounds().isEmpty());
416 int origScreenH = task.getConfiguration().screenHeightDp;
417 Configuration stackConfig = new Configuration();
418 stackConfig.setTo(task.getStack().getRequestedOverrideConfiguration());
419 stackConfig.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
420
421 // Set bounds on stack (not task) and verify that the task resource configuration changes
422 // despite it's override bounds being empty.
423 Rect bounds = new Rect(task.getStack().getBounds());
424 bounds.bottom = (int) (bounds.bottom * 0.6f);
425 stackConfig.windowConfiguration.setBounds(bounds);
426 task.getStack().onRequestedOverrideConfigurationChanged(stackConfig);
427 assertNotEquals(origScreenH, task.getConfiguration().screenHeightDp);
428 }
429
Louis Chang96c7b832018-12-27 09:27:53 +0800430 /** Ensures that the alias intent won't have target component resolved. */
431 @Test
432 public void testTaskIntentActivityAlias() {
Louis Chang23df1a62019-01-09 15:10:49 +0800433 final String aliasClassName = DEFAULT_COMPONENT_PACKAGE_NAME + ".aliasActivity";
434 final String targetClassName = DEFAULT_COMPONENT_PACKAGE_NAME + ".targetActivity";
435 final ComponentName aliasComponent =
436 new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, aliasClassName);
437 final ComponentName targetComponent =
438 new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, targetClassName);
439
Louis Chang96c7b832018-12-27 09:27:53 +0800440 final Intent intent = new Intent();
Louis Chang23df1a62019-01-09 15:10:49 +0800441 intent.setComponent(aliasComponent);
Louis Chang96c7b832018-12-27 09:27:53 +0800442 final ActivityInfo info = new ActivityInfo();
443 info.applicationInfo = new ApplicationInfo();
444 info.packageName = DEFAULT_COMPONENT_PACKAGE_NAME;
Louis Chang23df1a62019-01-09 15:10:49 +0800445 info.targetActivity = targetClassName;
Louis Chang96c7b832018-12-27 09:27:53 +0800446
Louis Changcdec0802019-11-11 11:45:07 +0800447 final Task task = Task.create(mService, 1 /* taskId */, info, intent,
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200448 null /* taskDescription */, null /*stack*/);
Louis Chang23df1a62019-01-09 15:10:49 +0800449 assertEquals("The alias activity component should be saved in task intent.", aliasClassName,
Louis Chang96c7b832018-12-27 09:27:53 +0800450 task.intent.getComponent().getClassName());
Louis Chang23df1a62019-01-09 15:10:49 +0800451
452 ActivityRecord aliasActivity = new ActivityBuilder(mService).setComponent(
453 aliasComponent).setTargetActivity(targetClassName).build();
454 assertEquals("Should be the same intent filter.", true,
455 task.isSameIntentFilter(aliasActivity));
456
457 ActivityRecord targetActivity = new ActivityBuilder(mService).setComponent(
458 targetComponent).build();
459 assertEquals("Should be the same intent filter.", true,
460 task.isSameIntentFilter(targetActivity));
461
462 ActivityRecord defaultActivity = new ActivityBuilder(mService).build();
463 assertEquals("Should not be the same intent filter.", false,
464 task.isSameIntentFilter(defaultActivity));
Louis Chang96c7b832018-12-27 09:27:53 +0800465 }
466
Andrii Kulian39f27442019-06-26 19:09:19 -0700467 /** Test that root activity index is reported correctly for several activities in the task. */
468 @Test
469 public void testFindRootIndex() {
Louis Changcdec0802019-11-11 11:45:07 +0800470 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700471 // Add an extra activity on top of the root one
472 new ActivityBuilder(mService).setTask(task).build();
473
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800474 assertEquals("The root activity in the task must be reported.", task.getChildAt(0),
475 task.getRootActivity(
476 true /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
Andrii Kulian39f27442019-06-26 19:09:19 -0700477 }
478
479 /**
480 * Test that root activity index is reported correctly for several activities in the task when
481 * the activities on the bottom are finishing.
482 */
483 @Test
484 public void testFindRootIndex_finishing() {
Louis Changcdec0802019-11-11 11:45:07 +0800485 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700486 // Add extra two activities and mark the two on the bottom as finishing.
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800487 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700488 activity0.finishing = true;
489 final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
490 activity1.finishing = true;
491 new ActivityBuilder(mService).setTask(task).build();
492
493 assertEquals("The first non-finishing activity in the task must be reported.",
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800494 task.getChildAt(2), task.getRootActivity(
495 true /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
Andrii Kulian39f27442019-06-26 19:09:19 -0700496 }
497
498 /**
499 * Test that root activity index is reported correctly for several activities in the task when
500 * looking for the 'effective root'.
501 */
502 @Test
503 public void testFindRootIndex_effectiveRoot() {
Louis Changcdec0802019-11-11 11:45:07 +0800504 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700505 // Add an extra activity on top of the root one
506 new ActivityBuilder(mService).setTask(task).build();
507
508 assertEquals("The root activity in the task must be reported.",
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800509 task.getChildAt(0), task.getRootActivity(
510 false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
Andrii Kulian39f27442019-06-26 19:09:19 -0700511 }
512
513 /**
514 * Test that root activity index is reported correctly when looking for the 'effective root' in
515 * case when bottom activities are relinquishing task identity or finishing.
516 */
517 @Test
518 public void testFindRootIndex_effectiveRoot_finishingAndRelinquishing() {
Louis Changcdec0802019-11-11 11:45:07 +0800519 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700520 // Add extra two activities. Mark the one on the bottom with "relinquishTaskIdentity" and
521 // one above as finishing.
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800522 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700523 activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
524 final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
525 activity1.finishing = true;
526 new ActivityBuilder(mService).setTask(task).build();
527
528 assertEquals("The first non-finishing activity and non-relinquishing task identity "
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800529 + "must be reported.", task.getChildAt(2), task.getRootActivity(
530 false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
Andrii Kulian39f27442019-06-26 19:09:19 -0700531 }
532
533 /**
534 * Test that root activity index is reported correctly when looking for the 'effective root'
535 * for the case when there is only a single activity that also has relinquishTaskIdentity set.
536 */
537 @Test
538 public void testFindRootIndex_effectiveRoot_relinquishingAndSingleActivity() {
Louis Changcdec0802019-11-11 11:45:07 +0800539 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700540 // Set relinquishTaskIdentity for the only activity in the task
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800541 task.getBottomMostActivity().info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
Andrii Kulian39f27442019-06-26 19:09:19 -0700542
543 assertEquals("The root activity in the task must be reported.",
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800544 task.getChildAt(0), task.getRootActivity(
545 false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
Andrii Kulian39f27442019-06-26 19:09:19 -0700546 }
547
548 /**
549 * Test that the topmost activity index is reported correctly when looking for the
550 * 'effective root' for the case when all activities have relinquishTaskIdentity set.
551 */
552 @Test
553 public void testFindRootIndex_effectiveRoot_relinquishingMultipleActivities() {
Louis Changcdec0802019-11-11 11:45:07 +0800554 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700555 // Set relinquishTaskIdentity for all activities in the task
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800556 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700557 activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
558 final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
559 activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
560
561 assertEquals("The topmost activity in the task must be reported.",
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800562 task.getChildAt(task.getChildCount() - 1), task.getRootActivity(
563 false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/));
Andrii Kulian39f27442019-06-26 19:09:19 -0700564 }
565
Louis Changcdec0802019-11-11 11:45:07 +0800566 /** Test that bottom-most activity is reported in {@link Task#getRootActivity()}. */
Andrii Kulian39f27442019-06-26 19:09:19 -0700567 @Test
568 public void testGetRootActivity() {
Louis Changcdec0802019-11-11 11:45:07 +0800569 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700570 // Add an extra activity on top of the root one
571 new ActivityBuilder(mService).setTask(task).build();
572
573 assertEquals("The root activity in the task must be reported.",
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800574 task.getBottomMostActivity(), task.getRootActivity());
Andrii Kulian39f27442019-06-26 19:09:19 -0700575 }
576
577 /**
Louis Changcdec0802019-11-11 11:45:07 +0800578 * Test that first non-finishing activity is reported in {@link Task#getRootActivity()}.
Andrii Kulian39f27442019-06-26 19:09:19 -0700579 */
580 @Test
581 public void testGetRootActivity_finishing() {
Louis Changcdec0802019-11-11 11:45:07 +0800582 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700583 // Add an extra activity on top of the root one
584 new ActivityBuilder(mService).setTask(task).build();
585 // Mark the root as finishing
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800586 task.getBottomMostActivity().finishing = true;
Andrii Kulian39f27442019-06-26 19:09:19 -0700587
588 assertEquals("The first non-finishing activity in the task must be reported.",
589 task.getChildAt(1), task.getRootActivity());
590 }
591
592 /**
Louis Changcdec0802019-11-11 11:45:07 +0800593 * Test that relinquishTaskIdentity flag is ignored in {@link Task#getRootActivity()}.
Andrii Kulian39f27442019-06-26 19:09:19 -0700594 */
595 @Test
596 public void testGetRootActivity_relinquishTaskIdentity() {
Louis Changcdec0802019-11-11 11:45:07 +0800597 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700598 // Mark the bottom-most activity with FLAG_RELINQUISH_TASK_IDENTITY.
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800599 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700600 activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
601 // Add an extra activity on top of the root one.
602 new ActivityBuilder(mService).setTask(task).build();
603
604 assertEquals("The root activity in the task must be reported.",
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800605 task.getBottomMostActivity(), task.getRootActivity());
Andrii Kulian39f27442019-06-26 19:09:19 -0700606 }
607
608 /**
Louis Changcdec0802019-11-11 11:45:07 +0800609 * Test that no activity is reported in {@link Task#getRootActivity()} when all activities
Andrii Kulian39f27442019-06-26 19:09:19 -0700610 * in the task are finishing.
611 */
612 @Test
613 public void testGetRootActivity_allFinishing() {
Louis Changcdec0802019-11-11 11:45:07 +0800614 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700615 // Mark the bottom-most activity as finishing.
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800616 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700617 activity0.finishing = true;
618 // Add an extra activity on top of the root one and mark it as finishing
619 final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
620 activity1.finishing = true;
621
622 assertNull("No activity must be reported if all are finishing", task.getRootActivity());
623 }
624
625 /**
626 * Test that first non-finishing activity is the root of task.
627 */
628 @Test
629 public void testIsRootActivity() {
Louis Changcdec0802019-11-11 11:45:07 +0800630 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700631 // Mark the bottom-most activity as finishing.
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800632 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700633 activity0.finishing = true;
634 // Add an extra activity on top of the root one.
635 final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
636
637 assertFalse("Finishing activity must not be the root of task", activity0.isRootOfTask());
638 assertTrue("Non-finishing activity must be the root of task", activity1.isRootOfTask());
639 }
640
641 /**
642 * Test that if all activities in the task are finishing, then the one on the bottom is the
643 * root of task.
644 */
645 @Test
646 public void testIsRootActivity_allFinishing() {
Louis Changcdec0802019-11-11 11:45:07 +0800647 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700648 // Mark the bottom-most activity as finishing.
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800649 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700650 activity0.finishing = true;
651 // Add an extra activity on top of the root one and mark it as finishing
652 final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
653 activity1.finishing = true;
654
655 assertTrue("Bottom activity must be the root of task", activity0.isRootOfTask());
656 assertFalse("Finishing activity on top must not be the root of task",
657 activity1.isRootOfTask());
658 }
659
660 /**
661 * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)}.
662 */
663 @Test
664 public void testGetTaskForActivity() {
Louis Changcdec0802019-11-11 11:45:07 +0800665 final Task task0 = getTestTask();
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800666 final ActivityRecord activity0 = task0.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700667
Louis Changcdec0802019-11-11 11:45:07 +0800668 final Task task1 = getTestTask();
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800669 final ActivityRecord activity1 = task1.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700670
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700671 assertEquals(task0.mTaskId,
Andrii Kulian39f27442019-06-26 19:09:19 -0700672 ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700673 assertEquals(task1.mTaskId,
Andrii Kulian39f27442019-06-26 19:09:19 -0700674 ActivityRecord.getTaskForActivityLocked(activity1.appToken, false /* onlyRoot */));
675 }
676
677 /**
678 * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with finishing
679 * activity.
680 */
681 @Test
682 public void testGetTaskForActivity_onlyRoot_finishing() {
Louis Changcdec0802019-11-11 11:45:07 +0800683 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700684 // Make the current root activity finishing
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800685 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700686 activity0.finishing = true;
687 // Add an extra activity on top - this will be the new root
688 final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
689 // Add one more on top
690 final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
691
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700692 assertEquals(task.mTaskId,
Andrii Kulian39f27442019-06-26 19:09:19 -0700693 ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700694 assertEquals(task.mTaskId,
Andrii Kulian39f27442019-06-26 19:09:19 -0700695 ActivityRecord.getTaskForActivityLocked(activity1.appToken, true /* onlyRoot */));
696 assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
697 ActivityRecord.getTaskForActivityLocked(activity2.appToken, true /* onlyRoot */));
698 }
699
700 /**
701 * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with activity that
702 * relinquishes task identity.
703 */
704 @Test
705 public void testGetTaskForActivity_onlyRoot_relinquishTaskIdentity() {
Louis Changcdec0802019-11-11 11:45:07 +0800706 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700707 // Make the current root activity relinquish task identity
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800708 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700709 activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
710 // Add an extra activity on top - this will be the new root
711 final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
712 // Add one more on top
713 final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
714
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700715 assertEquals(task.mTaskId,
Andrii Kulian39f27442019-06-26 19:09:19 -0700716 ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */));
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700717 assertEquals(task.mTaskId,
Andrii Kulian39f27442019-06-26 19:09:19 -0700718 ActivityRecord.getTaskForActivityLocked(activity1.appToken, true /* onlyRoot */));
719 assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID,
720 ActivityRecord.getTaskForActivityLocked(activity2.appToken, true /* onlyRoot */));
721 }
722
723 /**
724 * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} allowing non-root
725 * entries.
726 */
727 @Test
728 public void testGetTaskForActivity_notOnlyRoot() {
Louis Changcdec0802019-11-11 11:45:07 +0800729 final Task task = getTestTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700730 // Mark the bottom-most activity as finishing.
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800731 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700732 activity0.finishing = true;
733
734 // Add an extra activity on top of the root one and make it relinquish task identity
735 final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
736 activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY;
737
738 // Add one more activity on top
739 final ActivityRecord activity2 = new ActivityBuilder(mService).setTask(task).build();
740
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700741 assertEquals(task.mTaskId,
Andrii Kulian39f27442019-06-26 19:09:19 -0700742 ActivityRecord.getTaskForActivityLocked(activity0.appToken, false /* onlyRoot */));
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700743 assertEquals(task.mTaskId,
Andrii Kulian39f27442019-06-26 19:09:19 -0700744 ActivityRecord.getTaskForActivityLocked(activity1.appToken, false /* onlyRoot */));
Wale Ogunwale4e79a1c2019-10-05 20:52:40 -0700745 assertEquals(task.mTaskId,
Andrii Kulian39f27442019-06-26 19:09:19 -0700746 ActivityRecord.getTaskForActivityLocked(activity2.appToken, false /* onlyRoot */));
747 }
748
749 /**
Louis Changcdec0802019-11-11 11:45:07 +0800750 * Test {@link Task#updateEffectiveIntent()}.
Andrii Kulian39f27442019-06-26 19:09:19 -0700751 */
752 @Test
753 public void testUpdateEffectiveIntent() {
754 // Test simple case with a single activity.
Louis Changcdec0802019-11-11 11:45:07 +0800755 final Task task = getTestTask();
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800756 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700757
758 spyOn(task);
759 task.updateEffectiveIntent();
760 verify(task).setIntent(eq(activity0));
761 }
762
763 /**
Louis Changcdec0802019-11-11 11:45:07 +0800764 * Test {@link Task#updateEffectiveIntent()} with root activity marked as finishing. This
Andrii Kulian39f27442019-06-26 19:09:19 -0700765 * should make the task use the second activity when updating the intent.
766 */
767 @Test
768 public void testUpdateEffectiveIntent_rootFinishing() {
769 // Test simple case with a single activity.
Louis Changcdec0802019-11-11 11:45:07 +0800770 final Task task = getTestTask();
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800771 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700772 // Mark the bottom-most activity as finishing.
773 activity0.finishing = true;
774 // Add an extra activity on top of the root one
775 final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
776
777 spyOn(task);
778 task.updateEffectiveIntent();
779 verify(task).setIntent(eq(activity1));
780 }
781
782 /**
Louis Changcdec0802019-11-11 11:45:07 +0800783 * Test {@link Task#updateEffectiveIntent()} when all activities are finishing or
Andrii Kulian39f27442019-06-26 19:09:19 -0700784 * relinquishing task identity. In this case the root activity should still be used when
785 * updating the intent (legacy behavior).
786 */
787 @Test
788 public void testUpdateEffectiveIntent_allFinishing() {
789 // Test simple case with a single activity.
Louis Changcdec0802019-11-11 11:45:07 +0800790 final Task task = getTestTask();
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800791 final ActivityRecord activity0 = task.getBottomMostActivity();
Andrii Kulian39f27442019-06-26 19:09:19 -0700792 // Mark the bottom-most activity as finishing.
793 activity0.finishing = true;
794 // Add an extra activity on top of the root one and make it relinquish task identity
795 final ActivityRecord activity1 = new ActivityBuilder(mService).setTask(task).build();
796 activity1.finishing = true;
797
798 // Task must still update the intent using the root activity (preserving legacy behavior).
799 spyOn(task);
800 task.updateEffectiveIntent();
801 verify(task).setIntent(eq(activity0));
802 }
803
Louis Changcdec0802019-11-11 11:45:07 +0800804 private Task getTestTask() {
Andrii Kulian39f27442019-06-26 19:09:19 -0700805 final ActivityStack stack = new StackBuilder(mRootActivityContainer).build();
Wale Ogunwale85fb19a2019-12-05 10:41:05 +0900806 return stack.getBottomMostTask();
Andrii Kulian39f27442019-06-26 19:09:19 -0700807 }
808
Evan Rosky1ac84462018-11-13 11:25:30 -0800809 private void testStackBoundsConfiguration(int windowingMode, Rect parentBounds, Rect bounds,
810 Rect expectedConfigBounds) {
811
812 ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
813 ActivityStack stack = display.createStack(windowingMode, ACTIVITY_TYPE_STANDARD,
814 true /* onTop */);
Louis Changcdec0802019-11-11 11:45:07 +0800815 Task task = new TaskBuilder(mSupervisor).setStack(stack).build();
Evan Rosky1ac84462018-11-13 11:25:30 -0800816
817 final Configuration parentConfig = stack.getConfiguration();
818 parentConfig.windowConfiguration.setAppBounds(parentBounds);
819 task.setBounds(bounds);
820
821 task.resolveOverrideConfiguration(parentConfig);
822 // Assert that both expected and actual are null or are equal to each other
823 assertEquals(expectedConfigBounds,
824 task.getResolvedOverrideConfiguration().windowConfiguration.getAppBounds());
825 }
826
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800827 private byte[] serializeToBytes(Task r) throws Exception {
Tadashi G. Takaoka88df5c32018-11-21 16:33:57 +0900828 try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
Garfield Tan367b35a2017-12-13 12:16:21 -0800829 final XmlSerializer serializer = Xml.newSerializer();
830 serializer.setOutput(os, "UTF-8");
831 serializer.startDocument(null, true);
832 serializer.startTag(null, TASK_TAG);
833 r.saveToXml(serializer);
834 serializer.endTag(null, TASK_TAG);
835 serializer.endDocument();
Garfield Tan367b35a2017-12-13 12:16:21 -0800836
Tadashi G. Takaoka88df5c32018-11-21 16:33:57 +0900837 os.flush();
838 return os.toByteArray();
839 }
Garfield Tan367b35a2017-12-13 12:16:21 -0800840 }
841
Louis Changcdec0802019-11-11 11:45:07 +0800842 private Task restoreFromBytes(byte[] in) throws IOException, XmlPullParserException {
Tadashi G. Takaoka88df5c32018-11-21 16:33:57 +0900843 try (Reader reader = new InputStreamReader(new ByteArrayInputStream(in))) {
Garfield Tan367b35a2017-12-13 12:16:21 -0800844 final XmlPullParser parser = Xml.newPullParser();
845 parser.setInput(reader);
846 assertEquals(XmlPullParser.START_TAG, parser.next());
847 assertEquals(TASK_TAG, parser.getName());
Louis Changcdec0802019-11-11 11:45:07 +0800848 return Task.restoreFromXml(parser, mService.mStackSupervisor);
Garfield Tan367b35a2017-12-13 12:16:21 -0800849 }
850 }
851
Louis Changcdec0802019-11-11 11:45:07 +0800852 private Task createTask(int taskId) {
853 return new Task(mService, taskId, new Intent(), null, null, null,
Kazuki Takisec2e17bf2018-07-17 17:46:38 +0900854 ActivityBuilder.getDefaultComponent(), null, false, false, false, 0, 10050, null,
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200855 0, false, null, 0, 0, 0, 0, 0, null, 0, false, false, false, 0,
856 0, null /*ActivityInfo*/, null /*_voiceSession*/, null /*_voiceInteractor*/,
857 null /*stack*/);
Garfield Tan367b35a2017-12-13 12:16:21 -0800858 }
859
Louis Changcdec0802019-11-11 11:45:07 +0800860 private static class TestTaskFactory extends TaskFactory {
Garfield Tan9b1efea2017-12-05 16:43:46 -0800861 private boolean mCreated = false;
862
863 @Override
Louis Changcdec0802019-11-11 11:45:07 +0800864 Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200865 Intent intent, IVoiceInteractionSession voiceSession,
866 IVoiceInteractor voiceInteractor, ActivityStack stack) {
Garfield Tan9b1efea2017-12-05 16:43:46 -0800867 mCreated = true;
868 return null;
869 }
870
871 @Override
Louis Changcdec0802019-11-11 11:45:07 +0800872 Task create(ActivityTaskManagerService service, int taskId, ActivityInfo info,
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200873 Intent intent, ActivityManager.TaskDescription taskDescription,
874 ActivityStack stack) {
Garfield Tan9b1efea2017-12-05 16:43:46 -0800875 mCreated = true;
876 return null;
877 }
878
879 @Override
Louis Changcdec0802019-11-11 11:45:07 +0800880 Task create(ActivityTaskManagerService service, int taskId, Intent intent,
Garfield Tan9b1efea2017-12-05 16:43:46 -0800881 Intent affinityIntent, String affinity, String rootAffinity,
882 ComponentName realActivity,
883 ComponentName origActivity, boolean rootWasReset, boolean autoRemoveRecents,
884 boolean askedCompatMode, int userId, int effectiveUid, String lastDescription,
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200885 long lastTimeMoved,
Garfield Tan9b1efea2017-12-05 16:43:46 -0800886 boolean neverRelinquishIdentity,
887 ActivityManager.TaskDescription lastTaskDescription,
888 int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
889 int callingUid, String callingPackage, int resizeMode,
890 boolean supportsPictureInPicture,
891 boolean realActivitySuspended, boolean userSetupComplete, int minWidth,
Wale Ogunwale2322bed2019-10-10 17:24:19 +0200892 int minHeight, ActivityStack stack) {
Garfield Tan9b1efea2017-12-05 16:43:46 -0800893 mCreated = true;
894 return null;
895 }
896
897 @Override
Louis Changcdec0802019-11-11 11:45:07 +0800898 Task restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
Garfield Tan9b1efea2017-12-05 16:43:46 -0800899 throws IOException, XmlPullParserException {
900 mCreated = true;
901 return null;
902 }
903 }
904}