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