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