2 * Copyright (C) 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.wm;
19 import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
20 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
21 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
22 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
23 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
24 import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
25 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
26 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
27 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
28 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
29 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
30 import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK;
31 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
33 import android.app.ActivityManager.StackId;
34 import android.content.pm.ActivityInfo;
35 import android.content.res.Configuration;
36 import android.graphics.Rect;
37 import android.util.EventLog;
38 import android.util.Slog;
39 import android.view.DisplayInfo;
40 import android.view.Surface;
42 import com.android.server.EventLogTags;
44 import java.io.PrintWriter;
45 import java.util.ArrayList;
47 class Task implements DimLayer.DimLayerUser {
48 static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
49 // Return value from {@link setBounds} indicating no change was made to the Task bounds.
50 static final int BOUNDS_CHANGE_NONE = 0;
51 // Return value from {@link setBounds} indicating the position of the Task bounds changed.
52 static final int BOUNDS_CHANGE_POSITION = 1;
53 // Return value from {@link setBounds} indicating the size of the Task bounds changed.
54 static final int BOUNDS_CHANGE_SIZE = 1 << 1;
57 final AppTokenList mAppTokens = new AppTokenList();
60 boolean mDeferRemoval = false;
61 final WindowManagerService mService;
63 // Content limits relative to the DisplayContent this sits in.
64 private Rect mBounds = new Rect();
65 final Rect mPreparedFrozenBounds = new Rect();
66 final Configuration mPreparedFrozenMergedConfig = new Configuration();
68 private Rect mPreScrollBounds = new Rect();
69 private boolean mScrollValid;
71 // Bounds used to calculate the insets.
72 private final Rect mTempInsetBounds = new Rect();
74 // Device rotation as of the last time {@link #mBounds} was set.
77 // Whether mBounds is fullscreen
78 private boolean mFullscreen = true;
80 // Contains configurations settings that are different from the global configuration due to
81 // stack specific operations. E.g. {@link #setBounds}.
82 Configuration mOverrideConfig = Configuration.EMPTY;
84 // For comparison with DisplayContent bounds.
85 private Rect mTmpRect = new Rect();
86 // For handling display rotations.
87 private Rect mTmpRect2 = new Rect();
89 // Resize mode of the task. See {@link ActivityInfo#resizeMode}
90 private int mResizeMode;
92 // Whether the task is currently being drag-resized
93 private boolean mDragResizing;
94 private int mDragResizeMode;
96 private boolean mHomeTask;
98 Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
99 Configuration config) {
104 setBounds(bounds, config);
107 DisplayContent getDisplayContent() {
108 return mStack.getDisplayContent();
111 void addAppToken(int addPos, AppWindowToken wtoken, int resizeMode, boolean homeTask) {
112 final int lastPos = mAppTokens.size();
113 if (addPos >= lastPos) {
116 for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {
117 if (mAppTokens.get(pos).removed) {
118 // addPos assumes removed tokens are actually gone.
123 mAppTokens.add(addPos, wtoken);
125 mDeferRemoval = false;
126 mResizeMode = resizeMode;
127 mHomeTask = homeTask;
130 private boolean hasWindowsAlive() {
131 for (int i = mAppTokens.size() - 1; i >= 0; i--) {
132 if (mAppTokens.get(i).hasWindowsAlive()) {
139 void removeLocked() {
140 if (hasWindowsAlive() && mStack.isAnimating()) {
141 if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
142 mDeferRemoval = true;
145 if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
146 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
147 mDeferRemoval = false;
148 DisplayContent content = getDisplayContent();
149 if (content != null) {
150 content.mDimLayerController.removeDimLayerUser(this);
152 mStack.removeTask(this);
153 mService.mTaskIdToTask.delete(mTaskId);
156 void moveTaskToStack(TaskStack stack, boolean toTop) {
157 if (stack == mStack) {
160 if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
161 + " from stack=" + mStack);
162 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
163 if (mStack != null) {
164 mStack.removeTask(this);
166 stack.addTask(this, toTop);
169 void positionTaskInStack(TaskStack stack, int position, Rect bounds, Configuration config) {
170 if (mStack != null && stack != mStack) {
171 if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
172 + " from stack=" + mStack);
173 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
174 mStack.removeTask(this);
176 stack.positionTask(this, position, showForAllUsers());
177 resizeLocked(bounds, config, false /* force */);
179 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
180 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
181 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
182 final WindowState win = windows.get(winNdx);
183 win.notifyMovedInStack();
188 boolean removeAppToken(AppWindowToken wtoken) {
189 boolean removed = mAppTokens.remove(wtoken);
190 if (mAppTokens.size() == 0) {
191 EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
197 /* Leave mTaskId for now, it might be useful for debug
203 void setSendingToBottom(boolean toBottom) {
204 for (int appTokenNdx = 0; appTokenNdx < mAppTokens.size(); appTokenNdx++) {
205 mAppTokens.get(appTokenNdx).sendingToBottom = toBottom;
209 /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
210 private int setBounds(Rect bounds, Configuration config) {
211 if (config == null) {
212 config = Configuration.EMPTY;
214 if (bounds == null && !Configuration.EMPTY.equals(config)) {
215 throw new IllegalArgumentException("null bounds but non empty configuration: "
218 if (bounds != null && Configuration.EMPTY.equals(config)) {
219 throw new IllegalArgumentException("non null bounds, but empty configuration");
221 boolean oldFullscreen = mFullscreen;
222 int rotation = Surface.ROTATION_0;
223 final DisplayContent displayContent = mStack.getDisplayContent();
224 if (displayContent != null) {
225 displayContent.getLogicalDisplayRect(mTmpRect);
226 rotation = displayContent.getDisplayInfo().rotation;
227 mFullscreen = bounds == null;
233 if (bounds == null) {
234 // Can't set to fullscreen if we don't have a display to get bounds from...
235 return BOUNDS_CHANGE_NONE;
237 if (mPreScrollBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
238 return BOUNDS_CHANGE_NONE;
241 int boundsChange = BOUNDS_CHANGE_NONE;
242 if (mPreScrollBounds.left != bounds.left || mPreScrollBounds.top != bounds.top) {
243 boundsChange |= BOUNDS_CHANGE_POSITION;
245 if (mPreScrollBounds.width() != bounds.width() || mPreScrollBounds.height() != bounds.height()) {
246 boundsChange |= BOUNDS_CHANGE_SIZE;
250 mPreScrollBounds.set(bounds);
254 mRotation = rotation;
255 if (displayContent != null) {
256 displayContent.mDimLayerController.updateDimLayer(this);
258 mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
263 * Sets the bounds used to calculate the insets. See
264 * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
266 void setTempInsetBounds(Rect tempInsetBounds) {
267 if (tempInsetBounds != null) {
268 mTempInsetBounds.set(tempInsetBounds);
270 mTempInsetBounds.setEmpty();
275 * Gets the bounds used to calculate the insets. See
276 * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
278 void getTempInsetBounds(Rect out) {
279 out.set(mTempInsetBounds);
282 void setResizeable(int resizeMode) {
283 mResizeMode = resizeMode;
286 boolean isResizeable() {
288 && (ActivityInfo.isResizeableMode(mResizeMode) || mService.mForceResizableTasks);
291 boolean cropWindowsToStackBounds() {
292 return !mHomeTask && (isResizeable() || mResizeMode == RESIZE_MODE_CROP_WINDOWS);
295 boolean isHomeTask() {
299 private boolean inCropWindowsResizeMode() {
300 return !mHomeTask && !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
303 boolean resizeLocked(Rect bounds, Configuration configuration, boolean forced) {
304 int boundsChanged = setBounds(bounds, configuration);
306 boundsChanged |= BOUNDS_CHANGE_SIZE;
308 if (boundsChanged == BOUNDS_CHANGE_NONE) {
311 if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
320 * Prepares the task bounds to be frozen with the current size. See
321 * {@link AppWindowToken#freezeBounds}.
323 void prepareFreezingBounds() {
324 mPreparedFrozenBounds.set(mBounds);
325 mPreparedFrozenMergedConfig.setTo(mService.mCurConfiguration);
326 mPreparedFrozenMergedConfig.updateFrom(mOverrideConfig);
330 * Align the task to the adjusted bounds.
332 * @param adjustedBounds Adjusted bounds to which the task should be aligned.
333 * @param tempInsetBounds Insets bounds for the task.
334 * @param alignBottom True if the task's bottom should be aligned to the adjusted
335 * bounds's bottom; false if the task's top should be aligned
336 * the adjusted bounds's top.
338 void alignToAdjustedBounds(
339 Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
340 if (!isResizeable() || mOverrideConfig == Configuration.EMPTY) {
344 getBounds(mTmpRect2);
346 int offsetY = adjustedBounds.bottom - mTmpRect2.bottom;
347 mTmpRect2.offset(0, offsetY);
349 mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
351 setTempInsetBounds(tempInsetBounds);
352 resizeLocked(mTmpRect2, mOverrideConfig, false /* forced */);
355 void resetScrollLocked() {
357 mScrollValid = false;
358 applyScrollToAllWindows(0, 0);
360 mBounds.set(mPreScrollBounds);
363 void applyScrollToAllWindows(final int xOffset, final int yOffset) {
364 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
365 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
366 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
367 final WindowState win = windows.get(winNdx);
368 win.mXOffset = xOffset;
369 win.mYOffset = yOffset;
374 void applyScrollToWindowIfNeeded(final WindowState win) {
376 win.mXOffset = mBounds.left;
377 win.mYOffset = mBounds.top;
381 boolean scrollLocked(Rect bounds) {
382 // shift the task bound if it doesn't fully cover the stack area
383 mStack.getDimBounds(mTmpRect);
384 if (mService.mCurConfiguration.orientation == ORIENTATION_LANDSCAPE) {
385 if (bounds.left > mTmpRect.left) {
386 bounds.left = mTmpRect.left;
387 bounds.right = mTmpRect.left + mBounds.width();
388 } else if (bounds.right < mTmpRect.right) {
389 bounds.left = mTmpRect.right - mBounds.width();
390 bounds.right = mTmpRect.right;
393 if (bounds.top > mTmpRect.top) {
394 bounds.top = mTmpRect.top;
395 bounds.bottom = mTmpRect.top + mBounds.height();
396 } else if (bounds.bottom < mTmpRect.bottom) {
397 bounds.top = mTmpRect.bottom - mBounds.height();
398 bounds.bottom = mTmpRect.bottom;
402 // We can stop here if we're already scrolling and the scrolled bounds not changed.
403 if (mScrollValid && bounds.equals(mBounds)) {
407 // Normal setBounds() does not allow non-null bounds for fullscreen apps.
408 // We only change bounds for the scrolling case without change it size,
409 // on resizing path we should still want the validation.
412 applyScrollToAllWindows(bounds.left, bounds.top);
416 /** Return true if the current bound can get outputted to the rest of the system as-is. */
417 private boolean useCurrentBounds() {
418 final DisplayContent displayContent = mStack.getDisplayContent();
420 || !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
421 || displayContent == null
422 || displayContent.getDockedStackVisibleForUserLocked() != null) {
428 /** Original bounds of the task if applicable, otherwise fullscreen rect. */
429 void getBounds(Rect out) {
430 if (useCurrentBounds()) {
431 // No need to adjust the output bounds if fullscreen or the docked stack is visible
432 // since it is already what we want to represent to the rest of the system.
437 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
438 // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
439 mStack.getDisplayContent().getLogicalDisplayRect(out);
443 * Calculate the maximum visible area of this task. If the task has only one app,
444 * the result will be visible frame of that app. If the task has more than one apps,
445 * we search from top down if the next app got different visible area.
447 * This effort is to handle the case where some task (eg. GMail composer) might pop up
448 * a dialog that's different in size from the activity below, in which case we should
449 * be dimming the entire task area behind the dialog.
451 * @param out Rect containing the max visible bounds.
452 * @return true if the task has some visible app windows; false otherwise.
454 boolean getMaxVisibleBounds(Rect out) {
455 boolean foundTop = false;
456 for (int i = mAppTokens.size() - 1; i >= 0; i--) {
457 final AppWindowToken token = mAppTokens.get(i);
458 // skip hidden (or about to hide) apps
459 if (token.mIsExiting || token.clientHidden || token.hiddenRequested) {
462 final WindowState win = token.findMainWindow();
467 out.set(win.mVisibleFrame);
471 if (win.mVisibleFrame.left < out.left) {
472 out.left = win.mVisibleFrame.left;
474 if (win.mVisibleFrame.top < out.top) {
475 out.top = win.mVisibleFrame.top;
477 if (win.mVisibleFrame.right > out.right) {
478 out.right = win.mVisibleFrame.right;
480 if (win.mVisibleFrame.bottom > out.bottom) {
481 out.bottom = win.mVisibleFrame.bottom;
487 /** Bounds of the task to be used for dimming, as well as touch related tests. */
489 public void getDimBounds(Rect out) {
490 final DisplayContent displayContent = mStack.getDisplayContent();
491 // It doesn't matter if we in particular are part of the resize, since we couldn't have
492 // a DimLayer anyway if we weren't visible.
493 final boolean dockedResizing = displayContent != null ?
494 displayContent.mDividerControllerLocked.isResizing() : false;
495 if (useCurrentBounds()) {
496 if (inFreeformWorkspace() && getMaxVisibleBounds(out)) {
501 // When minimizing the docked stack when going home, we don't adjust the task bounds
502 // so we need to intersect the task bounds with the stack bounds here.
504 // If we are Docked Resizing with snap points, the task bounds could be smaller than the stack
505 // bounds and so we don't even want to use them. Even if the app should not be resized the Dim
506 // should keep up with the divider.
507 if (dockedResizing) {
508 mStack.getBounds(out);
510 mStack.getBounds(mTmpRect);
511 mTmpRect.intersect(mBounds);
520 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
521 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
523 displayContent.getLogicalDisplayRect(out);
526 void setDragResizing(boolean dragResizing, int dragResizeMode) {
527 if (mDragResizing != dragResizing) {
528 if (!DragResizeMode.isModeAllowedForStack(mStack.mStackId, dragResizeMode)) {
529 throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
530 + mStack.mStackId + " dragResizeMode=" + dragResizeMode);
532 mDragResizing = dragResizing;
533 mDragResizeMode = dragResizeMode;
534 resetDragResizingChangeReported();
538 void resetDragResizingChangeReported() {
539 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
540 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
541 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
542 final WindowState win = windows.get(winNdx);
543 win.resetDragResizingChangeReported();
548 boolean isDragResizing() {
549 return mDragResizing || (mStack != null && mStack.isDragResizing());
552 int getDragResizeMode() {
553 return mDragResizeMode;
557 * Adds all of the tasks windows to {@link WindowManagerService#mWaitingForDrawn} if drag
558 * resizing state of the window has been changed.
560 void addWindowsWaitingForDrawnIfResizingChanged() {
561 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
562 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
563 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
564 final WindowState win = windows.get(winNdx);
565 if (win.isDragResizeChanged()) {
566 mService.mWaitingForDrawn.add(win);
572 void updateDisplayInfo(final DisplayContent displayContent) {
573 if (displayContent == null) {
577 setBounds(null, Configuration.EMPTY);
580 final int newRotation = displayContent.getDisplayInfo().rotation;
581 if (mRotation == newRotation) {
585 // Device rotation changed.
586 // - Reset the bounds to the pre-scroll bounds as whatever scrolling was done is no longer
588 // - Rotate the bounds and notify activity manager if the task can be resized independently
589 // from its stack. The stack will take care of task rotation for the other case.
590 mTmpRect2.set(mPreScrollBounds);
592 if (!StackId.isTaskResizeAllowed(mStack.mStackId)) {
593 setBounds(mTmpRect2, mOverrideConfig);
597 displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
598 if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) {
599 // Post message to inform activity manager of the bounds change simulating a one-way
600 // call. We do this to prevent a deadlock between window manager lock and activity
601 // manager lock been held.
602 mService.mH.obtainMessage(RESIZE_TASK, mTaskId,
603 RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mPreScrollBounds).sendToTarget();
607 void resizeWindows() {
608 final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
609 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
610 final AppWindowToken atoken = mAppTokens.get(activityNdx);
612 // Some windows won't go through the resizing process, if they don't have a surface, so
613 // destroy all saved surfaces here.
614 atoken.destroySavedSurfaces();
615 final ArrayList<WindowState> windows = atoken.allAppWindows;
616 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
617 final WindowState win = windows.get(winNdx);
618 if (win.mHasSurface && !resizingWindows.contains(win)) {
619 if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + win);
620 resizingWindows.add(win);
622 // If we are not drag resizing, force recreating of a new surface so updating
623 // the content and positioning that surface will be in sync.
625 // As we use this flag as a hint to freeze surface boundary updates,
626 // we'd like to only apply this to TYPE_BASE_APPLICATION,
627 // windows of TYPE_APPLICATION like dialogs, could appear
628 // to not be drag resizing while they resize, but we'd
629 // still like to manipulate their frame to update crop, etc...
631 // Anyway we don't need to synchronize position and content updates for these
632 // windows since they aren't at the base layer and could be moved around anyway.
633 if (!win.computeDragResizing() && win.mAttrs.type == TYPE_BASE_APPLICATION &&
634 !mStack.getBoundsAnimating() && !win.isGoneForLayoutLw() &&
635 !inPinnedWorkspace()) {
636 win.setResizedWhileNotDragResizing(true);
639 if (win.isGoneForLayoutLw()) {
640 win.mResizedWhileGone = true;
647 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
648 final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
649 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
650 final WindowState win = windows.get(winNdx);
651 if (DEBUG_RESIZE) Slog.d(TAG, "moveWindows: Moving " + win);
652 win.mMovedByResize = true;
658 * Cancels any running app transitions associated with the task.
660 void cancelTaskWindowTransition() {
661 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
662 mAppTokens.get(activityNdx).mAppAnimator.clearAnimation();
667 * Cancels any running thumbnail transitions associated with the task.
669 void cancelTaskThumbnailTransition() {
670 for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
671 mAppTokens.get(activityNdx).mAppAnimator.clearThumbnail();
675 boolean showForAllUsers() {
676 final int tokensCount = mAppTokens.size();
677 return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
680 boolean isVisibleForUser() {
681 for (int i = mAppTokens.size() - 1; i >= 0; i--) {
682 final AppWindowToken appToken = mAppTokens.get(i);
683 for (int j = appToken.allAppWindows.size() - 1; j >= 0; j--) {
684 WindowState window = appToken.allAppWindows.get(j);
685 if (!window.isHiddenFromUserLocked()) {
693 boolean isVisible() {
694 for (int i = mAppTokens.size() - 1; i >= 0; i--) {
695 final AppWindowToken appToken = mAppTokens.get(i);
696 if (appToken.isVisible()) {
703 boolean inHomeStack() {
704 return mStack != null && mStack.mStackId == HOME_STACK_ID;
707 boolean inFreeformWorkspace() {
708 return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
711 boolean inDockedWorkspace() {
712 return mStack != null && mStack.mStackId == DOCKED_STACK_ID;
715 boolean inPinnedWorkspace() {
716 return mStack != null && mStack.mStackId == PINNED_STACK_ID;
719 boolean isResizeableByDockedStack() {
720 final DisplayContent displayContent = getDisplayContent();
721 return displayContent != null && displayContent.getDockedStackLocked() != null
722 && mStack != null && StackId.isTaskResizeableByDockedStack(mStack.mStackId);
725 boolean isFloating() {
726 return StackId.tasksAreFloating(mStack.mStackId);
730 * Whether the task should be treated as if it's docked. Returns true if the task
731 * is currently in docked workspace, or it's side-by-side to a docked task.
733 boolean isDockedInEffect() {
734 return inDockedWorkspace() || isResizeableByDockedStack();
737 boolean isTwoFingerScrollMode() {
738 return inCropWindowsResizeMode() && isDockedInEffect();
741 WindowState getTopVisibleAppMainWindow() {
742 final AppWindowToken token = getTopVisibleAppToken();
743 return token != null ? token.findMainWindow() : null;
746 AppWindowToken getTopVisibleAppToken() {
747 for (int i = mAppTokens.size() - 1; i >= 0; i--) {
748 final AppWindowToken token = mAppTokens.get(i);
749 // skip hidden (or about to hide) apps
750 if (!token.mIsExiting && !token.clientHidden && !token.hiddenRequested) {
757 AppWindowToken getTopAppToken() {
758 return mAppTokens.size() > 0 ? mAppTokens.get(mAppTokens.size() - 1) : null;
762 public boolean dimFullscreen() {
763 return isHomeTask() || isFullscreen();
766 boolean isFullscreen() {
767 if (useCurrentBounds()) {
770 // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
771 // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
777 public DisplayInfo getDisplayInfo() {
778 return mStack.getDisplayContent().getDisplayInfo();
782 public String toString() {
783 return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
787 public String toShortString() {
788 return "Task=" + mTaskId;
791 public void dump(String prefix, PrintWriter pw) {
792 final String doublePrefix = prefix + " ";
794 pw.println(prefix + "taskId=" + mTaskId);
795 pw.println(doublePrefix + "mFullscreen=" + mFullscreen);
796 pw.println(doublePrefix + "mBounds=" + mBounds.toShortString());
797 pw.println(doublePrefix + "mdr=" + mDeferRemoval);
798 pw.println(doublePrefix + "appTokens=" + mAppTokens);
799 pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString());
801 final String triplePrefix = doublePrefix + " ";
803 for (int i = mAppTokens.size() - 1; i >= 0; i--) {
804 final AppWindowToken wtoken = mAppTokens.get(i);
805 pw.println(triplePrefix + "Activity #" + i + " " + wtoken);
806 wtoken.dump(pw, triplePrefix);