DisplayContent.java revision ae9adbfb758712caaf11b4ba5c5fd15848dcc3c5
1/*
2 * Copyright (C) 2012 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.StackId.DOCKED_STACK_ID;
20import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
21import static android.app.ActivityManager.StackId.HOME_STACK_ID;
22import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
23import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
24import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
25import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
26import static android.view.Display.DEFAULT_DISPLAY;
27import static android.view.Display.FLAG_PRIVATE;
28import static android.view.Surface.ROTATION_0;
29import static android.view.Surface.ROTATION_180;
30import static android.view.Surface.ROTATION_270;
31import static android.view.Surface.ROTATION_90;
32import static android.view.WindowManager.DOCKED_BOTTOM;
33import static android.view.WindowManager.DOCKED_INVALID;
34import static android.view.WindowManager.DOCKED_TOP;
35import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
36import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
37import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
38import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
39import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE;
40import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET;
41import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
42import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
43import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
44import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
45import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
46import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
47import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
48import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
49import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
50import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
51import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
52import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
53import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
54import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
55import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
56import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
57import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
58import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
59import static com.android.server.wm.WindowManagerService.dipToPixel;
60import static com.android.server.wm.WindowManagerService.localLOGV;
61import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
62
63import android.annotation.NonNull;
64import android.app.ActivityManager.StackId;
65import android.content.res.Configuration;
66import android.graphics.Matrix;
67import android.graphics.Rect;
68import android.graphics.RectF;
69import android.graphics.Region;
70import android.graphics.Region.Op;
71import android.hardware.display.DisplayManagerInternal;
72import android.os.Debug;
73import android.os.Handler;
74import android.os.IBinder;
75import android.util.DisplayMetrics;
76import android.util.Slog;
77import android.view.Display;
78import android.view.DisplayInfo;
79import android.view.IWindow;
80import android.view.WindowManager;
81import android.view.WindowManagerPolicy;
82
83import com.android.internal.util.FastPrintWriter;
84
85import java.io.FileDescriptor;
86import java.io.PrintWriter;
87import java.io.StringWriter;
88import java.util.ArrayList;
89import java.util.Arrays;
90import java.util.Comparator;
91import java.util.HashMap;
92import java.util.Iterator;
93import java.util.List;
94
95/**
96 * Utility class for keeping track of the WindowStates and other pertinent contents of a
97 * particular Display.
98 *
99 * IMPORTANT: No method from this class should ever be used without holding
100 * WindowManagerService.mWindowMap.
101 */
102class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer> {
103
104    /** Unique identifier of this stack. */
105    private final int mDisplayId;
106
107    // The display only has 2 child window containers. mTaskStackContainers which contains all
108    // window containers that are related to apps (Activities) and mNonAppWindowContainers which
109    // contains all window containers not related to apps (e.g. Status bar).
110    private final TaskStackContainers mTaskStackContainers = new TaskStackContainers();
111    private final NonAppWindowContainers mNonAppWindowContainers = new NonAppWindowContainers();
112
113    /** Z-ordered (bottom-most first) list of all Window objects. Assigned to an element
114     * from mDisplayWindows; */
115    private final WindowList mWindows = new WindowList();
116
117    // Mapping from a token IBinder to a WindowToken object on this display.
118    private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap();
119
120    int mInitialDisplayWidth = 0;
121    int mInitialDisplayHeight = 0;
122    int mInitialDisplayDensity = 0;
123    int mBaseDisplayWidth = 0;
124    int mBaseDisplayHeight = 0;
125    int mBaseDisplayDensity = 0;
126    boolean mDisplayScalingDisabled;
127    private final DisplayInfo mDisplayInfo = new DisplayInfo();
128    private final Display mDisplay;
129    private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
130
131    Rect mBaseDisplayRect = new Rect();
132    private Rect mContentRect = new Rect();
133
134    // Accessed directly by all users.
135    private boolean mLayoutNeeded;
136    int pendingLayoutChanges;
137    final boolean isDefaultDisplay;
138
139    /** Window tokens that are in the process of exiting, but still on screen for animations. */
140    final ArrayList<WindowToken> mExitingTokens = new ArrayList<>();
141
142    /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
143     * (except a future lockscreen TaskStack) moves to the top. */
144    private TaskStack mHomeStack = null;
145
146    /** Detect user tapping outside of current focused task bounds .*/
147    TaskTapPointerEventListener mTapDetector;
148
149    /** Detect user tapping outside of current focused stack bounds .*/
150    private Region mTouchExcludeRegion = new Region();
151
152    /** Save allocating when calculating rects */
153    private final Rect mTmpRect = new Rect();
154    private final Rect mTmpRect2 = new Rect();
155    private final RectF mTmpRectF = new RectF();
156    private final Matrix mTmpMatrix = new Matrix();
157    private final Region mTmpRegion = new Region();
158
159    final WindowManagerService mService;
160
161    /** Remove this display when animation on it has completed. */
162    private boolean mDeferredRemoval;
163
164    final DockedStackDividerController mDividerControllerLocked;
165
166    final DimLayerController mDimLayerController;
167
168    final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>();
169
170    /** Used when rebuilding window list to keep track of windows that have been removed. */
171    private WindowState[] mRebuildTmp = new WindowState[20];
172
173    private final TaskForResizePointSearchResult mTmpTaskForResizePointSearchResult =
174            new TaskForResizePointSearchResult();
175    private final GetWindowOnDisplaySearchResult mTmpGetWindowOnDisplaySearchResult =
176            new GetWindowOnDisplaySearchResult();
177
178    // True if this display is in the process of being removed. Used to determine if the removal of
179    // the display's direct children should be allowed.
180    private boolean mRemovingDisplay = false;
181
182    private final WindowLayersController mLayersController;
183    int mInputMethodAnimLayerAdjustment;
184
185    /**
186     * @param display May not be null.
187     * @param service You know.
188     * @param layersController window layer controller used to assign layer to the windows on this
189     *                         display.
190     */
191    DisplayContent(Display display, WindowManagerService service,
192            WindowLayersController layersController) {
193        mDisplay = display;
194        mDisplayId = display.getDisplayId();
195        mLayersController = layersController;
196        display.getDisplayInfo(mDisplayInfo);
197        display.getMetrics(mDisplayMetrics);
198        isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
199        mService = service;
200        initializeDisplayBaseInfo();
201        mDividerControllerLocked = new DockedStackDividerController(service, this);
202        mDimLayerController = new DimLayerController(this);
203
204        // These are the only direct children we should ever have and they are permanent.
205        super.addChild(mTaskStackContainers, null);
206        super.addChild(mNonAppWindowContainers, null);
207    }
208
209    int getDisplayId() {
210        return mDisplayId;
211    }
212
213    WindowList getWindowList() {
214        return mWindows;
215    }
216
217    WindowToken getWindowToken(IBinder binder) {
218        return mTokenMap.get(binder);
219    }
220
221    AppWindowToken getAppWindowToken(IBinder binder) {
222        final WindowToken token = getWindowToken(binder);
223        if (token == null) {
224            return null;
225        }
226        return token.asAppWindowToken();
227    }
228
229    void setWindowToken(IBinder binder, WindowToken token) {
230        final DisplayContent dc = mService.mRoot.getWindowTokenDisplay(token);
231        if (dc != null) {
232            // We currently don't support adding a window token to the display if the display
233            // already has the binder mapped to another token. If there is a use case for supporting
234            // this moving forward we will either need to merge the WindowTokens some how or have
235            // the binder map to a list of window tokens.
236            throw new IllegalArgumentException("Can't map token=" + token + " to display=" + this
237                    + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);
238        }
239        mTokenMap.put(binder, token);
240
241        if (token.asAppWindowToken() == null) {
242            // Add non-app token to container hierarchy on the display. App tokens are added through
243            // the parent container managing them (e.g. Tasks).
244            mNonAppWindowContainers.addChild(token, null);
245        }
246    }
247
248    WindowToken removeWindowToken(IBinder binder) {
249        final WindowToken token = mTokenMap.remove(binder);
250        if (token != null && token.asAppWindowToken() == null) {
251            mNonAppWindowContainers.removeChild(token);
252        }
253        return token;
254    }
255
256    Display getDisplay() {
257        return mDisplay;
258    }
259
260    DisplayInfo getDisplayInfo() {
261        return mDisplayInfo;
262    }
263
264    DisplayMetrics getDisplayMetrics() {
265        return mDisplayMetrics;
266    }
267
268    DockedStackDividerController getDockedDividerController() {
269        return mDividerControllerLocked;
270    }
271
272    /**
273     * Returns true if the specified UID has access to this display.
274     */
275    boolean hasAccess(int uid) {
276        return mDisplay.hasAccess(uid);
277    }
278
279    boolean isPrivate() {
280        return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
281    }
282
283    TaskStack getHomeStack() {
284        if (mHomeStack == null && mDisplayId == DEFAULT_DISPLAY) {
285            Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this);
286        }
287        return mHomeStack;
288    }
289
290    TaskStack getStackById(int stackId) {
291        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
292            final TaskStack stack = mTaskStackContainers.get(i);
293            if (stack.mStackId == stackId) {
294                return stack;
295            }
296        }
297        return null;
298    }
299
300    @Override
301    void onConfigurationChanged(Configuration newParentConfig) {
302        super.onConfigurationChanged(newParentConfig);
303
304        // The display size information is heavily dependent on the resources in the current
305        // configuration, so we need to reconfigure it every time the configuration changes.
306        // See {@link PhoneWindowManager#setInitialDisplaySize}...sigh...
307        mService.reconfigureDisplayLocked(this);
308
309        getDockedDividerController().onConfigurationChanged();
310    }
311
312    /**
313     * Callback used to trigger bounds update after configuration change and get ids of stacks whose
314     * bounds were updated.
315     */
316    void updateStackBoundsAfterConfigChange(@NonNull List<Integer> changedStackList) {
317        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
318            final TaskStack stack = mTaskStackContainers.get(i);
319            if (stack.updateBoundsAfterConfigChange()) {
320                changedStackList.add(stack.mStackId);
321            }
322        }
323    }
324
325    @Override
326    boolean fillsParent() {
327        return true;
328    }
329
330    @Override
331    boolean isVisible() {
332        return true;
333    }
334
335    @Override
336    void onAppTransitionDone() {
337        super.onAppTransitionDone();
338        rebuildAppWindowList();
339    }
340
341    @Override
342    int getOrientation() {
343        if (mService.isStackVisibleLocked(DOCKED_STACK_ID)
344                || mService.isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
345            // Apps and their containers are not allowed to specify an orientation while the docked
346            // or freeform stack is visible...except for the home stack/task if the docked stack is
347            // minimized and it actually set something.
348            if (mHomeStack != null && mHomeStack.isVisible()
349                    && mDividerControllerLocked.isMinimizedDock()) {
350                final int orientation = mHomeStack.getOrientation();
351                if (orientation != SCREEN_ORIENTATION_UNSET) {
352                    return orientation;
353                }
354            }
355            return SCREEN_ORIENTATION_UNSPECIFIED;
356        }
357
358        final int orientation = super.getOrientation();
359        if (orientation != SCREEN_ORIENTATION_UNSET && orientation != SCREEN_ORIENTATION_BEHIND) {
360            if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
361                    "App is requesting an orientation, return " + orientation);
362            return orientation;
363        }
364
365        if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
366                "No app is requesting an orientation, return " + mService.mLastOrientation);
367        // The next app has not been requested to be visible, so we keep the current orientation
368        // to prevent freezing/unfreezing the display too early.
369        return mService.mLastOrientation;
370    }
371
372    void updateDisplayInfo() {
373        mDisplay.getDisplayInfo(mDisplayInfo);
374        mDisplay.getMetrics(mDisplayMetrics);
375        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
376            mTaskStackContainers.get(i).updateDisplayInfo(null);
377        }
378    }
379
380    void initializeDisplayBaseInfo() {
381        final DisplayManagerInternal displayManagerInternal = mService.mDisplayManagerInternal;
382        if (displayManagerInternal != null) {
383            // Bootstrap the default logical display from the display manager.
384            final DisplayInfo newDisplayInfo = displayManagerInternal.getDisplayInfo(mDisplayId);
385            if (newDisplayInfo != null) {
386                mDisplayInfo.copyFrom(newDisplayInfo);
387            }
388        }
389
390        mBaseDisplayWidth = mInitialDisplayWidth = mDisplayInfo.logicalWidth;
391        mBaseDisplayHeight = mInitialDisplayHeight = mDisplayInfo.logicalHeight;
392        mBaseDisplayDensity = mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
393        mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
394    }
395
396    void getLogicalDisplayRect(Rect out) {
397        // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
398        final int orientation = mDisplayInfo.rotation;
399        boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
400        final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
401        final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
402        int width = mDisplayInfo.logicalWidth;
403        int left = (physWidth - width) / 2;
404        int height = mDisplayInfo.logicalHeight;
405        int top = (physHeight - height) / 2;
406        out.set(left, top, left + width, top + height);
407    }
408
409    private void getLogicalDisplayRect(Rect out, int orientation) {
410        getLogicalDisplayRect(out);
411
412        // Rotate the Rect if needed.
413        final int currentRotation = mDisplayInfo.rotation;
414        final int rotationDelta = deltaRotation(currentRotation, orientation);
415        if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) {
416            createRotationMatrix(rotationDelta, mBaseDisplayWidth, mBaseDisplayHeight, mTmpMatrix);
417            mTmpRectF.set(out);
418            mTmpMatrix.mapRect(mTmpRectF);
419            mTmpRectF.round(out);
420        }
421    }
422
423    void getContentRect(Rect out) {
424        out.set(mContentRect);
425    }
426
427    /** Refer to {@link WindowManagerService#attachStack(int, int, boolean)} */
428    void attachStack(TaskStack stack, boolean onTop) {
429        mTaskStackContainers.attachStack(stack, onTop);
430    }
431
432    void moveStack(TaskStack stack, boolean toTop) {
433        mTaskStackContainers.moveStack(stack, toTop);
434    }
435
436    @Override
437    protected void addChild(DisplayChildWindowContainer child,
438            Comparator<DisplayChildWindowContainer> comparator) {
439        throw new UnsupportedOperationException("See DisplayChildWindowContainer");
440    }
441
442    @Override
443    protected void addChild(DisplayChildWindowContainer child, int index) {
444        throw new UnsupportedOperationException("See DisplayChildWindowContainer");
445    }
446
447    @Override
448    protected void removeChild(DisplayChildWindowContainer child) {
449        // Only allow removal of direct children from this display if the display is in the process
450        // of been removed.
451        if (mRemovingDisplay) {
452            super.removeChild(child);
453            return;
454        }
455        throw new UnsupportedOperationException("See DisplayChildWindowContainer");
456    }
457
458    /**
459     * Propagate the new bounds to all child stacks.
460     * @param contentRect The bounds to apply at the top level.
461     */
462    void resize(Rect contentRect) {
463        mContentRect.set(contentRect);
464    }
465
466    int taskIdFromPoint(int x, int y) {
467        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
468            final TaskStack stack = mTaskStackContainers.get(stackNdx);
469            final int taskId = stack.taskIdFromPoint(x, y);
470            if (taskId != -1) {
471                return taskId;
472            }
473        }
474        return -1;
475    }
476
477    /**
478     * Find the task whose outside touch area (for resizing) (x, y) falls within.
479     * Returns null if the touch doesn't fall into a resizing area.
480     */
481    Task findTaskForResizePoint(int x, int y) {
482        final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
483        mTmpTaskForResizePointSearchResult.reset();
484        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
485            final TaskStack stack = mTaskStackContainers.get(stackNdx);
486            if (!StackId.isTaskResizeAllowed(stack.mStackId)) {
487                return null;
488            }
489
490            stack.findTaskForResizePoint(x, y, delta, mTmpTaskForResizePointSearchResult);
491            if (mTmpTaskForResizePointSearchResult.searchDone) {
492                return mTmpTaskForResizePointSearchResult.taskForResize;
493            }
494        }
495        return null;
496    }
497
498    void setTouchExcludeRegion(Task focusedTask) {
499        mTouchExcludeRegion.set(mBaseDisplayRect);
500        final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
501        mTmpRect2.setEmpty();
502        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
503            final TaskStack stack = mTaskStackContainers.get(stackNdx);
504            stack.setTouchExcludeRegion(
505                    focusedTask, delta, mTouchExcludeRegion, mContentRect, mTmpRect2);
506        }
507        // If we removed the focused task above, add it back and only leave its
508        // outside touch area in the exclusion. TapDectector is not interested in
509        // any touch inside the focused task itself.
510        if (!mTmpRect2.isEmpty()) {
511            mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION);
512        }
513        final WindowState inputMethod = mService.mInputMethodWindow;
514        if (inputMethod != null && inputMethod.isVisibleLw()) {
515            // If the input method is visible and the user is typing, we don't want these touch
516            // events to be intercepted and used to change focus. This would likely cause a
517            // disappearance of the input method.
518            inputMethod.getTouchableRegion(mTmpRegion);
519            mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
520        }
521        for (int i = mTapExcludedWindows.size() - 1; i >= 0; i--) {
522            WindowState win = mTapExcludedWindows.get(i);
523            win.getTouchableRegion(mTmpRegion);
524            mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
525        }
526        if (getDockedStackVisibleForUserLocked() != null) {
527            mDividerControllerLocked.getTouchRegion(mTmpRect);
528            mTmpRegion.set(mTmpRect);
529            mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
530        }
531        if (mTapDetector != null) {
532            mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion);
533        }
534    }
535
536    void switchUser() {
537        final WindowList windows = getWindowList();
538        for (int i = 0; i < windows.size(); i++) {
539            final WindowState win = windows.get(i);
540            if (win.isHiddenFromUserLocked()) {
541                if (DEBUG_VISIBILITY) Slog.w(TAG_WM, "user changing, hiding " + win
542                        + ", attrs=" + win.mAttrs.type + ", belonging to " + win.mOwnerUid);
543                win.hideLw(false);
544            }
545        }
546
547        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
548            mTaskStackContainers.get(stackNdx).switchUser();
549        }
550
551        rebuildAppWindowList();
552    }
553
554    void resetAnimationBackgroundAnimator() {
555        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
556            mTaskStackContainers.get(stackNdx).resetAnimationBackgroundAnimator();
557        }
558    }
559
560    boolean animateDimLayers() {
561        return mDimLayerController.animateDimLayers();
562    }
563
564    void resetDimming() {
565        mDimLayerController.resetDimming();
566    }
567
568    boolean isDimming() {
569        return mDimLayerController.isDimming();
570    }
571
572    void stopDimmingIfNeeded() {
573        mDimLayerController.stopDimmingIfNeeded();
574    }
575
576    @Override
577    void removeIfPossible() {
578        if (isAnimating()) {
579            mDeferredRemoval = true;
580            return;
581        }
582        removeImmediately();
583    }
584
585    @Override
586    void removeImmediately() {
587        mRemovingDisplay = true;
588        try {
589            super.removeImmediately();
590            if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this);
591            mDimLayerController.close();
592            if (mDisplayId == DEFAULT_DISPLAY) {
593                mService.unregisterPointerEventListener(mTapDetector);
594                mService.unregisterPointerEventListener(mService.mMousePositionTracker);
595            }
596        } finally {
597            mRemovingDisplay = false;
598        }
599    }
600
601    /** Returns true if a removal action is still being deferred. */
602    @Override
603    boolean checkCompleteDeferredRemoval() {
604        final boolean stillDeferringRemoval = super.checkCompleteDeferredRemoval();
605
606        if (!stillDeferringRemoval && mDeferredRemoval) {
607            removeImmediately();
608            mService.onDisplayRemoved(mDisplayId);
609            return false;
610        }
611        return true;
612    }
613
614    boolean animateForIme(float interpolatedValue, float animationTarget,
615            float dividerAnimationTarget) {
616        boolean updated = false;
617
618        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
619            final TaskStack stack = mTaskStackContainers.get(i);
620            if (stack == null || !stack.isAdjustedForIme()) {
621                continue;
622            }
623
624            if (interpolatedValue >= 1f && animationTarget == 0f && dividerAnimationTarget == 0f) {
625                stack.resetAdjustedForIme(true /* adjustBoundsNow */);
626                updated = true;
627            } else {
628                mDividerControllerLocked.mLastAnimationProgress =
629                        mDividerControllerLocked.getInterpolatedAnimationValue(interpolatedValue);
630                mDividerControllerLocked.mLastDividerProgress =
631                        mDividerControllerLocked.getInterpolatedDividerValue(interpolatedValue);
632                updated |= stack.updateAdjustForIme(
633                        mDividerControllerLocked.mLastAnimationProgress,
634                        mDividerControllerLocked.mLastDividerProgress,
635                        false /* force */);
636            }
637            if (interpolatedValue >= 1f) {
638                stack.endImeAdjustAnimation();
639            }
640        }
641
642        return updated;
643    }
644
645    boolean clearImeAdjustAnimation() {
646        boolean changed = false;
647        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
648            final TaskStack stack = mTaskStackContainers.get(i);
649            if (stack != null && stack.isAdjustedForIme()) {
650                stack.resetAdjustedForIme(true /* adjustBoundsNow */);
651                changed  = true;
652            }
653        }
654        return changed;
655    }
656
657    void beginImeAdjustAnimation() {
658        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
659            final TaskStack stack = mTaskStackContainers.get(i);
660            if (stack.isVisible() && stack.isAdjustedForIme()) {
661                stack.beginImeAdjustAnimation();
662            }
663        }
664    }
665
666    void adjustForImeIfNeeded() {
667        final WindowState imeWin = mService.mInputMethodWindow;
668        final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
669                && !mDividerControllerLocked.isImeHideRequested();
670        final boolean dockVisible = mService.isStackVisibleLocked(DOCKED_STACK_ID);
671        final TaskStack imeTargetStack = mService.getImeFocusStackLocked();
672        final int imeDockSide = (dockVisible && imeTargetStack != null) ?
673                imeTargetStack.getDockSide() : DOCKED_INVALID;
674        final boolean imeOnTop = (imeDockSide == DOCKED_TOP);
675        final boolean imeOnBottom = (imeDockSide == DOCKED_BOTTOM);
676        final boolean dockMinimized = mDividerControllerLocked.isMinimizedDock();
677        final int imeHeight = mService.mPolicy.getInputMethodWindowVisibleHeightLw();
678        final boolean imeHeightChanged = imeVisible &&
679                imeHeight != mDividerControllerLocked.getImeHeightAdjustedFor();
680
681        // The divider could be adjusted for IME position, or be thinner than usual,
682        // or both. There are three possible cases:
683        // - If IME is visible, and focus is on top, divider is not moved for IME but thinner.
684        // - If IME is visible, and focus is on bottom, divider is moved for IME and thinner.
685        // - If IME is not visible, divider is not moved and is normal width.
686
687        if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) {
688            for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
689                final TaskStack stack = mTaskStackContainers.get(i);
690                final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
691                if (stack.isVisible() && (imeOnBottom || isDockedOnBottom)) {
692                    stack.setAdjustedForIme(imeWin, imeOnBottom && imeHeightChanged);
693                } else {
694                    stack.resetAdjustedForIme(false);
695                }
696            }
697            mDividerControllerLocked.setAdjustedForIme(
698                    imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin, imeHeight);
699        } else {
700            for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
701                final TaskStack stack = mTaskStackContainers.get(i);
702                stack.resetAdjustedForIme(!dockVisible);
703            }
704            mDividerControllerLocked.setAdjustedForIme(
705                    false /*ime*/, false /*divider*/, dockVisible /*animate*/, imeWin, imeHeight);
706        }
707    }
708
709    void setInputMethodAnimLayerAdjustment(int adj) {
710        if (DEBUG_LAYERS) Slog.v(TAG_WM, "Setting im layer adj to " + adj);
711        mInputMethodAnimLayerAdjustment = adj;
712        final WindowState imw = mService.mInputMethodWindow;
713        if (imw != null) {
714            imw.adjustAnimLayer(adj);
715        }
716        for (int i = mService.mInputMethodDialogs.size() - 1; i >= 0; i--) {
717            final WindowState dialog = mService.mInputMethodDialogs.get(i);
718            // TODO: This and other places setting mAnimLayer can probably use WS.adjustAnimLayer,
719            // but need to make sure we are not setting things twice for child windows that are
720            // already in the list.
721            dialog.mWinAnimator.mAnimLayer = dialog.mLayer + adj;
722            if (DEBUG_LAYERS) Slog.v(TAG_WM, "IM win " + imw
723                    + " anim layer: " + dialog.mWinAnimator.mAnimLayer);
724        }
725    }
726
727    /**
728     * If a window that has an animation specifying a colored background and the current wallpaper
729     * is visible, then the color goes *below* the wallpaper so we don't cause the wallpaper to
730     * suddenly disappear.
731     */
732    int getLayerForAnimationBackground(WindowStateAnimator winAnimator) {
733        for (int i = mWindows.size() - 1; i >= 0; --i) {
734            final WindowState win = mWindows.get(i);
735            if (win.mIsWallpaper && win.isVisibleNow()) {
736                return win.mWinAnimator.mAnimLayer;
737            }
738        }
739        return winAnimator.mAnimLayer;
740    }
741
742    void prepareFreezingTaskBounds() {
743        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
744            final TaskStack stack = mTaskStackContainers.get(stackNdx);
745            stack.prepareFreezingTaskBounds();
746        }
747    }
748
749    void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
750        getLogicalDisplayRect(mTmpRect, newRotation);
751
752        // Compute a transform matrix to undo the coordinate space transformation,
753        // and present the window at the same physical position it previously occupied.
754        final int deltaRotation = deltaRotation(newRotation, oldRotation);
755        createRotationMatrix(deltaRotation, mTmpRect.width(), mTmpRect.height(), mTmpMatrix);
756
757        mTmpRectF.set(bounds);
758        mTmpMatrix.mapRect(mTmpRectF);
759        mTmpRectF.round(bounds);
760    }
761
762    static int deltaRotation(int oldRotation, int newRotation) {
763        int delta = newRotation - oldRotation;
764        if (delta < 0) delta += 4;
765        return delta;
766    }
767
768    private static void createRotationMatrix(int rotation, float displayWidth, float displayHeight,
769            Matrix outMatrix) {
770        // For rotations without Z-ordering we don't need the target rectangle's position.
771        createRotationMatrix(rotation, 0 /* rectLeft */, 0 /* rectTop */, displayWidth,
772                displayHeight, outMatrix);
773    }
774
775    static void createRotationMatrix(int rotation, float rectLeft, float rectTop,
776            float displayWidth, float displayHeight, Matrix outMatrix) {
777        switch (rotation) {
778            case ROTATION_0:
779                outMatrix.reset();
780                break;
781            case ROTATION_270:
782                outMatrix.setRotate(270, 0, 0);
783                outMatrix.postTranslate(0, displayHeight);
784                outMatrix.postTranslate(rectTop, 0);
785                break;
786            case ROTATION_180:
787                outMatrix.reset();
788                break;
789            case ROTATION_90:
790                outMatrix.setRotate(90, 0, 0);
791                outMatrix.postTranslate(displayWidth, 0);
792                outMatrix.postTranslate(-rectTop, rectLeft);
793                break;
794        }
795    }
796
797    public void dump(String prefix, PrintWriter pw) {
798        pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
799        final String subPrefix = "  " + prefix;
800        pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
801            pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
802            pw.print("dpi");
803            if (mInitialDisplayWidth != mBaseDisplayWidth
804                    || mInitialDisplayHeight != mBaseDisplayHeight
805                    || mInitialDisplayDensity != mBaseDisplayDensity) {
806                pw.print(" base=");
807                pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
808                pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
809            }
810            if (mDisplayScalingDisabled) {
811                pw.println(" noscale");
812            }
813            pw.print(" cur=");
814            pw.print(mDisplayInfo.logicalWidth);
815            pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
816            pw.print(" app=");
817            pw.print(mDisplayInfo.appWidth);
818            pw.print("x"); pw.print(mDisplayInfo.appHeight);
819            pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
820            pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
821            pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
822            pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
823            pw.println(subPrefix + "deferred=" + mDeferredRemoval
824                    + " mLayoutNeeded=" + mLayoutNeeded);
825
826        pw.println();
827        pw.println("  Application tokens in top down Z order:");
828        for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
829            final TaskStack stack = mTaskStackContainers.get(stackNdx);
830            stack.dump(prefix + "  ", pw);
831        }
832
833        pw.println();
834        if (!mExitingTokens.isEmpty()) {
835            pw.println();
836            pw.println("  Exiting tokens:");
837            for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
838                final WindowToken token = mExitingTokens.get(i);
839                pw.print("  Exiting #"); pw.print(i);
840                pw.print(' '); pw.print(token);
841                pw.println(':');
842                token.dump(pw, "    ");
843            }
844        }
845        pw.println();
846        mDimLayerController.dump(prefix + "  ", pw);
847        pw.println();
848        mDividerControllerLocked.dump(prefix + "  ", pw);
849
850        if (mInputMethodAnimLayerAdjustment != 0) {
851            pw.println(subPrefix
852                    + "mInputMethodAnimLayerAdjustment=" + mInputMethodAnimLayerAdjustment);
853        }
854    }
855
856    @Override
857    public String toString() {
858        return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mChildren;
859    }
860
861    String getName() {
862        return "Display " + mDisplayId + " name=\"" + mDisplayInfo.name + "\"";
863    }
864
865    /**
866     * @return The docked stack, but only if it is visible, and {@code null} otherwise.
867     */
868    TaskStack getDockedStackLocked() {
869        final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
870        return (stack != null && stack.isVisible()) ? stack : null;
871    }
872
873    /**
874     * Like {@link #getDockedStackLocked}, but also returns the docked stack if it's currently not
875     * visible, as long as it's not hidden because the current user doesn't have any tasks there.
876     */
877    TaskStack getDockedStackVisibleForUserLocked() {
878        final TaskStack stack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
879        return (stack != null && stack.isVisible(true /* ignoreKeyguard */)) ? stack : null;
880    }
881
882    /** Find the visible, touch-deliverable window under the given point */
883    WindowState getTouchableWinAtPointLocked(float xf, float yf) {
884        WindowState touchedWin = null;
885        final int x = (int) xf;
886        final int y = (int) yf;
887
888        for (int i = mWindows.size() - 1; i >= 0; i--) {
889            WindowState window = mWindows.get(i);
890            final int flags = window.mAttrs.flags;
891            if (!window.isVisibleLw()) {
892                continue;
893            }
894            if ((flags & FLAG_NOT_TOUCHABLE) != 0) {
895                continue;
896            }
897
898            window.getVisibleBounds(mTmpRect);
899            if (!mTmpRect.contains(x, y)) {
900                continue;
901            }
902
903            window.getTouchableRegion(mTmpRegion);
904
905            final int touchFlags = flags & (FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL);
906            if (mTmpRegion.contains(x, y) || touchFlags == 0) {
907                touchedWin = window;
908                break;
909            }
910        }
911
912        return touchedWin;
913    }
914
915    boolean canAddToastWindowForUid(int uid) {
916        // We allow one toast window per UID being shown at a time.
917        WindowList windows = getWindowList();
918        final int windowCount = windows.size();
919        for (int i = 0; i < windowCount; i++) {
920            WindowState window = windows.get(i);
921            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == uid
922                    && !window.mPermanentlyHidden && !window.mAnimatingExit
923                    && !window.mRemoveOnExit) {
924                return false;
925            }
926        }
927        return true;
928    }
929
930    void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus, WindowState newFocus) {
931        if (oldFocus == null || (newFocus != null && newFocus.mOwnerUid == oldFocus.mOwnerUid)) {
932            return;
933        }
934        final int lostFocusUid = oldFocus.mOwnerUid;
935        final WindowList windows = getWindowList();
936        final int windowCount = windows.size();
937        final Handler handler = mService.mH;
938        for (int i = 0; i < windowCount; i++) {
939            final WindowState window = windows.get(i);
940            if (window.mAttrs.type == TYPE_TOAST && window.mOwnerUid == lostFocusUid) {
941                if (!handler.hasMessages(WINDOW_HIDE_TIMEOUT, window)) {
942                    handler.sendMessageDelayed(handler.obtainMessage(WINDOW_HIDE_TIMEOUT, window),
943                            window.mAttrs.hideTimeoutMilliseconds);
944                }
945            }
946        }
947    }
948
949    WindowState findFocusedWindow() {
950        final AppWindowToken focusedApp = mService.mFocusedApp;
951
952        for (int i = mWindows.size() - 1; i >= 0; i--) {
953            final WindowState win = mWindows.get(i);
954
955            if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + i + " = " + win
956                    + ", flags=" + win.mAttrs.flags + ", canReceive=" + win.canReceiveKeys());
957
958            if (!win.canReceiveKeys()) {
959                continue;
960            }
961
962            final AppWindowToken wtoken = win.mAppToken;
963
964            // If this window's application has been removed, just skip it.
965            if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) {
966                if (DEBUG_FOCUS) Slog.v(TAG_WM, "Skipping " + wtoken + " because "
967                        + (wtoken.removed ? "removed" : "sendingToBottom"));
968                continue;
969            }
970
971            if (focusedApp == null) {
972                if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp=null"
973                        + " using new focus @ " + i + " = " + win);
974                return win;
975            }
976
977            if (!focusedApp.windowsAreFocusable()) {
978                // Current focused app windows aren't focusable...
979                if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp windows not"
980                        + " focusable using new focus @ " + i + " = " + win);
981                return win;
982            }
983
984            // Descend through all of the app tokens and find the first that either matches
985            // win.mAppToken (return win) or mFocusedApp (return null).
986            if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING) {
987                if (focusedApp.compareTo(wtoken) > 0) {
988                    // App stack below focused app stack. No focus for you!!!
989                    if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM,
990                            "findFocusedWindow: Reached focused app=" + focusedApp);
991                    return null;
992                }
993            }
994
995            if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Found new focus @ "
996                    + i + " = " + win);
997            return win;
998        }
999
1000        if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: No focusable windows.");
1001        return null;
1002    }
1003
1004    int addAppWindowToWindowList(final WindowState win) {
1005        final IWindow client = win.mClient;
1006
1007        WindowList tokenWindowList = getTokenWindowsOnDisplay(win.mToken);
1008        if (!tokenWindowList.isEmpty()) {
1009            return addAppWindowExisting(win, tokenWindowList);
1010        }
1011
1012        // No windows from this token on this display
1013        if (localLOGV) Slog.v(TAG_WM, "Figuring out where to add app window "
1014                + client.asBinder() + " (token=" + this + ")");
1015
1016        final WindowToken wToken = win.mToken;
1017
1018        // Figure out where the window should go, based on the order of applications.
1019        mTmpGetWindowOnDisplaySearchResult.reset();
1020        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
1021            final TaskStack stack = mTaskStackContainers.get(i);
1022            stack.getWindowOnDisplayBeforeToken(this, wToken, mTmpGetWindowOnDisplaySearchResult);
1023            if (mTmpGetWindowOnDisplaySearchResult.reachedToken) {
1024                // We have reach the token we are interested in. End search.
1025                break;
1026            }
1027        }
1028
1029        WindowState pos = mTmpGetWindowOnDisplaySearchResult.foundWindow;
1030
1031        // We now know the index into the apps. If we found an app window above, that gives us the
1032        // position; else we need to look some more.
1033        if (pos != null) {
1034            // Move behind any windows attached to this one.
1035            final WindowToken atoken = getWindowToken(pos.mClient.asBinder());
1036            if (atoken != null) {
1037                tokenWindowList = getTokenWindowsOnDisplay(atoken);
1038                final int NC = tokenWindowList.size();
1039                if (NC > 0) {
1040                    WindowState bottom = tokenWindowList.get(0);
1041                    if (bottom.mSubLayer < 0) {
1042                        pos = bottom;
1043                    }
1044                }
1045            }
1046            addWindowToListBefore(win, pos);
1047            return 0;
1048        }
1049
1050        // Continue looking down until we find the first token that has windows on this display.
1051        mTmpGetWindowOnDisplaySearchResult.reset();
1052        for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
1053            final TaskStack stack = mTaskStackContainers.get(i);
1054            stack.getWindowOnDisplayAfterToken(this, wToken, mTmpGetWindowOnDisplaySearchResult);
1055            if (mTmpGetWindowOnDisplaySearchResult.foundWindow != null) {
1056                // We have found a window after the token. End search.
1057                break;
1058            }
1059        }
1060
1061        pos = mTmpGetWindowOnDisplaySearchResult.foundWindow;
1062
1063        if (pos != null) {
1064            // Move in front of any windows attached to this one.
1065            final WindowToken atoken = getWindowToken(pos.mClient.asBinder());
1066            if (atoken != null) {
1067                final WindowState top = atoken.getTopWindow();
1068                if (top != null && top.mSubLayer >= 0) {
1069                    pos = top;
1070                }
1071            }
1072            addWindowToListAfter(win, pos);
1073            return 0;
1074        }
1075
1076        // Just search for the start of this layer.
1077        final int myLayer = win.mBaseLayer;
1078        int i;
1079        for (i = mWindows.size() - 1; i >= 0; --i) {
1080            final WindowState w = mWindows.get(i);
1081            // Dock divider shares the base layer with application windows, but we want to always
1082            // keep it above the application windows. The sharing of the base layer is intended
1083            // for window animations, which need to be above the dock divider for the duration
1084            // of the animation.
1085            if (w.mBaseLayer <= myLayer && w.mAttrs.type != TYPE_DOCK_DIVIDER) {
1086                break;
1087            }
1088        }
1089        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
1090                "Based on layer: Adding window " + win + " at " + (i + 1) + " of "
1091                + mWindows.size());
1092        mWindows.add(i + 1, win);
1093        mService.mWindowsChanged = true;
1094        return 0;
1095    }
1096
1097    /** Adds this non-app window to the window list. */
1098    void addNonAppWindowToWindowList(WindowState win) {
1099        // Figure out where window should go, based on layer.
1100        int i;
1101        for (i = mWindows.size() - 1; i >= 0; i--) {
1102            final WindowState otherWin = mWindows.get(i);
1103            if (otherWin.getBaseType() != TYPE_WALLPAPER && otherWin.mBaseLayer <= win.mBaseLayer) {
1104                // Wallpaper wanders through the window list, for example to position itself
1105                // directly behind keyguard. Because of this it will break the ordering based on
1106                // WindowState.mBaseLayer. There might windows with higher mBaseLayer behind it and
1107                // we don't want the new window to appear above them. An example of this is adding
1108                // of the docked stack divider. Consider a scenario with the following ordering (top
1109                // to bottom): keyguard, wallpaper, assist preview, apps. We want the dock divider
1110                // to land below the assist preview, so the dock divider must ignore the wallpaper,
1111                // with which it shares the base layer.
1112                break;
1113            }
1114        }
1115
1116        i++;
1117        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
1118                "Free window: Adding window " + this + " at " + i + " of " + mWindows.size());
1119        mWindows.add(i, win);
1120        mService.mWindowsChanged = true;
1121    }
1122
1123    void addToWindowList(WindowState win, int index) {
1124        mWindows.add(index, win);
1125    }
1126
1127    boolean removeFromWindowList(WindowState win) {
1128        return mWindows.remove(win);
1129    }
1130
1131    private int removeWindowAndChildrenFromWindowList(WindowState win, int interestingPos) {
1132        final WindowList windows = getWindowList();
1133        int wpos = windows.indexOf(win);
1134        if (wpos < 0) {
1135            return interestingPos;
1136        }
1137
1138        if (wpos < interestingPos) interestingPos--;
1139        if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Temp removing at " + wpos + ": " + this);
1140        windows.remove(wpos);
1141        mService.mWindowsChanged = true;
1142        int childWinCount = win.mChildren.size();
1143        while (childWinCount > 0) {
1144            childWinCount--;
1145            final WindowState cw = win.mChildren.get(childWinCount);
1146            int cpos = windows.indexOf(cw);
1147            if (cpos >= 0) {
1148                if (cpos < interestingPos) interestingPos--;
1149                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM,
1150                        "Temp removing child at " + cpos + ": " + cw);
1151                windows.remove(cpos);
1152            }
1153        }
1154        return interestingPos;
1155    }
1156
1157    void addChildWindowToWindowList(WindowState win) {
1158        final WindowState parentWindow = win.getParentWindow();
1159
1160        WindowList windowsOnSameDisplay = getTokenWindowsOnDisplay(win.mToken);
1161
1162        // Figure out this window's ordering relative to the parent window.
1163        final int wCount = windowsOnSameDisplay.size();
1164        final int sublayer = win.mSubLayer;
1165        int largestSublayer = Integer.MIN_VALUE;
1166        WindowState windowWithLargestSublayer = null;
1167        int i;
1168        for (i = 0; i < wCount; i++) {
1169            WindowState w = windowsOnSameDisplay.get(i);
1170            final int wSublayer = w.mSubLayer;
1171            if (wSublayer >= largestSublayer) {
1172                largestSublayer = wSublayer;
1173                windowWithLargestSublayer = w;
1174            }
1175            if (sublayer < 0) {
1176                // For negative sublayers, we go below all windows in the same sublayer.
1177                if (wSublayer >= sublayer) {
1178                    addWindowToListBefore(win, wSublayer >= 0 ? parentWindow : w);
1179                    break;
1180                }
1181            } else {
1182                // For positive sublayers, we go above all windows in the same sublayer.
1183                if (wSublayer > sublayer) {
1184                    addWindowToListBefore(win, w);
1185                    break;
1186                }
1187            }
1188        }
1189        if (i >= wCount) {
1190            if (sublayer < 0) {
1191                addWindowToListBefore(win, parentWindow);
1192            } else {
1193                addWindowToListAfter(win,
1194                        largestSublayer >= 0 ? windowWithLargestSublayer : parentWindow);
1195            }
1196        }
1197    }
1198
1199    /** Updates the layer assignment of windows on this display. */
1200    void assignWindowLayers(boolean setLayoutNeeded) {
1201        mLayersController.assignWindowLayers(mWindows);
1202        if (setLayoutNeeded) {
1203            setLayoutNeeded();
1204        }
1205    }
1206
1207    /**
1208     * Z-orders the display window list so that:
1209     * <ul>
1210     * <li>Any windows that are currently below the wallpaper window stay below the wallpaper
1211     *      window.
1212     * <li>Exiting application windows are at the bottom, but above the wallpaper window.
1213     * <li>All other application windows are above the exiting application windows and ordered based
1214     *      on the ordering of their stacks and tasks on the display.
1215     * <li>Non-application windows are at the very top.
1216     * </ul>
1217     * <p>
1218     * NOTE: This isn't a complete picture of what the user see. Further manipulation of the window
1219     *       surface layering is done in {@link WindowLayersController}.
1220     */
1221    void rebuildAppWindowList() {
1222        int count = mWindows.size();
1223        int i;
1224        int lastBelow = -1;
1225        int numRemoved = 0;
1226
1227        if (mRebuildTmp.length < count) {
1228            mRebuildTmp = new WindowState[count + 10];
1229        }
1230
1231        // First remove all existing app windows.
1232        i = 0;
1233        while (i < count) {
1234            final WindowState w = mWindows.get(i);
1235            if (w.mAppToken != null) {
1236                final WindowState win = mWindows.remove(i);
1237                win.mRebuilding = true;
1238                mRebuildTmp[numRemoved] = win;
1239                mService.mWindowsChanged = true;
1240                if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "Rebuild removing window: " + win);
1241                count--;
1242                numRemoved++;
1243                continue;
1244            } else if (lastBelow == i-1) {
1245                if (w.mAttrs.type == TYPE_WALLPAPER) {
1246                    lastBelow = i;
1247                }
1248            }
1249            i++;
1250        }
1251
1252        // Keep whatever windows were below the app windows still below, by skipping them.
1253        lastBelow++;
1254        i = lastBelow;
1255
1256        // First add all of the exiting app tokens...  these are no longer in the main app list,
1257        // but still have windows shown. We put them in the back because now that the animation is
1258        // over we no longer will care about them.
1259        final int numStacks = mTaskStackContainers.size();
1260        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1261            AppTokenList exitingAppTokens = mTaskStackContainers.get(stackNdx).mExitingAppTokens;
1262            int NT = exitingAppTokens.size();
1263            for (int j = 0; j < NT; j++) {
1264                i = exitingAppTokens.get(j).rebuildWindowListUnchecked(i);
1265            }
1266        }
1267
1268        // And add in the still active app tokens in Z order.
1269        for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
1270            i = mTaskStackContainers.get(stackNdx).rebuildWindowList(i);
1271        }
1272
1273        i -= lastBelow;
1274        if (i != numRemoved) {
1275            setLayoutNeeded();
1276            Slog.w(TAG_WM, "On display=" + mDisplayId + " Rebuild removed " + numRemoved
1277                    + " windows but added " + i + " rebuildAppWindowListLocked() "
1278                    + " callers=" + Debug.getCallers(10));
1279            for (i = 0; i < numRemoved; i++) {
1280                WindowState ws = mRebuildTmp[i];
1281                if (ws.mRebuilding) {
1282                    StringWriter sw = new StringWriter();
1283                    PrintWriter pw = new FastPrintWriter(sw, false, 1024);
1284                    ws.dump(pw, "", true);
1285                    pw.flush();
1286                    Slog.w(TAG_WM, "This window was lost: " + ws);
1287                    Slog.w(TAG_WM, sw.toString());
1288                    ws.mWinAnimator.destroySurfaceLocked();
1289                }
1290            }
1291            Slog.w(TAG_WM, "Current window hierarchy:");
1292            dumpChildrenNames();
1293            Slog.w(TAG_WM, "Final window list:");
1294            dumpWindows();
1295        }
1296        Arrays.fill(mRebuildTmp, null);
1297    }
1298
1299    /** Return the list of Windows on this display associated with the input token. */
1300    WindowList getTokenWindowsOnDisplay(WindowToken token) {
1301        final WindowList windowList = new WindowList();
1302        final int count = mWindows.size();
1303        for (int i = 0; i < count; i++) {
1304            final WindowState win = mWindows.get(i);
1305            if (win.mToken == token) {
1306                windowList.add(win);
1307            }
1308        }
1309        return windowList;
1310    }
1311
1312    private void reAddToWindowList(WindowState win) {
1313        win.mToken.addWindow(win);
1314        // This is a hack to get all of the child windows added as well at the right position. Child
1315        // windows should be rare and this case should be rare, so it shouldn't be that big a deal.
1316        int wpos = mWindows.indexOf(win);
1317        if (wpos >= 0) {
1318            if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG_WM, "ReAdd removing from " + wpos + ": " + win);
1319            mWindows.remove(wpos);
1320            mService.mWindowsChanged = true;
1321            win.reAddWindow(wpos);
1322        }
1323    }
1324
1325    void moveInputMethodDialogs(int pos) {
1326        ArrayList<WindowState> dialogs = mService.mInputMethodDialogs;
1327
1328        final int N = dialogs.size();
1329        if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Removing " + N + " dialogs w/pos=" + pos);
1330        for (int i = 0; i < N; i++) {
1331            pos = removeWindowAndChildrenFromWindowList(dialogs.get(i), pos);
1332        }
1333        if (DEBUG_INPUT_METHOD) {
1334            Slog.v(TAG_WM, "Window list w/pos=" + pos);
1335            logWindowList(mWindows, "  ");
1336        }
1337
1338        WindowState ime = mService.mInputMethodWindow;
1339        if (pos >= 0) {
1340            // Skip windows owned by the input method.
1341            if (ime != null) {
1342                while (pos < mWindows.size()) {
1343                    WindowState wp = mWindows.get(pos);
1344                    if (wp == ime || wp.getParentWindow() == ime) {
1345                        pos++;
1346                        continue;
1347                    }
1348                    break;
1349                }
1350            }
1351            if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Adding " + N + " dialogs at pos=" + pos);
1352            for (int i=0; i<N; i++) {
1353                WindowState win = dialogs.get(i);
1354                pos = win.reAddWindow(pos);
1355            }
1356            if (DEBUG_INPUT_METHOD) {
1357                Slog.v(TAG_WM, "Final window list:");
1358                logWindowList(mWindows, "  ");
1359            }
1360            return;
1361        }
1362        for (int i=0; i<N; i++) {
1363            WindowState win = dialogs.get(i);
1364            reAddToWindowList(win);
1365            if (DEBUG_INPUT_METHOD) {
1366                Slog.v(TAG_WM, "No IM target, final list:");
1367                logWindowList(mWindows, "  ");
1368            }
1369        }
1370    }
1371
1372    boolean moveInputMethodWindowsIfNeeded(boolean needAssignLayers) {
1373        final WindowState imWin = mService.mInputMethodWindow;
1374        final int DN = mService.mInputMethodDialogs.size();
1375        if (imWin == null && DN == 0) {
1376            return false;
1377        }
1378
1379        // TODO(multidisplay): IMEs are only supported on the default display.
1380        WindowList windows = mWindows;
1381
1382        int imPos = findDesiredInputMethodWindowIndex(true);
1383        if (imPos >= 0) {
1384            // In this case, the input method windows are to be placed
1385            // immediately above the window they are targeting.
1386
1387            // First check to see if the input method windows are already
1388            // located here, and contiguous.
1389            final int N = windows.size();
1390            final WindowState firstImWin = imPos < N ? windows.get(imPos) : null;
1391
1392            // Figure out the actual input method window that should be
1393            // at the bottom of their stack.
1394            WindowState baseImWin = imWin != null ? imWin : mService.mInputMethodDialogs.get(0);
1395            final WindowState cw = baseImWin.getBottomChild();
1396            if (cw != null && cw.mSubLayer < 0) {
1397                baseImWin = cw;
1398            }
1399
1400            if (firstImWin == baseImWin) {
1401                // The windows haven't moved...  but are they still contiguous?
1402                // First find the top IM window.
1403                int pos = imPos+1;
1404                while (pos < N) {
1405                    if (!(windows.get(pos)).mIsImWindow) {
1406                        break;
1407                    }
1408                    pos++;
1409                }
1410                pos++;
1411                // Now there should be no more input method windows above.
1412                while (pos < N) {
1413                    if ((windows.get(pos)).mIsImWindow) {
1414                        break;
1415                    }
1416                    pos++;
1417                }
1418                if (pos >= N) {
1419                    return false;
1420                }
1421            }
1422
1423            if (imWin != null) {
1424                if (DEBUG_INPUT_METHOD) {
1425                    Slog.v(TAG_WM, "Moving IM from " + imPos);
1426                    logWindowList(windows, "  ");
1427                }
1428                imPos = removeWindowAndChildrenFromWindowList(imWin, imPos);
1429                if (DEBUG_INPUT_METHOD) {
1430                    Slog.v(TAG_WM, "List after removing with new pos " + imPos + ":");
1431                    logWindowList(windows, "  ");
1432                }
1433                imWin.reAddWindow(imPos);
1434                if (DEBUG_INPUT_METHOD) {
1435                    Slog.v(TAG_WM, "List after moving IM to " + imPos + ":");
1436                    logWindowList(windows, "  ");
1437                }
1438                if (DN > 0) moveInputMethodDialogs(imPos+1);
1439            } else {
1440                moveInputMethodDialogs(imPos);
1441            }
1442
1443        } else {
1444            // In this case, the input method windows go in a fixed layer,
1445            // because they aren't currently associated with a focus window.
1446
1447            if (imWin != null) {
1448                if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Moving IM from " + imPos);
1449                removeWindowAndChildrenFromWindowList(imWin, 0);
1450                reAddToWindowList(imWin);
1451                if (DEBUG_INPUT_METHOD) {
1452                    Slog.v(TAG_WM, "List with no IM target:");
1453                    logWindowList(windows, "  ");
1454                }
1455                if (DN > 0) moveInputMethodDialogs(-1);
1456            } else {
1457                moveInputMethodDialogs(-1);
1458            }
1459
1460        }
1461
1462        if (needAssignLayers) {
1463            assignWindowLayers(false /* setLayoutNeeded */);
1464        }
1465
1466        return true;
1467    }
1468
1469    /**
1470     * Dig through the WindowStates and find the one that the Input Method will target.
1471     * @param willMove
1472     * @return The index+1 in mWindows of the discovered target.
1473     */
1474    int findDesiredInputMethodWindowIndex(boolean willMove) {
1475        // TODO(multidisplay): Needs some serious rethought when the target and IME are not on the
1476        // same display. Or even when the current IME/target are not on the same screen as the next
1477        // IME/target. For now only look for input windows on the main screen.
1478        final WindowList windows = getWindowList();
1479        WindowState w = null;
1480        int i;
1481        for (i = windows.size() - 1; i >= 0; --i) {
1482            WindowState win = windows.get(i);
1483
1484            if (DEBUG_INPUT_METHOD && willMove) Slog.i(TAG_WM, "Checking window @" + i
1485                    + " " + win + " fl=0x" + Integer.toHexString(win.mAttrs.flags));
1486            if (canBeImeTarget(win)) {
1487                w = win;
1488                //Slog.i(TAG_WM, "Putting input method here!");
1489
1490                // Yet more tricksyness!  If this window is a "starting" window, we do actually want
1491                // to be on top of it, but it is not -really- where input will go.  So if the caller
1492                // is not actually looking to move the IME, look down below for a real window to
1493                // target...
1494                if (!willMove && w.mAttrs.type == TYPE_APPLICATION_STARTING && i > 0) {
1495                    WindowState wb = windows.get(i-1);
1496                    if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) {
1497                        i--;
1498                        w = wb;
1499                    }
1500                }
1501                break;
1502            }
1503        }
1504
1505        // Now w is either mWindows[0] or an IME (or null if mWindows is empty).
1506
1507        if (DEBUG_INPUT_METHOD && willMove) Slog.v(TAG_WM, "Proposed new IME target: " + w);
1508
1509        // Now, a special case -- if the last target's window is in the process of exiting, and is
1510        // above the new target, keep on the last target to avoid flicker. Consider for example a
1511        // Dialog with the IME shown: when the Dialog is dismissed, we want to keep the IME above it
1512        // until it is completely gone so it doesn't drop behind the dialog or its full-screen
1513        // scrim.
1514        final WindowState curTarget = mService.mInputMethodTarget;
1515        if (curTarget != null
1516                && curTarget.isDisplayedLw()
1517                && curTarget.isClosing()
1518                && (w == null || curTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer)) {
1519            if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Current target higher, not changing");
1520            return windows.indexOf(curTarget) + 1;
1521        }
1522
1523        if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Desired input method target="
1524                + w + " willMove=" + willMove);
1525
1526        if (willMove && w != null) {
1527            AppWindowToken token = curTarget == null ? null : curTarget.mAppToken;
1528            if (token != null) {
1529
1530                // Now some fun for dealing with window animations that modify the Z order. We need
1531                // to look at all windows below the current target that are in this app, finding the
1532                // highest visible one in layering.
1533                WindowState highestTarget = null;
1534                int highestPos = 0;
1535                if (token.mAppAnimator.animating || token.mAppAnimator.animation != null) {
1536                    WindowList curWindows = token.getDisplayContent().getWindowList();
1537                    int pos = curWindows.indexOf(curTarget);
1538                    while (pos >= 0) {
1539                        WindowState win = curWindows.get(pos);
1540                        if (win.mAppToken != token) {
1541                            break;
1542                        }
1543                        if (!win.mRemoved) {
1544                            if (highestTarget == null || win.mWinAnimator.mAnimLayer >
1545                                    highestTarget.mWinAnimator.mAnimLayer) {
1546                                highestTarget = win;
1547                                highestPos = pos;
1548                            }
1549                        }
1550                        pos--;
1551                    }
1552                }
1553
1554                if (highestTarget != null) {
1555                    final AppTransition appTransition = mService.mAppTransition;
1556                    if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, appTransition + " " + highestTarget
1557                            + " animating=" + highestTarget.mWinAnimator.isAnimationSet()
1558                            + " layer=" + highestTarget.mWinAnimator.mAnimLayer
1559                            + " new layer=" + w.mWinAnimator.mAnimLayer);
1560
1561                    if (appTransition.isTransitionSet()) {
1562                        // If we are currently setting up for an animation, hold everything until we
1563                        // can find out what will happen.
1564                        mService.mInputMethodTargetWaitingAnim = true;
1565                        mService.mInputMethodTarget = highestTarget;
1566                        return highestPos + 1;
1567                    } else if (highestTarget.mWinAnimator.isAnimationSet() &&
1568                            highestTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer) {
1569                        // If the window we are currently targeting is involved with an animation,
1570                        // and it is on top of the next target we will be over, then hold off on
1571                        // moving until that is done.
1572                        mService.mInputMethodTargetWaitingAnim = true;
1573                        mService.mInputMethodTarget = highestTarget;
1574                        return highestPos + 1;
1575                    }
1576                }
1577            }
1578        }
1579
1580        //Slog.i(TAG_WM, "Placing input method @" + (i+1));
1581        if (w != null) {
1582            if (willMove) {
1583                if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + " to "
1584                        + w + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : ""));
1585                mService.mInputMethodTarget = w;
1586                mService.mInputMethodTargetWaitingAnim = false;
1587                if (w.mAppToken != null) {
1588                    setInputMethodAnimLayerAdjustment(
1589                            w.mAppToken.mAppAnimator.animLayerAdjustment);
1590                } else {
1591                    setInputMethodAnimLayerAdjustment(0);
1592                }
1593            }
1594
1595            // If the docked divider is visible, we still need to go through this whole excercise to
1596            // find the appropriate input method target (used for animations and dialog
1597            // adjustments), but for purposes of Z ordering we simply wish to place it above the
1598            // docked divider. Unless it is already above the divider.
1599            final WindowState dockedDivider = mDividerControllerLocked.getWindow();
1600            if (dockedDivider != null && dockedDivider.isVisibleLw()) {
1601                int dividerIndex = windows.indexOf(dockedDivider);
1602                if (dividerIndex > 0 && dividerIndex > i) {
1603                    return dividerIndex + 1;
1604                }
1605            }
1606            return i+1;
1607        }
1608        if (willMove) {
1609            if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget
1610                    + " to null." + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : ""));
1611            mService.mInputMethodTarget = null;
1612            setInputMethodAnimLayerAdjustment(0);
1613        }
1614        return -1;
1615    }
1616
1617    private static boolean canBeImeTarget(WindowState w) {
1618        final int fl = w.mAttrs.flags & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
1619        final int type = w.mAttrs.type;
1620
1621        if (fl != 0 && fl != (FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM)
1622                && type != TYPE_APPLICATION_STARTING) {
1623            return false;
1624        }
1625
1626        if (DEBUG_INPUT_METHOD) {
1627            Slog.i(TAG_WM, "isVisibleOrAdding " + w + ": " + w.isVisibleOrAdding());
1628            if (!w.isVisibleOrAdding()) {
1629                Slog.i(TAG_WM, "  mSurfaceController=" + w.mWinAnimator.mSurfaceController
1630                        + " relayoutCalled=" + w.mRelayoutCalled
1631                        + " viewVis=" + w.mViewVisibility
1632                        + " policyVis=" + w.mPolicyVisibility
1633                        + " policyVisAfterAnim=" + w.mPolicyVisibilityAfterAnim
1634                        + " parentHidden=" + w.isParentWindowHidden()
1635                        + " exiting=" + w.mAnimatingExit + " destroying=" + w.mDestroying);
1636                if (w.mAppToken != null) {
1637                    Slog.i(TAG_WM, "  mAppToken.hiddenRequested=" + w.mAppToken.hiddenRequested);
1638                }
1639            }
1640        }
1641        return w.isVisibleOrAdding();
1642    }
1643
1644    private void logWindowList(final WindowList windows, String prefix) {
1645        int N = windows.size();
1646        while (N > 0) {
1647            N--;
1648            Slog.v(TAG_WM, prefix + "#" + N + ": " + windows.get(N));
1649        }
1650    }
1651
1652    boolean getNeedsMenu(WindowState win, WindowManagerPolicy.WindowState bottom) {
1653        int index = -1;
1654        WindowList windows = getWindowList();
1655        while (true) {
1656            if (win.mAttrs.needsMenuKey != NEEDS_MENU_UNSET) {
1657                return win.mAttrs.needsMenuKey == NEEDS_MENU_SET_TRUE;
1658            }
1659            // If we reached the bottom of the range of windows we are considering,
1660            // assume no menu is needed.
1661            if (win == bottom) {
1662                return false;
1663            }
1664            // The current window hasn't specified whether menu key is needed; look behind it.
1665            // First, we may need to determine the starting position.
1666            if (index < 0) {
1667                index = windows.indexOf(win);
1668            }
1669            index--;
1670            if (index < 0) {
1671                return false;
1672            }
1673            win = windows.get(index);
1674        }
1675    }
1676
1677    void setLayoutNeeded() {
1678        if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3));
1679        mLayoutNeeded = true;
1680    }
1681
1682    void clearLayoutNeeded() {
1683        if (DEBUG_LAYOUT) Slog.w(TAG_WM, "clearLayoutNeeded: callers=" + Debug.getCallers(3));
1684        mLayoutNeeded = false;
1685    }
1686
1687    boolean isLayoutNeeded() {
1688        return mLayoutNeeded;
1689    }
1690
1691    private int addAppWindowExisting(WindowState win, WindowList tokenWindowList) {
1692
1693        int tokenWindowsPos;
1694        // If this application has existing windows, we simply place the new window on top of
1695        // them... but keep the starting window on top.
1696        if (win.mAttrs.type == TYPE_BASE_APPLICATION) {
1697            // Base windows go behind everything else.
1698            final WindowState lowestWindow = tokenWindowList.get(0);
1699            addWindowToListBefore(win, lowestWindow);
1700            tokenWindowsPos = win.mToken.getWindowIndex(lowestWindow);
1701        } else {
1702            final AppWindowToken atoken = win.mAppToken;
1703            final int windowListPos = tokenWindowList.size();
1704            final WindowState lastWindow = tokenWindowList.get(windowListPos - 1);
1705            if (atoken != null && lastWindow == atoken.startingWindow) {
1706                addWindowToListBefore(win, lastWindow);
1707                tokenWindowsPos = win.mToken.getWindowIndex(lastWindow);
1708            } else {
1709                int newIdx = findIdxBasedOnAppTokens(win);
1710                // There is a window above this one associated with the same apptoken note that the
1711                // window could be a floating window that was created later or a window at the top
1712                // of the list of windows associated with this token.
1713                if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
1714                        "not Base app: Adding window " + win + " at " + (newIdx + 1) + " of "
1715                                + mWindows.size());
1716                mWindows.add(newIdx + 1, win);
1717                if (newIdx < 0) {
1718                    // No window from token found on win's display.
1719                    tokenWindowsPos = 0;
1720                } else {
1721                    tokenWindowsPos = win.mToken.getWindowIndex(mWindows.get(newIdx)) + 1;
1722                }
1723                mService.mWindowsChanged = true;
1724            }
1725        }
1726        return tokenWindowsPos;
1727    }
1728
1729    /** Places the first input window after the second input window in the window list. */
1730    private void addWindowToListAfter(WindowState first, WindowState second) {
1731        final int i = mWindows.indexOf(second);
1732        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
1733                "Adding window " + this + " at " + (i + 1) + " of " + mWindows.size()
1734                + " (after " + second + ")");
1735        mWindows.add(i + 1, first);
1736        mService.mWindowsChanged = true;
1737    }
1738
1739    /** Places the first input window before the second input window in the window list. */
1740    private void addWindowToListBefore(WindowState first, WindowState second) {
1741        int i = mWindows.indexOf(second);
1742        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
1743                "Adding window " + this + " at " + i + " of " + mWindows.size()
1744                + " (before " + second + ")");
1745        if (i < 0) {
1746            Slog.w(TAG_WM, "addWindowToListBefore: Unable to find " + second + " in " + mWindows);
1747            i = 0;
1748        }
1749        mWindows.add(i, first);
1750        mService.mWindowsChanged = true;
1751    }
1752
1753    /**
1754     * This method finds out the index of a window that has the same app token as win. used for z
1755     * ordering the windows in mWindows
1756     */
1757    private int findIdxBasedOnAppTokens(WindowState win) {
1758        for(int j = mWindows.size() - 1; j >= 0; j--) {
1759            final WindowState wentry = mWindows.get(j);
1760            if(wentry.mAppToken == win.mAppToken) {
1761                return j;
1762            }
1763        }
1764        return -1;
1765    }
1766
1767    private void dumpChildrenNames() {
1768        StringBuilder output = new StringBuilder();
1769        dumpChildrenNames(output, " ");
1770        Slog.v(TAG_WM, output.toString());
1771    }
1772
1773    private void dumpWindows() {
1774        Slog.v(TAG_WM, " Display #" + mDisplayId);
1775        final WindowList windows = getWindowList();
1776        for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
1777            Slog.v(TAG_WM, "  #" + winNdx + ": " + windows.get(winNdx));
1778        }
1779    }
1780
1781    void dumpTokens(PrintWriter pw, boolean dumpAll) {
1782        if (mTokenMap.isEmpty()) {
1783            return;
1784        }
1785        pw.println("  Display #" + mDisplayId);
1786        final Iterator<WindowToken> it = mTokenMap.values().iterator();
1787        while (it.hasNext()) {
1788            final WindowToken token = it.next();
1789            pw.print("  ");
1790            pw.print(token);
1791            if (dumpAll) {
1792                pw.println(':');
1793                token.dump(pw, "    ");
1794            } else {
1795                pw.println();
1796            }
1797        }
1798    }
1799
1800    void enableSurfaceTrace(FileDescriptor fd) {
1801        for (int i = mWindows.size() - 1; i >= 0; i--) {
1802            final WindowState win = mWindows.get(i);
1803            win.mWinAnimator.enableSurfaceTrace(fd);
1804        }
1805    }
1806
1807    void disableSurfaceTrace() {
1808        for (int i = mWindows.size() - 1; i >= 0; i--) {
1809            final WindowState win = mWindows.get(i);
1810            win.mWinAnimator.disableSurfaceTrace();
1811        }
1812    }
1813
1814    static final class GetWindowOnDisplaySearchResult {
1815        boolean reachedToken;
1816        WindowState foundWindow;
1817
1818        void reset() {
1819            reachedToken = false;
1820            foundWindow = null;
1821        }
1822    }
1823
1824    static final class TaskForResizePointSearchResult {
1825        boolean searchDone;
1826        Task taskForResize;
1827
1828        void reset() {
1829            searchDone = false;
1830            taskForResize = null;
1831        }
1832    }
1833
1834    /**
1835     * Base class for any direct child window container of {@link #DisplayContent} need to inherit
1836     * from. This is mainly a pass through class that allows {@link #DisplayContent} to have
1837     * homogeneous children type which is currently required by sub-classes of
1838     * {@link WindowContainer} class.
1839     */
1840    static class DisplayChildWindowContainer<E extends WindowContainer> extends WindowContainer<E> {
1841
1842        int size() {
1843            return mChildren.size();
1844        }
1845
1846        E get(int index) {
1847            return mChildren.get(index);
1848        }
1849
1850        @Override
1851        boolean fillsParent() {
1852            return true;
1853        }
1854
1855        @Override
1856        boolean isVisible() {
1857            return true;
1858        }
1859    }
1860
1861    /**
1862     * Window container class that contains all containers on this display relating to Apps.
1863     * I.e Activities.
1864     */
1865    private class TaskStackContainers extends DisplayChildWindowContainer<TaskStack> {
1866
1867        void attachStack(TaskStack stack, boolean onTop) {
1868            if (stack.mStackId == HOME_STACK_ID) {
1869                if (mHomeStack != null) {
1870                    throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
1871                }
1872                mHomeStack = stack;
1873            }
1874            addChild(stack, onTop);
1875            stack.onDisplayChanged(DisplayContent.this);
1876        }
1877
1878        void moveStack(TaskStack stack, boolean toTop) {
1879            if (StackId.isAlwaysOnTop(stack.mStackId) && !toTop) {
1880                // This stack is always-on-top silly...
1881                Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + stack + " to bottom");
1882                return;
1883            }
1884
1885            if (!mChildren.contains(stack)) {
1886                Slog.wtf(TAG_WM, "moving stack that was not added: " + stack, new Throwable());
1887            }
1888            removeChild(stack);
1889            addChild(stack, toTop);
1890        }
1891
1892        private void addChild(TaskStack stack, boolean toTop) {
1893            int addIndex = toTop ? mChildren.size() : 0;
1894
1895            if (toTop
1896                    && mService.isStackVisibleLocked(PINNED_STACK_ID)
1897                    && stack.mStackId != PINNED_STACK_ID) {
1898                // The pinned stack is always the top most stack (always-on-top) when it is visible.
1899                // So, stack is moved just below the pinned stack.
1900                addIndex--;
1901                TaskStack topStack = mChildren.get(addIndex);
1902                if (topStack.mStackId != PINNED_STACK_ID) {
1903                    throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren);
1904                }
1905            }
1906            addChild(stack, addIndex);
1907            setLayoutNeeded();
1908        }
1909
1910    }
1911
1912    /**
1913     * Window container class that contains all containers on this display that are not related to
1914     * Apps. E.g. status bar.
1915     */
1916    private static class NonAppWindowContainers extends DisplayChildWindowContainer<WindowToken> {
1917
1918    }
1919}
1920