1 /*
2  * Copyright (C) 2018 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.WindowConfiguration.ACTIVITY_TYPE_HOME;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
25 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
26 import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
27 import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
28 import static android.view.Display.TYPE_BUILT_IN;
29 import static android.view.InsetsState.TYPE_TOP_BAR;
30 import static android.view.InsetsState.TYPE_TOP_GESTURES;
31 import static android.view.InsetsState.TYPE_TOP_TAPPABLE_ELEMENT;
32 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
33 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
34 import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
35 import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
36 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
37 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
38 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
39 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
40 import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
41 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
42 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
43 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
44 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
45 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
46 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
47 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
48 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
49 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
50 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
51 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
52 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
53 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
54 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
55 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
56 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR;
57 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
58 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
59 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
60 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
61 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
62 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
63 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
64 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
65 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
66 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
67 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
68 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
69 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
70 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
71 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
72 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
73 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
74 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
75 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
76 import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
77 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
78 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
79 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
80 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
81 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
82 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
83 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
84 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
85 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
86 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
87 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
88 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
89 import static android.view.WindowManagerGlobal.ADD_OKAY;
90 import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
91 import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE;
92 import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
93 import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
94 import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
95 
96 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
97 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
98 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
99 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
100 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE;
101 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
102 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW;
103 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
104 import static com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
105 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
106 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
107 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
108 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
109 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
110 import static com.android.server.wm.WindowManagerService.localLOGV;
111 
112 import android.Manifest.permission;
113 import android.annotation.NonNull;
114 import android.annotation.Nullable;
115 import android.annotation.Px;
116 import android.app.ActivityManager;
117 import android.app.ActivityThread;
118 import android.app.LoadedApk;
119 import android.app.ResourcesManager;
120 import android.app.StatusBarManager;
121 import android.content.Context;
122 import android.content.Intent;
123 import android.content.pm.PackageManager;
124 import android.content.res.Resources;
125 import android.graphics.Insets;
126 import android.graphics.PixelFormat;
127 import android.graphics.Rect;
128 import android.graphics.Region;
129 import android.hardware.input.InputManager;
130 import android.hardware.power.V1_0.PowerHint;
131 import android.os.Handler;
132 import android.os.Looper;
133 import android.os.Message;
134 import android.os.SystemClock;
135 import android.os.SystemProperties;
136 import android.os.UserHandle;
137 import android.util.ArraySet;
138 import android.util.Pair;
139 import android.util.PrintWriterPrinter;
140 import android.util.Slog;
141 import android.view.DisplayCutout;
142 import android.view.Gravity;
143 import android.view.IApplicationToken;
144 import android.view.InputChannel;
145 import android.view.InputDevice;
146 import android.view.InputEvent;
147 import android.view.InputEventReceiver;
148 import android.view.InsetsState;
149 import android.view.MotionEvent;
150 import android.view.PointerIcon;
151 import android.view.Surface;
152 import android.view.View;
153 import android.view.ViewRootImpl;
154 import android.view.WindowManager;
155 import android.view.WindowManager.LayoutParams;
156 import android.view.WindowManagerGlobal;
157 import android.view.WindowManagerPolicyConstants;
158 import android.view.accessibility.AccessibilityManager;
159 
160 import com.android.internal.R;
161 import com.android.internal.annotations.GuardedBy;
162 import com.android.internal.annotations.VisibleForTesting;
163 import com.android.internal.policy.ScreenDecorationsUtils;
164 import com.android.internal.util.ScreenShapeHelper;
165 import com.android.internal.util.ScreenshotHelper;
166 import com.android.internal.util.function.TriConsumer;
167 import com.android.internal.widget.PointerLocationView;
168 import com.android.server.LocalServices;
169 import com.android.server.UiThread;
170 import com.android.server.policy.WindowManagerPolicy;
171 import com.android.server.policy.WindowManagerPolicy.InputConsumer;
172 import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition;
173 import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
174 import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
175 import com.android.server.policy.WindowOrientationListener;
176 import com.android.server.statusbar.StatusBarManagerInternal;
177 import com.android.server.wallpaper.WallpaperManagerInternal;
178 import com.android.server.wm.utils.InsetUtils;
179 
180 import java.io.PrintWriter;
181 
182 /**
183  * The policy that provides the basic behaviors and states of a display to show UI.
184  */
185 public class DisplayPolicy {
186     private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM;
187     private static final boolean DEBUG = false;
188 
189     private static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
190 
191     // The panic gesture may become active only after the keyguard is dismissed and the immersive
192     // app shows again. If that doesn't happen for 30s we drop the gesture.
193     private static final long PANIC_GESTURE_EXPIRATION = 30000;
194 
195     // Controls navigation bar opacity depending on which workspace stacks are currently
196     // visible.
197     // Nav bar is always opaque when either the freeform stack or docked stack is visible.
198     private static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0;
199     // Nav bar is always translucent when the freeform stack is visible, otherwise always opaque.
200     private static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
201     // Nav bar is never forced opaque.
202     private static final int NAV_BAR_FORCE_TRANSPARENT = 2;
203 
204     /**
205      * These are the system UI flags that, when changing, can cause the layout
206      * of the screen to change.
207      */
208     private static final int SYSTEM_UI_CHANGING_LAYOUT =
209             View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
210                     | View.SYSTEM_UI_FLAG_FULLSCREEN
211                     | View.STATUS_BAR_TRANSLUCENT
212                     | View.NAVIGATION_BAR_TRANSLUCENT
213                     | View.STATUS_BAR_TRANSPARENT
214                     | View.NAVIGATION_BAR_TRANSPARENT;
215 
216     private final WindowManagerService mService;
217     private final Context mContext;
218     private final DisplayContent mDisplayContent;
219     private final Object mLock;
220     private final Handler mHandler;
221 
222     private Resources mCurrentUserResources;
223 
224     private final boolean mCarDockEnablesAccelerometer;
225     private final boolean mDeskDockEnablesAccelerometer;
226     private final AccessibilityManager mAccessibilityManager;
227     private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
228     private final ScreenshotHelper mScreenshotHelper;
229 
230     private final Object mServiceAcquireLock = new Object();
231     private StatusBarManagerInternal mStatusBarManagerInternal;
232 
233     @Px
234     private int mBottomGestureAdditionalInset;
235     @Px
236     private int mSideGestureInset;
237 
getStatusBarManagerInternal()238     private StatusBarManagerInternal getStatusBarManagerInternal() {
239         synchronized (mServiceAcquireLock) {
240             if (mStatusBarManagerInternal == null) {
241                 mStatusBarManagerInternal =
242                         LocalServices.getService(StatusBarManagerInternal.class);
243             }
244             return mStatusBarManagerInternal;
245         }
246     }
247 
248     private final SystemGesturesPointerEventListener mSystemGestures;
249 
250     private volatile int mLidState = LID_ABSENT;
251     private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
252     private volatile boolean mHdmiPlugged;
253 
254     private volatile boolean mHasStatusBar;
255     private volatile boolean mHasNavigationBar;
256     // Can the navigation bar ever move to the side?
257     private volatile boolean mNavigationBarCanMove;
258     private volatile boolean mNavigationBarLetsThroughTaps;
259     private volatile boolean mNavigationBarAlwaysShowOnSideGesture;
260     private volatile boolean mAllowSeamlessRotationDespiteNavBarMoving;
261 
262     // Written by vr manager thread, only read in this class.
263     private volatile boolean mPersistentVrModeEnabled;
264 
265     private volatile boolean mAwake;
266     private volatile boolean mScreenOnEarly;
267     private volatile boolean mScreenOnFully;
268     private volatile ScreenOnListener mScreenOnListener;
269 
270     private volatile boolean mKeyguardDrawComplete;
271     private volatile boolean mWindowManagerDrawComplete;
272 
273     private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
274     private WindowState mStatusBar = null;
275     private final int[] mStatusBarHeightForRotation = new int[4];
276     private WindowState mNavigationBar = null;
277     @NavigationBarPosition
278     private int mNavigationBarPosition = NAV_BAR_BOTTOM;
279     private int[] mNavigationBarHeightForRotationDefault = new int[4];
280     private int[] mNavigationBarWidthForRotationDefault = new int[4];
281     private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
282     private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
283 
284     /** See {@link #getNavigationBarFrameHeight} */
285     private int[] mNavigationBarFrameHeightForRotationDefault = new int[4];
286 
287     /** Cached value of {@link ScreenShapeHelper#getWindowOutsetBottomPx} */
288     @Px private int mWindowOutsetBottom;
289 
290     private final StatusBarController mStatusBarController;
291 
292     private final BarController mNavigationBarController;
293 
294     private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
295             new BarController.OnBarVisibilityChangedListener() {
296                 @Override
297                 public void onBarVisibilityChanged(boolean visible) {
298                     if (mAccessibilityManager == null) {
299                         return;
300                     }
301                     mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
302                 }
303             };
304 
305     @GuardedBy("mHandler")
306     private SleepToken mDreamingSleepToken;
307 
308     @GuardedBy("mHandler")
309     private SleepToken mWindowSleepToken;
310 
311     private final Runnable mAcquireSleepTokenRunnable;
312     private final Runnable mReleaseSleepTokenRunnable;
313 
314     // The windows we were told about in focusChanged.
315     private WindowState mFocusedWindow;
316     private WindowState mLastFocusedWindow;
317 
318     IApplicationToken mFocusedApp;
319 
320     int mLastSystemUiFlags;
321     // Bits that we are in the process of clearing, so we want to prevent
322     // them from being set by applications until everything has been updated
323     // to have them clear.
324     private int mResettingSystemUiFlags = 0;
325     // Bits that we are currently always keeping cleared.
326     private int mForceClearedSystemUiFlags = 0;
327     private int mLastFullscreenStackSysUiFlags;
328     private int mLastDockedStackSysUiFlags;
329     private final Rect mNonDockedStackBounds = new Rect();
330     private final Rect mDockedStackBounds = new Rect();
331     private final Rect mLastNonDockedStackBounds = new Rect();
332     private final Rect mLastDockedStackBounds = new Rect();
333 
334     // What we last reported to system UI about whether the compatibility
335     // menu needs to be displayed.
336     private boolean mLastFocusNeedsMenu = false;
337     // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
338     private long mPendingPanicGestureUptime;
339 
340     private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
341     private static final Rect sTmpRect = new Rect();
342     private static final Rect sTmpDockedFrame = new Rect();
343     private static final Rect sTmpNavFrame = new Rect();
344     private static final Rect sTmpLastParentFrame = new Rect();
345 
346     private WindowState mTopFullscreenOpaqueWindowState;
347     private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
348     private WindowState mTopDockedOpaqueWindowState;
349     private WindowState mTopDockedOpaqueOrDimmingWindowState;
350     private boolean mTopIsFullscreen;
351     private boolean mForceStatusBar;
352     private boolean mForceStatusBarFromKeyguard;
353     private boolean mForceStatusBarTransparent;
354     private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
355     private boolean mForcingShowNavBar;
356     private int mForcingShowNavBarLayer;
357     private boolean mForceShowSystemBars;
358 
359     /**
360      * Force the display of system bars regardless of other settings.
361      */
362     private boolean mForceShowSystemBarsFromExternal;
363 
364     private boolean mShowingDream;
365     private boolean mLastShowingDream;
366     private boolean mDreamingLockscreen;
367     private boolean mDreamingSleepTokenNeeded;
368     private boolean mWindowSleepTokenNeeded;
369     private boolean mLastWindowSleepTokenNeeded;
370     private boolean mAllowLockscreenWhenOn;
371 
372     private InputConsumer mInputConsumer = null;
373 
374     private PointerLocationView mPointerLocationView;
375 
376     /**
377      * The area covered by system windows which belong to another display. Forwarded insets is set
378      * in case this is a virtual display, this is displayed on another display that has insets, and
379      * the bounds of this display is overlapping with the insets of the host display (e.g. IME is
380      * displayed on the host display, and it covers a part of this virtual display.)
381      * The forwarded insets is used to compute display frames of this virtual display, which will
382      * be then used to layout windows in the virtual display.
383      */
384     @NonNull private Insets mForwardedInsets = Insets.NONE;
385 
386     private RefreshRatePolicy mRefreshRatePolicy;
387 
388     // -------- PolicyHandler --------
389     private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
390     private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
391     private static final int MSG_DISPOSE_INPUT_CONSUMER = 3;
392     private static final int MSG_ENABLE_POINTER_LOCATION = 4;
393     private static final int MSG_DISABLE_POINTER_LOCATION = 5;
394 
395     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
396     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
397 
398     private class PolicyHandler extends Handler {
399 
PolicyHandler(Looper looper)400         PolicyHandler(Looper looper) {
401             super(looper);
402         }
403 
404         @Override
handleMessage(Message msg)405         public void handleMessage(Message msg) {
406             switch (msg.what) {
407                 case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
408                     updateDreamingSleepToken(msg.arg1 != 0);
409                     break;
410                 case MSG_REQUEST_TRANSIENT_BARS:
411                     WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
412                             ? mStatusBar : mNavigationBar;
413                     if (targetBar != null) {
414                         requestTransientBars(targetBar);
415                     }
416                     break;
417                 case MSG_DISPOSE_INPUT_CONSUMER:
418                     disposeInputConsumer((InputConsumer) msg.obj);
419                     break;
420                 case MSG_ENABLE_POINTER_LOCATION:
421                     enablePointerLocation();
422                     break;
423                 case MSG_DISABLE_POINTER_LOCATION:
424                     disablePointerLocation();
425                     break;
426             }
427         }
428     }
429 
DisplayPolicy(WindowManagerService service, DisplayContent displayContent)430     DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
431         mService = service;
432         mContext = displayContent.isDefaultDisplay ? service.mContext
433                 : service.mContext.createDisplayContext(displayContent.getDisplay());
434         mDisplayContent = displayContent;
435         mLock = service.getWindowManagerLock();
436 
437         final int displayId = displayContent.getDisplayId();
438         mStatusBarController = new StatusBarController(displayId);
439         mNavigationBarController = new BarController("NavigationBar",
440                 displayId,
441                 View.NAVIGATION_BAR_TRANSIENT,
442                 View.NAVIGATION_BAR_UNHIDE,
443                 View.NAVIGATION_BAR_TRANSLUCENT,
444                 StatusBarManager.WINDOW_NAVIGATION_BAR,
445                 FLAG_TRANSLUCENT_NAVIGATION,
446                 View.NAVIGATION_BAR_TRANSPARENT);
447 
448         final Resources r = mContext.getResources();
449         mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
450         mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
451         mForceShowSystemBarsFromExternal = r.getBoolean(R.bool.config_forceShowSystemBars);
452 
453         mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
454                 Context.ACCESSIBILITY_SERVICE);
455         if (!displayContent.isDefaultDisplay) {
456             mAwake = true;
457             mScreenOnEarly = true;
458             mScreenOnFully = true;
459         }
460 
461         final Looper looper = UiThread.getHandler().getLooper();
462         mHandler = new PolicyHandler(looper);
463         mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
464                 new SystemGesturesPointerEventListener.Callbacks() {
465                     @Override
466                     public void onSwipeFromTop() {
467                         if (mStatusBar != null) {
468                             requestTransientBars(mStatusBar);
469                         }
470                     }
471 
472                     @Override
473                     public void onSwipeFromBottom() {
474                         if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
475                             requestTransientBars(mNavigationBar);
476                         }
477                     }
478 
479                     @Override
480                     public void onSwipeFromRight() {
481                         final Region excludedRegion = Region.obtain();
482                         synchronized (mLock) {
483                             mDisplayContent.calculateSystemGestureExclusion(
484                                     excludedRegion, null /* outUnrestricted */);
485                         }
486                         final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
487                                 || mNavigationBarPosition == NAV_BAR_RIGHT;
488                         if (mNavigationBar != null && sideAllowed
489                                 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
490                             requestTransientBars(mNavigationBar);
491                         }
492                         excludedRegion.recycle();
493                     }
494 
495                     @Override
496                     public void onSwipeFromLeft() {
497                         final Region excludedRegion = Region.obtain();
498                         synchronized (mLock) {
499                             mDisplayContent.calculateSystemGestureExclusion(
500                                     excludedRegion, null /* outUnrestricted */);
501                         }
502                         final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
503                                 || mNavigationBarPosition == NAV_BAR_LEFT;
504                         if (mNavigationBar != null && sideAllowed
505                                 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
506                             requestTransientBars(mNavigationBar);
507                         }
508                         excludedRegion.recycle();
509                     }
510 
511                     @Override
512                     public void onFling(int duration) {
513                         if (mService.mPowerManagerInternal != null) {
514                             mService.mPowerManagerInternal.powerHint(
515                                     PowerHint.INTERACTION, duration);
516                         }
517                     }
518 
519                     @Override
520                     public void onDebug() {
521                         // no-op
522                     }
523 
524                     private WindowOrientationListener getOrientationListener() {
525                         final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
526                         return rotation != null ? rotation.getOrientationListener() : null;
527                     }
528 
529                     @Override
530                     public void onDown() {
531                         final WindowOrientationListener listener = getOrientationListener();
532                         if (listener != null) {
533                             listener.onTouchStart();
534                         }
535                     }
536 
537                     @Override
538                     public void onUpOrCancel() {
539                         final WindowOrientationListener listener = getOrientationListener();
540                         if (listener != null) {
541                             listener.onTouchEnd();
542                         }
543                     }
544 
545                     @Override
546                     public void onMouseHoverAtTop() {
547                         mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
548                         Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
549                         msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
550                         mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
551                     }
552 
553                     @Override
554                     public void onMouseHoverAtBottom() {
555                         mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
556                         Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
557                         msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
558                         mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
559                     }
560 
561                     @Override
562                     public void onMouseLeaveFromEdge() {
563                         mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
564                     }
565                 });
566         displayContent.registerPointerEventListener(mSystemGestures);
567         displayContent.mAppTransition.registerListenerLocked(
568                 mStatusBarController.getAppTransitionListener());
569         mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
570                 mService.mVrModeEnabled);
571         mAcquireSleepTokenRunnable = () -> {
572             if (mWindowSleepToken != null) {
573                 return;
574             }
575             mWindowSleepToken = service.mAtmInternal.acquireSleepToken(
576                     "WindowSleepTokenOnDisplay" + displayId, displayId);
577         };
578         mReleaseSleepTokenRunnable = () -> {
579             if (mWindowSleepToken == null) {
580                 return;
581             }
582             mWindowSleepToken.release();
583             mWindowSleepToken = null;
584         };
585 
586         // TODO: Make it can take screenshot on external display
587         mScreenshotHelper = displayContent.isDefaultDisplay
588                 ? new ScreenshotHelper(mContext) : null;
589 
590         if (mDisplayContent.isDefaultDisplay) {
591             mHasStatusBar = true;
592             mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
593 
594             // Allow a system property to override this. Used by the emulator.
595             // See also hasNavigationBar().
596             String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
597             if ("1".equals(navBarOverride)) {
598                 mHasNavigationBar = false;
599             } else if ("0".equals(navBarOverride)) {
600                 mHasNavigationBar = true;
601             }
602         } else {
603             mHasStatusBar = false;
604             mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
605         }
606 
607         mRefreshRatePolicy = new RefreshRatePolicy(mService,
608                 mDisplayContent.getDisplayInfo(),
609                 mService.mHighRefreshRateBlacklist);
610     }
611 
systemReady()612     void systemReady() {
613         mSystemGestures.systemReady();
614         if (mService.mPointerLocationEnabled) {
615             setPointerLocationEnabled(true);
616         }
617     }
618 
getDisplayId()619     private int getDisplayId() {
620         return mDisplayContent.getDisplayId();
621     }
622 
setHdmiPlugged(boolean plugged)623     public void setHdmiPlugged(boolean plugged) {
624         setHdmiPlugged(plugged, false /* force */);
625     }
626 
setHdmiPlugged(boolean plugged, boolean force)627     public void setHdmiPlugged(boolean plugged, boolean force) {
628         if (force || mHdmiPlugged != plugged) {
629             mHdmiPlugged = plugged;
630             mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
631             final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
632             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
633             intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
634             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
635         }
636     }
637 
isHdmiPlugged()638     boolean isHdmiPlugged() {
639         return mHdmiPlugged;
640     }
641 
isCarDockEnablesAccelerometer()642     boolean isCarDockEnablesAccelerometer() {
643         return mCarDockEnablesAccelerometer;
644     }
645 
isDeskDockEnablesAccelerometer()646     boolean isDeskDockEnablesAccelerometer() {
647         return mDeskDockEnablesAccelerometer;
648     }
649 
setPersistentVrModeEnabled(boolean persistentVrModeEnabled)650     public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
651         mPersistentVrModeEnabled = persistentVrModeEnabled;
652     }
653 
isPersistentVrModeEnabled()654     public boolean isPersistentVrModeEnabled() {
655         return mPersistentVrModeEnabled;
656     }
657 
setDockMode(int dockMode)658     public void setDockMode(int dockMode) {
659         mDockMode = dockMode;
660     }
661 
getDockMode()662     public int getDockMode() {
663         return mDockMode;
664     }
665 
666     /**
667      * @see WindowManagerService.setForceShowSystemBars
668      */
setForceShowSystemBars(boolean forceShowSystemBars)669     void setForceShowSystemBars(boolean forceShowSystemBars) {
670         mForceShowSystemBarsFromExternal = forceShowSystemBars;
671     }
672 
hasNavigationBar()673     public boolean hasNavigationBar() {
674         return mHasNavigationBar;
675     }
676 
hasStatusBar()677     public boolean hasStatusBar() {
678         return mHasStatusBar;
679     }
680 
hasSideGestures()681     boolean hasSideGestures() {
682         return mHasNavigationBar && mSideGestureInset > 0;
683     }
684 
navigationBarCanMove()685     public boolean navigationBarCanMove() {
686         return mNavigationBarCanMove;
687     }
688 
setLidState(int lidState)689     public void setLidState(int lidState) {
690         mLidState = lidState;
691     }
692 
getLidState()693     public int getLidState() {
694         return mLidState;
695     }
696 
setAwake(boolean awake)697     public void setAwake(boolean awake) {
698         mAwake = awake;
699     }
700 
isAwake()701     public boolean isAwake() {
702         return mAwake;
703     }
704 
isScreenOnEarly()705     public boolean isScreenOnEarly() {
706         return mScreenOnEarly;
707     }
708 
isScreenOnFully()709     public boolean isScreenOnFully() {
710         return mScreenOnFully;
711     }
712 
isKeyguardDrawComplete()713     public boolean isKeyguardDrawComplete() {
714         return mKeyguardDrawComplete;
715     }
716 
isWindowManagerDrawComplete()717     public boolean isWindowManagerDrawComplete() {
718         return mWindowManagerDrawComplete;
719     }
720 
getScreenOnListener()721     public ScreenOnListener getScreenOnListener() {
722         return mScreenOnListener;
723     }
724 
screenTurnedOn(ScreenOnListener screenOnListener)725     public void screenTurnedOn(ScreenOnListener screenOnListener) {
726         synchronized (mLock) {
727             mScreenOnEarly = true;
728             mScreenOnFully = false;
729             mKeyguardDrawComplete = false;
730             mWindowManagerDrawComplete = false;
731             mScreenOnListener = screenOnListener;
732         }
733     }
734 
screenTurnedOff()735     public void screenTurnedOff() {
736         synchronized (mLock) {
737             mScreenOnEarly = false;
738             mScreenOnFully = false;
739             mKeyguardDrawComplete = false;
740             mWindowManagerDrawComplete = false;
741             mScreenOnListener = null;
742         }
743     }
744 
745     /** Return false if we are not awake yet or we have already informed of this event. */
finishKeyguardDrawn()746     public boolean finishKeyguardDrawn() {
747         synchronized (mLock) {
748             if (!mScreenOnEarly || mKeyguardDrawComplete) {
749                 return false;
750             }
751 
752             mKeyguardDrawComplete = true;
753             mWindowManagerDrawComplete = false;
754         }
755         return true;
756     }
757 
758     /** Return false if screen is not turned on or we did already handle this case earlier. */
finishWindowsDrawn()759     public boolean finishWindowsDrawn() {
760         synchronized (mLock) {
761             if (!mScreenOnEarly || mWindowManagerDrawComplete) {
762                 return false;
763             }
764 
765             mWindowManagerDrawComplete = true;
766         }
767         return true;
768     }
769 
770     /** Return false if it is not ready to turn on. */
finishScreenTurningOn()771     public boolean finishScreenTurningOn() {
772         synchronized (mLock) {
773             if (DEBUG_SCREEN_ON) Slog.d(TAG,
774                     "finishScreenTurningOn: mAwake=" + mAwake
775                             + ", mScreenOnEarly=" + mScreenOnEarly
776                             + ", mScreenOnFully=" + mScreenOnFully
777                             + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
778                             + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
779 
780             if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
781                     || (mAwake && !mKeyguardDrawComplete)) {
782                 return false;
783             }
784 
785             if (DEBUG_SCREEN_ON) Slog.i(TAG, "Finished screen turning on...");
786             mScreenOnListener = null;
787             mScreenOnFully = true;
788         }
789         return true;
790     }
791 
hasStatusBarServicePermission(int pid, int uid)792     private boolean hasStatusBarServicePermission(int pid, int uid) {
793         return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid)
794                 == PackageManager.PERMISSION_GRANTED;
795     }
796 
797     /**
798      * Sanitize the layout parameters coming from a client.  Allows the policy
799      * to do things like ensure that windows of a specific type can't take
800      * input focus.
801      *
802      * @param attrs The window layout parameters to be modified.  These values
803      * are modified in-place.
804      */
adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs, int callingPid, int callingUid)805     public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
806             int callingPid, int callingUid) {
807 
808         final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
809         if (mScreenDecorWindows.contains(win)) {
810             if (!isScreenDecor) {
811                 // No longer has the flag set, so remove from the set.
812                 mScreenDecorWindows.remove(win);
813             }
814         } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
815             mScreenDecorWindows.add(win);
816         }
817 
818         switch (attrs.type) {
819             case TYPE_SYSTEM_OVERLAY:
820             case TYPE_SECURE_SYSTEM_OVERLAY:
821                 // These types of windows can't receive input events.
822                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
823                         | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
824                 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
825                 break;
826             case TYPE_DREAM:
827             case TYPE_WALLPAPER:
828                 // Dreams and wallpapers don't have an app window token and can thus not be
829                 // letterboxed. Hence always let them extend under the cutout.
830                 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
831                 break;
832             case TYPE_STATUS_BAR:
833 
834                 // If the Keyguard is in a hidden state (occluded by another window), we force to
835                 // remove the wallpaper and keyguard flag so that any change in-flight after setting
836                 // the keyguard as occluded wouldn't set these flags again.
837                 // See {@link #processKeyguardSetHiddenResultLw}.
838                 if (mService.mPolicy.isKeyguardOccluded()) {
839                     attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
840                     attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
841                 }
842                 break;
843 
844             case TYPE_SCREENSHOT:
845                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
846                 break;
847 
848             case TYPE_TOAST:
849                 // While apps should use the dedicated toast APIs to add such windows
850                 // it possible legacy apps to add the window directly. Therefore, we
851                 // make windows added directly by the app behave as a toast as much
852                 // as possible in terms of timeout and animation.
853                 if (attrs.hideTimeoutMilliseconds < 0
854                         || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
855                     attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
856                 }
857                 // Accessibility users may need longer timeout duration. This api compares
858                 // original timeout with user's preference and return longer one. It returns
859                 // original timeout if there's no preference.
860                 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
861                         (int) attrs.hideTimeoutMilliseconds,
862                         AccessibilityManager.FLAG_CONTENT_TEXT);
863                 attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
864                 // Toast can show with below conditions when the screen is locked.
865                 if (canToastShowWhenLocked(callingPid)) {
866                     attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
867                 }
868                 // Toasts can't be clickable
869                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
870                 break;
871         }
872 
873         if (attrs.type != TYPE_STATUS_BAR) {
874             // The status bar is the only window allowed to exhibit keyguard behavior.
875             attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
876         }
877     }
878 
879     /**
880      * @return {@code true} if the calling activity initiate toast and is visible with
881      * {@link WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} flag.
882      */
canToastShowWhenLocked(int callingPid)883     boolean canToastShowWhenLocked(int callingPid) {
884         return mDisplayContent.forAllWindows(w -> {
885             return callingPid == w.mSession.mPid && w.isVisible() && w.canShowWhenLocked();
886         }, true /* traverseTopToBottom */);
887     }
888 
889     /**
890      * Preflight adding a window to the system.
891      *
892      * Currently enforces that three window types are singletons per display:
893      * <ul>
894      * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
895      * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
896      * </ul>
897      *
898      * @param win The window to be added
899      * @param attrs Information about the window to be added
900      *
901      * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons,
902      * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
903      */
prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs)904     public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
905 
906         if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
907             mContext.enforceCallingOrSelfPermission(
908                     android.Manifest.permission.STATUS_BAR_SERVICE,
909                     "DisplayPolicy");
910             mScreenDecorWindows.add(win);
911         }
912 
913         switch (attrs.type) {
914             case TYPE_STATUS_BAR:
915                 mContext.enforceCallingOrSelfPermission(
916                         android.Manifest.permission.STATUS_BAR_SERVICE,
917                         "DisplayPolicy");
918                 if (mStatusBar != null) {
919                     if (mStatusBar.isAlive()) {
920                         return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
921                     }
922                 }
923                 mStatusBar = win;
924                 mStatusBarController.setWindow(win);
925                 if (mDisplayContent.isDefaultDisplay) {
926                     mService.mPolicy.setKeyguardCandidateLw(win);
927                 }
928                 final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
929                         (displayFrames, windowState, rect) -> {
930                             rect.top = 0;
931                             rect.bottom = getStatusBarHeight(displayFrames);
932                         };
933                 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, win, frameProvider);
934                 mDisplayContent.setInsetProvider(TYPE_TOP_GESTURES, win, frameProvider);
935                 mDisplayContent.setInsetProvider(TYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider);
936                 break;
937             case TYPE_NAVIGATION_BAR:
938                 mContext.enforceCallingOrSelfPermission(
939                         android.Manifest.permission.STATUS_BAR_SERVICE,
940                         "DisplayPolicy");
941                 if (mNavigationBar != null) {
942                     if (mNavigationBar.isAlive()) {
943                         return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
944                     }
945                 }
946                 mNavigationBar = win;
947                 mNavigationBarController.setWindow(win);
948                 mNavigationBarController.setOnBarVisibilityChangedListener(
949                         mNavBarVisibilityListener, true);
950                 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR,
951                         win, null /* frameProvider */);
952                 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_GESTURES, win,
953                         (displayFrames, windowState, inOutFrame) -> {
954                             inOutFrame.top -= mBottomGestureAdditionalInset;
955                         });
956                 mDisplayContent.setInsetProvider(InsetsState.TYPE_LEFT_GESTURES, win,
957                         (displayFrames, windowState, inOutFrame) -> {
958                             inOutFrame.left = 0;
959                             inOutFrame.top = 0;
960                             inOutFrame.bottom = displayFrames.mDisplayHeight;
961                             inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset;
962                         });
963                 mDisplayContent.setInsetProvider(InsetsState.TYPE_RIGHT_GESTURES, win,
964                         (displayFrames, windowState, inOutFrame) -> {
965                             inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset;
966                             inOutFrame.top = 0;
967                             inOutFrame.bottom = displayFrames.mDisplayHeight;
968                             inOutFrame.right = displayFrames.mDisplayWidth;
969                         });
970                 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_TAPPABLE_ELEMENT, win,
971                         (displayFrames, windowState, inOutFrame) -> {
972                             if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
973                                     || mNavigationBarLetsThroughTaps) {
974                                 inOutFrame.setEmpty();
975                             }
976                         });
977                 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
978                 break;
979             case TYPE_NAVIGATION_BAR_PANEL:
980             case TYPE_STATUS_BAR_PANEL:
981             case TYPE_STATUS_BAR_SUB_PANEL:
982             case TYPE_VOICE_INTERACTION_STARTING:
983                 mContext.enforceCallingOrSelfPermission(
984                         android.Manifest.permission.STATUS_BAR_SERVICE,
985                         "DisplayPolicy");
986                 break;
987         }
988         return ADD_OKAY;
989     }
990 
991     /**
992      * Called when a window is being removed from a window manager.  Must not
993      * throw an exception -- clean up as much as possible.
994      *
995      * @param win The window being removed.
996      */
removeWindowLw(WindowState win)997     public void removeWindowLw(WindowState win) {
998         if (mStatusBar == win) {
999             mStatusBar = null;
1000             mStatusBarController.setWindow(null);
1001             if (mDisplayContent.isDefaultDisplay) {
1002                 mService.mPolicy.setKeyguardCandidateLw(null);
1003             }
1004             mDisplayContent.setInsetProvider(TYPE_TOP_BAR, null, null);
1005         } else if (mNavigationBar == win) {
1006             mNavigationBar = null;
1007             mNavigationBarController.setWindow(null);
1008             mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR, null, null);
1009         }
1010         if (mLastFocusedWindow == win) {
1011             mLastFocusedWindow = null;
1012         }
1013         mScreenDecorWindows.remove(win);
1014     }
1015 
getStatusBarHeight(DisplayFrames displayFrames)1016     private int getStatusBarHeight(DisplayFrames displayFrames) {
1017         return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
1018                 displayFrames.mDisplayCutoutSafe.top);
1019     }
1020 
1021     /**
1022      * Control the animation to run when a window's state changes.  Return a
1023      * non-0 number to force the animation to a specific resource ID, or 0
1024      * to use the default animation.
1025      *
1026      * @param win The window that is changing.
1027      * @param transit What is happening to the window:
1028      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
1029      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
1030      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
1031      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
1032      *
1033      * @return Resource ID of the actual animation to use, or 0 for none.
1034      */
selectAnimationLw(WindowState win, int transit)1035     public int selectAnimationLw(WindowState win, int transit) {
1036         if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
1037                 + ": transit=" + transit);
1038         if (win == mStatusBar) {
1039             final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
1040             final boolean expanded = win.getAttrs().height == MATCH_PARENT
1041                     && win.getAttrs().width == MATCH_PARENT;
1042             if (isKeyguard || expanded) {
1043                 return -1;
1044             }
1045             if (transit == TRANSIT_EXIT
1046                     || transit == TRANSIT_HIDE) {
1047                 return R.anim.dock_top_exit;
1048             } else if (transit == TRANSIT_ENTER
1049                     || transit == TRANSIT_SHOW) {
1050                 return R.anim.dock_top_enter;
1051             }
1052         } else if (win == mNavigationBar) {
1053             if (win.getAttrs().windowAnimations != 0) {
1054                 return 0;
1055             }
1056             // This can be on either the bottom or the right or the left.
1057             if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1058                 if (transit == TRANSIT_EXIT
1059                         || transit == TRANSIT_HIDE) {
1060                     if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
1061                         return R.anim.dock_bottom_exit_keyguard;
1062                     } else {
1063                         return R.anim.dock_bottom_exit;
1064                     }
1065                 } else if (transit == TRANSIT_ENTER
1066                         || transit == TRANSIT_SHOW) {
1067                     return R.anim.dock_bottom_enter;
1068                 }
1069             } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1070                 if (transit == TRANSIT_EXIT
1071                         || transit == TRANSIT_HIDE) {
1072                     return R.anim.dock_right_exit;
1073                 } else if (transit == TRANSIT_ENTER
1074                         || transit == TRANSIT_SHOW) {
1075                     return R.anim.dock_right_enter;
1076                 }
1077             } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1078                 if (transit == TRANSIT_EXIT
1079                         || transit == TRANSIT_HIDE) {
1080                     return R.anim.dock_left_exit;
1081                 } else if (transit == TRANSIT_ENTER
1082                         || transit == TRANSIT_SHOW) {
1083                     return R.anim.dock_left_enter;
1084                 }
1085             }
1086         } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
1087             return selectDockedDividerAnimationLw(win, transit);
1088         }
1089 
1090         if (transit == TRANSIT_PREVIEW_DONE) {
1091             if (win.hasAppShownWindows()) {
1092                 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
1093                 return R.anim.app_starting_exit;
1094             }
1095         } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
1096                 && transit == TRANSIT_ENTER) {
1097             // Special case: we are animating in a dream, while the keyguard
1098             // is shown.  We don't want an animation on the dream, because
1099             // we need it shown immediately with the keyguard animating away
1100             // to reveal it.
1101             return -1;
1102         }
1103 
1104         return 0;
1105     }
1106 
selectDockedDividerAnimationLw(WindowState win, int transit)1107     private int selectDockedDividerAnimationLw(WindowState win, int transit) {
1108         int insets = mDisplayContent.getDockedDividerController().getContentInsets();
1109 
1110         // If the divider is behind the navigation bar, don't animate.
1111         final Rect frame = win.getFrameLw();
1112         final boolean behindNavBar = mNavigationBar != null
1113                 && ((mNavigationBarPosition == NAV_BAR_BOTTOM
1114                 && frame.top + insets >= mNavigationBar.getFrameLw().top)
1115                 || (mNavigationBarPosition == NAV_BAR_RIGHT
1116                 && frame.left + insets >= mNavigationBar.getFrameLw().left)
1117                 || (mNavigationBarPosition == NAV_BAR_LEFT
1118                 && frame.right - insets <= mNavigationBar.getFrameLw().right));
1119         final boolean landscape = frame.height() > frame.width();
1120         final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
1121                 || frame.left + insets >= win.getDisplayFrameLw().right);
1122         final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
1123                 || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
1124         final boolean offscreen = offscreenLandscape || offscreenPortrait;
1125         if (behindNavBar || offscreen) {
1126             return 0;
1127         }
1128         if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
1129             return R.anim.fade_in;
1130         } else if (transit == TRANSIT_EXIT) {
1131             return R.anim.fade_out;
1132         } else {
1133             return 0;
1134         }
1135     }
1136 
1137     /**
1138      * Determine the animation to run for a rotation transition based on the
1139      * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation}
1140      * and whether it is currently fullscreen and frontmost.
1141      *
1142      * @param anim The exiting animation resource id is stored in anim[0], the
1143      * entering animation resource id is stored in anim[1].
1144      */
selectRotationAnimationLw(int anim[])1145     public void selectRotationAnimationLw(int anim[]) {
1146         // If the screen is off or non-interactive, force a jumpcut.
1147         final boolean forceJumpcut = !mScreenOnFully || !mService.mPolicy.okToAnimate();
1148         if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
1149                 + mTopFullscreenOpaqueWindowState + " rotationAnimation="
1150                 + (mTopFullscreenOpaqueWindowState == null
1151                 ? "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation)
1152                 + " forceJumpcut=" + forceJumpcut);
1153         if (forceJumpcut) {
1154             anim[0] = R.anim.rotation_animation_jump_exit;
1155             anim[1] = R.anim.rotation_animation_enter;
1156             return;
1157         }
1158         if (mTopFullscreenOpaqueWindowState != null) {
1159             int animationHint = mTopFullscreenOpaqueWindowState.getRotationAnimationHint();
1160             if (animationHint < 0 && mTopIsFullscreen) {
1161                 animationHint = mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation;
1162             }
1163             switch (animationHint) {
1164                 case ROTATION_ANIMATION_CROSSFADE:
1165                 case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless.
1166                     anim[0] = R.anim.rotation_animation_xfade_exit;
1167                     anim[1] = R.anim.rotation_animation_enter;
1168                     break;
1169                 case ROTATION_ANIMATION_JUMPCUT:
1170                     anim[0] = R.anim.rotation_animation_jump_exit;
1171                     anim[1] = R.anim.rotation_animation_enter;
1172                     break;
1173                 case ROTATION_ANIMATION_ROTATE:
1174                 default:
1175                     anim[0] = anim[1] = 0;
1176                     break;
1177             }
1178         } else {
1179             anim[0] = anim[1] = 0;
1180         }
1181     }
1182 
1183     /**
1184      * Validate whether the current top fullscreen has specified the same
1185      * {@link WindowManager.LayoutParams#rotationAnimation} value as that
1186      * being passed in from the previous top fullscreen window.
1187      *
1188      * @param exitAnimId exiting resource id from the previous window.
1189      * @param enterAnimId entering resource id from the previous window.
1190      * @param forceDefault For rotation animations only, if true ignore the
1191      * animation values and just return false.
1192      * @return true if the previous values are still valid, false if they
1193      * should be replaced with the default.
1194      */
validateRotationAnimationLw(int exitAnimId, int enterAnimId, boolean forceDefault)1195     public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
1196             boolean forceDefault) {
1197         switch (exitAnimId) {
1198             case R.anim.rotation_animation_xfade_exit:
1199             case R.anim.rotation_animation_jump_exit:
1200                 // These are the only cases that matter.
1201                 if (forceDefault) {
1202                     return false;
1203                 }
1204                 int anim[] = new int[2];
1205                 selectRotationAnimationLw(anim);
1206                 return (exitAnimId == anim[0] && enterAnimId == anim[1]);
1207             default:
1208                 return true;
1209         }
1210     }
1211 
1212     /**
1213      * Called when a new system UI visibility is being reported, allowing
1214      * the policy to adjust what is actually reported.
1215      * @param visibility The raw visibility reported by the status bar.
1216      * @return The new desired visibility.
1217      */
adjustSystemUiVisibilityLw(int visibility)1218     public int adjustSystemUiVisibilityLw(int visibility) {
1219         mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1220         mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1221 
1222         // Reset any bits in mForceClearingStatusBarVisibility that
1223         // are now clear.
1224         mResettingSystemUiFlags &= visibility;
1225         // Clear any bits in the new visibility that are currently being
1226         // force cleared, before reporting it.
1227         return visibility & ~mResettingSystemUiFlags
1228                 & ~mForceClearedSystemUiFlags;
1229     }
1230 
1231     /**
1232      * @return true if the system bars are forced to stay visible
1233      */
areSystemBarsForcedShownLw(WindowState windowState)1234     public boolean areSystemBarsForcedShownLw(WindowState windowState) {
1235         return mForceShowSystemBars;
1236     }
1237 
1238     // TODO: Should probably be moved into DisplayFrames.
1239     /**
1240      * Return the layout hints for a newly added window. These values are computed on the
1241      * most recent layout, so they are not guaranteed to be correct.
1242      *
1243      * @param attrs The LayoutParams of the window.
1244      * @param taskBounds The bounds of the task this window is on or {@code null} if no task is
1245      *                   associated with the window.
1246      * @param displayFrames display frames.
1247      * @param floatingStack Whether the window's stack is floating.
1248      * @param outFrame The frame of the window.
1249      * @param outContentInsets The areas covered by system windows, expressed as positive insets.
1250      * @param outStableInsets The areas covered by stable system windows irrespective of their
1251      *                        current visibility. Expressed as positive insets.
1252      * @param outOutsets The areas that are not real display, but we would like to treat as such.
1253      * @param outDisplayCutout The area that has been cut away from the display.
1254      * @return Whether to always consume the system bars.
1255      *         See {@link #areSystemBarsForcedShownLw(WindowState)}.
1256      */
getLayoutHintLw(LayoutParams attrs, Rect taskBounds, DisplayFrames displayFrames, boolean floatingStack, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout)1257     public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
1258             DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
1259             Rect outContentInsets, Rect outStableInsets,
1260             Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
1261         final int fl = PolicyControl.getWindowFlags(null, attrs);
1262         final int pfl = attrs.privateFlags;
1263         final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
1264         final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
1265         final int displayRotation = displayFrames.mRotation;
1266 
1267         final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
1268         if (useOutsets) {
1269             int outset = mWindowOutsetBottom;
1270             if (outset > 0) {
1271                 if (displayRotation == Surface.ROTATION_0) {
1272                     outOutsets.bottom += outset;
1273                 } else if (displayRotation == Surface.ROTATION_90) {
1274                     outOutsets.right += outset;
1275                 } else if (displayRotation == Surface.ROTATION_180) {
1276                     outOutsets.top += outset;
1277                 } else if (displayRotation == Surface.ROTATION_270) {
1278                     outOutsets.left += outset;
1279                 }
1280             }
1281         }
1282 
1283         final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
1284         final boolean layoutInScreenAndInsetDecor = layoutInScreen
1285                 && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
1286         final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
1287 
1288         if (layoutInScreenAndInsetDecor && !screenDecor) {
1289             if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
1290                 outFrame.set(displayFrames.mUnrestricted);
1291             } else {
1292                 outFrame.set(displayFrames.mRestricted);
1293             }
1294 
1295             final Rect sf;
1296             if (floatingStack) {
1297                 sf = null;
1298             } else {
1299                 sf = displayFrames.mStable;
1300             }
1301 
1302             final Rect cf;
1303             if (floatingStack) {
1304                 cf = null;
1305             } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
1306                 if ((fl & FLAG_FULLSCREEN) != 0) {
1307                     cf = displayFrames.mStableFullscreen;
1308                 } else {
1309                     cf = displayFrames.mStable;
1310                 }
1311             } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
1312                 cf = displayFrames.mOverscan;
1313             } else {
1314                 cf = displayFrames.mCurrent;
1315             }
1316 
1317             if (taskBounds != null) {
1318                 outFrame.intersect(taskBounds);
1319             }
1320             InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets);
1321             InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
1322             outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
1323                     .getDisplayCutout());
1324             return mForceShowSystemBars;
1325         } else {
1326             if (layoutInScreen) {
1327                 outFrame.set(displayFrames.mUnrestricted);
1328             } else {
1329                 outFrame.set(displayFrames.mStable);
1330             }
1331             if (taskBounds != null) {
1332                 outFrame.intersect(taskBounds);
1333             }
1334 
1335             outContentInsets.setEmpty();
1336             outStableInsets.setEmpty();
1337             outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
1338             return mForceShowSystemBars;
1339         }
1340     }
1341 
getImpliedSysUiFlagsForLayout(LayoutParams attrs)1342     private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
1343         int impliedFlags = 0;
1344         final boolean forceWindowDrawsBarBackgrounds =
1345                 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1346                 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
1347         if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
1348                 || forceWindowDrawsBarBackgrounds) {
1349             impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1350             impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1351         }
1352         return impliedFlags;
1353     }
1354 
shouldUseOutsets(WindowManager.LayoutParams attrs, int fl)1355     private static boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) {
1356         return attrs.type == TYPE_WALLPAPER || (fl & (WindowManager.LayoutParams.FLAG_FULLSCREEN
1357                 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)) != 0;
1358     }
1359 
1360     private final Runnable mClearHideNavigationFlag = new Runnable() {
1361         @Override
1362         public void run() {
1363             synchronized (mLock) {
1364                 mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1365                 mDisplayContent.reevaluateStatusBarVisibility();
1366             }
1367         }
1368     };
1369 
1370     /**
1371      * Input handler used while nav bar is hidden.  Captures any touch on the screen,
1372      * to determine when the nav bar should be shown and prevent applications from
1373      * receiving those touches.
1374      */
1375     private final class HideNavInputEventReceiver extends InputEventReceiver {
HideNavInputEventReceiver(InputChannel inputChannel, Looper looper)1376         HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
1377             super(inputChannel, looper);
1378         }
1379 
1380         @Override
onInputEvent(InputEvent event)1381         public void onInputEvent(InputEvent event) {
1382             try {
1383                 if (event instanceof MotionEvent
1384                         && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1385                     final MotionEvent motionEvent = (MotionEvent) event;
1386                     if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
1387                         // When the user taps down, we re-show the nav bar.
1388                         boolean changed = false;
1389                         synchronized (mLock) {
1390                             if (mInputConsumer == null) {
1391                                 return;
1392                             }
1393                             // Any user activity always causes us to show the
1394                             // navigation controls, if they had been hidden.
1395                             // We also clear the low profile and only content
1396                             // flags so that tapping on the screen will atomically
1397                             // restore all currently hidden screen decorations.
1398                             int newVal = mResettingSystemUiFlags
1399                                     | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
1400                                     | View.SYSTEM_UI_FLAG_LOW_PROFILE
1401                                     | View.SYSTEM_UI_FLAG_FULLSCREEN;
1402                             if (mResettingSystemUiFlags != newVal) {
1403                                 mResettingSystemUiFlags = newVal;
1404                                 changed = true;
1405                             }
1406                             // We don't allow the system's nav bar to be hidden
1407                             // again for 1 second, to prevent applications from
1408                             // spamming us and keeping it from being shown.
1409                             newVal = mForceClearedSystemUiFlags
1410                                     | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1411                             if (mForceClearedSystemUiFlags != newVal) {
1412                                 mForceClearedSystemUiFlags = newVal;
1413                                 changed = true;
1414                                 mHandler.postDelayed(mClearHideNavigationFlag, 1000);
1415                             }
1416                             if (changed) {
1417                                 mDisplayContent.reevaluateStatusBarVisibility();
1418                             }
1419                         }
1420                     }
1421                 }
1422             } finally {
1423                 finishInputEvent(event, false /* handled */);
1424             }
1425         }
1426     }
1427 
1428     /**
1429      * Called when layout of the windows is about to start.
1430      *
1431      * @param displayFrames frames of the display we are doing layout on.
1432      * @param uiMode The current uiMode in configuration.
1433      */
beginLayoutLw(DisplayFrames displayFrames, int uiMode)1434     public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
1435         displayFrames.onBeginLayout();
1436         mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
1437         mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
1438 
1439         // For purposes of putting out fake window up to steal focus, we will
1440         // drive nav being hidden only by whether it is requested.
1441         final int sysui = mLastSystemUiFlags;
1442         boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
1443         boolean navTranslucent = (sysui
1444                 & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
1445         boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
1446         boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
1447         boolean navAllowedHidden = immersive || immersiveSticky;
1448         navTranslucent &= !immersiveSticky;  // transient trumps translucent
1449         boolean isKeyguardShowing = isStatusBarKeyguard()
1450                 && !mService.mPolicy.isKeyguardOccluded();
1451         boolean statusBarForcesShowingNavigation = !isKeyguardShowing && mStatusBar != null
1452                 && (mStatusBar.getAttrs().privateFlags
1453                 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
1454 
1455         // When the navigation bar isn't visible, we put up a fake input window to catch all
1456         // touch events. This way we can detect when the user presses anywhere to bring back the
1457         // nav bar and ensure the application doesn't see the event.
1458         if (navVisible || navAllowedHidden) {
1459             if (mInputConsumer != null) {
1460                 mHandler.sendMessage(
1461                         mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
1462                 mInputConsumer = null;
1463             }
1464         } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
1465             mInputConsumer = mService.createInputConsumer(mHandler.getLooper(),
1466                     INPUT_CONSUMER_NAVIGATION,
1467                     HideNavInputEventReceiver::new,
1468                     displayFrames.mDisplayId);
1469             // As long as mInputConsumer is active, hover events are not dispatched to the app
1470             // and the pointer icon is likely to become stale. Hide it to avoid confusion.
1471             InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
1472         }
1473 
1474         // For purposes of positioning and showing the nav bar, if we have decided that it can't
1475         // be hidden (because of the screen aspect ratio), then take that into account.
1476         navVisible |= !canHideNavigationBar();
1477 
1478         boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
1479                 navTranslucent, navAllowedHidden, statusBarForcesShowingNavigation);
1480         if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
1481         updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
1482         if (updateSysUiVisibility) {
1483             updateSystemUiVisibilityLw();
1484         }
1485         layoutScreenDecorWindows(displayFrames);
1486 
1487         if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
1488             // Make sure that the zone we're avoiding for the cutout is at least as tall as the
1489             // status bar; otherwise fullscreen apps will end up cutting halfway into the status
1490             // bar.
1491             displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
1492                     displayFrames.mStable.top);
1493         }
1494 
1495         // In case this is a virtual display, and the host display has insets that overlap this
1496         // virtual display, apply the insets of the overlapped area onto the current and content
1497         // frame of this virtual display. This let us layout windows in the virtual display as
1498         // expected when the window needs to avoid overlap with the system windows.
1499         // TODO: Generalize the forwarded insets, so that we can handle system windows other than
1500         // IME.
1501         displayFrames.mCurrent.inset(mForwardedInsets);
1502         displayFrames.mContent.inset(mForwardedInsets);
1503     }
1504 
layoutScreenDecorWindows(DisplayFrames displayFrames)1505     private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
1506         if (mScreenDecorWindows.isEmpty()) {
1507             return;
1508         }
1509 
1510         sTmpRect.setEmpty();
1511         final int displayId = displayFrames.mDisplayId;
1512         final Rect dockFrame = displayFrames.mDock;
1513         final int displayHeight = displayFrames.mDisplayHeight;
1514         final int displayWidth = displayFrames.mDisplayWidth;
1515 
1516         for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
1517             final WindowState w = mScreenDecorWindows.valueAt(i);
1518             if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
1519                 // Skip if not on the same display or not visible.
1520                 continue;
1521             }
1522 
1523             w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
1524                     displayFrames.mUnrestricted /* displayFrame */,
1525                     displayFrames.mUnrestricted /* overscanFrame */,
1526                     displayFrames.mUnrestricted /* contentFrame */,
1527                     displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
1528                     displayFrames.mUnrestricted /* stableFrame */,
1529                     displayFrames.mUnrestricted /* outsetFrame */);
1530             w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1531             w.computeFrameLw();
1532             final Rect frame = w.getFrameLw();
1533 
1534             if (frame.left <= 0 && frame.top <= 0) {
1535                 // Docked at left or top.
1536                 if (frame.bottom >= displayHeight) {
1537                     // Docked left.
1538                     dockFrame.left = Math.max(frame.right, dockFrame.left);
1539                 } else if (frame.right >= displayWidth) {
1540                     // Docked top.
1541                     dockFrame.top = Math.max(frame.bottom, dockFrame.top);
1542                 } else {
1543                     Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1544                             + " not docked on left or top of display. frame=" + frame
1545                             + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1546                 }
1547             } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
1548                 // Docked at right or bottom.
1549                 if (frame.top <= 0) {
1550                     // Docked right.
1551                     dockFrame.right = Math.min(frame.left, dockFrame.right);
1552                 } else if (frame.left <= 0) {
1553                     // Docked bottom.
1554                     dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
1555                 } else {
1556                     Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1557                             + " not docked on right or bottom" + " of display. frame=" + frame
1558                             + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1559                 }
1560             } else {
1561                 // Screen decor windows are required to be docked on one of the sides of the screen.
1562                 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1563                         + " not docked on one of the sides of the display. frame=" + frame
1564                         + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1565             }
1566         }
1567 
1568         displayFrames.mRestricted.set(dockFrame);
1569         displayFrames.mCurrent.set(dockFrame);
1570         displayFrames.mVoiceContent.set(dockFrame);
1571         displayFrames.mSystem.set(dockFrame);
1572         displayFrames.mContent.set(dockFrame);
1573         displayFrames.mRestrictedOverscan.set(dockFrame);
1574     }
1575 
layoutStatusBar(DisplayFrames displayFrames, int sysui, boolean isKeyguardShowing)1576     private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
1577             boolean isKeyguardShowing) {
1578         // decide where the status bar goes ahead of time
1579         if (mStatusBar == null) {
1580             return false;
1581         }
1582         // apply any navigation bar insets
1583         sTmpRect.setEmpty();
1584         final WindowFrames windowFrames = mStatusBar.getWindowFrames();
1585         windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
1586                 displayFrames.mUnrestricted /* displayFrame */,
1587                 displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
1588                 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
1589                 displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
1590         windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1591 
1592         // Let the status bar determine its size.
1593         mStatusBar.computeFrameLw();
1594 
1595         // For layout, the status bar is always at the top with our fixed height.
1596         displayFrames.mStable.top = displayFrames.mUnrestricted.top
1597                 + mStatusBarHeightForRotation[displayFrames.mRotation];
1598         // Make sure the status bar covers the entire cutout height
1599         displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
1600                 displayFrames.mDisplayCutoutSafe.top);
1601 
1602         // Tell the bar controller where the collapsed status bar content is
1603         sTmpRect.set(mStatusBar.getContentFrameLw());
1604         sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
1605         sTmpRect.top = mStatusBar.getContentFrameLw().top;  // Ignore top display cutout inset
1606         sTmpRect.bottom = displayFrames.mStable.top;  // Use collapsed status bar size
1607         mStatusBarController.setContentFrame(sTmpRect);
1608 
1609         boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
1610         boolean statusBarTranslucent = (sysui
1611                 & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
1612 
1613         // If the status bar is hidden, we don't want to cause windows behind it to scroll.
1614         if (mStatusBar.isVisibleLw() && !statusBarTransient) {
1615             // Status bar may go away, so the screen area it occupies is available to apps but just
1616             // covering them when the status bar is visible.
1617             final Rect dockFrame = displayFrames.mDock;
1618             dockFrame.top = displayFrames.mStable.top;
1619             displayFrames.mContent.set(dockFrame);
1620             displayFrames.mVoiceContent.set(dockFrame);
1621             displayFrames.mCurrent.set(dockFrame);
1622 
1623             if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
1624                     "dock=%s content=%s cur=%s", dockFrame.toString(),
1625                     displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
1626 
1627             if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent()
1628                     && !mStatusBar.isAnimatingLw()) {
1629 
1630                 // If the opaque status bar is currently requested to be visible, and not in the
1631                 // process of animating on or off, then we can tell the app that it is covered by
1632                 // it.
1633                 displayFrames.mSystem.top = displayFrames.mStable.top;
1634             }
1635         }
1636         return mStatusBarController.checkHiddenLw();
1637     }
1638 
layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible, boolean navTranslucent, boolean navAllowedHidden, boolean statusBarForcesShowingNavigation)1639     private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
1640             boolean navTranslucent, boolean navAllowedHidden,
1641             boolean statusBarForcesShowingNavigation) {
1642         if (mNavigationBar == null) {
1643             return false;
1644         }
1645 
1646         final Rect navigationFrame = sTmpNavFrame;
1647         boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
1648         // Force the navigation bar to its appropriate place and size. We need to do this directly,
1649         // instead of relying on it to bubble up from the nav bar, because this needs to change
1650         // atomically with screen rotations.
1651         final int rotation = displayFrames.mRotation;
1652         final int displayHeight = displayFrames.mDisplayHeight;
1653         final int displayWidth = displayFrames.mDisplayWidth;
1654         final Rect dockFrame = displayFrames.mDock;
1655         mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
1656 
1657         final Rect cutoutSafeUnrestricted = sTmpRect;
1658         cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
1659         cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1660 
1661         if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1662             // It's a system nav bar or a portrait screen; nav bar goes on bottom.
1663             final int top = cutoutSafeUnrestricted.bottom
1664                     - getNavigationBarHeight(rotation, uiMode);
1665             final int topNavBar = cutoutSafeUnrestricted.bottom
1666                     - getNavigationBarFrameHeight(rotation, uiMode);
1667             navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom);
1668             displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
1669             if (transientNavBarShowing) {
1670                 mNavigationBarController.setBarShowingLw(true);
1671             } else if (navVisible) {
1672                 mNavigationBarController.setBarShowingLw(true);
1673                 dockFrame.bottom = displayFrames.mRestricted.bottom =
1674                         displayFrames.mRestrictedOverscan.bottom = top;
1675             } else {
1676                 // We currently want to hide the navigation UI - unless we expanded the status bar.
1677                 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1678             }
1679             if (navVisible && !navTranslucent && !navAllowedHidden
1680                     && !mNavigationBar.isAnimatingLw()
1681                     && !mNavigationBarController.wasRecentlyTranslucent()) {
1682                 // If the opaque nav bar is currently requested to be visible and not in the process
1683                 // of animating on or off, then we can tell the app that it is covered by it.
1684                 displayFrames.mSystem.bottom = top;
1685             }
1686         } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1687             // Landscape screen; nav bar goes to the right.
1688             final int left = cutoutSafeUnrestricted.right
1689                     - getNavigationBarWidth(rotation, uiMode);
1690             navigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
1691             displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
1692             if (transientNavBarShowing) {
1693                 mNavigationBarController.setBarShowingLw(true);
1694             } else if (navVisible) {
1695                 mNavigationBarController.setBarShowingLw(true);
1696                 dockFrame.right = displayFrames.mRestricted.right =
1697                         displayFrames.mRestrictedOverscan.right = left;
1698             } else {
1699                 // We currently want to hide the navigation UI - unless we expanded the status bar.
1700                 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1701             }
1702             if (navVisible && !navTranslucent && !navAllowedHidden
1703                     && !mNavigationBar.isAnimatingLw()
1704                     && !mNavigationBarController.wasRecentlyTranslucent()) {
1705                 // If the nav bar is currently requested to be visible, and not in the process of
1706                 // animating on or off, then we can tell the app that it is covered by it.
1707                 displayFrames.mSystem.right = left;
1708             }
1709         } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1710             // Seascape screen; nav bar goes to the left.
1711             final int right = cutoutSafeUnrestricted.left
1712                     + getNavigationBarWidth(rotation, uiMode);
1713             navigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
1714             displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
1715             if (transientNavBarShowing) {
1716                 mNavigationBarController.setBarShowingLw(true);
1717             } else if (navVisible) {
1718                 mNavigationBarController.setBarShowingLw(true);
1719                 dockFrame.left = displayFrames.mRestricted.left =
1720                         displayFrames.mRestrictedOverscan.left = right;
1721             } else {
1722                 // We currently want to hide the navigation UI - unless we expanded the status bar.
1723                 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1724             }
1725             if (navVisible && !navTranslucent && !navAllowedHidden
1726                     && !mNavigationBar.isAnimatingLw()
1727                     && !mNavigationBarController.wasRecentlyTranslucent()) {
1728                 // If the nav bar is currently requested to be visible, and not in the process of
1729                 // animating on or off, then we can tell the app that it is covered by it.
1730                 displayFrames.mSystem.left = right;
1731             }
1732         }
1733 
1734         // Make sure the content and current rectangles are updated to account for the restrictions
1735         // from the navigation bar.
1736         displayFrames.mCurrent.set(dockFrame);
1737         displayFrames.mVoiceContent.set(dockFrame);
1738         displayFrames.mContent.set(dockFrame);
1739         // And compute the final frame.
1740         sTmpRect.setEmpty();
1741         mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
1742                 navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
1743                 displayFrames.mDisplayCutoutSafe /* contentFrame */,
1744                 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
1745                 navigationFrame /* stableFrame */,
1746                 displayFrames.mDisplayCutoutSafe /* outsetFrame */);
1747         mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1748         mNavigationBar.computeFrameLw();
1749         mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
1750 
1751         if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
1752         return mNavigationBarController.checkHiddenLw();
1753     }
1754 
setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf, DisplayFrames displayFrames)1755     private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
1756             boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf,
1757             DisplayFrames displayFrames) {
1758         if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
1759             // Here's a special case: if the child window is not the 'dock window'
1760             // or input method target, and the window it is attached to is below
1761             // the dock window, then the frames we computed for the window it is
1762             // attached to can not be used because the dock is effectively part
1763             // of the underlying window and the attached window is floating on top
1764             // of the whole thing. So, we ignore the attached window and explicitly
1765             // compute the frames that would be appropriate without the dock.
1766             vf.set(displayFrames.mDock);
1767             cf.set(displayFrames.mDock);
1768             of.set(displayFrames.mDock);
1769             df.set(displayFrames.mDock);
1770         } else {
1771 
1772             // In case we forced the window to draw behind the navigation bar, restrict df/of to
1773             // DF.RestrictedOverscan to simulate old compat behavior.
1774             Rect parentDisplayFrame = attached.getDisplayFrameLw();
1775             Rect parentOverscan = attached.getOverscanFrameLw();
1776             final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
1777             if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1778                     && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1779                     && (attachedAttrs.systemUiVisibility
1780                             & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
1781                 parentOverscan = new Rect(parentOverscan);
1782                 parentOverscan.intersect(displayFrames.mRestrictedOverscan);
1783                 parentDisplayFrame = new Rect(parentDisplayFrame);
1784                 parentDisplayFrame.intersect(displayFrames.mRestrictedOverscan);
1785             }
1786 
1787             // The effective display frame of the attached window depends on whether it is taking
1788             // care of insetting its content. If not, we need to use the parent's content frame so
1789             // that the entire window is positioned within that content. Otherwise we can use the
1790             // overscan frame and let the attached window take care of positioning its content
1791             // appropriately.
1792             if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1793                 // Set the content frame of the attached window to the parent's decor frame
1794                 // (same as content frame when IME isn't present) if specifically requested by
1795                 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
1796                 // Otherwise, use the overscan frame.
1797                 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
1798                         ? attached.getContentFrameLw() : parentOverscan);
1799             } else {
1800                 // If the window is resizing, then we want to base the content frame on our attached
1801                 // content frame to resize...however, things can be tricky if the attached window is
1802                 // NOT in resize mode, in which case its content frame will be larger.
1803                 // Ungh. So to deal with that, make sure the content frame we end up using is not
1804                 // covering the IM dock.
1805                 cf.set(attached.getContentFrameLw());
1806                 if (attached.isVoiceInteraction()) {
1807                     cf.intersectUnchecked(displayFrames.mVoiceContent);
1808                 } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
1809                     cf.intersectUnchecked(displayFrames.mContent);
1810                 }
1811             }
1812             df.set(insetDecors ? parentDisplayFrame : cf);
1813             of.set(insetDecors ? parentOverscan : cf);
1814             vf.set(attached.getVisibleFrameLw());
1815         }
1816         // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
1817         // positioned relative to its parent or the entire screen.
1818         pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1819     }
1820 
applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames)1821     private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
1822         if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
1823             return;
1824         }
1825         // If app is requesting a stable layout, don't let the content insets go below the stable
1826         // values.
1827         if ((fl & FLAG_FULLSCREEN) != 0) {
1828             r.intersectUnchecked(displayFrames.mStableFullscreen);
1829         } else {
1830             r.intersectUnchecked(displayFrames.mStable);
1831         }
1832     }
1833 
canReceiveInput(WindowState win)1834     private boolean canReceiveInput(WindowState win) {
1835         boolean notFocusable =
1836                 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
1837         boolean altFocusableIm =
1838                 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
1839         boolean notFocusableForIm = notFocusable ^ altFocusableIm;
1840         return !notFocusableForIm;
1841     }
1842 
1843     /**
1844      * Called for each window attached to the window manager as layout is proceeding. The
1845      * implementation of this function must take care of setting the window's frame, either here or
1846      * in finishLayout().
1847      *
1848      * @param win The window being positioned.
1849      * @param attached For sub-windows, the window it is attached to; this
1850      *                 window will already have had layoutWindow() called on it
1851      *                 so you can use its Rect.  Otherwise null.
1852      * @param displayFrames The display frames.
1853      */
layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames)1854     public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
1855         // We've already done the navigation bar, status bar, and all screen decor windows. If the
1856         // status bar can receive input, we need to layout it again to accommodate for the IME
1857         // window.
1858         if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
1859                 || mScreenDecorWindows.contains(win)) {
1860             return;
1861         }
1862         final WindowManager.LayoutParams attrs = win.getAttrs();
1863         final boolean isDefaultDisplay = win.isDefaultDisplay();
1864 
1865         final int type = attrs.type;
1866         final int fl = PolicyControl.getWindowFlags(win, attrs);
1867         final int pfl = attrs.privateFlags;
1868         final int sim = attrs.softInputMode;
1869         final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
1870         final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
1871 
1872         final WindowFrames windowFrames = win.getWindowFrames();
1873 
1874         windowFrames.setHasOutsets(false);
1875         sTmpLastParentFrame.set(windowFrames.mParentFrame);
1876         final Rect pf = windowFrames.mParentFrame;
1877         final Rect df = windowFrames.mDisplayFrame;
1878         final Rect of = windowFrames.mOverscanFrame;
1879         final Rect cf = windowFrames.mContentFrame;
1880         final Rect vf = windowFrames.mVisibleFrame;
1881         final Rect dcf = windowFrames.mDecorFrame;
1882         final Rect sf = windowFrames.mStableFrame;
1883         dcf.setEmpty();
1884         windowFrames.setParentFrameWasClippedByDisplayCutout(false);
1885         windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1886 
1887         final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
1888                 && mNavigationBar.isVisibleLw();
1889 
1890         final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
1891 
1892         final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
1893                 || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
1894 
1895         final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
1896         final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
1897 
1898         sf.set(displayFrames.mStable);
1899 
1900         if (type == TYPE_INPUT_METHOD) {
1901             vf.set(displayFrames.mDock);
1902             cf.set(displayFrames.mDock);
1903             of.set(displayFrames.mDock);
1904             df.set(displayFrames.mDock);
1905             windowFrames.mParentFrame.set(displayFrames.mDock);
1906             // IM dock windows layout below the nav bar...
1907             pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
1908             // ...with content insets above the nav bar
1909             cf.bottom = vf.bottom = displayFrames.mStable.bottom;
1910             if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
1911                 // The status bar forces the navigation bar while it's visible. Make sure the IME
1912                 // avoids the navigation bar in that case.
1913                 if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1914                     pf.right = df.right = of.right = cf.right = vf.right =
1915                             displayFrames.mStable.right;
1916                 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1917                     pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left;
1918                 }
1919             }
1920 
1921             // In case the navigation bar is on the bottom, we use the frame height instead of the
1922             // regular height for the insets we send to the IME as we need some space to show
1923             // additional buttons in SystemUI when the IME is up.
1924             if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1925                 final int rotation = displayFrames.mRotation;
1926                 final int uimode = mService.mPolicy.getUiMode();
1927                 final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode)
1928                         - getNavigationBarHeight(rotation, uimode);
1929                 if (navHeightOffset > 0) {
1930                     cf.bottom -= navHeightOffset;
1931                     sf.bottom -= navHeightOffset;
1932                     vf.bottom -= navHeightOffset;
1933                     dcf.bottom -= navHeightOffset;
1934                 }
1935             }
1936 
1937             // IM dock windows always go to the bottom of the screen.
1938             attrs.gravity = Gravity.BOTTOM;
1939         } else if (type == TYPE_VOICE_INTERACTION) {
1940             of.set(displayFrames.mUnrestricted);
1941             df.set(displayFrames.mUnrestricted);
1942             pf.set(displayFrames.mUnrestricted);
1943             if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1944                 cf.set(displayFrames.mDock);
1945             } else {
1946                 cf.set(displayFrames.mContent);
1947             }
1948             if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1949                 vf.set(displayFrames.mCurrent);
1950             } else {
1951                 vf.set(cf);
1952             }
1953         } else if (type == TYPE_WALLPAPER) {
1954             layoutWallpaper(displayFrames, pf, df, of, cf);
1955         } else if (win == mStatusBar) {
1956             of.set(displayFrames.mUnrestricted);
1957             df.set(displayFrames.mUnrestricted);
1958             pf.set(displayFrames.mUnrestricted);
1959             cf.set(displayFrames.mStable);
1960             vf.set(displayFrames.mStable);
1961 
1962             if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
1963                 cf.bottom = displayFrames.mContent.bottom;
1964             } else {
1965                 cf.bottom = displayFrames.mDock.bottom;
1966                 vf.bottom = displayFrames.mContent.bottom;
1967             }
1968         } else {
1969             dcf.set(displayFrames.mSystem);
1970             final boolean inheritTranslucentDecor =
1971                     (attrs.privateFlags & PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
1972             final boolean isAppWindow =
1973                     type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
1974             final boolean topAtRest =
1975                     win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
1976             if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
1977                 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
1978                         && (fl & FLAG_FULLSCREEN) == 0
1979                         && (fl & FLAG_TRANSLUCENT_STATUS) == 0
1980                         && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1981                         && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
1982                     // Ensure policy decor includes status bar
1983                     dcf.top = displayFrames.mStable.top;
1984                 }
1985                 if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
1986                         && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
1987                         && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1988                         && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
1989                     // Ensure policy decor includes navigation bar
1990                     dcf.bottom = displayFrames.mStable.bottom;
1991                     dcf.right = displayFrames.mStable.right;
1992                 }
1993             }
1994 
1995             if (layoutInScreen && layoutInsetDecor) {
1996                 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
1997                         + "): IN_SCREEN, INSET_DECOR");
1998                 // This is the case for a normal activity window: we want it to cover all of the
1999                 // screen space, and it can take care of moving its contents to account for screen
2000                 // decorations that intrude into that space.
2001                 if (attached != null) {
2002                     // If this window is attached to another, our display
2003                     // frame is the same as the one we are attached to.
2004                     setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf,
2005                             displayFrames);
2006                 } else {
2007                     if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2008                         // Status bar panels are the only windows who can go on top of the status
2009                         // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
2010                         // have the same privileges as the status bar itself.
2011                         //
2012                         // However, they should still dodge the navigation bar if it exists.
2013 
2014                         pf.left = df.left = of.left = hasNavBar
2015                                 ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
2016                         pf.top = df.top = of.top = displayFrames.mUnrestricted.top;
2017                         pf.right = df.right = of.right = hasNavBar
2018                                 ? displayFrames.mRestricted.right
2019                                 : displayFrames.mUnrestricted.right;
2020                         pf.bottom = df.bottom = of.bottom = hasNavBar
2021                                 ? displayFrames.mRestricted.bottom
2022                                 : displayFrames.mUnrestricted.bottom;
2023 
2024                         if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
2025                     } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
2026                             && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
2027                         // Asking to layout into the overscan region, so give it that pure
2028                         // unrestricted area.
2029                         of.set(displayFrames.mOverscan);
2030                         df.set(displayFrames.mOverscan);
2031                         pf.set(displayFrames.mOverscan);
2032                     } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
2033                             && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
2034                             || type == TYPE_VOLUME_OVERLAY
2035                             || type == TYPE_KEYGUARD_DIALOG)) {
2036                         // Asking for layout as if the nav bar is hidden, lets the application
2037                         // extend into the unrestricted overscan screen area. We only do this for
2038                         // application windows and certain system windows to ensure no window that
2039                         // can be above the nav bar can do this.
2040                         df.set(displayFrames.mOverscan);
2041                         pf.set(displayFrames.mOverscan);
2042                         // We need to tell the app about where the frame inside the overscan is, so
2043                         // it can inset its content by that amount -- it didn't ask to actually
2044                         // extend itself into the overscan region.
2045                         of.set(displayFrames.mUnrestricted);
2046                     } else {
2047                         df.set(displayFrames.mRestrictedOverscan);
2048                         pf.set(displayFrames.mRestrictedOverscan);
2049                         // We need to tell the app about where the frame inside the overscan
2050                         // is, so it can inset its content by that amount -- it didn't ask
2051                         // to actually extend itself into the overscan region.
2052                         of.set(displayFrames.mUnrestricted);
2053                     }
2054 
2055                     if ((fl & FLAG_FULLSCREEN) == 0) {
2056                         if (win.isVoiceInteraction()) {
2057                             cf.set(displayFrames.mVoiceContent);
2058                         } else {
2059                             // IME Insets are handled on the client for ADJUST_RESIZE in the new
2060                             // insets world
2061                             if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2062                                     || adjust != SOFT_INPUT_ADJUST_RESIZE) {
2063                                 cf.set(displayFrames.mDock);
2064                             } else {
2065                                 cf.set(displayFrames.mContent);
2066                             }
2067                         }
2068                     } else {
2069                         // Full screen windows are always given a layout that is as if the status
2070                         // bar and other transient decors are gone. This is to avoid bad states when
2071                         // moving from a window that is not hiding the status bar to one that is.
2072                         cf.set(displayFrames.mRestricted);
2073                     }
2074                     applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2075                     if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2076                         vf.set(displayFrames.mCurrent);
2077                     } else {
2078                         vf.set(cf);
2079                     }
2080                 }
2081             } else if (layoutInScreen || (sysUiFl
2082                     & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
2083                     | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
2084                 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2085                         + "): IN_SCREEN");
2086                 // A window that has requested to fill the entire screen just
2087                 // gets everything, period.
2088                 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2089                     cf.set(displayFrames.mUnrestricted);
2090                     of.set(displayFrames.mUnrestricted);
2091                     df.set(displayFrames.mUnrestricted);
2092                     pf.set(displayFrames.mUnrestricted);
2093                     if (hasNavBar) {
2094                         pf.left = df.left = of.left = cf.left = displayFrames.mDock.left;
2095                         pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right;
2096                         pf.bottom = df.bottom = of.bottom = cf.bottom =
2097                                 displayFrames.mRestricted.bottom;
2098                     }
2099                     if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
2100                 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
2101                     // The navigation bar has Real Ultimate Power.
2102                     of.set(displayFrames.mUnrestricted);
2103                     df.set(displayFrames.mUnrestricted);
2104                     pf.set(displayFrames.mUnrestricted);
2105                     if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
2106                 } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
2107                         && ((fl & FLAG_FULLSCREEN) != 0)) {
2108                     // Fullscreen secure system overlays get what they ask for. Screenshot region
2109                     // selection overlay should also expand to full screen.
2110                     cf.set(displayFrames.mOverscan);
2111                     of.set(displayFrames.mOverscan);
2112                     df.set(displayFrames.mOverscan);
2113                     pf.set(displayFrames.mOverscan);
2114                 } else if (type == TYPE_BOOT_PROGRESS) {
2115                     // Boot progress screen always covers entire display.
2116                     cf.set(displayFrames.mOverscan);
2117                     of.set(displayFrames.mOverscan);
2118                     df.set(displayFrames.mOverscan);
2119                     pf.set(displayFrames.mOverscan);
2120                 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
2121                         && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
2122                     // Asking to layout into the overscan region, so give it that pure unrestricted
2123                     // area.
2124                     cf.set(displayFrames.mOverscan);
2125                     of.set(displayFrames.mOverscan);
2126                     df.set(displayFrames.mOverscan);
2127                     pf.set(displayFrames.mOverscan);
2128                 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
2129                         && (type == TYPE_STATUS_BAR
2130                         || type == TYPE_TOAST
2131                         || type == TYPE_DOCK_DIVIDER
2132                         || type == TYPE_VOICE_INTERACTION_STARTING
2133                         || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
2134                     // Asking for layout as if the nav bar is hidden, lets the
2135                     // application extend into the unrestricted screen area.  We
2136                     // only do this for application windows (or toasts) to ensure no window that
2137                     // can be above the nav bar can do this.
2138                     // XXX This assumes that an app asking for this will also
2139                     // ask for layout in only content.  We can't currently figure out
2140                     // what the screen would be if only laying out to hide the nav bar.
2141                     cf.set(displayFrames.mUnrestricted);
2142                     of.set(displayFrames.mUnrestricted);
2143                     df.set(displayFrames.mUnrestricted);
2144                     pf.set(displayFrames.mUnrestricted);
2145                 } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
2146                     of.set(displayFrames.mRestricted);
2147                     df.set(displayFrames.mRestricted);
2148                     pf.set(displayFrames.mRestricted);
2149 
2150                     // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
2151                     // world
2152                     if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2153                             || adjust != SOFT_INPUT_ADJUST_RESIZE) {
2154                         cf.set(displayFrames.mDock);
2155                     } else {
2156                         cf.set(displayFrames.mContent);
2157                     }
2158                 } else {
2159                     cf.set(displayFrames.mRestricted);
2160                     of.set(displayFrames.mRestricted);
2161                     df.set(displayFrames.mRestricted);
2162                     pf.set(displayFrames.mRestricted);
2163                 }
2164 
2165                 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2166 
2167                 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2168                     vf.set(displayFrames.mCurrent);
2169                 } else {
2170                     vf.set(cf);
2171                 }
2172             } else if (attached != null) {
2173                 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2174                         + "): attached to " + attached);
2175                 // A child window should be placed inside of the same visible
2176                 // frame that its parent had.
2177                 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf,
2178                         displayFrames);
2179             } else {
2180                 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2181                         + "): normal window");
2182                 // Otherwise, a normal window must be placed inside the content
2183                 // of all screen decorations.
2184                 if (type == TYPE_STATUS_BAR_PANEL) {
2185                     // Status bar panels can go on
2186                     // top of the status bar. They are protected by the STATUS_BAR_SERVICE
2187                     // permission, so they have the same privileges as the status bar itself.
2188                     cf.set(displayFrames.mRestricted);
2189                     of.set(displayFrames.mRestricted);
2190                     df.set(displayFrames.mRestricted);
2191                     pf.set(displayFrames.mRestricted);
2192                 } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
2193                     // These dialogs are stable to interim decor changes.
2194                     cf.set(displayFrames.mStable);
2195                     of.set(displayFrames.mStable);
2196                     df.set(displayFrames.mStable);
2197                     pf.set(displayFrames.mStable);
2198                 } else {
2199                     pf.set(displayFrames.mContent);
2200                     if (win.isVoiceInteraction()) {
2201                         cf.set(displayFrames.mVoiceContent);
2202                         of.set(displayFrames.mVoiceContent);
2203                         df.set(displayFrames.mVoiceContent);
2204                     } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2205                         cf.set(displayFrames.mDock);
2206                         of.set(displayFrames.mDock);
2207                         df.set(displayFrames.mDock);
2208                     } else {
2209                         cf.set(displayFrames.mContent);
2210                         of.set(displayFrames.mContent);
2211                         df.set(displayFrames.mContent);
2212                     }
2213                     if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2214                         vf.set(displayFrames.mCurrent);
2215                     } else {
2216                         vf.set(cf);
2217                     }
2218                 }
2219             }
2220         }
2221 
2222         final int cutoutMode = attrs.layoutInDisplayCutoutMode;
2223         final boolean attachedInParent = attached != null && !layoutInScreen;
2224         final boolean requestedHideNavigation =
2225                 (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
2226 
2227         // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
2228         // cropped / shifted to the displayFrame in WindowState.
2229         final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
2230                 && type != TYPE_BASE_APPLICATION;
2231 
2232         // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
2233         // the cutout safe zone.
2234         if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
2235             final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
2236             displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
2237             if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
2238                     && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2239                 // At the top we have the status bar, so apps that are
2240                 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
2241                 // already expect that there's an inset there and we don't need to exclude
2242                 // the window from that area.
2243                 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
2244             }
2245             if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
2246                     && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2247                 // Same for the navigation bar.
2248                 switch (mNavigationBarPosition) {
2249                     case NAV_BAR_BOTTOM:
2250                         displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2251                         break;
2252                     case NAV_BAR_RIGHT:
2253                         displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
2254                         break;
2255                     case NAV_BAR_LEFT:
2256                         displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
2257                         break;
2258                 }
2259             }
2260             if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
2261                 // The IME can always extend under the bottom cutout if the navbar is there.
2262                 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2263             }
2264             // Windows that are attached to a parent and laid out in said parent already avoid
2265             // the cutout according to that parent and don't need to be further constrained.
2266             // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
2267             // They will later be cropped or shifted using the displayFrame in WindowState,
2268             // which prevents overlap with the DisplayCutout.
2269             if (!attachedInParent && !floatingInScreenWindow) {
2270                 sTmpRect.set(pf);
2271                 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2272                 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
2273             }
2274             // Make sure that NO_LIMITS windows clipped to the display don't extend under the
2275             // cutout.
2276             df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2277         }
2278 
2279         // Content should never appear in the cutout.
2280         cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
2281 
2282         // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
2283         // Also, we don't allow windows in multi-window mode to extend out of the screen.
2284         if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
2285                 && !win.inMultiWindowMode()) {
2286             df.left = df.top = -10000;
2287             df.right = df.bottom = 10000;
2288             if (type != TYPE_WALLPAPER) {
2289                 of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
2290                 of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
2291             }
2292         }
2293 
2294         // If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we
2295         // need to provide information to the clients that want to pretend that you can draw there.
2296         // We only want to apply outsets to certain types of windows. For example, we never want to
2297         // apply the outsets to floating dialogs, because they wouldn't make sense there.
2298         final boolean useOutsets = shouldUseOutsets(attrs, fl);
2299         if (isDefaultDisplay && useOutsets) {
2300             final Rect osf = windowFrames.mOutsetFrame;
2301             osf.set(cf.left, cf.top, cf.right, cf.bottom);
2302             windowFrames.setHasOutsets(true);
2303             int outset = mWindowOutsetBottom;
2304             if (outset > 0) {
2305                 int rotation = displayFrames.mRotation;
2306                 if (rotation == Surface.ROTATION_0) {
2307                     osf.bottom += outset;
2308                 } else if (rotation == Surface.ROTATION_90) {
2309                     osf.right += outset;
2310                 } else if (rotation == Surface.ROTATION_180) {
2311                     osf.top -= outset;
2312                 } else if (rotation == Surface.ROTATION_270) {
2313                     osf.left -= outset;
2314                 }
2315                 if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset
2316                         + " with rotation " + rotation + ", result: " + osf);
2317             }
2318         }
2319 
2320         if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
2321                 + ": sim=#" + Integer.toHexString(sim)
2322                 + " attach=" + attached + " type=" + type
2323                 + String.format(" flags=0x%08x", fl)
2324                 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
2325                 + " of=" + of.toShortString()
2326                 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
2327                 + " dcf=" + dcf.toShortString()
2328                 + " sf=" + sf.toShortString()
2329                 + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win);
2330 
2331         if (!sTmpLastParentFrame.equals(pf)) {
2332             windowFrames.setContentChanged(true);
2333         }
2334 
2335         win.computeFrameLw();
2336         // Dock windows carve out the bottom of the screen, so normal windows
2337         // can't appear underneath them.
2338         if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
2339                 && !win.getGivenInsetsPendingLw()) {
2340             offsetInputMethodWindowLw(win, displayFrames);
2341         }
2342         if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
2343                 && !win.getGivenInsetsPendingLw()) {
2344             offsetVoiceInputWindowLw(win, displayFrames);
2345         }
2346     }
2347 
layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf)2348     private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf) {
2349         // The wallpaper has Real Ultimate Power, but we want to tell it about the overscan area.
2350         df.set(displayFrames.mOverscan);
2351         pf.set(displayFrames.mOverscan);
2352         cf.set(displayFrames.mUnrestricted);
2353         of.set(displayFrames.mUnrestricted);
2354     }
2355 
offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames)2356     private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
2357         int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2358         top += win.getGivenContentInsetsLw().top;
2359         displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
2360         displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2361         top = win.getVisibleFrameLw().top;
2362         top += win.getGivenVisibleInsetsLw().top;
2363         displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
2364         if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
2365                 + displayFrames.mDock.bottom + " mContentBottom="
2366                 + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
2367     }
2368 
offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames)2369     private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
2370         int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2371         top += win.getGivenContentInsetsLw().top;
2372         displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2373     }
2374 
2375     /**
2376      * Called following layout of all windows before each window has policy applied.
2377      */
beginPostLayoutPolicyLw()2378     public void beginPostLayoutPolicyLw() {
2379         mTopFullscreenOpaqueWindowState = null;
2380         mTopFullscreenOpaqueOrDimmingWindowState = null;
2381         mTopDockedOpaqueWindowState = null;
2382         mTopDockedOpaqueOrDimmingWindowState = null;
2383         mForceStatusBar = false;
2384         mForceStatusBarFromKeyguard = false;
2385         mForceStatusBarTransparent = false;
2386         mForcingShowNavBar = false;
2387         mForcingShowNavBarLayer = -1;
2388 
2389         mAllowLockscreenWhenOn = false;
2390         mShowingDream = false;
2391         mWindowSleepTokenNeeded = false;
2392     }
2393 
2394     /**
2395      * Called following layout of all window to apply policy to each window.
2396      *
2397      * @param win The window being positioned.
2398      * @param attrs The LayoutParams of the window.
2399      * @param attached For sub-windows, the window it is attached to. Otherwise null.
2400      */
applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached, WindowState imeTarget)2401     public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
2402             WindowState attached, WindowState imeTarget) {
2403         final boolean affectsSystemUi = win.canAffectSystemUiFlags();
2404         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
2405         mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
2406         final int fl = PolicyControl.getWindowFlags(win, attrs);
2407         if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
2408                 && attrs.type == TYPE_INPUT_METHOD) {
2409             mForcingShowNavBar = true;
2410             mForcingShowNavBarLayer = win.getSurfaceLayer();
2411         }
2412         if (attrs.type == TYPE_STATUS_BAR) {
2413             if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
2414                 mForceStatusBarFromKeyguard = true;
2415             }
2416             if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
2417                 mForceStatusBarTransparent = true;
2418             }
2419         }
2420 
2421         boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
2422                 && attrs.type < FIRST_SYSTEM_WINDOW;
2423         final int windowingMode = win.getWindowingMode();
2424         final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
2425                 windowingMode == WINDOWING_MODE_FULLSCREEN
2426                         || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
2427         if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
2428             if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2429                 mForceStatusBar = true;
2430             }
2431             if (attrs.type == TYPE_DREAM) {
2432                 // If the lockscreen was showing when the dream started then wait
2433                 // for the dream to draw before hiding the lockscreen.
2434                 if (!mDreamingLockscreen
2435                         || (win.isVisibleLw() && win.hasDrawnLw())) {
2436                     mShowingDream = true;
2437                     appWindow = true;
2438                 }
2439             }
2440 
2441             // For app windows that are not attached, we decide if all windows in the app they
2442             // represent should be hidden or if we should hide the lockscreen. For attached app
2443             // windows we defer the decision to the window it is attached to.
2444             if (appWindow && attached == null) {
2445                 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2446                     if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
2447                     mTopFullscreenOpaqueWindowState = win;
2448                     if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2449                         mTopFullscreenOpaqueOrDimmingWindowState = win;
2450                     }
2451                     if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2452                         mAllowLockscreenWhenOn = true;
2453                     }
2454                 }
2455             }
2456         }
2457 
2458         // Voice interaction overrides both top fullscreen and top docked.
2459         if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION) {
2460             if (mTopFullscreenOpaqueWindowState == null) {
2461                 mTopFullscreenOpaqueWindowState = win;
2462                 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2463                     mTopFullscreenOpaqueOrDimmingWindowState = win;
2464                 }
2465             }
2466             if (mTopDockedOpaqueWindowState == null) {
2467                 mTopDockedOpaqueWindowState = win;
2468                 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2469                     mTopDockedOpaqueOrDimmingWindowState = win;
2470                 }
2471             }
2472         }
2473 
2474         // Keep track of the window if it's dimming but not necessarily fullscreen.
2475         if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
2476                 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2477             mTopFullscreenOpaqueOrDimmingWindowState = win;
2478         }
2479 
2480         // We need to keep track of the top "fullscreen" opaque window for the docked stack
2481         // separately, because both the "real fullscreen" opaque window and the one for the docked
2482         // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
2483         if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
2484                 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2485             mTopDockedOpaqueWindowState = win;
2486             if (mTopDockedOpaqueOrDimmingWindowState == null) {
2487                 mTopDockedOpaqueOrDimmingWindowState = win;
2488             }
2489         }
2490 
2491         // Also keep track of any windows that are dimming but not necessarily fullscreen in the
2492         // docked stack.
2493         if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
2494                 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2495             mTopDockedOpaqueOrDimmingWindowState = win;
2496         }
2497     }
2498 
2499     /**
2500      * Called following layout of all windows and after policy has been applied
2501      * to each window. If in this function you do
2502      * something that may have modified the animation state of another window,
2503      * be sure to return non-zero in order to perform another pass through layout.
2504      *
2505      * @return Return any bit set of
2506      *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
2507      *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
2508      *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
2509      *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
2510      */
2511     public int finishPostLayoutPolicyLw() {
2512         int changes = 0;
2513         boolean topIsFullscreen = false;
2514 
2515         // If we are not currently showing a dream then remember the current
2516         // lockscreen state.  We will use this to determine whether the dream
2517         // started while the lockscreen was showing and remember this state
2518         // while the dream is showing.
2519         if (!mShowingDream) {
2520             mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
2521             if (mDreamingSleepTokenNeeded) {
2522                 mDreamingSleepTokenNeeded = false;
2523                 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
2524             }
2525         } else {
2526             if (!mDreamingSleepTokenNeeded) {
2527                 mDreamingSleepTokenNeeded = true;
2528                 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
2529             }
2530         }
2531 
2532         if (mStatusBar != null) {
2533             if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
2534                     + " forcefkg=" + mForceStatusBarFromKeyguard
2535                     + " top=" + mTopFullscreenOpaqueWindowState);
2536             boolean shouldBeTransparent = mForceStatusBarTransparent
2537                     && !mForceStatusBar
2538                     && !mForceStatusBarFromKeyguard;
2539             if (!shouldBeTransparent) {
2540                 mStatusBarController.setShowTransparent(false /* transparent */);
2541             } else if (!mStatusBar.isVisibleLw()) {
2542                 mStatusBarController.setShowTransparent(true /* transparent */);
2543             }
2544 
2545             boolean statusBarForcesShowingNavigation =
2546                     (mStatusBar.getAttrs().privateFlags
2547                             & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
2548             boolean topAppHidesStatusBar = topAppHidesStatusBar();
2549             if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent
2550                     || statusBarForcesShowingNavigation) {
2551                 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
2552                 if (mStatusBarController.setBarShowingLw(true)) {
2553                     changes |= FINISH_LAYOUT_REDO_LAYOUT;
2554                 }
2555                 // Maintain fullscreen layout until incoming animation is complete.
2556                 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
2557                 // Transient status bar is not allowed if status bar is on lockscreen or status bar
2558                 // is expecting the navigation keys from the user.
2559                 if ((mForceStatusBarFromKeyguard || statusBarForcesShowingNavigation)
2560                         && mStatusBarController.isTransientShowing()) {
2561                     mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
2562                             mLastSystemUiFlags, mLastSystemUiFlags);
2563                 }
2564             } else if (mTopFullscreenOpaqueWindowState != null) {
2565                 topIsFullscreen = topAppHidesStatusBar;
2566                 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2567                 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
2568                 // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
2569                 // case though.
2570                 if (mStatusBarController.isTransientShowing()) {
2571                     if (mStatusBarController.setBarShowingLw(true)) {
2572                         changes |= FINISH_LAYOUT_REDO_LAYOUT;
2573                     }
2574                 } else if (topIsFullscreen
2575                         && !mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM)
2576                         && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
2577                     if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
2578                     if (mStatusBarController.setBarShowingLw(false)) {
2579                         changes |= FINISH_LAYOUT_REDO_LAYOUT;
2580                     } else {
2581                         if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
2582                     }
2583                 } else {
2584                     if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
2585                     if (mStatusBarController.setBarShowingLw(true)) {
2586                         changes |= FINISH_LAYOUT_REDO_LAYOUT;
2587                     }
2588                     topAppHidesStatusBar = false;
2589                 }
2590             }
2591             mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
2592         }
2593 
2594         if (mTopIsFullscreen != topIsFullscreen) {
2595             if (!topIsFullscreen) {
2596                 // Force another layout when status bar becomes fully shown.
2597                 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2598             }
2599             mTopIsFullscreen = topIsFullscreen;
2600         }
2601 
2602         if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
2603             // If the navigation bar has been hidden or shown, we need to do another
2604             // layout pass to update that window.
2605             changes |= FINISH_LAYOUT_REDO_LAYOUT;
2606         }
2607 
2608         if (mShowingDream != mLastShowingDream) {
2609             mLastShowingDream = mShowingDream;
2610             mService.notifyShowingDreamChanged();
2611         }
2612 
2613         updateWindowSleepToken();
2614 
2615         mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
2616         return changes;
2617     }
2618 
2619     private void updateWindowSleepToken() {
2620         if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) {
2621             mHandler.removeCallbacks(mReleaseSleepTokenRunnable);
2622             mHandler.post(mAcquireSleepTokenRunnable);
2623         } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) {
2624             mHandler.removeCallbacks(mAcquireSleepTokenRunnable);
2625             mHandler.post(mReleaseSleepTokenRunnable);
2626         }
2627         mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded;
2628     }
2629 
2630     /**
2631      * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
2632      *         window.
2633      */
2634     private boolean topAppHidesStatusBar() {
2635         if (mTopFullscreenOpaqueWindowState == null) {
2636             return false;
2637         }
2638         final int fl = PolicyControl.getWindowFlags(null,
2639                 mTopFullscreenOpaqueWindowState.getAttrs());
2640         if (localLOGV) {
2641             Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
2642             Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2643                     + " lp.flags=0x" + Integer.toHexString(fl));
2644         }
2645         return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
2646                 || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
2647     }
2648 
2649     /**
2650      * Called when the user is switched.
2651      */
2652     public void switchUser() {
2653         updateCurrentUserResources();
2654     }
2655 
2656     /**
2657      * Called when the resource overlays change.
2658      */
2659     public void onOverlayChangedLw() {
2660         updateCurrentUserResources();
2661         onConfigurationChanged();
2662         mSystemGestures.onConfigurationChanged();
2663     }
2664 
2665     /**
2666      * Called when the configuration has changed, and it's safe to load new values from resources.
2667      */
2668     public void onConfigurationChanged() {
2669         final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
2670 
2671         final Resources res = getCurrentUserResources();
2672         final int portraitRotation = displayRotation.getPortraitRotation();
2673         final int upsideDownRotation = displayRotation.getUpsideDownRotation();
2674         final int landscapeRotation = displayRotation.getLandscapeRotation();
2675         final int seascapeRotation = displayRotation.getSeascapeRotation();
2676         final int uiMode = mService.mPolicy.getUiMode();
2677 
2678         if (hasStatusBar()) {
2679             mStatusBarHeightForRotation[portraitRotation] =
2680                     mStatusBarHeightForRotation[upsideDownRotation] =
2681                             res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
2682             mStatusBarHeightForRotation[landscapeRotation] =
2683                     mStatusBarHeightForRotation[seascapeRotation] =
2684                             res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
2685         } else {
2686             mStatusBarHeightForRotation[portraitRotation] =
2687                     mStatusBarHeightForRotation[upsideDownRotation] =
2688                             mStatusBarHeightForRotation[landscapeRotation] =
2689                                     mStatusBarHeightForRotation[seascapeRotation] = 0;
2690         }
2691 
2692         // Height of the navigation bar when presented horizontally at bottom
2693         mNavigationBarHeightForRotationDefault[portraitRotation] =
2694         mNavigationBarHeightForRotationDefault[upsideDownRotation] =
2695                 res.getDimensionPixelSize(R.dimen.navigation_bar_height);
2696         mNavigationBarHeightForRotationDefault[landscapeRotation] =
2697         mNavigationBarHeightForRotationDefault[seascapeRotation] =
2698                 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
2699 
2700         // Height of the navigation bar frame when presented horizontally at bottom
2701         mNavigationBarFrameHeightForRotationDefault[portraitRotation] =
2702         mNavigationBarFrameHeightForRotationDefault[upsideDownRotation] =
2703                 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
2704         mNavigationBarFrameHeightForRotationDefault[landscapeRotation] =
2705         mNavigationBarFrameHeightForRotationDefault[seascapeRotation] =
2706                 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height_landscape);
2707 
2708         // Width of the navigation bar when presented vertically along one side
2709         mNavigationBarWidthForRotationDefault[portraitRotation] =
2710         mNavigationBarWidthForRotationDefault[upsideDownRotation] =
2711         mNavigationBarWidthForRotationDefault[landscapeRotation] =
2712         mNavigationBarWidthForRotationDefault[seascapeRotation] =
2713                 res.getDimensionPixelSize(R.dimen.navigation_bar_width);
2714 
2715         if (ALTERNATE_CAR_MODE_NAV_SIZE) {
2716             // Height of the navigation bar when presented horizontally at bottom
2717             mNavigationBarHeightForRotationInCarMode[portraitRotation] =
2718             mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
2719                     res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
2720             mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
2721             mNavigationBarHeightForRotationInCarMode[seascapeRotation] =
2722                     res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode);
2723 
2724             // Width of the navigation bar when presented vertically along one side
2725             mNavigationBarWidthForRotationInCarMode[portraitRotation] =
2726             mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
2727             mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
2728             mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
2729                     res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
2730         }
2731 
2732         mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
2733         mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset);
2734         mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
2735         mNavigationBarAlwaysShowOnSideGesture =
2736                 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
2737 
2738         // This should calculate how much above the frame we accept gestures.
2739         mBottomGestureAdditionalInset =
2740                 res.getDimensionPixelSize(R.dimen.navigation_bar_gesture_height)
2741                         - getNavigationBarFrameHeight(portraitRotation, uiMode);
2742 
2743         updateConfigurationAndScreenSizeDependentBehaviors();
2744         mWindowOutsetBottom = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
2745     }
2746 
2747     void updateConfigurationAndScreenSizeDependentBehaviors() {
2748         final Resources res = getCurrentUserResources();
2749         mNavigationBarCanMove =
2750                 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
2751                         && res.getBoolean(R.bool.config_navBarCanMove);
2752         mAllowSeamlessRotationDespiteNavBarMoving =
2753                 res.getBoolean(R.bool.config_allowSeamlessRotationDespiteNavBarMoving);
2754     }
2755 
2756     /**
2757      * Updates the current user's resources to pick up any changes for the current user (including
2758      * overlay paths)
2759      */
2760     private void updateCurrentUserResources() {
2761         final int userId = mService.mAmInternal.getCurrentUserId();
2762         final Context uiContext = getSystemUiContext();
2763 
2764         if (userId == UserHandle.USER_SYSTEM) {
2765             // Skip the (expensive) recreation of resources for the system user below and just
2766             // use the resources from the system ui context
2767             mCurrentUserResources = uiContext.getResources();
2768             return;
2769         }
2770 
2771         // For non-system users, ensure that the resources are loaded from the current
2772         // user's package info (see ContextImpl.createDisplayContext)
2773         final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
2774                 uiContext.getPackageName(), null, 0, userId);
2775         mCurrentUserResources = ResourcesManager.getInstance().getResources(null,
2776                 pi.getResDir(),
2777                 null /* splitResDirs */,
2778                 pi.getOverlayDirs(),
2779                 pi.getApplicationInfo().sharedLibraryFiles,
2780                 mDisplayContent.getDisplayId(),
2781                 null /* overrideConfig */,
2782                 uiContext.getResources().getCompatibilityInfo(),
2783                 null /* classLoader */);
2784     }
2785 
2786     @VisibleForTesting
2787     Resources getCurrentUserResources() {
2788         if (mCurrentUserResources == null) {
2789             updateCurrentUserResources();
2790         }
2791         return mCurrentUserResources;
2792     }
2793 
2794     @VisibleForTesting
2795     Context getContext() {
2796         return mContext;
2797     }
2798 
2799     private Context getSystemUiContext() {
2800         final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
2801         return mDisplayContent.isDefaultDisplay
2802                 ? uiContext : uiContext.createDisplayContext(mDisplayContent.getDisplay());
2803     }
2804 
2805     private int getNavigationBarWidth(int rotation, int uiMode) {
2806         if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2807             return mNavigationBarWidthForRotationInCarMode[rotation];
2808         } else {
2809             return mNavigationBarWidthForRotationDefault[rotation];
2810         }
2811     }
2812 
2813     void notifyDisplayReady() {
2814         mHandler.post(() -> {
2815             final int displayId = getDisplayId();
2816             getStatusBarManagerInternal().onDisplayReady(displayId);
2817             final WallpaperManagerInternal wpMgr = LocalServices
2818                     .getService(WallpaperManagerInternal.class);
2819             if (wpMgr != null) {
2820                 wpMgr.onDisplayReady(displayId);
2821             }
2822         });
2823     }
2824 
2825     /**
2826      * Return the display width available after excluding any screen
2827      * decorations that could never be removed in Honeycomb. That is, system bar or
2828      * button bar.
2829      */
getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, DisplayCutout displayCutout)2830     public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2831             DisplayCutout displayCutout) {
2832         int width = fullWidth;
2833         if (hasNavigationBar()) {
2834             final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2835             if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
2836                 width -= getNavigationBarWidth(rotation, uiMode);
2837             }
2838         }
2839         if (displayCutout != null) {
2840             width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
2841         }
2842         return width;
2843     }
2844 
getNavigationBarHeight(int rotation, int uiMode)2845     private int getNavigationBarHeight(int rotation, int uiMode) {
2846         if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2847             return mNavigationBarHeightForRotationInCarMode[rotation];
2848         } else {
2849             return mNavigationBarHeightForRotationDefault[rotation];
2850         }
2851     }
2852 
2853     /**
2854      * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that
2855      * is used for spacing to show additional buttons on the navigation bar (such as the ime
2856      * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible
2857      * height that we send to the app as content insets that can be smaller.
2858      * <p>
2859      * In car mode it will return the same height as {@link #getNavigationBarHeight}
2860      *
2861      * @param rotation specifies rotation to return dimension from
2862      * @param uiMode to determine if in car mode
2863      * @return navigation bar frame height
2864      */
getNavigationBarFrameHeight(int rotation, int uiMode)2865     private int getNavigationBarFrameHeight(int rotation, int uiMode) {
2866         if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2867             return mNavigationBarHeightForRotationInCarMode[rotation];
2868         } else {
2869             return mNavigationBarFrameHeightForRotationDefault[rotation];
2870         }
2871     }
2872 
2873     /**
2874      * Return the display height available after excluding any screen
2875      * decorations that could never be removed in Honeycomb. That is, system bar or
2876      * button bar.
2877      */
getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, DisplayCutout displayCutout)2878     public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2879             DisplayCutout displayCutout) {
2880         int height = fullHeight;
2881         if (hasNavigationBar()) {
2882             final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2883             if (navBarPosition == NAV_BAR_BOTTOM) {
2884                 height -= getNavigationBarHeight(rotation, uiMode);
2885             }
2886         }
2887         if (displayCutout != null) {
2888             height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
2889         }
2890         return height;
2891     }
2892 
2893     /**
2894      * Return the available screen width that we should report for the
2895      * configuration.  This must be no larger than
2896      * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller
2897      * than that to account for more transient decoration like a status bar.
2898      */
getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, DisplayCutout displayCutout)2899     public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2900             DisplayCutout displayCutout) {
2901         return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout);
2902     }
2903 
2904     /**
2905      * Return the available screen height that we should report for the
2906      * configuration.  This must be no larger than
2907      * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller
2908      * than that to account for more transient decoration like a status bar.
2909      */
getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, DisplayCutout displayCutout)2910     public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2911             DisplayCutout displayCutout) {
2912         // There is a separate status bar at the top of the display.  We don't count that as part
2913         // of the fixed decor, since it can hide; however, for purposes of configurations,
2914         // we do want to exclude it since applications can't generally use that part
2915         // of the screen.
2916         int statusBarHeight = mStatusBarHeightForRotation[rotation];
2917         if (displayCutout != null) {
2918             // If there is a cutout, it may already have accounted for some part of the status
2919             // bar height.
2920             statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
2921         }
2922         return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
2923                 - statusBarHeight;
2924     }
2925 
2926     /**
2927      * Return corner radius in pixels that should be used on windows in order to cover the display.
2928      * The radius is only valid for built-in displays since the one who configures window corner
2929      * radius cannot know the corner radius of non-built-in display.
2930      */
getWindowCornerRadius()2931     float getWindowCornerRadius() {
2932         return mDisplayContent.getDisplay().getType() == TYPE_BUILT_IN
2933                 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f;
2934     }
2935 
isShowingDreamLw()2936     boolean isShowingDreamLw() {
2937         return mShowingDream;
2938     }
2939 
2940     /**
2941      * Calculates the stable insets if we already have the non-decor insets.
2942      *
2943      * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
2944      * @param rotation The current display rotation.
2945      */
convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation)2946     void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
2947         inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
2948     }
2949 
2950     /**
2951      * Calculates the stable insets without running a layout.
2952      *
2953      * @param displayRotation the current display rotation
2954      * @param displayWidth the current display width
2955      * @param displayHeight the current display height
2956      * @param displayCutout the current display cutout
2957      * @param outInsets the insets to return
2958      */
getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight, DisplayCutout displayCutout, Rect outInsets)2959     public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2960             DisplayCutout displayCutout, Rect outInsets) {
2961         outInsets.setEmpty();
2962 
2963         // Navigation bar and status bar.
2964         getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
2965         convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
2966     }
2967 
2968     /**
2969      * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
2970      * bar or button bar. See {@link #getNonDecorDisplayWidth}.
2971      *
2972      * @param displayRotation the current display rotation
2973      * @param displayWidth the current display width
2974      * @param displayHeight the current display height
2975      * @param displayCutout the current display cutout
2976      * @param outInsets the insets to return
2977      */
getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight, DisplayCutout displayCutout, Rect outInsets)2978     public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2979             DisplayCutout displayCutout, Rect outInsets) {
2980         outInsets.setEmpty();
2981 
2982         // Only navigation bar
2983         if (hasNavigationBar()) {
2984             final int uiMode = mService.mPolicy.getUiMode();
2985             int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
2986             if (position == NAV_BAR_BOTTOM) {
2987                 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
2988             } else if (position == NAV_BAR_RIGHT) {
2989                 outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
2990             } else if (position == NAV_BAR_LEFT) {
2991                 outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
2992             }
2993         }
2994 
2995         if (displayCutout != null) {
2996             outInsets.left += displayCutout.getSafeInsetLeft();
2997             outInsets.top += displayCutout.getSafeInsetTop();
2998             outInsets.right += displayCutout.getSafeInsetRight();
2999             outInsets.bottom += displayCutout.getSafeInsetBottom();
3000         }
3001     }
3002 
3003     /**
3004      * @see IWindowManager#setForwardedInsets
3005      */
setForwardedInsets(@onNull Insets forwardedInsets)3006     public void setForwardedInsets(@NonNull Insets forwardedInsets) {
3007         mForwardedInsets = forwardedInsets;
3008     }
3009 
3010     @NonNull
getForwardedInsets()3011     public Insets getForwardedInsets() {
3012         return mForwardedInsets;
3013     }
3014 
3015     @NavigationBarPosition
navigationBarPosition(int displayWidth, int displayHeight, int displayRotation)3016     int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
3017         if (navigationBarCanMove() && displayWidth > displayHeight) {
3018             if (displayRotation == Surface.ROTATION_270) {
3019                 return NAV_BAR_LEFT;
3020             } else if (displayRotation == Surface.ROTATION_90) {
3021                 return NAV_BAR_RIGHT;
3022             }
3023         }
3024         return NAV_BAR_BOTTOM;
3025     }
3026 
3027     /**
3028      * @return The side of the screen where navigation bar is positioned.
3029      * @see WindowManagerPolicyConstants#NAV_BAR_LEFT
3030      * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT
3031      * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM
3032      */
3033     @NavigationBarPosition
getNavBarPosition()3034     public int getNavBarPosition() {
3035         return mNavigationBarPosition;
3036     }
3037 
3038     /**
3039      * A new window has been focused.
3040      */
focusChangedLw(WindowState lastFocus, WindowState newFocus)3041     public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
3042         mFocusedWindow = newFocus;
3043         mLastFocusedWindow = lastFocus;
3044         if (mDisplayContent.isDefaultDisplay) {
3045             mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
3046         }
3047         if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
3048             // If the navigation bar has been hidden or shown, we need to do another
3049             // layout pass to update that window.
3050             return FINISH_LAYOUT_REDO_LAYOUT;
3051         }
3052         return 0;
3053     }
3054 
3055     /**
3056      * Return true if it is okay to perform animations for an app transition
3057      * that is about to occur. You may return false for this if, for example,
3058      * the dream window is currently displayed so the switch should happen
3059      * immediately.
3060      */
allowAppAnimationsLw()3061     public boolean allowAppAnimationsLw() {
3062         return !mShowingDream;
3063     }
3064 
updateDreamingSleepToken(boolean acquire)3065     private void updateDreamingSleepToken(boolean acquire) {
3066         if (acquire) {
3067             final int displayId = getDisplayId();
3068             if (mDreamingSleepToken == null) {
3069                 mDreamingSleepToken = mService.mAtmInternal.acquireSleepToken(
3070                         "DreamOnDisplay" + displayId, displayId);
3071             }
3072         } else {
3073             if (mDreamingSleepToken != null) {
3074                 mDreamingSleepToken.release();
3075                 mDreamingSleepToken = null;
3076             }
3077         }
3078     }
3079 
requestTransientBars(WindowState swipeTarget)3080     private void requestTransientBars(WindowState swipeTarget) {
3081         synchronized (mLock) {
3082             if (!mService.mPolicy.isUserSetupComplete()) {
3083                 // Swipe-up for navigation bar is disabled during setup
3084                 return;
3085             }
3086             boolean sb = mStatusBarController.checkShowTransientBarLw();
3087             boolean nb = mNavigationBarController.checkShowTransientBarLw()
3088                     && !isNavBarEmpty(mLastSystemUiFlags);
3089             if (sb || nb) {
3090                 // Don't show status bar when swiping on already visible navigation bar
3091                 if (!nb && swipeTarget == mNavigationBar) {
3092                     if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
3093                     return;
3094                 }
3095                 if (sb) mStatusBarController.showTransient();
3096                 if (nb) mNavigationBarController.showTransient();
3097                 mImmersiveModeConfirmation.confirmCurrentPrompt();
3098                 updateSystemUiVisibilityLw();
3099             }
3100         }
3101     }
3102 
disposeInputConsumer(InputConsumer inputConsumer)3103     private void disposeInputConsumer(InputConsumer inputConsumer) {
3104         if (inputConsumer != null) {
3105             inputConsumer.dismiss();
3106         }
3107     }
3108 
isStatusBarKeyguard()3109     private boolean isStatusBarKeyguard() {
3110         return mStatusBar != null
3111                 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
3112     }
3113 
isKeyguardOccluded()3114     private boolean isKeyguardOccluded() {
3115         // TODO (b/113840485): Handle per display keyguard.
3116         return mService.mPolicy.isKeyguardOccluded();
3117     }
3118 
resetSystemUiVisibilityLw()3119     void resetSystemUiVisibilityLw() {
3120         mLastSystemUiFlags = 0;
3121         updateSystemUiVisibilityLw();
3122     }
3123 
updateSystemUiVisibilityLw()3124     private int updateSystemUiVisibilityLw() {
3125         // If there is no window focused, there will be nobody to handle the events
3126         // anyway, so just hang on in whatever state we're in until things settle down.
3127         WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
3128                 : mTopFullscreenOpaqueWindowState;
3129         if (winCandidate == null) {
3130             return 0;
3131         }
3132 
3133         // The immersive mode confirmation should never affect the system bar visibility, otherwise
3134         // it will unhide the navigation bar and hide itself.
3135         if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
3136 
3137             // The immersive mode confirmation took the focus from mLastFocusedWindow which was
3138             // controlling the system ui visibility. So if mLastFocusedWindow can still receive
3139             // keys, we let it keep controlling the visibility.
3140             final boolean lastFocusCanReceiveKeys =
3141                     (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
3142             winCandidate = isStatusBarKeyguard() ? mStatusBar
3143                     : lastFocusCanReceiveKeys ? mLastFocusedWindow
3144                             : mTopFullscreenOpaqueWindowState;
3145             if (winCandidate == null) {
3146                 return 0;
3147             }
3148         }
3149         final WindowState win = winCandidate;
3150         if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && isKeyguardOccluded()) {
3151             // We are updating at a point where the keyguard has gotten
3152             // focus, but we were last in a state where the top window is
3153             // hiding it.  This is probably because the keyguard as been
3154             // shown while the top window was displayed, so we want to ignore
3155             // it here because this is just a very transient change and it
3156             // will quickly lose focus once it correctly gets hidden.
3157             return 0;
3158         }
3159 
3160         mDisplayContent.getInsetsStateController().onBarControllingWindowChanged(
3161                 mTopFullscreenOpaqueWindowState);
3162 
3163         int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
3164                 & ~mResettingSystemUiFlags
3165                 & ~mForceClearedSystemUiFlags;
3166         if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
3167             tmpVisibility
3168                     &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
3169         }
3170 
3171         final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
3172                 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
3173         final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
3174                 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
3175         mService.getStackBounds(
3176                 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds);
3177         mService.getStackBounds(
3178                 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
3179         final Pair<Integer, Boolean> result =
3180                 updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
3181         final int visibility = result.first;
3182         final int diff = visibility ^ mLastSystemUiFlags;
3183         final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
3184         final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
3185         final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
3186         if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
3187                 && mFocusedApp == win.getAppToken()
3188                 && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
3189                 && mLastDockedStackBounds.equals(mDockedStackBounds)) {
3190             return 0;
3191         }
3192         mLastSystemUiFlags = visibility;
3193         mLastFullscreenStackSysUiFlags = fullscreenVisibility;
3194         mLastDockedStackSysUiFlags = dockedVisibility;
3195         mLastFocusNeedsMenu = needsMenu;
3196         mFocusedApp = win.getAppToken();
3197         mLastNonDockedStackBounds.set(mNonDockedStackBounds);
3198         mLastDockedStackBounds.set(mDockedStackBounds);
3199         final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
3200         final Rect dockedStackBounds = new Rect(mDockedStackBounds);
3201         final boolean isNavbarColorManagedByIme = result.second;
3202         mHandler.post(() -> {
3203             StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
3204             if (statusBar != null) {
3205                 final int displayId = getDisplayId();
3206                 statusBar.setSystemUiVisibility(displayId, visibility, fullscreenVisibility,
3207                         dockedVisibility, 0xffffffff, fullscreenStackBounds,
3208                         dockedStackBounds, isNavbarColorManagedByIme, win.toString());
3209                 statusBar.topAppWindowChanged(displayId, needsMenu);
3210             }
3211         });
3212         return diff;
3213     }
3214 
updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming)3215     private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
3216         final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded();
3217         final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming;
3218         if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
3219             // If the top fullscreen-or-dimming window is also the top fullscreen, respect
3220             // its light flag.
3221             vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3222             vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
3223                     & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3224         } else if (statusColorWin != null && statusColorWin.isDimming()) {
3225             // Otherwise if it's dimming, clear the light flag.
3226             vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3227         }
3228         return vis;
3229     }
3230 
3231     @VisibleForTesting
3232     @Nullable
chooseNavigationColorWindowLw(WindowState opaque, WindowState opaqueOrDimming, WindowState imeWindow, @NavigationBarPosition int navBarPosition)3233     static WindowState chooseNavigationColorWindowLw(WindowState opaque,
3234             WindowState opaqueOrDimming, WindowState imeWindow,
3235             @NavigationBarPosition int navBarPosition) {
3236         // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
3237         // window can be navigation color window.
3238         final boolean imeWindowCanNavColorWindow = imeWindow != null
3239                 && imeWindow.isVisibleLw()
3240                 && navBarPosition == NAV_BAR_BOTTOM
3241                 && (PolicyControl.getWindowFlags(imeWindow, null)
3242                 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3243 
3244         if (opaque != null && opaqueOrDimming == opaque) {
3245             // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
3246             // unless IME window is also eligible, since currently the IME window is always show
3247             // above the opaque fullscreen app window, regardless of the IME target window.
3248             // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
3249             return imeWindowCanNavColorWindow ? imeWindow : opaque;
3250         }
3251 
3252         if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
3253             // No dimming window is involved. Determine the result only with the IME window.
3254             return imeWindowCanNavColorWindow ? imeWindow : null;
3255         }
3256 
3257         if (!imeWindowCanNavColorWindow) {
3258             // No IME window is involved. Determine the result only with opaqueOrDimming.
3259             return opaqueOrDimming;
3260         }
3261 
3262         // The IME window and the dimming window are competing.  Check if the dimming window can be
3263         // IME target or not.
3264         if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
3265             // The IME window is above the dimming window.
3266             return imeWindow;
3267         } else {
3268             // The dimming window is above the IME window.
3269             return opaqueOrDimming;
3270         }
3271     }
3272 
3273     @VisibleForTesting
updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming, WindowState imeWindow, WindowState navColorWin)3274     static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
3275             WindowState imeWindow, WindowState navColorWin) {
3276 
3277         if (navColorWin != null) {
3278             if (navColorWin == imeWindow || navColorWin == opaque) {
3279                 // Respect the light flag.
3280                 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3281                 vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
3282                         & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3283             } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
3284                 // Clear the light flag for dimming window.
3285                 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3286             }
3287         }
3288         return vis;
3289     }
3290 
updateSystemBarsLw(WindowState win, int oldVis, int vis)3291     private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
3292         final boolean dockedStackVisible =
3293                 mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
3294         final boolean freeformStackVisible =
3295                 mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
3296         final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
3297 
3298         // We need to force system bars when the docked stack is visible, when the freeform stack
3299         // is visible but also when we are resizing for the transitions when docked stack
3300         // visibility changes.
3301         mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing
3302                 || mForceShowSystemBarsFromExternal;
3303         final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
3304 
3305         // apply translucent bar vis flags
3306         WindowState fullscreenTransWin = isStatusBarKeyguard() && !isKeyguardOccluded()
3307                 ? mStatusBar
3308                 : mTopFullscreenOpaqueWindowState;
3309         vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3310         vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3311         int dockedVis = mStatusBarController.applyTranslucentFlagLw(
3312                 mTopDockedOpaqueWindowState, 0, 0);
3313         dockedVis = mNavigationBarController.applyTranslucentFlagLw(
3314                 mTopDockedOpaqueWindowState, dockedVis, 0);
3315 
3316         final boolean fullscreenDrawsStatusBarBackground =
3317                 drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
3318         final boolean dockedDrawsStatusBarBackground =
3319                 drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
3320         final boolean fullscreenDrawsNavBarBackground =
3321                 drawsNavigationBarBackground(vis, mTopFullscreenOpaqueWindowState);
3322         final boolean dockedDrawsNavigationBarBackground =
3323                 drawsNavigationBarBackground(dockedVis, mTopDockedOpaqueWindowState);
3324 
3325         // prevent status bar interaction from clearing certain flags
3326         int type = win.getAttrs().type;
3327         boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
3328         if (statusBarHasFocus && !isStatusBarKeyguard()) {
3329             int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
3330                     | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
3331                     | View.SYSTEM_UI_FLAG_IMMERSIVE
3332                     | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
3333                     | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3334             if (isKeyguardOccluded()) {
3335                 flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
3336             }
3337             vis = (vis & ~flags) | (oldVis & flags);
3338         }
3339 
3340         if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
3341             vis |= View.STATUS_BAR_TRANSPARENT;
3342             vis &= ~View.STATUS_BAR_TRANSLUCENT;
3343         } else if (forceOpaqueStatusBar) {
3344             vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
3345         }
3346 
3347         vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing,
3348                 fullscreenDrawsNavBarBackground, dockedDrawsNavigationBarBackground);
3349 
3350         // update status bar
3351         boolean immersiveSticky =
3352                 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3353         final boolean hideStatusBarWM =
3354                 mTopFullscreenOpaqueWindowState != null
3355                         && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
3356                         & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
3357         final boolean hideStatusBarSysui =
3358                 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
3359         final boolean hideNavBarSysui =
3360                 (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
3361 
3362         final boolean transientStatusBarAllowed = mStatusBar != null
3363                 && (statusBarHasFocus || (!mForceShowSystemBars
3364                 && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
3365 
3366         final boolean transientNavBarAllowed = mNavigationBar != null
3367                 && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
3368 
3369         final long now = SystemClock.uptimeMillis();
3370         final boolean pendingPanic = mPendingPanicGestureUptime != 0
3371                 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
3372         final DisplayPolicy defaultDisplayPolicy =
3373                 mService.getDefaultDisplayContentLocked().getDisplayPolicy();
3374         if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard()
3375                 // TODO (b/111955725): Show keyguard presentation on all external displays
3376                 && defaultDisplayPolicy.isKeyguardDrawComplete()) {
3377             // The user performed the panic gesture recently, we're about to hide the bars,
3378             // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
3379             mPendingPanicGestureUptime = 0;
3380             mStatusBarController.showTransient();
3381             if (!isNavBarEmpty(vis)) {
3382                 mNavigationBarController.showTransient();
3383             }
3384         }
3385 
3386         final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
3387                 && !transientStatusBarAllowed && hideStatusBarSysui;
3388         final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
3389                 && !transientNavBarAllowed;
3390         if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
3391             // clear the clearable flags instead
3392             clearClearableFlagsLw();
3393             vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
3394         }
3395 
3396         final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
3397         immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3398         final boolean navAllowedHidden = immersive || immersiveSticky;
3399 
3400         if (hideNavBarSysui && !navAllowedHidden
3401                 && mService.mPolicy.getWindowLayerLw(win)
3402                         > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
3403             // We can't hide the navbar from this window otherwise the input consumer would not get
3404             // the input events.
3405             vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
3406         }
3407 
3408         vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
3409 
3410         // update navigation bar
3411         boolean oldImmersiveMode = isImmersiveMode(oldVis);
3412         boolean newImmersiveMode = isImmersiveMode(vis);
3413         if (oldImmersiveMode != newImmersiveMode) {
3414             final String pkg = win.getOwningPackage();
3415             mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
3416                     mService.mPolicy.isUserSetupComplete(),
3417                     isNavBarEmpty(win.getSystemUiVisibility()));
3418         }
3419 
3420         vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
3421 
3422         final WindowState navColorWin = chooseNavigationColorWindowLw(
3423                 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
3424                 mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
3425         vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
3426                 mTopFullscreenOpaqueOrDimmingWindowState,
3427                 mDisplayContent.mInputMethodWindow, navColorWin);
3428         // Navbar color is controlled by the IME.
3429         final boolean isManagedByIme =
3430                 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
3431 
3432         return Pair.create(vis, isManagedByIme);
3433     }
3434 
drawsBarBackground(int vis, WindowState win, BarController controller, int translucentFlag)3435     private boolean drawsBarBackground(int vis, WindowState win, BarController controller,
3436             int translucentFlag) {
3437         if (!controller.isTransparentAllowed(win)) {
3438             return false;
3439         }
3440         if (win == null) {
3441             return true;
3442         }
3443 
3444         final boolean drawsSystemBars =
3445                 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3446         final boolean forceDrawsSystemBars =
3447                 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
3448 
3449         return forceDrawsSystemBars || drawsSystemBars && (vis & translucentFlag) == 0;
3450     }
3451 
drawsStatusBarBackground(int vis, WindowState win)3452     private boolean drawsStatusBarBackground(int vis, WindowState win) {
3453         return drawsBarBackground(vis, win, mStatusBarController, FLAG_TRANSLUCENT_STATUS);
3454     }
3455 
drawsNavigationBarBackground(int vis, WindowState win)3456     private boolean drawsNavigationBarBackground(int vis, WindowState win) {
3457         return drawsBarBackground(vis, win, mNavigationBarController, FLAG_TRANSLUCENT_NAVIGATION);
3458     }
3459 
3460     /**
3461      * @return the current visibility flags with the nav-bar opacity related flags toggled based
3462      *         on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
3463      */
configureNavBarOpacity(int visibility, boolean dockedStackVisible, boolean freeformStackVisible, boolean isDockedDividerResizing, boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground)3464     private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
3465             boolean freeformStackVisible, boolean isDockedDividerResizing,
3466             boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground) {
3467         if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
3468             if (fullscreenDrawsBackground && dockedDrawsNavigationBarBackground) {
3469                 visibility = setNavBarTransparentFlag(visibility);
3470             } else if (dockedStackVisible) {
3471                 visibility = setNavBarOpaqueFlag(visibility);
3472             }
3473         } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
3474             if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
3475                 visibility = setNavBarOpaqueFlag(visibility);
3476             } else if (fullscreenDrawsBackground) {
3477                 visibility = setNavBarTransparentFlag(visibility);
3478             }
3479         } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
3480             if (isDockedDividerResizing) {
3481                 visibility = setNavBarOpaqueFlag(visibility);
3482             } else if (freeformStackVisible) {
3483                 visibility = setNavBarTranslucentFlag(visibility);
3484             } else {
3485                 visibility = setNavBarOpaqueFlag(visibility);
3486             }
3487         }
3488 
3489         return visibility;
3490     }
3491 
setNavBarOpaqueFlag(int visibility)3492     private int setNavBarOpaqueFlag(int visibility) {
3493         return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
3494     }
3495 
setNavBarTranslucentFlag(int visibility)3496     private int setNavBarTranslucentFlag(int visibility) {
3497         visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
3498         return visibility | View.NAVIGATION_BAR_TRANSLUCENT;
3499     }
3500 
setNavBarTransparentFlag(int visibility)3501     private int setNavBarTransparentFlag(int visibility) {
3502         visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
3503         return visibility | View.NAVIGATION_BAR_TRANSPARENT;
3504     }
3505 
clearClearableFlagsLw()3506     private void clearClearableFlagsLw() {
3507         int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
3508         if (newVal != mResettingSystemUiFlags) {
3509             mResettingSystemUiFlags = newVal;
3510             mDisplayContent.reevaluateStatusBarVisibility();
3511         }
3512     }
3513 
isImmersiveMode(int vis)3514     private boolean isImmersiveMode(int vis) {
3515         final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
3516         return mNavigationBar != null
3517                 && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
3518                 && (vis & flags) != 0
3519                 && canHideNavigationBar();
3520     }
3521 
3522     /**
3523      * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
3524      */
canHideNavigationBar()3525     private boolean canHideNavigationBar() {
3526         return hasNavigationBar();
3527     }
3528 
isNavBarEmpty(int systemUiFlags)3529     private static boolean isNavBarEmpty(int systemUiFlags) {
3530         final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
3531                 | View.STATUS_BAR_DISABLE_BACK
3532                 | View.STATUS_BAR_DISABLE_RECENT);
3533 
3534         return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
3535     }
3536 
shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation, int newRotation)3537     boolean shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation,
3538             int newRotation) {
3539         // For the upside down rotation we don't rotate seamlessly as the navigation
3540         // bar moves position.
3541         // Note most apps (using orientation:sensor or user as opposed to fullSensor)
3542         // will not enter the reverse portrait orientation, so actually the
3543         // orientation won't change at all.
3544         if (oldRotation == displayRotation.getUpsideDownRotation()
3545                 || newRotation == displayRotation.getUpsideDownRotation()) {
3546             return false;
3547         }
3548         // If the navigation bar can't change sides, then it will
3549         // jump when we change orientations and we don't rotate
3550         // seamlessly - unless that is allowed, eg. with gesture
3551         // navigation where the navbar is low-profile enough that this isn't very noticeable.
3552         if (!navigationBarCanMove() && !mAllowSeamlessRotationDespiteNavBarMoving) {
3553             return false;
3554         }
3555 
3556         final WindowState w = mTopFullscreenOpaqueWindowState;
3557         if (w == null || w != mFocusedWindow) {
3558             return false;
3559         }
3560         // If the bounds of activity window is different from its parent, then reject to be seamless
3561         // because the window position may change after rotation that will look like a sudden jump.
3562         if (w.mAppToken != null && !w.mAppToken.matchParentBounds()) {
3563             return false;
3564         }
3565 
3566         // We only enable seamless rotation if the top window has requested
3567         // it and is in the fullscreen opaque state. Seamless rotation
3568         // requires freezing various Surface states and won't work well
3569         // with animations, so we disable it in the animation case for now.
3570         if (!w.isAnimatingLw() && w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS) {
3571             return true;
3572         }
3573         return false;
3574     }
3575 
3576     private final Runnable mHiddenNavPanic = new Runnable() {
3577         @Override
3578         public void run() {
3579             synchronized (mLock) {
3580                 if (!mService.mPolicy.isUserSetupComplete()) {
3581                     // Swipe-up for navigation bar is disabled during setup
3582                     return;
3583                 }
3584                 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
3585                 if (!isNavBarEmpty(mLastSystemUiFlags)) {
3586                     mNavigationBarController.showTransient();
3587                 }
3588             }
3589         }
3590     };
3591 
onPowerKeyDown(boolean isScreenOn)3592     void onPowerKeyDown(boolean isScreenOn) {
3593         // Detect user pressing the power button in panic when an application has
3594         // taken over the whole screen.
3595         boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
3596                 SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
3597                 isNavBarEmpty(mLastSystemUiFlags));
3598         if (panic) {
3599             mHandler.post(mHiddenNavPanic);
3600         }
3601     }
3602 
onVrStateChangedLw(boolean enabled)3603     void onVrStateChangedLw(boolean enabled) {
3604         mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
3605     }
3606 
3607     /**
3608      * Called when the state of lock task mode changes. This should be used to disable immersive
3609      * mode confirmation.
3610      *
3611      * @param lockTaskState the new lock task mode state. One of
3612      *                      {@link ActivityManager#LOCK_TASK_MODE_NONE},
3613      *                      {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
3614      *                      {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
3615      */
onLockTaskStateChangedLw(int lockTaskState)3616     public void onLockTaskStateChangedLw(int lockTaskState) {
3617         mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
3618     }
3619 
3620     /**
3621      * Request a screenshot be taken.
3622      *
3623      * @param screenshotType The type of screenshot, for example either
3624      *                       {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
3625      *                       {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
3626      */
takeScreenshot(int screenshotType)3627     public void takeScreenshot(int screenshotType) {
3628         if (mScreenshotHelper != null) {
3629             mScreenshotHelper.takeScreenshot(screenshotType,
3630                     mStatusBar != null && mStatusBar.isVisibleLw(),
3631                     mNavigationBar != null && mNavigationBar.isVisibleLw(),
3632                     mHandler, null /* completionConsumer */);
3633         }
3634     }
3635 
getRefreshRatePolicy()3636     RefreshRatePolicy getRefreshRatePolicy() {
3637         return mRefreshRatePolicy;
3638     }
3639 
dump(String prefix, PrintWriter pw)3640     void dump(String prefix, PrintWriter pw) {
3641         pw.print(prefix); pw.print("DisplayPolicy");
3642         prefix += "  ";
3643         pw.print(prefix);
3644         pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
3645         pw.print(" mDeskDockEnablesAccelerometer=");
3646         pw.println(mDeskDockEnablesAccelerometer);
3647         pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
3648         pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
3649         pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
3650         pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
3651         pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
3652         pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
3653         pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
3654         pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
3655         if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
3656                 || mForceClearedSystemUiFlags != 0) {
3657             pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
3658             pw.print(Integer.toHexString(mLastSystemUiFlags));
3659             pw.print(" mResettingSystemUiFlags=0x");
3660             pw.print(Integer.toHexString(mResettingSystemUiFlags));
3661             pw.print(" mForceClearedSystemUiFlags=0x");
3662             pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
3663         }
3664         if (mLastFocusNeedsMenu) {
3665             pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu);
3666         }
3667         pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
3668         pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
3669         pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
3670         if (mStatusBar != null) {
3671             pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
3672                     pw.print(" isStatusBarKeyguard="); pw.println(isStatusBarKeyguard());
3673         }
3674         if (mNavigationBar != null) {
3675             pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
3676             pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
3677             pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove);
3678             pw.print(prefix); pw.print("mNavigationBarPosition=");
3679             pw.println(mNavigationBarPosition);
3680         }
3681         if (mFocusedWindow != null) {
3682             pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
3683         }
3684         if (mFocusedApp != null) {
3685             pw.print(prefix); pw.print("mFocusedApp="); pw.println(mFocusedApp);
3686         }
3687         if (mTopFullscreenOpaqueWindowState != null) {
3688             pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
3689             pw.println(mTopFullscreenOpaqueWindowState);
3690         }
3691         if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
3692             pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
3693             pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
3694         }
3695         if (mForcingShowNavBar) {
3696             pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar);
3697             pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
3698             pw.println(mForcingShowNavBarLayer);
3699         }
3700         pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
3701         pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
3702         pw.print(" mForceStatusBarFromKeyguard="); pw.println(mForceStatusBarFromKeyguard);
3703         pw.print(" mForceShowSystemBarsFromExternal=");
3704         pw.println(mForceShowSystemBarsFromExternal);
3705         pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
3706         mStatusBarController.dump(pw, prefix);
3707         mNavigationBarController.dump(pw, prefix);
3708 
3709         pw.print(prefix); pw.println("Looper state:");
3710         mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + "  ");
3711     }
3712 
supportsPointerLocation()3713     private boolean supportsPointerLocation() {
3714         return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate();
3715     }
3716 
setPointerLocationEnabled(boolean pointerLocationEnabled)3717     void setPointerLocationEnabled(boolean pointerLocationEnabled) {
3718         if (!supportsPointerLocation()) {
3719             return;
3720         }
3721 
3722         mHandler.sendEmptyMessage(pointerLocationEnabled
3723                 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
3724     }
3725 
enablePointerLocation()3726     private void enablePointerLocation() {
3727         if (mPointerLocationView != null) {
3728             return;
3729         }
3730 
3731         mPointerLocationView = new PointerLocationView(mContext);
3732         mPointerLocationView.setPrintCoords(false);
3733         final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
3734                 WindowManager.LayoutParams.MATCH_PARENT,
3735                 WindowManager.LayoutParams.MATCH_PARENT);
3736         lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
3737         lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
3738                 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
3739                 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
3740                 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
3741         lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3742         if (ActivityManager.isHighEndGfx()) {
3743             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
3744             lp.privateFlags |=
3745                     WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
3746         }
3747         lp.format = PixelFormat.TRANSLUCENT;
3748         lp.setTitle("PointerLocation - display " + getDisplayId());
3749         lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
3750         final WindowManager wm = mContext.getSystemService(WindowManager.class);
3751         wm.addView(mPointerLocationView, lp);
3752         mDisplayContent.registerPointerEventListener(mPointerLocationView);
3753     }
3754 
disablePointerLocation()3755     private void disablePointerLocation() {
3756         if (mPointerLocationView == null) {
3757             return;
3758         }
3759 
3760         mDisplayContent.unregisterPointerEventListener(mPointerLocationView);
3761         final WindowManager wm = mContext.getSystemService(WindowManager.class);
3762         wm.removeView(mPointerLocationView);
3763         mPointerLocationView = null;
3764     }
3765 }
3766