blob: 369cc6524d56f095285b0706b423e3b76a8e7845 [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;
Jorim Jaggi737af722015-12-31 10:42:27 +010021import android.content.res.Resources;
Craig Mautner05d29032013-05-03 13:40:13 -070022import android.graphics.Rect;
Craig Mautnerf0ac5c82013-06-24 11:21:57 -070023import android.os.Debug;
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;
41import static android.view.WindowManager.DOCKED_BOTTOM;
42import static android.view.WindowManager.DOCKED_INVALID;
43import static android.view.WindowManager.DOCKED_LEFT;
44import static android.view.WindowManager.DOCKED_RIGHT;
45import static android.view.WindowManager.DOCKED_TOP;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080046import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010047import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -080048import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
Jorim Jaggi61f39a72015-10-29 16:54:18 +010049
Wale Ogunwalee4a0c572015-06-30 08:40:31 -070050public class TaskStack implements DimLayer.DimLayerUser {
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -070051
52 // If the stack should be resized to fullscreen.
53 private static final boolean FULLSCREEN = true;
54
Craig Mautner00af9fe2013-03-25 09:13:41 -070055 /** Unique identifier */
Craig Mautnerc00204b2013-03-05 15:02:14 -080056 final int mStackId;
Craig Mautner00af9fe2013-03-25 09:13:41 -070057
Craig Mautner05d29032013-05-03 13:40:13 -070058 /** The service */
59 private final WindowManagerService mService;
60
Craig Mautner00af9fe2013-03-25 09:13:41 -070061 /** The display this stack sits under. */
Craig Mautnerdf88d732014-01-27 09:21:32 -080062 private DisplayContent mDisplayContent;
Craig Mautner00af9fe2013-03-25 09:13:41 -070063
64 /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
65 * mTaskHistory in the ActivityStack with the same mStackId */
Wale Ogunwalee4a0c572015-06-30 08:40:31 -070066 private final ArrayList<Task> mTasks = new ArrayList<>();
Craig Mautner00af9fe2013-03-25 09:13:41 -070067
Craig Mautnerb660b9d2014-02-13 10:59:16 -080068 /** For comparison with DisplayContent bounds. */
69 private Rect mTmpRect = new Rect();
Wale Ogunwalee45899a2015-10-01 11:30:34 -070070 private Rect mTmpRect2 = new Rect();
Craig Mautnerb660b9d2014-02-13 10:59:16 -080071
72 /** Content limits relative to the DisplayContent this sits in. */
73 private Rect mBounds = new Rect();
74
75 /** Whether mBounds is fullscreen */
76 private boolean mFullscreen = true;
Craig Mautnerc00204b2013-03-05 15:02:14 -080077
Wale Ogunwale94744212015-09-21 19:01:47 -070078 // Device rotation as of the last time {@link #mBounds} was set.
79 int mRotation;
80
Craig Mautner05d29032013-05-03 13:40:13 -070081 /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
Craig Mautnerdf88d732014-01-27 09:21:32 -080082 DimLayer mAnimationBackgroundSurface;
Craig Mautner05d29032013-05-03 13:40:13 -070083
84 /** The particular window with an Animation with non-zero background color. */
85 WindowStateAnimator mAnimationBackgroundAnimator;
86
Craig Mautnerdc548482014-02-05 13:35:24 -080087 /** Application tokens that are exiting, but still on screen for animations. */
88 final AppTokenList mExitingAppTokens = new AppTokenList();
89
Craig Mautner95da1082014-02-24 17:54:35 -080090 /** Detach this stack from its display when animation completes. */
91 boolean mDeferDetach;
92
Craig Mautnerdf88d732014-01-27 09:21:32 -080093 TaskStack(WindowManagerService service, int stackId) {
Craig Mautner05d29032013-05-03 13:40:13 -070094 mService = service;
Craig Mautnerc00204b2013-03-05 15:02:14 -080095 mStackId = stackId;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -070096 EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
Craig Mautnerc00204b2013-03-05 15:02:14 -080097 }
98
99 DisplayContent getDisplayContent() {
100 return mDisplayContent;
101 }
102
Craig Mautnerd9a22882013-03-16 15:00:36 -0700103 ArrayList<Task> getTasks() {
104 return mTasks;
105 }
106
Craig Mautnerb660b9d2014-02-13 10:59:16 -0800107 void resizeWindows() {
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800108 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700109 mTasks.get(taskNdx).resizeWindows();
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800110 }
Craig Mautnerd5d5d0f2013-04-03 15:08:21 -0700111 }
112
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700113 /**
114 * Set the bounds of the stack and its containing tasks.
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700115 * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700116 * @param configs Configuration for individual tasks, keyed by task id.
117 * @param taskBounds Bounds for individual tasks, keyed by task id.
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700118 * @return True if the stack bounds was changed.
119 * */
Wale Ogunwalea6e902e2015-09-21 18:37:15 -0700120 boolean setBounds(
Jorim Jaggidc249c42015-12-15 14:57:31 -0800121 Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
122 SparseArray<Rect> taskTempInsetBounds) {
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700123 if (!setBounds(stackBounds)) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700124 return false;
125 }
126
127 // Update bounds of containing tasks.
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700128 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
129 final Task task = mTasks.get(taskNdx);
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700130 Configuration config = configs.get(task.mTaskId);
131 if (config != null) {
132 Rect bounds = taskBounds.get(task.mTaskId);
Chong Zhangb15758a2015-11-17 12:12:03 -0800133 if (!task.isResizeable() && task.isDockedInEffect()) {
134 // This is a non-resizeable task that's docked (or side-by-side to the docked
135 // stack). It might have been scrolled previously, and after the stack resizing,
136 // it might no longer fully cover the stack area.
137 // Save the old bounds and re-apply the scroll. This adjusts the bounds to
138 // fit the new stack bounds.
139 task.getBounds(mTmpRect);
140 task.setBounds(bounds, config);
141 task.scrollLocked(mTmpRect);
142 } else {
143 task.setBounds(bounds, config);
Jorim Jaggidc249c42015-12-15 14:57:31 -0800144 task.setTempInsetBounds(
145 taskTempInsetBounds != null ? taskTempInsetBounds.get(task.mTaskId)
146 : null);
Chong Zhangb15758a2015-11-17 12:12:03 -0800147 }
Filip Gruszczynskiebcc8752015-08-25 16:51:05 -0700148 } else {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800149 Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700150 }
151 }
152 return true;
153 }
154
Jorim Jaggi0429f352015-12-22 16:29:16 +0100155 void prepareFreezingTaskBounds() {
156 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
157 final Task task = mTasks.get(taskNdx);
158 task.prepareFreezingBounds();
159 }
160 }
161
Wale Ogunwaleb4ec0a32015-12-14 10:31:43 -0800162 boolean isFullscreenBounds(Rect bounds) {
163 if (mDisplayContent == null || bounds == null) {
164 return true;
165 }
166 mDisplayContent.getLogicalDisplayRect(mTmpRect);
167 return mTmpRect.equals(bounds);
168 }
169
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700170 private boolean setBounds(Rect bounds) {
Craig Mautnerb660b9d2014-02-13 10:59:16 -0800171 boolean oldFullscreen = mFullscreen;
Wale Ogunwale94744212015-09-21 19:01:47 -0700172 int rotation = Surface.ROTATION_0;
Craig Mautnerb660b9d2014-02-13 10:59:16 -0800173 if (mDisplayContent != null) {
174 mDisplayContent.getLogicalDisplayRect(mTmpRect);
Wale Ogunwale94744212015-09-21 19:01:47 -0700175 rotation = mDisplayContent.getDisplayInfo().rotation;
Wale Ogunwale9d3de4c2015-02-01 16:49:44 -0800176 if (bounds == null) {
177 bounds = mTmpRect;
178 mFullscreen = true;
179 } else {
Wale Ogunwale9d3de4c2015-02-01 16:49:44 -0800180 mFullscreen = mTmpRect.equals(bounds);
181 }
Craig Mautnerb660b9d2014-02-13 10:59:16 -0800182 }
183
Wale Ogunwale9d3de4c2015-02-01 16:49:44 -0800184 if (bounds == null) {
Wale Ogunwale4a02d812015-02-12 23:01:38 -0800185 // Can't set to fullscreen if we don't have a display to get bounds from...
Wale Ogunwale9d3de4c2015-02-01 16:49:44 -0800186 return false;
187 }
Wale Ogunwale94744212015-09-21 19:01:47 -0700188 if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800189 return false;
190 }
191
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700192 if (mDisplayContent != null) {
Chong Zhang112eb8c2015-11-02 11:17:00 -0800193 mDisplayContent.mDimLayerController.updateDimLayer(this);
Filip Gruszczynski57b6cce2015-10-06 09:50:51 -0700194 mAnimationBackgroundSurface.setBounds(bounds);
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700195 }
196
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800197 mBounds.set(bounds);
Wale Ogunwale94744212015-09-21 19:01:47 -0700198 mRotation = rotation;
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800199 return true;
200 }
201
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700202 /** Bounds of the stack without adjusting for other factors in the system like visibility
203 * of docked stack.
204 * Most callers should be using {@link #getBounds} as it take into consideration other system
205 * factors. */
206 void getRawBounds(Rect out) {
Craig Mautnerb660b9d2014-02-13 10:59:16 -0800207 out.set(mBounds);
208 }
209
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700210 /** Return true if the current bound can get outputted to the rest of the system as-is. */
211 private boolean useCurrentBounds() {
212 if (mFullscreen
Wale Ogunwale3797c222015-10-27 14:21:58 -0700213 || !StackId.isResizeableByDockedStack(mStackId)
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700214 || mDisplayContent == null
215 || mDisplayContent.getDockedStackLocked() != null) {
216 return true;
217 }
218 return false;
219 }
220
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700221 public void getBounds(Rect out) {
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700222 if (useCurrentBounds()) {
223 // No need to adjust the output bounds if fullscreen or the docked stack is visible
224 // since it is already what we want to represent to the rest of the system.
225 out.set(mBounds);
226 return;
227 }
228
229 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
230 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
231 // system.
232 mDisplayContent.getLogicalDisplayRect(out);
233 }
234
Chong Zhang4c9ba52a2015-11-10 18:36:33 -0800235 /** Bounds of the stack with other system factors taken into consideration. */
236 @Override
237 public void getDimBounds(Rect out) {
238 getBounds(out);
239 }
240
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700241 void updateDisplayInfo(Rect bounds) {
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700242 if (mDisplayContent != null) {
Wale Ogunwale1ed0d892015-09-28 13:27:44 -0700243 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
244 mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
245 }
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700246 if (bounds != null) {
247 setBounds(bounds);
Wale Ogunwale94744212015-09-21 19:01:47 -0700248 } else if (mFullscreen) {
249 setBounds(null);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700250 } else {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700251 mTmpRect2.set(mBounds);
Jorim Jaggi737af722015-12-31 10:42:27 +0100252 final int newRotation = mDisplayContent.getDisplayInfo().rotation;
253 if (mRotation == newRotation) {
254 setBounds(mTmpRect2);
Wale Ogunwale1ed0d892015-09-28 13:27:44 -0700255 }
Jorim Jaggi737af722015-12-31 10:42:27 +0100256
257 // If the rotation changes, we'll handle it in updateBoundsAfterRotation
Wale Ogunwale4a02d812015-02-12 23:01:38 -0800258 }
Wale Ogunwale9d3de4c2015-02-01 16:49:44 -0800259 }
260 }
261
Jorim Jaggi737af722015-12-31 10:42:27 +0100262 /**
263 * Updates the bounds after rotating the screen. We can't handle it in
264 * {@link #updateDisplayInfo} because at that point the configuration might not be fully updated
265 * yet.
266 */
267 void updateBoundsAfterRotation() {
268 final int newRotation = getDisplayInfo().rotation;
269 mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
270 if (mStackId == DOCKED_STACK_ID) {
271 snapDockedStackAfterRotation(mTmpRect2);
272 }
273
274 // Post message to inform activity manager of the bounds change simulating
275 // a one-way call. We do this to prevent a deadlock between window manager
276 // lock and activity manager lock been held.
277 mService.mH.sendMessage(mService.mH.obtainMessage(
278 RESIZE_STACK, mStackId, 0 /*allowResizeInDockedMode*/, mTmpRect2));
279 }
280
281 /**
282 * Snaps the bounds after rotation to the closest snap target for the docked stack.
283 */
284 private void snapDockedStackAfterRotation(Rect outBounds) {
285
286 // Calculate the current position.
287 final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
288 final int dividerSize = mService.getDefaultDisplayContentLocked()
289 .getDockedDividerController().getContentWidth();
290 final int dockSide = getDockSide(outBounds);
291 final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
292 dockSide, dividerSize);
293 final int displayWidth = mDisplayContent.getDisplayInfo().logicalWidth;
294 final int displayHeight = mDisplayContent.getDisplayInfo().logicalHeight;
295
296 // Snap the position to a target.
297 final int rotation = displayInfo.rotation;
298 final int orientation = mService.mCurConfiguration.orientation;
299 mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
300 final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
301 mService.mContext.getResources(),
302 0 /* minFlingVelocityPxPerSecond */, displayWidth, displayHeight,
303 dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds);
304 final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
305
306 // Recalculate the bounds based on the position of the target.
307 DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
308 outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight,
309 dividerSize);
310 }
311
Craig Mautner1bf2b872014-02-05 15:37:40 -0800312 boolean isAnimating() {
313 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
314 final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
315 for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
316 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
317 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700318 final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
Craig Mautner7c9ee192014-08-14 16:08:26 -0700319 if (winAnimator.isAnimating() || winAnimator.mWin.mExiting) {
Craig Mautner1bf2b872014-02-05 15:37:40 -0800320 return true;
321 }
322 }
323 }
324 }
325 return false;
326 }
327
Wale Ogunwale3fcb4a82015-04-06 14:00:13 -0700328 void addTask(Task task, boolean toTop) {
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700329 addTask(task, toTop, task.showForAllUsers());
Wale Ogunwale3fcb4a82015-04-06 14:00:13 -0700330 }
331
Craig Mautner00af9fe2013-03-25 09:13:41 -0700332 /**
333 * Put a Task in this stack. Used for adding and moving.
334 * @param task The task to add.
335 * @param toTop Whether to add it to the top or bottom.
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700336 * @param showForAllUsers Whether to show the task regardless of the current user.
Craig Mautner00af9fe2013-03-25 09:13:41 -0700337 */
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700338 void addTask(Task task, boolean toTop, boolean showForAllUsers) {
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700339 positionTask(task, toTop ? mTasks.size() : 0, showForAllUsers);
340 }
341
342 void positionTask(Task task, int position, boolean showForAllUsers) {
343 final boolean canShowTask =
344 showForAllUsers || mService.isCurrentProfileLocked(task.mUserId);
345 mTasks.remove(task);
346 int stackSize = mTasks.size();
347 int minPosition = 0;
348 int maxPosition = stackSize;
349
350 if (canShowTask) {
351 minPosition = computeMinPosition(minPosition, stackSize);
Craig Mautnerac6f8432013-07-17 13:24:59 -0700352 } else {
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700353 maxPosition = computeMaxPosition(maxPosition);
Craig Mautnerac6f8432013-07-17 13:24:59 -0700354 }
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700355 // Reset position based on minimum/maximum possible positions.
356 position = Math.min(Math.max(position, minPosition), maxPosition);
357
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800358 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM,
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700359 "positionTask: task=" + task + " position=" + position);
360 mTasks.add(position, task);
Craig Mautnerac6f8432013-07-17 13:24:59 -0700361
Craig Mautner967212c2013-04-13 21:10:58 -0700362 task.mStack = this;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700363 task.updateDisplayInfo(mDisplayContent);
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700364 boolean toTop = position == mTasks.size() - 1;
raysb.kim00a27252014-11-11 08:38:21 +0900365 if (toTop) {
366 mDisplayContent.moveStack(this, true);
367 }
Wale Ogunwaleddc1cb22015-07-25 19:23:04 -0700368 EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, position);
369 }
370
371 /** Calculate the minimum possible position for a task that can be shown to the user.
372 * The minimum position will be above all other tasks that can't be shown.
373 * @param minPosition The minimum position the caller is suggesting.
374 * We will start adjusting up from here.
375 * @param size The size of the current task list.
376 */
377 private int computeMinPosition(int minPosition, int size) {
378 while (minPosition < size) {
379 final Task tmpTask = mTasks.get(minPosition);
380 final boolean canShowTmpTask =
381 tmpTask.showForAllUsers()
382 || mService.isCurrentProfileLocked(tmpTask.mUserId);
383 if (canShowTmpTask) {
384 break;
385 }
386 minPosition++;
387 }
388 return minPosition;
389 }
390
391 /** Calculate the maximum possible position for a task that can't be shown to the user.
392 * The maximum position will be below all other tasks that can be shown.
393 * @param maxPosition The maximum position the caller is suggesting.
394 * We will start adjusting down from here.
395 */
396 private int computeMaxPosition(int maxPosition) {
397 while (maxPosition > 0) {
398 final Task tmpTask = mTasks.get(maxPosition - 1);
399 final boolean canShowTmpTask =
400 tmpTask.showForAllUsers()
401 || mService.isCurrentProfileLocked(tmpTask.mUserId);
402 if (!canShowTmpTask) {
403 break;
404 }
405 maxPosition--;
406 }
407 return maxPosition;
Craig Mautnerc00204b2013-03-05 15:02:14 -0800408 }
409
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800410 void moveTaskToTop(Task task) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800411 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToTop: task=" + task + " Callers="
Craig Mautnerf0ac5c82013-06-24 11:21:57 -0700412 + Debug.getCallers(6));
Craig Mautnerd9a22882013-03-16 15:00:36 -0700413 mTasks.remove(task);
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800414 addTask(task, true);
Craig Mautnerd9a22882013-03-16 15:00:36 -0700415 }
416
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800417 void moveTaskToBottom(Task task) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800418 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToBottom: task=" + task);
Craig Mautnerd9a22882013-03-16 15:00:36 -0700419 mTasks.remove(task);
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800420 addTask(task, false);
Craig Mautnerd9a22882013-03-16 15:00:36 -0700421 }
422
Craig Mautner00af9fe2013-03-25 09:13:41 -0700423 /**
Craig Mautner04a0ea62014-01-13 12:51:26 -0800424 * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the
425 * back.
Craig Mautner00af9fe2013-03-25 09:13:41 -0700426 * @param task The Task to delete.
Craig Mautner00af9fe2013-03-25 09:13:41 -0700427 */
Craig Mautnerde4ef022013-04-07 19:01:33 -0700428 void removeTask(Task task) {
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800429 if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeTask: task=" + task);
Craig Mautnerde4ef022013-04-07 19:01:33 -0700430 mTasks.remove(task);
Craig Mautnerdf88d732014-01-27 09:21:32 -0800431 if (mDisplayContent != null) {
Craig Mautnerdf88d732014-01-27 09:21:32 -0800432 if (mTasks.isEmpty()) {
433 mDisplayContent.moveStack(this, false);
434 }
435 mDisplayContent.layoutNeeded = true;
Craig Mautner04a0ea62014-01-13 12:51:26 -0800436 }
Craig Mautnere3119b72015-01-20 15:02:36 -0800437 for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) {
438 final AppWindowToken wtoken = mExitingAppTokens.get(appNdx);
Craig Mautner83162a92015-01-26 14:43:30 -0800439 if (wtoken.mTask == task) {
Craig Mautnere3119b72015-01-20 15:02:36 -0800440 wtoken.mIsExiting = false;
441 mExitingAppTokens.remove(appNdx);
442 }
443 }
Craig Mautnerc00204b2013-03-05 15:02:14 -0800444 }
445
Craig Mautnerdf88d732014-01-27 09:21:32 -0800446 void attachDisplayContent(DisplayContent displayContent) {
447 if (mDisplayContent != null) {
448 throw new IllegalStateException("attachDisplayContent: Already attached");
Craig Mautner4a1cb222013-12-04 16:14:06 -0800449 }
Craig Mautnerdf88d732014-01-27 09:21:32 -0800450
451 mDisplayContent = displayContent;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700452 mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId());
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700453
454 Rect bounds = null;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700455 final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
Wale Ogunwale3797c222015-10-27 14:21:58 -0700456 if (mStackId == DOCKED_STACK_ID
457 || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId))) {
458 // The existence of a docked stack affects the size of other static stack created since
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700459 // the docked stack occupies a dedicated region on screen.
460 bounds = new Rect();
461 displayContent.getLogicalDisplayRect(mTmpRect);
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700462 mTmpRect2.setEmpty();
463 if (dockedStack != null) {
464 dockedStack.getRawBounds(mTmpRect2);
465 }
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800466 final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700467 == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
468 getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2,
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100469 mDisplayContent.mDividerControllerLocked.getContentWidth(),
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700470 dockedOnTopOrLeft);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700471 }
472
473 updateDisplayInfo(bounds);
474
475 if (mStackId == DOCKED_STACK_ID) {
476 // Attaching a docked stack to the display affects the size of all other static
477 // stacks since the docked stack occupies a dedicated region on screen.
478 // Resize existing static stacks so they are pushed to the side of the docked stack.
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700479 resizeNonDockedStacks(!FULLSCREEN, mBounds);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700480 }
481 }
482
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700483 void getStackDockedModeBoundsLocked(Rect outBounds) {
Wale Ogunwale3797c222015-10-27 14:21:58 -0700484 if (!StackId.isResizeableByDockedStack(mStackId) || mDisplayContent == null) {
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700485 outBounds.set(mBounds);
486 return;
487 }
488
Filip Gruszczynski54977fe2015-10-19 17:26:45 -0700489 final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700490 if (dockedStack == null) {
491 // Not sure why you are calling this method when there is no docked stack...
492 throw new IllegalStateException(
493 "Calling getStackDockedModeBoundsLocked() when there is no docked stack.");
494 }
Filip Gruszczynski54977fe2015-10-19 17:26:45 -0700495 if (!dockedStack.isVisibleLocked()) {
496 // The docked stack is being dismissed, but we caught before it finished being
497 // dismissed. In that case we want to treat it as if it is not occupying any space and
498 // let others occupy the whole display.
499 mDisplayContent.getLogicalDisplayRect(mTmpRect);
500 return;
501 }
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700502
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700503 final int dockedSide = dockedStack.getDockSide();
504 if (dockedSide == DOCKED_INVALID) {
505 // Not sure how you got here...Only thing we can do is return current bounds.
Filip Gruszczynski0bd180d2015-12-07 15:43:52 -0800506 Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack);
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700507 outBounds.set(mBounds);
508 return;
509 }
510
511 mDisplayContent.getLogicalDisplayRect(mTmpRect);
512 dockedStack.getRawBounds(mTmpRect2);
Jorim Jaggi61f39a72015-10-29 16:54:18 +0100513 final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP
514 || dockedSide == DOCKED_LEFT;
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700515 getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2,
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100516 mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700517
518 }
519
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700520 /**
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700521 * Outputs the bounds a stack should be given the presence of a docked stack on the display.
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700522 * @param displayRect The bounds of the display the docked stack is on.
523 * @param outBounds Output bounds that should be used for the stack.
524 * @param stackId Id of stack we are calculating the bounds for.
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700525 * @param dockedBounds Bounds of the docked stack.
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700526 * @param dockDividerWidth We need to know the width of the divider make to the output bounds
527 * close to the side of the dock.
528 * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen.
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700529 */
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800530 private void getStackDockedModeBounds(
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700531 Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth,
532 boolean dockOnTopOrLeft) {
Filip Gruszczynski466f3212015-09-21 17:57:57 -0700533 final boolean dockedStack = stackId == DOCKED_STACK_ID;
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700534 final boolean splitHorizontally = displayRect.width() > displayRect.height();
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700535
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700536 outBounds.set(displayRect);
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700537 if (dockedStack) {
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800538 if (mService.mDockedStackCreateBounds != null) {
539 outBounds.set(mService.mDockedStackCreateBounds);
540 return;
541 }
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700542 // The initial bounds of the docked stack when it is created half the screen space and
543 // its bounds can be adjusted after that. The bounds of all other stacks are adjusted
544 // to occupy whatever screen space the docked stack isn't occupying.
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700545 if (dockOnTopOrLeft) {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700546 if (splitHorizontally) {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700547 outBounds.right = displayRect.centerX() - dockDividerWidth / 2;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700548 } else {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700549 outBounds.bottom = displayRect.centerY() - dockDividerWidth / 2;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700550 }
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700551 } else {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700552 if (splitHorizontally) {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700553 outBounds.left = displayRect.centerX() + dockDividerWidth / 2;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700554 } else {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700555 outBounds.top = displayRect.centerY() + dockDividerWidth / 2;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700556 }
557 }
558 return;
559 }
560
561 // Other stacks occupy whatever space is left by the docked stack.
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700562 if (!dockOnTopOrLeft) {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700563 if (splitHorizontally) {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700564 outBounds.right = dockedBounds.left - dockDividerWidth;
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700565 } else {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700566 outBounds.bottom = dockedBounds.top - dockDividerWidth;
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700567 }
568 } else {
569 if (splitHorizontally) {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700570 outBounds.left = dockedBounds.right + dockDividerWidth;
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700571 } else {
Filip Gruszczynskiba47f812015-10-28 16:11:55 -0700572 outBounds.top = dockedBounds.bottom + dockDividerWidth;
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700573 }
574 }
575 }
576
577 /** Resizes all non-docked stacks in the system to either fullscreen or the appropriate size
578 * based on the presence of a docked stack.
579 * @param fullscreen If true the stacks will be resized to fullscreen, else they will be
580 * resized to the appropriate size based on the presence of a docked stack.
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700581 * @param dockedBounds Bounds of the docked stack.
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700582 */
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700583 private void resizeNonDockedStacks(boolean fullscreen, Rect dockedBounds) {
584 // Not using mTmpRect because we are posting the object in a message.
585 final Rect bounds = new Rect();
586 mDisplayContent.getLogicalDisplayRect(bounds);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700587 if (!fullscreen) {
Jorim Jaggi9ea2f7b2015-11-23 18:08:28 -0800588 final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700589 == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
590 getStackDockedModeBounds(bounds, bounds, FULLSCREEN_WORKSPACE_STACK_ID, dockedBounds,
Jorim Jaggi1fcbab62015-11-04 16:39:50 +0100591 mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700592 }
593
594 final int count = mService.mStackIdToStack.size();
595 for (int i = 0; i < count; i++) {
596 final TaskStack otherStack = mService.mStackIdToStack.valueAt(i);
597 final int otherStackId = otherStack.mStackId;
Wale Ogunwale3856bf72015-11-20 09:36:46 -0800598 if (StackId.isResizeableByDockedStack(otherStackId)
599 && !otherStack.mBounds.equals(bounds)) {
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700600 mService.mH.sendMessage(
Wale Ogunwaleffc11bb2015-10-10 13:05:45 -0700601 mService.mH.obtainMessage(RESIZE_STACK, otherStackId,
Wale Ogunwale3856bf72015-11-20 09:36:46 -0800602 1 /*allowResizeInDockedMode*/, fullscreen ? null : bounds));
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700603 }
604 }
Craig Mautnerdf88d732014-01-27 09:21:32 -0800605 }
606
Craig Mautnerdc548482014-02-05 13:35:24 -0800607 void detachDisplay() {
Craig Mautnerdf88d732014-01-27 09:21:32 -0800608 EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700609
610 boolean doAnotherLayoutPass = false;
Craig Mautnerdc548482014-02-05 13:35:24 -0800611 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700612 final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens;
613 for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
614 final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
615 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
Filip Gruszczynskid66af6a2015-08-31 08:57:24 -0700616 // We are in the middle of changing the state of displays/stacks/tasks. We need
617 // to finish that, before we let layout interfere with it.
Filip Gruszczynski49b80af2015-09-24 09:04:26 -0700618 mService.removeWindowLocked(appWindows.get(winNdx));
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700619 doAnotherLayoutPass = true;
620 }
621 }
Craig Mautnerdc548482014-02-05 13:35:24 -0800622 }
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700623 if (doAnotherLayoutPass) {
Filip Gruszczynski24966d42015-09-05 15:00:00 -0700624 mService.mWindowPlacerLocked.requestTraversal();
Craig Mautnerbc2a6df2014-06-13 15:08:48 -0700625 }
626
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700627 if (mStackId == DOCKED_STACK_ID) {
628 // Docked stack was detached from the display, so we no longer need to restrict the
629 // region of the screen other static stacks occupy. Go ahead and make them fullscreen.
Wale Ogunwalee45899a2015-10-01 11:30:34 -0700630 resizeNonDockedStacks(FULLSCREEN, null);
Wale Ogunwaleb34a7ad2015-08-14 11:05:30 -0700631 }
632
Craig Mautner00a66752015-03-23 14:00:47 -0700633 close();
Craig Mautner00af9fe2013-03-25 09:13:41 -0700634 }
635
Craig Mautner05d29032013-05-03 13:40:13 -0700636 void resetAnimationBackgroundAnimator() {
637 mAnimationBackgroundAnimator = null;
638 mAnimationBackgroundSurface.hide();
639 }
640
Craig Mautner05d29032013-05-03 13:40:13 -0700641 void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
642 int animLayer = winAnimator.mAnimLayer;
643 if (mAnimationBackgroundAnimator == null
644 || animLayer < mAnimationBackgroundAnimator.mAnimLayer) {
645 mAnimationBackgroundAnimator = winAnimator;
646 animLayer = mService.adjustAnimationBackground(winAnimator);
647 mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM,
648 ((color >> 24) & 0xff) / 255f, 0);
649 }
650 }
651
Wale Ogunwale498e8c92015-02-13 09:42:46 -0800652 void switchUser() {
Craig Mautnerac6f8432013-07-17 13:24:59 -0700653 int top = mTasks.size();
654 for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
655 Task task = mTasks.get(taskNdx);
Wale Ogunwale6dfdfd62015-04-15 12:01:38 -0700656 if (mService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
Craig Mautnerac6f8432013-07-17 13:24:59 -0700657 mTasks.remove(taskNdx);
658 mTasks.add(task);
659 --top;
660 }
661 }
662 }
663
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800664 void close() {
Craig Mautner00a66752015-03-23 14:00:47 -0700665 if (mAnimationBackgroundSurface != null) {
666 mAnimationBackgroundSurface.destroySurface();
667 mAnimationBackgroundSurface = null;
668 }
Filip Gruszczynski26ed2652015-08-10 11:02:53 -0700669 mDisplayContent = null;
Craig Mautnerbdc748af2013-12-02 14:08:25 -0800670 }
671
Craig Mautner00af9fe2013-03-25 09:13:41 -0700672 public void dump(String prefix, PrintWriter pw) {
Wale Ogunwaleb429e682016-01-06 12:36:34 -0800673 pw.println(prefix + "mStackId=" + mStackId);
674 pw.println(prefix + "mDeferDetach=" + mDeferDetach);
675 pw.println(prefix + "mFullscreen=" + mFullscreen);
676 pw.println(prefix + "mBounds=" + mBounds.toShortString());
677 for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) {
678 mTasks.get(taskNdx).dump(prefix + " ", pw);
Craig Mautner00af9fe2013-03-25 09:13:41 -0700679 }
Craig Mautner05d29032013-05-03 13:40:13 -0700680 if (mAnimationBackgroundSurface.isDimming()) {
Wale Ogunwaleb429e682016-01-06 12:36:34 -0800681 pw.println(prefix + "mWindowAnimationBackgroundSurface:");
Craig Mautner05d29032013-05-03 13:40:13 -0700682 mAnimationBackgroundSurface.printTo(prefix + " ", pw);
683 }
Craig Mautnerdc548482014-02-05 13:35:24 -0800684 if (!mExitingAppTokens.isEmpty()) {
685 pw.println();
686 pw.println(" Exiting application tokens:");
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700687 for (int i = mExitingAppTokens.size() - 1; i >= 0; i--) {
Craig Mautnerdc548482014-02-05 13:35:24 -0800688 WindowToken token = mExitingAppTokens.get(i);
689 pw.print(" Exiting App #"); pw.print(i);
690 pw.print(' '); pw.print(token);
691 pw.println(':');
692 token.dump(pw, " ");
693 }
694 }
Craig Mautner00af9fe2013-03-25 09:13:41 -0700695 }
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700696
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700697 /** Fullscreen status of the stack without adjusting for other factors in the system like
698 * visibility of docked stack.
699 * Most callers should be using {@link #isFullscreen} as it take into consideration other
700 * system factors. */
701 boolean getRawFullscreen() {
702 return mFullscreen;
703 }
704
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700705 @Override
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700706 public boolean isFullscreen() {
Wale Ogunwalef175e8a2015-09-29 11:07:06 -0700707 if (useCurrentBounds()) {
708 return mFullscreen;
709 }
710 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
711 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
712 // system.
713 return true;
Wale Ogunwalee4a0c572015-06-30 08:40:31 -0700714 }
715
716 @Override
717 public DisplayInfo getDisplayInfo() {
718 return mDisplayContent.getDisplayInfo();
719 }
720
721 @Override
Craig Mautner4cd0c13f2013-04-16 15:55:52 -0700722 public String toString() {
723 return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
724 }
Filip Gruszczynski923f8262015-09-17 17:41:13 -0700725
Filip Gruszczynski0689ae92015-10-01 12:30:31 -0700726 @Override
727 public String toShortString() {
728 return "Stack=" + mStackId;
729 }
730
Filip Gruszczynski923f8262015-09-17 17:41:13 -0700731 /**
Chong Zhangc806d902015-11-30 09:44:27 -0800732 * For docked workspace (or workspace that's side-by-side to the docked), provides
733 * information which side of the screen was the dock anchored.
Filip Gruszczynski923f8262015-09-17 17:41:13 -0700734 */
Filip Gruszczynski923f8262015-09-17 17:41:13 -0700735 int getDockSide() {
Jorim Jaggi737af722015-12-31 10:42:27 +0100736 return getDockSide(mBounds);
737 }
738
739 int getDockSide(Rect bounds) {
Chong Zhangc806d902015-11-30 09:44:27 -0800740 if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) {
Filip Gruszczynski923f8262015-09-17 17:41:13 -0700741 return DOCKED_INVALID;
742 }
743 if (mDisplayContent == null) {
744 return DOCKED_INVALID;
745 }
746 mDisplayContent.getLogicalDisplayRect(mTmpRect);
747 final int orientation = mService.mCurConfiguration.orientation;
748 if (orientation == Configuration.ORIENTATION_PORTRAIT) {
749 // Portrait mode, docked either at the top or the bottom.
Jorim Jaggi737af722015-12-31 10:42:27 +0100750 if (bounds.top - mTmpRect.top < mTmpRect.bottom - bounds.bottom) {
Filip Gruszczynski923f8262015-09-17 17:41:13 -0700751 return DOCKED_TOP;
752 } else {
753 return DOCKED_BOTTOM;
754 }
755 } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
756 // Landscape mode, docked either on the left or on the right.
Jorim Jaggi737af722015-12-31 10:42:27 +0100757 if (bounds.left - mTmpRect.left < mTmpRect.right - bounds.right) {
Filip Gruszczynski923f8262015-09-17 17:41:13 -0700758 return DOCKED_LEFT;
759 } else {
760 return DOCKED_RIGHT;
761 }
762 } else {
763 return DOCKED_INVALID;
764 }
765 }
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700766
767 boolean isVisibleLocked() {
Chong Zhang75b37202015-12-04 14:16:36 -0800768 final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded();
769 if (keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
770 return false;
771 }
Filip Gruszczynski3ddc5d62015-09-23 15:01:30 -0700772 for (int i = mTasks.size() - 1; i >= 0; i--) {
773 Task task = mTasks.get(i);
774 for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
775 if (!task.mAppTokens.get(j).hidden) {
776 return true;
777 }
778 }
779 }
780 return false;
781 }
Craig Mautnerc00204b2013-03-05 15:02:14 -0800782}