TaskStack.java revision eb1cb927adf4b10296dfd9cdb975514d85a1116a
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.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
20import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
21import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
22import static android.content.res.Configuration.DENSITY_DPI_UNDEFINED;
23import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
24import static android.view.WindowManager.DOCKED_BOTTOM;
25import static android.view.WindowManager.DOCKED_INVALID;
26import static android.view.WindowManager.DOCKED_LEFT;
27import static android.view.WindowManager.DOCKED_RIGHT;
28import static android.view.WindowManager.DOCKED_TOP;
29import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
30import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_MOVEMENT;
31import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
32import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
33
34import android.app.ActivityManager.StackId;
35import android.content.res.Configuration;
36import android.graphics.Rect;
37import android.os.Debug;
38import android.os.RemoteException;
39import android.util.EventLog;
40import android.util.Slog;
41import android.util.SparseArray;
42import android.view.DisplayInfo;
43import android.view.Surface;
44import android.view.SurfaceControl;
45
46import com.android.internal.policy.DividerSnapAlgorithm;
47import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
48import com.android.internal.policy.DockedDividerUtils;
49import com.android.server.EventLogTags;
50
51import java.io.PrintWriter;
52import java.util.ArrayList;
53
54public class TaskStack implements DimLayer.DimLayerUser,
55        BoundsAnimationController.AnimateBoundsUser {
56    /** Minimum size of an adjusted stack bounds relative to original stack bounds. Used to
57     * restrict IME adjustment so that a min portion of top stack remains visible.*/
58    private static final float ADJUSTED_STACK_FRACTION_MIN = 0.3f;
59
60    /** Dimming amount for non-focused stack when stacks are IME-adjusted. */
61    private static final float IME_ADJUST_DIM_AMOUNT = 0.25f;
62
63    /** Unique identifier */
64    final int mStackId;
65
66    /** The service */
67    private final WindowManagerService mService;
68
69    /** The display this stack sits under. */
70    private DisplayContent mDisplayContent;
71
72    /** The Tasks that define this stack. Oldest Tasks are at the bottom. The ordering must match
73     * mTaskHistory in the ActivityStack with the same mStackId */
74    private final ArrayList<Task> mTasks = new ArrayList<>();
75
76    /** For comparison with DisplayContent bounds. */
77    private Rect mTmpRect = new Rect();
78    private Rect mTmpRect2 = new Rect();
79
80    /** Content limits relative to the DisplayContent this sits in. */
81    private Rect mBounds = new Rect();
82
83    /** Stack bounds adjusted to screen content area (taking into account IM windows, etc.) */
84    private final Rect mAdjustedBounds = new Rect();
85
86    /**
87     * Fully adjusted IME bounds. These are different from {@link #mAdjustedBounds} because they
88     * represent the state when the animation has ended.
89     */
90    private final Rect mFullyAdjustedImeBounds = new Rect();
91
92    /** Whether mBounds is fullscreen */
93    private boolean mFullscreen = true;
94
95    // Device rotation as of the last time {@link #mBounds} was set.
96    int mRotation;
97
98    /** Density as of last time {@link #mBounds} was set. */
99    int mDensity;
100
101    /** Support for non-zero {@link android.view.animation.Animation#getBackgroundColor()} */
102    DimLayer mAnimationBackgroundSurface;
103
104    /** The particular window with an Animation with non-zero background color. */
105    WindowStateAnimator mAnimationBackgroundAnimator;
106
107    /** Application tokens that are exiting, but still on screen for animations. */
108    final AppTokenList mExitingAppTokens = new AppTokenList();
109
110    /** Detach this stack from its display when animation completes. */
111    boolean mDeferDetach;
112
113    // Whether the stack and all its tasks is currently being drag-resized
114    private boolean mDragResizing;
115
116    private final Rect mTmpAdjustedBounds = new Rect();
117    private boolean mAdjustedForIme;
118    private boolean mImeGoingAway;
119    private WindowState mImeWin;
120    private float mMinimizeAmount;
121    private float mAdjustImeAmount;
122    private float mAdjustDividerAmount;
123    private final int mDockedStackMinimizeThickness;
124
125    // If this is true, we are in the bounds animating mode.
126    // The task will be down or upscaled to perfectly fit the
127    // region it would have been cropped to. We may also avoid
128    // certain logic we would otherwise apply while resizing,
129    // while resizing in the bounds animating mode.
130    private boolean mBoundsAnimating = false;
131    // By default, movement animations are applied to all
132    // window movement. If this is true, animations will not
133    // be applied within this stack. This is useful for example
134    // if the windows are moving as the result of a stack animation,
135    // in which case a second window animation would cause jitter.
136    private boolean mFreezeMovementAnimations = false;
137
138    // Temporary storage for the new bounds that should be used after the configuration change.
139    // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
140    private final Rect mBoundsAfterRotation = new Rect();
141
142    TaskStack(WindowManagerService service, int stackId) {
143        mService = service;
144        mStackId = stackId;
145        mDockedStackMinimizeThickness = service.mContext.getResources().getDimensionPixelSize(
146                com.android.internal.R.dimen.docked_stack_minimize_thickness);
147        EventLog.writeEvent(EventLogTags.WM_STACK_CREATED, stackId);
148    }
149
150    DisplayContent getDisplayContent() {
151        return mDisplayContent;
152    }
153
154    ArrayList<Task> getTasks() {
155        return mTasks;
156    }
157
158    /**
159     * Set the bounds of the stack and its containing tasks.
160     * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
161     * @param configs Configuration for individual tasks, keyed by task id.
162     * @param taskBounds Bounds for individual tasks, keyed by task id.
163     * @return True if the stack bounds was changed.
164     * */
165    boolean setBounds(
166            Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
167            SparseArray<Rect> taskTempInsetBounds) {
168        setBounds(stackBounds);
169
170        // Update bounds of containing tasks.
171        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
172            final Task task = mTasks.get(taskNdx);
173            Configuration config = configs.get(task.mTaskId);
174            if (config != null) {
175                Rect bounds = taskBounds.get(task.mTaskId);
176                if (task.isTwoFingerScrollMode()) {
177                    // This is a non-resizeable task that's docked (or side-by-side to the docked
178                    // stack). It might have been scrolled previously, and after the stack resizing,
179                    // it might no longer fully cover the stack area.
180                    // Save the old bounds and re-apply the scroll. This adjusts the bounds to
181                    // fit the new stack bounds.
182                    task.resizeLocked(bounds, config, false /* forced */);
183                    task.getBounds(mTmpRect);
184                    task.scrollLocked(mTmpRect);
185                } else {
186                    task.resizeLocked(bounds, config, false /* forced */);
187                    task.setTempInsetBounds(
188                            taskTempInsetBounds != null ? taskTempInsetBounds.get(task.mTaskId)
189                                    : null);
190                }
191            } else {
192                Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
193            }
194        }
195        return true;
196    }
197
198    void prepareFreezingTaskBounds() {
199        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
200            final Task task = mTasks.get(taskNdx);
201            task.prepareFreezingBounds();
202        }
203    }
204
205    boolean isFullscreenBounds(Rect bounds) {
206        if (mDisplayContent == null || bounds == null) {
207            return true;
208        }
209        mDisplayContent.getLogicalDisplayRect(mTmpRect);
210        return mTmpRect.equals(bounds);
211    }
212
213    /**
214     * Overrides the adjusted bounds, i.e. sets temporary layout bounds which are different from
215     * the normal task bounds.
216     *
217     * @param bounds The adjusted bounds.
218     */
219    private void setAdjustedBounds(Rect bounds) {
220        if (mAdjustedBounds.equals(bounds) && !isAnimatingForIme()) {
221            return;
222        }
223
224        mAdjustedBounds.set(bounds);
225        final boolean adjusted = !mAdjustedBounds.isEmpty();
226        Rect insetBounds = null;
227        if (adjusted && isAdjustedForMinimizedDock()) {
228            insetBounds = mBounds;
229        } else if (adjusted && isAdjustedForIme()) {
230            if (mImeGoingAway) {
231                insetBounds = mBounds;
232            } else {
233                insetBounds = mFullyAdjustedImeBounds;
234            }
235        }
236        alignTasksToAdjustedBounds(adjusted ? mAdjustedBounds : mBounds, insetBounds);
237        mDisplayContent.layoutNeeded = true;
238    }
239
240    private void alignTasksToAdjustedBounds(Rect adjustedBounds, Rect tempInsetBounds) {
241        if (mFullscreen) {
242            return;
243        }
244        // Update bounds of containing tasks.
245        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
246            final Task task = mTasks.get(taskNdx);
247            if (task.isTwoFingerScrollMode()) {
248                // If we're scrolling we don't care about your bounds or configs,
249                // they should be null as if we were in fullscreen.
250                task.resizeLocked(null, null, false /* forced */);
251                task.getBounds(mTmpRect2);
252                task.scrollLocked(mTmpRect2);
253            } else if (task.isResizeable() && task.mOverrideConfig != Configuration.EMPTY) {
254                task.getBounds(mTmpRect2);
255                if (mAdjustedForIme && getDockSide() == DOCKED_TOP) {
256                    int offsetY = adjustedBounds.bottom - mTmpRect2.bottom;
257                    mTmpRect2.offset(0, offsetY);
258                } else {
259                    mTmpRect2.offsetTo(adjustedBounds.left, adjustedBounds.top);
260                }
261                task.setTempInsetBounds(tempInsetBounds);
262                task.resizeLocked(mTmpRect2, task.mOverrideConfig, false /* forced */);
263            }
264        }
265    }
266
267    private boolean setBounds(Rect bounds) {
268        boolean oldFullscreen = mFullscreen;
269        int rotation = Surface.ROTATION_0;
270        int density = DENSITY_DPI_UNDEFINED;
271        if (mDisplayContent != null) {
272            mDisplayContent.getLogicalDisplayRect(mTmpRect);
273            rotation = mDisplayContent.getDisplayInfo().rotation;
274            density = mDisplayContent.getDisplayInfo().logicalDensityDpi;
275            mFullscreen = bounds == null;
276            if (mFullscreen) {
277                bounds = mTmpRect;
278            }
279        }
280
281        if (bounds == null) {
282            // Can't set to fullscreen if we don't have a display to get bounds from...
283            return false;
284        }
285        if (mBounds.equals(bounds) && oldFullscreen == mFullscreen && mRotation == rotation) {
286            return false;
287        }
288
289        if (mDisplayContent != null) {
290            mDisplayContent.mDimLayerController.updateDimLayer(this);
291            mAnimationBackgroundSurface.setBounds(bounds);
292        }
293
294        mBounds.set(bounds);
295        mRotation = rotation;
296        mDensity = density;
297
298        updateAdjustedBounds();
299
300        return true;
301    }
302
303    /** Bounds of the stack without adjusting for other factors in the system like visibility
304     * of docked stack.
305     * Most callers should be using {@link #getBounds} as it take into consideration other system
306     * factors. */
307    void getRawBounds(Rect out) {
308        out.set(mBounds);
309    }
310
311    /** Return true if the current bound can get outputted to the rest of the system as-is. */
312    private boolean useCurrentBounds() {
313        if (mFullscreen
314                || !StackId.isResizeableByDockedStack(mStackId)
315                || mDisplayContent == null
316                || mDisplayContent.getDockedStackLocked() != null) {
317            return true;
318        }
319        return false;
320    }
321
322    public void getBounds(Rect out) {
323        if (useCurrentBounds()) {
324            // If we're currently adjusting for IME or minimized docked stack, we use the adjusted
325            // bounds; otherwise, no need to adjust the output bounds if fullscreen or the docked
326            // stack is visible since it is already what we want to represent to the rest of the
327            // system.
328            if (!mAdjustedBounds.isEmpty()) {
329                out.set(mAdjustedBounds);
330            } else {
331                out.set(mBounds);
332            }
333            return;
334        }
335
336        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
337        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
338        // system.
339        mDisplayContent.getLogicalDisplayRect(out);
340    }
341
342    /** Bounds of the stack with other system factors taken into consideration. */
343    @Override
344    public void getDimBounds(Rect out) {
345        getBounds(out);
346    }
347
348    void updateDisplayInfo(Rect bounds) {
349        if (mDisplayContent == null) {
350            return;
351        }
352
353        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
354            mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
355        }
356        if (bounds != null) {
357            setBounds(bounds);
358            return;
359        } else if (mFullscreen) {
360            setBounds(null);
361            return;
362        }
363
364        mTmpRect2.set(mBounds);
365        final int newRotation = mDisplayContent.getDisplayInfo().rotation;
366        final int newDensity = mDisplayContent.getDisplayInfo().logicalDensityDpi;
367        if (mRotation == newRotation && mDensity == newDensity) {
368            setBounds(mTmpRect2);
369        }
370
371        // If the rotation or density didn't match, we'll update it in onConfigurationChanged.
372    }
373
374    boolean onConfigurationChanged() {
375        return updateBoundsAfterConfigChange();
376    }
377
378    private boolean updateBoundsAfterConfigChange() {
379        if (mFullscreen) {
380            // Bounds will already be set correctly when display info is updated in the case of
381            // fullscreen.
382            return false;
383        }
384
385        final int newRotation = getDisplayInfo().rotation;
386        final int newDensity = getDisplayInfo().logicalDensityDpi;
387
388        if (mRotation == newRotation && mDensity == newDensity) {
389            // Nothing to do here as we already update the state in updateDisplayInfo.
390            return false;
391        }
392
393        final int oldDockSide = mStackId == DOCKED_STACK_ID ? getDockSide() : DOCKED_INVALID;
394        mTmpRect2.set(mBounds);
395        mDisplayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
396        if (mStackId == DOCKED_STACK_ID) {
397            repositionDockedStackAfterRotation(mTmpRect2);
398            snapDockedStackAfterRotation(mTmpRect2);
399            final int newDockSide = getDockSide(mTmpRect2);
400            if (oldDockSide != newDockSide) {
401                mDisplayContent.getDockedDividerController().notifyDockSideChanged(newDockSide);
402            }
403        }
404
405        mBoundsAfterRotation.set(mTmpRect2);
406        return true;
407    }
408
409    void getBoundsForNewConfiguration(Rect outBounds) {
410        outBounds.set(mBoundsAfterRotation);
411        mBoundsAfterRotation.setEmpty();
412    }
413
414    /**
415     * Some dock sides are not allowed by the policy. This method queries the policy and moves
416     * the docked stack around if needed.
417     *
418     * @param inOutBounds the bounds of the docked stack to adjust
419     */
420    private void repositionDockedStackAfterRotation(Rect inOutBounds) {
421        int dockSide = getDockSide(inOutBounds);
422        if (mService.mPolicy.isDockSideAllowed(dockSide)) {
423            return;
424        }
425        mDisplayContent.getLogicalDisplayRect(mTmpRect);
426        dockSide = DockedDividerUtils.invertDockSide(dockSide);
427        switch (dockSide) {
428            case DOCKED_LEFT:
429                int movement = inOutBounds.left;
430                inOutBounds.left -= movement;
431                inOutBounds.right -= movement;
432                break;
433            case DOCKED_RIGHT:
434                movement = mTmpRect.right - inOutBounds.right;
435                inOutBounds.left += movement;
436                inOutBounds.right += movement;
437                break;
438            case DOCKED_TOP:
439                movement = inOutBounds.top;
440                inOutBounds.top -= movement;
441                inOutBounds.bottom -= movement;
442                break;
443            case DOCKED_BOTTOM:
444                movement = mTmpRect.bottom - inOutBounds.bottom;
445                inOutBounds.top += movement;
446                inOutBounds.bottom += movement;
447                break;
448        }
449    }
450
451    /**
452     * Snaps the bounds after rotation to the closest snap target for the docked stack.
453     */
454    private void snapDockedStackAfterRotation(Rect outBounds) {
455
456        // Calculate the current position.
457        final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
458        final int dividerSize = mService.getDefaultDisplayContentLocked()
459                .getDockedDividerController().getContentWidth();
460        final int dockSide = getDockSide(outBounds);
461        final int dividerPosition = DockedDividerUtils.calculatePositionForBounds(outBounds,
462                dockSide, dividerSize);
463        final int displayWidth = mDisplayContent.getDisplayInfo().logicalWidth;
464        final int displayHeight = mDisplayContent.getDisplayInfo().logicalHeight;
465
466        // Snap the position to a target.
467        final int rotation = displayInfo.rotation;
468        final int orientation = mService.mCurConfiguration.orientation;
469        mService.mPolicy.getStableInsetsLw(rotation, displayWidth, displayHeight, outBounds);
470        final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
471                mService.mContext.getResources(), displayWidth, displayHeight,
472                dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds);
473        final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
474
475        // Recalculate the bounds based on the position of the target.
476        DockedDividerUtils.calculateBoundsForPosition(target.position, dockSide,
477                outBounds, displayInfo.logicalWidth, displayInfo.logicalHeight,
478                dividerSize);
479    }
480
481    boolean isAnimating() {
482        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
483            final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
484            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
485                final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
486                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
487                    final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
488                    if (winAnimator.isAnimationSet() || winAnimator.mWin.mAnimatingExit) {
489                        return true;
490                    }
491                }
492            }
493        }
494        return false;
495    }
496
497    void addTask(Task task, boolean toTop) {
498        addTask(task, toTop, task.showForAllUsers());
499    }
500
501    /**
502     * Put a Task in this stack. Used for adding and moving.
503     * @param task The task to add.
504     * @param toTop Whether to add it to the top or bottom.
505     * @param showForAllUsers Whether to show the task regardless of the current user.
506     */
507    void addTask(Task task, boolean toTop, boolean showForAllUsers) {
508        positionTask(task, toTop ? mTasks.size() : 0, showForAllUsers);
509    }
510
511    void positionTask(Task task, int position, boolean showForAllUsers) {
512        final boolean canShowTask =
513                showForAllUsers || mService.isCurrentProfileLocked(task.mUserId);
514        mTasks.remove(task);
515        int stackSize = mTasks.size();
516        int minPosition = 0;
517        int maxPosition = stackSize;
518
519        if (canShowTask) {
520            minPosition = computeMinPosition(minPosition, stackSize);
521        } else {
522            maxPosition = computeMaxPosition(maxPosition);
523        }
524        // Reset position based on minimum/maximum possible positions.
525        position = Math.min(Math.max(position, minPosition), maxPosition);
526
527        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM,
528                "positionTask: task=" + task + " position=" + position);
529        mTasks.add(position, task);
530
531        // If we are moving the task across stacks, the scroll is no longer valid.
532        if (task.mStack != this) {
533            task.resetScrollLocked();
534        }
535        task.mStack = this;
536        task.updateDisplayInfo(mDisplayContent);
537        boolean toTop = position == mTasks.size() - 1;
538        if (toTop) {
539            mDisplayContent.moveStack(this, true);
540        }
541
542        if (StackId.windowsAreScaleable(mStackId)) {
543            // We force windows out of SCALING_MODE_FREEZE
544            // so that we can continue to animate them
545            // while a resize is pending.
546            forceWindowsScaleable(task, true);
547        } else {
548            forceWindowsScaleable(task, false);
549        }
550        EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, position);
551    }
552
553    /** Calculate the minimum possible position for a task that can be shown to the user.
554     *  The minimum position will be above all other tasks that can't be shown.
555     *  @param minPosition The minimum position the caller is suggesting.
556     *                  We will start adjusting up from here.
557     *  @param size The size of the current task list.
558     */
559    private int computeMinPosition(int minPosition, int size) {
560        while (minPosition < size) {
561            final Task tmpTask = mTasks.get(minPosition);
562            final boolean canShowTmpTask =
563                    tmpTask.showForAllUsers()
564                            || mService.isCurrentProfileLocked(tmpTask.mUserId);
565            if (canShowTmpTask) {
566                break;
567            }
568            minPosition++;
569        }
570        return minPosition;
571    }
572
573    /** Calculate the maximum possible position for a task that can't be shown to the user.
574     *  The maximum position will be below all other tasks that can be shown.
575     *  @param maxPosition The maximum position the caller is suggesting.
576     *                  We will start adjusting down from here.
577     */
578    private int computeMaxPosition(int maxPosition) {
579        while (maxPosition > 0) {
580            final Task tmpTask = mTasks.get(maxPosition - 1);
581            final boolean canShowTmpTask =
582                    tmpTask.showForAllUsers()
583                            || mService.isCurrentProfileLocked(tmpTask.mUserId);
584            if (!canShowTmpTask) {
585                break;
586            }
587            maxPosition--;
588        }
589        return maxPosition;
590    }
591
592    void moveTaskToTop(Task task) {
593        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToTop: task=" + task + " Callers="
594                + Debug.getCallers(6));
595        mTasks.remove(task);
596        addTask(task, true);
597    }
598
599    void moveTaskToBottom(Task task) {
600        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "moveTaskToBottom: task=" + task);
601        mTasks.remove(task);
602        addTask(task, false);
603    }
604
605    /**
606     * Delete a Task from this stack. If it is the last Task in the stack, move this stack to the
607     * back.
608     * @param task The Task to delete.
609     */
610    void removeTask(Task task) {
611        if (DEBUG_TASK_MOVEMENT) Slog.d(TAG_WM, "removeTask: task=" + task);
612        mTasks.remove(task);
613        if (mDisplayContent != null) {
614            if (mTasks.isEmpty()) {
615                mDisplayContent.moveStack(this, false);
616            }
617            mDisplayContent.layoutNeeded = true;
618        }
619        for (int appNdx = mExitingAppTokens.size() - 1; appNdx >= 0; --appNdx) {
620            final AppWindowToken wtoken = mExitingAppTokens.get(appNdx);
621            if (wtoken.mTask == task) {
622                wtoken.mIsExiting = false;
623                mExitingAppTokens.remove(appNdx);
624            }
625        }
626    }
627
628    void attachDisplayContent(DisplayContent displayContent) {
629        if (mDisplayContent != null) {
630            throw new IllegalStateException("attachDisplayContent: Already attached");
631        }
632
633        mDisplayContent = displayContent;
634        mAnimationBackgroundSurface = new DimLayer(mService, this, mDisplayContent.getDisplayId(),
635                "animation background stackId=" + mStackId);
636
637        Rect bounds = null;
638        final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
639        if (mStackId == DOCKED_STACK_ID
640                || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId)
641                        && !dockedStack.isFullscreen())) {
642            // The existence of a docked stack affects the size of other static stack created since
643            // the docked stack occupies a dedicated region on screen, but only if the dock stack is
644            // not fullscreen. If it's fullscreen, it means that we are in the transition of
645            // dismissing it, so we must not resize this stack.
646            bounds = new Rect();
647            displayContent.getLogicalDisplayRect(mTmpRect);
648            mTmpRect2.setEmpty();
649            if (dockedStack != null) {
650                dockedStack.getRawBounds(mTmpRect2);
651            }
652            final boolean dockedOnTopOrLeft = mService.mDockedStackCreateMode
653                    == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
654            getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2,
655                    mDisplayContent.mDividerControllerLocked.getContentWidth(),
656                    dockedOnTopOrLeft);
657        }
658
659        updateDisplayInfo(bounds);
660    }
661
662    void getStackDockedModeBoundsLocked(Rect outBounds, boolean ignoreVisibility) {
663        if ((mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId))
664                || mDisplayContent == null) {
665            outBounds.set(mBounds);
666            return;
667        }
668
669        final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
670        if (dockedStack == null) {
671            // Not sure why you are calling this method when there is no docked stack...
672            throw new IllegalStateException(
673                    "Calling getStackDockedModeBoundsLocked() when there is no docked stack.");
674        }
675        if (!ignoreVisibility && !dockedStack.isVisibleLocked()) {
676            // The docked stack is being dismissed, but we caught before it finished being
677            // dismissed. In that case we want to treat it as if it is not occupying any space and
678            // let others occupy the whole display.
679            mDisplayContent.getLogicalDisplayRect(outBounds);
680            return;
681        }
682
683        final int dockedSide = dockedStack.getDockSide();
684        if (dockedSide == DOCKED_INVALID) {
685            // Not sure how you got here...Only thing we can do is return current bounds.
686            Slog.e(TAG_WM, "Failed to get valid docked side for docked stack=" + dockedStack);
687            outBounds.set(mBounds);
688            return;
689        }
690
691        mDisplayContent.getLogicalDisplayRect(mTmpRect);
692        dockedStack.getRawBounds(mTmpRect2);
693        final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
694        getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2,
695                mDisplayContent.mDividerControllerLocked.getContentWidth(), dockedOnTopOrLeft);
696
697    }
698
699    /**
700     * Outputs the bounds a stack should be given the presence of a docked stack on the display.
701     * @param displayRect The bounds of the display the docked stack is on.
702     * @param outBounds Output bounds that should be used for the stack.
703     * @param stackId Id of stack we are calculating the bounds for.
704     * @param dockedBounds Bounds of the docked stack.
705     * @param dockDividerWidth We need to know the width of the divider make to the output bounds
706     *                         close to the side of the dock.
707     * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen.
708     */
709    private void getStackDockedModeBounds(
710            Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth,
711            boolean dockOnTopOrLeft) {
712        final boolean dockedStack = stackId == DOCKED_STACK_ID;
713        final boolean splitHorizontally = displayRect.width() > displayRect.height();
714
715        outBounds.set(displayRect);
716        if (dockedStack) {
717            if (mService.mDockedStackCreateBounds != null) {
718                outBounds.set(mService.mDockedStackCreateBounds);
719                return;
720            }
721
722            // The initial bounds of the docked stack when it is created about half the screen space
723            // and its bounds can be adjusted after that. The bounds of all other stacks are
724            // adjusted to occupy whatever screen space the docked stack isn't occupying.
725            final DisplayInfo di = mDisplayContent.getDisplayInfo();
726            mService.mPolicy.getStableInsetsLw(di.rotation, di.logicalWidth, di.logicalHeight,
727                    mTmpRect2);
728            final int position = new DividerSnapAlgorithm(mService.mContext.getResources(),
729                    di.logicalWidth,
730                    di.logicalHeight,
731                    dockDividerWidth,
732                    mService.mCurConfiguration.orientation == ORIENTATION_PORTRAIT,
733                    mTmpRect2).getMiddleTarget().position;
734
735            if (dockOnTopOrLeft) {
736                if (splitHorizontally) {
737                    outBounds.right = position;
738                } else {
739                    outBounds.bottom = position;
740                }
741            } else {
742                if (splitHorizontally) {
743                    outBounds.left = position + dockDividerWidth;
744                } else {
745                    outBounds.top = position + dockDividerWidth;
746                }
747            }
748            return;
749        }
750
751        // Other stacks occupy whatever space is left by the docked stack.
752        if (!dockOnTopOrLeft) {
753            if (splitHorizontally) {
754                outBounds.right = dockedBounds.left - dockDividerWidth;
755            } else {
756                outBounds.bottom = dockedBounds.top - dockDividerWidth;
757            }
758        } else {
759            if (splitHorizontally) {
760                outBounds.left = dockedBounds.right + dockDividerWidth;
761            } else {
762                outBounds.top = dockedBounds.bottom + dockDividerWidth;
763            }
764        }
765        DockedDividerUtils.sanitizeStackBounds(outBounds, !dockOnTopOrLeft);
766    }
767
768    void resetDockedStackToMiddle() {
769        if (mStackId != DOCKED_STACK_ID) {
770            throw new IllegalStateException("Not a docked stack=" + this);
771        }
772
773        mService.mDockedStackCreateBounds = null;
774
775        final Rect bounds = new Rect();
776        getStackDockedModeBoundsLocked(bounds, true /*ignoreVisibility*/);
777        mService.mH.obtainMessage(RESIZE_STACK, DOCKED_STACK_ID,
778                1 /*allowResizeInDockedMode*/, bounds).sendToTarget();
779    }
780
781    void detachDisplay() {
782        EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
783
784        boolean doAnotherLayoutPass = false;
785        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
786            final AppTokenList appWindowTokens = mTasks.get(taskNdx).mAppTokens;
787            for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
788                final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
789                for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
790                    // We are in the middle of changing the state of displays/stacks/tasks. We need
791                    // to finish that, before we let layout interfere with it.
792                    mService.removeWindowLocked(appWindows.get(winNdx));
793                    doAnotherLayoutPass = true;
794                }
795            }
796        }
797        if (doAnotherLayoutPass) {
798            mService.mWindowPlacerLocked.requestTraversal();
799        }
800
801        close();
802    }
803
804    void resetAnimationBackgroundAnimator() {
805        mAnimationBackgroundAnimator = null;
806        mAnimationBackgroundSurface.hide();
807    }
808
809    void setAnimationBackground(WindowStateAnimator winAnimator, int color) {
810        int animLayer = winAnimator.mAnimLayer;
811        if (mAnimationBackgroundAnimator == null
812                || animLayer < mAnimationBackgroundAnimator.mAnimLayer) {
813            mAnimationBackgroundAnimator = winAnimator;
814            animLayer = mService.adjustAnimationBackground(winAnimator);
815            mAnimationBackgroundSurface.show(animLayer - WindowManagerService.LAYER_OFFSET_DIM,
816                    ((color >> 24) & 0xff) / 255f, 0);
817        }
818    }
819
820    void switchUser() {
821        int top = mTasks.size();
822        for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
823            Task task = mTasks.get(taskNdx);
824            if (mService.isCurrentProfileLocked(task.mUserId) || task.showForAllUsers()) {
825                mTasks.remove(taskNdx);
826                mTasks.add(task);
827                --top;
828            }
829        }
830    }
831
832    void close() {
833        if (mAnimationBackgroundSurface != null) {
834            mAnimationBackgroundSurface.destroySurface();
835            mAnimationBackgroundSurface = null;
836        }
837        mDisplayContent = null;
838    }
839
840    /**
841     * Adjusts the stack bounds if the IME is visible.
842     *
843     * @param imeWin The IME window.
844     */
845    void setAdjustedForIme(WindowState imeWin) {
846        mImeWin = imeWin;
847        mImeGoingAway = false;
848        if (!mAdjustedForIme) {
849            mAdjustedForIme = true;
850            mAdjustImeAmount = 0f;
851            mAdjustDividerAmount = 0f;
852            updateAdjustForIme(0f, 0f, true /* force */);
853        }
854    }
855
856    boolean isAdjustedForIme() {
857        return mAdjustedForIme || mImeGoingAway;
858    }
859
860    boolean isAnimatingForIme() {
861        return mImeWin != null && mImeWin.isAnimatingLw();
862    }
863
864    /**
865     * Update the stack's bounds (crop or position) according to the IME window's
866     * current position. When IME window is animated, the bottom stack is animated
867     * together to track the IME window's current position, and the top stack is
868     * cropped as necessary.
869     *
870     * @return true if a traversal should be performed after the adjustment.
871     */
872    boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) {
873        if (adjustAmount != mAdjustImeAmount
874                || adjustDividerAmount != mAdjustDividerAmount || force) {
875            mAdjustImeAmount = adjustAmount;
876            mAdjustDividerAmount = adjustDividerAmount;
877            updateAdjustedBounds();
878            return isVisibleForUserLocked();
879        } else {
880            return false;
881        }
882    }
883
884    /**
885     * Resets the adjustment after it got adjusted for the IME.
886     * @param adjustBoundsNow if true, reset and update the bounds immediately and forget about
887     *                        animations; otherwise, set flag and animates the window away together
888     *                        with IME window.
889     */
890    void resetAdjustedForIme(boolean adjustBoundsNow) {
891        if (adjustBoundsNow) {
892            mImeWin = null;
893            mAdjustedForIme = false;
894            mImeGoingAway = false;
895            mAdjustImeAmount = 0f;
896            mAdjustDividerAmount = 0f;
897            updateAdjustedBounds();
898            mService.setResizeDimLayer(false, mStackId, 1.0f);
899        } else {
900            mImeGoingAway |= mAdjustedForIme;
901        }
902    }
903
904    /**
905     * Sets the amount how much we currently minimize our stack.
906     *
907     * @param minimizeAmount The amount, between 0 and 1.
908     * @return Whether the amount has changed and a layout is needed.
909     */
910    boolean setAdjustedForMinimizedDock(float minimizeAmount) {
911        if (minimizeAmount != mMinimizeAmount) {
912            mMinimizeAmount = minimizeAmount;
913            updateAdjustedBounds();
914            return isVisibleForUserLocked();
915        } else {
916            return false;
917        }
918    }
919
920    boolean isAdjustedForMinimizedDock() {
921        return mMinimizeAmount != 0f;
922    }
923
924    /**
925     * Puts all visible tasks that are adjusted for IME into resizing mode and adds the windows
926     * to the list of to be drawn windows the service is waiting for.
927     */
928    void beginImeAdjustAnimation() {
929        for (int j = mTasks.size() - 1; j >= 0; j--) {
930            final Task task = mTasks.get(j);
931            if (task.isVisibleForUser()) {
932                task.setDragResizing(true, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
933                task.addWindowsWaitingForDrawnIfResizingChanged();
934            }
935        }
936    }
937
938    /**
939     * Resets the resizing state of all windows.
940     */
941    void endImeAdjustAnimation() {
942        for (int j = mTasks.size() - 1; j >= 0; j--) {
943            mTasks.get(j).setDragResizing(false, DRAG_RESIZE_MODE_DOCKED_DIVIDER);
944        }
945    }
946
947    int getMinTopStackBottom(final Rect displayContentRect, int originalStackBottom) {
948        return displayContentRect.top + (int)
949                ((originalStackBottom - displayContentRect.top) * ADJUSTED_STACK_FRACTION_MIN);
950    }
951
952    private boolean adjustForIME(final WindowState imeWin) {
953        final int dockedSide = getDockSide();
954        final boolean dockedTopOrBottom = dockedSide == DOCKED_TOP || dockedSide == DOCKED_BOTTOM;
955        if (imeWin == null || !dockedTopOrBottom) {
956            return false;
957        }
958
959        final Rect displayContentRect = mTmpRect;
960        final Rect contentBounds = mTmpRect2;
961
962        // Calculate the content bounds excluding the area occupied by IME
963        getDisplayContent().getContentRect(displayContentRect);
964        contentBounds.set(displayContentRect);
965        int imeTop = Math.max(imeWin.getFrameLw().top, contentBounds.top);
966
967        imeTop += imeWin.getGivenContentInsetsLw().top;
968        if (contentBounds.bottom > imeTop) {
969            contentBounds.bottom = imeTop;
970        }
971
972        final int yOffset = displayContentRect.bottom - contentBounds.bottom;
973
974        final int dividerWidth =
975                getDisplayContent().mDividerControllerLocked.getContentWidth();
976        final int dividerWidthInactive =
977                getDisplayContent().mDividerControllerLocked.getContentWidthInactive();
978
979        if (dockedSide == DOCKED_TOP) {
980            // If this stack is docked on top, we make it smaller so the bottom stack is not
981            // occluded by IME. We shift its bottom up by the height of the IME, but
982            // leaves at least 30% of the top stack visible.
983            final int minTopStackBottom =
984                    getMinTopStackBottom(displayContentRect, mBounds.bottom);
985            final int bottom = Math.max(
986                    mBounds.bottom - yOffset + dividerWidth - dividerWidthInactive,
987                    minTopStackBottom);
988            mTmpAdjustedBounds.set(mBounds);
989            mTmpAdjustedBounds.bottom =
990                    (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom);
991            mFullyAdjustedImeBounds.set(mBounds);
992        } else {
993            // When the stack is on bottom and has no focus, it's only adjusted for divider width.
994            final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
995
996            // When the stack is on bottom and has focus, it needs to be moved up so as to
997            // not occluded by IME, and at the same time adjusted for divider width.
998            // We try to move it up by the height of the IME window, but only to the extent
999            // that leaves at least 30% of the top stack visible.
1000            // 'top' is where the top of bottom stack will move to in this case.
1001            final int topBeforeImeAdjust = mBounds.top - dividerWidth + dividerWidthInactive;
1002            final int minTopStackBottom =
1003                    getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
1004            final int top = Math.max(
1005                    mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
1006
1007            mTmpAdjustedBounds.set(mBounds);
1008            // Account for the adjustment for IME and divider width separately.
1009            // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
1010            // and dividerWidthDelta is due to divider width change only.
1011            mTmpAdjustedBounds.top = mBounds.top +
1012                    (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) +
1013                            mAdjustDividerAmount * dividerWidthDelta);
1014            mFullyAdjustedImeBounds.set(mBounds);
1015            mFullyAdjustedImeBounds.top = top;
1016            mFullyAdjustedImeBounds.bottom = top + mBounds.height();
1017        }
1018        return true;
1019    }
1020
1021    private boolean adjustForMinimizedDockedStack(float minimizeAmount) {
1022        final int dockSide = getDockSide();
1023        if (dockSide == DOCKED_INVALID && !mTmpAdjustedBounds.isEmpty()) {
1024            return false;
1025        }
1026
1027        if (dockSide == DOCKED_TOP) {
1028            mService.getStableInsetsLocked(mTmpRect);
1029            int topInset = mTmpRect.top;
1030            mTmpAdjustedBounds.set(mBounds);
1031            mTmpAdjustedBounds.bottom =
1032                    (int) (minimizeAmount * topInset + (1 - minimizeAmount) * mBounds.bottom);
1033        } else if (dockSide == DOCKED_LEFT) {
1034            mTmpAdjustedBounds.set(mBounds);
1035            final int width = mBounds.width();
1036            mTmpAdjustedBounds.right =
1037                    (int) (minimizeAmount * mDockedStackMinimizeThickness
1038                            + (1 - minimizeAmount) * mBounds.right);
1039            mTmpAdjustedBounds.left = mTmpAdjustedBounds.right - width;
1040        } else if (dockSide == DOCKED_RIGHT) {
1041            mTmpAdjustedBounds.set(mBounds);
1042            mTmpAdjustedBounds.left =
1043                    (int) (minimizeAmount * (mBounds.right - mDockedStackMinimizeThickness)
1044                            + (1 - minimizeAmount) * mBounds.left);
1045        }
1046        return true;
1047    }
1048
1049    /**
1050     * @return the distance in pixels how much the stack gets minimized from it's original size
1051     */
1052    int getMinimizeDistance() {
1053        final int dockSide = getDockSide();
1054        if (dockSide == DOCKED_INVALID) {
1055            return 0;
1056        }
1057
1058        if (dockSide == DOCKED_TOP) {
1059            mService.getStableInsetsLocked(mTmpRect);
1060            int topInset = mTmpRect.top;
1061            return mBounds.bottom - topInset;
1062        } else if (dockSide == DOCKED_LEFT || dockSide == DOCKED_RIGHT) {
1063            return mBounds.width() - mDockedStackMinimizeThickness;
1064        } else {
1065            return 0;
1066        }
1067    }
1068
1069    /**
1070     * Updates the adjustment depending on it's current state.
1071     */
1072    void updateAdjustedBounds() {
1073        boolean adjust = false;
1074        if (mMinimizeAmount != 0f) {
1075            adjust = adjustForMinimizedDockedStack(mMinimizeAmount);
1076        } else if (mAdjustedForIme) {
1077            adjust = adjustForIME(mImeWin);
1078        }
1079        if (!adjust) {
1080            mTmpAdjustedBounds.setEmpty();
1081        }
1082        setAdjustedBounds(mTmpAdjustedBounds);
1083
1084        final boolean isImeTarget = (mService.getImeTargetStackLocked() == this);
1085        if (mAdjustedForIme && adjust && !isImeTarget) {
1086            final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
1087                    * IME_ADJUST_DIM_AMOUNT;
1088            mService.setResizeDimLayer(true, mStackId, alpha);
1089        }
1090    }
1091
1092    boolean isAdjustedForMinimizedDockedStack() {
1093        return mMinimizeAmount != 0f;
1094    }
1095
1096    public void dump(String prefix, PrintWriter pw) {
1097        pw.println(prefix + "mStackId=" + mStackId);
1098        pw.println(prefix + "mDeferDetach=" + mDeferDetach);
1099        pw.println(prefix + "mFullscreen=" + mFullscreen);
1100        pw.println(prefix + "mBounds=" + mBounds.toShortString());
1101        if (!mAdjustedBounds.isEmpty()) {
1102            pw.println(prefix + "mAdjustedBounds=" + mAdjustedBounds.toShortString());
1103        }
1104        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) {
1105            mTasks.get(taskNdx).dump(prefix + "  ", pw);
1106        }
1107        if (mAnimationBackgroundSurface.isDimming()) {
1108            pw.println(prefix + "mWindowAnimationBackgroundSurface:");
1109            mAnimationBackgroundSurface.printTo(prefix + "  ", pw);
1110        }
1111        if (!mExitingAppTokens.isEmpty()) {
1112            pw.println();
1113            pw.println("  Exiting application tokens:");
1114            for (int i = mExitingAppTokens.size() - 1; i >= 0; i--) {
1115                WindowToken token = mExitingAppTokens.get(i);
1116                pw.print("  Exiting App #"); pw.print(i);
1117                pw.print(' '); pw.print(token);
1118                pw.println(':');
1119                token.dump(pw, "    ");
1120            }
1121        }
1122    }
1123
1124    /** Fullscreen status of the stack without adjusting for other factors in the system like
1125     * visibility of docked stack.
1126     * Most callers should be using {@link #isFullscreen} as it take into consideration other
1127     * system factors. */
1128    boolean getRawFullscreen() {
1129        return mFullscreen;
1130    }
1131
1132    @Override
1133    public boolean isFullscreen() {
1134        if (useCurrentBounds()) {
1135            return mFullscreen;
1136        }
1137        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
1138        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
1139        // system.
1140        return true;
1141    }
1142
1143    @Override
1144    public DisplayInfo getDisplayInfo() {
1145        return mDisplayContent.getDisplayInfo();
1146    }
1147
1148    @Override
1149    public String toString() {
1150        return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
1151    }
1152
1153    @Override
1154    public String toShortString() {
1155        return "Stack=" + mStackId;
1156    }
1157
1158    /**
1159     * For docked workspace (or workspace that's side-by-side to the docked), provides
1160     * information which side of the screen was the dock anchored.
1161     */
1162    int getDockSide() {
1163        return getDockSide(mBounds);
1164    }
1165
1166    int getDockSide(Rect bounds) {
1167        if (mStackId != DOCKED_STACK_ID && !StackId.isResizeableByDockedStack(mStackId)) {
1168            return DOCKED_INVALID;
1169        }
1170        if (mDisplayContent == null) {
1171            return DOCKED_INVALID;
1172        }
1173        mDisplayContent.getLogicalDisplayRect(mTmpRect);
1174        final int orientation = mService.mCurConfiguration.orientation;
1175        if (orientation == Configuration.ORIENTATION_PORTRAIT) {
1176            // Portrait mode, docked either at the top or the bottom.
1177            if (bounds.top - mTmpRect.top <= mTmpRect.bottom - bounds.bottom) {
1178                return DOCKED_TOP;
1179            } else {
1180                return DOCKED_BOTTOM;
1181            }
1182        } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
1183            // Landscape mode, docked either on the left or on the right.
1184            if (bounds.left - mTmpRect.left <= mTmpRect.right - bounds.right) {
1185                return DOCKED_LEFT;
1186            } else {
1187                return DOCKED_RIGHT;
1188            }
1189        } else {
1190            return DOCKED_INVALID;
1191        }
1192    }
1193
1194    boolean isVisibleLocked() {
1195        final boolean keyguardOn = mService.mPolicy.isKeyguardShowingOrOccluded()
1196                && !mService.mAnimator.mKeyguardGoingAway;
1197        if (keyguardOn && !StackId.isAllowedOverLockscreen(mStackId)) {
1198            // The keyguard is showing and the stack shouldn't show on top of the keyguard.
1199            return false;
1200        }
1201
1202        for (int i = mTasks.size() - 1; i >= 0; i--) {
1203            final Task task = mTasks.get(i);
1204            for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
1205                if (!task.mAppTokens.get(j).hidden) {
1206                    return true;
1207                }
1208            }
1209        }
1210
1211        return false;
1212    }
1213
1214    /**
1215     * @return true if a the stack is visible for the current in user, ignoring any other visibility
1216     *         aspects, and false otherwise
1217     */
1218    boolean isVisibleForUserLocked() {
1219        for (int i = mTasks.size() - 1; i >= 0; i--) {
1220            final Task task = mTasks.get(i);
1221            if (task.isVisibleForUser()) {
1222                return true;
1223            }
1224        }
1225        return false;
1226    }
1227
1228    boolean isDragResizing() {
1229        return mDragResizing;
1230    }
1231
1232    void setDragResizingLocked(boolean resizing) {
1233        if (mDragResizing == resizing) {
1234            return;
1235        }
1236        mDragResizing = resizing;
1237        for (int i = mTasks.size() - 1; i >= 0 ; i--) {
1238            mTasks.get(i).resetDragResizingChangeReported();
1239        }
1240    }
1241
1242    @Override  // AnimatesBounds
1243    public boolean setSize(Rect bounds) {
1244        synchronized (mService.mWindowMap) {
1245            if (mDisplayContent == null) {
1246                return false;
1247            }
1248        }
1249        try {
1250            mService.mActivityManager.resizeStack(mStackId, bounds, false, true, false, -1);
1251        } catch (RemoteException e) {
1252        }
1253        return true;
1254    }
1255
1256    public boolean setPinnedStackSize(Rect bounds, Rect tempTaskBounds) {
1257        synchronized (mService.mWindowMap) {
1258            if (mDisplayContent == null) {
1259                return false;
1260            }
1261            if (mStackId != PINNED_STACK_ID) {
1262                Slog.w(TAG_WM, "Attempt to use pinned stack resize animation helper on"
1263                        + "non pinned stack");
1264                return false;
1265            }
1266        }
1267        try {
1268            mService.mActivityManager.resizePinnedStack(bounds, tempTaskBounds);
1269        } catch (RemoteException e) {
1270            // I don't believe you.
1271        }
1272        return true;
1273    }
1274
1275    void forceWindowsScaleable(Task task, boolean force) {
1276        SurfaceControl.openTransaction();
1277        try {
1278            final ArrayList<AppWindowToken> activities = task.mAppTokens;
1279            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
1280                final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
1281                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
1282                    final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
1283                    if (winAnimator == null || !winAnimator.hasSurface()) {
1284                        continue;
1285                    }
1286                    winAnimator.mSurfaceController.forceScaleableInTransaction(force);
1287                }
1288            }
1289        } finally {
1290            SurfaceControl.closeTransaction();
1291        }
1292    }
1293
1294    @Override  // AnimatesBounds
1295    public void onAnimationStart() {
1296        synchronized (mService.mWindowMap) {
1297            mFreezeMovementAnimations = true;
1298            mBoundsAnimating = true;
1299        }
1300    }
1301
1302    @Override  // AnimatesBounds
1303    public void onAnimationEnd() {
1304        synchronized (mService.mWindowMap) {
1305            mFreezeMovementAnimations = false;
1306            mBoundsAnimating = false;
1307            mService.requestTraversal();
1308        }
1309        if (mStackId == PINNED_STACK_ID) {
1310            try {
1311                mService.mActivityManager.notifyPinnedStackAnimationEnded();
1312            } catch (RemoteException e) {
1313                // I don't believe you...
1314            }
1315        }
1316    }
1317
1318    @Override
1319    public void moveToFullscreen() {
1320        try {
1321            mService.mActivityManager.moveTasksToFullscreenStack(mStackId, true);
1322        } catch (RemoteException e) {
1323            e.printStackTrace();
1324        }
1325    }
1326
1327    @Override
1328    public void getFullScreenBounds(Rect bounds) {
1329        getDisplayContent().getContentRect(bounds);
1330    }
1331
1332    public boolean getFreezeMovementAnimations() {
1333        return mFreezeMovementAnimations;
1334    }
1335
1336    public boolean getForceScaleToCrop() {
1337        return mBoundsAnimating;
1338    }
1339
1340    public boolean getBoundsAnimating() {
1341        return mBoundsAnimating;
1342    }
1343}
1344