blob: 07a6514de5f1a93a4607a6ae5bf7d65b832f69fa [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) {
Jorim Jaggi5060bd82016-02-19 17:12:19 -0800355 repositionDockedStackAfterRotation(mTmpRect2);
Jorim Jaggi737af722015-12-31 10:42:27 +0100356 snapDockedStackAfterRotation(mTmpRect2);
357 }
358
359 // Post message to inform activity manager of the bounds change simulating
360 // a one-way call. We do this to prevent a deadlock between window manager
361 // lock and activity manager lock been held.
Wale Ogunwaleecbcadd2016-02-21 14:18:51 -0800362 mService.mH.obtainMessage(
363 RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2).sendToTarget();
Jorim Jaggi737af722015-12-31 10:42:27 +0100364 }
365
366 /**
Jorim Jaggi5060bd82016-02-19 17:12:19 -0800367 * Some dock sides are not allowed by the policy. This method queries the policy and moves
368 * the docked stack around if needed.
369 *
370 * @param inOutBounds the bounds of the docked stack to adjust
371 */
372 private void repositionDockedStackAfterRotation(Rect inOutBounds) {
373 int dockSide = getDockSide(inOutBounds);
374 if (mService.mPolicy.isDockSideAllowed(dockSide)) {
375 return;
376 }
377 mDisplayContent.getLogicalDisplayRect(mTmpRect);
378 dockSide = DockedDividerUtils.invertDockSide(dockSide);
379 switch (dockSide) {
380 case DOCKED_LEFT:
381 int movement = inOutBounds.left;
382 inOutBounds.left -= movement;
383 inOutBounds.right -= movement;
384 break;
385 case DOCKED_RIGHT:
386 movement = mTmpRect.right - inOutBounds.right;
387 inOutBounds.left += movement;
388 inOutBounds.right += movement;
389 break;
390 case DOCKED_TOP:
391 movement = inOutBounds.top;
392 inOutBounds.top -= movement;
393 inOutBounds.bottom -= movement;
394 break;
395 case DOCKED_BOTTOM:
396 movement = mTmpRect.bottom - inOutBounds.bottom;
397 inOutBounds.top += movement;
398 inOutBounds.bottom += movement;
399 break;
400 }
401 }
402
403 /**
Jorim Jaggi737af722015-12-31 10:42:27 +0100404 * Snaps the bounds after rotation to the closest snap target for the docked stack.
405 */
406 private void snapDockedStackAfterRotation(Rect outBounds) {
407
408 // Calculate the current position.
409 final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
410 final int dividerSize = mService.getDefaultDisplayContentLocked()
411 .getDockedDividerController().getContentWidth();
412 final int dockSide = getDockSide(outBounds);
413 final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
414 dockSide, dividerSize);
415 final int displayWidth = mDisplayContent.getDisplayInfo().logicalWidth;
416 final int displayHeight = mDisplayContent.getDisplayInfo().logicalHeight;
417
418 // Snap the position to a target.
419 final int rotation = displayInfo.rotation;
420 final int orientation = mService.mCurConfiguration.orientation;
421 mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
422 final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
Jorim Jaggidf012d52016-01-15 22:40:13 -0800423 mService.mContext.getResources(), displayWidth, displayHeight,
Jorim Jaggi737af722015-12-31 10:42:27 +0100424 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds);
425 final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
426
427 // Recalculate the bounds based on the position of the target.
428 DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
429 outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight,
430 dividerSize);
431 }
432
Craig Mautner1bf2b872014-02-05 15:37:40 -0800433 boolean isAnimating() {
434 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
435 final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
436 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
437 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
438 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700439 final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
Wale Ogunwalec48a3542016-02-19 15:18:45 -0800440 if (winAnimator.isAnimating() || winAnimator.mWin.mAnimatingExit) {
Craig Mautner1bf2b872014-02-05 15:37:40 -0800441 return true;
442 }
443 }
444 }
445 }
446 return false;
447 }
448
Wale Ogunwale3fcb4a82015-04-06 14:00:13 -0700449 void addTask(Task task, boolean toTop) {
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700450 addTask(task, toTop, task.showForAllUsers());
Wale Ogunwale3fcb4a82015-04-06 14:00:13 -0700451 }
452
Craig Mautner00af9fe2013-03-25 09:13:41 -0700453 /**
454 * Put a Task in this stack. Used for adding and moving.
455 * @param task The task to add.
456 * @param toTop Whether to add it to the top or bottom.
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700457 * @param showForAllUsers Whether to show the task regardless of the current user.
Craig Mautner00af9fe2013-03-25 09:13:41 -0700458 */
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700459 void addTask(Task task, boolean toTop, boolean showForAllUsers) {
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700460 positionTask(task, toTop ? mTasks.size() : 0, showForAllUsers);
461 }
462
463 void positionTask(Task task, int position, boolean showForAllUsers) {
464 final boolean canShowTask =
465 showForAllUsers || mService.isCurrentProfileLocked(task.mUserId);
466 mTasks.remove(task);
467 int stackSize = mTasks.size();
468 int minPosition = 0;
469 int maxPosition = stackSize;
470
471 if (canShowTask) {
472 minPosition = computeMinPosition(minPosition, stackSize);
Craig Mautnerac6f8432013-07-17 13:24:59 -0700473 } else {
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700474 maxPosition = computeMaxPosition(maxPosition);
Craig Mautnerac6f8432013-07-17 13:24:59 -0700475 }
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700476 // Reset position based on minimum/maximum possible positions.
477 position = Math.min(Math.max(position, minPosition), maxPosition);
478
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800479 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM,
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700480 "positionTask: task=" + task + " position=" + position);
481 mTasks.add(position, task);
Craig Mautnerac6f8432013-07-17 13:24:59 -0700482
Chong Zhangf66db432016-01-13 10:39:51 -0800483 // If we are moving the task across stacks, the scroll is no longer valid.
484 if (task.mStack != this) {
485 task.resetScrollLocked();
486 }
Craig Mautner967212c2013-04-13 21:10:58 -0700487 task.mStack = this;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700488 task.updateDisplayInfo(mDisplayContent);
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700489 boolean toTop = position == mTasks.size() - 1;
raysb.kim00a27252014-11-11 08:38:21 +0900490 if (toTop) {
491 mDisplayContent.moveStack(this, true);
492 }
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700493 EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, position);
494 }
495
496 /** Calculate the minimum possible position for a task that can be shown to the user.
497 * The minimum position will be above all other tasks that can't be shown.
498 * @param minPosition The minimum position the caller is suggesting.
499 * We will start adjusting up from here.
500 * @param size The size of the current task list.
501 */
502 private int computeMinPosition(int minPosition, int size) {
503 while (minPosition < size) {
504 final Task tmpTask = mTasks.get(minPosition);
505 final boolean canShowTmpTask =
506 tmpTask.showForAllUsers()
507 || mService.isCurrentProfileLocked(tmpTask.mUserId);
508 if (canShowTmpTask) {
509 break;
510 }
511 minPosition++;
512 }
513 return minPosition;
514 }
515
516 /** Calculate the maximum possible position for a task that can't be shown to the user.
517 * The maximum position will be below all other tasks that can be shown.
518 * @param maxPosition The maximum position the caller is suggesting.
519 * We will start adjusting down from here.
520 */
521 private int computeMaxPosition(int maxPosition) {
522 while (maxPosition > 0) {
523 final Task tmpTask = mTasks.get(maxPosition - 1);
524 final boolean canShowTmpTask =
525 tmpTask.showForAllUsers()
526 || mService.isCurrentProfileLocked(tmpTask.mUserId);
527 if (!canShowTmpTask) {
528 break;
529 }
530 maxPosition--;
531 }
532 return maxPosition;
Craig Mautnerc00204b2013-03-05 15:02:14 -0800533 }
534
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800535 void moveTaskToTop(Task task) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800536 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToTop: task=" + task + " Callers="
Craig Mautnerf0ac5c82013-06-24 11:21:57 -0700537 + Debug.getCallers(6));
Craig Mautnerd9a22882013-03-16 15:00:36 -0700538 mTasks.remove(task);
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800539 addTask(task, true);
Craig Mautnerd9a22882013-03-16 15:00:36 -0700540 }
541
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800542 void moveTaskToBottom(Task task) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800543 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToBottom: task=" + task);
Craig Mautnerd9a22882013-03-16 15:00:36 -0700544 mTasks.remove(task);
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800545 addTask(task, false);
Craig Mautnerd9a22882013-03-16 15:00:36 -0700546 }
547
Craig Mautner00af9fe2013-03-25 09:13:41 -0700548 /**
Craig Mautner04a0ea62014-01-13 12:51:26 -0800549 * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the
550 * back.
Craig Mautner00af9fe2013-03-25 09:13:41 -0700551 * @param task The Task to delete.
Craig Mautner00af9fe2013-03-25 09:13:41 -0700552 */
Craig Mautnerde4ef022013-04-07 19:01:33 -0700553 void removeTask(Task task) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800554 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeTask: task=" + task);
Craig Mautnerde4ef022013-04-07 19:01:33 -0700555 mTasks.remove(task);
Craig Mautnerdf88d732014-01-27 09:21:32 -0800556 if (mDisplayContent != null) {
Craig Mautnerdf88d732014-01-27 09:21:32 -0800557 if (mTasks.isEmpty()) {
558 mDisplayContent.moveStack(this, false);
559 }
560 mDisplayContent.layoutNeeded = true;
Craig Mautner04a0ea62014-01-13 12:51:26 -0800561 }
Craig Mautnere3119b72015-01-20 15:02:36 -0800562 for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) {
563 final AppWindowToken wtoken = mExitingAppTokens.get(appNdx);
Craig Mautner83162a92015-01-26 14:43:30 -0800564 if (wtoken.mTask == task) {
Craig Mautnere3119b72015-01-20 15:02:36 -0800565 wtoken.mIsExiting = false;
566 mExitingAppTokens.remove(appNdx);
567 }
568 }
Craig Mautnerc00204b2013-03-05 15:02:14 -0800569 }
570
Craig Mautnerdf88d732014-01-27 09:21:32 -0800571 void attachDisplayContent(DisplayContent displayContent) {
572 if (mDisplayContent != null) {
573 throw new IllegalStateException("attachDisplayContent: Already attached");
Craig Mautner4a1cb222013-12-04 16:14:06 -0800574 }
Craig Mautnerdf88d732014-01-27 09:21:32 -0800575
576 mDisplayContent = displayContent;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700577 mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId());
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700578
579 Rect bounds = null;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700580 final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
Wale Ogunwale3797c222015-10-27 14:21:58 -0700581 if (mStackId == DOCKED_STACK_ID
582 || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId))) {
583 // The existence of a docked stack affects the size of other static stack created since
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700584 // the docked stack occupies a dedicated region on screen.
585 bounds = new Rect();
586 displayContent.getLogicalDisplayRect(mTmpRect);
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700587 mTmpRect2.setEmpty();
588 if (dockedStack != null) {
589 dockedStack.getRawBounds(mTmpRect2);
590 }
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800591 final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700592 == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
593 getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2,
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100594 mDisplayContent.mDividerControllerLocked.getContentWidth(),
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700595 dockedOnTopOrLeft);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700596 }
597
598 updateDisplayInfo(bounds);
599
600 if (mStackId == DOCKED_STACK_ID) {
601 // Attaching a docked stack to the display affects the size of all other static
602 // stacks since the docked stack occupies a dedicated region on screen.
603 // Resize existing static stacks so they are pushed to the side of the docked stack.
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700604 resizeNonDockedStacks(!FULLSCREEN, mBounds);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700605 }
606 }
607
Wale Ogunwale961f4852016-02-01 20:25:54 -0800608 void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) {
Wale Ogunwalea9f9b372016-02-04 18:04:39 -0800609 if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId))
610 || mDisplayContent == null) {
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700611 outBounds.set(mBounds);
612 return;
613 }
614
Filip Gruszczynski54977fe2015-10-19 17:26:45 -0700615 final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700616 if (dockedStack == null) {
617 // Not sure why you are calling this method when there is no docked stack...
618 throw new IllegalStateException(
619 "Calling getStackDockedModeBoundsLocked() when there is no docked stack.");
620 }
Wale Ogunwale961f4852016-02-01 20:25:54 -0800621 if (!ignoreVisibility && !dockedStack.isVisibleLocked()) {
Filip Gruszczynski54977fe2015-10-19 17:26:45 -0700622 // The docked stack is being dismissed, but we caught before it finished being
623 // dismissed. In that case we want to treat it as if it is not occupying any space and
624 // let others occupy the whole display.
Wale Ogunwaleccb6ce22016-01-14 15:36:35 -0800625 mDisplayContent.getLogicalDisplayRect(outBounds);
Filip Gruszczynski54977fe2015-10-19 17:26:45 -0700626 return;
627 }
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700628
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700629 final int dockedSide = dockedStack.getDockSide();
630 if (dockedSide == DOCKED_INVALID) {
631 // Not sure how you got here...Only thing we can do is return current bounds.
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800632 Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack);
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700633 outBounds.set(mBounds);
634 return;
635 }
636
637 mDisplayContent.getLogicalDisplayRect(mTmpRect);
638 dockedStack.getRawBounds(mTmpRect2);
Wale Ogunwalea9f9b372016-02-04 18:04:39 -0800639 final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700640 getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2,
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100641 mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700642
643 }
644
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700645 /**
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700646 * Outputs the bounds a stack should be given the presence of a docked stack on the display.
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700647 * @param displayRect The bounds of the display the docked stack is on.
648 * @param outBounds Output bounds that should be used for the stack.
649 * @param stackId Id of stack we are calculating the bounds for.
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700650 * @param dockedBounds Bounds of the docked stack.
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700651 * @param dockDividerWidth We need to know the width of the divider make to the output bounds
652 * close to the side of the dock.
653 * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen.
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700654 */
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800655 private void getStackDockedModeBounds(
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700656 Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth,
657 boolean dockOnTopOrLeft) {
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700658 final boolean dockedStack = stackId == DOCKED_STACK_ID;
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700659 final boolean splitHorizontally = displayRect.width() > displayRect.height();
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700660
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700661 outBounds.set(displayRect);
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700662 if (dockedStack) {
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800663 if (mService.mDockedStackCreateBounds != null) {
664 outBounds.set(mService.mDockedStackCreateBounds);
665 return;
666 }
Jorim Jaggid434dcb2016-01-06 17:18:44 +0100667
668 // The initial bounds of the docked stack when it is created about half the screen space
669 // and its bounds can be adjusted after that. The bounds of all other stacks are
670 // adjusted to occupy whatever screen space the docked stack isn't occupying.
671 final DisplayInfo di = mDisplayContent.getDisplayInfo();
672 mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
673 mTmpRect2);
674 final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
Jorim Jaggid434dcb2016-01-06 17:18:44 +0100675 di.logicalWidth,
676 di.logicalHeight,
677 dockDividerWidth,
678 mService.mCurConfiguration.orientation == ORIENTATION_PORTRAIT,
679 mTmpRect2).getMiddleTarget().position;
680
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700681 if (dockOnTopOrLeft) {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700682 if (splitHorizontally) {
Jorim Jaggid434dcb2016-01-06 17:18:44 +0100683 outBounds.right = position;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700684 } else {
Jorim Jaggid434dcb2016-01-06 17:18:44 +0100685 outBounds.bottom = position;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700686 }
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700687 } else {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700688 if (splitHorizontally) {
Jorim Jaggid434dcb2016-01-06 17:18:44 +0100689 outBounds.left = position - dockDividerWidth;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700690 } else {
Jorim Jaggid434dcb2016-01-06 17:18:44 +0100691 outBounds.top = position - dockDividerWidth;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700692 }
693 }
694 return;
695 }
696
697 // Other stacks occupy whatever space is left by the docked stack.
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700698 if (!dockOnTopOrLeft) {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700699 if (splitHorizontally) {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700700 outBounds.right = dockedBounds.left - dockDividerWidth;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700701 } else {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700702 outBounds.bottom = dockedBounds.top - dockDividerWidth;
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700703 }
704 } else {
705 if (splitHorizontally) {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700706 outBounds.left = dockedBounds.right + dockDividerWidth;
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700707 } else {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700708 outBounds.top = dockedBounds.bottom + dockDividerWidth;
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700709 }
710 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800711 DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700712 }
713
714 /** Resizes all non-docked stacks in the system to either fullscreen or the appropriate size
715 * based on the presence of a docked stack.
716 * @param fullscreen If true the stacks will be resized to fullscreen, else they will be
717 * resized to the appropriate size based on the presence of a docked stack.
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700718 * @param dockedBounds Bounds of the docked stack.
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700719 */
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700720 private void resizeNonDockedStacks(boolean fullscreen, Rect dockedBounds) {
721 // Not using mTmpRect because we are posting the object in a message.
722 final Rect bounds = new Rect();
723 mDisplayContent.getLogicalDisplayRect(bounds);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700724 if (!fullscreen) {
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800725 final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700726 == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
727 getStackDockedModeBounds(bounds, bounds, FULLSCREEN_WORKSPACE_STACK_ID, dockedBounds,
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100728 mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700729 }
730
731 final int count = mService.mStackIdToStack.size();
732 for (int i = 0; i < count; i++) {
733 final TaskStack otherStack = mService.mStackIdToStack.valueAt(i);
734 final int otherStackId = otherStack.mStackId;
Wale Ogunwale3856bf72015-11-20 09:36:46 -0800735 if (StackId.isResizeableByDockedStack(otherStackId)
736 && !otherStack.mBounds.equals(bounds)) {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700737 mService.mH.sendMessage(
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700738 mService.mH.obtainMessage(RESIZE_STACK, otherStackId,
Wale Ogunwale3856bf72015-11-20 09:36:46 -0800739 1 /*allowResizeInDockedMode*/, fullscreen ? null : bounds));
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700740 }
741 }
Craig Mautnerdf88d732014-01-27 09:21:32 -0800742 }
743
Wale Ogunwalea9f9b372016-02-04 18:04:39 -0800744 void resetDockedStackToMiddle() {
745 if (mStackId != DOCKED_STACK_ID) {
746 throw new IllegalStateException("Not a docked stack=" + this);
747 }
748
749 mService.mDockedStackCreateBounds = null;
750
751 final Rect bounds = new Rect();
752 getStackDockedModeBoundsLocked(bounds, true /*ignoreVisibility*/);
753 mService.mH.obtainMessage(RESIZE_STACK, DOCKED_STACK_ID,
754 1 /*allowResizeInDockedMode*/, bounds).sendToTarget();
755 }
756
Craig Mautnerdc548482014-02-05 13:35:24 -0800757 void detachDisplay() {
Craig Mautnerdf88d732014-01-27 09:21:32 -0800758 EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700759
760 boolean doAnotherLayoutPass = false;
Craig Mautnerdc548482014-02-05 13:35:24 -0800761 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700762 final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens;
763 for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
764 final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
765 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
Filip Gruszczynskid66af6a2015-08-31 08:57:24 -0700766 // We are in the middle of changing the state of displays/stacks/tasks. We need
767 // to finish that, before we let layout interfere with it.
Filip Gruszczynski49b80af2015-09-24 09:04:26 -0700768 mService.removeWindowLocked(appWindows.get(winNdx));
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700769 doAnotherLayoutPass = true;
770 }
771 }
Craig Mautnerdc548482014-02-05 13:35:24 -0800772 }
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700773 if (doAnotherLayoutPass) {
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700774 mService.mWindowPlacerLocked.requestTraversal();
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700775 }
776
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700777 if (mStackId == DOCKED_STACK_ID) {
778 // Docked stack was detached from the display, so we no longer need to restrict the
779 // region of the screen other static stacks occupy. Go ahead and make them fullscreen.
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700780 resizeNonDockedStacks(FULLSCREEN, null);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700781 }
782
Craig Mautner00a66752015-03-23 14:00:47 -0700783 close();
Craig Mautner00af9fe2013-03-25 09:13:41 -0700784 }
785
Craig Mautner05d29032013-05-03 13:40:13 -0700786 void resetAnimationBackgroundAnimator() {
787 mAnimationBackgroundAnimator = null;
788 mAnimationBackgroundSurface.hide();
789 }
790
Craig Mautner05d29032013-05-03 13:40:13 -0700791 void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
792 int animLayer = winAnimator.mAnimLayer;
793 if (mAnimationBackgroundAnimator == null
794 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) {
795 mAnimationBackgroundAnimator = winAnimator;
796 animLayer = mService.adjustAnimationBackground(winAnimator);
797 mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM,
798 ((color >> 24) & 0xff) / 255f, 0);
799 }
800 }
801
Wale Ogunwale498e8c92015-02-13 09:42:46 -0800802 void switchUser() {
Craig Mautnerac6f8432013-07-17 13:24:59 -0700803 int top = mTasks.size();
804 for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
805 Task task = mTasks.get(taskNdx);
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700806 if (mService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
Craig Mautnerac6f8432013-07-17 13:24:59 -0700807 mTasks.remove(taskNdx);
808 mTasks.add(task);
809 --top;
810 }
811 }
812 }
813
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800814 void close() {
Craig Mautner00a66752015-03-23 14:00:47 -0700815 if (mAnimationBackgroundSurface != null) {
816 mAnimationBackgroundSurface.destroySurface();
817 mAnimationBackgroundSurface = null;
818 }
Filip Gruszczynski26ed2652015-08-10 11:02:53 -0700819 mDisplayContent = null;
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800820 }
821
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800822 /**
823 * Adjusts the stack bounds if the IME is visible.
824 *
825 * @param imeWin The IME window.
826 */
827 void setAdjustedForIme(WindowState imeWin) {
828 mAdjustedForIme = true;
829 mImeWin = imeWin;
830 updateAdjustedBounds();
831 }
832
833 /**
834 * Resets the adjustment after it got adjusted for the IME.
835 */
836 void resetAdjustedForIme() {
837 mAdjustedForIme = false;
838 mImeWin = null;
839 updateAdjustedBounds();
840 }
841
842 /**
843 * Sets the amount how much we currently minimize our stack.
844 *
845 * @param minimizeAmount The amount, between 0 and 1.
846 * @return Whether the amount has changed and a layout is needed.
847 */
848 boolean setAdjustedForMinimizedDock(float minimizeAmount) {
849 if (minimizeAmount != mMinimizeAmount) {
850 mMinimizeAmount = minimizeAmount;
851 updateAdjustedBounds();
852 return isVisibleForUserLocked();
853 } else {
854 return false;
855 }
856 }
857
858 private boolean adjustForIME(final WindowState imeWin) {
859 final int dockedSide = getDockSide();
860 final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
861 final Rect adjustedBounds = mTmpAdjustedBounds;
862 if (imeWin == null || !dockedTopOrBottom) {
863 return false;
864 }
865
866 final Rect displayContentRect = mTmpRect;
867 final Rect contentBounds = mTmpRect2;
868
869 // Calculate the content bounds excluding the area occupied by IME
870 getDisplayContent().getContentRect(displayContentRect);
871 contentBounds.set(displayContentRect);
872 int imeTop = Math.max(imeWin.getDisplayFrameLw().top, contentBounds.top);
873 imeTop += imeWin.getGivenContentInsetsLw().top;
874 if (contentBounds.bottom > imeTop) {
875 contentBounds.bottom = imeTop;
876 }
877
878 // If content bounds not changing, nothing to do.
879 if (mLastContentBounds.equals(contentBounds)) {
880 return true;
881 }
882
883 // Content bounds changed, need to apply adjustments depending on dock sides.
884 mLastContentBounds.set(contentBounds);
885 adjustedBounds.set(mBounds);
886 final int yOffset = displayContentRect.bottom - contentBounds.bottom;
887
888 if (dockedSide == DOCKED_TOP) {
889 // If this stack is docked on top, we make it smaller so the bottom stack is not
890 // occluded by IME. We shift its bottom up by the height of the IME (capped by
891 // the display content rect). Note that we don't change the task bounds.
892 adjustedBounds.bottom = Math.max(
893 adjustedBounds.bottom - yOffset, displayContentRect.top);
894 } else {
895 // If this stack is docked on bottom, we shift it up so that it's not occluded by
896 // IME. We try to move it up by the height of the IME window (although the best
897 // we could do is to make the top stack fully collapsed).
898 final int dividerWidth = getDisplayContent().mDividerControllerLocked
899 .getContentWidth();
900 adjustedBounds.top = Math.max(
901 adjustedBounds.top - yOffset, displayContentRect.top + dividerWidth);
902 adjustedBounds.bottom = adjustedBounds.top + mBounds.height();
903 }
904 return true;
905 }
906
907 private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
908 final int dockSide = getDockSide();
909 if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
910 return false;
911 }
912
913 if (dockSide == DOCKED_TOP) {
914 mService.getStableInsetsLocked(mTmpRect);
915 int topInset = mTmpRect.top;
916 mTmpAdjustedBounds.set(mBounds);
917 mTmpAdjustedBounds.bottom =
918 (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
919 } else if (dockSide == DOCKED_LEFT) {
920 mTmpAdjustedBounds.set(mBounds);
921 mTmpAdjustedBounds.right =
922 (int) (minimizeAmount * mDockedStackMinimizeThickness
923 + (1 - minimizeAmount) * mBounds.right);
924 } else if (dockSide == DOCKED_RIGHT) {
925 mTmpAdjustedBounds.set(mBounds);
926 mTmpAdjustedBounds.left =
927 (int) (minimizeAmount * (mBounds.right - mDockedStackMinimizeThickness)
928 + (1 - minimizeAmount) * mBounds.left);
929 }
930 return true;
931 }
932
933 /**
Jorim Jaggif97ed922016-02-18 18:57:07 -0800934 * @return the distance in pixels how much the stack gets minimized from it's original size
935 */
936 int getMinimizeDistance() {
937 final int dockSide = getDockSide();
938 if (dockSide == DOCKED_INVALID) {
939 return 0;
940 }
941
942 if (dockSide == DOCKED_TOP) {
943 mService.getStableInsetsLocked(mTmpRect);
944 int topInset = mTmpRect.top;
945 return mBounds.bottom - topInset;
946 } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
947 return mBounds.width() - mDockedStackMinimizeThickness;
948 } else {
949 return 0;
950 }
951 }
952
953 /**
Jorim Jaggi42625d1b2016-02-11 20:11:07 -0800954 * Updates the adjustment depending on it's current state.
955 */
956 void updateAdjustedBounds() {
957 boolean adjust = false;
958 if (mMinimizeAmount != 0f) {
959 adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
960 } else if (mAdjustedForIme) {
961 adjust = adjustForIME(mImeWin);
962 }
963 if (!adjust) {
964 mTmpAdjustedBounds.setEmpty();
965 mLastContentBounds.setEmpty();
966 }
967 setAdjustedBounds(mTmpAdjustedBounds, isAdjustedForMinimizedDockedStack());
968 }
969
970 boolean isAdjustedForMinimizedDockedStack() {
971 return mMinimizeAmount != 0f;
972 }
973
Craig Mautner00af9fe2013-03-25 09:13:41 -0700974 public void dump(String prefix, PrintWriter pw) {
Wale Ogunwaleb429e682016-01-06 12:36:34 -0800975 pw.println(prefix + "mStackId=" + mStackId);
976 pw.println(prefix + "mDeferDetach=" + mDeferDetach);
977 pw.println(prefix + "mFullscreen=" + mFullscreen);
978 pw.println(prefix + "mBounds=" + mBounds.toShortString());
979 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) {
980 mTasks.get(taskNdx).dump(prefix + " ", pw);
Craig Mautner00af9fe2013-03-25 09:13:41 -0700981 }
Craig Mautner05d29032013-05-03 13:40:13 -0700982 if (mAnimationBackgroundSurface.isDimming()) {
Wale Ogunwaleb429e682016-01-06 12:36:34 -0800983 pw.println(prefix + "mWindowAnimationBackgroundSurface:");
Craig Mautner05d29032013-05-03 13:40:13 -0700984 mAnimationBackgroundSurface.printTo(prefix + " ", pw);
985 }
Craig Mautnerdc548482014-02-05 13:35:24 -0800986 if (!mExitingAppTokens.isEmpty()) {
987 pw.println();
988 pw.println(" Exiting application tokens:");
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700989 for (int i = mExitingAppTokens.size() - 1; i >= 0; i--) {
Craig Mautnerdc548482014-02-05 13:35:24 -0800990 WindowToken token = mExitingAppTokens.get(i);
991 pw.print(" Exiting App #"); pw.print(i);
992 pw.print(' '); pw.print(token);
993 pw.println(':');
994 token.dump(pw, " ");
995 }
996 }
Craig Mautner00af9fe2013-03-25 09:13:41 -0700997 }
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700998
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700999 /** Fullscreen status of the stack without adjusting for other factors in the system like
1000 * visibility of docked stack.
1001 * Most callers should be using {@link #isFullscreen} as it take into consideration other
1002 * system factors. */
1003 boolean getRawFullscreen() {
1004 return mFullscreen;
1005 }
1006
Craig Mautner4cd0c13f2013-04-16 15:55:52 -07001007 @Override
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07001008 public boolean isFullscreen() {
Wale Ogunwalef175e8a2015-09-29 11:07:06 -07001009 if (useCurrentBounds()) {
1010 return mFullscreen;
1011 }
1012 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
1013 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
1014 // system.
1015 return true;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -07001016 }
1017
1018 @Override
1019 public DisplayInfo getDisplayInfo() {
1020 return mDisplayContent.getDisplayInfo();
1021 }
1022
1023 @Override
Craig Mautner4cd0c13f2013-04-16 15:55:52 -07001024 public String toString() {
1025 return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
1026 }
Filip Gruszczynski923f8262015-09-17 17:41:13 -07001027
Filip Gruszczynski0689ae92015-10-01 12:30:31 -07001028 @Override
1029 public String toShortString() {
1030 return "Stack=" + mStackId;
1031 }
1032
Filip Gruszczynski923f8262015-09-17 17:41:13 -07001033 /**
Chong Zhangc806d902015-11-30 09:44:27 -08001034 * For docked workspace (or workspace that's side-by-side to the docked), provides
1035 * information which side of the screen was the dock anchored.
Filip Gruszczynski923f8262015-09-17 17:41:13 -07001036 */
Filip Gruszczynski923f8262015-09-17 17:41:13 -07001037 int getDockSide() {
Jorim Jaggi737af722015-12-31 10:42:27 +01001038 return getDockSide(mBounds);
1039 }
1040
1041 int getDockSide(Rect bounds) {
Chong Zhangc806d902015-11-30 09:44:27 -08001042 if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) {
Filip Gruszczynski923f8262015-09-17 17:41:13 -07001043 return DOCKED_INVALID;
1044 }
1045 if (mDisplayContent == null) {
1046 return DOCKED_INVALID;
1047 }
1048 mDisplayContent.getLogicalDisplayRect(mTmpRect);
1049 final int orientation = mService.mCurConfiguration.orientation;
1050 if (orientation == Configuration.ORIENTATION_PORTRAIT) {
1051 // Portrait mode, docked either at the top or the bottom.
Jorim Jaggi067e8172016-02-03 18:24:12 -08001052 if (bounds.top - mTmpRect.top <= mTmpRect.bottom - bounds.bottom) {
Filip Gruszczynski923f8262015-09-17 17:41:13 -07001053 return DOCKED_TOP;
1054 } else {
1055 return DOCKED_BOTTOM;
1056 }
1057 } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
1058 // Landscape mode, docked either on the left or on the right.
Jorim Jaggi067e8172016-02-03 18:24:12 -08001059 if (bounds.left - mTmpRect.left <= mTmpRect.right - bounds.right) {
Filip Gruszczynski923f8262015-09-17 17:41:13 -07001060 return DOCKED_LEFT;
1061 } else {
1062 return DOCKED_RIGHT;
1063 }
1064 } else {
1065 return DOCKED_INVALID;
1066 }
1067 }
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -07001068
1069 boolean isVisibleLocked() {
Jorim Jaggi7998e482016-02-12 18:47:06 -08001070 final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded()
1071 && !mService.mAnimator.mKeyguardGoingAway;
Chong Zhang75b37202015-12-04 14:16:36 -08001072 if (keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
Wale Ogunwaleccb6ce22016-01-14 15:36:35 -08001073 // The keyguard is showing and the stack shouldn't show on top of the keyguard.
Wale Ogunwale961f4852016-02-01 20:25:54 -08001074 return false;
Chong Zhang75b37202015-12-04 14:16:36 -08001075 }
Wale Ogunwaleccb6ce22016-01-14 15:36:35 -08001076
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -07001077 for (int i = mTasks.size() - 1; i >= 0; i--) {
Jorim Jaggi42625d1b2016-02-11 20:11:07 -08001078 final Task task = mTasks.get(i);
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -07001079 for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
1080 if (!task.mAppTokens.get(j).hidden) {
1081 return true;
1082 }
1083 }
1084 }
Jorim Jaggi42625d1b2016-02-11 20:11:07 -08001085
1086 return false;
1087 }
1088
1089 /**
1090 * @return true if a the stack is visible for the current in user, ignoring any other visibility
1091 * aspects, and false otherwise
1092 */
1093 boolean isVisibleForUserLocked() {
1094 for (int i = mTasks.size() - 1; i >= 0; i--) {
1095 final Task task = mTasks.get(i);
1096 if (task.isVisibleForUser()) {
1097 return true;
1098 }
1099 }
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -07001100 return false;
1101 }
Filip Gruszczynski84fa3352016-01-25 16:28:49 -08001102
Wale Ogunwalece144522016-02-05 22:51:01 -08001103 boolean isDragResizing() {
1104 return mDragResizing;
1105 }
1106
Jorim Jaggic662d8e2016-02-05 16:54:54 -08001107 private void setDragResizingLocked(boolean resizing) {
1108 if (mDragResizing == resizing) {
1109 return;
1110 }
1111 mDragResizing = resizing;
1112 for (int i = mTasks.size() - 1; i >= 0 ; i--) {
1113 mTasks.get(i).resetDragResizingChangeReported();
1114 }
1115 }
1116
Filip Gruszczynski84fa3352016-01-25 16:28:49 -08001117 @Override // AnimatesBounds
1118 public boolean setSize(Rect bounds) {
1119 synchronized (mService.mWindowMap) {
1120 if (mDisplayContent == null) {
1121 return false;
1122 }
1123 }
1124 try {
1125 mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false);
1126 } catch (RemoteException e) {
1127 }
1128 return true;
1129 }
1130
1131 @Override // AnimatesBounds
Wale Ogunwalece144522016-02-05 22:51:01 -08001132 public void onAnimationStart() {
Filip Gruszczynski84fa3352016-01-25 16:28:49 -08001133 synchronized (mService.mWindowMap) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -08001134 setDragResizingLocked(true);
Wale Ogunwalece144522016-02-05 22:51:01 -08001135 }
1136 }
1137
1138 @Override // AnimatesBounds
1139 public void onAnimationEnd() {
1140 synchronized (mService.mWindowMap) {
Jorim Jaggic662d8e2016-02-05 16:54:54 -08001141 setDragResizingLocked(false);
Wale Ogunwalece144522016-02-05 22:51:01 -08001142 mService.requestTraversal();
Filip Gruszczynski84fa3352016-01-25 16:28:49 -08001143 }
Wale Ogunwale480dca02016-02-06 13:58:29 -08001144 if (mStackId == PINNED_STACK_ID) {
1145 try {
1146 mService.mActivityManager.notifyPinnedStackAnimationEnded();
1147 } catch (RemoteException e) {
1148 // I don't believe you...
1149 }
1150 }
Filip Gruszczynski84fa3352016-01-25 16:28:49 -08001151 }
Filip Gruszczynskic17d8b72016-02-03 16:52:59 -08001152
1153 @Override
1154 public void moveToFullscreen() {
1155 try {
1156 mService.mActivityManager.moveTasksToFullscreenStack(mStackId, true);
1157 } catch (RemoteException e) {
1158 e.printStackTrace();
1159 }
1160 }
1161
1162 @Override
1163 public void getFullScreenBounds(Rect bounds) {
1164 getDisplayContent().getContentRect(bounds);
1165 }
Wale Ogunwaleecbcadd2016-02-21 14:18:51 -08001166}