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