Task.java revision 5406e7ade87c33f70c83a283781dcc48fb67cdb9
158d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes/*
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 2013 The Android Open Source Project
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * you may not use this file except in compliance with the License.
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * You may obtain a copy of the License at
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * See the License for the specific language governing permissions and
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * limitations under the License.
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectpackage com.android.server.wm;
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static android.app.ActivityManager.StackId.PINNED_STACK_ID;
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static android.app.ActivityManager.StackId.HOME_STACK_ID;
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport static com.android.server.wm.WindowManagerService.H.RESIZE_TASK;
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.app.ActivityManager.StackId;
291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.content.pm.ActivityInfo;
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.content.res.Configuration;
311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.graphics.Rect;
321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.util.EventLog;
331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.util.Slog;
3458d9e280d459225aa8dc4533e883182b08215f7dElliott Hughesimport android.view.DisplayInfo;
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport android.view.Surface;
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectimport com.android.server.EventLogTags;
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3958d9e280d459225aa8dc4533e883182b08215f7dElliott Hughesimport java.io.PrintWriter;
401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
4158d9e280d459225aa8dc4533e883182b08215f7dElliott Hughesclass Task extends WindowContainer<AppWindowToken> implements DimLayer.DimLayerUser {
421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    static final String TAG = TAG_WITH_CLASS_NAME ? "Task" : TAG_WM;
431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // Return value from {@link setBounds} indicating no change was made to the Task bounds.
441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    private static final int BOUNDS_CHANGE_NONE = 0;
451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // Return value from {@link setBounds} indicating the position of the Task bounds changed.
461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    private static final int BOUNDS_CHANGE_POSITION = 1;
4758d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes    // Return value from {@link setBounds} indicating the size of the Task bounds changed.
481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    private static final int BOUNDS_CHANGE_SIZE = 1 << 1;
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
5058d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes    // TODO: Track parent marks like this in WindowContainer.
511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    TaskStack mStack;
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    final int mTaskId;
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    final int mUserId;
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    private boolean mDeferRemoval = false;
551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    final WindowManagerService mService;
5658d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes
571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // Content limits relative to the DisplayContent this sits in.
581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    private Rect mBounds = new Rect();
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    final Rect mPreparedFrozenBounds = new Rect();
601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    final Configuration mPreparedFrozenMergedConfig = new Configuration();
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // Bounds used to calculate the insets.
63e734769276045c0cb89d4620fdd4ef35a0e6c335André Goddard Rosa    private final Rect mTempInsetBounds = new Rect();
64e734769276045c0cb89d4620fdd4ef35a0e6c335André Goddard Rosa
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // Device rotation as of the last time {@link #mBounds} was set.
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    private int mRotation;
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // Whether mBounds is fullscreen
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    private boolean mFillsParent = true;
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // For comparison with DisplayContent bounds.
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    private Rect mTmpRect = new Rect();
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    // For handling display rotations.
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    private Rect mTmpRect2 = new Rect();
7558d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes
7658d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes    // Resize mode of the task. See {@link ActivityInfo#resizeMode}
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    private int mResizeMode;
7858d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes
7958d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes    // Whether the task is currently being drag-resized
8058d9e280d459225aa8dc4533e883182b08215f7dElliott Hughes    private boolean mDragResizing;
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    private int mDragResizeMode;
82
83    private boolean mHomeTask;
84
85    // Whether this task is an on-top launcher task, which is determined by the root activity.
86    private boolean mIsOnTopLauncher;
87
88    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
89            Configuration overrideConfig, boolean isOnTopLauncher) {
90        mTaskId = taskId;
91        mStack = stack;
92        mUserId = userId;
93        mService = service;
94        mIsOnTopLauncher = isOnTopLauncher;
95        setBounds(bounds, overrideConfig);
96    }
97
98    DisplayContent getDisplayContent() {
99        return mStack.getDisplayContent();
100    }
101
102    void addAppToken(int addPos, AppWindowToken wtoken, int resizeMode, boolean homeTask) {
103        final int lastPos = mChildren.size();
104        if (addPos >= lastPos) {
105            addPos = lastPos;
106        } else {
107            for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {
108                if (mChildren.get(pos).removed) {
109                    // addPos assumes removed tokens are actually gone.
110                    ++addPos;
111                }
112            }
113        }
114
115        final WindowContainer parent = wtoken.getParent();
116        if (parent != null) {
117            parent.removeChild(wtoken);
118        }
119        addChild(wtoken, addPos);
120        wtoken.mTask = this;
121        mDeferRemoval = false;
122        mResizeMode = resizeMode;
123        mHomeTask = homeTask;
124    }
125
126    private boolean hasWindowsAlive() {
127        for (int i = mChildren.size() - 1; i >= 0; i--) {
128            if (mChildren.get(i).hasWindowsAlive()) {
129                return true;
130            }
131        }
132        return false;
133    }
134
135    @Override
136    void removeIfPossible() {
137        if (hasWindowsAlive() && mStack.isAnimating()) {
138            if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
139            mDeferRemoval = true;
140            return;
141        }
142        if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
143        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
144        mDeferRemoval = false;
145        DisplayContent content = getDisplayContent();
146        if (content != null) {
147            content.mDimLayerController.removeDimLayerUser(this);
148        }
149        getParent().removeChild(this);
150        mService.mTaskIdToTask.delete(mTaskId);
151    }
152
153    // Change to use reparenting in WC when TaskStack is switched to use WC.
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        getParent().removeChild(this);
162        stack.addTask(this, toTop);
163    }
164
165    void positionTaskInStack(TaskStack stack, int position, Rect bounds,
166            Configuration overrideConfig) {
167        if (mStack != null && stack != mStack) {
168            if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
169                    + " from stack=" + mStack);
170            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "moveTask");
171            mStack.removeChild(this);
172        }
173        stack.positionTask(this, position, showForAllUsers());
174        resizeLocked(bounds, overrideConfig, false /* force */);
175
176        for (int activityNdx = mChildren.size() - 1; activityNdx >= 0; --activityNdx) {
177            mChildren.get(activityNdx).notifyMovedInStack();
178        }
179    }
180
181    @Override
182    void removeChild(AppWindowToken token) {
183        if (!mChildren.contains(token)) {
184            Slog.e(TAG, "removeChild: token=" + this + " not found.");
185            return;
186        }
187
188        super.removeChild(token);
189
190        if (mChildren.isEmpty()) {
191            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
192            if (mDeferRemoval) {
193                removeIfPossible();
194            }
195        }
196        token.mTask = null;
197    }
198
199    void setSendingToBottom(boolean toBottom) {
200        for (int appTokenNdx = 0; appTokenNdx < mChildren.size(); appTokenNdx++) {
201            mChildren.get(appTokenNdx).sendingToBottom = toBottom;
202        }
203    }
204
205    /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
206    private int setBounds(Rect bounds, Configuration overrideConfig) {
207        if (overrideConfig == null) {
208            overrideConfig = Configuration.EMPTY;
209        }
210        if (bounds == null && !Configuration.EMPTY.equals(overrideConfig)) {
211            throw new IllegalArgumentException("null bounds but non empty configuration: "
212                    + overrideConfig);
213        }
214        if (bounds != null && Configuration.EMPTY.equals(overrideConfig)) {
215            throw new IllegalArgumentException("non null bounds, but empty configuration");
216        }
217        boolean oldFullscreen = mFillsParent;
218        int rotation = Surface.ROTATION_0;
219        final DisplayContent displayContent = mStack.getDisplayContent();
220        if (displayContent != null) {
221            displayContent.getLogicalDisplayRect(mTmpRect);
222            rotation = displayContent.getDisplayInfo().rotation;
223            mFillsParent = bounds == null;
224            if (mFillsParent) {
225                bounds = mTmpRect;
226            }
227        }
228
229        if (bounds == null) {
230            // Can't set to fullscreen if we don't have a display to get bounds from...
231            return BOUNDS_CHANGE_NONE;
232        }
233        if (mBounds.equals(bounds) && oldFullscreen == mFillsParent && mRotation == rotation) {
234            return BOUNDS_CHANGE_NONE;
235        }
236
237        int boundsChange = BOUNDS_CHANGE_NONE;
238        if (mBounds.left != bounds.left || mBounds.top != bounds.top) {
239            boundsChange |= BOUNDS_CHANGE_POSITION;
240        }
241        if (mBounds.width() != bounds.width() || mBounds.height() != bounds.height()) {
242            boundsChange |= BOUNDS_CHANGE_SIZE;
243        }
244
245        mBounds.set(bounds);
246
247        mRotation = rotation;
248        if (displayContent != null) {
249            displayContent.mDimLayerController.updateDimLayer(this);
250        }
251        onOverrideConfigurationChanged(mFillsParent ? Configuration.EMPTY : overrideConfig);
252        return boundsChange;
253    }
254
255    /**
256     * Sets the bounds used to calculate the insets. See
257     * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
258     */
259    void setTempInsetBounds(Rect tempInsetBounds) {
260        if (tempInsetBounds != null) {
261            mTempInsetBounds.set(tempInsetBounds);
262        } else {
263            mTempInsetBounds.setEmpty();
264        }
265    }
266
267    /**
268     * Gets the bounds used to calculate the insets. See
269     * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
270     */
271    void getTempInsetBounds(Rect out) {
272        out.set(mTempInsetBounds);
273    }
274
275    void setResizeable(int resizeMode) {
276        mResizeMode = resizeMode;
277    }
278
279    boolean isResizeable() {
280        return ActivityInfo.isResizeableMode(mResizeMode) || mService.mForceResizableTasks;
281    }
282
283    boolean isOnTopLauncher() {
284        return mIsOnTopLauncher;
285    }
286
287    boolean cropWindowsToStackBounds() {
288        return isResizeable();
289    }
290
291    boolean isHomeTask() {
292        return mHomeTask;
293    }
294
295    boolean resizeLocked(Rect bounds, Configuration overrideConfig, boolean forced) {
296        int boundsChanged = setBounds(bounds, overrideConfig);
297        if (forced) {
298            boundsChanged |= BOUNDS_CHANGE_SIZE;
299        }
300        if (boundsChanged == BOUNDS_CHANGE_NONE) {
301            return false;
302        }
303        if ((boundsChanged & BOUNDS_CHANGE_SIZE) == BOUNDS_CHANGE_SIZE) {
304            onResize();
305        } else {
306            onMovedByResize();
307        }
308        return true;
309    }
310
311    /**
312     * Prepares the task bounds to be frozen with the current size. See
313     * {@link AppWindowToken#freezeBounds}.
314     */
315    void prepareFreezingBounds() {
316        mPreparedFrozenBounds.set(mBounds);
317        mPreparedFrozenMergedConfig.setTo(getConfiguration());
318    }
319
320    /**
321     * Align the task to the adjusted bounds.
322     *
323     * @param adjustedBounds Adjusted bounds to which the task should be aligned.
324     * @param tempInsetBounds Insets bounds for the task.
325     * @param alignBottom True if the task's bottom should be aligned to the adjusted
326     *                    bounds's bottom; false if the task's top should be aligned
327     *                    the adjusted bounds's top.
328     */
329    void alignToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds, boolean alignBottom) {
330        // Task override config might be empty, while display or stack override config isn't, so
331        // we have to check merged override config here.
332        if (!isResizeable() || Configuration.EMPTY.equals(getMergedOverrideConfiguration())) {
333            return;
334        }
335
336        getBounds(mTmpRect2);
337        if (alignBottom) {
338            int offsetY = adjustedBounds.bottom - mTmpRect2.bottom;
339            mTmpRect2.offset(0, offsetY);
340        } else {
341            mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
342        }
343        setTempInsetBounds(tempInsetBounds);
344        resizeLocked(mTmpRect2, getOverrideConfiguration(), false /* forced */);
345    }
346
347    /** Return true if the current bound can get outputted to the rest of the system as-is. */
348    private boolean useCurrentBounds() {
349        final DisplayContent displayContent = mStack.getDisplayContent();
350        return mFillsParent
351                || !StackId.isTaskResizeableByDockedStack(mStack.mStackId)
352                || displayContent == null
353                || displayContent.getDockedStackVisibleForUserLocked() != null;
354    }
355
356    /** Original bounds of the task if applicable, otherwise fullscreen rect. */
357    void getBounds(Rect out) {
358        if (useCurrentBounds()) {
359            // No need to adjust the output bounds if fullscreen or the docked stack is visible
360            // since it is already what we want to represent to the rest of the system.
361            out.set(mBounds);
362            return;
363        }
364
365        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
366        // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
367        mStack.getDisplayContent().getLogicalDisplayRect(out);
368    }
369
370    /**
371     * Calculate the maximum visible area of this task. If the task has only one app,
372     * the result will be visible frame of that app. If the task has more than one apps,
373     * we search from top down if the next app got different visible area.
374     *
375     * This effort is to handle the case where some task (eg. GMail composer) might pop up
376     * a dialog that's different in size from the activity below, in which case we should
377     * be dimming the entire task area behind the dialog.
378     *
379     * @param out Rect containing the max visible bounds.
380     * @return true if the task has some visible app windows; false otherwise.
381     */
382    boolean getMaxVisibleBounds(Rect out) {
383        boolean foundTop = false;
384        for (int i = mChildren.size() - 1; i >= 0; i--) {
385            final AppWindowToken token = mChildren.get(i);
386            // skip hidden (or about to hide) apps
387            if (token.mIsExiting || token.clientHidden || token.hiddenRequested) {
388                continue;
389            }
390            final WindowState win = token.findMainWindow();
391            if (win == null) {
392                continue;
393            }
394            if (!foundTop) {
395                out.set(win.mVisibleFrame);
396                foundTop = true;
397                continue;
398            }
399            if (win.mVisibleFrame.left < out.left) {
400                out.left = win.mVisibleFrame.left;
401            }
402            if (win.mVisibleFrame.top < out.top) {
403                out.top = win.mVisibleFrame.top;
404            }
405            if (win.mVisibleFrame.right > out.right) {
406                out.right = win.mVisibleFrame.right;
407            }
408            if (win.mVisibleFrame.bottom > out.bottom) {
409                out.bottom = win.mVisibleFrame.bottom;
410            }
411        }
412        return foundTop;
413    }
414
415    /** Bounds of the task to be used for dimming, as well as touch related tests. */
416    @Override
417    public void getDimBounds(Rect out) {
418        final DisplayContent displayContent = mStack.getDisplayContent();
419        // It doesn't matter if we in particular are part of the resize, since we couldn't have
420        // a DimLayer anyway if we weren't visible.
421        final boolean dockedResizing = displayContent != null
422                && displayContent.mDividerControllerLocked.isResizing();
423        if (useCurrentBounds()) {
424            if (inFreeformWorkspace() && getMaxVisibleBounds(out)) {
425                return;
426            }
427
428            if (!mFillsParent) {
429                // When minimizing the docked stack when going home, we don't adjust the task bounds
430                // so we need to intersect the task bounds with the stack bounds here.
431                //
432                // If we are Docked Resizing with snap points, the task bounds could be smaller than the stack
433                // bounds and so we don't even want to use them. Even if the app should not be resized the Dim
434                // should keep up with the divider.
435                if (dockedResizing) {
436                    mStack.getBounds(out);
437                } else {
438                    mStack.getBounds(mTmpRect);
439                    mTmpRect.intersect(mBounds);
440                }
441                out.set(mTmpRect);
442            } else {
443                out.set(mBounds);
444            }
445            return;
446        }
447
448        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack is
449        // not currently visible. Go ahead a represent it as fullscreen to the rest of the system.
450        if (displayContent != null) {
451            displayContent.getLogicalDisplayRect(out);
452        }
453    }
454
455    void setDragResizing(boolean dragResizing, int dragResizeMode) {
456        if (mDragResizing != dragResizing) {
457            if (!DragResizeMode.isModeAllowedForStack(mStack.mStackId, dragResizeMode)) {
458                throw new IllegalArgumentException("Drag resize mode not allow for stack stackId="
459                        + mStack.mStackId + " dragResizeMode=" + dragResizeMode);
460            }
461            mDragResizing = dragResizing;
462            mDragResizeMode = dragResizeMode;
463            resetDragResizingChangeReported();
464        }
465    }
466
467    boolean isDragResizing() {
468        return mDragResizing;
469    }
470
471    int getDragResizeMode() {
472        return mDragResizeMode;
473    }
474
475    void updateDisplayInfo(final DisplayContent displayContent) {
476        if (displayContent == null) {
477            return;
478        }
479        if (mFillsParent) {
480            setBounds(null, Configuration.EMPTY);
481            return;
482        }
483        final int newRotation = displayContent.getDisplayInfo().rotation;
484        if (mRotation == newRotation) {
485            return;
486        }
487
488        // Device rotation changed.
489        // - We don't want the task to move around on the screen when this happens, so update the
490        //   task bounds so it stays in the same place.
491        // - Rotate the bounds and notify activity manager if the task can be resized independently
492        //   from its stack. The stack will take care of task rotation for the other case.
493        mTmpRect2.set(mBounds);
494
495        if (!StackId.isTaskResizeAllowed(mStack.mStackId)) {
496            setBounds(mTmpRect2, getOverrideConfiguration());
497            return;
498        }
499
500        displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
501        if (setBounds(mTmpRect2, getOverrideConfiguration()) != BOUNDS_CHANGE_NONE) {
502            // Post message to inform activity manager of the bounds change simulating a one-way
503            // call. We do this to prevent a deadlock between window manager lock and activity
504            // manager lock been held.
505            mService.mH.obtainMessage(RESIZE_TASK, mTaskId,
506                    RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds).sendToTarget();
507        }
508    }
509
510    /** Cancels any running app transitions associated with the task. */
511    void cancelTaskWindowTransition() {
512        for (int i = mChildren.size() - 1; i >= 0; --i) {
513            mChildren.get(i).mAppAnimator.clearAnimation();
514        }
515    }
516
517    /** Cancels any running thumbnail transitions associated with the task. */
518    void cancelTaskThumbnailTransition() {
519        for (int i = mChildren.size() - 1; i >= 0; --i) {
520            mChildren.get(i).mAppAnimator.clearThumbnail();
521        }
522    }
523
524    boolean showForAllUsers() {
525        final int tokensCount = mChildren.size();
526        return (tokensCount != 0) && mChildren.get(tokensCount - 1).showForAllUsers;
527    }
528
529    boolean inHomeStack() {
530        return mStack != null && mStack.mStackId == HOME_STACK_ID;
531    }
532
533    boolean inFreeformWorkspace() {
534        return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
535    }
536
537    boolean inPinnedWorkspace() {
538        return mStack != null && mStack.mStackId == PINNED_STACK_ID;
539    }
540
541    boolean isFloating() {
542        return StackId.tasksAreFloating(mStack.mStackId);
543    }
544
545    WindowState getTopVisibleAppMainWindow() {
546        final AppWindowToken token = getTopVisibleAppToken();
547        return token != null ? token.findMainWindow() : null;
548    }
549
550    AppWindowToken getTopVisibleAppToken() {
551        for (int i = mChildren.size() - 1; i >= 0; i--) {
552            final AppWindowToken token = mChildren.get(i);
553            // skip hidden (or about to hide) apps
554            if (!token.mIsExiting && !token.clientHidden && !token.hiddenRequested) {
555                return token;
556            }
557        }
558        return null;
559    }
560
561    @Override
562    public boolean dimFullscreen() {
563        return isFullscreen();
564    }
565
566    boolean isFullscreen() {
567        if (useCurrentBounds()) {
568            return mFillsParent;
569        }
570        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
571        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
572        // system.
573        return true;
574    }
575
576    @Override
577    public DisplayInfo getDisplayInfo() {
578        return mStack.getDisplayContent().getDisplayInfo();
579    }
580
581    void forceWindowsScaleable(boolean force) {
582        mService.openSurfaceTransaction();
583        try {
584            for (int i = mChildren.size() - 1; i >= 0; i--) {
585                mChildren.get(i).forceWindowsScaleableInTransaction(force);
586            }
587        } finally {
588            mService.closeSurfaceTransaction();
589        }
590    }
591
592    void getWindowOnDisplayBeforeToken(DisplayContent dc, WindowToken token,
593            DisplayContent.GetWindowOnDisplaySearchResult result) {
594        for (int i = mChildren.size() - 1; i >= 0; --i) {
595            final AppWindowToken current = mChildren.get(i);
596            if (current == token) {
597                // We have reach the token we are interested in. End search.
598                result.reachedToken = true;
599                return;
600            }
601
602            // We haven't reached the token yet; if this token is not going to the bottom and
603            // has windows on this display, then it is a candidate for what we are looking for.
604            final WindowList tokenWindowList = dc.getTokenWindowsOnDisplay(current);
605            if (!current.sendingToBottom && tokenWindowList.size() > 0) {
606                result.foundWindow = tokenWindowList.get(0);
607            }
608        }
609    }
610
611    void getWindowOnDisplayAfterToken(DisplayContent dc, WindowToken token,
612            DisplayContent.GetWindowOnDisplaySearchResult result) {
613        for (int i = mChildren.size() - 1; i >= 0; --i) {
614            final AppWindowToken current = mChildren.get(i);
615            if (!result.reachedToken) {
616                if (current == token) {
617                    // We have reached the token we are interested in. Get whichever window occurs
618                    // after it that is on the same display.
619                    result.reachedToken = true;
620                }
621                continue;
622            }
623
624            final WindowList tokenWindowList = dc.getTokenWindowsOnDisplay(current);
625            if (tokenWindowList.size() > 0) {
626                result.foundWindow = tokenWindowList.get(tokenWindowList.size() - 1);
627                return;
628            }
629        }
630    }
631
632    @Override
633    boolean fillsParent() {
634        return mFillsParent || !StackId.isTaskResizeAllowed(mStack.mStackId);
635    }
636
637    @Override
638    public String toString() {
639        return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}";
640    }
641
642    String getName() {
643        return toShortString();
644    }
645
646    @Override
647    public String toShortString() {
648        return "Task=" + mTaskId;
649    }
650
651    public void dump(String prefix, PrintWriter pw) {
652        final String doublePrefix = prefix + "  ";
653
654        pw.println(prefix + "taskId=" + mTaskId);
655        pw.println(doublePrefix + "mFillsParent=" + mFillsParent);
656        pw.println(doublePrefix + "mBounds=" + mBounds.toShortString());
657        pw.println(doublePrefix + "mdr=" + mDeferRemoval);
658        pw.println(doublePrefix + "appTokens=" + mChildren);
659        pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString());
660
661        final String triplePrefix = doublePrefix + "  ";
662
663        for (int i = mChildren.size() - 1; i >= 0; i--) {
664            final AppWindowToken wtoken = mChildren.get(i);
665            pw.println(triplePrefix + "Activity #" + i + " " + wtoken);
666            wtoken.dump(pw, triplePrefix);
667        }
668
669    }
670}
671