Task.java revision e42d0e102dbdf5287703389183a69019b64fc35e
1/*
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
19import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
20import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
21import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
22import static android.app.ActivityManager.StackId.HOME_STACK_ID;
23import static android.content.pm.ActivityInfo.RESIZE_MODE_CROP_WINDOWS;
24import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
25import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
26import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
27import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
28import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
29import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK;
30import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
31
32import android.app.ActivityManager.StackId;
33import android.content.pm.ActivityInfo;
34import android.content.res.Configuration;
35import android.graphics.Rect;
36import android.util.EventLog;
37import android.util.Slog;
38import android.view.DisplayInfo;
39import android.view.Surface;
40
41import com.android.server.EventLogTags;
42
43import java.io.PrintWriter;
44import java.util.ArrayList;
45
46class Task implements DimLayer.DimLayerUser {
47    static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
48    // Return value from {@link setBounds} indicating no change was made to the Task bounds.
49    static final int BOUNDS_CHANGE_NONE = 0;
50    // Return value from {@link setBounds} indicating the position of the Task bounds changed.
51    static final int BOUNDS_CHANGE_POSITION = 1;
52    // Return value from {@link setBounds} indicating the size of the Task bounds changed.
53    static final int BOUNDS_CHANGE_SIZE = 1 << 1;
54
55    TaskStack mStack;
56    final AppTokenList mAppTokens = new AppTokenList();
57    final int mTaskId;
58    final int mUserId;
59    boolean mDeferRemoval = false;
60    final WindowManagerService mService;
61
62    // Content limits relative to the DisplayContent this sits in.
63    private Rect mBounds = new Rect();
64    final Rect mPreparedFrozenBounds = new Rect();
65
66    private Rect mPreScrollBounds = new Rect();
67    private boolean mScrollValid;
68
69    // Bounds used to calculate the insets.
70    private final Rect mTempInsetBounds = new Rect();
71
72    // Device rotation as of the last time {@link #mBounds} was set.
73    int mRotation;
74
75    // Whether mBounds is fullscreen
76    private boolean mFullscreen = true;
77
78    // Contains configurations settings that are different from the global configuration due to
79    // stack specific operations. E.g. {@link #setBounds}.
80    Configuration mOverrideConfig;
81
82    // For comparison with DisplayContent bounds.
83    private Rect mTmpRect = new Rect();
84    // For handling display rotations.
85    private Rect mTmpRect2 = new Rect();
86
87    // Resize mode of the task. See {@link ActivityInfo#resizeMode}
88    private int mResizeMode;
89
90    // Whether the task is currently being drag-resized
91    private boolean mDragResizing;
92    private int mDragResizeMode;
93
94    private boolean mHomeTask;
95
96    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
97            Configuration config) {
98        mTaskId = taskId;
99        mStack = stack;
100        mUserId = userId;
101        mService = service;
102        setBounds(bounds, config);
103    }
104
105    DisplayContent getDisplayContent() {
106        return mStack.getDisplayContent();
107    }
108
109    void addAppToken(int addPos, AppWindowToken wtoken, int resizeMode, boolean homeTask) {
110        final int lastPos = mAppTokens.size();
111        if (addPos >= lastPos) {
112            addPos = lastPos;
113        } else {
114            for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {
115                if (mAppTokens.get(pos).removed) {
116                    // addPos assumes removed tokens are actually gone.
117                    ++addPos;
118                }
119            }
120        }
121        mAppTokens.add(addPos, wtoken);
122        wtoken.mTask = this;
123        mDeferRemoval = false;
124        mResizeMode = resizeMode;
125        mHomeTask = homeTask;
126    }
127
128    private boolean hasWindowsAlive() {
129        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
130            if (mAppTokens.get(i).hasWindowsAlive()) {
131                return true;
132            }
133        }
134        return false;
135    }
136
137    void removeLocked() {
138        if (hasWindowsAlive() && mStack.isAnimating()) {
139            if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
140            mDeferRemoval = true;
141            return;
142        }
143        if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
144        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
145        mDeferRemoval = false;
146        DisplayContent content = getDisplayContent();
147        if (content != null) {
148            content.mDimLayerController.removeDimLayerUser(this);
149        }
150        mStack.removeTask(this);
151        mService.mTaskIdToTask.delete(mTaskId);
152    }
153
154    void moveTaskToStack(TaskStack stack, boolean toTop) {
155        if (stack == mStack) {
156            return;
157        }
158        if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
159                + " from stack=" + mStack);
160        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
161        if (mStack != null) {
162            mStack.removeTask(this);
163        }
164        stack.addTask(this, toTop);
165    }
166
167    void positionTaskInStack(TaskStack stack, int position, Rect bounds, Configuration config) {
168        if (mStack != null && stack != mStack) {
169            if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
170                    + " from stack=" + mStack);
171            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
172            mStack.removeTask(this);
173        }
174        stack.positionTask(this, position, showForAllUsers());
175        resizeLocked(bounds, config, false /* force */);
176
177        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
178            final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
179            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
180                final WindowState win = windows.get(winNdx);
181                win.notifyMovedInStack();
182            }
183        }
184    }
185
186    boolean removeAppToken(AppWindowToken wtoken) {
187        boolean removed = mAppTokens.remove(wtoken);
188        if (mAppTokens.size() == 0) {
189            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
190            if (mDeferRemoval) {
191                removeLocked();
192            }
193        }
194        wtoken.mTask = null;
195        /* Leave mTaskId for now, it might be useful for debug
196        wtoken.mTaskId = -1;
197         */
198        return removed;
199    }
200
201    void setSendingToBottom(boolean toBottom) {
202        for (int appTokenNdx = 0; appTokenNdx < mAppTokens.size(); appTokenNdx++) {
203            mAppTokens.get(appTokenNdx).sendingToBottom = toBottom;
204        }
205    }
206
207    /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
208    private int setBounds(Rect bounds, Configuration config) {
209        if (config == null) {
210            config = Configuration.EMPTY;
211        }
212        if (bounds == null && !Configuration.EMPTY.equals(config)) {
213            throw new IllegalArgumentException("null bounds but non empty configuration: "
214                    + config);
215        }
216        if (bounds != null && Configuration.EMPTY.equals(config)) {
217            throw new IllegalArgumentException("non null bounds, but empty configuration");
218        }
219        boolean oldFullscreen = mFullscreen;
220        int rotation = Surface.ROTATION_0;
221        final DisplayContent displayContent = mStack.getDisplayContent();
222        if (displayContent != null) {
223            displayContent.getLogicalDisplayRect(mTmpRect);
224            rotation = displayContent.getDisplayInfo().rotation;
225            mFullscreen = bounds == null;
226            if (mFullscreen) {
227                bounds = mTmpRect;
228            }
229        }
230
231        if (bounds == null) {
232            // Can't set to fullscreen if we don't have a display to get bounds from...
233            return BOUNDS_CHANGE_NONE;
234        }
235        if (mPreScrollBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
236            return BOUNDS_CHANGE_NONE;
237        }
238
239        int boundsChange = BOUNDS_CHANGE_NONE;
240        if (mPreScrollBounds.left != bounds.left || mPreScrollBounds.top != bounds.top) {
241            boundsChange |= BOUNDS_CHANGE_POSITION;
242        }
243        if (mPreScrollBounds.width() != bounds.width() || mPreScrollBounds.height() != bounds.height()) {
244            boundsChange |= BOUNDS_CHANGE_SIZE;
245        }
246
247
248        mPreScrollBounds.set(bounds);
249
250        resetScrollLocked();
251
252        mRotation = rotation;
253        if (displayContent != null) {
254            displayContent.mDimLayerController.updateDimLayer(this);
255        }
256        mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
257        return boundsChange;
258    }
259
260    /**
261     * Sets the bounds used to calculate the insets. See
262     * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
263     */
264    void setTempInsetBounds(Rect tempInsetBounds) {
265        if (tempInsetBounds != null) {
266            mTempInsetBounds.set(tempInsetBounds);
267        } else {
268            mTempInsetBounds.setEmpty();
269        }
270    }
271
272    /**
273     * Gets the bounds used to calculate the insets. See
274     * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
275     */
276    void getTempInsetBounds(Rect out) {
277        out.set(mTempInsetBounds);
278    }
279
280    void setResizeable(int resizeMode) {
281        mResizeMode = resizeMode;
282    }
283
284    boolean isResizeable() {
285        return !mHomeTask
286                && (ActivityInfo.isResizeableMode(mResizeMode) || mService.mForceResizableTasks);
287    }
288
289    boolean cropWindowsToStackBounds() {
290        return !mHomeTask && (isResizeable() || mResizeMode == RESIZE_MODE_CROP_WINDOWS);
291    }
292
293    boolean isHomeTask() {
294        return mHomeTask;
295    }
296
297    private boolean inCropWindowsResizeMode() {
298        return !mHomeTask && !isResizeable() && mResizeMode == RESIZE_MODE_CROP_WINDOWS;
299    }
300
301    boolean resizeLocked(Rect bounds, Configuration configuration, boolean forced) {
302        int boundsChanged = setBounds(bounds, configuration);
303        if (forced) {
304            boundsChanged |= BOUNDS_CHANGE_SIZE;
305        }
306        if (boundsChanged == BOUNDS_CHANGE_NONE) {
307            return false;
308        }
309        if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
310            resizeWindows();
311        } else {
312            moveWindows();
313        }
314        return true;
315    }
316
317    /**
318     * Prepares the task bounds to be frozen with the current size. See
319     * {@link AppWindowToken#freezeBounds}.
320     */
321    void prepareFreezingBounds() {
322        mPreparedFrozenBounds.set(mBounds);
323    }
324
325    void resetScrollLocked() {
326        if (mScrollValid) {
327            mScrollValid = false;
328            applyScrollToAllWindows(0, 0);
329        }
330        mBounds.set(mPreScrollBounds);
331    }
332
333    void applyScrollToAllWindows(final int xOffset, final int yOffset) {
334        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
335            final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
336            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
337                final WindowState win = windows.get(winNdx);
338                win.mXOffset = xOffset;
339                win.mYOffset = yOffset;
340            }
341        }
342    }
343
344    void applyScrollToWindowIfNeeded(final WindowState win) {
345        if (mScrollValid) {
346            win.mXOffset = mBounds.left;
347            win.mYOffset = mBounds.top;
348        }
349    }
350
351    boolean scrollLocked(Rect bounds) {
352        // shift the task bound if it doesn't fully cover the stack area
353        mStack.getDimBounds(mTmpRect);
354        if (mService.mCurConfiguration.orientation == ORIENTATION_LANDSCAPE) {
355            if (bounds.left > mTmpRect.left) {
356                bounds.left = mTmpRect.left;
357                bounds.right = mTmpRect.left + mBounds.width();
358            } else if (bounds.right < mTmpRect.right) {
359                bounds.left = mTmpRect.right - mBounds.width();
360                bounds.right = mTmpRect.right;
361            }
362        } else {
363            if (bounds.top > mTmpRect.top) {
364                bounds.top = mTmpRect.top;
365                bounds.bottom = mTmpRect.top + mBounds.height();
366            } else if (bounds.bottom < mTmpRect.bottom) {
367                bounds.top = mTmpRect.bottom - mBounds.height();
368                bounds.bottom = mTmpRect.bottom;
369            }
370        }
371
372        // We can stop here if we're already scrolling and the scrolled bounds not changed.
373        if (mScrollValid && bounds.equals(mBounds)) {
374            return false;
375        }
376
377        // Normal setBounds() does not allow non-null bounds for fullscreen apps.
378        // We only change bounds for the scrolling case without change it size,
379        // on resizing path we should still want the validation.
380        mBounds.set(bounds);
381        mScrollValid = true;
382        applyScrollToAllWindows(bounds.left, bounds.top);
383        return true;
384    }
385
386    /** Return true if the current bound can get outputted to the rest of the system as-is. */
387    private boolean useCurrentBounds() {
388        final DisplayContent displayContent = mStack.getDisplayContent();
389        if (mFullscreen
390                || !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
391                || displayContent == null
392                || displayContent.getDockedStackVisibleForUserLocked() != null) {
393            return true;
394        }
395        return false;
396    }
397
398    /** Original bounds of the task if applicable, otherwise fullscreen rect. */
399    void getBounds(Rect out) {
400        if (useCurrentBounds()) {
401            // No need to adjust the output bounds if fullscreen or the docked stack is visible
402            // since it is already what we want to represent to the rest of the system.
403            out.set(mBounds);
404            return;
405        }
406
407        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
408        // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
409        mStack.getDisplayContent().getLogicalDisplayRect(out);
410    }
411
412    /**
413     * Calculate the maximum visible area of this task. If the task has only one app,
414     * the result will be visible frame of that app. If the task has more than one apps,
415     * we search from top down if the next app got different visible area.
416     *
417     * This effort is to handle the case where some task (eg. GMail composer) might pop up
418     * a dialog that's different in size from the activity below, in which case we should
419     * be dimming the entire task area behind the dialog.
420     *
421     * @param out Rect containing the max visible bounds.
422     * @return true if the task has some visible app windows; false otherwise.
423     */
424    boolean getMaxVisibleBounds(Rect out) {
425        boolean foundTop = false;
426        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
427            final AppWindowToken token = mAppTokens.get(i);
428            // skip hidden (or about to hide) apps
429            if (token.mIsExiting || token.clientHidden || token.hiddenRequested) {
430                continue;
431            }
432            final WindowState win = token.findMainWindow();
433            if (win == null) {
434                continue;
435            }
436            if (!foundTop) {
437                out.set(win.mVisibleFrame);
438                foundTop = true;
439                continue;
440            }
441            if (win.mVisibleFrame.left < out.left) {
442                out.left = win.mVisibleFrame.left;
443            }
444            if (win.mVisibleFrame.top < out.top) {
445                out.top = win.mVisibleFrame.top;
446            }
447            if (win.mVisibleFrame.right > out.right) {
448                out.right = win.mVisibleFrame.right;
449            }
450            if (win.mVisibleFrame.bottom > out.bottom) {
451                out.bottom = win.mVisibleFrame.bottom;
452            }
453        }
454        return foundTop;
455    }
456
457    /** Bounds of the task to be used for dimming, as well as touch related tests. */
458    @Override
459    public void getDimBounds(Rect out) {
460        final DisplayContent displayContent = mStack.getDisplayContent();
461        // It doesn't matter if we in particular are part of the resize, since we couldn't have
462        // a DimLayer anyway if we weren't visible.
463        final boolean dockedResizing = displayContent != null ?
464                displayContent.mDividerControllerLocked.isResizing() : false;
465        if (useCurrentBounds()) {
466            if (inFreeformWorkspace() && getMaxVisibleBounds(out)) {
467                return;
468            }
469
470            if (!mFullscreen) {
471                // When minimizing the docked stack when going home, we don't adjust the task bounds
472                // so we need to intersect the task bounds with the stack bounds here.
473                //
474                // If we are Docked Resizing with snap points, the task bounds could be smaller than the stack
475                // bounds and so we don't even want to use them. Even if the app should not be resized the Dim
476                // should keep up with the divider.
477                if (dockedResizing) {
478                    mStack.getBounds(out);
479                } else {
480                    mStack.getBounds(mTmpRect);
481                    mTmpRect.intersect(mBounds);
482                }
483                out.set(mTmpRect);
484            } else {
485                out.set(mBounds);
486            }
487            return;
488        }
489
490        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
491        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
492        // system.
493        displayContent.getLogicalDisplayRect(out);
494    }
495
496    void setDragResizing(boolean dragResizing, int dragResizeMode) {
497        if (mDragResizing != dragResizing) {
498            if (!DragResizeMode.isModeAllowedForStack(mStack.mStackId, dragResizeMode)) {
499                throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
500                        + mStack.mStackId + " dragResizeMode=" + dragResizeMode);
501            }
502            mDragResizing = dragResizing;
503            mDragResizeMode = dragResizeMode;
504            resetDragResizingChangeReported();
505        }
506    }
507
508    void resetDragResizingChangeReported() {
509        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
510            final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
511            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
512                final WindowState win = windows.get(winNdx);
513                win.resetDragResizingChangeReported();
514            }
515        }
516    }
517
518    boolean isDragResizing() {
519        return mDragResizing || (mStack != null && mStack.isDragResizing());
520    }
521
522    int getDragResizeMode() {
523        return mDragResizeMode;
524    }
525
526    /**
527     * Adds all of the tasks windows to {@link WindowManagerService#mWaitingForDrawn} if drag
528     * resizing state of the window has been changed.
529     */
530    void addWindowsWaitingForDrawnIfResizingChanged() {
531        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
532            final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
533            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
534                final WindowState win = windows.get(winNdx);
535                if (win.isDragResizeChanged()) {
536                    mService.mWaitingForDrawn.add(win);
537                }
538            }
539        }
540    }
541
542    void updateDisplayInfo(final DisplayContent displayContent) {
543        if (displayContent == null) {
544            return;
545        }
546        if (mFullscreen) {
547            setBounds(null, Configuration.EMPTY);
548            return;
549        }
550        final int newRotation = displayContent.getDisplayInfo().rotation;
551        if (mRotation == newRotation) {
552            return;
553        }
554
555        // Device rotation changed.
556        // - Reset the bounds to the pre-scroll bounds as whatever scrolling was done is no longer
557        // valid.
558        // - Rotate the bounds and notify activity manager if the task can be resized independently
559        // from its stack. The stack will take care of task rotation for the other case.
560        mTmpRect2.set(mPreScrollBounds);
561
562        if (!StackId.isTaskResizeAllowed(mStack.mStackId)) {
563            setBounds(mTmpRect2, mOverrideConfig);
564            return;
565        }
566
567        displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
568        if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) {
569            // Post message to inform activity manager of the bounds change simulating a one-way
570            // call. We do this to prevent a deadlock between window manager lock and activity
571            // manager lock been held.
572            mService.mH.obtainMessage(RESIZE_TASK, mTaskId,
573                    RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mPreScrollBounds).sendToTarget();
574        }
575    }
576
577    void resizeWindows() {
578        final ArrayList<WindowState> resizingWindows = mService.mResizingWindows;
579        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
580            final AppWindowToken atoken = mAppTokens.get(activityNdx);
581
582            // Some windows won't go through the resizing process, if they don't have a surface, so
583            // destroy all saved surfaces here.
584            atoken.destroySavedSurfaces();
585            final ArrayList<WindowState> windows = atoken.allAppWindows;
586            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
587                final WindowState win = windows.get(winNdx);
588                if (win.mHasSurface && !resizingWindows.contains(win)) {
589                    if (DEBUG_RESIZE) Slog.d(TAG, "resizeWindows: Resizing " + win);
590                    resizingWindows.add(win);
591
592                    // If we are not drag resizing, force recreating of a new surface so updating
593                    // the content and positioning that surface will be in sync.
594                    //
595                    // As we use this flag as a hint to freeze surface boundary updates,
596                    // we'd like to only apply this to TYPE_BASE_APPLICATION,
597                    // windows of TYPE_APPLICATION like dialogs, could appear
598                    // to not be drag resizing while they resize, but we'd
599                    // still like to manipulate their frame to update crop, etc...
600                    //
601                    // Anyway we don't need to synchronize position and content updates for these
602                    // windows since they aren't at the base layer and could be moved around anyway.
603                    if (!win.computeDragResizing() && win.mAttrs.type == TYPE_BASE_APPLICATION &&
604                            !mStack.getBoundsAnimating() && !win.isGoneForLayoutLw()) {
605                        win.mResizedWhileNotDragResizing = true;
606                    }
607                }
608                if (win.isGoneForLayoutLw()) {
609                    win.mResizedWhileGone = true;
610                }
611            }
612        }
613    }
614
615    void moveWindows() {
616        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
617            final ArrayList<WindowState> windows = mAppTokens.get(activityNdx).allAppWindows;
618            for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
619                final WindowState win = windows.get(winNdx);
620                if (DEBUG_RESIZE) Slog.d(TAG, "moveWindows: Moving " + win);
621                win.mMovedByResize = true;
622            }
623        }
624    }
625
626    /**
627     * Cancels any running app transitions associated with the task.
628     */
629    void cancelTaskWindowTransition() {
630        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
631            mAppTokens.get(activityNdx).mAppAnimator.clearAnimation();
632        }
633    }
634
635    /**
636     * Cancels any running thumbnail transitions associated with the task.
637     */
638    void cancelTaskThumbnailTransition() {
639        for (int activityNdx = mAppTokens.size() - 1; activityNdx >= 0; --activityNdx) {
640            mAppTokens.get(activityNdx).mAppAnimator.clearThumbnail();
641        }
642    }
643
644    boolean showForAllUsers() {
645        final int tokensCount = mAppTokens.size();
646        return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
647    }
648
649    boolean isVisibleForUser() {
650        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
651            final AppWindowToken appToken = mAppTokens.get(i);
652            for (int j = appToken.allAppWindows.size() - 1; j >= 0; j--) {
653                WindowState window = appToken.allAppWindows.get(j);
654                if (!window.isHiddenFromUserLocked()) {
655                    return true;
656                }
657            }
658        }
659        return false;
660    }
661
662    boolean isVisible() {
663        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
664            final AppWindowToken appToken = mAppTokens.get(i);
665            if (appToken.isVisible()) {
666                return true;
667            }
668        }
669        return false;
670    }
671
672    boolean inHomeStack() {
673        return mStack != null && mStack.mStackId == HOME_STACK_ID;
674    }
675
676    boolean inFreeformWorkspace() {
677        return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
678    }
679
680    boolean inDockedWorkspace() {
681        return mStack != null && mStack.mStackId == DOCKED_STACK_ID;
682    }
683
684    boolean isResizeableByDockedStack() {
685        final DisplayContent displayContent = getDisplayContent();
686        return displayContent != null && displayContent.getDockedStackLocked() != null
687                && mStack != null && StackId.isTaskResizeableByDockedStack(mStack.mStackId);
688    }
689
690    boolean isFloating() {
691        return StackId.tasksAreFloating(mStack.mStackId);
692    }
693
694    /**
695     * Whether the task should be treated as if it's docked. Returns true if the task
696     * is currently in docked workspace, or it's side-by-side to a docked task.
697     */
698    boolean isDockedInEffect() {
699        return inDockedWorkspace() || isResizeableByDockedStack();
700    }
701
702    boolean isTwoFingerScrollMode() {
703        return inCropWindowsResizeMode() && isDockedInEffect();
704    }
705
706    WindowState getTopVisibleAppMainWindow() {
707        final AppWindowToken token = getTopVisibleAppToken();
708        return token != null ? token.findMainWindow() : null;
709    }
710
711    AppWindowToken getTopVisibleAppToken() {
712        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
713            final AppWindowToken token = mAppTokens.get(i);
714            // skip hidden (or about to hide) apps
715            if (!token.mIsExiting && !token.clientHidden && !token.hiddenRequested) {
716                return token;
717            }
718        }
719        return null;
720    }
721
722    AppWindowToken getTopAppToken() {
723        return mAppTokens.size() > 0 ? mAppTokens.get(mAppTokens.size() - 1) : null;
724    }
725
726    @Override
727    public boolean isFullscreen() {
728        if (useCurrentBounds()) {
729            return mFullscreen;
730        }
731        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
732        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
733        // system.
734        return true;
735    }
736
737    @Override
738    public DisplayInfo getDisplayInfo() {
739        return mStack.getDisplayContent().getDisplayInfo();
740    }
741
742    @Override
743    public String toString() {
744        return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
745    }
746
747    @Override
748    public String toShortString() {
749        return "Task=" + mTaskId;
750    }
751
752    public void dump(String prefix, PrintWriter pw) {
753        final String doublePrefix = prefix + "  ";
754
755        pw.println(prefix + "taskId=" + mTaskId);
756        pw.println(doublePrefix + "mFullscreen=" + mFullscreen);
757        pw.println(doublePrefix + "mBounds=" + mBounds.toShortString());
758        pw.println(doublePrefix + "mdr=" + mDeferRemoval);
759        pw.println(doublePrefix + "appTokens=" + mAppTokens);
760        pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString());
761
762        final String triplePrefix = doublePrefix + "  ";
763
764        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
765            final AppWindowToken wtoken = mAppTokens.get(i);
766            pw.println(triplePrefix + "Activity #" + i + " " + wtoken);
767            wtoken.dump(pw, triplePrefix);
768        }
769
770    }
771}
772