Home | History | Annotate | Download | only in wm
      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 
     17 package com.android.server.wm;
     18 
     19 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
     20 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
     21 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
     22 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
     23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
     24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
     25 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
     26 import static android.view.Display.DEFAULT_DISPLAY;
     27 import static android.view.Display.FLAG_PRIVATE;
     28 import static android.view.Surface.ROTATION_0;
     29 import static android.view.Surface.ROTATION_180;
     30 import static android.view.Surface.ROTATION_270;
     31 import static android.view.Surface.ROTATION_90;
     32 import static android.view.View.GONE;
     33 import static android.view.WindowManager.DOCKED_BOTTOM;
     34 import static android.view.WindowManager.DOCKED_INVALID;
     35 import static android.view.WindowManager.DOCKED_TOP;
     36 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
     37 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
     38 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
     39 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
     40 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
     41 import static android.view.WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE;
     42 import static android.view.WindowManager.LayoutParams.NEEDS_MENU_UNSET;
     43 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
     44 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
     45 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
     46 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
     47 import static android.view.WindowManager.LayoutParams.TYPE_DRAWN_APPLICATION;
     48 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
     49 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
     50 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
     51 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
     52 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
     53 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
     54 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
     55 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
     56 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
     57 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
     58 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
     59 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
     60 import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_UNOCCLUDE;
     61 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
     62 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
     63 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
     64 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
     65 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
     66 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
     67 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
     68 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
     69 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
     70 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
     71 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
     72 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
     73 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
     74 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
     75 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
     76 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
     77 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
     78 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
     79 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
     80 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
     81 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     82 import static com.android.server.wm.WindowManagerService.CUSTOM_SCREEN_ROTATION;
     83 import static com.android.server.wm.WindowManagerService.H.SEND_NEW_CONFIGURATION;
     84 import static com.android.server.wm.WindowManagerService.H.UPDATE_DOCKED_STACK_DIVIDER;
     85 import static com.android.server.wm.WindowManagerService.H.WINDOW_HIDE_TIMEOUT;
     86 import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
     87 import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
     88 import static com.android.server.wm.WindowManagerService.SEAMLESS_ROTATION_TIMEOUT_DURATION;
     89 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
     90 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
     91 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
     92 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_ACTIVE;
     93 import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_TIMEOUT;
     94 import static com.android.server.wm.WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION;
     95 import static com.android.server.wm.WindowManagerService.dipToPixel;
     96 import static com.android.server.wm.WindowManagerService.logSurface;
     97 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
     98 import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;
     99 import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
    100 import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
    101 
    102 import android.annotation.NonNull;
    103 import android.app.ActivityManager.StackId;
    104 import android.content.res.CompatibilityInfo;
    105 import android.content.res.Configuration;
    106 import android.graphics.Bitmap;
    107 import android.graphics.GraphicBuffer;
    108 import android.graphics.Matrix;
    109 import android.graphics.Rect;
    110 import android.graphics.RectF;
    111 import android.graphics.Region;
    112 import android.graphics.Region.Op;
    113 import android.hardware.display.DisplayManagerInternal;
    114 import android.os.Debug;
    115 import android.os.Handler;
    116 import android.os.IBinder;
    117 import android.os.RemoteException;
    118 import android.os.SystemClock;
    119 import android.util.DisplayMetrics;
    120 import android.util.MutableBoolean;
    121 import android.util.Slog;
    122 import android.view.Display;
    123 import android.view.DisplayInfo;
    124 import android.view.InputDevice;
    125 import android.view.Surface;
    126 import android.view.SurfaceControl;
    127 import android.view.WindowManagerPolicy;
    128 
    129 import com.android.internal.annotations.VisibleForTesting;
    130 import com.android.internal.util.ToBooleanFunction;
    131 import com.android.internal.view.IInputMethodClient;
    132 
    133 import java.io.FileDescriptor;
    134 import java.io.PrintWriter;
    135 import java.util.ArrayList;
    136 import java.util.Comparator;
    137 import java.util.HashMap;
    138 import java.util.Iterator;
    139 import java.util.LinkedList;
    140 import java.util.List;
    141 import java.util.function.Consumer;
    142 import java.util.function.Predicate;
    143 
    144 /**
    145  * Utility class for keeping track of the WindowStates and other pertinent contents of a
    146  * particular Display.
    147  *
    148  * IMPORTANT: No method from this class should ever be used without holding
    149  * WindowManagerService.mWindowMap.
    150  */
    151 class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowContainer> {
    152     private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayContent" : TAG_WM;
    153 
    154     /** Unique identifier of this stack. */
    155     private final int mDisplayId;
    156 
    157     /** The containers below are the only child containers the display can have. */
    158     // Contains all window containers that are related to apps (Activities)
    159     private final TaskStackContainers mTaskStackContainers = new TaskStackContainers();
    160     // Contains all non-app window containers that should be displayed above the app containers
    161     // (e.g. Status bar)
    162     private final NonAppWindowContainers mAboveAppWindowsContainers =
    163             new NonAppWindowContainers("mAboveAppWindowsContainers");
    164     // Contains all non-app window containers that should be displayed below the app containers
    165     // (e.g. Wallpaper).
    166     private final NonAppWindowContainers mBelowAppWindowsContainers =
    167             new NonAppWindowContainers("mBelowAppWindowsContainers");
    168     // Contains all IME window containers. Note that the z-ordering of the IME windows will depend
    169     // on the IME target. We mainly have this container grouping so we can keep track of all the IME
    170     // window containers together and move them in-sync if/when needed.
    171     private final NonAppWindowContainers mImeWindowsContainers =
    172             new NonAppWindowContainers("mImeWindowsContainers");
    173 
    174     private WindowState mTmpWindow;
    175     private WindowState mTmpWindow2;
    176     private WindowAnimator mTmpWindowAnimator;
    177     private boolean mTmpRecoveringMemory;
    178     private boolean mUpdateImeTarget;
    179     private boolean mTmpInitial;
    180     private int mMaxUiWidth;
    181 
    182     // Mapping from a token IBinder to a WindowToken object on this display.
    183     private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap();
    184 
    185     // Initial display metrics.
    186     int mInitialDisplayWidth = 0;
    187     int mInitialDisplayHeight = 0;
    188     int mInitialDisplayDensity = 0;
    189 
    190     /**
    191      * Overridden display size. Initialized with {@link #mInitialDisplayWidth}
    192      * and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size".
    193      * @see WindowManagerService#setForcedDisplaySize(int, int, int)
    194      */
    195     int mBaseDisplayWidth = 0;
    196     int mBaseDisplayHeight = 0;
    197     /**
    198      * Overridden display density for current user. Initialized with {@link #mInitialDisplayDensity}
    199      * but can be set from Settings or via shell command "adb shell wm density".
    200      * @see WindowManagerService#setForcedDisplayDensityForUser(int, int, int)
    201      */
    202     int mBaseDisplayDensity = 0;
    203     boolean mDisplayScalingDisabled;
    204     private final DisplayInfo mDisplayInfo = new DisplayInfo();
    205     private final Display mDisplay;
    206     private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
    207     /**
    208      * For default display it contains real metrics, empty for others.
    209      * @see WindowManagerService#createWatermarkInTransaction()
    210      */
    211     final DisplayMetrics mRealDisplayMetrics = new DisplayMetrics();
    212     /** @see #computeCompatSmallestWidth(boolean, int, int, int, int) */
    213     private final DisplayMetrics mTmpDisplayMetrics = new DisplayMetrics();
    214 
    215     /**
    216      * Compat metrics computed based on {@link #mDisplayMetrics}.
    217      * @see #updateDisplayAndOrientation(int)
    218      */
    219     private final DisplayMetrics mCompatDisplayMetrics = new DisplayMetrics();
    220 
    221     /** The desired scaling factor for compatible apps. */
    222     float mCompatibleScreenScale;
    223 
    224     /**
    225      * Current rotation of the display.
    226      * Constants as per {@link android.view.Surface.Rotation}.
    227      *
    228      * @see #updateRotationUnchecked(boolean)
    229      */
    230     private int mRotation = 0;
    231 
    232     /**
    233      * Last applied orientation of the display.
    234      * Constants as per {@link android.content.pm.ActivityInfo.ScreenOrientation}.
    235      *
    236      * @see WindowManagerService#updateOrientationFromAppTokensLocked(boolean, int)
    237      */
    238     private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
    239 
    240     /**
    241      * Flag indicating that the application is receiving an orientation that has different metrics
    242      * than it expected. E.g. Portrait instead of Landscape.
    243      *
    244      * @see #updateRotationUnchecked(boolean)
    245      */
    246     private boolean mAltOrientation = false;
    247 
    248     /**
    249      * Orientation forced by some window. If there is no visible window that specifies orientation
    250      * it is set to {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}.
    251      *
    252      * @see NonAppWindowContainers#getOrientation()
    253      */
    254     private int mLastWindowForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
    255 
    256     /**
    257      * Last orientation forced by the keyguard. It is applied when keyguard is shown and is not
    258      * occluded.
    259      *
    260      * @see NonAppWindowContainers#getOrientation()
    261      */
    262     private int mLastKeyguardForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
    263 
    264     /**
    265      * Keep track of wallpaper visibility to notify changes.
    266      */
    267     private boolean mLastWallpaperVisible = false;
    268 
    269     private Rect mBaseDisplayRect = new Rect();
    270     private Rect mContentRect = new Rect();
    271 
    272     // Accessed directly by all users.
    273     private boolean mLayoutNeeded;
    274     int pendingLayoutChanges;
    275     // TODO(multi-display): remove some of the usages.
    276     boolean isDefaultDisplay;
    277 
    278     /** Window tokens that are in the process of exiting, but still on screen for animations. */
    279     final ArrayList<WindowToken> mExitingTokens = new ArrayList<>();
    280 
    281     /** A special TaskStack with id==HOME_STACK_ID that moves to the bottom whenever any TaskStack
    282      * (except a future lockscreen TaskStack) moves to the top. */
    283     private TaskStack mHomeStack = null;
    284 
    285     /** Detect user tapping outside of current focused task bounds .*/
    286     TaskTapPointerEventListener mTapDetector;
    287 
    288     /** Detect user tapping outside of current focused stack bounds .*/
    289     private Region mTouchExcludeRegion = new Region();
    290 
    291     /** Save allocating when calculating rects */
    292     private final Rect mTmpRect = new Rect();
    293     private final Rect mTmpRect2 = new Rect();
    294     private final RectF mTmpRectF = new RectF();
    295     private final Matrix mTmpMatrix = new Matrix();
    296     private final Region mTmpRegion = new Region();
    297 
    298     WindowManagerService mService;
    299 
    300     /** Remove this display when animation on it has completed. */
    301     private boolean mDeferredRemoval;
    302 
    303     final DockedStackDividerController mDividerControllerLocked;
    304     final PinnedStackController mPinnedStackControllerLocked;
    305 
    306     DimLayerController mDimLayerController;
    307 
    308     final ArrayList<WindowState> mTapExcludedWindows = new ArrayList<>();
    309 
    310     private boolean mHaveBootMsg = false;
    311     private boolean mHaveApp = false;
    312     private boolean mHaveWallpaper = false;
    313     private boolean mHaveKeyguard = true;
    314 
    315     private final LinkedList<AppWindowToken> mTmpUpdateAllDrawn = new LinkedList();
    316 
    317     private final TaskForResizePointSearchResult mTmpTaskForResizePointSearchResult =
    318             new TaskForResizePointSearchResult();
    319     private final ApplySurfaceChangesTransactionState mTmpApplySurfaceChangesTransactionState =
    320             new ApplySurfaceChangesTransactionState();
    321     private final ScreenshotApplicationState mScreenshotApplicationState =
    322             new ScreenshotApplicationState();
    323 
    324     // True if this display is in the process of being removed. Used to determine if the removal of
    325     // the display's direct children should be allowed.
    326     private boolean mRemovingDisplay = false;
    327 
    328     // {@code false} if this display is in the processing of being created.
    329     private boolean mDisplayReady = false;
    330 
    331     private final WindowLayersController mLayersController;
    332     WallpaperController mWallpaperController;
    333     int mInputMethodAnimLayerAdjustment;
    334 
    335     private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
    336         WindowStateAnimator winAnimator = w.mWinAnimator;
    337         if (winAnimator.hasSurface()) {
    338             final boolean wasAnimating = winAnimator.mWasAnimating;
    339             final boolean nowAnimating = winAnimator.stepAnimationLocked(
    340                     mTmpWindowAnimator.mCurrentTime);
    341             winAnimator.mWasAnimating = nowAnimating;
    342             mTmpWindowAnimator.orAnimating(nowAnimating);
    343 
    344             if (DEBUG_WALLPAPER) Slog.v(TAG,
    345                     w + ": wasAnimating=" + wasAnimating + ", nowAnimating=" + nowAnimating);
    346 
    347             if (wasAnimating && !winAnimator.mAnimating
    348                     && mWallpaperController.isWallpaperTarget(w)) {
    349                 mTmpWindowAnimator.mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
    350                 pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
    351                 if (DEBUG_LAYOUT_REPEATS) {
    352                     mService.mWindowPlacerLocked.debugLayoutRepeats(
    353                             "updateWindowsAndWallpaperLocked 2", pendingLayoutChanges);
    354                 }
    355             }
    356         }
    357 
    358         final AppWindowToken atoken = w.mAppToken;
    359         if (winAnimator.mDrawState == READY_TO_SHOW) {
    360             if (atoken == null || atoken.allDrawn) {
    361                 if (w.performShowLocked()) {
    362                     pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
    363                     if (DEBUG_LAYOUT_REPEATS) {
    364                         mService.mWindowPlacerLocked.debugLayoutRepeats(
    365                                 "updateWindowsAndWallpaperLocked 5", pendingLayoutChanges);
    366                     }
    367                 }
    368             }
    369         }
    370         final AppWindowAnimator appAnimator = winAnimator.mAppAnimator;
    371         if (appAnimator != null && appAnimator.thumbnail != null) {
    372             if (appAnimator.thumbnailTransactionSeq
    373                     != mTmpWindowAnimator.mAnimTransactionSequence) {
    374                 appAnimator.thumbnailTransactionSeq =
    375                         mTmpWindowAnimator.mAnimTransactionSequence;
    376                 appAnimator.thumbnailLayer = 0;
    377             }
    378             if (appAnimator.thumbnailLayer < winAnimator.mAnimLayer) {
    379                 appAnimator.thumbnailLayer = winAnimator.mAnimLayer;
    380             }
    381         }
    382     };
    383 
    384     private final Consumer<WindowState> mUpdateWallpaperForAnimator = w -> {
    385         final WindowStateAnimator winAnimator = w.mWinAnimator;
    386         if (winAnimator.mSurfaceController == null || !winAnimator.hasSurface()) {
    387             return;
    388         }
    389 
    390         final int flags = w.mAttrs.flags;
    391 
    392         // If this window is animating, make a note that we have an animating window and take
    393         // care of a request to run a detached wallpaper animation.
    394         if (winAnimator.mAnimating) {
    395             if (winAnimator.mAnimation != null) {
    396                 if ((flags & FLAG_SHOW_WALLPAPER) != 0
    397                         && winAnimator.mAnimation.getDetachWallpaper()) {
    398                     mTmpWindow = w;
    399                 }
    400                 final int color = winAnimator.mAnimation.getBackgroundColor();
    401                 if (color != 0) {
    402                     final TaskStack stack = w.getStack();
    403                     if (stack != null) {
    404                         stack.setAnimationBackground(winAnimator, color);
    405                     }
    406                 }
    407             }
    408             mTmpWindowAnimator.setAnimating(true);
    409         }
    410 
    411         // If this window's app token is running a detached wallpaper animation, make a note so
    412         // we can ensure the wallpaper is displayed behind it.
    413         final AppWindowAnimator appAnimator = winAnimator.mAppAnimator;
    414         if (appAnimator != null && appAnimator.animation != null
    415                 && appAnimator.animating) {
    416             if ((flags & FLAG_SHOW_WALLPAPER) != 0
    417                     && appAnimator.animation.getDetachWallpaper()) {
    418                 mTmpWindow = w;
    419             }
    420 
    421             final int color = appAnimator.animation.getBackgroundColor();
    422             if (color != 0) {
    423                 final TaskStack stack = w.getStack();
    424                 if (stack != null) {
    425                     stack.setAnimationBackground(winAnimator, color);
    426                 }
    427             }
    428         }
    429     };
    430 
    431     private final Consumer<WindowState> mScheduleToastTimeout = w -> {
    432         final int lostFocusUid = mTmpWindow.mOwnerUid;
    433         final Handler handler = mService.mH;
    434         if (w.mAttrs.type == TYPE_TOAST && w.mOwnerUid == lostFocusUid) {
    435             if (!handler.hasMessages(WINDOW_HIDE_TIMEOUT, w)) {
    436                 handler.sendMessageDelayed(handler.obtainMessage(WINDOW_HIDE_TIMEOUT, w),
    437                         w.mAttrs.hideTimeoutMilliseconds);
    438             }
    439         }
    440     };
    441 
    442     private final ToBooleanFunction<WindowState> mFindFocusedWindow = w -> {
    443         final AppWindowToken focusedApp = mService.mFocusedApp;
    444         if (DEBUG_FOCUS) Slog.v(TAG_WM, "Looking for focus: " + w
    445                 + ", flags=" + w.mAttrs.flags + ", canReceive=" + w.canReceiveKeys());
    446 
    447         if (!w.canReceiveKeys()) {
    448             return false;
    449         }
    450 
    451         final AppWindowToken wtoken = w.mAppToken;
    452 
    453         // If this window's application has been removed, just skip it.
    454         if (wtoken != null && (wtoken.removed || wtoken.sendingToBottom)) {
    455             if (DEBUG_FOCUS) Slog.v(TAG_WM, "Skipping " + wtoken + " because "
    456                     + (wtoken.removed ? "removed" : "sendingToBottom"));
    457             return false;
    458         }
    459 
    460         if (focusedApp == null) {
    461             if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp=null"
    462                     + " using new focus @ " + w);
    463             mTmpWindow = w;
    464             return true;
    465         }
    466 
    467         if (!focusedApp.windowsAreFocusable()) {
    468             // Current focused app windows aren't focusable...
    469             if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: focusedApp windows not"
    470                     + " focusable using new focus @ " + w);
    471             mTmpWindow = w;
    472             return true;
    473         }
    474 
    475         // Descend through all of the app tokens and find the first that either matches
    476         // win.mAppToken (return win) or mFocusedApp (return null).
    477         if (wtoken != null && w.mAttrs.type != TYPE_APPLICATION_STARTING) {
    478             if (focusedApp.compareTo(wtoken) > 0) {
    479                 // App stack below focused app stack. No focus for you!!!
    480                 if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM,
    481                         "findFocusedWindow: Reached focused app=" + focusedApp);
    482                 mTmpWindow = null;
    483                 return true;
    484             }
    485         }
    486 
    487         if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: Found new focus @ " + w);
    488         mTmpWindow = w;
    489         return true;
    490     };
    491 
    492     private final Consumer<WindowState> mPrepareWindowSurfaces =
    493             w -> w.mWinAnimator.prepareSurfaceLocked(true);
    494 
    495     private final Consumer<WindowState> mPerformLayout = w -> {
    496         // Don't do layout of a window if it is not visible, or soon won't be visible, to avoid
    497         // wasting time and funky changes while a window is animating away.
    498         final boolean gone = (mTmpWindow != null && mService.mPolicy.canBeHiddenByKeyguardLw(w))
    499                 || w.isGoneForLayoutLw();
    500 
    501         if (DEBUG_LAYOUT && !w.mLayoutAttached) {
    502             Slog.v(TAG, "1ST PASS " + w + ": gone=" + gone + " mHaveFrame=" + w.mHaveFrame
    503                     + " mLayoutAttached=" + w.mLayoutAttached
    504                     + " screen changed=" + w.isConfigChanged());
    505             final AppWindowToken atoken = w.mAppToken;
    506             if (gone) Slog.v(TAG, "  GONE: mViewVisibility=" + w.mViewVisibility
    507                     + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.hidden
    508                     + " hiddenRequested=" + (atoken != null && atoken.hiddenRequested)
    509                     + " parentHidden=" + w.isParentWindowHidden());
    510             else Slog.v(TAG, "  VIS: mViewVisibility=" + w.mViewVisibility
    511                     + " mRelayoutCalled=" + w.mRelayoutCalled + " hidden=" + w.mToken.hidden
    512                     + " hiddenRequested=" + (atoken != null && atoken.hiddenRequested)
    513                     + " parentHidden=" + w.isParentWindowHidden());
    514         }
    515 
    516         // If this view is GONE, then skip it -- keep the current frame, and let the caller know
    517         // so they can ignore it if they want.  (We do the normal layout for INVISIBLE windows,
    518         // since that means "perform layout as normal, just don't display").
    519         if (!gone || !w.mHaveFrame || w.mLayoutNeeded
    520                 || ((w.isConfigChanged() || w.setReportResizeHints())
    521                 && !w.isGoneForLayoutLw() &&
    522                 ((w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
    523                         (w.mHasSurface && w.mAppToken != null &&
    524                                 w.mAppToken.layoutConfigChanges)))) {
    525             if (!w.mLayoutAttached) {
    526                 if (mTmpInitial) {
    527                     //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
    528                     w.mContentChanged = false;
    529                 }
    530                 if (w.mAttrs.type == TYPE_DREAM) {
    531                     // Don't layout windows behind a dream, so that if it does stuff like hide
    532                     // the status bar we won't get a bad transition when it goes away.
    533                     mTmpWindow = w;
    534                 }
    535                 w.mLayoutNeeded = false;
    536                 w.prelayout();
    537                 final boolean firstLayout = !w.isLaidOut();
    538                 mService.mPolicy.layoutWindowLw(w, null);
    539                 w.mLayoutSeq = mService.mLayoutSeq;
    540 
    541                 // If this is the first layout, we need to initialize the last inset values as
    542                 // otherwise we'd immediately cause an unnecessary resize.
    543                 if (firstLayout) {
    544                     w.updateLastInsetValues();
    545                 }
    546 
    547                 // Window frames may have changed. Update dim layer with the new bounds.
    548                 final Task task = w.getTask();
    549                 if (task != null) {
    550                     mDimLayerController.updateDimLayer(task);
    551                 }
    552 
    553                 if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame=" + w.mFrame
    554                         + " mContainingFrame=" + w.mContainingFrame
    555                         + " mDisplayFrame=" + w.mDisplayFrame);
    556             }
    557         }
    558     };
    559 
    560     private final Consumer<WindowState> mPerformLayoutAttached = w -> {
    561         if (w.mLayoutAttached) {
    562             if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + w + " mHaveFrame=" + w.mHaveFrame
    563                     + " mViewVisibility=" + w.mViewVisibility
    564                     + " mRelayoutCalled=" + w.mRelayoutCalled);
    565             // If this view is GONE, then skip it -- keep the current frame, and let the caller
    566             // know so they can ignore it if they want.  (We do the normal layout for INVISIBLE
    567             // windows, since that means "perform layout as normal, just don't display").
    568             if (mTmpWindow != null && mService.mPolicy.canBeHiddenByKeyguardLw(w)) {
    569                 return;
    570             }
    571             if ((w.mViewVisibility != GONE && w.mRelayoutCalled) || !w.mHaveFrame
    572                     || w.mLayoutNeeded) {
    573                 if (mTmpInitial) {
    574                     //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
    575                     w.mContentChanged = false;
    576                 }
    577                 w.mLayoutNeeded = false;
    578                 w.prelayout();
    579                 mService.mPolicy.layoutWindowLw(w, w.getParentWindow());
    580                 w.mLayoutSeq = mService.mLayoutSeq;
    581                 if (DEBUG_LAYOUT) Slog.v(TAG, " LAYOUT: mFrame=" + w.mFrame
    582                         + " mContainingFrame=" + w.mContainingFrame
    583                         + " mDisplayFrame=" + w.mDisplayFrame);
    584             }
    585         } else if (w.mAttrs.type == TYPE_DREAM) {
    586             // Don't layout windows behind a dream, so that if it does stuff like hide the
    587             // status bar we won't get a bad transition when it goes away.
    588             mTmpWindow = mTmpWindow2;
    589         }
    590     };
    591 
    592     private final Predicate<WindowState> mComputeImeTargetPredicate = w -> {
    593         if (DEBUG_INPUT_METHOD && mUpdateImeTarget) Slog.i(TAG_WM, "Checking window @" + w
    594                 + " fl=0x" + Integer.toHexString(w.mAttrs.flags));
    595         return w.canBeImeTarget();
    596     };
    597 
    598     private final Consumer<WindowState> mApplyPostLayoutPolicy =
    599             w -> mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs, w.getParentWindow(),
    600                     mService.mInputMethodTarget);
    601 
    602     private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
    603         final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked;
    604         final boolean obscuredChanged = w.mObscured !=
    605                 mTmpApplySurfaceChangesTransactionState.obscured;
    606         final RootWindowContainer root = mService.mRoot;
    607         // Only used if default window
    608         final boolean someoneLosingFocus = !mService.mLosingFocus.isEmpty();
    609 
    610         // Update effect.
    611         w.mObscured = mTmpApplySurfaceChangesTransactionState.obscured;
    612         if (!mTmpApplySurfaceChangesTransactionState.obscured) {
    613             final boolean isDisplayed = w.isDisplayedLw();
    614 
    615             if (isDisplayed && w.isObscuringDisplay()) {
    616                 // This window completely covers everything behind it, so we want to leave all
    617                 // of them as undimmed (for performance reasons).
    618                 root.mObscuringWindow = w;
    619                 mTmpApplySurfaceChangesTransactionState.obscured = true;
    620             }
    621 
    622             mTmpApplySurfaceChangesTransactionState.displayHasContent |=
    623                     root.handleNotObscuredLocked(w,
    624                             mTmpApplySurfaceChangesTransactionState.obscured,
    625                             mTmpApplySurfaceChangesTransactionState.syswin);
    626 
    627             if (w.mHasSurface && isDisplayed) {
    628                 final int type = w.mAttrs.type;
    629                 if (type == TYPE_SYSTEM_DIALOG || type == TYPE_SYSTEM_ERROR
    630                         || (w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
    631                     mTmpApplySurfaceChangesTransactionState.syswin = true;
    632                 }
    633                 if (mTmpApplySurfaceChangesTransactionState.preferredRefreshRate == 0
    634                         && w.mAttrs.preferredRefreshRate != 0) {
    635                     mTmpApplySurfaceChangesTransactionState.preferredRefreshRate
    636                             = w.mAttrs.preferredRefreshRate;
    637                 }
    638                 if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0
    639                         && w.mAttrs.preferredDisplayModeId != 0) {
    640                     mTmpApplySurfaceChangesTransactionState.preferredModeId
    641                             = w.mAttrs.preferredDisplayModeId;
    642                 }
    643             }
    644         }
    645 
    646         w.applyDimLayerIfNeeded();
    647 
    648         if (isDefaultDisplay && obscuredChanged && w.isVisibleLw()
    649                 && mWallpaperController.isWallpaperTarget(w)) {
    650             // This is the wallpaper target and its obscured state changed... make sure the
    651             // current wallpaper's visibility has been updated accordingly.
    652             mWallpaperController.updateWallpaperVisibility();
    653         }
    654 
    655         w.handleWindowMovedIfNeeded();
    656 
    657         final WindowStateAnimator winAnimator = w.mWinAnimator;
    658 
    659         //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
    660         w.mContentChanged = false;
    661 
    662         // Moved from updateWindowsAndWallpaperLocked().
    663         if (w.mHasSurface) {
    664             // Take care of the window being ready to display.
    665             final boolean committed = winAnimator.commitFinishDrawingLocked();
    666             if (isDefaultDisplay && committed) {
    667                 if (w.mAttrs.type == TYPE_DREAM) {
    668                     // HACK: When a dream is shown, it may at that point hide the lock screen.
    669                     // So we need to redo the layout to let the phone window manager make this
    670                     // happen.
    671                     pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
    672                     if (DEBUG_LAYOUT_REPEATS) {
    673                         surfacePlacer.debugLayoutRepeats(
    674                                 "dream and commitFinishDrawingLocked true",
    675                                 pendingLayoutChanges);
    676                     }
    677                 }
    678                 if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
    679                     if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
    680                             "First draw done in potential wallpaper target " + w);
    681                     root.mWallpaperMayChange = true;
    682                     pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
    683                     if (DEBUG_LAYOUT_REPEATS) {
    684                         surfacePlacer.debugLayoutRepeats(
    685                                 "wallpaper and commitFinishDrawingLocked true",
    686                                 pendingLayoutChanges);
    687                     }
    688                 }
    689             }
    690             final TaskStack stack = w.getStack();
    691             if ((!winAnimator.isAnimationStarting() && !winAnimator.isWaitingForOpening())
    692                     || (stack != null && stack.isAnimatingBounds())) {
    693                 // Updates the shown frame before we set up the surface. This is needed
    694                 // because the resizing could change the top-left position (in addition to
    695                 // size) of the window. setSurfaceBoundariesLocked uses mShownPosition to
    696                 // position the surface.
    697                 //
    698                 // If an animation is being started, we can't call this method because the
    699                 // animation hasn't processed its initial transformation yet, but in general
    700                 // we do want to update the position if the window is animating. We make an exception
    701                 // for the bounds animating state, where an application may have been waiting
    702                 // for an exit animation to start, but instead enters PiP. We need to ensure
    703                 // we always recompute the top-left in this case.
    704                 winAnimator.computeShownFrameLocked();
    705             }
    706             winAnimator.setSurfaceBoundariesLocked(mTmpRecoveringMemory /* recoveringMemory */);
    707         }
    708 
    709         final AppWindowToken atoken = w.mAppToken;
    710         if (atoken != null) {
    711             final boolean updateAllDrawn = atoken.updateDrawnWindowStates(w);
    712             if (updateAllDrawn && !mTmpUpdateAllDrawn.contains(atoken)) {
    713                 mTmpUpdateAllDrawn.add(atoken);
    714             }
    715         }
    716 
    717         if (isDefaultDisplay && someoneLosingFocus && w == mService.mCurrentFocus
    718                 && w.isDisplayedLw()) {
    719             mTmpApplySurfaceChangesTransactionState.focusDisplayed = true;
    720         }
    721 
    722         w.updateResizingWindowIfNeeded();
    723     };
    724 
    725     /**
    726      * Create new {@link DisplayContent} instance, add itself to the root window container and
    727      * initialize direct children.
    728      * @param display May not be null.
    729      * @param service You know.
    730      * @param layersController window layer controller used to assign layer to the windows on this
    731      *                         display.
    732      * @param wallpaperController wallpaper windows controller used to adjust the positioning of the
    733      *                            wallpaper windows in the window list.
    734      */
    735     DisplayContent(Display display, WindowManagerService service,
    736             WindowLayersController layersController, WallpaperController wallpaperController) {
    737         if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
    738             throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
    739                     + " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
    740                     + " new=" + display);
    741         }
    742 
    743         mDisplay = display;
    744         mDisplayId = display.getDisplayId();
    745         mLayersController = layersController;
    746         mWallpaperController = wallpaperController;
    747         display.getDisplayInfo(mDisplayInfo);
    748         display.getMetrics(mDisplayMetrics);
    749         isDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
    750         mService = service;
    751         initializeDisplayBaseInfo();
    752         mDividerControllerLocked = new DockedStackDividerController(service, this);
    753         mPinnedStackControllerLocked = new PinnedStackController(service, this);
    754         mDimLayerController = new DimLayerController(this);
    755 
    756         // These are the only direct children we should ever have and they are permanent.
    757         super.addChild(mBelowAppWindowsContainers, null);
    758         super.addChild(mTaskStackContainers, null);
    759         super.addChild(mAboveAppWindowsContainers, null);
    760         super.addChild(mImeWindowsContainers, null);
    761 
    762         // Add itself as a child to the root container.
    763         mService.mRoot.addChild(this, null);
    764 
    765         // TODO(b/62541591): evaluate whether this is the best spot to declare the
    766         // {@link DisplayContent} ready for use.
    767         mDisplayReady = true;
    768     }
    769 
    770     boolean isReady() {
    771         // The display is ready when the system and the individual display are both ready.
    772         return mService.mDisplayReady && mDisplayReady;
    773     }
    774 
    775     int getDisplayId() {
    776         return mDisplayId;
    777     }
    778 
    779     WindowToken getWindowToken(IBinder binder) {
    780         return mTokenMap.get(binder);
    781     }
    782 
    783     AppWindowToken getAppWindowToken(IBinder binder) {
    784         final WindowToken token = getWindowToken(binder);
    785         if (token == null) {
    786             return null;
    787         }
    788         return token.asAppWindowToken();
    789     }
    790 
    791     private void addWindowToken(IBinder binder, WindowToken token) {
    792         final DisplayContent dc = mService.mRoot.getWindowTokenDisplay(token);
    793         if (dc != null) {
    794             // We currently don't support adding a window token to the display if the display
    795             // already has the binder mapped to another token. If there is a use case for supporting
    796             // this moving forward we will either need to merge the WindowTokens some how or have
    797             // the binder map to a list of window tokens.
    798             throw new IllegalArgumentException("Can't map token=" + token + " to display="
    799                     + getName() + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);
    800         }
    801         if (binder == null) {
    802             throw new IllegalArgumentException("Can't map token=" + token + " to display="
    803                     + getName() + " binder is null");
    804         }
    805         if (token == null) {
    806             throw new IllegalArgumentException("Can't map null token to display="
    807                     + getName() + " binder=" + binder);
    808         }
    809 
    810         mTokenMap.put(binder, token);
    811 
    812         if (token.asAppWindowToken() == null) {
    813             // Add non-app token to container hierarchy on the display. App tokens are added through
    814             // the parent container managing them (e.g. Tasks).
    815             switch (token.windowType) {
    816                 case TYPE_WALLPAPER:
    817                     mBelowAppWindowsContainers.addChild(token);
    818                     break;
    819                 case TYPE_INPUT_METHOD:
    820                 case TYPE_INPUT_METHOD_DIALOG:
    821                     mImeWindowsContainers.addChild(token);
    822                     break;
    823                 default:
    824                     mAboveAppWindowsContainers.addChild(token);
    825                     break;
    826             }
    827         }
    828     }
    829 
    830     WindowToken removeWindowToken(IBinder binder) {
    831         final WindowToken token = mTokenMap.remove(binder);
    832         if (token != null && token.asAppWindowToken() == null) {
    833             token.setExiting();
    834         }
    835         return token;
    836     }
    837 
    838     /** Changes the display the input window token is housed on to this one. */
    839     void reParentWindowToken(WindowToken token) {
    840         final DisplayContent prevDc = token.getDisplayContent();
    841         if (prevDc == this) {
    842             return;
    843         }
    844         if (prevDc != null && prevDc.mTokenMap.remove(token.token) != null
    845                 && token.asAppWindowToken() == null) {
    846             // Removed the token from the map, but made sure it's not an app token before removing
    847             // from parent.
    848             token.getParent().removeChild(token);
    849         }
    850 
    851         addWindowToken(token.token, token);
    852     }
    853 
    854     void removeAppToken(IBinder binder) {
    855         final WindowToken token = removeWindowToken(binder);
    856         if (token == null) {
    857             Slog.w(TAG_WM, "removeAppToken: Attempted to remove non-existing token: " + binder);
    858             return;
    859         }
    860 
    861         final AppWindowToken appToken = token.asAppWindowToken();
    862 
    863         if (appToken == null) {
    864             Slog.w(TAG_WM, "Attempted to remove non-App token: " + binder + " token=" + token);
    865             return;
    866         }
    867 
    868         appToken.onRemovedFromDisplay();
    869     }
    870 
    871     Display getDisplay() {
    872         return mDisplay;
    873     }
    874 
    875     DisplayInfo getDisplayInfo() {
    876         return mDisplayInfo;
    877     }
    878 
    879     DisplayMetrics getDisplayMetrics() {
    880         return mDisplayMetrics;
    881     }
    882 
    883     int getRotation() {
    884         return mRotation;
    885     }
    886 
    887     void setRotation(int newRotation) {
    888         mRotation = newRotation;
    889     }
    890 
    891     int getLastOrientation() {
    892         return mLastOrientation;
    893     }
    894 
    895     void setLastOrientation(int orientation) {
    896         mLastOrientation = orientation;
    897     }
    898 
    899     boolean getAltOrientation() {
    900         return mAltOrientation;
    901     }
    902 
    903     void setAltOrientation(boolean altOrientation) {
    904         mAltOrientation = altOrientation;
    905     }
    906 
    907     int getLastWindowForcedOrientation() {
    908         return mLastWindowForcedOrientation;
    909     }
    910 
    911     /**
    912      * Update rotation of the display.
    913      *
    914      * Returns true if the rotation has been changed.  In this case YOU MUST CALL
    915      * {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
    916      */
    917     boolean updateRotationUnchecked(boolean inTransaction) {
    918         if (mService.mDeferredRotationPauseCount > 0) {
    919             // Rotation updates have been paused temporarily.  Defer the update until
    920             // updates have been resumed.
    921             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, rotation is paused.");
    922             return false;
    923         }
    924 
    925         ScreenRotationAnimation screenRotationAnimation =
    926                 mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
    927         if (screenRotationAnimation != null && screenRotationAnimation.isAnimating()) {
    928             // Rotation updates cannot be performed while the previous rotation change
    929             // animation is still in progress.  Skip this update.  We will try updating
    930             // again after the animation is finished and the display is unfrozen.
    931             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
    932             return false;
    933         }
    934         if (mService.mDisplayFrozen) {
    935             // Even if the screen rotation animation has finished (e.g. isAnimating
    936             // returns false), there is still some time where we haven't yet unfrozen
    937             // the display. We also need to abort rotation here.
    938             if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
    939                     "Deferring rotation, still finishing previous rotation");
    940             return false;
    941         }
    942 
    943         if (!mService.mDisplayEnabled) {
    944             // No point choosing a rotation if the display is not enabled.
    945             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, display is not enabled.");
    946             return false;
    947         }
    948 
    949         final int oldRotation = mRotation;
    950         final int lastOrientation = mLastOrientation;
    951         final boolean oldAltOrientation = mAltOrientation;
    952         int rotation = mService.mPolicy.rotationForOrientationLw(lastOrientation, oldRotation);
    953         boolean mayRotateSeamlessly = mService.mPolicy.shouldRotateSeamlessly(oldRotation,
    954                 rotation);
    955 
    956         if (mayRotateSeamlessly) {
    957             final WindowState seamlessRotated = getWindow((w) -> w.mSeamlesslyRotated);
    958             if (seamlessRotated != null) {
    959                 // We can't rotate (seamlessly or not) while waiting for the last seamless rotation
    960                 // to complete (that is, waiting for windows to redraw). It's tempting to check
    961                 // w.mSeamlessRotationCount but that could be incorrect in the case of
    962                 // window-removal.
    963                 return false;
    964             }
    965 
    966             // In the presence of the PINNED stack or System Alert
    967             // windows we unforuntately can not seamlessly rotate.
    968             if (getStackById(PINNED_STACK_ID) != null) {
    969                 mayRotateSeamlessly = false;
    970             }
    971             for (int i = 0; i < mService.mSessions.size(); i++) {
    972                 if (mService.mSessions.valueAt(i).hasAlertWindowSurfaces()) {
    973                     mayRotateSeamlessly = false;
    974                     break;
    975                 }
    976             }
    977         }
    978         final boolean rotateSeamlessly = mayRotateSeamlessly;
    979 
    980         // TODO: Implement forced rotation changes.
    981         //       Set mAltOrientation to indicate that the application is receiving
    982         //       an orientation that has different metrics than it expected.
    983         //       eg. Portrait instead of Landscape.
    984 
    985         final boolean altOrientation = !mService.mPolicy.rotationHasCompatibleMetricsLw(
    986                 lastOrientation, rotation);
    987 
    988         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Selected orientation " + lastOrientation
    989                 + ", got rotation " + rotation + " which has "
    990                 + (altOrientation ? "incompatible" : "compatible") + " metrics");
    991 
    992         if (oldRotation == rotation && oldAltOrientation == altOrientation) {
    993             // No change.
    994             return false;
    995         }
    996 
    997         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Rotation changed to " + rotation
    998                 + (altOrientation ? " (alt)" : "") + " from " + oldRotation
    999                 + (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation);
   1000 
   1001         if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
   1002             mService.mWaitingForConfig = true;
   1003         }
   1004 
   1005         mRotation = rotation;
   1006         mAltOrientation = altOrientation;
   1007         if (isDefaultDisplay) {
   1008             mService.mPolicy.setRotationLw(rotation);
   1009         }
   1010 
   1011         mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
   1012         mService.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT);
   1013         mService.mH.sendEmptyMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
   1014                 WINDOW_FREEZE_TIMEOUT_DURATION);
   1015 
   1016         setLayoutNeeded();
   1017         final int[] anim = new int[2];
   1018         if (isDimming()) {
   1019             anim[0] = anim[1] = 0;
   1020         } else {
   1021             mService.mPolicy.selectRotationAnimationLw(anim);
   1022         }
   1023 
   1024         if (!rotateSeamlessly) {
   1025             mService.startFreezingDisplayLocked(inTransaction, anim[0], anim[1], this);
   1026             // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
   1027             screenRotationAnimation = mService.mAnimator.getScreenRotationAnimationLocked(
   1028                     mDisplayId);
   1029         } else {
   1030             // The screen rotation animation uses a screenshot to freeze the screen
   1031             // while windows resize underneath.
   1032             // When we are rotating seamlessly, we allow the elements to transition
   1033             // to their rotated state independently and without a freeze required.
   1034             screenRotationAnimation = null;
   1035 
   1036             // We have to reset this in case a window was removed before it
   1037             // finished seamless rotation.
   1038             mService.mSeamlessRotationCount = 0;
   1039         }
   1040 
   1041         // We need to update our screen size information to match the new rotation. If the rotation
   1042         // has actually changed then this method will return true and, according to the comment at
   1043         // the top of the method, the caller is obligated to call computeNewConfigurationLocked().
   1044         // By updating the Display info here it will be available to
   1045         // #computeScreenConfiguration() later.
   1046         updateDisplayAndOrientation(getConfiguration().uiMode);
   1047 
   1048         if (!inTransaction) {
   1049             if (SHOW_TRANSACTIONS) {
   1050                 Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked");
   1051             }
   1052             mService.openSurfaceTransaction();
   1053         }
   1054         try {
   1055             // NOTE: We disable the rotation in the emulator because
   1056             //       it doesn't support hardware OpenGL emulation yet.
   1057             if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
   1058                     && screenRotationAnimation.hasScreenshot()) {
   1059                 if (screenRotationAnimation.setRotationInTransaction(
   1060                         rotation, mService.mFxSession,
   1061                         MAX_ANIMATION_DURATION, mService.getTransitionAnimationScaleLocked(),
   1062                         mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight)) {
   1063                     mService.scheduleAnimationLocked();
   1064                 }
   1065             }
   1066 
   1067             if (rotateSeamlessly) {
   1068                 forAllWindows(w -> {
   1069                     w.mWinAnimator.seamlesslyRotateWindow(oldRotation, rotation);
   1070                 }, true /* traverseTopToBottom */);
   1071             }
   1072 
   1073             mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
   1074         } finally {
   1075             if (!inTransaction) {
   1076                 mService.closeSurfaceTransaction();
   1077                 if (SHOW_LIGHT_TRANSACTIONS) {
   1078                     Slog.i(TAG_WM, "<<< CLOSE TRANSACTION setRotationUnchecked");
   1079                 }
   1080             }
   1081         }
   1082 
   1083         forAllWindows(w -> {
   1084             // Discard surface after orientation change, these can't be reused.
   1085             if (w.mAppToken != null) {
   1086                 w.mAppToken.destroySavedSurfaces();
   1087             }
   1088             if (w.mHasSurface && !rotateSeamlessly) {
   1089                 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
   1090                 w.setOrientationChanging(true);
   1091                 mService.mRoot.mOrientationChangeComplete = false;
   1092                 w.mLastFreezeDuration = 0;
   1093             }
   1094             w.mReportOrientationChanged = true;
   1095         }, true /* traverseTopToBottom */);
   1096 
   1097         if (rotateSeamlessly) {
   1098             mService.mH.removeMessages(WindowManagerService.H.SEAMLESS_ROTATION_TIMEOUT);
   1099             mService.mH.sendEmptyMessageDelayed(WindowManagerService.H.SEAMLESS_ROTATION_TIMEOUT,
   1100                     SEAMLESS_ROTATION_TIMEOUT_DURATION);
   1101         }
   1102 
   1103         for (int i = mService.mRotationWatchers.size() - 1; i >= 0; i--) {
   1104             final WindowManagerService.RotationWatcher rotationWatcher
   1105                     = mService.mRotationWatchers.get(i);
   1106             if (rotationWatcher.mDisplayId == mDisplayId) {
   1107                 try {
   1108                     rotationWatcher.mWatcher.onRotationChanged(rotation);
   1109                 } catch (RemoteException e) {
   1110                     // Ignore
   1111                 }
   1112             }
   1113         }
   1114 
   1115         // TODO (multi-display): Magnification is supported only for the default display.
   1116         // Announce rotation only if we will not animate as we already have the
   1117         // windows in final state. Otherwise, we make this call at the rotation end.
   1118         if (screenRotationAnimation == null && mService.mAccessibilityController != null
   1119                 && isDefaultDisplay) {
   1120             mService.mAccessibilityController.onRotationChangedLocked(this);
   1121         }
   1122 
   1123         return true;
   1124     }
   1125 
   1126     /**
   1127      * Update {@link #mDisplayInfo} and other internal variables when display is rotated or config
   1128      * changed.
   1129      * Do not call if {@link WindowManagerService#mDisplayReady} == false.
   1130      */
   1131     private DisplayInfo updateDisplayAndOrientation(int uiMode) {
   1132         // Use the effective "visual" dimensions based on current rotation
   1133         final boolean rotated = (mRotation == ROTATION_90 || mRotation == ROTATION_270);
   1134         final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
   1135         final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
   1136         int dw = realdw;
   1137         int dh = realdh;
   1138 
   1139         if (mAltOrientation) {
   1140             if (realdw > realdh) {
   1141                 // Turn landscape into portrait.
   1142                 int maxw = (int)(realdh/1.3f);
   1143                 if (maxw < realdw) {
   1144                     dw = maxw;
   1145                 }
   1146             } else {
   1147                 // Turn portrait into landscape.
   1148                 int maxh = (int)(realdw/1.3f);
   1149                 if (maxh < realdh) {
   1150                     dh = maxh;
   1151                 }
   1152             }
   1153         }
   1154 
   1155         // Update application display metrics.
   1156         final int appWidth = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode,
   1157                 mDisplayId);
   1158         final int appHeight = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode,
   1159                 mDisplayId);
   1160         mDisplayInfo.rotation = mRotation;
   1161         mDisplayInfo.logicalWidth = dw;
   1162         mDisplayInfo.logicalHeight = dh;
   1163         mDisplayInfo.logicalDensityDpi = mBaseDisplayDensity;
   1164         mDisplayInfo.appWidth = appWidth;
   1165         mDisplayInfo.appHeight = appHeight;
   1166         if (isDefaultDisplay) {
   1167             mDisplayInfo.getLogicalMetrics(mRealDisplayMetrics,
   1168                     CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
   1169         }
   1170         mDisplayInfo.getAppMetrics(mDisplayMetrics);
   1171         if (mDisplayScalingDisabled) {
   1172             mDisplayInfo.flags |= Display.FLAG_SCALING_DISABLED;
   1173         } else {
   1174             mDisplayInfo.flags &= ~Display.FLAG_SCALING_DISABLED;
   1175         }
   1176 
   1177         mService.mDisplayManagerInternal.setDisplayInfoOverrideFromWindowManager(mDisplayId,
   1178                 mDisplayInfo);
   1179 
   1180         mBaseDisplayRect.set(0, 0, dw, dh);
   1181 
   1182         if (isDefaultDisplay) {
   1183             mCompatibleScreenScale = CompatibilityInfo.computeCompatibleScaling(mDisplayMetrics,
   1184                     mCompatDisplayMetrics);
   1185         }
   1186         return mDisplayInfo;
   1187     }
   1188 
   1189     /**
   1190      * Compute display configuration based on display properties and policy settings.
   1191      * Do not call if mDisplayReady == false.
   1192      */
   1193     void computeScreenConfiguration(Configuration config) {
   1194         final DisplayInfo displayInfo = updateDisplayAndOrientation(config.uiMode);
   1195 
   1196         final int dw = displayInfo.logicalWidth;
   1197         final int dh = displayInfo.logicalHeight;
   1198         config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT :
   1199                 Configuration.ORIENTATION_LANDSCAPE;
   1200 
   1201         config.screenWidthDp =
   1202                 (int)(mService.mPolicy.getConfigDisplayWidth(dw, dh, displayInfo.rotation,
   1203                         config.uiMode, mDisplayId) / mDisplayMetrics.density);
   1204         config.screenHeightDp =
   1205                 (int)(mService.mPolicy.getConfigDisplayHeight(dw, dh, displayInfo.rotation,
   1206                         config.uiMode, mDisplayId) / mDisplayMetrics.density);
   1207 
   1208         mService.mPolicy.getNonDecorInsetsLw(displayInfo.rotation, dw, dh, mTmpRect);
   1209         final int leftInset = mTmpRect.left;
   1210         final int topInset = mTmpRect.top;
   1211         // appBounds at the root level should mirror the app screen size.
   1212         config.setAppBounds(leftInset /*left*/, topInset /*top*/, leftInset + displayInfo.appWidth /*right*/,
   1213                 topInset + displayInfo.appHeight /*bottom*/);
   1214         final boolean rotated = (displayInfo.rotation == Surface.ROTATION_90
   1215                 || displayInfo.rotation == Surface.ROTATION_270);
   1216 
   1217         computeSizeRangesAndScreenLayout(displayInfo, mDisplayId, rotated, config.uiMode, dw, dh,
   1218                 mDisplayMetrics.density, config);
   1219 
   1220         config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK)
   1221                 | ((displayInfo.flags & Display.FLAG_ROUND) != 0
   1222                 ? Configuration.SCREENLAYOUT_ROUND_YES
   1223                 : Configuration.SCREENLAYOUT_ROUND_NO);
   1224 
   1225         config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale);
   1226         config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale);
   1227         config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode, dw,
   1228                 dh, mDisplayId);
   1229         config.densityDpi = displayInfo.logicalDensityDpi;
   1230 
   1231         config.colorMode =
   1232                 (displayInfo.isHdr()
   1233                         ? Configuration.COLOR_MODE_HDR_YES
   1234                         : Configuration.COLOR_MODE_HDR_NO)
   1235                         | (displayInfo.isWideColorGamut() && mService.hasWideColorGamutSupport()
   1236                         ? Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_YES
   1237                         : Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_NO);
   1238 
   1239         // Update the configuration based on available input devices, lid switch,
   1240         // and platform configuration.
   1241         config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
   1242         config.keyboard = Configuration.KEYBOARD_NOKEYS;
   1243         config.navigation = Configuration.NAVIGATION_NONAV;
   1244 
   1245         int keyboardPresence = 0;
   1246         int navigationPresence = 0;
   1247         final InputDevice[] devices = mService.mInputManager.getInputDevices();
   1248         final int len = devices != null ? devices.length : 0;
   1249         for (int i = 0; i < len; i++) {
   1250             InputDevice device = devices[i];
   1251             if (!device.isVirtual()) {
   1252                 final int sources = device.getSources();
   1253                 final int presenceFlag = device.isExternal() ?
   1254                         WindowManagerPolicy.PRESENCE_EXTERNAL :
   1255                         WindowManagerPolicy.PRESENCE_INTERNAL;
   1256 
   1257                 // TODO(multi-display): Configure on per-display basis.
   1258                 if (mService.mIsTouchDevice) {
   1259                     if ((sources & InputDevice.SOURCE_TOUCHSCREEN) ==
   1260                             InputDevice.SOURCE_TOUCHSCREEN) {
   1261                         config.touchscreen = Configuration.TOUCHSCREEN_FINGER;
   1262                     }
   1263                 } else {
   1264                     config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
   1265                 }
   1266 
   1267                 if ((sources & InputDevice.SOURCE_TRACKBALL) == InputDevice.SOURCE_TRACKBALL) {
   1268                     config.navigation = Configuration.NAVIGATION_TRACKBALL;
   1269                     navigationPresence |= presenceFlag;
   1270                 } else if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD
   1271                         && config.navigation == Configuration.NAVIGATION_NONAV) {
   1272                     config.navigation = Configuration.NAVIGATION_DPAD;
   1273                     navigationPresence |= presenceFlag;
   1274                 }
   1275 
   1276                 if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
   1277                     config.keyboard = Configuration.KEYBOARD_QWERTY;
   1278                     keyboardPresence |= presenceFlag;
   1279                 }
   1280             }
   1281         }
   1282 
   1283         if (config.navigation == Configuration.NAVIGATION_NONAV && mService.mHasPermanentDpad) {
   1284             config.navigation = Configuration.NAVIGATION_DPAD;
   1285             navigationPresence |= WindowManagerPolicy.PRESENCE_INTERNAL;
   1286         }
   1287 
   1288         // Determine whether a hard keyboard is available and enabled.
   1289         // TODO(multi-display): Should the hardware keyboard be tied to a display or to a device?
   1290         boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
   1291         if (hardKeyboardAvailable != mService.mHardKeyboardAvailable) {
   1292             mService.mHardKeyboardAvailable = hardKeyboardAvailable;
   1293             mService.mH.removeMessages(WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
   1294             mService.mH.sendEmptyMessage(WindowManagerService.H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
   1295         }
   1296 
   1297         // Let the policy update hidden states.
   1298         config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
   1299         config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
   1300         config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
   1301         mService.mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
   1302     }
   1303 
   1304     private int computeCompatSmallestWidth(boolean rotated, int uiMode, int dw, int dh,
   1305             int displayId) {
   1306         mTmpDisplayMetrics.setTo(mDisplayMetrics);
   1307         final DisplayMetrics tmpDm = mTmpDisplayMetrics;
   1308         final int unrotDw, unrotDh;
   1309         if (rotated) {
   1310             unrotDw = dh;
   1311             unrotDh = dw;
   1312         } else {
   1313             unrotDw = dw;
   1314             unrotDh = dh;
   1315         }
   1316         int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh,
   1317                 displayId);
   1318         sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw,
   1319                 displayId);
   1320         sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh,
   1321                 displayId);
   1322         sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw,
   1323                 displayId);
   1324         return sw;
   1325     }
   1326 
   1327     private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode,
   1328             DisplayMetrics dm, int dw, int dh, int displayId) {
   1329         dm.noncompatWidthPixels = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode,
   1330                 displayId);
   1331         dm.noncompatHeightPixels = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation,
   1332                 uiMode, displayId);
   1333         float scale = CompatibilityInfo.computeCompatibleScaling(dm, null);
   1334         int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f);
   1335         if (curSize == 0 || size < curSize) {
   1336             curSize = size;
   1337         }
   1338         return curSize;
   1339     }
   1340 
   1341     private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, int displayId,
   1342             boolean rotated, int uiMode, int dw, int dh, float density, Configuration outConfig) {
   1343 
   1344         // We need to determine the smallest width that will occur under normal
   1345         // operation.  To this, start with the base screen size and compute the
   1346         // width under the different possible rotations.  We need to un-rotate
   1347         // the current screen dimensions before doing this.
   1348         int unrotDw, unrotDh;
   1349         if (rotated) {
   1350             unrotDw = dh;
   1351             unrotDh = dw;
   1352         } else {
   1353             unrotDw = dw;
   1354             unrotDh = dh;
   1355         }
   1356         displayInfo.smallestNominalAppWidth = 1<<30;
   1357         displayInfo.smallestNominalAppHeight = 1<<30;
   1358         displayInfo.largestNominalAppWidth = 0;
   1359         displayInfo.largestNominalAppHeight = 0;
   1360         adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_0, uiMode, unrotDw,
   1361                 unrotDh);
   1362         adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_90, uiMode, unrotDh,
   1363                 unrotDw);
   1364         adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_180, uiMode, unrotDw,
   1365                 unrotDh);
   1366         adjustDisplaySizeRanges(displayInfo, displayId, Surface.ROTATION_270, uiMode, unrotDh,
   1367                 unrotDw);
   1368         int sl = Configuration.resetScreenLayout(outConfig.screenLayout);
   1369         sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode,
   1370                 displayId);
   1371         sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode,
   1372                 displayId);
   1373         sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode,
   1374                 displayId);
   1375         sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode,
   1376                 displayId);
   1377         outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density);
   1378         outConfig.screenLayout = sl;
   1379     }
   1380 
   1381     private int reduceConfigLayout(int curLayout, int rotation, float density, int dw, int dh,
   1382             int uiMode, int displayId) {
   1383         // Get the app screen size at this rotation.
   1384         int w = mService.mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode, displayId);
   1385         int h = mService.mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode, displayId);
   1386 
   1387         // Compute the screen layout size class for this rotation.
   1388         int longSize = w;
   1389         int shortSize = h;
   1390         if (longSize < shortSize) {
   1391             int tmp = longSize;
   1392             longSize = shortSize;
   1393             shortSize = tmp;
   1394         }
   1395         longSize = (int)(longSize/density);
   1396         shortSize = (int)(shortSize/density);
   1397         return Configuration.reduceScreenLayout(curLayout, longSize, shortSize);
   1398     }
   1399 
   1400     private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int displayId, int rotation,
   1401             int uiMode, int dw, int dh) {
   1402         final int width = mService.mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode,
   1403                 displayId);
   1404         if (width < displayInfo.smallestNominalAppWidth) {
   1405             displayInfo.smallestNominalAppWidth = width;
   1406         }
   1407         if (width > displayInfo.largestNominalAppWidth) {
   1408             displayInfo.largestNominalAppWidth = width;
   1409         }
   1410         final int height = mService.mPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode,
   1411                 displayId);
   1412         if (height < displayInfo.smallestNominalAppHeight) {
   1413             displayInfo.smallestNominalAppHeight = height;
   1414         }
   1415         if (height > displayInfo.largestNominalAppHeight) {
   1416             displayInfo.largestNominalAppHeight = height;
   1417         }
   1418     }
   1419 
   1420     DockedStackDividerController getDockedDividerController() {
   1421         return mDividerControllerLocked;
   1422     }
   1423 
   1424     PinnedStackController getPinnedStackController() {
   1425         return mPinnedStackControllerLocked;
   1426     }
   1427 
   1428     /**
   1429      * Returns true if the specified UID has access to this display.
   1430      */
   1431     boolean hasAccess(int uid) {
   1432         return mDisplay.hasAccess(uid);
   1433     }
   1434 
   1435     boolean isPrivate() {
   1436         return (mDisplay.getFlags() & FLAG_PRIVATE) != 0;
   1437     }
   1438 
   1439     TaskStack getHomeStack() {
   1440         if (mHomeStack == null && mDisplayId == DEFAULT_DISPLAY) {
   1441             Slog.e(TAG_WM, "getHomeStack: Returning null from this=" + this);
   1442         }
   1443         return mHomeStack;
   1444     }
   1445 
   1446     TaskStack getStackById(int stackId) {
   1447         for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
   1448             final TaskStack stack = mTaskStackContainers.get(i);
   1449             if (stack.mStackId == stackId) {
   1450                 return stack;
   1451             }
   1452         }
   1453         return null;
   1454     }
   1455 
   1456     @VisibleForTesting
   1457     int getStackCount() {
   1458         return mTaskStackContainers.size();
   1459     }
   1460 
   1461     @VisibleForTesting
   1462     int getStaskPosById(int stackId) {
   1463         for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
   1464             final TaskStack stack = mTaskStackContainers.get(i);
   1465             if (stack.mStackId == stackId) {
   1466                 return i;
   1467             }
   1468         }
   1469         return -1;
   1470     }
   1471 
   1472     @Override
   1473     void onConfigurationChanged(Configuration newParentConfig) {
   1474         super.onConfigurationChanged(newParentConfig);
   1475 
   1476         // The display size information is heavily dependent on the resources in the current
   1477         // configuration, so we need to reconfigure it every time the configuration changes.
   1478         // See {@link PhoneWindowManager#setInitialDisplaySize}...sigh...
   1479         mService.reconfigureDisplayLocked(this);
   1480 
   1481         getDockedDividerController().onConfigurationChanged();
   1482         getPinnedStackController().onConfigurationChanged();
   1483     }
   1484 
   1485     /**
   1486      * Callback used to trigger bounds update after configuration change and get ids of stacks whose
   1487      * bounds were updated.
   1488      */
   1489     void updateStackBoundsAfterConfigChange(@NonNull List<Integer> changedStackList) {
   1490         for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
   1491             final TaskStack stack = mTaskStackContainers.get(i);
   1492             if (stack.updateBoundsAfterConfigChange()) {
   1493                 changedStackList.add(stack.mStackId);
   1494             }
   1495         }
   1496 
   1497         // If there was no pinned stack, we still need to notify the controller of the display info
   1498         // update as a result of the config change.  We do this here to consolidate the flow between
   1499         // changes when there is and is not a stack.
   1500         if (getStackById(PINNED_STACK_ID) == null) {
   1501             mPinnedStackControllerLocked.onDisplayInfoChanged();
   1502         }
   1503     }
   1504 
   1505     @Override
   1506     boolean fillsParent() {
   1507         return true;
   1508     }
   1509 
   1510     @Override
   1511     boolean isVisible() {
   1512         return true;
   1513     }
   1514 
   1515     @Override
   1516     void onAppTransitionDone() {
   1517         super.onAppTransitionDone();
   1518         mService.mWindowsChanged = true;
   1519     }
   1520 
   1521     @Override
   1522     boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
   1523         // Special handling so we can process IME windows with #forAllImeWindows above their IME
   1524         // target, or here in order if there isn't an IME target.
   1525         if (traverseTopToBottom) {
   1526             for (int i = mChildren.size() - 1; i >= 0; --i) {
   1527                 final DisplayChildWindowContainer child = mChildren.get(i);
   1528                 if (child == mImeWindowsContainers && mService.mInputMethodTarget != null) {
   1529                     // In this case the Ime windows will be processed above their target so we skip
   1530                     // here.
   1531                     continue;
   1532                 }
   1533                 if (child.forAllWindows(callback, traverseTopToBottom)) {
   1534                     return true;
   1535                 }
   1536             }
   1537         } else {
   1538             final int count = mChildren.size();
   1539             for (int i = 0; i < count; i++) {
   1540                 final DisplayChildWindowContainer child = mChildren.get(i);
   1541                 if (child == mImeWindowsContainers && mService.mInputMethodTarget != null) {
   1542                     // In this case the Ime windows will be processed above their target so we skip
   1543                     // here.
   1544                     continue;
   1545                 }
   1546                 if (child.forAllWindows(callback, traverseTopToBottom)) {
   1547                     return true;
   1548                 }
   1549             }
   1550         }
   1551         return false;
   1552     }
   1553 
   1554     boolean forAllImeWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) {
   1555         return mImeWindowsContainers.forAllWindows(callback, traverseTopToBottom);
   1556     }
   1557 
   1558     @Override
   1559     int getOrientation() {
   1560         final WindowManagerPolicy policy = mService.mPolicy;
   1561 
   1562         if (mService.mDisplayFrozen) {
   1563             if (mLastWindowForcedOrientation != SCREEN_ORIENTATION_UNSPECIFIED) {
   1564                 if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
   1565                         "Display is frozen, return " + mLastWindowForcedOrientation);
   1566                 // If the display is frozen, some activities may be in the middle of restarting, and
   1567                 // thus have removed their old window. If the window has the flag to hide the lock
   1568                 // screen, then the lock screen can re-appear and inflict its own orientation on us.
   1569                 // Keep the orientation stable until this all settles down.
   1570                 return mLastWindowForcedOrientation;
   1571             } else if (policy.isKeyguardLocked()) {
   1572                 // Use the last orientation the while the display is frozen with the keyguard
   1573                 // locked. This could be the keyguard forced orientation or from a SHOW_WHEN_LOCKED
   1574                 // window. We don't want to check the show when locked window directly though as
   1575                 // things aren't stable while the display is frozen, for example the window could be
   1576                 // momentarily unavailable due to activity relaunch.
   1577                 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display is frozen while keyguard locked, "
   1578                         + "return " + mLastOrientation);
   1579                 return mLastOrientation;
   1580             }
   1581         } else {
   1582             final int orientation = mAboveAppWindowsContainers.getOrientation();
   1583             if (orientation != SCREEN_ORIENTATION_UNSET) {
   1584                 return orientation;
   1585             }
   1586         }
   1587 
   1588         // Top system windows are not requesting an orientation. Start searching from apps.
   1589         return mTaskStackContainers.getOrientation();
   1590     }
   1591 
   1592     void updateDisplayInfo() {
   1593         // Check if display metrics changed and update base values if needed.
   1594         updateBaseDisplayMetricsIfNeeded();
   1595 
   1596         mDisplay.getDisplayInfo(mDisplayInfo);
   1597         mDisplay.getMetrics(mDisplayMetrics);
   1598 
   1599         for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
   1600             mTaskStackContainers.get(i).updateDisplayInfo(null);
   1601         }
   1602     }
   1603 
   1604     void initializeDisplayBaseInfo() {
   1605         final DisplayManagerInternal displayManagerInternal = mService.mDisplayManagerInternal;
   1606         if (displayManagerInternal != null) {
   1607             // Bootstrap the default logical display from the display manager.
   1608             final DisplayInfo newDisplayInfo = displayManagerInternal.getDisplayInfo(mDisplayId);
   1609             if (newDisplayInfo != null) {
   1610                 mDisplayInfo.copyFrom(newDisplayInfo);
   1611             }
   1612         }
   1613 
   1614         updateBaseDisplayMetrics(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
   1615                 mDisplayInfo.logicalDensityDpi);
   1616         mInitialDisplayWidth = mDisplayInfo.logicalWidth;
   1617         mInitialDisplayHeight = mDisplayInfo.logicalHeight;
   1618         mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
   1619     }
   1620 
   1621     void getLogicalDisplayRect(Rect out) {
   1622         // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
   1623         final int orientation = mDisplayInfo.rotation;
   1624         boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
   1625         final int physWidth = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
   1626         final int physHeight = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
   1627         int width = mDisplayInfo.logicalWidth;
   1628         int left = (physWidth - width) / 2;
   1629         int height = mDisplayInfo.logicalHeight;
   1630         int top = (physHeight - height) / 2;
   1631         out.set(left, top, left + width, top + height);
   1632     }
   1633 
   1634     private void getLogicalDisplayRect(Rect out, int orientation) {
   1635         getLogicalDisplayRect(out);
   1636 
   1637         // Rotate the Rect if needed.
   1638         final int currentRotation = mDisplayInfo.rotation;
   1639         final int rotationDelta = deltaRotation(currentRotation, orientation);
   1640         if (rotationDelta == ROTATION_90 || rotationDelta == ROTATION_270) {
   1641             createRotationMatrix(rotationDelta, mBaseDisplayWidth, mBaseDisplayHeight, mTmpMatrix);
   1642             mTmpRectF.set(out);
   1643             mTmpMatrix.mapRect(mTmpRectF);
   1644             mTmpRectF.round(out);
   1645         }
   1646     }
   1647 
   1648     /**
   1649      * If display metrics changed, overrides are not set and it's not just a rotation - update base
   1650      * values.
   1651      */
   1652     private void updateBaseDisplayMetricsIfNeeded() {
   1653         // Get real display metrics without overrides from WM.
   1654         mService.mDisplayManagerInternal.getNonOverrideDisplayInfo(mDisplayId, mDisplayInfo);
   1655         final int orientation = mDisplayInfo.rotation;
   1656         final boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
   1657         final int newWidth = rotated ? mDisplayInfo.logicalHeight : mDisplayInfo.logicalWidth;
   1658         final int newHeight = rotated ? mDisplayInfo.logicalWidth : mDisplayInfo.logicalHeight;
   1659         final int newDensity = mDisplayInfo.logicalDensityDpi;
   1660 
   1661         final boolean displayMetricsChanged = mInitialDisplayWidth != newWidth
   1662                 || mInitialDisplayHeight != newHeight
   1663                 || mInitialDisplayDensity != mDisplayInfo.logicalDensityDpi;
   1664 
   1665         if (displayMetricsChanged) {
   1666             // Check if display size or density is forced.
   1667             final boolean isDisplaySizeForced = mBaseDisplayWidth != mInitialDisplayWidth
   1668                     || mBaseDisplayHeight != mInitialDisplayHeight;
   1669             final boolean isDisplayDensityForced = mBaseDisplayDensity != mInitialDisplayDensity;
   1670 
   1671             // If there is an override set for base values - use it, otherwise use new values.
   1672             updateBaseDisplayMetrics(isDisplaySizeForced ? mBaseDisplayWidth : newWidth,
   1673                     isDisplaySizeForced ? mBaseDisplayHeight : newHeight,
   1674                     isDisplayDensityForced ? mBaseDisplayDensity : newDensity);
   1675 
   1676             // Real display metrics changed, so we should also update initial values.
   1677             mInitialDisplayWidth = newWidth;
   1678             mInitialDisplayHeight = newHeight;
   1679             mInitialDisplayDensity = newDensity;
   1680             mService.reconfigureDisplayLocked(this);
   1681         }
   1682     }
   1683 
   1684     /** Sets the maximum width the screen resolution can be */
   1685     void setMaxUiWidth(int width) {
   1686         if (DEBUG_DISPLAY) {
   1687             Slog.v(TAG_WM, "Setting max ui width:" + width + " on display:" + getDisplayId());
   1688         }
   1689 
   1690         mMaxUiWidth = width;
   1691 
   1692         // Update existing metrics.
   1693         updateBaseDisplayMetrics(mBaseDisplayWidth, mBaseDisplayHeight, mBaseDisplayDensity);
   1694     }
   1695 
   1696     /** Update base (override) display metrics. */
   1697     void updateBaseDisplayMetrics(int baseWidth, int baseHeight, int baseDensity) {
   1698         mBaseDisplayWidth = baseWidth;
   1699         mBaseDisplayHeight = baseHeight;
   1700         mBaseDisplayDensity = baseDensity;
   1701 
   1702         if (mMaxUiWidth > 0 && mBaseDisplayWidth > mMaxUiWidth) {
   1703             mBaseDisplayHeight = (mMaxUiWidth * mBaseDisplayHeight) / mBaseDisplayWidth;
   1704             mBaseDisplayDensity = (mMaxUiWidth * mBaseDisplayDensity) / mBaseDisplayWidth;
   1705             mBaseDisplayWidth = mMaxUiWidth;
   1706 
   1707             if (DEBUG_DISPLAY) {
   1708                 Slog.v(TAG_WM, "Applying config restraints:" + mBaseDisplayWidth + "x"
   1709                         + mBaseDisplayHeight + " at density:" + mBaseDisplayDensity
   1710                         + " on display:" + getDisplayId());
   1711             }
   1712         }
   1713 
   1714         mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
   1715     }
   1716 
   1717     void getContentRect(Rect out) {
   1718         out.set(mContentRect);
   1719     }
   1720 
   1721     TaskStack addStackToDisplay(int stackId, boolean onTop) {
   1722         if (DEBUG_STACK) Slog.d(TAG_WM, "Create new stackId=" + stackId + " on displayId="
   1723                 + mDisplayId);
   1724 
   1725         TaskStack stack = getStackById(stackId);
   1726         if (stack != null) {
   1727             // It's already attached to the display...clear mDeferRemoval and move stack to
   1728             // appropriate z-order on display as needed.
   1729             stack.mDeferRemoval = false;
   1730             // We're not moving the display to front when we're adding stacks, only when
   1731             // requested to change the position of stack explicitly.
   1732             mTaskStackContainers.positionChildAt(onTop ? POSITION_TOP : POSITION_BOTTOM, stack,
   1733                     false /* includingParents */);
   1734         } else {
   1735             stack = new TaskStack(mService, stackId);
   1736             mTaskStackContainers.addStackToDisplay(stack, onTop);
   1737         }
   1738 
   1739         if (stackId == DOCKED_STACK_ID) {
   1740             mDividerControllerLocked.notifyDockedStackExistsChanged(true);
   1741         }
   1742         return stack;
   1743     }
   1744 
   1745     void moveStackToDisplay(TaskStack stack, boolean onTop) {
   1746         final DisplayContent prevDc = stack.getDisplayContent();
   1747         if (prevDc == null) {
   1748             throw new IllegalStateException("Trying to move stackId=" + stack.mStackId
   1749                     + " which is not currently attached to any display");
   1750         }
   1751         if (prevDc.getDisplayId() == mDisplayId) {
   1752             throw new IllegalArgumentException("Trying to move stackId=" + stack.mStackId
   1753                     + " to its current displayId=" + mDisplayId);
   1754         }
   1755 
   1756         prevDc.mTaskStackContainers.removeStackFromDisplay(stack);
   1757         mTaskStackContainers.addStackToDisplay(stack, onTop);
   1758     }
   1759 
   1760     @Override
   1761     protected void addChild(DisplayChildWindowContainer child,
   1762             Comparator<DisplayChildWindowContainer> comparator) {
   1763         throw new UnsupportedOperationException("See DisplayChildWindowContainer");
   1764     }
   1765 
   1766     @Override
   1767     protected void addChild(DisplayChildWindowContainer child, int index) {
   1768         throw new UnsupportedOperationException("See DisplayChildWindowContainer");
   1769     }
   1770 
   1771     @Override
   1772     protected void removeChild(DisplayChildWindowContainer child) {
   1773         // Only allow removal of direct children from this display if the display is in the process
   1774         // of been removed.
   1775         if (mRemovingDisplay) {
   1776             super.removeChild(child);
   1777             return;
   1778         }
   1779         throw new UnsupportedOperationException("See DisplayChildWindowContainer");
   1780     }
   1781 
   1782     @Override
   1783     void positionChildAt(int position, DisplayChildWindowContainer child, boolean includingParents) {
   1784         // Children of the display are statically ordered, so the real intention here is to perform
   1785         // the operation on the display and not the static direct children.
   1786         getParent().positionChildAt(position, this, includingParents);
   1787     }
   1788 
   1789     int taskIdFromPoint(int x, int y) {
   1790         for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
   1791             final TaskStack stack = mTaskStackContainers.get(stackNdx);
   1792             final int taskId = stack.taskIdFromPoint(x, y);
   1793             if (taskId != -1) {
   1794                 return taskId;
   1795             }
   1796         }
   1797         return -1;
   1798     }
   1799 
   1800     /**
   1801      * Find the task whose outside touch area (for resizing) (x, y) falls within.
   1802      * Returns null if the touch doesn't fall into a resizing area.
   1803      */
   1804     Task findTaskForResizePoint(int x, int y) {
   1805         final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
   1806         mTmpTaskForResizePointSearchResult.reset();
   1807         for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
   1808             final TaskStack stack = mTaskStackContainers.get(stackNdx);
   1809             if (!StackId.isTaskResizeAllowed(stack.mStackId)) {
   1810                 return null;
   1811             }
   1812 
   1813             stack.findTaskForResizePoint(x, y, delta, mTmpTaskForResizePointSearchResult);
   1814             if (mTmpTaskForResizePointSearchResult.searchDone) {
   1815                 return mTmpTaskForResizePointSearchResult.taskForResize;
   1816             }
   1817         }
   1818         return null;
   1819     }
   1820 
   1821     void setTouchExcludeRegion(Task focusedTask) {
   1822         // The provided task is the task on this display with focus, so if WindowManagerService's
   1823         // focused app is not on this display, focusedTask will be null.
   1824         if (focusedTask == null) {
   1825             mTouchExcludeRegion.setEmpty();
   1826         } else {
   1827             mTouchExcludeRegion.set(mBaseDisplayRect);
   1828             final int delta = dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
   1829             mTmpRect2.setEmpty();
   1830             for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
   1831                 final TaskStack stack = mTaskStackContainers.get(stackNdx);
   1832                 stack.setTouchExcludeRegion(
   1833                         focusedTask, delta, mTouchExcludeRegion, mContentRect, mTmpRect2);
   1834             }
   1835             // If we removed the focused task above, add it back and only leave its
   1836             // outside touch area in the exclusion. TapDectector is not interested in
   1837             // any touch inside the focused task itself.
   1838             if (!mTmpRect2.isEmpty()) {
   1839                 mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION);
   1840             }
   1841         }
   1842         final WindowState inputMethod = mService.mInputMethodWindow;
   1843         if (inputMethod != null && inputMethod.isVisibleLw()) {
   1844             // If the input method is visible and the user is typing, we don't want these touch
   1845             // events to be intercepted and used to change focus. This would likely cause a
   1846             // disappearance of the input method.
   1847             inputMethod.getTouchableRegion(mTmpRegion);
   1848             if (inputMethod.getDisplayId() == mDisplayId) {
   1849                 mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
   1850             } else {
   1851                 // IME is on a different display, so we need to update its tap detector.
   1852                 // TODO(multidisplay): Remove when IME will always appear on same display.
   1853                 inputMethod.getDisplayContent().setTouchExcludeRegion(null /* focusedTask */);
   1854             }
   1855         }
   1856         for (int i = mTapExcludedWindows.size() - 1; i >= 0; i--) {
   1857             WindowState win = mTapExcludedWindows.get(i);
   1858             win.getTouchableRegion(mTmpRegion);
   1859             mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
   1860         }
   1861         // TODO(multi-display): Support docked stacks on secondary displays.
   1862         if (mDisplayId == DEFAULT_DISPLAY && getDockedStackLocked() != null) {
   1863             mDividerControllerLocked.getTouchRegion(mTmpRect);
   1864             mTmpRegion.set(mTmpRect);
   1865             mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
   1866         }
   1867         if (mTapDetector != null) {
   1868             mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion);
   1869         }
   1870     }
   1871 
   1872     @Override
   1873     void switchUser() {
   1874         super.switchUser();
   1875         mService.mWindowsChanged = true;
   1876     }
   1877 
   1878     private void resetAnimationBackgroundAnimator() {
   1879         for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
   1880             mTaskStackContainers.get(stackNdx).resetAnimationBackgroundAnimator();
   1881         }
   1882     }
   1883 
   1884     boolean animateDimLayers() {
   1885         return mDimLayerController.animateDimLayers();
   1886     }
   1887 
   1888     private void resetDimming() {
   1889         mDimLayerController.resetDimming();
   1890     }
   1891 
   1892     boolean isDimming() {
   1893         return mDimLayerController.isDimming();
   1894     }
   1895 
   1896     private void stopDimmingIfNeeded() {
   1897         mDimLayerController.stopDimmingIfNeeded();
   1898     }
   1899 
   1900     @Override
   1901     void removeIfPossible() {
   1902         if (isAnimating()) {
   1903             mDeferredRemoval = true;
   1904             return;
   1905         }
   1906         removeImmediately();
   1907     }
   1908 
   1909     @Override
   1910     void removeImmediately() {
   1911         mRemovingDisplay = true;
   1912         try {
   1913             super.removeImmediately();
   1914             if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Removing display=" + this);
   1915             mDimLayerController.close();
   1916             if (mDisplayId == DEFAULT_DISPLAY && mService.canDispatchPointerEvents()) {
   1917                 mService.unregisterPointerEventListener(mTapDetector);
   1918                 mService.unregisterPointerEventListener(mService.mMousePositionTracker);
   1919             }
   1920         } finally {
   1921             mRemovingDisplay = false;
   1922         }
   1923     }
   1924 
   1925     /** Returns true if a removal action is still being deferred. */
   1926     @Override
   1927     boolean checkCompleteDeferredRemoval() {
   1928         final boolean stillDeferringRemoval = super.checkCompleteDeferredRemoval();
   1929 
   1930         if (!stillDeferringRemoval && mDeferredRemoval) {
   1931             removeImmediately();
   1932             mService.onDisplayRemoved(mDisplayId);
   1933             return false;
   1934         }
   1935         return true;
   1936     }
   1937 
   1938     /** @return 'true' if removal of this display content is deferred due to active animation. */
   1939     boolean isRemovalDeferred() {
   1940         return mDeferredRemoval;
   1941     }
   1942 
   1943     boolean animateForIme(float interpolatedValue, float animationTarget,
   1944             float dividerAnimationTarget) {
   1945         boolean updated = false;
   1946 
   1947         for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
   1948             final TaskStack stack = mTaskStackContainers.get(i);
   1949             if (stack == null || !stack.isAdjustedForIme()) {
   1950                 continue;
   1951             }
   1952 
   1953             if (interpolatedValue >= 1f && animationTarget == 0f && dividerAnimationTarget == 0f) {
   1954                 stack.resetAdjustedForIme(true /* adjustBoundsNow */);
   1955                 updated = true;
   1956             } else {
   1957                 mDividerControllerLocked.mLastAnimationProgress =
   1958                         mDividerControllerLocked.getInterpolatedAnimationValue(interpolatedValue);
   1959                 mDividerControllerLocked.mLastDividerProgress =
   1960                         mDividerControllerLocked.getInterpolatedDividerValue(interpolatedValue);
   1961                 updated |= stack.updateAdjustForIme(
   1962                         mDividerControllerLocked.mLastAnimationProgress,
   1963                         mDividerControllerLocked.mLastDividerProgress,
   1964                         false /* force */);
   1965             }
   1966             if (interpolatedValue >= 1f) {
   1967                 stack.endImeAdjustAnimation();
   1968             }
   1969         }
   1970 
   1971         return updated;
   1972     }
   1973 
   1974     boolean clearImeAdjustAnimation() {
   1975         boolean changed = false;
   1976         for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
   1977             final TaskStack stack = mTaskStackContainers.get(i);
   1978             if (stack != null && stack.isAdjustedForIme()) {
   1979                 stack.resetAdjustedForIme(true /* adjustBoundsNow */);
   1980                 changed  = true;
   1981             }
   1982         }
   1983         return changed;
   1984     }
   1985 
   1986     void beginImeAdjustAnimation() {
   1987         for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
   1988             final TaskStack stack = mTaskStackContainers.get(i);
   1989             if (stack.isVisible() && stack.isAdjustedForIme()) {
   1990                 stack.beginImeAdjustAnimation();
   1991             }
   1992         }
   1993     }
   1994 
   1995     void adjustForImeIfNeeded() {
   1996         final WindowState imeWin = mService.mInputMethodWindow;
   1997         final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
   1998                 && !mDividerControllerLocked.isImeHideRequested();
   1999         final boolean dockVisible = isStackVisible(DOCKED_STACK_ID);
   2000         final TaskStack imeTargetStack = mService.getImeFocusStackLocked();
   2001         final int imeDockSide = (dockVisible && imeTargetStack != null) ?
   2002                 imeTargetStack.getDockSide() : DOCKED_INVALID;
   2003         final boolean imeOnTop = (imeDockSide == DOCKED_TOP);
   2004         final boolean imeOnBottom = (imeDockSide == DOCKED_BOTTOM);
   2005         final boolean dockMinimized = mDividerControllerLocked.isMinimizedDock();
   2006         final int imeHeight = mService.mPolicy.getInputMethodWindowVisibleHeightLw();
   2007         final boolean imeHeightChanged = imeVisible &&
   2008                 imeHeight != mDividerControllerLocked.getImeHeightAdjustedFor();
   2009 
   2010         // The divider could be adjusted for IME position, or be thinner than usual,
   2011         // or both. There are three possible cases:
   2012         // - If IME is visible, and focus is on top, divider is not moved for IME but thinner.
   2013         // - If IME is visible, and focus is on bottom, divider is moved for IME and thinner.
   2014         // - If IME is not visible, divider is not moved and is normal width.
   2015 
   2016         if (imeVisible && dockVisible && (imeOnTop || imeOnBottom) && !dockMinimized) {
   2017             for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
   2018                 final TaskStack stack = mTaskStackContainers.get(i);
   2019                 final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
   2020                 if (stack.isVisible() && (imeOnBottom || isDockedOnBottom) &&
   2021                         StackId.isStackAffectedByDragResizing(stack.mStackId)) {
   2022                     stack.setAdjustedForIme(imeWin, imeOnBottom && imeHeightChanged);
   2023                 } else {
   2024                     stack.resetAdjustedForIme(false);
   2025                 }
   2026             }
   2027             mDividerControllerLocked.setAdjustedForIme(
   2028                     imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin, imeHeight);
   2029         } else {
   2030             for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
   2031                 final TaskStack stack = mTaskStackContainers.get(i);
   2032                 stack.resetAdjustedForIme(!dockVisible);
   2033             }
   2034             mDividerControllerLocked.setAdjustedForIme(
   2035                     false /*ime*/, false /*divider*/, dockVisible /*animate*/, imeWin, imeHeight);
   2036         }
   2037         mPinnedStackControllerLocked.setAdjustedForIme(imeVisible, imeHeight);
   2038     }
   2039 
   2040     void setInputMethodAnimLayerAdjustment(int adj) {
   2041         if (DEBUG_LAYERS) Slog.v(TAG_WM, "Setting im layer adj to " + adj);
   2042         mInputMethodAnimLayerAdjustment = adj;
   2043         assignWindowLayers(false /* relayoutNeeded */);
   2044     }
   2045 
   2046     /**
   2047      * If a window that has an animation specifying a colored background and the current wallpaper
   2048      * is visible, then the color goes *below* the wallpaper so we don't cause the wallpaper to
   2049      * suddenly disappear.
   2050      */
   2051     int getLayerForAnimationBackground(WindowStateAnimator winAnimator) {
   2052         final WindowState visibleWallpaper = mBelowAppWindowsContainers.getWindow(
   2053                 w -> w.mIsWallpaper && w.isVisibleNow());
   2054 
   2055         if (visibleWallpaper != null) {
   2056             return visibleWallpaper.mWinAnimator.mAnimLayer;
   2057         }
   2058         return winAnimator.mAnimLayer;
   2059     }
   2060 
   2061     void prepareFreezingTaskBounds() {
   2062         for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
   2063             final TaskStack stack = mTaskStackContainers.get(stackNdx);
   2064             stack.prepareFreezingTaskBounds();
   2065         }
   2066     }
   2067 
   2068     void rotateBounds(int oldRotation, int newRotation, Rect bounds) {
   2069         getLogicalDisplayRect(mTmpRect, newRotation);
   2070 
   2071         // Compute a transform matrix to undo the coordinate space transformation,
   2072         // and present the window at the same physical position it previously occupied.
   2073         final int deltaRotation = deltaRotation(newRotation, oldRotation);
   2074         createRotationMatrix(deltaRotation, mTmpRect.width(), mTmpRect.height(), mTmpMatrix);
   2075 
   2076         mTmpRectF.set(bounds);
   2077         mTmpMatrix.mapRect(mTmpRectF);
   2078         mTmpRectF.round(bounds);
   2079     }
   2080 
   2081     static int deltaRotation(int oldRotation, int newRotation) {
   2082         int delta = newRotation - oldRotation;
   2083         if (delta < 0) delta += 4;
   2084         return delta;
   2085     }
   2086 
   2087     private static void createRotationMatrix(int rotation, float displayWidth, float displayHeight,
   2088             Matrix outMatrix) {
   2089         // For rotations without Z-ordering we don't need the target rectangle's position.
   2090         createRotationMatrix(rotation, 0 /* rectLeft */, 0 /* rectTop */, displayWidth,
   2091                 displayHeight, outMatrix);
   2092     }
   2093 
   2094     static void createRotationMatrix(int rotation, float rectLeft, float rectTop,
   2095             float displayWidth, float displayHeight, Matrix outMatrix) {
   2096         switch (rotation) {
   2097             case ROTATION_0:
   2098                 outMatrix.reset();
   2099                 break;
   2100             case ROTATION_270:
   2101                 outMatrix.setRotate(270, 0, 0);
   2102                 outMatrix.postTranslate(0, displayHeight);
   2103                 outMatrix.postTranslate(rectTop, 0);
   2104                 break;
   2105             case ROTATION_180:
   2106                 outMatrix.reset();
   2107                 break;
   2108             case ROTATION_90:
   2109                 outMatrix.setRotate(90, 0, 0);
   2110                 outMatrix.postTranslate(displayWidth, 0);
   2111                 outMatrix.postTranslate(-rectTop, rectLeft);
   2112                 break;
   2113         }
   2114     }
   2115 
   2116     public void dump(String prefix, PrintWriter pw) {
   2117         pw.print(prefix); pw.print("Display: mDisplayId="); pw.println(mDisplayId);
   2118         final String subPrefix = "  " + prefix;
   2119         pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
   2120             pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
   2121             pw.print("dpi");
   2122             if (mInitialDisplayWidth != mBaseDisplayWidth
   2123                     || mInitialDisplayHeight != mBaseDisplayHeight
   2124                     || mInitialDisplayDensity != mBaseDisplayDensity) {
   2125                 pw.print(" base=");
   2126                 pw.print(mBaseDisplayWidth); pw.print("x"); pw.print(mBaseDisplayHeight);
   2127                 pw.print(" "); pw.print(mBaseDisplayDensity); pw.print("dpi");
   2128             }
   2129             if (mDisplayScalingDisabled) {
   2130                 pw.println(" noscale");
   2131             }
   2132             pw.print(" cur=");
   2133             pw.print(mDisplayInfo.logicalWidth);
   2134             pw.print("x"); pw.print(mDisplayInfo.logicalHeight);
   2135             pw.print(" app=");
   2136             pw.print(mDisplayInfo.appWidth);
   2137             pw.print("x"); pw.print(mDisplayInfo.appHeight);
   2138             pw.print(" rng="); pw.print(mDisplayInfo.smallestNominalAppWidth);
   2139             pw.print("x"); pw.print(mDisplayInfo.smallestNominalAppHeight);
   2140             pw.print("-"); pw.print(mDisplayInfo.largestNominalAppWidth);
   2141             pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight);
   2142             pw.print(subPrefix + "deferred=" + mDeferredRemoval
   2143                     + " mLayoutNeeded=" + mLayoutNeeded);
   2144             pw.println(" mTouchExcludeRegion=" + mTouchExcludeRegion);
   2145 
   2146         pw.println();
   2147         pw.println(prefix + "Application tokens in top down Z order:");
   2148         for (int stackNdx = mTaskStackContainers.size() - 1; stackNdx >= 0; --stackNdx) {
   2149             final TaskStack stack = mTaskStackContainers.get(stackNdx);
   2150             stack.dump(prefix + "  ", pw);
   2151         }
   2152 
   2153         pw.println();
   2154         if (!mExitingTokens.isEmpty()) {
   2155             pw.println();
   2156             pw.println("  Exiting tokens:");
   2157             for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
   2158                 final WindowToken token = mExitingTokens.get(i);
   2159                 pw.print("  Exiting #"); pw.print(i);
   2160                 pw.print(' '); pw.print(token);
   2161                 pw.println(':');
   2162                 token.dump(pw, "    ");
   2163             }
   2164         }
   2165         pw.println();
   2166         mDimLayerController.dump(prefix, pw);
   2167         pw.println();
   2168         mDividerControllerLocked.dump(prefix, pw);
   2169         pw.println();
   2170         mPinnedStackControllerLocked.dump(prefix, pw);
   2171 
   2172         if (mInputMethodAnimLayerAdjustment != 0) {
   2173             pw.println(subPrefix
   2174                     + "mInputMethodAnimLayerAdjustment=" + mInputMethodAnimLayerAdjustment);
   2175         }
   2176     }
   2177 
   2178     @Override
   2179     public String toString() {
   2180         return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mChildren;
   2181     }
   2182 
   2183     String getName() {
   2184         return "Display " + mDisplayId + " name=\"" + mDisplayInfo.name + "\"";
   2185     }
   2186 
   2187     /** Checks if stack with provided id is visible on this display. */
   2188     boolean isStackVisible(int stackId) {
   2189         final TaskStack stack = getStackById(stackId);
   2190         return (stack != null && stack.isVisible());
   2191     }
   2192 
   2193     /**
   2194      * @return The docked stack, but only if it is visible, and {@code null} otherwise.
   2195      */
   2196     TaskStack getDockedStackLocked() {
   2197         final TaskStack stack = getStackById(DOCKED_STACK_ID);
   2198         return (stack != null && stack.isVisible()) ? stack : null;
   2199     }
   2200 
   2201     /**
   2202      * Like {@link #getDockedStackLocked}, but also returns the docked stack if it's currently not
   2203      * visible.
   2204      */
   2205     TaskStack getDockedStackIgnoringVisibility() {
   2206         return getStackById(DOCKED_STACK_ID);
   2207     }
   2208 
   2209     /** Find the visible, touch-deliverable window under the given point */
   2210     WindowState getTouchableWinAtPointLocked(float xf, float yf) {
   2211         final int x = (int) xf;
   2212         final int y = (int) yf;
   2213         final WindowState touchedWin = getWindow(w -> {
   2214             final int flags = w.mAttrs.flags;
   2215             if (!w.isVisibleLw()) {
   2216                 return false;
   2217             }
   2218             if ((flags & FLAG_NOT_TOUCHABLE) != 0) {
   2219                 return false;
   2220             }
   2221 
   2222             w.getVisibleBounds(mTmpRect);
   2223             if (!mTmpRect.contains(x, y)) {
   2224                 return false;
   2225             }
   2226 
   2227             w.getTouchableRegion(mTmpRegion);
   2228 
   2229             final int touchFlags = flags & (FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL);
   2230             return mTmpRegion.contains(x, y) || touchFlags == 0;
   2231         });
   2232 
   2233         return touchedWin;
   2234     }
   2235 
   2236     boolean canAddToastWindowForUid(int uid) {
   2237         // We allow one toast window per UID being shown at a time.
   2238         // Also if the app is focused adding more than one toast at
   2239         // a time for better backwards compatibility.
   2240         final WindowState focusedWindowForUid = getWindow(w ->
   2241                 w.mOwnerUid == uid && w.isFocused());
   2242         if (focusedWindowForUid != null) {
   2243             return true;
   2244         }
   2245         final WindowState win = getWindow(w ->
   2246                 w.mAttrs.type == TYPE_TOAST && w.mOwnerUid == uid && !w.mPermanentlyHidden
   2247                 && !w.mWindowRemovalAllowed);
   2248         return win == null;
   2249     }
   2250 
   2251     void scheduleToastWindowsTimeoutIfNeededLocked(WindowState oldFocus, WindowState newFocus) {
   2252         if (oldFocus == null || (newFocus != null && newFocus.mOwnerUid == oldFocus.mOwnerUid)) {
   2253             return;
   2254         }
   2255 
   2256         // Used to communicate the old focus to the callback method.
   2257         mTmpWindow = oldFocus;
   2258 
   2259         forAllWindows(mScheduleToastTimeout, false /* traverseTopToBottom */);
   2260     }
   2261 
   2262     WindowState findFocusedWindow() {
   2263         mTmpWindow = null;
   2264 
   2265         forAllWindows(mFindFocusedWindow, true /* traverseTopToBottom */);
   2266 
   2267         if (mTmpWindow == null) {
   2268             if (DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM, "findFocusedWindow: No focusable windows.");
   2269             return null;
   2270         }
   2271         return mTmpWindow;
   2272     }
   2273 
   2274     /** Updates the layer assignment of windows on this display. */
   2275     void assignWindowLayers(boolean setLayoutNeeded) {
   2276         mLayersController.assignWindowLayers(this);
   2277         if (setLayoutNeeded) {
   2278             setLayoutNeeded();
   2279         }
   2280     }
   2281 
   2282     // TODO: This should probably be called any time a visual change is made to the hierarchy like
   2283     // moving containers or resizing them. Need to investigate the best way to have it automatically
   2284     // happen so we don't run into issues with programmers forgetting to do it.
   2285     void layoutAndAssignWindowLayersIfNeeded() {
   2286         mService.mWindowsChanged = true;
   2287         setLayoutNeeded();
   2288 
   2289         if (!mService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
   2290                 false /*updateInputWindows*/)) {
   2291             assignWindowLayers(false /* setLayoutNeeded */);
   2292         }
   2293 
   2294         mService.mInputMonitor.setUpdateInputWindowsNeededLw();
   2295         mService.mWindowPlacerLocked.performSurfacePlacement();
   2296         mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
   2297     }
   2298 
   2299     /** Returns true if a leaked surface was destroyed */
   2300     boolean destroyLeakedSurfaces() {
   2301         // Used to indicate that a surface was leaked.
   2302         mTmpWindow = null;
   2303         forAllWindows(w -> {
   2304             final WindowStateAnimator wsa = w.mWinAnimator;
   2305             if (wsa.mSurfaceController == null) {
   2306                 return;
   2307             }
   2308             if (!mService.mSessions.contains(wsa.mSession)) {
   2309                 Slog.w(TAG_WM, "LEAKED SURFACE (session doesn't exist): "
   2310                         + w + " surface=" + wsa.mSurfaceController
   2311                         + " token=" + w.mToken
   2312                         + " pid=" + w.mSession.mPid
   2313                         + " uid=" + w.mSession.mUid);
   2314                 wsa.destroySurface();
   2315                 mService.mForceRemoves.add(w);
   2316                 mTmpWindow = w;
   2317             } else if (w.mAppToken != null && w.mAppToken.isClientHidden()) {
   2318                 Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
   2319                         + w + " surface=" + wsa.mSurfaceController
   2320                         + " token=" + w.mAppToken
   2321                         + " saved=" + w.hasSavedSurface());
   2322                 if (SHOW_TRANSACTIONS) logSurface(w, "LEAK DESTROY", false);
   2323                 wsa.destroySurface();
   2324                 mTmpWindow = w;
   2325             }
   2326         }, false /* traverseTopToBottom */);
   2327 
   2328         return mTmpWindow != null;
   2329     }
   2330 
   2331     /**
   2332      * Determine and return the window that should be the IME target.
   2333      * @param updateImeTarget If true the system IME target will be updated to match what we found.
   2334      * @return The window that should be used as the IME target or null if there isn't any.
   2335      */
   2336     WindowState computeImeTarget(boolean updateImeTarget) {
   2337         if (mService.mInputMethodWindow == null) {
   2338             // There isn't an IME so there shouldn't be a target...That was easy!
   2339             if (updateImeTarget) {
   2340                 if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from "
   2341                         + mService.mInputMethodTarget + " to null since mInputMethodWindow is null");
   2342                 setInputMethodTarget(null, mService.mInputMethodTargetWaitingAnim, 0);
   2343             }
   2344             return null;
   2345         }
   2346 
   2347         // TODO(multidisplay): Needs some serious rethought when the target and IME are not on the
   2348         // same display. Or even when the current IME/target are not on the same screen as the next
   2349         // IME/target. For now only look for input windows on the main screen.
   2350         mUpdateImeTarget = updateImeTarget;
   2351         WindowState target = getWindow(mComputeImeTargetPredicate);
   2352 
   2353 
   2354         // Yet more tricksyness!  If this window is a "starting" window, we do actually want
   2355         // to be on top of it, but it is not -really- where input will go. So look down below
   2356         // for a real window to target...
   2357         if (target != null && target.mAttrs.type == TYPE_APPLICATION_STARTING) {
   2358             final AppWindowToken token = target.mAppToken;
   2359             if (token != null) {
   2360                 final WindowState betterTarget = token.getImeTargetBelowWindow(target);
   2361                 if (betterTarget != null) {
   2362                     target = betterTarget;
   2363                 }
   2364             }
   2365         }
   2366 
   2367         if (DEBUG_INPUT_METHOD && updateImeTarget) Slog.v(TAG_WM,
   2368                 "Proposed new IME target: " + target);
   2369 
   2370         // Now, a special case -- if the last target's window is in the process of exiting, and is
   2371         // above the new target, keep on the last target to avoid flicker. Consider for example a
   2372         // Dialog with the IME shown: when the Dialog is dismissed, we want to keep the IME above it
   2373         // until it is completely gone so it doesn't drop behind the dialog or its full-screen
   2374         // scrim.
   2375         final WindowState curTarget = mService.mInputMethodTarget;
   2376         if (curTarget != null && curTarget.isDisplayedLw() && curTarget.isClosing()
   2377                 && (target == null
   2378                     || curTarget.mWinAnimator.mAnimLayer > target.mWinAnimator.mAnimLayer)) {
   2379             if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Current target higher, not changing");
   2380             return curTarget;
   2381         }
   2382 
   2383         if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, "Desired input method target=" + target
   2384                 + " updateImeTarget=" + updateImeTarget);
   2385 
   2386         if (target == null) {
   2387             if (updateImeTarget) {
   2388                 if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget
   2389                         + " to null." + (SHOW_STACK_CRAWLS ? " Callers="
   2390                         + Debug.getCallers(4) : ""));
   2391                 setInputMethodTarget(null, mService.mInputMethodTargetWaitingAnim, 0);
   2392             }
   2393 
   2394             return null;
   2395         }
   2396 
   2397         if (updateImeTarget) {
   2398             AppWindowToken token = curTarget == null ? null : curTarget.mAppToken;
   2399             if (token != null) {
   2400 
   2401                 // Now some fun for dealing with window animations that modify the Z order. We need
   2402                 // to look at all windows below the current target that are in this app, finding the
   2403                 // highest visible one in layering.
   2404                 WindowState highestTarget = null;
   2405                 if (token.mAppAnimator.animating || token.mAppAnimator.animation != null) {
   2406                     highestTarget = token.getHighestAnimLayerWindow(curTarget);
   2407                 }
   2408 
   2409                 if (highestTarget != null) {
   2410                     final AppTransition appTransition = mService.mAppTransition;
   2411                     if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, appTransition + " " + highestTarget
   2412                             + " animating=" + highestTarget.mWinAnimator.isAnimationSet()
   2413                             + " layer=" + highestTarget.mWinAnimator.mAnimLayer
   2414                             + " new layer=" + target.mWinAnimator.mAnimLayer);
   2415 
   2416                     if (appTransition.isTransitionSet()) {
   2417                         // If we are currently setting up for an animation, hold everything until we
   2418                         // can find out what will happen.
   2419                         setInputMethodTarget(highestTarget, true, mInputMethodAnimLayerAdjustment);
   2420                         return highestTarget;
   2421                     } else if (highestTarget.mWinAnimator.isAnimationSet() &&
   2422                             highestTarget.mWinAnimator.mAnimLayer > target.mWinAnimator.mAnimLayer) {
   2423                         // If the window we are currently targeting is involved with an animation,
   2424                         // and it is on top of the next target we will be over, then hold off on
   2425                         // moving until that is done.
   2426                         setInputMethodTarget(highestTarget, true, mInputMethodAnimLayerAdjustment);
   2427                         return highestTarget;
   2428                     }
   2429                 }
   2430             }
   2431 
   2432             if (DEBUG_INPUT_METHOD) Slog.w(TAG_WM, "Moving IM target from " + curTarget + " to "
   2433                     + target + (SHOW_STACK_CRAWLS ? " Callers=" + Debug.getCallers(4) : ""));
   2434             setInputMethodTarget(target, false, target.mAppToken != null
   2435                     ? target.mAppToken.getAnimLayerAdjustment() : 0);
   2436         }
   2437 
   2438         return target;
   2439     }
   2440 
   2441     private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim, int layerAdj) {
   2442         if (target == mService.mInputMethodTarget
   2443                 && mService.mInputMethodTargetWaitingAnim == targetWaitingAnim
   2444                 && mInputMethodAnimLayerAdjustment == layerAdj) {
   2445             return;
   2446         }
   2447 
   2448         mService.mInputMethodTarget = target;
   2449         mService.mInputMethodTargetWaitingAnim = targetWaitingAnim;
   2450         setInputMethodAnimLayerAdjustment(layerAdj);
   2451         assignWindowLayers(false /* setLayoutNeeded */);
   2452     }
   2453 
   2454     boolean getNeedsMenu(WindowState top, WindowManagerPolicy.WindowState bottom) {
   2455         if (top.mAttrs.needsMenuKey != NEEDS_MENU_UNSET) {
   2456             return top.mAttrs.needsMenuKey == NEEDS_MENU_SET_TRUE;
   2457         }
   2458 
   2459         // Used to indicate we have reached the first window in the range we are interested in.
   2460         mTmpWindow = null;
   2461 
   2462         // TODO: Figure-out a more efficient way to do this.
   2463         final WindowState candidate = getWindow(w -> {
   2464             if (w == top) {
   2465                 // Reached the first window in the range we are interested in.
   2466                 mTmpWindow = w;
   2467             }
   2468             if (mTmpWindow == null) {
   2469                 return false;
   2470             }
   2471 
   2472             if (w.mAttrs.needsMenuKey != NEEDS_MENU_UNSET) {
   2473                 return true;
   2474             }
   2475             // If we reached the bottom of the range of windows we are considering,
   2476             // assume no menu is needed.
   2477             if (w == bottom) {
   2478                 return true;
   2479             }
   2480             return false;
   2481         });
   2482 
   2483         return candidate != null && candidate.mAttrs.needsMenuKey == NEEDS_MENU_SET_TRUE;
   2484     }
   2485 
   2486     void setLayoutNeeded() {
   2487         if (DEBUG_LAYOUT) Slog.w(TAG_WM, "setLayoutNeeded: callers=" + Debug.getCallers(3));
   2488         mLayoutNeeded = true;
   2489     }
   2490 
   2491     private void clearLayoutNeeded() {
   2492         if (DEBUG_LAYOUT) Slog.w(TAG_WM, "clearLayoutNeeded: callers=" + Debug.getCallers(3));
   2493         mLayoutNeeded = false;
   2494     }
   2495 
   2496     boolean isLayoutNeeded() {
   2497         return mLayoutNeeded;
   2498     }
   2499 
   2500     void dumpTokens(PrintWriter pw, boolean dumpAll) {
   2501         if (mTokenMap.isEmpty()) {
   2502             return;
   2503         }
   2504         pw.println("  Display #" + mDisplayId);
   2505         final Iterator<WindowToken> it = mTokenMap.values().iterator();
   2506         while (it.hasNext()) {
   2507             final WindowToken token = it.next();
   2508             pw.print("  ");
   2509             pw.print(token);
   2510             if (dumpAll) {
   2511                 pw.println(':');
   2512                 token.dump(pw, "    ");
   2513             } else {
   2514                 pw.println();
   2515             }
   2516         }
   2517     }
   2518 
   2519     void dumpWindowAnimators(PrintWriter pw, String subPrefix) {
   2520         final int[] index = new int[1];
   2521         forAllWindows(w -> {
   2522             final WindowStateAnimator wAnim = w.mWinAnimator;
   2523             pw.println(subPrefix + "Window #" + index[0] + ": " + wAnim);
   2524             index[0] = index[0] + 1;
   2525         }, false /* traverseTopToBottom */);
   2526     }
   2527 
   2528     void enableSurfaceTrace(FileDescriptor fd) {
   2529         forAllWindows(w -> {
   2530             w.mWinAnimator.enableSurfaceTrace(fd);
   2531         }, true /* traverseTopToBottom */);
   2532     }
   2533 
   2534     void disableSurfaceTrace() {
   2535         forAllWindows(w -> {
   2536             w.mWinAnimator.disableSurfaceTrace();
   2537         }, true /* traverseTopToBottom */);
   2538     }
   2539 
   2540     /**
   2541      * Starts the Keyguard exit animation on all windows that don't belong to an app token.
   2542      */
   2543     void startKeyguardExitOnNonAppWindows(boolean onWallpaper, boolean goingToShade) {
   2544         final WindowManagerPolicy policy = mService.mPolicy;
   2545         forAllWindows(w -> {
   2546             if (w.mAppToken == null && policy.canBeHiddenByKeyguardLw(w)
   2547                     && w.wouldBeVisibleIfPolicyIgnored() && !w.isVisible()) {
   2548                 w.mWinAnimator.setAnimation(
   2549                         policy.createHiddenByKeyguardExit(onWallpaper, goingToShade));
   2550             }
   2551         }, true /* traverseTopToBottom */);
   2552     }
   2553 
   2554     boolean checkWaitingForWindows() {
   2555 
   2556         mHaveBootMsg = false;
   2557         mHaveApp = false;
   2558         mHaveWallpaper = false;
   2559         mHaveKeyguard = true;
   2560 
   2561         final WindowState visibleWindow = getWindow(w -> {
   2562             if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) {
   2563                 return true;
   2564             }
   2565             if (w.isDrawnLw()) {
   2566                 if (w.mAttrs.type == TYPE_BOOT_PROGRESS) {
   2567                     mHaveBootMsg = true;
   2568                 } else if (w.mAttrs.type == TYPE_APPLICATION
   2569                         || w.mAttrs.type == TYPE_DRAWN_APPLICATION) {
   2570                     mHaveApp = true;
   2571                 } else if (w.mAttrs.type == TYPE_WALLPAPER) {
   2572                     mHaveWallpaper = true;
   2573                 } else if (w.mAttrs.type == TYPE_STATUS_BAR) {
   2574                     mHaveKeyguard = mService.mPolicy.isKeyguardDrawnLw();
   2575                 }
   2576             }
   2577             return false;
   2578         });
   2579 
   2580         if (visibleWindow != null) {
   2581             // We have a visible window.
   2582             return true;
   2583         }
   2584 
   2585         // if the wallpaper service is disabled on the device, we're never going to have
   2586         // wallpaper, don't bother waiting for it
   2587         boolean wallpaperEnabled = mService.mContext.getResources().getBoolean(
   2588                 com.android.internal.R.bool.config_enableWallpaperService)
   2589                 && !mService.mOnlyCore;
   2590 
   2591         if (DEBUG_SCREEN_ON || DEBUG_BOOT) Slog.i(TAG_WM,
   2592                 "******** booted=" + mService.mSystemBooted
   2593                 + " msg=" + mService.mShowingBootMessages
   2594                 + " haveBoot=" + mHaveBootMsg + " haveApp=" + mHaveApp
   2595                 + " haveWall=" + mHaveWallpaper + " wallEnabled=" + wallpaperEnabled
   2596                 + " haveKeyguard=" + mHaveKeyguard);
   2597 
   2598         // If we are turning on the screen to show the boot message, don't do it until the boot
   2599         // message is actually displayed.
   2600         if (!mService.mSystemBooted && !mHaveBootMsg) {
   2601             return true;
   2602         }
   2603 
   2604         // If we are turning on the screen after the boot is completed normally, don't do so until
   2605         // we have the application and wallpaper.
   2606         if (mService.mSystemBooted
   2607                 && ((!mHaveApp && !mHaveKeyguard) || (wallpaperEnabled && !mHaveWallpaper))) {
   2608             return true;
   2609         }
   2610 
   2611         return false;
   2612     }
   2613 
   2614     void updateWindowsForAnimator(WindowAnimator animator) {
   2615         mTmpWindowAnimator = animator;
   2616         forAllWindows(mUpdateWindowsForAnimator, true /* traverseTopToBottom */);
   2617     }
   2618 
   2619     void updateWallpaperForAnimator(WindowAnimator animator) {
   2620         resetAnimationBackgroundAnimator();
   2621 
   2622         // Used to indicate a detached wallpaper.
   2623         mTmpWindow = null;
   2624         mTmpWindowAnimator = animator;
   2625 
   2626         forAllWindows(mUpdateWallpaperForAnimator, true /* traverseTopToBottom */);
   2627 
   2628         if (animator.mWindowDetachedWallpaper != mTmpWindow) {
   2629             if (DEBUG_WALLPAPER) Slog.v(TAG, "Detached wallpaper changed from "
   2630                     + animator.mWindowDetachedWallpaper + " to " + mTmpWindow);
   2631             animator.mWindowDetachedWallpaper = mTmpWindow;
   2632             animator.mBulkUpdateParams |= SET_WALLPAPER_MAY_CHANGE;
   2633         }
   2634     }
   2635 
   2636     void prepareWindowSurfaces() {
   2637         forAllWindows(mPrepareWindowSurfaces, false /* traverseTopToBottom */);
   2638     }
   2639 
   2640     boolean inputMethodClientHasFocus(IInputMethodClient client) {
   2641         final WindowState imFocus = computeImeTarget(false /* updateImeTarget */);
   2642         if (imFocus == null) {
   2643             return false;
   2644         }
   2645 
   2646         if (DEBUG_INPUT_METHOD) {
   2647             Slog.i(TAG_WM, "Desired input method target: " + imFocus);
   2648             Slog.i(TAG_WM, "Current focus: " + mService.mCurrentFocus);
   2649             Slog.i(TAG_WM, "Last focus: " + mService.mLastFocus);
   2650         }
   2651 
   2652         final IInputMethodClient imeClient = imFocus.mSession.mClient;
   2653 
   2654         if (DEBUG_INPUT_METHOD) {
   2655             Slog.i(TAG_WM, "IM target client: " + imeClient);
   2656             if (imeClient != null) {
   2657                 Slog.i(TAG_WM, "IM target client binder: " + imeClient.asBinder());
   2658                 Slog.i(TAG_WM, "Requesting client binder: " + client.asBinder());
   2659             }
   2660         }
   2661 
   2662         return imeClient != null && imeClient.asBinder() == client.asBinder();
   2663     }
   2664 
   2665     boolean hasSecureWindowOnScreen() {
   2666         final WindowState win = getWindow(
   2667                 w -> w.isOnScreen() && (w.mAttrs.flags & FLAG_SECURE) != 0);
   2668         return win != null;
   2669     }
   2670 
   2671     void updateSystemUiVisibility(int visibility, int globalDiff) {
   2672         forAllWindows(w -> {
   2673             try {
   2674                 final int curValue = w.mSystemUiVisibility;
   2675                 final int diff = (curValue ^ visibility) & globalDiff;
   2676                 final int newValue = (curValue & ~diff) | (visibility & diff);
   2677                 if (newValue != curValue) {
   2678                     w.mSeq++;
   2679                     w.mSystemUiVisibility = newValue;
   2680                 }
   2681                 if (newValue != curValue || w.mAttrs.hasSystemUiListeners) {
   2682                     w.mClient.dispatchSystemUiVisibilityChanged(w.mSeq,
   2683                             visibility, newValue, diff);
   2684                 }
   2685             } catch (RemoteException e) {
   2686                 // so sorry
   2687             }
   2688         }, true /* traverseTopToBottom */);
   2689     }
   2690 
   2691     void onWindowFreezeTimeout() {
   2692         Slog.w(TAG_WM, "Window freeze timeout expired.");
   2693         mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
   2694 
   2695         forAllWindows(w -> {
   2696             if (!w.getOrientationChanging()) {
   2697                 return;
   2698             }
   2699             w.orientationChangeTimedOut();
   2700             w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
   2701                     - mService.mDisplayFreezeTime);
   2702             Slog.w(TAG_WM, "Force clearing orientation change: " + w);
   2703         }, true /* traverseTopToBottom */);
   2704         mService.mWindowPlacerLocked.performSurfacePlacement();
   2705     }
   2706 
   2707     void waitForAllWindowsDrawn() {
   2708         final WindowManagerPolicy policy = mService.mPolicy;
   2709         forAllWindows(w -> {
   2710             final boolean keyguard = policy.isKeyguardHostWindow(w.mAttrs);
   2711             if (w.isVisibleLw() && (w.mAppToken != null || keyguard)) {
   2712                 w.mWinAnimator.mDrawState = DRAW_PENDING;
   2713                 // Force add to mResizingWindows.
   2714                 w.mLastContentInsets.set(-1, -1, -1, -1);
   2715                 mService.mWaitingForDrawn.add(w);
   2716             }
   2717         }, true /* traverseTopToBottom */);
   2718     }
   2719 
   2720     // TODO: Super crazy long method that should be broken down...
   2721     boolean applySurfaceChangesTransaction(boolean recoveringMemory) {
   2722 
   2723         final int dw = mDisplayInfo.logicalWidth;
   2724         final int dh = mDisplayInfo.logicalHeight;
   2725         final WindowSurfacePlacer surfacePlacer = mService.mWindowPlacerLocked;
   2726 
   2727         mTmpUpdateAllDrawn.clear();
   2728 
   2729         int repeats = 0;
   2730         do {
   2731             repeats++;
   2732             if (repeats > 6) {
   2733                 Slog.w(TAG, "Animation repeat aborted after too many iterations");
   2734                 clearLayoutNeeded();
   2735                 break;
   2736             }
   2737 
   2738             if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats("On entry to LockedInner",
   2739                     pendingLayoutChanges);
   2740 
   2741             // TODO(multi-display): For now adjusting wallpaper only on primary display to avoid
   2742             // the wallpaper window jumping across displays.
   2743             // Remove check for default display when there will be support for multiple wallpaper
   2744             // targets (on different displays).
   2745             if (isDefaultDisplay && (pendingLayoutChanges & FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
   2746                 mWallpaperController.adjustWallpaperWindows(this);
   2747             }
   2748 
   2749             if (isDefaultDisplay && (pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
   2750                 if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
   2751                 if (mService.updateOrientationFromAppTokensLocked(true, mDisplayId)) {
   2752                     setLayoutNeeded();
   2753                     mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, mDisplayId).sendToTarget();
   2754                 }
   2755             }
   2756 
   2757             if ((pendingLayoutChanges & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
   2758                 setLayoutNeeded();
   2759             }
   2760 
   2761             // FIRST LOOP: Perform a layout, if needed.
   2762             if (repeats < LAYOUT_REPEAT_THRESHOLD) {
   2763                 performLayout(repeats == 1, false /* updateInputWindows */);
   2764             } else {
   2765                 Slog.w(TAG, "Layout repeat skipped after too many iterations");
   2766             }
   2767 
   2768             // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think it is animating.
   2769             pendingLayoutChanges = 0;
   2770 
   2771             if (isDefaultDisplay) {
   2772                 mService.mPolicy.beginPostLayoutPolicyLw(dw, dh);
   2773                 forAllWindows(mApplyPostLayoutPolicy, true /* traverseTopToBottom */);
   2774                 pendingLayoutChanges |= mService.mPolicy.finishPostLayoutPolicyLw();
   2775                 if (DEBUG_LAYOUT_REPEATS) surfacePlacer.debugLayoutRepeats(
   2776                         "after finishPostLayoutPolicyLw", pendingLayoutChanges);
   2777             }
   2778         } while (pendingLayoutChanges != 0);
   2779 
   2780         mTmpApplySurfaceChangesTransactionState.reset();
   2781         resetDimming();
   2782 
   2783         mTmpRecoveringMemory = recoveringMemory;
   2784         forAllWindows(mApplySurfaceChangesTransaction, true /* traverseTopToBottom */);
   2785 
   2786         mService.mDisplayManagerInternal.setDisplayProperties(mDisplayId,
   2787                 mTmpApplySurfaceChangesTransactionState.displayHasContent,
   2788                 mTmpApplySurfaceChangesTransactionState.preferredRefreshRate,
   2789                 mTmpApplySurfaceChangesTransactionState.preferredModeId,
   2790                 true /* inTraversal, must call performTraversalInTrans... below */);
   2791 
   2792         stopDimmingIfNeeded();
   2793 
   2794         final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
   2795         if (wallpaperVisible != mLastWallpaperVisible) {
   2796             mLastWallpaperVisible = wallpaperVisible;
   2797             mService.mWallpaperVisibilityListeners.notifyWallpaperVisibilityChanged(this);
   2798         }
   2799 
   2800         while (!mTmpUpdateAllDrawn.isEmpty()) {
   2801             final AppWindowToken atoken = mTmpUpdateAllDrawn.removeLast();
   2802             // See if any windows have been drawn, so they (and others associated with them)
   2803             // can now be shown.
   2804             atoken.updateAllDrawn();
   2805         }
   2806 
   2807         return mTmpApplySurfaceChangesTransactionState.focusDisplayed;
   2808     }
   2809 
   2810     void performLayout(boolean initial, boolean updateInputWindows) {
   2811         if (!isLayoutNeeded()) {
   2812             return;
   2813         }
   2814         clearLayoutNeeded();
   2815 
   2816         final int dw = mDisplayInfo.logicalWidth;
   2817         final int dh = mDisplayInfo.logicalHeight;
   2818 
   2819         if (DEBUG_LAYOUT) {
   2820             Slog.v(TAG, "-------------------------------------");
   2821             Slog.v(TAG, "performLayout: needed=" + isLayoutNeeded() + " dw=" + dw + " dh=" + dh);
   2822         }
   2823 
   2824         mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation,
   2825                 getConfiguration().uiMode);
   2826         if (isDefaultDisplay) {
   2827             // Not needed on non-default displays.
   2828             mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw();
   2829             mService.mScreenRect.set(0, 0, dw, dh);
   2830         }
   2831 
   2832         mService.mPolicy.getContentRectLw(mContentRect);
   2833 
   2834         int seq = mService.mLayoutSeq + 1;
   2835         if (seq < 0) seq = 0;
   2836         mService.mLayoutSeq = seq;
   2837 
   2838         // Used to indicate that we have processed the dream window and all additional windows are
   2839         // behind it.
   2840         mTmpWindow = null;
   2841         mTmpInitial = initial;
   2842 
   2843         // First perform layout of any root windows (not attached to another window).
   2844         forAllWindows(mPerformLayout, true /* traverseTopToBottom */);
   2845 
   2846         // Used to indicate that we have processed the dream window and all additional attached
   2847         // windows are behind it.
   2848         mTmpWindow2 = mTmpWindow;
   2849         mTmpWindow = null;
   2850 
   2851         // Now perform layout of attached windows, which usually depend on the position of the
   2852         // window they are attached to. XXX does not deal with windows that are attached to windows
   2853         // that are themselves attached.
   2854         forAllWindows(mPerformLayoutAttached, true /* traverseTopToBottom */);
   2855 
   2856         // Window frames may have changed. Tell the input dispatcher about it.
   2857         mService.mInputMonitor.layoutInputConsumers(dw, dh);
   2858         mService.mInputMonitor.setUpdateInputWindowsNeededLw();
   2859         if (updateInputWindows) {
   2860             mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
   2861         }
   2862 
   2863         mService.mPolicy.finishLayoutLw();
   2864         mService.mH.sendEmptyMessage(UPDATE_DOCKED_STACK_DIVIDER);
   2865     }
   2866 
   2867     /**
   2868      * Takes a snapshot of the display.  In landscape mode this grabs the whole screen.
   2869      * In portrait mode, it grabs the full screenshot.
   2870      *
   2871      * @param width the width of the target bitmap
   2872      * @param height the height of the target bitmap
   2873      * @param includeFullDisplay true if the screen should not be cropped before capture
   2874      * @param frameScale the scale to apply to the frame, only used when width = -1 and height = -1
   2875      * @param config of the output bitmap
   2876      * @param wallpaperOnly true if only the wallpaper layer should be included in the screenshot
   2877      * @param includeDecor whether to include window decors, like the status or navigation bar
   2878      *                     background of the window
   2879      */
   2880     Bitmap screenshotApplications(IBinder appToken, int width, int height,
   2881             boolean includeFullDisplay, float frameScale, Bitmap.Config config,
   2882             boolean wallpaperOnly, boolean includeDecor) {
   2883         Bitmap bitmap = screenshotApplications(appToken, width, height, includeFullDisplay,
   2884                 frameScale, wallpaperOnly, includeDecor, SurfaceControl::screenshot);
   2885         if (bitmap == null) {
   2886             return null;
   2887         }
   2888 
   2889         if (DEBUG_SCREENSHOT) {
   2890             // TEST IF IT's ALL BLACK
   2891             int[] buffer = new int[bitmap.getWidth() * bitmap.getHeight()];
   2892             bitmap.getPixels(buffer, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(),
   2893                     bitmap.getHeight());
   2894             boolean allBlack = true;
   2895             final int firstColor = buffer[0];
   2896             for (int i = 0; i < buffer.length; i++) {
   2897                 if (buffer[i] != firstColor) {
   2898                     allBlack = false;
   2899                     break;
   2900                 }
   2901             }
   2902             if (allBlack) {
   2903                 final WindowState appWin = mScreenshotApplicationState.appWin;
   2904                 final int maxLayer = mScreenshotApplicationState.maxLayer;
   2905                 final int minLayer = mScreenshotApplicationState.minLayer;
   2906                 Slog.i(TAG_WM, "Screenshot " + appWin + " was monochrome(" +
   2907                         Integer.toHexString(firstColor) + ")! mSurfaceLayer=" +
   2908                         (appWin != null ?
   2909                                 appWin.mWinAnimator.mSurfaceController.getLayer() : "null") +
   2910                         " minLayer=" + minLayer + " maxLayer=" + maxLayer);
   2911             }
   2912         }
   2913 
   2914         // Create a copy of the screenshot that is immutable and backed in ashmem.
   2915         // This greatly reduces the overhead of passing the bitmap between processes.
   2916         Bitmap ret = bitmap.createAshmemBitmap(config);
   2917         bitmap.recycle();
   2918         return ret;
   2919     }
   2920 
   2921     GraphicBuffer screenshotApplicationsToBuffer(IBinder appToken, int width, int height,
   2922             boolean includeFullDisplay, float frameScale, boolean wallpaperOnly,
   2923             boolean includeDecor) {
   2924         return screenshotApplications(appToken, width, height, includeFullDisplay, frameScale,
   2925                 wallpaperOnly, includeDecor, SurfaceControl::screenshotToBuffer);
   2926     }
   2927 
   2928     private <E> E screenshotApplications(IBinder appToken, int width, int height,
   2929             boolean includeFullDisplay, float frameScale, boolean wallpaperOnly,
   2930             boolean includeDecor, Screenshoter<E> screenshoter) {
   2931         int dw = mDisplayInfo.logicalWidth;
   2932         int dh = mDisplayInfo.logicalHeight;
   2933         if (dw == 0 || dh == 0) {
   2934             if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + appToken
   2935                     + ": returning null. logical widthxheight=" + dw + "x" + dh);
   2936             return null;
   2937         }
   2938 
   2939         E bitmap;
   2940 
   2941         mScreenshotApplicationState.reset(appToken == null && !wallpaperOnly);
   2942         final Rect frame = new Rect();
   2943         final Rect stackBounds = new Rect();
   2944 
   2945         final int aboveAppLayer = (mService.mPolicy.getWindowLayerFromTypeLw(TYPE_APPLICATION) + 1)
   2946                 * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
   2947         final MutableBoolean mutableIncludeFullDisplay = new MutableBoolean(includeFullDisplay);
   2948         synchronized(mService.mWindowMap) {
   2949             if (!mService.mPolicy.isScreenOn()) {
   2950                 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Attempted to take screenshot while display"
   2951                         + " was off.");
   2952                 return null;
   2953             }
   2954             // Figure out the part of the screen that is actually the app.
   2955             mScreenshotApplicationState.appWin = null;
   2956             forAllWindows(w -> {
   2957                 if (!w.mHasSurface) {
   2958                     return false;
   2959                 }
   2960                 if (w.mLayer >= aboveAppLayer) {
   2961                     return false;
   2962                 }
   2963                 if (wallpaperOnly && !w.mIsWallpaper) {
   2964                     return false;
   2965                 }
   2966                 if (w.mIsImWindow) {
   2967                     return false;
   2968                 } else if (w.mIsWallpaper) {
   2969                     // If this is the wallpaper layer and we're only looking for the wallpaper layer
   2970                     // then the target window state is this one.
   2971                     if (wallpaperOnly) {
   2972                         mScreenshotApplicationState.appWin = w;
   2973                     }
   2974 
   2975                     if (mScreenshotApplicationState.appWin == null) {
   2976                         // We have not ran across the target window yet, so it is probably behind
   2977                         // the wallpaper. This can happen when the keyguard is up and all windows
   2978                         // are moved behind the wallpaper. We don't want to include the wallpaper
   2979                         // layer in the screenshot as it will cover-up the layer of the target
   2980                         // window.
   2981                         return false;
   2982                     }
   2983                     // Fall through. The target window is in front of the wallpaper. For this
   2984                     // case we want to include the wallpaper layer in the screenshot because
   2985                     // the target window might have some transparent areas.
   2986                 } else if (appToken != null) {
   2987                     if (w.mAppToken == null || w.mAppToken.token != appToken) {
   2988                         // This app window is of no interest if it is not associated with the
   2989                         // screenshot app.
   2990                         return false;
   2991                     }
   2992                     mScreenshotApplicationState.appWin = w;
   2993                 }
   2994 
   2995                 // Include this window.
   2996 
   2997                 final WindowStateAnimator winAnim = w.mWinAnimator;
   2998                 int layer = winAnim.mSurfaceController.getLayer();
   2999                 if (mScreenshotApplicationState.maxLayer < layer) {
   3000                     mScreenshotApplicationState.maxLayer = layer;
   3001                 }
   3002                 if (mScreenshotApplicationState.minLayer > layer) {
   3003                     mScreenshotApplicationState.minLayer = layer;
   3004                 }
   3005 
   3006                 // Don't include wallpaper in bounds calculation
   3007                 if (!w.mIsWallpaper && !mutableIncludeFullDisplay.value) {
   3008                     if (includeDecor) {
   3009                         final Task task = w.getTask();
   3010                         if (task != null) {
   3011                             task.getBounds(frame);
   3012                         } else {
   3013 
   3014                             // No task bounds? Too bad! Ain't no screenshot then.
   3015                             return true;
   3016                         }
   3017                     } else {
   3018                         final Rect wf = w.mFrame;
   3019                         final Rect cr = w.mContentInsets;
   3020                         int left = wf.left + cr.left;
   3021                         int top = wf.top + cr.top;
   3022                         int right = wf.right - cr.right;
   3023                         int bottom = wf.bottom - cr.bottom;
   3024                         frame.union(left, top, right, bottom);
   3025                         w.getVisibleBounds(stackBounds);
   3026                         if (!Rect.intersects(frame, stackBounds)) {
   3027                             // Set frame empty if there's no intersection.
   3028                             frame.setEmpty();
   3029                         }
   3030                     }
   3031                 }
   3032 
   3033                 final boolean foundTargetWs =
   3034                         (w.mAppToken != null && w.mAppToken.token == appToken)
   3035                                 || (mScreenshotApplicationState.appWin != null && wallpaperOnly);
   3036                 if (foundTargetWs && winAnim.getShown() && winAnim.mLastAlpha > 0f) {
   3037                     mScreenshotApplicationState.screenshotReady = true;
   3038                 }
   3039 
   3040                 if (w.isObscuringDisplay()){
   3041                     return true;
   3042                 }
   3043                 return false;
   3044             }, true /* traverseTopToBottom */);
   3045 
   3046             final WindowState appWin = mScreenshotApplicationState.appWin;
   3047             final boolean screenshotReady = mScreenshotApplicationState.screenshotReady;
   3048             final int maxLayer = mScreenshotApplicationState.maxLayer;
   3049             final int minLayer = mScreenshotApplicationState.minLayer;
   3050 
   3051             if (appToken != null && appWin == null) {
   3052                 // Can't find a window to snapshot.
   3053                 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM,
   3054                         "Screenshot: Couldn't find a surface matching " + appToken);
   3055                 return null;
   3056             }
   3057 
   3058             if (!screenshotReady) {
   3059                 Slog.i(TAG_WM, "Failed to capture screenshot of " + appToken +
   3060                         " appWin=" + (appWin == null ? "null" : (appWin + " drawState=" +
   3061                         appWin.mWinAnimator.mDrawState)));
   3062                 return null;
   3063             }
   3064 
   3065             // Screenshot is ready to be taken. Everything from here below will continue
   3066             // through the bottom of the loop and return a value. We only stay in the loop
   3067             // because we don't want to release the mWindowMap lock until the screenshot is
   3068             // taken.
   3069 
   3070             if (maxLayer == 0) {
   3071                 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot of " + appToken
   3072                         + ": returning null maxLayer=" + maxLayer);
   3073                 return null;
   3074             }
   3075 
   3076             if (!mutableIncludeFullDisplay.value) {
   3077                 // Constrain frame to the screen size.
   3078                 if (!frame.intersect(0, 0, dw, dh)) {
   3079                     frame.setEmpty();
   3080                 }
   3081             } else {
   3082                 // Caller just wants entire display.
   3083                 frame.set(0, 0, dw, dh);
   3084             }
   3085             if (frame.isEmpty()) {
   3086                 return null;
   3087             }
   3088 
   3089             if (width < 0) {
   3090                 width = (int) (frame.width() * frameScale);
   3091             }
   3092             if (height < 0) {
   3093                 height = (int) (frame.height() * frameScale);
   3094             }
   3095 
   3096             // Tell surface flinger what part of the image to crop. Take the top
   3097             // right part of the application, and crop the larger dimension to fit.
   3098             Rect crop = new Rect(frame);
   3099             if (width / (float) frame.width() < height / (float) frame.height()) {
   3100                 int cropWidth = (int)((float)width / (float)height * frame.height());
   3101                 crop.right = crop.left + cropWidth;
   3102             } else {
   3103                 int cropHeight = (int)((float)height / (float)width * frame.width());
   3104                 crop.bottom = crop.top + cropHeight;
   3105             }
   3106 
   3107             // The screenshot API does not apply the current screen rotation.
   3108             int rot = mDisplay.getRotation();
   3109 
   3110             if (rot == ROTATION_90 || rot == ROTATION_270) {
   3111                 rot = (rot == ROTATION_90) ? ROTATION_270 : ROTATION_90;
   3112             }
   3113 
   3114             // Surfaceflinger is not aware of orientation, so convert our logical
   3115             // crop to surfaceflinger's portrait orientation.
   3116             convertCropForSurfaceFlinger(crop, rot, dw, dh);
   3117 
   3118             if (DEBUG_SCREENSHOT) {
   3119                 Slog.i(TAG_WM, "Screenshot: " + dw + "x" + dh + " from " + minLayer + " to "
   3120                         + maxLayer + " appToken=" + appToken);
   3121                 forAllWindows(w -> {
   3122                     final WindowSurfaceController controller = w.mWinAnimator.mSurfaceController;
   3123                     Slog.i(TAG_WM, w + ": " + w.mLayer
   3124                             + " animLayer=" + w.mWinAnimator.mAnimLayer
   3125                             + " surfaceLayer=" + ((controller == null)
   3126                             ? "null" : controller.getLayer()));
   3127                 }, false /* traverseTopToBottom */);
   3128             }
   3129 
   3130             final ScreenRotationAnimation screenRotationAnimation =
   3131                     mService.mAnimator.getScreenRotationAnimationLocked(DEFAULT_DISPLAY);
   3132             final boolean inRotation = screenRotationAnimation != null &&
   3133                     screenRotationAnimation.isAnimating();
   3134             if (DEBUG_SCREENSHOT && inRotation) Slog.v(TAG_WM,
   3135                     "Taking screenshot while rotating");
   3136 
   3137             // We force pending transactions to flush before taking
   3138             // the screenshot by pushing an empty synchronous transaction.
   3139             SurfaceControl.openTransaction();
   3140             SurfaceControl.closeTransactionSync();
   3141 
   3142             bitmap = screenshoter.screenshot(crop, width, height, minLayer, maxLayer,
   3143                     inRotation, rot);
   3144             if (bitmap == null) {
   3145                 Slog.w(TAG_WM, "Screenshot failure taking screenshot for (" + dw + "x" + dh
   3146                         + ") to layer " + maxLayer);
   3147                 return null;
   3148             }
   3149         }
   3150         return bitmap;
   3151     }
   3152 
   3153     // TODO: Can this use createRotationMatrix()?
   3154     private static void convertCropForSurfaceFlinger(Rect crop, int rot, int dw, int dh) {
   3155         if (rot == Surface.ROTATION_90) {
   3156             final int tmp = crop.top;
   3157             crop.top = dw - crop.right;
   3158             crop.right = crop.bottom;
   3159             crop.bottom = dw - crop.left;
   3160             crop.left = tmp;
   3161         } else if (rot == Surface.ROTATION_180) {
   3162             int tmp = crop.top;
   3163             crop.top = dh - crop.bottom;
   3164             crop.bottom = dh - tmp;
   3165             tmp = crop.right;
   3166             crop.right = dw - crop.left;
   3167             crop.left = dw - tmp;
   3168         } else if (rot == Surface.ROTATION_270) {
   3169             final int tmp = crop.top;
   3170             crop.top = crop.left;
   3171             crop.left = dh - crop.bottom;
   3172             crop.bottom = crop.right;
   3173             crop.right = dh - tmp;
   3174         }
   3175     }
   3176 
   3177     void onSeamlessRotationTimeout() {
   3178         // Used to indicate the layout is needed.
   3179         mTmpWindow = null;
   3180 
   3181         forAllWindows(w -> {
   3182             if (!w.mSeamlesslyRotated) {
   3183                 return;
   3184             }
   3185             mTmpWindow = w;
   3186             w.setDisplayLayoutNeeded();
   3187             mService.markForSeamlessRotation(w, false);
   3188         }, true /* traverseTopToBottom */);
   3189 
   3190         if (mTmpWindow != null) {
   3191             mService.mWindowPlacerLocked.performSurfacePlacement();
   3192         }
   3193     }
   3194 
   3195     void setExitingTokensHasVisible(boolean hasVisible) {
   3196         for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
   3197             mExitingTokens.get(i).hasVisible = hasVisible;
   3198         }
   3199 
   3200         // Initialize state of exiting applications.
   3201         mTaskStackContainers.setExitingTokensHasVisible(hasVisible);
   3202     }
   3203 
   3204     void removeExistingTokensIfPossible() {
   3205         for (int i = mExitingTokens.size() - 1; i >= 0; i--) {
   3206             final WindowToken token = mExitingTokens.get(i);
   3207             if (!token.hasVisible) {
   3208                 mExitingTokens.remove(i);
   3209             }
   3210         }
   3211 
   3212         // Time to remove any exiting applications?
   3213         mTaskStackContainers.removeExistingAppTokensIfPossible();
   3214     }
   3215 
   3216     @Override
   3217     void onDescendantOverrideConfigurationChanged() {
   3218         setLayoutNeeded();
   3219         mService.requestTraversal();
   3220     }
   3221 
   3222     boolean okToDisplay() {
   3223         if (mDisplayId == DEFAULT_DISPLAY) {
   3224             return !mService.mDisplayFrozen
   3225                     && mService.mDisplayEnabled && mService.mPolicy.isScreenOn();
   3226         }
   3227         return mDisplayInfo.state == Display.STATE_ON;
   3228     }
   3229 
   3230     boolean okToAnimate() {
   3231         return okToDisplay() &&
   3232                 (mDisplayId != DEFAULT_DISPLAY || mService.mPolicy.okToAnimate());
   3233     }
   3234 
   3235     static final class TaskForResizePointSearchResult {
   3236         boolean searchDone;
   3237         Task taskForResize;
   3238 
   3239         void reset() {
   3240             searchDone = false;
   3241             taskForResize = null;
   3242         }
   3243     }
   3244 
   3245     private static final class ApplySurfaceChangesTransactionState {
   3246         boolean displayHasContent;
   3247         boolean obscured;
   3248         boolean syswin;
   3249         boolean focusDisplayed;
   3250         float preferredRefreshRate;
   3251         int preferredModeId;
   3252 
   3253         void reset() {
   3254             displayHasContent = false;
   3255             obscured = false;
   3256             syswin = false;
   3257             focusDisplayed = false;
   3258             preferredRefreshRate = 0;
   3259             preferredModeId = 0;
   3260         }
   3261     }
   3262 
   3263     private static final class ScreenshotApplicationState {
   3264         WindowState appWin;
   3265         int maxLayer;
   3266         int minLayer;
   3267         boolean screenshotReady;
   3268 
   3269         void reset(boolean screenshotReady) {
   3270             appWin = null;
   3271             maxLayer = 0;
   3272             minLayer = 0;
   3273             this.screenshotReady = screenshotReady;
   3274             minLayer = (screenshotReady) ? 0 : Integer.MAX_VALUE;
   3275         }
   3276     }
   3277 
   3278     /**
   3279      * Base class for any direct child window container of {@link #DisplayContent} need to inherit
   3280      * from. This is mainly a pass through class that allows {@link #DisplayContent} to have
   3281      * homogeneous children type which is currently required by sub-classes of
   3282      * {@link WindowContainer} class.
   3283      */
   3284     static class DisplayChildWindowContainer<E extends WindowContainer> extends WindowContainer<E> {
   3285 
   3286         int size() {
   3287             return mChildren.size();
   3288         }
   3289 
   3290         E get(int index) {
   3291             return mChildren.get(index);
   3292         }
   3293 
   3294         @Override
   3295         boolean fillsParent() {
   3296             return true;
   3297         }
   3298 
   3299         @Override
   3300         boolean isVisible() {
   3301             return true;
   3302         }
   3303     }
   3304 
   3305     /**
   3306      * Window container class that contains all containers on this display relating to Apps.
   3307      * I.e Activities.
   3308      */
   3309     private final class TaskStackContainers extends DisplayChildWindowContainer<TaskStack> {
   3310 
   3311         /**
   3312          * Adds the stack to this container.
   3313          * @see WindowManagerService#addStackToDisplay(int, int, boolean)
   3314          */
   3315         void addStackToDisplay(TaskStack stack, boolean onTop) {
   3316             if (stack.mStackId == HOME_STACK_ID) {
   3317                 if (mHomeStack != null) {
   3318                     throw new IllegalArgumentException("attachStack: HOME_STACK_ID (0) not first.");
   3319                 }
   3320                 mHomeStack = stack;
   3321             }
   3322             addChild(stack, onTop);
   3323             stack.onDisplayChanged(DisplayContent.this);
   3324         }
   3325 
   3326         /** Removes the stack from its container and prepare for changing the parent. */
   3327         void removeStackFromDisplay(TaskStack stack) {
   3328             removeChild(stack);
   3329             stack.onRemovedFromDisplay();
   3330         }
   3331 
   3332         private void addChild(TaskStack stack, boolean toTop) {
   3333             final int addIndex = findPositionForStack(toTop ? mChildren.size() : 0, stack,
   3334                     true /* adding */);
   3335             addChild(stack, addIndex);
   3336             setLayoutNeeded();
   3337         }
   3338 
   3339 
   3340         @Override
   3341         boolean isOnTop() {
   3342             // Considered always on top
   3343             return true;
   3344         }
   3345 
   3346         @Override
   3347         void positionChildAt(int position, TaskStack child, boolean includingParents) {
   3348             if (StackId.isAlwaysOnTop(child.mStackId) && position != POSITION_TOP) {
   3349                 // This stack is always-on-top, override the default behavior.
   3350                 Slog.w(TAG_WM, "Ignoring move of always-on-top stack=" + this + " to bottom");
   3351 
   3352                 // Moving to its current position, as we must call super but we don't want to
   3353                 // perform any meaningful action.
   3354                 final int currentPosition = mChildren.indexOf(child);
   3355                 super.positionChildAt(currentPosition, child, false /* includingParents */);
   3356                 return;
   3357             }
   3358 
   3359             final int targetPosition = findPositionForStack(position, child, false /* adding */);
   3360             super.positionChildAt(targetPosition, child, includingParents);
   3361 
   3362             setLayoutNeeded();
   3363         }
   3364 
   3365         /**
   3366          * When stack is added or repositioned, find a proper position for it.
   3367          * This will make sure that pinned stack always stays on top.
   3368          * @param requestedPosition Position requested by caller.
   3369          * @param stack Stack to be added or positioned.
   3370          * @param adding Flag indicates whether we're adding a new stack or positioning an existing.
   3371          * @return The proper position for the stack.
   3372          */
   3373         private int findPositionForStack(int requestedPosition, TaskStack stack, boolean adding) {
   3374             final int topChildPosition = mChildren.size() - 1;
   3375             boolean toTop = requestedPosition == POSITION_TOP;
   3376             toTop |= adding ? requestedPosition >= topChildPosition + 1
   3377                     : requestedPosition >= topChildPosition;
   3378             int targetPosition = requestedPosition;
   3379 
   3380             if (toTop && stack.mStackId != PINNED_STACK_ID
   3381                     && getStackById(PINNED_STACK_ID) != null) {
   3382                 // The pinned stack is always the top most stack (always-on-top) when it is present.
   3383                 TaskStack topStack = mChildren.get(topChildPosition);
   3384                 if (topStack.mStackId != PINNED_STACK_ID) {
   3385                     throw new IllegalStateException("Pinned stack isn't top stack??? " + mChildren);
   3386                 }
   3387 
   3388                 // So, stack is moved just below the pinned stack.
   3389                 // When we're adding a new stack the target is the current pinned stack position.
   3390                 // When we're positioning an existing stack the target is the position below pinned
   3391                 // stack, because WindowContainer#positionAt() first removes element and then adds
   3392                 // it to specified place.
   3393                 targetPosition = adding ? topChildPosition : topChildPosition - 1;
   3394             }
   3395 
   3396             return targetPosition;
   3397         }
   3398 
   3399         @Override
   3400         boolean forAllWindows(ToBooleanFunction<WindowState> callback,
   3401                 boolean traverseTopToBottom) {
   3402             if (traverseTopToBottom) {
   3403                 if (super.forAllWindows(callback, traverseTopToBottom)) {
   3404                     return true;
   3405                 }
   3406                 if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) {
   3407                     return true;
   3408                 }
   3409             } else {
   3410                 if (forAllExitingAppTokenWindows(callback, traverseTopToBottom)) {
   3411                     return true;
   3412                 }
   3413                 if (super.forAllWindows(callback, traverseTopToBottom)) {
   3414                     return true;
   3415                 }
   3416             }
   3417             return false;
   3418         }
   3419 
   3420         private boolean forAllExitingAppTokenWindows(ToBooleanFunction<WindowState> callback,
   3421                 boolean traverseTopToBottom) {
   3422             // For legacy reasons we process the TaskStack.mExitingAppTokens first here before the
   3423             // app tokens.
   3424             // TODO: Investigate if we need to continue to do this or if we can just process them
   3425             // in-order.
   3426             if (traverseTopToBottom) {
   3427                 for (int i = mChildren.size() - 1; i >= 0; --i) {
   3428                     final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens;
   3429                     for (int j = appTokens.size() - 1; j >= 0; --j) {
   3430                         if (appTokens.get(j).forAllWindowsUnchecked(callback,
   3431                                 traverseTopToBottom)) {
   3432                             return true;
   3433                         }
   3434                     }
   3435                 }
   3436             } else {
   3437                 final int count = mChildren.size();
   3438                 for (int i = 0; i < count; ++i) {
   3439                     final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens;
   3440                     final int appTokensCount = appTokens.size();
   3441                     for (int j = 0; j < appTokensCount; j++) {
   3442                         if (appTokens.get(j).forAllWindowsUnchecked(callback,
   3443                                 traverseTopToBottom)) {
   3444                             return true;
   3445                         }
   3446                     }
   3447                 }
   3448             }
   3449             return false;
   3450         }
   3451 
   3452         void setExitingTokensHasVisible(boolean hasVisible) {
   3453             for (int i = mChildren.size() - 1; i >= 0; --i) {
   3454                 final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens;
   3455                 for (int j = appTokens.size() - 1; j >= 0; --j) {
   3456                     appTokens.get(j).hasVisible = hasVisible;
   3457                 }
   3458             }
   3459         }
   3460 
   3461         void removeExistingAppTokensIfPossible() {
   3462             for (int i = mChildren.size() - 1; i >= 0; --i) {
   3463                 final AppTokenList appTokens = mChildren.get(i).mExitingAppTokens;
   3464                 for (int j = appTokens.size() - 1; j >= 0; --j) {
   3465                     final AppWindowToken token = appTokens.get(j);
   3466                     if (!token.hasVisible && !mService.mClosingApps.contains(token)
   3467                             && (!token.mIsExiting || token.isEmpty())) {
   3468                         // Make sure there is no animation running on this token, so any windows
   3469                         // associated with it will be removed as soon as their animations are
   3470                         // complete.
   3471                         token.mAppAnimator.clearAnimation();
   3472                         token.mAppAnimator.animating = false;
   3473                         if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
   3474                                 "performLayout: App token exiting now removed" + token);
   3475                         token.removeIfPossible();
   3476                     }
   3477                 }
   3478             }
   3479         }
   3480 
   3481         @Override
   3482         int getOrientation() {
   3483             if (isStackVisible(DOCKED_STACK_ID) || isStackVisible(FREEFORM_WORKSPACE_STACK_ID)) {
   3484                 // Apps and their containers are not allowed to specify an orientation while the
   3485                 // docked or freeform stack is visible...except for the home stack/task if the
   3486                 // docked stack is minimized and it actually set something.
   3487                 if (mHomeStack != null && mHomeStack.isVisible()
   3488                         && mDividerControllerLocked.isMinimizedDock()) {
   3489                     final int orientation = mHomeStack.getOrientation();
   3490                     if (orientation != SCREEN_ORIENTATION_UNSET) {
   3491                         return orientation;
   3492                     }
   3493                 }
   3494                 return SCREEN_ORIENTATION_UNSPECIFIED;
   3495             }
   3496 
   3497             final int orientation = super.getOrientation();
   3498             if (orientation != SCREEN_ORIENTATION_UNSET
   3499                     && orientation != SCREEN_ORIENTATION_BEHIND) {
   3500                 if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
   3501                         "App is requesting an orientation, return " + orientation);
   3502                 return orientation;
   3503             }
   3504 
   3505             if (DEBUG_ORIENTATION) Slog.v(TAG_WM,
   3506                     "No app is requesting an orientation, return " + mLastOrientation);
   3507             // The next app has not been requested to be visible, so we keep the current orientation
   3508             // to prevent freezing/unfreezing the display too early.
   3509             return mLastOrientation;
   3510         }
   3511     }
   3512 
   3513     /**
   3514      * Window container class that contains all containers on this display that are not related to
   3515      * Apps. E.g. status bar.
   3516      */
   3517     private final class NonAppWindowContainers extends DisplayChildWindowContainer<WindowToken> {
   3518         /**
   3519          * Compares two child window tokens returns -1 if the first is lesser than the second in
   3520          * terms of z-order and 1 otherwise.
   3521          */
   3522         private final Comparator<WindowToken> mWindowComparator = (token1, token2) ->
   3523                 // Tokens with higher base layer are z-ordered on-top.
   3524                 mService.mPolicy.getWindowLayerFromTypeLw(token1.windowType,
   3525                         token1.mOwnerCanManageAppTokens)
   3526                 < mService.mPolicy.getWindowLayerFromTypeLw(token2.windowType,
   3527                         token2.mOwnerCanManageAppTokens) ? -1 : 1;
   3528 
   3529         private final Predicate<WindowState> mGetOrientingWindow = w -> {
   3530             if (!w.isVisibleLw() || !w.mPolicyVisibilityAfterAnim) {
   3531                 return false;
   3532             }
   3533             final int req = w.mAttrs.screenOrientation;
   3534             if(req == SCREEN_ORIENTATION_UNSPECIFIED || req == SCREEN_ORIENTATION_BEHIND
   3535                     || req == SCREEN_ORIENTATION_UNSET) {
   3536                 return false;
   3537             }
   3538             return true;
   3539         };
   3540 
   3541         private final String mName;
   3542         NonAppWindowContainers(String name) {
   3543             mName = name;
   3544         }
   3545 
   3546         void addChild(WindowToken token) {
   3547             addChild(token, mWindowComparator);
   3548         }
   3549 
   3550         @Override
   3551         int getOrientation() {
   3552             final WindowManagerPolicy policy = mService.mPolicy;
   3553             // Find a window requesting orientation.
   3554             final WindowState win = getWindow(mGetOrientingWindow);
   3555 
   3556             if (win != null) {
   3557                 final int req = win.mAttrs.screenOrientation;
   3558                 if (policy.isKeyguardHostWindow(win.mAttrs)) {
   3559                     mLastKeyguardForcedOrientation = req;
   3560                     if (mService.mKeyguardGoingAway) {
   3561                         // Keyguard can't affect the orientation if it is going away...
   3562                         mLastWindowForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
   3563                         return SCREEN_ORIENTATION_UNSET;
   3564                     }
   3565                 }
   3566                 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, win + " forcing orientation to " + req);
   3567                 return (mLastWindowForcedOrientation = req);
   3568             }
   3569 
   3570             mLastWindowForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
   3571 
   3572             if (policy.isKeyguardShowingAndNotOccluded()
   3573                     || mService.mAppTransition.getAppTransition() == TRANSIT_KEYGUARD_UNOCCLUDE) {
   3574                 return mLastKeyguardForcedOrientation;
   3575             }
   3576 
   3577             return SCREEN_ORIENTATION_UNSET;
   3578         }
   3579 
   3580         @Override
   3581         String getName() {
   3582             return mName;
   3583         }
   3584     }
   3585 
   3586     /**
   3587      * Interface to screenshot into various types, i.e. {@link Bitmap} and {@link GraphicBuffer}.
   3588      */
   3589     @FunctionalInterface
   3590     private interface Screenshoter<E> {
   3591         E screenshot(Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
   3592                 boolean useIdentityTransform, int rotation);
   3593     }
   3594 }
   3595