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