blob: 673366f34fc2c8bc88b6a111604d93a5ab3d17a9 [file] [log] [blame]
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001/*
2 * Copyright (C) 2017 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
Wale Ogunwale59507092018-10-29 09:00:30 -070017package com.android.server.wm;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070018
Andrii Kulianab132ee2018-07-24 22:10:21 +080019import static android.app.ActivityTaskManager.INVALID_STACK_ID;
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -070020import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070021import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
22import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
23import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
Evan Roskye747c3e2018-10-30 20:06:41 -070024import static android.app.WindowConfiguration.ROTATION_UNDEFINED;
Wale Ogunwaleab5de372017-10-18 06:46:31 -070025import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070026import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
27import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
28import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
29import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
30import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
31import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Shivam Agrawal1d3db652019-07-01 15:26:11 -070032import static android.os.Build.VERSION_CODES.N;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070033import static android.view.Display.DEFAULT_DISPLAY;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070034import static android.view.Display.FLAG_PRIVATE;
35import static android.view.Display.REMOVE_MODE_DESTROY_CONTENT;
Louis Chang7d0037c2018-08-13 12:42:06 +080036
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -070037import static com.android.server.am.ActivityDisplayProto.CONFIGURATION_CONTAINER;
Andrii Kulianab132ee2018-07-24 22:10:21 +080038import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -070039import static com.android.server.am.ActivityDisplayProto.ID;
Andrii Kulianab132ee2018-07-24 22:10:21 +080040import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY;
Wale Ogunwale9e737db2018-12-17 15:42:37 -080041import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -070042import static com.android.server.am.ActivityDisplayProto.STACKS;
Wale Ogunwale59507092018-10-29 09:00:30 -070043import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070044import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
Andrii Kulian0c869cc2019-02-06 19:50:32 -080045import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
Wale Ogunwale59507092018-10-29 09:00:30 -070046import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
47import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
48import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
49import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
50import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
51import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
52import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
Adrian Roosb125e0b2019-10-02 14:55:14 +020053import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
Wale Ogunwaled32da472018-11-16 07:19:28 -080054import static com.android.server.wm.RootActivityContainer.FindTaskResult;
55import static com.android.server.wm.RootActivityContainer.TAG_STATES;
Wale Ogunwale3a256e62018-12-06 14:41:18 -080056import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
57import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070058
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -070059import android.annotation.Nullable;
Shivam Agrawal1d3db652019-07-01 15:26:11 -070060import android.app.ActivityManager;
61import android.app.ActivityManagerInternal;
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -070062import android.app.ActivityOptions;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070063import android.app.WindowConfiguration;
Shivam Agrawal1d3db652019-07-01 15:26:11 -070064import android.content.pm.ActivityInfo;
Evan Roskye747c3e2018-10-30 20:06:41 -070065import android.content.res.Configuration;
Bryce Leef3c6a472017-11-14 14:53:06 -080066import android.graphics.Point;
Wale Ogunwale3a256e62018-12-06 14:41:18 -080067import android.os.IBinder;
Shivam Agrawal1d3db652019-07-01 15:26:11 -070068import android.os.Message;
Louis Changbd48dca2018-08-29 17:44:34 +080069import android.os.UserHandle;
Shivam Agrawal1d3db652019-07-01 15:26:11 -070070import android.provider.Settings;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070071import android.util.IntArray;
72import android.util.Slog;
73import android.util.proto.ProtoOutputStream;
74import android.view.Display;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -070075
Wale Ogunwale04a05ac2017-09-17 21:35:02 -070076import com.android.internal.annotations.VisibleForTesting;
Shivam Agrawal1d3db652019-07-01 15:26:11 -070077import com.android.internal.util.function.pooled.PooledLambda;
Wale Ogunwale59507092018-10-29 09:00:30 -070078import com.android.server.am.EventLogTags;
Adrian Roosb125e0b2019-10-02 14:55:14 +020079import com.android.server.protolog.common.ProtoLog;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -070080
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -070081import java.io.PrintWriter;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070082import java.util.ArrayList;
83
84/**
85 * Exactly one of these classes per Display in the system. Capable of holding zero or more
86 * attached {@link ActivityStack}s.
87 */
Riddle Hsu5947c362019-09-23 18:52:36 +080088class ActivityDisplay extends ConfigurationContainer<ActivityStack> {
Wale Ogunwale98875612018-10-12 07:53:02 -070089 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityDisplay" : TAG_ATM;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -070090 private static final String TAG_STACK = TAG + POSTFIX_STACK;
91
92 static final int POSITION_TOP = Integer.MAX_VALUE;
93 static final int POSITION_BOTTOM = Integer.MIN_VALUE;
94
Bryce Leed9cce2c2017-12-04 16:16:27 -080095
96 /**
97 * Counter for next free stack ID to use for dynamic activity stacks. Unique across displays.
98 */
99 private static int sNextFreeStackId = 0;
100
Wale Ogunwaled32da472018-11-16 07:19:28 -0800101 private ActivityTaskManagerService mService;
102 private RootActivityContainer mRootActivityContainer;
Wale Ogunwale3a256e62018-12-06 14:41:18 -0800103 // TODO: Remove once unification is complete.
104 DisplayContent mDisplayContent;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700105 /** Actual Display this object tracks. */
106 int mDisplayId;
107 Display mDisplay;
108
Winson Chung0f7ec962018-05-03 18:03:15 -0700109 /**
110 * All of the stacks on this display. Order matters, topmost stack is in front of all other
111 * stacks, bottommost behind. Accessed directly by ActivityManager package classes. Any calls
112 * changing the list should also call {@link #onStackOrderChanged()}.
113 */
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700114 private final ArrayList<ActivityStack> mStacks = new ArrayList<>();
Winson Chung0f7ec962018-05-03 18:03:15 -0700115 private ArrayList<OnStackOrderChangedListener> mStackOrderChangedCallbacks = new ArrayList<>();
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700116
117 /** Array of all UIDs that are present on the display. */
118 private IntArray mDisplayAccessUIDs = new IntArray();
119
120 /** All tokens used to put activities on this stack to sleep (including mOffToken) */
Wale Ogunwale6767eae2018-05-03 15:52:51 -0700121 final ArrayList<ActivityTaskManagerInternal.SleepToken> mAllSleepTokens = new ArrayList<>();
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700122 /** The token acquired by ActivityStackSupervisor to put stacks on the display to sleep */
Wale Ogunwale6767eae2018-05-03 15:52:51 -0700123 ActivityTaskManagerInternal.SleepToken mOffToken;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700124
125 private boolean mSleeping;
126
Louis Chang7d0037c2018-08-13 12:42:06 +0800127 /**
128 * The display is removed from the system and we are just waiting for all activities on it to be
129 * finished before removing this object.
130 */
131 private boolean mRemoved;
132
Wale Ogunwale9e737db2018-12-17 15:42:37 -0800133 /** The display can only contain one task. */
134 private boolean mSingleTaskInstance;
135
Riddle Hsu75016992018-09-20 20:37:14 +0800136 /**
Riddle Hsu7b766fd2019-01-28 21:14:59 +0800137 * Non-null if the last size compatibility mode activity is using non-native screen
138 * configuration. The activity is not able to put in multi-window mode, so it exists only one
139 * per display.
140 */
141 private ActivityRecord mLastCompatModeActivity;
142
143 /**
Riddle Hsu75016992018-09-20 20:37:14 +0800144 * A focusable stack that is purposely to be positioned at the top. Although the stack may not
145 * have the topmost index, it is used as a preferred candidate to prevent being unable to resume
146 * target stack properly when there are other focusable always-on-top stacks.
147 */
148 private ActivityStack mPreferredTopFocusableStack;
149
Riddle Hsubbb63c22018-10-03 12:28:29 +0800150 /**
151 * If this is the same as {@link #getFocusedStack} then the activity on the top of the focused
152 * stack has been resumed. If stacks are changing position this will hold the old stack until
153 * the new stack becomes resumed after which it will be set to current focused stack.
154 */
155 private ActivityStack mLastFocusedStack;
156
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700157 // Cached reference to some special stacks we tend to get a lot so we don't need to loop
158 // through the list to find them.
159 private ActivityStack mHomeStack = null;
160 private ActivityStack mRecentsStack = null;
161 private ActivityStack mPinnedStack = null;
162 private ActivityStack mSplitScreenPrimaryStack = null;
163
Bryce Leef3c6a472017-11-14 14:53:06 -0800164 // Used in updating the display size
165 private Point mTmpDisplaySize = new Point();
166
Shivam Agrawal1d3db652019-07-01 15:26:11 -0700167 // Used in updating override configurations
168 private final Configuration mTempConfig = new Configuration();
169
Louis Changc85b1a32018-08-14 16:40:53 +0800170 private final FindTaskResult mTmpFindTaskResult = new FindTaskResult();
171
Wale Ogunwaled32da472018-11-16 07:19:28 -0800172 ActivityDisplay(RootActivityContainer root, Display display) {
173 mRootActivityContainer = root;
174 mService = root.mService;
Wale Ogunwale45477b52018-03-06 12:24:19 -0800175 mDisplayId = display.getDisplayId();
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700176 mDisplay = display;
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700177 mDisplayContent = mService.mWindowManager.mRoot.createDisplayContent(mDisplay, this);
Shivam Agrawal6472e0e2019-07-03 16:27:49 -0700178 mDisplayContent.reconfigureDisplayLocked();
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700179 onRequestedOverrideConfigurationChanged(
180 mDisplayContent.getRequestedOverrideConfiguration());
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700181 }
182
Riddle Hsuf53da812018-08-15 22:00:27 +0800183 void onDisplayChanged() {
184 // The window policy is responsible for stopping activities on the default display.
185 final int displayId = mDisplay.getDisplayId();
186 if (displayId != DEFAULT_DISPLAY) {
187 final int displayState = mDisplay.getState();
188 if (displayState == Display.STATE_OFF && mOffToken == null) {
Wale Ogunwaled32da472018-11-16 07:19:28 -0800189 mOffToken = mService.acquireSleepToken("Display-off", displayId);
Riddle Hsuf53da812018-08-15 22:00:27 +0800190 } else if (displayState == Display.STATE_ON && mOffToken != null) {
191 mOffToken.release();
192 mOffToken = null;
193 }
194 }
195
Wale Ogunwale8a1860a2019-06-05 08:57:19 -0700196 mDisplay.getRealSize(mTmpDisplaySize);
197 setBounds(0, 0, mTmpDisplaySize.x, mTmpDisplaySize.y);
Wale Ogunwale3a256e62018-12-06 14:41:18 -0800198 if (mDisplayContent != null) {
199 mDisplayContent.updateDisplayInfo();
200 mService.mWindowManager.requestTraversal();
201 }
Riddle Hsuf53da812018-08-15 22:00:27 +0800202 }
203
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700204 void addChild(ActivityStack stack, int position) {
205 if (position == POSITION_BOTTOM) {
206 position = 0;
207 } else if (position == POSITION_TOP) {
208 position = mStacks.size();
209 }
210 if (DEBUG_STACK) Slog.v(TAG_STACK, "addChild: attaching " + stack
211 + " to displayId=" + mDisplayId + " position=" + position);
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700212 addStackReferenceIfNeeded(stack);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700213 positionChildAt(stack, position);
Wale Ogunwaled32da472018-11-16 07:19:28 -0800214 mService.updateSleepIfNeededLocked();
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700215 }
216
217 void removeChild(ActivityStack stack) {
218 if (DEBUG_STACK) Slog.v(TAG_STACK, "removeChild: detaching " + stack
219 + " from displayId=" + mDisplayId);
220 mStacks.remove(stack);
Riddle Hsu75016992018-09-20 20:37:14 +0800221 if (mPreferredTopFocusableStack == stack) {
222 mPreferredTopFocusableStack = null;
223 }
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700224 removeStackReferenceIfNeeded(stack);
Louis Chang7d0037c2018-08-13 12:42:06 +0800225 releaseSelfIfNeeded();
Wale Ogunwaled32da472018-11-16 07:19:28 -0800226 mService.updateSleepIfNeededLocked();
Winson Chung65d66d32018-12-13 17:48:39 -0800227 onStackOrderChanged(stack);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700228 }
229
Riddle Hsu57831b52018-07-27 00:31:48 +0800230 void positionChildAtTop(ActivityStack stack, boolean includingParents) {
Riddle Hsubbb63c22018-10-03 12:28:29 +0800231 positionChildAtTop(stack, includingParents, null /* updateLastFocusedStackReason */);
232 }
233
234 void positionChildAtTop(ActivityStack stack, boolean includingParents,
235 String updateLastFocusedStackReason) {
236 positionChildAt(stack, mStacks.size(), includingParents, updateLastFocusedStackReason);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700237 }
238
239 void positionChildAtBottom(ActivityStack stack) {
Riddle Hsubbb63c22018-10-03 12:28:29 +0800240 positionChildAtBottom(stack, null /* updateLastFocusedStackReason */);
241 }
242
243 void positionChildAtBottom(ActivityStack stack, String updateLastFocusedStackReason) {
244 positionChildAt(stack, 0, false /* includingParents */, updateLastFocusedStackReason);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700245 }
246
247 private void positionChildAt(ActivityStack stack, int position) {
Riddle Hsubbb63c22018-10-03 12:28:29 +0800248 positionChildAt(stack, position, false /* includingParents */,
249 null /* updateLastFocusedStackReason */);
Riddle Hsu57831b52018-07-27 00:31:48 +0800250 }
251
Riddle Hsubbb63c22018-10-03 12:28:29 +0800252 private void positionChildAt(ActivityStack stack, int position, boolean includingParents,
253 String updateLastFocusedStackReason) {
Winson Chung123e07a2018-02-27 11:47:16 -0800254 // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust
255 // the position internally, also update the logic here
Riddle Hsubbb63c22018-10-03 12:28:29 +0800256 final ActivityStack prevFocusedStack = updateLastFocusedStackReason != null
257 ? getFocusedStack() : null;
Riddle Hsu75016992018-09-20 20:37:14 +0800258 final boolean wasContained = mStacks.remove(stack);
Wale Ogunwale9e737db2018-12-17 15:42:37 -0800259 if (mSingleTaskInstance && getChildCount() > 0) {
260 throw new IllegalStateException(
261 "positionChildAt: Can only have one child on display=" + this);
262 }
Winson Chung59a47ded2018-01-25 17:46:06 +0000263 final int insertPosition = getTopInsertPosition(stack, position);
264 mStacks.add(insertPosition, stack);
Riddle Hsu75016992018-09-20 20:37:14 +0800265
266 // The insert position may be adjusted to non-top when there is always-on-top stack. Since
267 // the original position is preferred to be top, the stack should have higher priority when
268 // we are looking for top focusable stack. The condition {@code wasContained} restricts the
269 // preferred stack is set only when moving an existing stack to top instead of adding a new
270 // stack that may be too early (e.g. in the middle of launching or reparenting).
271 if (wasContained && position >= mStacks.size() - 1 && stack.isFocusableAndVisible()) {
272 mPreferredTopFocusableStack = stack;
273 } else if (mPreferredTopFocusableStack == stack) {
274 mPreferredTopFocusableStack = null;
275 }
276
Riddle Hsubbb63c22018-10-03 12:28:29 +0800277 if (updateLastFocusedStackReason != null) {
278 final ActivityStack currentFocusedStack = getFocusedStack();
279 if (currentFocusedStack != prevFocusedStack) {
280 mLastFocusedStack = prevFocusedStack;
Wale Ogunwaled32da472018-11-16 07:19:28 -0800281 EventLogTags.writeAmFocusedStack(mRootActivityContainer.mCurrentUser, mDisplayId,
Riddle Hsubbb63c22018-10-03 12:28:29 +0800282 currentFocusedStack == null ? -1 : currentFocusedStack.getStackId(),
283 mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(),
284 updateLastFocusedStackReason);
285 }
286 }
287
Kazuki Takise048e2662018-06-27 17:05:11 +0900288 // Since positionChildAt() is called during the creation process of pinned stacks,
Riddle Hsu5947c362019-09-23 18:52:36 +0800289 // ActivityStack#getStack() can be null.
Yunfan Chen279f5582018-12-12 15:24:50 -0800290 if (stack.getTaskStack() != null && mDisplayContent != null) {
Wale Ogunwale3a256e62018-12-06 14:41:18 -0800291 mDisplayContent.positionStackAt(insertPosition,
Yunfan Chen279f5582018-12-12 15:24:50 -0800292 stack.getTaskStack(), includingParents);
Kazuki Takise048e2662018-06-27 17:05:11 +0900293 }
Evan Roskyc5abbd82018-10-05 16:02:19 -0700294 if (!wasContained) {
295 stack.setParent(this);
296 }
Winson Chung65d66d32018-12-13 17:48:39 -0800297 onStackOrderChanged(stack);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700298 }
299
300 private int getTopInsertPosition(ActivityStack stack, int candidatePosition) {
301 int position = mStacks.size();
Kazuki Takise148d00a2018-05-31 15:32:19 +0900302 if (stack.inPinnedWindowingMode()) {
303 // Stack in pinned windowing mode is z-ordered on-top of all other stacks so okay to
304 // just return the candidate position.
305 return Math.min(position, candidatePosition);
306 }
307 while (position > 0) {
308 final ActivityStack targetStack = mStacks.get(position - 1);
309 if (!targetStack.isAlwaysOnTop()) {
310 // We reached a stack that isn't always-on-top.
311 break;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700312 }
Kazuki Takise148d00a2018-05-31 15:32:19 +0900313 if (stack.isAlwaysOnTop() && !targetStack.inPinnedWindowingMode()) {
314 // Always on-top non-pinned windowing mode stacks can go anywhere below pinned stack.
315 break;
316 }
317 position--;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -0700318 }
319 return Math.min(position, candidatePosition);
320 }
321
322 <T extends ActivityStack> T getStack(int stackId) {
323 for (int i = mStacks.size() - 1; i >= 0; --i) {
324 final ActivityStack stack = mStacks.get(i);
325 if (stack.mStackId == stackId) {
326 return (T) stack;
327 }
328 }
329 return null;
330 }
331
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700332 /**
333 * @return the topmost stack on the display that is compatible with the input windowing mode and
334 * activity type. {@code null} means no compatible stack on the display.
335 * @see ConfigurationContainer#isCompatible(int, int)
336 */
337 <T extends ActivityStack> T getStack(int windowingMode, int activityType) {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700338 if (activityType == ACTIVITY_TYPE_HOME) {
339 return (T) mHomeStack;
340 } else if (activityType == ACTIVITY_TYPE_RECENTS) {
341 return (T) mRecentsStack;
342 }
343 if (windowingMode == WINDOWING_MODE_PINNED) {
344 return (T) mPinnedStack;
345 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
346 return (T) mSplitScreenPrimaryStack;
347 }
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700348
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700349 for (int i = mStacks.size() - 1; i >= 0; --i) {
350 final ActivityStack stack = mStacks.get(i);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700351 if (stack.isCompatible(windowingMode, activityType)) {
352 return (T) stack;
353 }
354 }
355 return null;
356 }
357
Louis Chang9d6ba282019-02-20 17:22:10 +0800358 boolean alwaysCreateStack(int windowingMode, int activityType) {
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700359 // Always create a stack for fullscreen, freeform, and split-screen-secondary windowing
360 // modes so that we can manage visual ordering and return types correctly.
361 return activityType == ACTIVITY_TYPE_STANDARD
362 && (windowingMode == WINDOWING_MODE_FULLSCREEN
363 || windowingMode == WINDOWING_MODE_FREEFORM
364 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
365 }
366
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700367 /**
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700368 * Returns an existing stack compatible with the windowing mode and activity type or creates one
369 * if a compatible stack doesn't exist.
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700370 * @see #getStack(int, int)
371 * @see #createStack(int, int, boolean)
372 */
373 <T extends ActivityStack> T getOrCreateStack(int windowingMode, int activityType,
374 boolean onTop) {
Wale Ogunwaleab5de372017-10-18 06:46:31 -0700375 if (!alwaysCreateStack(windowingMode, activityType)) {
376 T stack = getStack(windowingMode, activityType);
377 if (stack != null) {
378 return stack;
379 }
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700380 }
381 return createStack(windowingMode, activityType, onTop);
382 }
383
Wale Ogunwale68278562017-09-23 17:13:55 -0700384 /**
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700385 * Returns an existing stack compatible with the input params or creates one
386 * if a compatible stack doesn't exist.
387 * @see #getOrCreateStack(int, int, boolean)
388 */
389 <T extends ActivityStack> T getOrCreateStack(@Nullable ActivityRecord r,
390 @Nullable ActivityOptions options, @Nullable TaskRecord candidateTask, int activityType,
391 boolean onTop) {
Evan Rosky10475742018-09-05 19:02:48 -0700392 // First preference is the windowing mode in the activity options if set.
393 int windowingMode = (options != null)
394 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
395 // Validate that our desired windowingMode will work under the current conditions.
396 // UNDEFINED windowing mode is a valid result and means that the new stack will inherit
397 // it's display's windowing mode.
398 windowingMode = validateWindowingMode(windowingMode, r, candidateTask, activityType);
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700399 return getOrCreateStack(windowingMode, activityType, onTop);
400 }
401
Louis Changf2835df2018-10-17 15:14:45 +0800402 @VisibleForTesting
403 int getNextStackId() {
Bryce Leed9cce2c2017-12-04 16:16:27 -0800404 return sNextFreeStackId++;
405 }
406
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700407 /**
Wale Ogunwale68278562017-09-23 17:13:55 -0700408 * Creates a stack matching the input windowing mode and activity type on this display.
409 * @param windowingMode The windowing mode the stack should be created in. If
410 * {@link WindowConfiguration#WINDOWING_MODE_UNDEFINED} then the stack will
Evan Rosky10475742018-09-05 19:02:48 -0700411 * inherit it's parent's windowing mode.
Wale Ogunwale68278562017-09-23 17:13:55 -0700412 * @param activityType The activityType the stack should be created in. If
413 * {@link WindowConfiguration#ACTIVITY_TYPE_UNDEFINED} then the stack will
414 * be created in {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}.
415 * @param onTop If true the stack will be created at the top of the display, else at the bottom.
416 * @return The newly created stack.
417 */
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700418 <T extends ActivityStack> T createStack(int windowingMode, int activityType, boolean onTop) {
419
Wale Ogunwale9e737db2018-12-17 15:42:37 -0800420 if (mSingleTaskInstance && getChildCount() > 0) {
421 // Create stack on default display instead since this display can only contain 1 stack.
422 // TODO: Kinda a hack, but better that having the decision at each call point. Hoping
423 // this goes away once ActivityView is no longer using virtual displays.
424 return mRootActivityContainer.getDefaultDisplay().createStack(
425 windowingMode, activityType, onTop);
426 }
427
Wale Ogunwale68278562017-09-23 17:13:55 -0700428 if (activityType == ACTIVITY_TYPE_UNDEFINED) {
429 // Can't have an undefined stack type yet...so re-map to standard. Anyone that wants
430 // anything else should be passing it in anyways...
431 activityType = ACTIVITY_TYPE_STANDARD;
432 }
433
434 if (activityType != ACTIVITY_TYPE_STANDARD) {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700435 // For now there can be only one stack of a particular non-standard activity type on a
436 // display. So, get that ignoring whatever windowing mode it is currently in.
437 T stack = getStack(WINDOWING_MODE_UNDEFINED, activityType);
438 if (stack != null) {
439 throw new IllegalArgumentException("Stack=" + stack + " of activityType="
440 + activityType + " already on display=" + this + ". Can't have multiple.");
441 }
442 }
443
Wale Ogunwaled32da472018-11-16 07:19:28 -0800444 if (!isWindowingModeSupported(windowingMode, mService.mSupportsMultiWindow,
445 mService.mSupportsSplitScreenMultiWindow,
446 mService.mSupportsFreeformWindowManagement, mService.mSupportsPictureInPicture,
447 activityType)) {
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700448 throw new IllegalArgumentException("Can't create stack for unsupported windowingMode="
449 + windowingMode);
450 }
451
Bryce Leed9cce2c2017-12-04 16:16:27 -0800452 final int stackId = getNextStackId();
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700453 return createStackUnchecked(windowingMode, activityType, stackId, onTop);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700454 }
455
456 @VisibleForTesting
457 <T extends ActivityStack> T createStackUnchecked(int windowingMode, int activityType,
458 int stackId, boolean onTop) {
Yunfan Chen279f5582018-12-12 15:24:50 -0800459 if (windowingMode == WINDOWING_MODE_PINNED && activityType != ACTIVITY_TYPE_STANDARD) {
460 throw new IllegalArgumentException("Stack with windowing mode cannot with non standard "
461 + "activity type.");
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700462 }
Wale Ogunwaled32da472018-11-16 07:19:28 -0800463 return (T) new ActivityStack(this, stackId,
Yunfan Chen279f5582018-12-12 15:24:50 -0800464 mRootActivityContainer.mStackSupervisor, windowingMode, activityType, onTop);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700465 }
466
Riddle Hsu75016992018-09-20 20:37:14 +0800467 /**
468 * Get the preferred focusable stack in priority. If the preferred stack does not exist, find a
469 * focusable and visible stack from the top of stacks in this display.
470 */
Andrii Kulian52d255c2018-07-13 11:32:19 -0700471 ActivityStack getFocusedStack() {
Riddle Hsu75016992018-09-20 20:37:14 +0800472 if (mPreferredTopFocusableStack != null) {
473 return mPreferredTopFocusableStack;
474 }
475
Andrii Kulian52d255c2018-07-13 11:32:19 -0700476 for (int i = mStacks.size() - 1; i >= 0; --i) {
477 final ActivityStack stack = mStacks.get(i);
Riddle Hsu75016992018-09-20 20:37:14 +0800478 if (stack.isFocusableAndVisible()) {
Andrii Kulian52d255c2018-07-13 11:32:19 -0700479 return stack;
480 }
481 }
482
483 return null;
484 }
485
Andrii Kulianab132ee2018-07-24 22:10:21 +0800486 ActivityStack getNextFocusableStack(ActivityStack currentFocus, boolean ignoreCurrent) {
487 final int currentWindowingMode = currentFocus != null
488 ? currentFocus.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
489
490 ActivityStack candidate = null;
491 for (int i = mStacks.size() - 1; i >= 0; --i) {
492 final ActivityStack stack = mStacks.get(i);
493 if (ignoreCurrent && stack == currentFocus) {
494 continue;
495 }
Riddle Hsu75016992018-09-20 20:37:14 +0800496 if (!stack.isFocusableAndVisible()) {
Andrii Kulianab132ee2018-07-24 22:10:21 +0800497 continue;
498 }
499
500 if (currentWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
501 && candidate == null && stack.inSplitScreenPrimaryWindowingMode()) {
502 // If the currently focused stack is in split-screen secondary we save off the
503 // top primary split-screen stack as a candidate for focus because we might
504 // prefer focus to move to an other stack to avoid primary split-screen stack
505 // overlapping with a fullscreen stack when a fullscreen stack is higher in z
506 // than the next split-screen stack. Assistant stack, I am looking at you...
507 // We only move the focus to the primary-split screen stack if there isn't a
508 // better alternative.
509 candidate = stack;
510 continue;
511 }
512 if (candidate != null && stack.inSplitScreenSecondaryWindowingMode()) {
513 // Use the candidate stack since we are now at the secondary split-screen.
514 return candidate;
515 }
516 return stack;
517 }
518 return candidate;
519 }
520
Andrii Kulian52d255c2018-07-13 11:32:19 -0700521 ActivityRecord getResumedActivity() {
522 final ActivityStack focusedStack = getFocusedStack();
523 if (focusedStack == null) {
524 return null;
525 }
526 // TODO(b/111541062): Move this into ActivityStack#getResumedActivity()
527 // Check if the focused stack has the resumed activity
528 ActivityRecord resumedActivity = focusedStack.getResumedActivity();
529 if (resumedActivity == null || resumedActivity.app == null) {
530 // If there is no registered resumed activity in the stack or it is not running -
531 // try to use previously resumed one.
532 resumedActivity = focusedStack.mPausingActivity;
533 if (resumedActivity == null || resumedActivity.app == null) {
534 // If previously resumed activity doesn't work either - find the topmost running
535 // activity that can be focused.
536 resumedActivity = focusedStack.topRunningActivityLocked(true /* focusableOnly */);
537 }
538 }
539 return resumedActivity;
540 }
541
Riddle Hsubbb63c22018-10-03 12:28:29 +0800542 ActivityStack getLastFocusedStack() {
543 return mLastFocusedStack;
544 }
545
546 boolean allResumedActivitiesComplete() {
547 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
548 final ActivityRecord r = mStacks.get(stackNdx).getResumedActivity();
549 if (r != null && !r.isState(RESUMED)) {
550 return false;
551 }
552 }
553 final ActivityStack currentFocusedStack = getFocusedStack();
554 if (DEBUG_STACK) {
555 Slog.d(TAG_STACK, "allResumedActivitiesComplete: mLastFocusedStack changing from="
556 + mLastFocusedStack + " to=" + currentFocusedStack);
557 }
558 mLastFocusedStack = currentFocusedStack;
559 return true;
560 }
561
Wale Ogunwale68278562017-09-23 17:13:55 -0700562 /**
Andrii Kulian6b321512019-01-23 06:37:00 +0000563 * Pause all activities in either all of the stacks or just the back stacks. This is done before
564 * resuming a new activity and to make sure that previously active activities are
565 * paused in stacks that are no longer visible or in pinned windowing mode. This does not
566 * pause activities in visible stacks, so if an activity is launched within the same stack/task,
567 * then we should explicitly pause that stack's top activity.
Andrii Kulianab132ee2018-07-24 22:10:21 +0800568 * @param userLeaving Passed to pauseActivity() to indicate whether to call onUserLeaving().
569 * @param resuming The resuming activity.
Andrii Kulian6b321512019-01-23 06:37:00 +0000570 * @return {@code true} if any activity was paused as a result of this call.
Andrii Kulianab132ee2018-07-24 22:10:21 +0800571 */
Louis Chang7b03ad92019-08-21 12:32:33 +0800572 boolean pauseBackStacks(boolean userLeaving, ActivityRecord resuming) {
Andrii Kulianab132ee2018-07-24 22:10:21 +0800573 boolean someActivityPaused = false;
574 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
575 final ActivityStack stack = mStacks.get(stackNdx);
Andrii Kulian6b321512019-01-23 06:37:00 +0000576 final ActivityRecord resumedActivity = stack.getResumedActivity();
577 if (resumedActivity != null
Andrii Kulian0c869cc2019-02-06 19:50:32 -0800578 && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
579 || !stack.isFocusable())) {
Andrii Kulianab132ee2018-07-24 22:10:21 +0800580 if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
Andrii Kulian6b321512019-01-23 06:37:00 +0000581 " mResumedActivity=" + resumedActivity);
Louis Chang7b03ad92019-08-21 12:32:33 +0800582 someActivityPaused |= stack.startPausingLocked(userLeaving, false /* uiSleeping*/,
583 resuming);
Andrii Kulianab132ee2018-07-24 22:10:21 +0800584 }
585 }
586 return someActivityPaused;
587 }
588
589 /**
Louis Changc85b1a32018-08-14 16:40:53 +0800590 * Find task for putting the Activity in.
591 */
592 void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplay,
593 FindTaskResult result) {
594 mTmpFindTaskResult.clear();
595 for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
596 final ActivityStack stack = getChildAt(stackNdx);
597 if (!r.hasCompatibleActivityType(stack)) {
598 if (DEBUG_TASKS) {
599 Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) " + stack);
600 }
601 continue;
602 }
603
604 stack.findTaskLocked(r, mTmpFindTaskResult);
605 // It is possible to have tasks in multiple stacks with the same root affinity, so
606 // we should keep looking after finding an affinity match to see if there is a
607 // better match in another stack. Also, task affinity isn't a good enough reason
608 // to target a display which isn't the source of the intent, so skip any affinity
609 // matches not on the specified display.
610 if (mTmpFindTaskResult.mRecord != null) {
611 if (mTmpFindTaskResult.mIdealMatch) {
612 result.setTo(mTmpFindTaskResult);
613 return;
614 } else if (isPreferredDisplay) {
615 // Note: since the traversing through the stacks is top down, the floating
616 // tasks should always have lower priority than any affinity-matching tasks
617 // in the fullscreen stacks
618 result.setTo(mTmpFindTaskResult);
619 }
620 }
621 }
622 }
623
624 /**
Wale Ogunwale68278562017-09-23 17:13:55 -0700625 * Removes stacks in the input windowing modes from the system if they are of activity type
626 * ACTIVITY_TYPE_STANDARD or ACTIVITY_TYPE_UNDEFINED
627 */
628 void removeStacksInWindowingModes(int... windowingModes) {
629 if (windowingModes == null || windowingModes.length == 0) {
630 return;
631 }
632
Louis Changf787e532019-01-15 12:46:49 +0800633 // Collect the stacks that are necessary to be removed instead of performing the removal
634 // by looping mStacks, so that we don't miss any stacks after the stack size changed or
635 // stacks reordered.
636 final ArrayList<ActivityStack> stacks = new ArrayList<>();
Wale Ogunwale68278562017-09-23 17:13:55 -0700637 for (int j = windowingModes.length - 1 ; j >= 0; --j) {
638 final int windowingMode = windowingModes[j];
639 for (int i = mStacks.size() - 1; i >= 0; --i) {
640 final ActivityStack stack = mStacks.get(i);
641 if (!stack.isActivityTypeStandardOrUndefined()) {
642 continue;
643 }
644 if (stack.getWindowingMode() != windowingMode) {
645 continue;
646 }
Louis Changf787e532019-01-15 12:46:49 +0800647 stacks.add(stack);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700648 }
649 }
Louis Changf787e532019-01-15 12:46:49 +0800650
651 for (int i = stacks.size() - 1; i >= 0; --i) {
652 mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
653 }
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700654 }
655
Wale Ogunwale68278562017-09-23 17:13:55 -0700656 void removeStacksWithActivityTypes(int... activityTypes) {
657 if (activityTypes == null || activityTypes.length == 0) {
658 return;
659 }
660
Louis Changf787e532019-01-15 12:46:49 +0800661 // Collect the stacks that are necessary to be removed instead of performing the removal
662 // by looping mStacks, so that we don't miss any stacks after the stack size changed or
663 // stacks reordered.
664 final ArrayList<ActivityStack> stacks = new ArrayList<>();
Wale Ogunwale68278562017-09-23 17:13:55 -0700665 for (int j = activityTypes.length - 1 ; j >= 0; --j) {
666 final int activityType = activityTypes[j];
667 for (int i = mStacks.size() - 1; i >= 0; --i) {
668 final ActivityStack stack = mStacks.get(i);
669 if (stack.getActivityType() == activityType) {
Louis Changf787e532019-01-15 12:46:49 +0800670 stacks.add(stack);
Wale Ogunwale68278562017-09-23 17:13:55 -0700671 }
672 }
673 }
Louis Changf787e532019-01-15 12:46:49 +0800674
675 for (int i = stacks.size() - 1; i >= 0; --i) {
676 mRootActivityContainer.mStackSupervisor.removeStack(stacks.get(i));
677 }
Wale Ogunwale68278562017-09-23 17:13:55 -0700678 }
679
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700680 void onStackWindowingModeChanged(ActivityStack stack) {
681 removeStackReferenceIfNeeded(stack);
682 addStackReferenceIfNeeded(stack);
683 }
684
685 private void addStackReferenceIfNeeded(ActivityStack stack) {
686 final int activityType = stack.getActivityType();
687 final int windowingMode = stack.getWindowingMode();
688
689 if (activityType == ACTIVITY_TYPE_HOME) {
690 if (mHomeStack != null && mHomeStack != stack) {
Louis Chang7d0037c2018-08-13 12:42:06 +0800691 throw new IllegalArgumentException("addStackReferenceIfNeeded: home stack="
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700692 + mHomeStack + " already exist on display=" + this + " stack=" + stack);
693 }
Louis Chang7d0037c2018-08-13 12:42:06 +0800694 mHomeStack = stack;
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700695 } else if (activityType == ACTIVITY_TYPE_RECENTS) {
696 if (mRecentsStack != null && mRecentsStack != stack) {
697 throw new IllegalArgumentException("addStackReferenceIfNeeded: recents stack="
698 + mRecentsStack + " already exist on display=" + this + " stack=" + stack);
699 }
700 mRecentsStack = stack;
701 }
702 if (windowingMode == WINDOWING_MODE_PINNED) {
703 if (mPinnedStack != null && mPinnedStack != stack) {
704 throw new IllegalArgumentException("addStackReferenceIfNeeded: pinned stack="
705 + mPinnedStack + " already exist on display=" + this
706 + " stack=" + stack);
707 }
708 mPinnedStack = stack;
709 } else if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
710 if (mSplitScreenPrimaryStack != null && mSplitScreenPrimaryStack != stack) {
711 throw new IllegalArgumentException("addStackReferenceIfNeeded:"
712 + " split-screen-primary" + " stack=" + mSplitScreenPrimaryStack
713 + " already exist on display=" + this + " stack=" + stack);
714 }
715 mSplitScreenPrimaryStack = stack;
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800716 onSplitScreenModeActivated();
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700717 }
718 }
719
720 private void removeStackReferenceIfNeeded(ActivityStack stack) {
721 if (stack == mHomeStack) {
722 mHomeStack = null;
723 } else if (stack == mRecentsStack) {
724 mRecentsStack = null;
725 } else if (stack == mPinnedStack) {
726 mPinnedStack = null;
727 } else if (stack == mSplitScreenPrimaryStack) {
728 mSplitScreenPrimaryStack = null;
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800729 // Inform the reset of the system that split-screen mode was dismissed so things like
730 // resizing all the other stacks can take place.
731 onSplitScreenModeDismissed();
732 }
733 }
734
735 private void onSplitScreenModeDismissed() {
Riddle Hsua0022cd2019-09-09 21:12:41 +0800736 mService.deferWindowLayout();
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800737 try {
738 // Adjust the windowing mode of any stack in secondary split-screen to fullscreen.
739 for (int i = mStacks.size() - 1; i >= 0; --i) {
740 final ActivityStack otherStack = mStacks.get(i);
741 if (!otherStack.inSplitScreenSecondaryWindowingMode()) {
742 continue;
743 }
Evan Rosky10475742018-09-05 19:02:48 -0700744 otherStack.setWindowingMode(WINDOWING_MODE_UNDEFINED, false /* animate */,
Andrii Kulian9da138a2018-04-24 17:12:44 -0700745 false /* showRecents */, false /* enteringSplitScreenMode */,
Evan Roskyc5abbd82018-10-05 16:02:19 -0700746 true /* deferEnsuringVisibility */, false /* creating */);
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800747 }
748 } finally {
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800749 final ActivityStack topFullscreenStack =
Wale Ogunwalef3257852018-01-24 08:52:28 -0800750 getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN);
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800751 if (topFullscreenStack != null && mHomeStack != null && !isTopStack(mHomeStack)) {
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800752 // Whenever split-screen is dismissed we want the home stack directly behind the
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800753 // current top fullscreen stack so it shows up when the top stack is finished.
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800754 // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however
755 // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch
756 // once we have that.
757 mHomeStack.moveToFront("onSplitScreenModeDismissed");
Wale Ogunwale1dbc5c82017-12-08 08:12:20 -0800758 topFullscreenStack.moveToFront("onSplitScreenModeDismissed");
Wale Ogunwaleeb76b762017-11-17 10:08:04 -0800759 }
Riddle Hsua0022cd2019-09-09 21:12:41 +0800760 mService.continueWindowLayout();
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800761 }
762 }
763
764 private void onSplitScreenModeActivated() {
Riddle Hsua0022cd2019-09-09 21:12:41 +0800765 mService.deferWindowLayout();
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800766 try {
767 // Adjust the windowing mode of any affected by split-screen to split-screen secondary.
768 for (int i = mStacks.size() - 1; i >= 0; --i) {
769 final ActivityStack otherStack = mStacks.get(i);
770 if (otherStack == mSplitScreenPrimaryStack
771 || !otherStack.affectedBySplitScreenResize()) {
772 continue;
773 }
Wale Ogunwaledf262f52017-12-07 18:17:12 -0800774 otherStack.setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
775 false /* animate */, false /* showRecents */,
Evan Roskyc5abbd82018-10-05 16:02:19 -0700776 true /* enteringSplitScreenMode */, true /* deferEnsuringVisibility */,
777 false /* creating */);
Wale Ogunwale30e441d2017-11-09 08:28:45 -0800778 }
779 } finally {
Riddle Hsua0022cd2019-09-09 21:12:41 +0800780 mService.continueWindowLayout();
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700781 }
782 }
783
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700784 /**
785 * Returns true if the {@param windowingMode} is supported based on other parameters passed in.
786 * @param windowingMode The windowing mode we are checking support for.
787 * @param supportsMultiWindow If we should consider support for multi-window mode in general.
788 * @param supportsSplitScreen If we should consider support for split-screen multi-window.
789 * @param supportsFreeform If we should consider support for freeform multi-window.
790 * @param supportsPip If we should consider support for picture-in-picture mutli-window.
791 * @param activityType The activity type under consideration.
792 * @return true if the windowing mode is supported.
793 */
794 private boolean isWindowingModeSupported(int windowingMode, boolean supportsMultiWindow,
795 boolean supportsSplitScreen, boolean supportsFreeform, boolean supportsPip,
796 int activityType) {
797
798 if (windowingMode == WINDOWING_MODE_UNDEFINED
799 || windowingMode == WINDOWING_MODE_FULLSCREEN) {
800 return true;
801 }
802 if (!supportsMultiWindow) {
803 return false;
804 }
805
Evan Rosky10475742018-09-05 19:02:48 -0700806 final int displayWindowingMode = getWindowingMode();
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700807 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
808 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
Wale Ogunwale2b07da82017-11-08 14:52:40 -0800809 return supportsSplitScreen
Evan Rosky10475742018-09-05 19:02:48 -0700810 && WindowConfiguration.supportSplitScreenWindowingMode(activityType)
811 // Freeform windows and split-screen windows don't mix well, so prevent
812 // split windowing modes on freeform displays.
813 && displayWindowingMode != WINDOWING_MODE_FREEFORM;
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700814 }
815
816 if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
817 return false;
818 }
819
820 if (!supportsPip && windowingMode == WINDOWING_MODE_PINNED) {
821 return false;
822 }
823 return true;
824 }
825
Evan Rosky10475742018-09-05 19:02:48 -0700826 /**
827 * Resolves the windowing mode that an {@link ActivityRecord} would be in if started on this
828 * display with the provided parameters.
829 *
830 * @param r The ActivityRecord in question.
831 * @param options Options to start with.
832 * @param task The task within-which the activity would start.
833 * @param activityType The type of activity to start.
834 * @return The resolved (not UNDEFINED) windowing-mode that the activity would be in.
835 */
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700836 int resolveWindowingMode(@Nullable ActivityRecord r, @Nullable ActivityOptions options,
837 @Nullable TaskRecord task, int activityType) {
838
839 // First preference if the windowing mode in the activity options if set.
840 int windowingMode = (options != null)
841 ? options.getLaunchWindowingMode() : WINDOWING_MODE_UNDEFINED;
842
843 // If windowing mode is unset, then next preference is the candidate task, then the
844 // activity record.
845 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
846 if (task != null) {
847 windowingMode = task.getWindowingMode();
848 }
849 if (windowingMode == WINDOWING_MODE_UNDEFINED && r != null) {
850 windowingMode = r.getWindowingMode();
851 }
852 if (windowingMode == WINDOWING_MODE_UNDEFINED) {
853 // Use the display's windowing mode.
854 windowingMode = getWindowingMode();
855 }
856 }
Evan Rosky10475742018-09-05 19:02:48 -0700857 windowingMode = validateWindowingMode(windowingMode, r, task, activityType);
858 return windowingMode != WINDOWING_MODE_UNDEFINED
859 ? windowingMode : WINDOWING_MODE_FULLSCREEN;
Evan Rosky9ba524e2018-01-03 16:27:56 -0800860 }
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700861
Evan Rosky9ba524e2018-01-03 16:27:56 -0800862 /**
863 * Check that the requested windowing-mode is appropriate for the specified task and/or activity
864 * on this display.
865 *
866 * @param windowingMode The windowing-mode to validate.
867 * @param r The {@link ActivityRecord} to check against.
868 * @param task The {@link TaskRecord} to check against.
869 * @param activityType An activity type.
870 * @return The provided windowingMode or the closest valid mode which is appropriate.
871 */
872 int validateWindowingMode(int windowingMode, @Nullable ActivityRecord r,
873 @Nullable TaskRecord task, int activityType) {
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700874 // Make sure the windowing mode we are trying to use makes sense for what is supported.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800875 boolean supportsMultiWindow = mService.mSupportsMultiWindow;
876 boolean supportsSplitScreen = mService.mSupportsSplitScreenMultiWindow;
877 boolean supportsFreeform = mService.mSupportsFreeformWindowManagement;
878 boolean supportsPip = mService.mSupportsPictureInPicture;
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700879 if (supportsMultiWindow) {
880 if (task != null) {
881 supportsMultiWindow = task.isResizeable();
882 supportsSplitScreen = task.supportsSplitScreenWindowingMode();
883 // TODO: Do we need to check for freeform and Pip support here?
884 } else if (r != null) {
885 supportsMultiWindow = r.isResizeable();
886 supportsSplitScreen = r.supportsSplitScreenWindowingMode();
887 supportsFreeform = r.supportsFreeform();
888 supportsPip = r.supportsPictureInPicture();
889 }
890 }
891
892 final boolean inSplitScreenMode = hasSplitScreenPrimaryStack();
893 if (!inSplitScreenMode
894 && windowingMode == WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY) {
Evan Rosky10475742018-09-05 19:02:48 -0700895 // Switch to the display's windowing mode if we are not in split-screen mode and we are
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700896 // trying to launch in split-screen secondary.
Evan Rosky10475742018-09-05 19:02:48 -0700897 windowingMode = WINDOWING_MODE_UNDEFINED;
898 } else if (inSplitScreenMode && (windowingMode == WINDOWING_MODE_FULLSCREEN
899 || windowingMode == WINDOWING_MODE_UNDEFINED)
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700900 && supportsSplitScreen) {
901 windowingMode = WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
902 }
903
904 if (windowingMode != WINDOWING_MODE_UNDEFINED
905 && isWindowingModeSupported(windowingMode, supportsMultiWindow, supportsSplitScreen,
Evan Rosky10475742018-09-05 19:02:48 -0700906 supportsFreeform, supportsPip, activityType)) {
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -0700907 return windowingMode;
908 }
Evan Rosky10475742018-09-05 19:02:48 -0700909 return WINDOWING_MODE_UNDEFINED;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700910 }
911
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700912 /**
913 * Get the topmost stack on the display. It may be different from focused stack, because
Andrii Kulian52d255c2018-07-13 11:32:19 -0700914 * some stacks are not focusable (e.g. PiP).
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700915 */
916 ActivityStack getTopStack() {
917 return mStacks.isEmpty() ? null : mStacks.get(mStacks.size() - 1);
Wale Ogunwale04a05ac2017-09-17 21:35:02 -0700918 }
919
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700920 boolean isTopStack(ActivityStack stack) {
921 return stack == getTopStack();
922 }
923
chaviw2c500982018-01-04 17:05:05 -0800924 boolean isTopNotPinnedStack(ActivityStack stack) {
Wale Ogunwale2cca8622017-12-11 08:40:13 -0800925 for (int i = mStacks.size() - 1; i >= 0; --i) {
926 final ActivityStack current = mStacks.get(i);
chaviw2c500982018-01-04 17:05:05 -0800927 if (!current.inPinnedWindowingMode()) {
Wale Ogunwale2cca8622017-12-11 08:40:13 -0800928 return current == stack;
929 }
930 }
931 return false;
932 }
933
Wale Ogunwalef3257852018-01-24 08:52:28 -0800934 ActivityStack getTopStackInWindowingMode(int windowingMode) {
935 for (int i = mStacks.size() - 1; i >= 0; --i) {
936 final ActivityStack current = mStacks.get(i);
937 if (windowingMode == current.getWindowingMode()) {
938 return current;
939 }
940 }
941 return null;
942 }
943
Riddle Hsue10cea52018-10-16 23:33:23 +0800944 ActivityRecord topRunningActivity() {
945 return topRunningActivity(false /* considerKeyguardState */);
946 }
947
948 /**
949 * Returns the top running activity in the focused stack. In the case the focused stack has no
950 * such activity, the next focusable stack on this display is returned.
951 *
952 * @param considerKeyguardState Indicates whether the locked state should be considered. if
953 * {@code true} and the keyguard is locked, only activities that
954 * can be shown on top of the keyguard will be considered.
955 * @return The top running activity. {@code null} if none is available.
956 */
957 ActivityRecord topRunningActivity(boolean considerKeyguardState) {
958 ActivityRecord topRunning = null;
959 final ActivityStack focusedStack = getFocusedStack();
960 if (focusedStack != null) {
961 topRunning = focusedStack.topRunningActivityLocked();
962 }
963
964 // Look in other focusable stacks.
965 if (topRunning == null) {
966 for (int i = mStacks.size() - 1; i >= 0; --i) {
967 final ActivityStack stack = mStacks.get(i);
968 // Only consider focusable stacks other than the current focused one.
969 if (stack == focusedStack || !stack.isFocusable()) {
970 continue;
971 }
972 topRunning = stack.topRunningActivityLocked();
973 if (topRunning != null) {
974 break;
975 }
976 }
977 }
978
979 // This activity can be considered the top running activity if we are not considering
980 // the locked state, the keyguard isn't locked, or we can show when locked.
981 if (topRunning != null && considerKeyguardState
Wale Ogunwaled32da472018-11-16 07:19:28 -0800982 && mRootActivityContainer.mStackSupervisor.getKeyguardController().isKeyguardLocked()
Riddle Hsue10cea52018-10-16 23:33:23 +0800983 && !topRunning.canShowWhenLocked()) {
984 return null;
985 }
986
987 return topRunning;
988 }
989
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -0700990 int getIndexOf(ActivityStack stack) {
991 return mStacks.indexOf(stack);
992 }
993
Shivam Agrawal1d3db652019-07-01 15:26:11 -0700994 boolean updateDisplayOverrideConfigurationLocked() {
995 Configuration values = new Configuration();
996 mDisplayContent.computeScreenConfiguration(values);
997
Riddle Hsua0022cd2019-09-09 21:12:41 +0800998 mService.mH.sendMessage(PooledLambda.obtainMessage(
999 ActivityManagerInternal::updateOomLevelsForDisplay, mService.mAmInternal,
1000 mDisplayId));
Shivam Agrawal1d3db652019-07-01 15:26:11 -07001001
1002 Settings.System.clearConfiguration(values);
1003 updateDisplayOverrideConfigurationLocked(values, null /* starting */,
1004 false /* deferResume */, mService.mTmpUpdateConfigurationResult);
1005 return mService.mTmpUpdateConfigurationResult.changes != 0;
1006 }
1007
1008 /**
1009 * Updates override configuration specific for the selected display. If no config is provided,
1010 * new one will be computed in WM based on current display info.
1011 */
1012 boolean updateDisplayOverrideConfigurationLocked(Configuration values,
1013 ActivityRecord starting, boolean deferResume,
1014 ActivityTaskManagerService.UpdateConfigurationResult result) {
1015
1016 int changes = 0;
1017 boolean kept = true;
1018
Riddle Hsua0022cd2019-09-09 21:12:41 +08001019 mService.deferWindowLayout();
Shivam Agrawal1d3db652019-07-01 15:26:11 -07001020 try {
1021 if (values != null) {
1022 if (mDisplayId == DEFAULT_DISPLAY) {
1023 // Override configuration of the default display duplicates global config, so
1024 // we're calling global config update instead for default display. It will also
1025 // apply the correct override config.
1026 changes = mService.updateGlobalConfigurationLocked(values,
1027 false /* initLocale */, false /* persistent */,
1028 UserHandle.USER_NULL /* userId */, deferResume);
1029 } else {
1030 changes = performDisplayOverrideConfigUpdate(values, deferResume);
1031 }
1032 }
1033
1034 kept = mService.ensureConfigAndVisibilityAfterUpdate(starting, changes);
1035 } finally {
Riddle Hsua0022cd2019-09-09 21:12:41 +08001036 mService.continueWindowLayout();
Shivam Agrawal1d3db652019-07-01 15:26:11 -07001037 }
1038
1039 if (result != null) {
1040 result.changes = changes;
1041 result.activityRelaunched = !kept;
1042 }
1043 return kept;
1044 }
1045
1046 int performDisplayOverrideConfigUpdate(Configuration values, boolean deferResume) {
1047 mTempConfig.setTo(getRequestedOverrideConfiguration());
1048 final int changes = mTempConfig.updateFrom(values);
1049 if (changes != 0) {
1050 Slog.i(TAG, "Override config changes=" + Integer.toHexString(changes) + " "
1051 + mTempConfig + " for displayId=" + mDisplayId);
1052 onRequestedOverrideConfigurationChanged(mTempConfig);
1053
1054 final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
1055 if (isDensityChange && mDisplayId == DEFAULT_DISPLAY) {
1056 mService.mAppWarnings.onDensityChanged();
1057
1058 // Post message to start process to avoid possible deadlock of calling into AMS with
1059 // the ATMS lock held.
1060 final Message msg = PooledLambda.obtainMessage(
1061 ActivityManagerInternal::killAllBackgroundProcessesExcept,
1062 mService.mAmInternal, N,
1063 ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND);
1064 mService.mH.sendMessage(msg);
1065 }
1066 }
1067 return changes;
1068 }
1069
Evan Roskye747c3e2018-10-30 20:06:41 -07001070 @Override
Evan Roskydfe3da72018-10-26 17:21:06 -07001071 public void onRequestedOverrideConfigurationChanged(Configuration overrideConfiguration) {
1072 final int currRotation =
1073 getRequestedOverrideConfiguration().windowConfiguration.getRotation();
Evan Roskye747c3e2018-10-30 20:06:41 -07001074 if (currRotation != ROTATION_UNDEFINED
1075 && currRotation != overrideConfiguration.windowConfiguration.getRotation()
Wale Ogunwale3a256e62018-12-06 14:41:18 -08001076 && mDisplayContent != null) {
1077 mDisplayContent.applyRotationLocked(currRotation,
Evan Roskye747c3e2018-10-30 20:06:41 -07001078 overrideConfiguration.windowConfiguration.getRotation());
1079 }
Evan Roskydfe3da72018-10-26 17:21:06 -07001080 super.onRequestedOverrideConfigurationChanged(overrideConfiguration);
Wale Ogunwale3a256e62018-12-06 14:41:18 -08001081 if (mDisplayContent != null) {
1082 mService.mWindowManager.setNewDisplayOverrideConfiguration(
1083 overrideConfiguration, mDisplayContent);
1084 }
Riddle Hsua0022cd2019-09-09 21:12:41 +08001085 mService.addWindowLayoutReasons(
1086 ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED);
Evan Roskye747c3e2018-10-30 20:06:41 -07001087 }
1088
1089 @Override
1090 public void onConfigurationChanged(Configuration newParentConfig) {
1091 // update resources before cascade so that docked/pinned stacks use the correct info
Wale Ogunwale3a256e62018-12-06 14:41:18 -08001092 if (mDisplayContent != null) {
1093 mDisplayContent.preOnConfigurationChanged();
1094 }
Evan Roskye747c3e2018-10-30 20:06:41 -07001095 super.onConfigurationChanged(newParentConfig);
1096 }
1097
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -07001098 void onLockTaskPackagesUpdated() {
1099 for (int i = mStacks.size() - 1; i >= 0; --i) {
1100 mStacks.get(i).onLockTaskPackagesUpdated();
1101 }
1102 }
1103
Wale Ogunwale7e1f5f52017-10-18 15:19:59 -07001104 /** We are in the process of exiting split-screen mode. */
1105 void onExitingSplitScreenMode() {
1106 // Remove reference to the primary-split-screen stack so it no longer has any effect on the
1107 // display. For example, we want to be able to create fullscreen stack for standard activity
1108 // types when exiting split-screen mode.
1109 mSplitScreenPrimaryStack = null;
1110 }
1111
Riddle Hsu7b766fd2019-01-28 21:14:59 +08001112 /** Checks whether the given activity is in size compatibility mode and notifies the change. */
1113 void handleActivitySizeCompatModeIfNeeded(ActivityRecord r) {
1114 if (!r.isState(RESUMED) || r.getWindowingMode() != WINDOWING_MODE_FULLSCREEN) {
1115 // The callback is only interested in the foreground changes of fullscreen activity.
1116 return;
1117 }
1118 if (!r.inSizeCompatMode()) {
1119 if (mLastCompatModeActivity != null) {
1120 mService.getTaskChangeNotificationController()
1121 .notifySizeCompatModeActivityChanged(mDisplayId, null /* activityToken */);
1122 }
1123 mLastCompatModeActivity = null;
1124 return;
1125 }
1126 if (mLastCompatModeActivity == r) {
1127 return;
1128 }
1129 mLastCompatModeActivity = r;
1130 mService.getTaskChangeNotificationController()
1131 .notifySizeCompatModeActivityChanged(mDisplayId, r.appToken);
1132 }
1133
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -07001134 ActivityStack getSplitScreenPrimaryStack() {
1135 return mSplitScreenPrimaryStack;
1136 }
1137
1138 boolean hasSplitScreenPrimaryStack() {
1139 return mSplitScreenPrimaryStack != null;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -07001140 }
1141
Yunfan Chen279f5582018-12-12 15:24:50 -08001142 ActivityStack getPinnedStack() {
1143 return mPinnedStack;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -07001144 }
1145
1146 boolean hasPinnedStack() {
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -07001147 return mPinnedStack != null;
Wale Ogunwale04a05ac2017-09-17 21:35:02 -07001148 }
1149
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001150 @Override
1151 public String toString() {
1152 return "ActivityDisplay={" + mDisplayId + " numStacks=" + mStacks.size() + "}";
1153 }
1154
1155 @Override
1156 protected int getChildCount() {
1157 return mStacks.size();
1158 }
1159
1160 @Override
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -07001161 protected ActivityStack getChildAt(int index) {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001162 return mStacks.get(index);
1163 }
1164
1165 @Override
1166 protected ConfigurationContainer getParent() {
Wale Ogunwaled32da472018-11-16 07:19:28 -08001167 return mRootActivityContainer;
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001168 }
1169
1170 boolean isPrivate() {
1171 return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
1172 }
1173
1174 boolean isUidPresent(int uid) {
1175 for (ActivityStack stack : mStacks) {
1176 if (stack.isUidPresent(uid)) {
1177 return true;
1178 }
1179 }
1180 return false;
1181 }
1182
Louis Chang7d0037c2018-08-13 12:42:06 +08001183 /**
1184 * @see #mRemoved
1185 */
1186 boolean isRemoved() {
1187 return mRemoved;
1188 }
1189
Bryce Leef19cbe22018-02-02 15:09:21 -08001190 void remove() {
1191 final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
Riddle Hsu402b4402018-11-06 17:23:15 +08001192 ActivityStack lastReparentedStack = null;
1193 mPreferredTopFocusableStack = null;
Louis Chang7d0037c2018-08-13 12:42:06 +08001194
1195 // Stacks could be reparented from the removed display to other display. While
1196 // reparenting the last stack of the removed display, the remove display is ready to be
1197 // released (no more ActivityStack). But, we cannot release it at that moment or the
Riddle Hsu5947c362019-09-23 18:52:36 +08001198 // related WindowContainer will also be removed. So, we set display as removed after
1199 // reparenting stack finished.
Wale Ogunwaled32da472018-11-16 07:19:28 -08001200 final ActivityDisplay toDisplay = mRootActivityContainer.getDefaultDisplay();
1201 mRootActivityContainer.mStackSupervisor.beginDeferResume();
Riddle Hsu402b4402018-11-06 17:23:15 +08001202 try {
1203 int numStacks = mStacks.size();
1204 // Keep the order from bottom to top.
1205 for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
1206 final ActivityStack stack = mStacks.get(stackNdx);
1207 // Always finish non-standard type stacks.
1208 if (destroyContentOnRemoval || !stack.isActivityTypeStandardOrUndefined()) {
Andrii Kuliande93eff2019-07-12 12:21:27 -07001209 stack.finishAllActivitiesImmediately();
Riddle Hsu402b4402018-11-06 17:23:15 +08001210 } else {
1211 // If default display is in split-window mode, set windowing mode of the stack
1212 // to split-screen secondary. Otherwise, set the windowing mode to undefined by
1213 // default to let stack inherited the windowing mode from the new display.
1214 final int windowingMode = toDisplay.hasSplitScreenPrimaryStack()
1215 ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
1216 : WINDOWING_MODE_UNDEFINED;
1217 stack.reparent(toDisplay, true /* onTop */, true /* displayRemoved */);
1218 stack.setWindowingMode(windowingMode);
1219 lastReparentedStack = stack;
1220 }
1221 // Stacks may be removed from this display. Ensure each stack will be processed and
1222 // the loop will end.
1223 stackNdx -= numStacks - mStacks.size();
1224 numStacks = mStacks.size();
Bryce Leef19cbe22018-02-02 15:09:21 -08001225 }
Riddle Hsu402b4402018-11-06 17:23:15 +08001226 } finally {
Wale Ogunwaled32da472018-11-16 07:19:28 -08001227 mRootActivityContainer.mStackSupervisor.endDeferResume();
Bryce Leef19cbe22018-02-02 15:09:21 -08001228 }
Louis Chang7d0037c2018-08-13 12:42:06 +08001229 mRemoved = true;
Bryce Leef19cbe22018-02-02 15:09:21 -08001230
Riddle Hsu402b4402018-11-06 17:23:15 +08001231 // Only update focus/visibility for the last one because there may be many stacks are
1232 // reparented and the intermediate states are unnecessary.
1233 if (lastReparentedStack != null) {
1234 lastReparentedStack.postReparent();
1235 }
Louis Chang7d0037c2018-08-13 12:42:06 +08001236 releaseSelfIfNeeded();
wilsonshih0299c8a2018-08-24 15:52:57 +08001237
Riddle Hsuf53da812018-08-15 22:00:27 +08001238 if (!mAllSleepTokens.isEmpty()) {
Wale Ogunwaled32da472018-11-16 07:19:28 -08001239 mRootActivityContainer.mSleepTokens.removeAll(mAllSleepTokens);
Riddle Hsuf53da812018-08-15 22:00:27 +08001240 mAllSleepTokens.clear();
Wale Ogunwaled32da472018-11-16 07:19:28 -08001241 mService.updateSleepIfNeededLocked();
Riddle Hsuf53da812018-08-15 22:00:27 +08001242 }
Louis Chang7d0037c2018-08-13 12:42:06 +08001243 }
1244
1245 private void releaseSelfIfNeeded() {
Louis Changcc568712019-03-08 14:54:41 +08001246 if (!mRemoved || mDisplayContent == null) {
1247 return;
1248 }
1249
1250 final ActivityStack stack = mStacks.size() == 1 ? mStacks.get(0) : null;
1251 if (stack != null && stack.isActivityTypeHome() && stack.getAllTasks().isEmpty()) {
1252 // Release this display if an empty home stack is the only thing left.
1253 // Since it is the last stack, this display will be released along with the stack
1254 // removal.
1255 stack.remove();
1256 } else if (mStacks.isEmpty()) {
Wale Ogunwale3a256e62018-12-06 14:41:18 -08001257 mDisplayContent.removeIfPossible();
1258 mDisplayContent = null;
Wale Ogunwaled32da472018-11-16 07:19:28 -08001259 mRootActivityContainer.removeChild(this);
1260 mRootActivityContainer.mStackSupervisor
1261 .getKeyguardController().onDisplayRemoved(mDisplayId);
Louis Chang7d0037c2018-08-13 12:42:06 +08001262 }
Bryce Leef19cbe22018-02-02 15:09:21 -08001263 }
1264
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001265 /** Update and get all UIDs that are present on the display and have access to it. */
1266 IntArray getPresentUIDs() {
1267 mDisplayAccessUIDs.clear();
1268 for (ActivityStack stack : mStacks) {
1269 stack.getPresentUIDs(mDisplayAccessUIDs);
1270 }
1271 return mDisplayAccessUIDs;
1272 }
1273
Louis Changbd48dca2018-08-29 17:44:34 +08001274 /**
Andrii Kulian15cfb422018-11-07 13:38:49 -08001275 * Checks if system decorations should be shown on this display.
1276 *
Louis Changbd48dca2018-08-29 17:44:34 +08001277 * @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
1278 */
1279 boolean supportsSystemDecorations() {
Wale Ogunwale3a256e62018-12-06 14:41:18 -08001280 return mDisplayContent.supportsSystemDecorations();
Louis Changbd48dca2018-08-29 17:44:34 +08001281 }
1282
Riddle Hsu402b4402018-11-06 17:23:15 +08001283 @VisibleForTesting
1284 boolean shouldDestroyContentOnRemove() {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001285 return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
1286 }
1287
1288 boolean shouldSleep() {
1289 return (mStacks.isEmpty() || !mAllSleepTokens.isEmpty())
Wale Ogunwaled32da472018-11-16 07:19:28 -08001290 && (mService.mRunningVoice == null);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001291 }
1292
Tiger Huang1e5b10a2018-07-30 20:19:51 +08001293 void setFocusedApp(ActivityRecord r, boolean moveFocusNow) {
Wale Ogunwale3a256e62018-12-06 14:41:18 -08001294 if (mDisplayContent == null) {
1295 return;
1296 }
1297 final AppWindowToken newFocus;
1298 final IBinder token = r.appToken;
1299 if (token == null) {
Adrian Roosb125e0b2019-10-02 14:55:14 +02001300 ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, "Clearing focused app, displayId=%d",
1301 mDisplayId);
Wale Ogunwale3a256e62018-12-06 14:41:18 -08001302 newFocus = null;
1303 } else {
1304 newFocus = mService.mWindowManager.mRoot.getAppWindowToken(token);
1305 if (newFocus == null) {
1306 Slog.w(TAG_WM, "Attempted to set focus to non-existing app token: " + token
1307 + ", displayId=" + mDisplayId);
1308 }
Adrian Roosb125e0b2019-10-02 14:55:14 +02001309 ProtoLog.v(WM_DEBUG_FOCUS_LIGHT,
1310 "Set focused app to: %s moveFocusNow=%b displayId=%d", newFocus,
1311 moveFocusNow, mDisplayId);
Wale Ogunwale3a256e62018-12-06 14:41:18 -08001312 }
1313
1314 final boolean changed = mDisplayContent.setFocusedApp(newFocus);
1315 if (moveFocusNow && changed) {
1316 mService.mWindowManager.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
1317 true /*updateInputWindows*/);
1318 }
Tiger Huang1e5b10a2018-07-30 20:19:51 +08001319 }
1320
Winson Chunge2d72172018-01-25 17:46:20 +00001321 /**
Winson Chung3e2980e2018-03-29 17:28:57 -07001322 * @return the stack currently above the {@param stack}. Can be null if the {@param stack} is
1323 * already top-most.
Winson Chunge2d72172018-01-25 17:46:20 +00001324 */
Winson Chung3e2980e2018-03-29 17:28:57 -07001325 ActivityStack getStackAbove(ActivityStack stack) {
1326 final int stackIndex = mStacks.indexOf(stack) + 1;
Winson Chunge2d72172018-01-25 17:46:20 +00001327 return (stackIndex < mStacks.size()) ? mStacks.get(stackIndex) : null;
1328 }
1329
1330 /**
Winson Chung3e2980e2018-03-29 17:28:57 -07001331 * Adjusts the {@param stack} behind the last visible stack in the display if necessary.
1332 * Generally used in conjunction with {@link #moveStackBehindStack}.
Winson Chunge2d72172018-01-25 17:46:20 +00001333 */
Winson Chung3e2980e2018-03-29 17:28:57 -07001334 void moveStackBehindBottomMostVisibleStack(ActivityStack stack) {
1335 if (stack.shouldBeVisible(null)) {
1336 // Skip if the stack is already visible
Winson Chunge2d72172018-01-25 17:46:20 +00001337 return;
1338 }
1339
Winson Chung3e2980e2018-03-29 17:28:57 -07001340 // Move the stack to the bottom to not affect the following visibility checks
1341 positionChildAtBottom(stack);
Winson Chunge2d72172018-01-25 17:46:20 +00001342
Winson Chung3e2980e2018-03-29 17:28:57 -07001343 // Find the next position where the stack should be placed
Winson Chunge2d72172018-01-25 17:46:20 +00001344 final int numStacks = mStacks.size();
1345 for (int stackNdx = 0; stackNdx < numStacks; stackNdx++) {
Winson Chung3e2980e2018-03-29 17:28:57 -07001346 final ActivityStack s = mStacks.get(stackNdx);
1347 if (s == stack) {
Winson Chunge2d72172018-01-25 17:46:20 +00001348 continue;
1349 }
Winson Chung3e2980e2018-03-29 17:28:57 -07001350 final int winMode = s.getWindowingMode();
Winson Chunge2d72172018-01-25 17:46:20 +00001351 final boolean isValidWindowingMode = winMode == WINDOWING_MODE_FULLSCREEN ||
1352 winMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Winson Chung3e2980e2018-03-29 17:28:57 -07001353 if (s.shouldBeVisible(null) && isValidWindowingMode) {
1354 // Move the provided stack to behind this stack
1355 positionChildAt(stack, Math.max(0, stackNdx - 1));
Winson Chunge2d72172018-01-25 17:46:20 +00001356 break;
1357 }
1358 }
1359 }
1360
1361 /**
Winson Chung3e2980e2018-03-29 17:28:57 -07001362 * Moves the {@param stack} behind the given {@param behindStack} if possible. If
1363 * {@param behindStack} is not currently in the display, then then the stack is moved to the
1364 * back. Generally used in conjunction with {@link #moveStackBehindBottomMostVisibleStack}.
Winson Chunge2d72172018-01-25 17:46:20 +00001365 */
Winson Chung3e2980e2018-03-29 17:28:57 -07001366 void moveStackBehindStack(ActivityStack stack, ActivityStack behindStack) {
1367 if (behindStack == null || behindStack == stack) {
Winson Chunge2d72172018-01-25 17:46:20 +00001368 return;
1369 }
1370
Winson Chung123e07a2018-02-27 11:47:16 -08001371 // Note that positionChildAt will first remove the given stack before inserting into the
1372 // list, so we need to adjust the insertion index to account for the removed index
1373 // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the
1374 // position internally
Winson Chung3e2980e2018-03-29 17:28:57 -07001375 final int stackIndex = mStacks.indexOf(stack);
Winson Chung123e07a2018-02-27 11:47:16 -08001376 final int behindStackIndex = mStacks.indexOf(behindStack);
Winson Chung3e2980e2018-03-29 17:28:57 -07001377 final int insertIndex = stackIndex <= behindStackIndex
Winson Chung123e07a2018-02-27 11:47:16 -08001378 ? behindStackIndex - 1 : behindStackIndex;
Winson Chung3e2980e2018-03-29 17:28:57 -07001379 positionChildAt(stack, Math.max(0, insertIndex));
Winson Chunge2d72172018-01-25 17:46:20 +00001380 }
1381
Louis Chang77ce34d2019-01-03 15:45:12 +08001382 void ensureActivitiesVisible(ActivityRecord starting, int configChanges,
1383 boolean preserveWindows, boolean notifyClients) {
1384 for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) {
1385 final ActivityStack stack = getChildAt(stackNdx);
1386 stack.ensureActivitiesVisibleLocked(starting, configChanges, preserveWindows,
1387 notifyClients);
1388 }
1389 }
1390
Louis Changbd48dca2018-08-29 17:44:34 +08001391 void moveHomeStackToFront(String reason) {
1392 if (mHomeStack != null) {
1393 mHomeStack.moveToFront(reason);
1394 }
1395 }
1396
Riddle Hsu2b9a6d72019-04-24 23:55:11 +08001397 /**
1398 * Moves the focusable home activity to top. If there is no such activity, the home stack will
1399 * still move to top.
1400 */
1401 void moveHomeActivityToTop(String reason) {
Louis Changbd48dca2018-08-29 17:44:34 +08001402 final ActivityRecord top = getHomeActivity();
1403 if (top == null) {
Riddle Hsu2b9a6d72019-04-24 23:55:11 +08001404 moveHomeStackToFront(reason);
1405 return;
Louis Changbd48dca2018-08-29 17:44:34 +08001406 }
Louis Chang19443452018-10-09 12:10:21 +08001407 top.moveFocusableActivityToTop(reason);
Louis Changbd48dca2018-08-29 17:44:34 +08001408 }
1409
1410 @Nullable
1411 ActivityStack getHomeStack() {
1412 return mHomeStack;
1413 }
1414
1415 @Nullable
1416 ActivityRecord getHomeActivity() {
Wale Ogunwaled32da472018-11-16 07:19:28 -08001417 return getHomeActivityForUser(mRootActivityContainer.mCurrentUser);
Louis Changbd48dca2018-08-29 17:44:34 +08001418 }
1419
1420 @Nullable
1421 ActivityRecord getHomeActivityForUser(int userId) {
1422 if (mHomeStack == null) {
1423 return null;
1424 }
1425
1426 final ArrayList<TaskRecord> tasks = mHomeStack.getAllTasks();
1427 for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
1428 final TaskRecord task = tasks.get(taskNdx);
1429 if (!task.isActivityTypeHome()) {
1430 continue;
1431 }
1432
Wale Ogunwale1a06f152019-10-11 11:26:30 +02001433 for (int activityNdx = task.getChildCount() - 1; activityNdx >= 0; --activityNdx) {
1434 final ActivityRecord r = task.getChildAt(activityNdx);
Louis Changbd48dca2018-08-29 17:44:34 +08001435 if (r.isActivityTypeHome()
Wale Ogunwale8b19de92018-11-29 19:58:26 -08001436 && ((userId == UserHandle.USER_ALL) || (r.mUserId == userId))) {
Louis Changbd48dca2018-08-29 17:44:34 +08001437 return r;
1438 }
1439 }
1440 }
1441 return null;
1442 }
1443
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001444 boolean isSleeping() {
1445 return mSleeping;
1446 }
1447
1448 void setIsSleeping(boolean asleep) {
1449 mSleeping = asleep;
1450 }
1451
Winson Chung0f7ec962018-05-03 18:03:15 -07001452 /**
1453 * Adds a listener to be notified whenever the stack order in the display changes. Currently
1454 * only used by the {@link RecentsAnimation} to determine whether to interrupt and cancel the
1455 * current animation when the system state changes.
1456 */
1457 void registerStackOrderChangedListener(OnStackOrderChangedListener listener) {
1458 if (!mStackOrderChangedCallbacks.contains(listener)) {
1459 mStackOrderChangedCallbacks.add(listener);
1460 }
1461 }
1462
1463 /**
1464 * Removes a previously registered stack order change listener.
1465 */
1466 void unregisterStackOrderChangedListener(OnStackOrderChangedListener listener) {
1467 mStackOrderChangedCallbacks.remove(listener);
1468 }
1469
Winson Chung65d66d32018-12-13 17:48:39 -08001470 /**
1471 * Notifies of a stack order change
1472 * @param stack The stack which triggered the order change
1473 */
1474 private void onStackOrderChanged(ActivityStack stack) {
Winson Chung0f7ec962018-05-03 18:03:15 -07001475 for (int i = mStackOrderChangedCallbacks.size() - 1; i >= 0; i--) {
Winson Chung65d66d32018-12-13 17:48:39 -08001476 mStackOrderChangedCallbacks.get(i).onStackOrderChanged(stack);
Winson Chung0f7ec962018-05-03 18:03:15 -07001477 }
1478 }
1479
Chavi Weingarten3a748552018-05-14 17:32:42 +00001480 /**
Wale Ogunwale3a256e62018-12-06 14:41:18 -08001481 * See {@link DisplayContent#deferUpdateImeTarget()}
Chavi Weingarten3a748552018-05-14 17:32:42 +00001482 */
1483 public void deferUpdateImeTarget() {
Wale Ogunwale3a256e62018-12-06 14:41:18 -08001484 if (mDisplayContent != null) {
1485 mDisplayContent.deferUpdateImeTarget();
1486 }
Chavi Weingarten3a748552018-05-14 17:32:42 +00001487 }
1488
1489 /**
Wale Ogunwale3a256e62018-12-06 14:41:18 -08001490 * See {@link DisplayContent#deferUpdateImeTarget()}
Chavi Weingarten3a748552018-05-14 17:32:42 +00001491 */
1492 public void continueUpdateImeTarget() {
Wale Ogunwale3a256e62018-12-06 14:41:18 -08001493 if (mDisplayContent != null) {
1494 mDisplayContent.continueUpdateImeTarget();
1495 }
Chavi Weingarten3a748552018-05-14 17:32:42 +00001496 }
1497
Wale Ogunwale9e737db2018-12-17 15:42:37 -08001498 void setDisplayToSingleTaskInstance() {
1499 final int childCount = getChildCount();
1500 if (childCount > 1) {
1501 throw new IllegalArgumentException("Display already has multiple stacks. display="
1502 + this);
1503 }
1504 if (childCount > 0) {
1505 final ActivityStack stack = getChildAt(0);
1506 if (stack.getChildCount() > 1) {
1507 throw new IllegalArgumentException("Display stack already has multiple tasks."
1508 + " display=" + this + " stack=" + stack);
1509 }
1510 }
1511
1512 mSingleTaskInstance = true;
1513 }
1514
1515 /** Returns true if the display can only contain one task */
1516 boolean isSingleTaskInstance() {
1517 return mSingleTaskInstance;
1518 }
1519
Wale Ogunwale8a1860a2019-06-05 08:57:19 -07001520 @VisibleForTesting
1521 void removeAllTasks() {
1522 for (int i = getChildCount() - 1; i >= 0; --i) {
1523 final ActivityStack stack = getChildAt(i);
1524 final ArrayList<TaskRecord> tasks = stack.getAllTasks();
1525 for (int j = tasks.size() - 1; j >= 0; --j) {
1526 stack.removeTask(tasks.get(j), "removeAllTasks", REMOVE_TASK_MODE_DESTROYING);
1527 }
1528 }
1529 }
1530
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -07001531 public void dump(PrintWriter pw, String prefix) {
Wale Ogunwale9e737db2018-12-17 15:42:37 -08001532 pw.println(prefix + "displayId=" + mDisplayId + " stacks=" + mStacks.size()
1533 + (mSingleTaskInstance ? " mSingleTaskInstance" : ""));
Wale Ogunwale30e441d2017-11-09 08:28:45 -08001534 final String myPrefix = prefix + " ";
1535 if (mHomeStack != null) {
1536 pw.println(myPrefix + "mHomeStack=" + mHomeStack);
1537 }
1538 if (mRecentsStack != null) {
1539 pw.println(myPrefix + "mRecentsStack=" + mRecentsStack);
1540 }
1541 if (mPinnedStack != null) {
1542 pw.println(myPrefix + "mPinnedStack=" + mPinnedStack);
1543 }
1544 if (mSplitScreenPrimaryStack != null) {
1545 pw.println(myPrefix + "mSplitScreenPrimaryStack=" + mSplitScreenPrimaryStack);
1546 }
Riddle Hsu75016992018-09-20 20:37:14 +08001547 if (mPreferredTopFocusableStack != null) {
1548 pw.println(myPrefix + "mPreferredTopFocusableStack=" + mPreferredTopFocusableStack);
1549 }
Riddle Hsubbb63c22018-10-03 12:28:29 +08001550 if (mLastFocusedStack != null) {
1551 pw.println(myPrefix + "mLastFocusedStack=" + mLastFocusedStack);
1552 }
Wale Ogunwalea0f5b5e2017-10-11 09:37:23 -07001553 }
1554
Bryce Lee77a7dd62018-01-22 15:47:09 -08001555 public void dumpStacks(PrintWriter pw) {
1556 for (int i = mStacks.size() - 1; i >= 0; --i) {
1557 pw.print(mStacks.get(i).mStackId);
1558 if (i > 0) {
1559 pw.print(",");
1560 }
1561 }
1562 }
1563
Nataniel Borges023ecb52019-01-16 14:15:43 -08001564 public void writeToProto(ProtoOutputStream proto, long fieldId,
1565 @WindowTraceLogLevel int logLevel) {
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001566 final long token = proto.start(fieldId);
Nataniel Borges023ecb52019-01-16 14:15:43 -08001567 super.writeToProto(proto, CONFIGURATION_CONTAINER, logLevel);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001568 proto.write(ID, mDisplayId);
Wale Ogunwale9e737db2018-12-17 15:42:37 -08001569 proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance);
Andrii Kulianab132ee2018-07-24 22:10:21 +08001570 final ActivityStack focusedStack = getFocusedStack();
1571 if (focusedStack != null) {
1572 proto.write(FOCUSED_STACK_ID, focusedStack.mStackId);
1573 final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity();
1574 if (focusedActivity != null) {
1575 focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
1576 }
1577 } else {
1578 proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
1579 }
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001580 for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
1581 final ActivityStack stack = mStacks.get(stackNdx);
Nataniel Borges023ecb52019-01-16 14:15:43 -08001582 stack.writeToProto(proto, STACKS, logLevel);
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001583 }
1584 proto.end(token);
1585 }
Winson Chung0f7ec962018-05-03 18:03:15 -07001586
1587 /**
1588 * Callback for when the order of the stacks in the display changes.
1589 */
1590 interface OnStackOrderChangedListener {
Winson Chung65d66d32018-12-13 17:48:39 -08001591 void onStackOrderChanged(ActivityStack stack);
Winson Chung0f7ec962018-05-03 18:03:15 -07001592 }
Wale Ogunwale9dcf9462017-09-19 15:13:01 -07001593}