blob: 06e5ac5d440ed50a51c3bd4b1c69ec6409afb284 [file] [log] [blame]
Craig Mautnerc00204b2013-03-05 15:02:14 -08001/*
2 * Copyright (C) 2013 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
17package com.android.server.wm;
18
Wale Ogunwale3797c222015-10-27 14:21:58 -070019import android.app.ActivityManager.StackId;
Wale Ogunwale60454db2015-01-23 16:05:07 -080020import android.content.res.Configuration;
Craig Mautner05d29032013-05-03 13:40:13 -070021import android.graphics.Rect;
Craig Mautnerf0ac5c82013-06-24 11:21:57 -070022import android.os.Debug;
Filip Gruszczynski84fa3352016-01-25 16:28:49 -080023import android.os.RemoteException;
Craig Mautner2c2549c2013-11-12 08:31:15 -080024import android.util.EventLog;
Craig Mautnerf0ac5c82013-06-24 11:21:57 -070025import android.util.Slog;
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -070026import android.util.SparseArray;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -070027import android.view.DisplayInfo;
Wale Ogunwale94744212015-09-21 19:01:47 -070028import android.view.Surface;
Filip Gruszczynski54977fe2015-10-19 17:26:45 -070029
Jorim Jaggi737af722015-12-31 10:42:27 +010030import com.android.internal.policy.DividerSnapAlgorithm;
31import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
32import com.android.internal.policy.DockedDividerUtils;
Craig Mautner2c2549c2013-11-12 08:31:15 -080033import com.android.server.EventLogTags;
Craig Mautner05d29032013-05-03 13:40:13 -070034
Craig Mautner00af9fe2013-03-25 09:13:41 -070035import java.io.PrintWriter;
Craig Mautnerc00204b2013-03-05 15:02:14 -080036import java.util.ArrayList;
37
Jorim Jaggi61f39a72015-10-29 16:54:18 +010038import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
39import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
40import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
Wale Ogunwale480dca02016-02-06 13:58:29 -080041import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
Jorim Jaggid434dcb2016-01-06 17:18:44 +010042import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010043import static android.view.WindowManager.DOCKED_BOTTOM;
44import static android.view.WindowManager.DOCKED_INVALID;
45import static android.view.WindowManager.DOCKED_LEFT;
46import static android.view.WindowManager.DOCKED_RIGHT;
47import static android.view.WindowManager.DOCKED_TOP;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080048import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010049import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080050import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010051
Filip Gruszczynski84fa3352016-01-25 16:28:49 -080052public class TaskStack implements DimLayer.DimLayerUser,
53 BoundsAnimationController.AnimateBoundsUser {
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -070054
55 // If the stack should be resized to fullscreen.
56 private static final boolean FULLSCREEN = true;
57
Craig Mautner00af9fe2013-03-25 09:13:41 -070058 /** Unique identifier */
Craig Mautnerc00204b2013-03-05 15:02:14 -080059 final int mStackId;
Craig Mautner00af9fe2013-03-25 09:13:41 -070060
Craig Mautner05d29032013-05-03 13:40:13 -070061 /** The service */
62 private final WindowManagerService mService;
63
Craig Mautner00af9fe2013-03-25 09:13:41 -070064 /** The display this stack sits under. */
Craig Mautnerdf88d732014-01-27 09:21:32 -080065 private DisplayContent mDisplayContent;
Craig Mautner00af9fe2013-03-25 09:13:41 -070066
67 /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
68 * mTaskHistory in the ActivityStack with the same mStackId */
Wale Ogunwalee4a0c572015-06-30 08:40:31 -070069 private final ArrayList<Task> mTasks = new ArrayList<>();
Craig Mautner00af9fe2013-03-25 09:13:41 -070070
Craig Mautnerb660b9d2014-02-13 10:59:16 -080071 /** For comparison with DisplayContent bounds. */
72 private Rect mTmpRect = new Rect();
Wale Ogunwalee45899a2015-10-01 11:30:34 -070073 private Rect mTmpRect2 = new Rect();
Craig Mautnerb660b9d2014-02-13 10:59:16 -080074
75 /** Content limits relative to the DisplayContent this sits in. */
76 private Rect mBounds = new Rect();
77
Chong Zhangb816b862016-01-25 12:01:12 -080078 /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
79 private final Rect mAdjustedBounds = new Rect();
80
Craig Mautnerb660b9d2014-02-13 10:59:16 -080081 /** Whether mBounds is fullscreen */
82 private boolean mFullscreen = true;
Craig Mautnerc00204b2013-03-05 15:02:14 -080083
Wale Ogunwale94744212015-09-21 19:01:47 -070084 // Device rotation as of the last time {@link #mBounds} was set.
85 int mRotation;
86
Craig Mautner05d29032013-05-03 13:40:13 -070087 /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
Craig Mautnerdf88d732014-01-27 09:21:32 -080088 DimLayer mAnimationBackgroundSurface;
Craig Mautner05d29032013-05-03 13:40:13 -070089
90 /** The particular window with an Animation with non-zero background color. */
91 WindowStateAnimator mAnimationBackgroundAnimator;
92
Craig Mautnerdc548482014-02-05 13:35:24 -080093 /** Application tokens that are exiting, but still on screen for animations. */
94 final AppTokenList mExitingAppTokens = new AppTokenList();
95
Craig Mautner95da1082014-02-24 17:54:35 -080096 /** Detach this stack from its display when animation completes. */
97 boolean mDeferDetach;
Wale Ogunwaleecbcadd2016-02-21 14:18:51 -080098
99 // Display rotation as of the last time the display information was updated for this stack.
100 private int mLastUpdateDisplayInfoRotation = -1;
101 // Display rotation as of the last time the configuration was updated for this stack.
102 private int mLastConfigChangedRotation = -1;
Craig Mautner95da1082014-02-24 17:54:35 -0800103
Wale Ogunwalece144522016-02-05 22:51:01 -0800104 // Whether the stack and all its tasks is currently being drag-resized
105 private boolean mDragResizing;
106
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800107 private final Rect mLastContentBounds = new Rect();
108 private final Rect mTmpAdjustedBounds = new Rect();
109 private boolean mAdjustedForIme;
110 private WindowState mImeWin;
111 private float mMinimizeAmount;
112 private final int mDockedStackMinimizeThickness;
113
Craig Mautnerdf88d732014-01-27 09:21:32 -0800114 TaskStack(WindowManagerService service, int stackId) {
Craig Mautner05d29032013-05-03 13:40:13 -0700115 mService = service;
Craig Mautnerc00204b2013-03-05 15:02:14 -0800116 mStackId = stackId;
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800117 mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
118 com.android.internal.R.dimen.docked_stack_minimize_thickness);
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700119 EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
Craig Mautnerc00204b2013-03-05 15:02:14 -0800120 }
121
122 DisplayContent getDisplayContent() {
123 return mDisplayContent;
124 }
125
Craig Mautnerd9a22882013-03-16 15:00:36 -0700126 ArrayList<Task> getTasks() {
127 return mTasks;
128 }
129
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700130 /**
131 * Set the bounds of the stack and its containing tasks.
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700132 * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700133 * @param configs Configuration for individual tasks, keyed by task id.
134 * @param taskBounds Bounds for individual tasks, keyed by task id.
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700135 * @return True if the stack bounds was changed.
136 * */
Wale Ogunwalea6e902e2015-09-21 18:37:15 -0700137 boolean setBounds(
Jorim Jaggidc249c42015-12-15 14:57:31 -0800138 Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
139 SparseArray<Rect> taskTempInsetBounds) {
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700140 if (!setBounds(stackBounds)) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700141 return false;
142 }
143
144 // Update bounds of containing tasks.
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700145 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
146 final Task task = mTasks.get(taskNdx);
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700147 Configuration config = configs.get(task.mTaskId);
148 if (config != null) {
149 Rect bounds = taskBounds.get(task.mTaskId);
Chong Zhang2a88fc32016-01-11 17:14:24 -0800150 if (task.isTwoFingerScrollMode()) {
Chong Zhangb15758a2015-11-17 12:12:03 -0800151 // This is a non-resizeable task that's docked (or side-by-side to the docked
152 // stack). It might have been scrolled previously, and after the stack resizing,
153 // it might no longer fully cover the stack area.
154 // Save the old bounds and re-apply the scroll. This adjusts the bounds to
155 // fit the new stack bounds.
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100156 task.resizeLocked(bounds, config, false /* forced */);
Chong Zhangf66db432016-01-13 10:39:51 -0800157 task.getBounds(mTmpRect);
Chong Zhangb15758a2015-11-17 12:12:03 -0800158 task.scrollLocked(mTmpRect);
159 } else {
Jorim Jaggi4846ee32016-01-07 17:39:12 +0100160 task.resizeLocked(bounds, config, false /* forced */);
Jorim Jaggidc249c42015-12-15 14:57:31 -0800161 task.setTempInsetBounds(
162 taskTempInsetBounds != null ? taskTempInsetBounds.get(task.mTaskId)
163 : null);
Chong Zhangb15758a2015-11-17 12:12:03 -0800164 }
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700165 } else {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800166 Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700167 }
168 }
169 return true;
170 }
171
Jorim Jaggi0429f352015-12-22 16:29:16 +0100172 void prepareFreezingTaskBounds() {
173 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
174 final Task task = mTasks.get(taskNdx);
175 task.prepareFreezingBounds();
176 }
177 }
178
Wale Ogunwaleb4ec0a32015-12-14 10:31:43 -0800179 boolean isFullscreenBounds(Rect bounds) {
180 if (mDisplayContent == null || bounds == null) {
181 return true;
182 }
183 mDisplayContent.getLogicalDisplayRect(mTmpRect);
184 return mTmpRect.equals(bounds);
185 }
186
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800187 /**
188 * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
189 * the normal task bounds.
190 *
191 * @param bounds The adjusted bounds.
192 * @param keepInsets Whether to keep the insets from the original bounds or to calculate new
193 * ones depending on the adjusted bounds.
194 */
195 private void setAdjustedBounds(Rect bounds, boolean keepInsets) {
196 if (mAdjustedBounds.equals(bounds)) {
197 return;
198 }
199
200 mAdjustedBounds.set(bounds);
201 final boolean adjusted = !mAdjustedBounds.isEmpty();
202 alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds,
203 adjusted && keepInsets ? mBounds : null);
204 mDisplayContent.layoutNeeded = true;
205 }
206
207 private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
Chong Zhangb816b862016-01-25 12:01:12 -0800208 if (mFullscreen) {
209 return;
210 }
211 // Update bounds of containing tasks.
212 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
213 final Task task = mTasks.get(taskNdx);
214 if (task.isTwoFingerScrollMode()) {
215 // If we're scrolling we don't care about your bounds or configs,
216 // they should be null as if we were in fullscreen.
217 task.resizeLocked(null, null, false /* forced */);
218 task.getBounds(mTmpRect2);
219 task.scrollLocked(mTmpRect2);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800220 } else if (task.isResizeable() && task.mOverrideConfig != Configuration.EMPTY) {
Chong Zhangb816b862016-01-25 12:01:12 -0800221 task.getBounds(mTmpRect2);
222 mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800223 task.setTempInsetBounds(tempInsetBounds);
Chong Zhangb816b862016-01-25 12:01:12 -0800224 task.resizeLocked(mTmpRect2, task.mOverrideConfig, false /* forced */);
225 }
226 }
227 }
228
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700229 private boolean setBounds(Rect bounds) {
Craig Mautnerb660b9d2014-02-13 10:59:16 -0800230 boolean oldFullscreen = mFullscreen;
Wale Ogunwale94744212015-09-21 19:01:47 -0700231 int rotation = Surface.ROTATION_0;
Craig Mautnerb660b9d2014-02-13 10:59:16 -0800232 if (mDisplayContent != null) {
233 mDisplayContent.getLogicalDisplayRect(mTmpRect);
Wale Ogunwale94744212015-09-21 19:01:47 -0700234 rotation = mDisplayContent.getDisplayInfo().rotation;
Jorim Jaggi067e8172016-02-03 18:24:12 -0800235 mFullscreen = bounds == null;
236 if (mFullscreen) {
Wale Ogunwale9d3de4c2015-02-01 16:49:44 -0800237 bounds = mTmpRect;
Wale Ogunwale9d3de4c2015-02-01 16:49:44 -0800238 }
Craig Mautnerb660b9d2014-02-13 10:59:16 -0800239 }
240
Wale Ogunwale9d3de4c2015-02-01 16:49:44 -0800241 if (bounds == null) {
Wale Ogunwale4a02d812015-02-12 23:01:38 -0800242 // Can't set to fullscreen if we don't have a display to get bounds from...
Wale Ogunwale9d3de4c2015-02-01 16:49:44 -0800243 return false;
244 }
Wale Ogunwale94744212015-09-21 19:01:47 -0700245 if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800246 return false;
247 }
248
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700249 if (mDisplayContent != null) {
Chong Zhang112eb8c2015-11-02 11:17:00 -0800250 mDisplayContent.mDimLayerController.updateDimLayer(this);
Filip Gruszczynski57b6cce2015-10-06 09:50:51 -0700251 mAnimationBackgroundSurface.setBounds(bounds);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700252 }
253
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800254 mBounds.set(bounds);
Wale Ogunwale94744212015-09-21 19:01:47 -0700255 mRotation = rotation;
Chong Zhangb816b862016-01-25 12:01:12 -0800256
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800257 updateAdjustedBounds();
Chong Zhangb816b862016-01-25 12:01:12 -0800258
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800259 return true;
260 }
261
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700262 /** Bounds of the stack without adjusting for other factors in the system like visibility
263 * of docked stack.
264 * Most callers should be using {@link #getBounds} as it take into consideration other system
265 * factors. */
266 void getRawBounds(Rect out) {
Craig Mautnerb660b9d2014-02-13 10:59:16 -0800267 out.set(mBounds);
268 }
269
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700270 /** Return true if the current bound can get outputted to the rest of the system as-is. */
271 private boolean useCurrentBounds() {
272 if (mFullscreen
Wale Ogunwale3797c222015-10-27 14:21:58 -0700273 || !StackId.isResizeableByDockedStack(mStackId)
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700274 || mDisplayContent == null
275 || mDisplayContent.getDockedStackLocked() != null) {
276 return true;
277 }
278 return false;
279 }
280
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700281 public void getBounds(Rect out) {
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700282 if (useCurrentBounds()) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800283 // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
284 // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
285 // stack is visible since it is already what we want to represent to the rest of the
286 // system.
287 if (!mAdjustedBounds.isEmpty()) {
Chong Zhangb816b862016-01-25 12:01:12 -0800288 out.set(mAdjustedBounds);
289 } else {
290 out.set(mBounds);
291 }
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700292 return;
293 }
294
295 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
296 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
297 // system.
298 mDisplayContent.getLogicalDisplayRect(out);
299 }
300
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800301 /** Bounds of the stack with other system factors taken into consideration. */
302 @Override
303 public void getDimBounds(Rect out) {
304 getBounds(out);
305 }
306
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700307 void updateDisplayInfo(Rect bounds) {
Wale Ogunwaleecbcadd2016-02-21 14:18:51 -0800308 if (mDisplayContent == null) {
309 return;
310 }
Jorim Jaggi737af722015-12-31 10:42:27 +0100311
Wale Ogunwaleecbcadd2016-02-21 14:18:51 -0800312 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
313 mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
314 }
315 if (bounds != null) {
316 setBounds(bounds);
317 return;
318 } else if (mFullscreen) {
319 setBounds(null);
320 return;
321 }
322
323 mTmpRect2.set(mBounds);
324 final int newRotation = mDisplayContent.getDisplayInfo().rotation;
325 if (mRotation == newRotation) {
326 setBounds(mTmpRect2);
327 } else {
328 mLastUpdateDisplayInfoRotation = newRotation;
329 updateBoundsAfterRotation();
Wale Ogunwale9d3de4c2015-02-01 16:49:44 -0800330 }
331 }
332
Wale Ogunwaleecbcadd2016-02-21 14:18:51 -0800333 void onConfigurationChanged() {
334 mLastConfigChangedRotation = getDisplayInfo().rotation;
335 updateBoundsAfterRotation();
336 }
337
Jorim Jaggi737af722015-12-31 10:42:27 +0100338 void updateBoundsAfterRotation() {
Wale Ogunwaleecbcadd2016-02-21 14:18:51 -0800339 if (mLastConfigChangedRotation != mLastUpdateDisplayInfoRotation) {
340 // We wait for the rotation values after configuration change and display info. update
341 // to be equal before updating the bounds due to rotation change otherwise things might
342 // get out of alignment...
Filip Gruszczynskidce2d162016-01-12 15:40:13 -0800343 return;
344 }
Wale Ogunwaleecbcadd2016-02-21 14:18:51 -0800345
Jorim Jaggi737af722015-12-31 10:42:27 +0100346 final int newRotation = getDisplayInfo().rotation;
Wale Ogunwaleecbcadd2016-02-21 14:18:51 -0800347
348 if (mRotation == newRotation) {
349 // Nothing to do here if the rotation didn't change
350 return;
351 }
352
Jorim Jaggi737af722015-12-31 10:42:27 +0100353 mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
354 if (mStackId == DOCKED_STACK_ID) {
355 snapDockedStackAfterRotation(mTmpRect2);
356 }
357
358 // Post message to inform activity manager of the bounds change simulating
359 // a one-way call. We do this to prevent a deadlock between window manager
360 // lock and activity manager lock been held.
Wale Ogunwaleecbcadd2016-02-21 14:18:51 -0800361 mService.mH.obtainMessage(
362 RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget();
Jorim Jaggi737af722015-12-31 10:42:27 +0100363 }
364
365 /**
366 * Snaps the bounds after rotation to the closest snap target for the docked stack.
367 */
368 private void snapDockedStackAfterRotation(Rect outBounds) {
369
370 // Calculate the current position.
371 final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
372 final int dividerSize = mService.getDefaultDisplayContentLocked()
373 .getDockedDividerController().getContentWidth();
374 final int dockSide = getDockSide(outBounds);
375 final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
376 dockSide, dividerSize);
377 final int displayWidth = mDisplayContent.getDisplayInfo().logicalWidth;
378 final int displayHeight = mDisplayContent.getDisplayInfo().logicalHeight;
379
380 // Snap the position to a target.
381 final int rotation = displayInfo.rotation;
382 final int orientation = mService.mCurConfiguration.orientation;
383 mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
384 final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
Jorim Jaggidf012d52016-01-15 22:40:13 -0800385 mService.mContext.getResources(), displayWidth, displayHeight,
Jorim Jaggi737af722015-12-31 10:42:27 +0100386 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds);
387 final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
388
389 // Recalculate the bounds based on the position of the target.
390 DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
391 outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight,
392 dividerSize);
393 }
394
Craig Mautner1bf2b872014-02-05 15:37:40 -0800395 boolean isAnimating() {
396 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
397 final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
398 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
399 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
400 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700401 final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
Wale Ogunwalec48a3542016-02-19 15:18:45 -0800402 if (winAnimator.isAnimating() || winAnimator.mWin.mAnimatingExit) {
Craig Mautner1bf2b872014-02-05 15:37:40 -0800403 return true;
404 }
405 }
406 }
407 }
408 return false;
409 }
410
Wale Ogunwale3fcb4a82015-04-06 14:00:13 -0700411 void addTask(Task task, boolean toTop) {
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700412 addTask(task, toTop, task.showForAllUsers());
Wale Ogunwale3fcb4a82015-04-06 14:00:13 -0700413 }
414
Craig Mautner00af9fe2013-03-25 09:13:41 -0700415 /**
416 * Put a Task in this stack. Used for adding and moving.
417 * @param task The task to add.
418 * @param toTop Whether to add it to the top or bottom.
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700419 * @param showForAllUsers Whether to show the task regardless of the current user.
Craig Mautner00af9fe2013-03-25 09:13:41 -0700420 */
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700421 void addTask(Task task, boolean toTop, boolean showForAllUsers) {
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700422 positionTask(task, toTop ? mTasks.size() : 0, showForAllUsers);
423 }
424
425 void positionTask(Task task, int position, boolean showForAllUsers) {
426 final boolean canShowTask =
427 showForAllUsers || mService.isCurrentProfileLocked(task.mUserId);
428 mTasks.remove(task);
429 int stackSize = mTasks.size();
430 int minPosition = 0;
431 int maxPosition = stackSize;
432
433 if (canShowTask) {
434 minPosition = computeMinPosition(minPosition, stackSize);
Craig Mautnerac6f8432013-07-17 13:24:59 -0700435 } else {
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700436 maxPosition = computeMaxPosition(maxPosition);
Craig Mautnerac6f8432013-07-17 13:24:59 -0700437 }
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700438 // Reset position based on minimum/maximum possible positions.
439 position = Math.min(Math.max(position, minPosition), maxPosition);
440
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800441 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM,
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700442 "positionTask: task=" + task + " position=" + position);
443 mTasks.add(position, task);
Craig Mautnerac6f8432013-07-17 13:24:59 -0700444
Chong Zhangf66db432016-01-13 10:39:51 -0800445 // If we are moving the task across stacks, the scroll is no longer valid.
446 if (task.mStack != this) {
447 task.resetScrollLocked();
448 }
Craig Mautner967212c2013-04-13 21:10:58 -0700449 task.mStack = this;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700450 task.updateDisplayInfo(mDisplayContent);
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700451 boolean toTop = position == mTasks.size() - 1;
raysb.kim00a27252014-11-11 08:38:21 +0900452 if (toTop) {
453 mDisplayContent.moveStack(this, true);
454 }
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700455 EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, position);
456 }
457
458 /** Calculate the minimum possible position for a task that can be shown to the user.
459 * The minimum position will be above all other tasks that can't be shown.
460 * @param minPosition The minimum position the caller is suggesting.
461 * We will start adjusting up from here.
462 * @param size The size of the current task list.
463 */
464 private int computeMinPosition(int minPosition, int size) {
465 while (minPosition < size) {
466 final Task tmpTask = mTasks.get(minPosition);
467 final boolean canShowTmpTask =
468 tmpTask.showForAllUsers()
469 || mService.isCurrentProfileLocked(tmpTask.mUserId);
470 if (canShowTmpTask) {
471 break;
472 }
473 minPosition++;
474 }
475 return minPosition;
476 }
477
478 /** Calculate the maximum possible position for a task that can't be shown to the user.
479 * The maximum position will be below all other tasks that can be shown.
480 * @param maxPosition The maximum position the caller is suggesting.
481 * We will start adjusting down from here.
482 */
483 private int computeMaxPosition(int maxPosition) {
484 while (maxPosition > 0) {
485 final Task tmpTask = mTasks.get(maxPosition - 1);
486 final boolean canShowTmpTask =
487 tmpTask.showForAllUsers()
488 || mService.isCurrentProfileLocked(tmpTask.mUserId);
489 if (!canShowTmpTask) {
490 break;
491 }
492 maxPosition--;
493 }
494 return maxPosition;
Craig Mautnerc00204b2013-03-05 15:02:14 -0800495 }
496
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800497 void moveTaskToTop(Task task) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800498 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToTop: task=" + task + " Callers="
Craig Mautnerf0ac5c82013-06-24 11:21:57 -0700499 + Debug.getCallers(6));
Craig Mautnerd9a22882013-03-16 15:00:36 -0700500 mTasks.remove(task);
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800501 addTask(task, true);
Craig Mautnerd9a22882013-03-16 15:00:36 -0700502 }
503
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800504 void moveTaskToBottom(Task task) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800505 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToBottom: task=" + task);
Craig Mautnerd9a22882013-03-16 15:00:36 -0700506 mTasks.remove(task);
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800507 addTask(task, false);
Craig Mautnerd9a22882013-03-16 15:00:36 -0700508 }
509
Craig Mautner00af9fe2013-03-25 09:13:41 -0700510 /**
Craig Mautner04a0ea62014-01-13 12:51:26 -0800511 * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the
512 * back.
Craig Mautner00af9fe2013-03-25 09:13:41 -0700513 * @param task The Task to delete.
Craig Mautner00af9fe2013-03-25 09:13:41 -0700514 */
Craig Mautnerde4ef022013-04-07 19:01:33 -0700515 void removeTask(Task task) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800516 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeTask: task=" + task);
Craig Mautnerde4ef022013-04-07 19:01:33 -0700517 mTasks.remove(task);
Craig Mautnerdf88d732014-01-27 09:21:32 -0800518 if (mDisplayContent != null) {
Craig Mautnerdf88d732014-01-27 09:21:32 -0800519 if (mTasks.isEmpty()) {
520 mDisplayContent.moveStack(this, false);
521 }
522 mDisplayContent.layoutNeeded = true;
Craig Mautner04a0ea62014-01-13 12:51:26 -0800523 }
Craig Mautnere3119b72015-01-20 15:02:36 -0800524 for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) {
525 final AppWindowToken wtoken = mExitingAppTokens.get(appNdx);
Craig Mautner83162a92015-01-26 14:43:30 -0800526 if (wtoken.mTask == task) {
Craig Mautnere3119b72015-01-20 15:02:36 -0800527 wtoken.mIsExiting = false;
528 mExitingAppTokens.remove(appNdx);
529 }
530 }
Craig Mautnerc00204b2013-03-05 15:02:14 -0800531 }
532
Craig Mautnerdf88d732014-01-27 09:21:32 -0800533 void attachDisplayContent(DisplayContent displayContent) {
534 if (mDisplayContent != null) {
535 throw new IllegalStateException("attachDisplayContent: Already attached");
Craig Mautner4a1cb222013-12-04 16:14:06 -0800536 }
Craig Mautnerdf88d732014-01-27 09:21:32 -0800537
538 mDisplayContent = displayContent;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700539 mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId());
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700540
541 Rect bounds = null;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700542 final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
Wale Ogunwale3797c222015-10-27 14:21:58 -0700543 if (mStackId == DOCKED_STACK_ID
544 || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId))) {
545 // The existence of a docked stack affects the size of other static stack created since
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700546 // the docked stack occupies a dedicated region on screen.
547 bounds = new Rect();
548 displayContent.getLogicalDisplayRect(mTmpRect);
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700549 mTmpRect2.setEmpty();
550 if (dockedStack != null) {
551 dockedStack.getRawBounds(mTmpRect2);
552 }
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800553 final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700554 == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
555 getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2,
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100556 mDisplayContent.mDividerControllerLocked.getContentWidth(),
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700557 dockedOnTopOrLeft);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700558 }
559
560 updateDisplayInfo(bounds);
561
562 if (mStackId == DOCKED_STACK_ID) {
563 // Attaching a docked stack to the display affects the size of all other static
564 // stacks since the docked stack occupies a dedicated region on screen.
565 // Resize existing static stacks so they are pushed to the side of the docked stack.
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700566 resizeNonDockedStacks(!FULLSCREEN, mBounds);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700567 }
568 }
569
Wale Ogunwale961f4852016-02-01 20:25:54 -0800570 void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) {
Wale Ogunwalea9f9b372016-02-04 18:04:39 -0800571 if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId))
572 || mDisplayContent == null) {
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700573 outBounds.set(mBounds);
574 return;
575 }
576
Filip Gruszczynski54977fe2015-10-19 17:26:45 -0700577 final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700578 if (dockedStack == null) {
579 // Not sure why you are calling this method when there is no docked stack...
580 throw new IllegalStateException(
581 "Calling getStackDockedModeBoundsLocked() when there is no docked stack.");
582 }
Wale Ogunwale961f4852016-02-01 20:25:54 -0800583 if (!ignoreVisibility && !dockedStack.isVisibleLocked()) {
Filip Gruszczynski54977fe2015-10-19 17:26:45 -0700584 // The docked stack is being dismissed, but we caught before it finished being
585 // dismissed. In that case we want to treat it as if it is not occupying any space and
586 // let others occupy the whole display.
Wale Ogunwaleccb6ce22016-01-14 15:36:35 -0800587 mDisplayContent.getLogicalDisplayRect(outBounds);
Filip Gruszczynski54977fe2015-10-19 17:26:45 -0700588 return;
589 }
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700590
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700591 final int dockedSide = dockedStack.getDockSide();
592 if (dockedSide == DOCKED_INVALID) {
593 // Not sure how you got here...Only thing we can do is return current bounds.
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800594 Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack);
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700595 outBounds.set(mBounds);
596 return;
597 }
598
599 mDisplayContent.getLogicalDisplayRect(mTmpRect);
600 dockedStack.getRawBounds(mTmpRect2);
Wale Ogunwalea9f9b372016-02-04 18:04:39 -0800601 final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700602 getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2,
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100603 mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700604
605 }
606
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700607 /**
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700608 * Outputs the bounds a stack should be given the presence of a docked stack on the display.
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700609 * @param displayRect The bounds of the display the docked stack is on.
610 * @param outBounds Output bounds that should be used for the stack.
611 * @param stackId Id of stack we are calculating the bounds for.
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700612 * @param dockedBounds Bounds of the docked stack.
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700613 * @param dockDividerWidth We need to know the width of the divider make to the output bounds
614 * close to the side of the dock.
615 * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen.
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700616 */
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800617 private void getStackDockedModeBounds(
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700618 Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth,
619 boolean dockOnTopOrLeft) {
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700620 final boolean dockedStack = stackId == DOCKED_STACK_ID;
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700621 final boolean splitHorizontally = displayRect.width() > displayRect.height();
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700622
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700623 outBounds.set(displayRect);
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700624 if (dockedStack) {
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800625 if (mService.mDockedStackCreateBounds != null) {
626 outBounds.set(mService.mDockedStackCreateBounds);
627 return;
628 }
Jorim Jaggid434dcb2016-01-06 17:18:44 +0100629
630 // The initial bounds of the docked stack when it is created about half the screen space
631 // and its bounds can be adjusted after that. The bounds of all other stacks are
632 // adjusted to occupy whatever screen space the docked stack isn't occupying.
633 final DisplayInfo di = mDisplayContent.getDisplayInfo();
634 mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
635 mTmpRect2);
636 final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
Jorim Jaggid434dcb2016-01-06 17:18:44 +0100637 di.logicalWidth,
638 di.logicalHeight,
639 dockDividerWidth,
640 mService.mCurConfiguration.orientation == ORIENTATION_PORTRAIT,
641 mTmpRect2).getMiddleTarget().position;
642
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700643 if (dockOnTopOrLeft) {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700644 if (splitHorizontally) {
Jorim Jaggid434dcb2016-01-06 17:18:44 +0100645 outBounds.right = position;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700646 } else {
Jorim Jaggid434dcb2016-01-06 17:18:44 +0100647 outBounds.bottom = position;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700648 }
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700649 } else {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700650 if (splitHorizontally) {
Jorim Jaggid434dcb2016-01-06 17:18:44 +0100651 outBounds.left = position - dockDividerWidth;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700652 } else {
Jorim Jaggid434dcb2016-01-06 17:18:44 +0100653 outBounds.top = position - dockDividerWidth;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700654 }
655 }
656 return;
657 }
658
659 // Other stacks occupy whatever space is left by the docked stack.
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700660 if (!dockOnTopOrLeft) {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700661 if (splitHorizontally) {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700662 outBounds.right = dockedBounds.left - dockDividerWidth;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700663 } else {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700664 outBounds.bottom = dockedBounds.top - dockDividerWidth;
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700665 }
666 } else {
667 if (splitHorizontally) {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700668 outBounds.left = dockedBounds.right + dockDividerWidth;
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700669 } else {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700670 outBounds.top = dockedBounds.bottom + dockDividerWidth;
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700671 }
672 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800673 DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700674 }
675
676 /** Resizes all non-docked stacks in the system to either fullscreen or the appropriate size
677 * based on the presence of a docked stack.
678 * @param fullscreen If true the stacks will be resized to fullscreen, else they will be
679 * resized to the appropriate size based on the presence of a docked stack.
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700680 * @param dockedBounds Bounds of the docked stack.
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700681 */
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700682 private void resizeNonDockedStacks(boolean fullscreen, Rect dockedBounds) {
683 // Not using mTmpRect because we are posting the object in a message.
684 final Rect bounds = new Rect();
685 mDisplayContent.getLogicalDisplayRect(bounds);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700686 if (!fullscreen) {
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800687 final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700688 == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
689 getStackDockedModeBounds(bounds, bounds, FULLSCREEN_WORKSPACE_STACK_ID, dockedBounds,
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100690 mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700691 }
692
693 final int count = mService.mStackIdToStack.size();
694 for (int i = 0; i < count; i++) {
695 final TaskStack otherStack = mService.mStackIdToStack.valueAt(i);
696 final int otherStackId = otherStack.mStackId;
Wale Ogunwale3856bf72015-11-20 09:36:46 -0800697 if (StackId.isResizeableByDockedStack(otherStackId)
698 && !otherStack.mBounds.equals(bounds)) {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700699 mService.mH.sendMessage(
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700700 mService.mH.obtainMessage(RESIZE_STACK, otherStackId,
Wale Ogunwale3856bf72015-11-20 09:36:46 -0800701 1 /*allowResizeInDockedMode*/, fullscreen ? null : bounds));
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700702 }
703 }
Craig Mautnerdf88d732014-01-27 09:21:32 -0800704 }
705
Wale Ogunwalea9f9b372016-02-04 18:04:39 -0800706 void resetDockedStackToMiddle() {
707 if (mStackId != DOCKED_STACK_ID) {
708 throw new IllegalStateException("Not a docked stack=" + this);
709 }
710
711 mService.mDockedStackCreateBounds = null;
712
713 final Rect bounds = new Rect();
714 getStackDockedModeBoundsLocked(bounds, true /*ignoreVisibility*/);
715 mService.mH.obtainMessage(RESIZE_STACK, DOCKED_STACK_ID,
716 1 /*allowResizeInDockedMode*/, bounds).sendToTarget();
717 }
718
Craig Mautnerdc548482014-02-05 13:35:24 -0800719 void detachDisplay() {
Craig Mautnerdf88d732014-01-27 09:21:32 -0800720 EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700721
722 boolean doAnotherLayoutPass = false;
Craig Mautnerdc548482014-02-05 13:35:24 -0800723 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700724 final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens;
725 for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
726 final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
727 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
Filip Gruszczynskid66af6a2015-08-31 08:57:24 -0700728 // We are in the middle of changing the state of displays/stacks/tasks. We need
729 // to finish that, before we let layout interfere with it.
Filip Gruszczynski49b80af2015-09-24 09:04:26 -0700730 mService.removeWindowLocked(appWindows.get(winNdx));
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700731 doAnotherLayoutPass = true;
732 }
733 }
Craig Mautnerdc548482014-02-05 13:35:24 -0800734 }
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700735 if (doAnotherLayoutPass) {
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700736 mService.mWindowPlacerLocked.requestTraversal();
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700737 }
738
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700739 if (mStackId == DOCKED_STACK_ID) {
740 // Docked stack was detached from the display, so we no longer need to restrict the
741 // region of the screen other static stacks occupy. Go ahead and make them fullscreen.
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700742 resizeNonDockedStacks(FULLSCREEN, null);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700743 }
744
Craig Mautner00a66752015-03-23 14:00:47 -0700745 close();
Craig Mautner00af9fe2013-03-25 09:13:41 -0700746 }
747
Craig Mautner05d29032013-05-03 13:40:13 -0700748 void resetAnimationBackgroundAnimator() {
749 mAnimationBackgroundAnimator = null;
750 mAnimationBackgroundSurface.hide();
751 }
752
Craig Mautner05d29032013-05-03 13:40:13 -0700753 void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
754 int animLayer = winAnimator.mAnimLayer;
755 if (mAnimationBackgroundAnimator == null
756 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) {
757 mAnimationBackgroundAnimator = winAnimator;
758 animLayer = mService.adjustAnimationBackground(winAnimator);
759 mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM,
760 ((color >> 24) & 0xff) / 255f, 0);
761 }
762 }
763
Wale Ogunwale498e8c92015-02-13 09:42:46 -0800764 void switchUser() {
Craig Mautnerac6f8432013-07-17 13:24:59 -0700765 int top = mTasks.size();
766 for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
767 Task task = mTasks.get(taskNdx);
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700768 if (mService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
Craig Mautnerac6f8432013-07-17 13:24:59 -0700769 mTasks.remove(taskNdx);
770 mTasks.add(task);
771 --top;
772 }
773 }
774 }
775
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800776 void close() {
Craig Mautner00a66752015-03-23 14:00:47 -0700777 if (mAnimationBackgroundSurface != null) {
778 mAnimationBackgroundSurface.destroySurface();
779 mAnimationBackgroundSurface = null;
780 }
Filip Gruszczynski26ed2652015-08-10 11:02:53 -0700781 mDisplayContent = null;
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800782 }
783
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800784 /**
785 * Adjusts the stack bounds if the IME is visible.
786 *
787 * @param imeWin The IME window.
788 */
789 void setAdjustedForIme(WindowState imeWin) {
790 mAdjustedForIme = true;
791 mImeWin = imeWin;
792 updateAdjustedBounds();
793 }
794
795 /**
796 * Resets the adjustment after it got adjusted for the IME.
797 */
798 void resetAdjustedForIme() {
799 mAdjustedForIme = false;
800 mImeWin = null;
801 updateAdjustedBounds();
802 }
803
804 /**
805 * Sets the amount how much we currently minimize our stack.
806 *
807 * @param minimizeAmount The amount, between 0 and 1.
808 * @return Whether the amount has changed and a layout is needed.
809 */
810 boolean setAdjustedForMinimizedDock(float minimizeAmount) {
811 if (minimizeAmount != mMinimizeAmount) {
812 mMinimizeAmount = minimizeAmount;
813 updateAdjustedBounds();
814 return isVisibleForUserLocked();
815 } else {
816 return false;
817 }
818 }
819
820 private boolean adjustForIME(final WindowState imeWin) {
821 final int dockedSide = getDockSide();
822 final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
823 final Rect adjustedBounds = mTmpAdjustedBounds;
824 if (imeWin == null || !dockedTopOrBottom) {
825 return false;
826 }
827
828 final Rect displayContentRect = mTmpRect;
829 final Rect contentBounds = mTmpRect2;
830
831 // Calculate the content bounds excluding the area occupied by IME
832 getDisplayContent().getContentRect(displayContentRect);
833 contentBounds.set(displayContentRect);
834 int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
835 imeTop += imeWin.getGivenContentInsetsLw().top;
836 if (contentBounds.bottom > imeTop) {
837 contentBounds.bottom = imeTop;
838 }
839
840 // If content bounds not changing, nothing to do.
841 if (mLastContentBounds.equals(contentBounds)) {
842 return true;
843 }
844
845 // Content bounds changed, need to apply adjustments depending on dock sides.
846 mLastContentBounds.set(contentBounds);
847 adjustedBounds.set(mBounds);
848 final int yOffset = displayContentRect.bottom - contentBounds.bottom;
849
850 if (dockedSide == DOCKED_TOP) {
851 // If this stack is docked on top, we make it smaller so the bottom stack is not
852 // occluded by IME. We shift its bottom up by the height of the IME (capped by
853 // the display content rect). Note that we don't change the task bounds.
854 adjustedBounds.bottom = Math.max(
855 adjustedBounds.bottom - yOffset, displayContentRect.top);
856 } else {
857 // If this stack is docked on bottom, we shift it up so that it's not occluded by
858 // IME. We try to move it up by the height of the IME window (although the best
859 // we could do is to make the top stack fully collapsed).
860 final int dividerWidth = getDisplayContent().mDividerControllerLocked
861 .getContentWidth();
862 adjustedBounds.top = Math.max(
863 adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
864 adjustedBounds.bottom = adjustedBounds.top + mBounds.height();
865 }
866 return true;
867 }
868
869 private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
870 final int dockSide = getDockSide();
871 if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
872 return false;
873 }
874
875 if (dockSide == DOCKED_TOP) {
876 mService.getStableInsetsLocked(mTmpRect);
877 int topInset = mTmpRect.top;
878 mTmpAdjustedBounds.set(mBounds);
879 mTmpAdjustedBounds.bottom =
880 (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
881 } else if (dockSide == DOCKED_LEFT) {
882 mTmpAdjustedBounds.set(mBounds);
883 mTmpAdjustedBounds.right =
884 (int) (minimizeAmount * mDockedStackMinimizeThickness
885 + (1 - minimizeAmount) * mBounds.right);
886 } else if (dockSide == DOCKED_RIGHT) {
887 mTmpAdjustedBounds.set(mBounds);
888 mTmpAdjustedBounds.left =
889 (int) (minimizeAmount * (mBounds.right - mDockedStackMinimizeThickness)
890 + (1 - minimizeAmount) * mBounds.left);
891 }
892 return true;
893 }
894
895 /**
Jorim Jaggif97ed922016-02-18 18:57:07 -0800896 * @return the distance in pixels how much the stack gets minimized from it's original size
897 */
898 int getMinimizeDistance() {
899 final int dockSide = getDockSide();
900 if (dockSide == DOCKED_INVALID) {
901 return 0;
902 }
903
904 if (dockSide == DOCKED_TOP) {
905 mService.getStableInsetsLocked(mTmpRect);
906 int topInset = mTmpRect.top;
907 return mBounds.bottom - topInset;
908 } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
909 return mBounds.width() - mDockedStackMinimizeThickness;
910 } else {
911 return 0;
912 }
913 }
914
915 /**
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800916 * Updates the adjustment depending on it's current state.
917 */
918 void updateAdjustedBounds() {
919 boolean adjust = false;
920 if (mMinimizeAmount != 0f) {
921 adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
922 } else if (mAdjustedForIme) {
923 adjust = adjustForIME(mImeWin);
924 }
925 if (!adjust) {
926 mTmpAdjustedBounds.setEmpty();
927 mLastContentBounds.setEmpty();
928 }
929 setAdjustedBounds(mTmpAdjustedBounds, isAdjustedForMinimizedDockedStack());
930 }
931
932 boolean isAdjustedForMinimizedDockedStack() {
933 return mMinimizeAmount != 0f;
934 }
935
Craig Mautner00af9fe2013-03-25 09:13:41 -0700936 public void dump(String prefix, PrintWriter pw) {
Wale Ogunwaleb429e682016-01-06 12:36:34 -0800937 pw.println(prefix + "mStackId=" + mStackId);
938 pw.println(prefix + "mDeferDetach=" + mDeferDetach);
939 pw.println(prefix + "mFullscreen=" + mFullscreen);
940 pw.println(prefix + "mBounds=" + mBounds.toShortString());
941 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) {
942 mTasks.get(taskNdx).dump(prefix + " ", pw);
Craig Mautner00af9fe2013-03-25 09:13:41 -0700943 }
Craig Mautner05d29032013-05-03 13:40:13 -0700944 if (mAnimationBackgroundSurface.isDimming()) {
Wale Ogunwaleb429e682016-01-06 12:36:34 -0800945 pw.println(prefix + "mWindowAnimationBackgroundSurface:");
Craig Mautner05d29032013-05-03 13:40:13 -0700946 mAnimationBackgroundSurface.printTo(prefix + " ", pw);
947 }
Craig Mautnerdc548482014-02-05 13:35:24 -0800948 if (!mExitingAppTokens.isEmpty()) {
949 pw.println();
950 pw.println(" Exiting application tokens:");
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700951 for (int i = mExitingAppTokens.size() - 1; i >= 0; i--) {
Craig Mautnerdc548482014-02-05 13:35:24 -0800952 WindowToken token = mExitingAppTokens.get(i);
953 pw.print(" Exiting App #"); pw.print(i);
954 pw.print(' '); pw.print(token);
955 pw.println(':');
956 token.dump(pw, " ");
957 }
958 }
Craig Mautner00af9fe2013-03-25 09:13:41 -0700959 }
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700960
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700961 /** Fullscreen status of the stack without adjusting for other factors in the system like
962 * visibility of docked stack.
963 * Most callers should be using {@link #isFullscreen} as it take into consideration other
964 * system factors. */
965 boolean getRawFullscreen() {
966 return mFullscreen;
967 }
968
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700969 @Override
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700970 public boolean isFullscreen() {
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700971 if (useCurrentBounds()) {
972 return mFullscreen;
973 }
974 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
975 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
976 // system.
977 return true;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700978 }
979
980 @Override
981 public DisplayInfo getDisplayInfo() {
982 return mDisplayContent.getDisplayInfo();
983 }
984
985 @Override
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700986 public String toString() {
987 return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
988 }
Filip Gruszczynski923f8262015-09-17 17:41:13 -0700989
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700990 @Override
991 public String toShortString() {
992 return "Stack=" + mStackId;
993 }
994
Filip Gruszczynski923f8262015-09-17 17:41:13 -0700995 /**
Chong Zhangc806d902015-11-30 09:44:27 -0800996 * For docked workspace (or workspace that's side-by-side to the docked), provides
997 * information which side of the screen was the dock anchored.
Filip Gruszczynski923f8262015-09-17 17:41:13 -0700998 */
Filip Gruszczynski923f8262015-09-17 17:41:13 -0700999 int getDockSide() {
Jorim Jaggi737af722015-12-31 10:42:27 +01001000 return getDockSide(mBounds);
1001 }
1002
1003 int getDockSide(Rect bounds) {
Chong Zhangc806d902015-11-30 09:44:27 -08001004 if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) {
Filip Gruszczynski923f8262015-09-17 17:41:13 -07001005 return DOCKED_INVALID;
1006 }
1007 if (mDisplayContent == null) {
1008 return DOCKED_INVALID;
1009 }
1010 mDisplayContent.getLogicalDisplayRect(mTmpRect);
1011 final int orientation = mService.mCurConfiguration.orientation;
1012 if (orientation == Configuration.ORIENTATION_PORTRAIT) {
1013 // Portrait mode, docked either at the top or the bottom.
Jorim Jaggi067e8172016-02-03 18:24:12 -08001014 if (bounds.top - mTmpRect.top <= mTmpRect.bottom - bounds.bottom) {
Filip Gruszczynski923f8262015-09-17 17:41:13 -07001015 return DOCKED_TOP;
1016 } else {
1017 return DOCKED_BOTTOM;
1018 }
1019 } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
1020 // Landscape mode, docked either on the left or on the right.
Jorim Jaggi067e8172016-02-03 18:24:12 -08001021 if (bounds.left - mTmpRect.left <= mTmpRect.right - bounds.right) {
Filip Gruszczynski923f8262015-09-17 17:41:13 -07001022 return DOCKED_LEFT;
1023 } else {
1024 return DOCKED_RIGHT;
1025 }
1026 } else {
1027 return DOCKED_INVALID;
1028 }
1029 }
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -07001030
1031 boolean isVisibleLocked() {
Jorim Jaggi7998e482016-02-12 18:47:06 -08001032 final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded()
1033 && !mService.mAnimator.mKeyguardGoingAway;
Chong Zhang75b37202015-12-04 14:16:36 -08001034 if (keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
Wale Ogunwaleccb6ce22016-01-14 15:36:35 -08001035 // The keyguard is showing and the stack shouldn't show on top of the keyguard.
Wale Ogunwale961f4852016-02-01 20:25:54 -08001036 return false;
Chong Zhang75b37202015-12-04 14:16:36 -08001037 }
Wale Ogunwaleccb6ce22016-01-14 15:36:35 -08001038
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -07001039 for (int i = mTasks.size() - 1; i >= 0; i--) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -08001040 final Task task = mTasks.get(i);
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -07001041 for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
1042 if (!task.mAppTokens.get(j).hidden) {
1043 return true;
1044 }
1045 }
1046 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -08001047
1048 return false;
1049 }
1050
1051 /**
1052 * @return true if a the stack is visible for the current in user, ignoring any other visibility
1053 * aspects, and false otherwise
1054 */
1055 boolean isVisibleForUserLocked() {
1056 for (int i = mTasks.size() - 1; i >= 0; i--) {
1057 final Task task = mTasks.get(i);
1058 if (task.isVisibleForUser()) {
1059 return true;
1060 }
1061 }
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -07001062 return false;
1063 }
Filip Gruszczynski84fa3352016-01-25 16:28:49 -08001064
Wale Ogunwalece144522016-02-05 22:51:01 -08001065 boolean isDragResizing() {
1066 return mDragResizing;
1067 }
1068
Jorim Jaggic662d8e2016-02-05 16:54:54 -08001069 private void setDragResizingLocked(boolean resizing) {
1070 if (mDragResizing == resizing) {
1071 return;
1072 }
1073 mDragResizing = resizing;
1074 for (int i = mTasks.size() - 1; i >= 0 ; i--) {
1075 mTasks.get(i).resetDragResizingChangeReported();
1076 }
1077 }
1078
Filip Gruszczynski84fa3352016-01-25 16:28:49 -08001079 @Override // AnimatesBounds
1080 public boolean setSize(Rect bounds) {
1081 synchronized (mService.mWindowMap) {
1082 if (mDisplayContent == null) {
1083 return false;
1084 }
1085 }
1086 try {
1087 mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false);
1088 } catch (RemoteException e) {
1089 }
1090 return true;
1091 }
1092
1093 @Override // AnimatesBounds
Wale Ogunwalece144522016-02-05 22:51:01 -08001094 public void onAnimationStart() {
Filip Gruszczynski84fa3352016-01-25 16:28:49 -08001095 synchronized (mService.mWindowMap) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -08001096 setDragResizingLocked(true);
Wale Ogunwalece144522016-02-05 22:51:01 -08001097 }
1098 }
1099
1100 @Override // AnimatesBounds
1101 public void onAnimationEnd() {
1102 synchronized (mService.mWindowMap) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -08001103 setDragResizingLocked(false);
Wale Ogunwalece144522016-02-05 22:51:01 -08001104 mService.requestTraversal();
Filip Gruszczynski84fa3352016-01-25 16:28:49 -08001105 }
Wale Ogunwale480dca02016-02-06 13:58:29 -08001106 if (mStackId == PINNED_STACK_ID) {
1107 try {
1108 mService.mActivityManager.notifyPinnedStackAnimationEnded();
1109 } catch (RemoteException e) {
1110 // I don't believe you...
1111 }
1112 }
Filip Gruszczynski84fa3352016-01-25 16:28:49 -08001113 }
Filip Gruszczynskic17d8b72016-02-03 16:52:59 -08001114
1115 @Override
1116 public void moveToFullscreen() {
1117 try {
1118 mService.mActivityManager.moveTasksToFullscreenStack(mStackId, true);
1119 } catch (RemoteException e) {
1120 e.printStackTrace();
1121 }
1122 }
1123
1124 @Override
1125 public void getFullScreenBounds(Rect bounds) {
1126 getDisplayContent().getContentRect(bounds);
1127 }
Wale Ogunwaleecbcadd2016-02-21 14:18:51 -08001128}