• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wm;
18 
19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
25 import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
26 import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
27 import static android.util.RotationUtils.deltaRotation;
28 import static android.util.RotationUtils.rotateBounds;
29 import static android.view.Display.TYPE_INTERNAL;
30 import static android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES;
31 import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
32 import static android.view.InsetsState.ITYPE_CAPTION_BAR;
33 import static android.view.InsetsState.ITYPE_CLIMATE_BAR;
34 import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR;
35 import static android.view.InsetsState.ITYPE_IME;
36 import static android.view.InsetsState.ITYPE_LEFT_GESTURES;
37 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
38 import static android.view.InsetsState.ITYPE_RIGHT_GESTURES;
39 import static android.view.InsetsState.ITYPE_STATUS_BAR;
40 import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES;
41 import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT;
42 import static android.view.ViewRootImpl.computeWindowBounds;
43 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
44 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
45 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
46 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
47 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
48 import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS;
49 import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS;
50 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
51 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
52 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
53 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
54 import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
55 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
56 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
57 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
58 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
59 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
60 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
61 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
62 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
63 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
64 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME;
65 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
66 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
67 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
68 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
69 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
70 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
71 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
72 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
73 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
74 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
75 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
76 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
77 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
78 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
79 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
80 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
81 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
82 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
83 import static android.view.WindowManagerGlobal.ADD_OKAY;
84 import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
85 import static android.view.WindowManagerPolicyConstants.ALT_BAR_BOTTOM;
86 import static android.view.WindowManagerPolicyConstants.ALT_BAR_LEFT;
87 import static android.view.WindowManagerPolicyConstants.ALT_BAR_RIGHT;
88 import static android.view.WindowManagerPolicyConstants.ALT_BAR_TOP;
89 import static android.view.WindowManagerPolicyConstants.ALT_BAR_UNKNOWN;
90 import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE;
91 import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
92 import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
93 import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
94 import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
95 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
96 
97 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
98 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
99 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
100 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
101 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
102 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE;
103 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
104 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW;
105 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
106 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
107 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
108 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
109 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
110 
111 import android.Manifest.permission;
112 import android.annotation.NonNull;
113 import android.annotation.Nullable;
114 import android.annotation.Px;
115 import android.app.ActivityManager;
116 import android.app.ActivityThread;
117 import android.app.LoadedApk;
118 import android.app.ResourcesManager;
119 import android.content.Context;
120 import android.content.Intent;
121 import android.content.pm.PackageManager;
122 import android.content.res.Resources;
123 import android.graphics.Insets;
124 import android.graphics.PixelFormat;
125 import android.graphics.Rect;
126 import android.graphics.Region;
127 import android.hardware.power.Boost;
128 import android.os.Handler;
129 import android.os.IBinder;
130 import android.os.Looper;
131 import android.os.Message;
132 import android.os.SystemClock;
133 import android.os.SystemProperties;
134 import android.os.UserHandle;
135 import android.util.PrintWriterPrinter;
136 import android.util.Slog;
137 import android.util.SparseArray;
138 import android.view.DisplayCutout;
139 import android.view.DisplayInfo;
140 import android.view.Gravity;
141 import android.view.InsetsFlags;
142 import android.view.InsetsSource;
143 import android.view.InsetsState;
144 import android.view.InsetsState.InternalInsetsType;
145 import android.view.Surface;
146 import android.view.View;
147 import android.view.ViewDebug;
148 import android.view.WindowInsets.Type;
149 import android.view.WindowInsets.Type.InsetsType;
150 import android.view.WindowManager;
151 import android.view.WindowManager.LayoutParams;
152 import android.view.WindowManagerGlobal;
153 import android.view.WindowManagerPolicyConstants;
154 import android.view.accessibility.AccessibilityManager;
155 
156 import com.android.internal.R;
157 import com.android.internal.annotations.VisibleForTesting;
158 import com.android.internal.policy.GestureNavigationSettingsObserver;
159 import com.android.internal.policy.ScreenDecorationsUtils;
160 import com.android.internal.protolog.common.ProtoLog;
161 import com.android.internal.util.ScreenshotHelper;
162 import com.android.internal.util.function.TriConsumer;
163 import com.android.internal.view.AppearanceRegion;
164 import com.android.internal.widget.PointerLocationView;
165 import com.android.server.LocalServices;
166 import com.android.server.UiThread;
167 import com.android.server.policy.WindowManagerPolicy;
168 import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition;
169 import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
170 import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
171 import com.android.server.statusbar.StatusBarManagerInternal;
172 import com.android.server.wallpaper.WallpaperManagerInternal;
173 import com.android.server.wm.InputMonitor.EventReceiverInputConsumer;
174 
175 import java.io.PrintWriter;
176 import java.util.function.Consumer;
177 
178 /**
179  * The policy that provides the basic behaviors and states of a display to show UI.
180  */
181 public class DisplayPolicy {
182     private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM;
183 
184     private static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
185 
186     // The panic gesture may become active only after the keyguard is dismissed and the immersive
187     // app shows again. If that doesn't happen for 30s we drop the gesture.
188     private static final long PANIC_GESTURE_EXPIRATION = 30000;
189 
190     // Controls navigation bar opacity depending on which workspace root tasks are currently
191     // visible.
192     // Nav bar is always opaque when either the freeform root task or docked root task is visible.
193     private static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0;
194     // Nav bar is always translucent when the freeform rootTask is visible, otherwise always opaque.
195     private static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
196     // Nav bar is never forced opaque.
197     private static final int NAV_BAR_FORCE_TRANSPARENT = 2;
198 
199     /** Don't apply window animation (see {@link #selectAnimation}). */
200     static final int ANIMATION_NONE = -1;
201     /** Use the transit animation in style resource (see {@link #selectAnimation}). */
202     static final int ANIMATION_STYLEABLE = 0;
203 
204     private static final int[] SHOW_TYPES_FOR_SWIPE = {ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR,
205             ITYPE_CLIMATE_BAR, ITYPE_EXTRA_NAVIGATION_BAR};
206     private static final int[] SHOW_TYPES_FOR_PANIC = {ITYPE_NAVIGATION_BAR};
207 
208     private final WindowManagerService mService;
209     private final Context mContext;
210     private final Context mUiContext;
211     private final DisplayContent mDisplayContent;
212     private final Object mLock;
213     private final Handler mHandler;
214 
215     private Resources mCurrentUserResources;
216 
217     private final boolean mCarDockEnablesAccelerometer;
218     private final boolean mDeskDockEnablesAccelerometer;
219     private final AccessibilityManager mAccessibilityManager;
220     private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
221     private final ScreenshotHelper mScreenshotHelper;
222 
223     private final Object mServiceAcquireLock = new Object();
224     private StatusBarManagerInternal mStatusBarManagerInternal;
225 
226     @Px
227     private int mBottomGestureAdditionalInset;
228     @Px
229     private int mLeftGestureInset;
230     @Px
231     private int mRightGestureInset;
232 
233     private boolean mNavButtonForcedVisible;
234 
getStatusBarManagerInternal()235     StatusBarManagerInternal getStatusBarManagerInternal() {
236         synchronized (mServiceAcquireLock) {
237             if (mStatusBarManagerInternal == null) {
238                 mStatusBarManagerInternal =
239                         LocalServices.getService(StatusBarManagerInternal.class);
240             }
241             return mStatusBarManagerInternal;
242         }
243     }
244 
245     private final SystemGesturesPointerEventListener mSystemGestures;
246 
247     private volatile int mLidState = LID_ABSENT;
248     private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
249     private volatile boolean mHdmiPlugged;
250 
251     private volatile boolean mHasStatusBar;
252     private volatile boolean mHasNavigationBar;
253     // Can the navigation bar ever move to the side?
254     private volatile boolean mNavigationBarCanMove;
255     private volatile boolean mNavigationBarLetsThroughTaps;
256     private volatile boolean mNavigationBarAlwaysShowOnSideGesture;
257 
258     // Written by vr manager thread, only read in this class.
259     private volatile boolean mPersistentVrModeEnabled;
260 
261     private volatile boolean mAwake;
262     private volatile boolean mScreenOnEarly;
263     private volatile boolean mScreenOnFully;
264     private volatile ScreenOnListener mScreenOnListener;
265 
266     private volatile boolean mKeyguardDrawComplete;
267     private volatile boolean mWindowManagerDrawComplete;
268 
269     private WindowState mStatusBar = null;
270     private WindowState mNotificationShade = null;
271     private final int[] mStatusBarHeightForRotation = new int[4];
272     private WindowState mNavigationBar = null;
273     @NavigationBarPosition
274     private int mNavigationBarPosition = NAV_BAR_BOTTOM;
275     private int[] mNavigationBarHeightForRotationDefault = new int[4];
276     private int[] mNavigationBarWidthForRotationDefault = new int[4];
277     private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
278     private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
279 
280     // Alternative status bar for when flexible insets mapping is used to place the status bar on
281     // another side of the screen.
282     private WindowState mStatusBarAlt = null;
283     @WindowManagerPolicy.AltBarPosition
284     private int mStatusBarAltPosition = ALT_BAR_UNKNOWN;
285     // Alternative navigation bar for when flexible insets mapping is used to place the navigation
286     // bar elsewhere on the screen.
287     private WindowState mNavigationBarAlt = null;
288     @WindowManagerPolicy.AltBarPosition
289     private int mNavigationBarAltPosition = ALT_BAR_UNKNOWN;
290     // Alternative climate bar for when flexible insets mapping is used to place a climate bar on
291     // the screen.
292     private WindowState mClimateBarAlt = null;
293     @WindowManagerPolicy.AltBarPosition
294     private int mClimateBarAltPosition = ALT_BAR_UNKNOWN;
295     // Alternative extra nav bar for when flexible insets mapping is used to place an extra nav bar
296     // on the screen.
297     private WindowState mExtraNavBarAlt = null;
298     @WindowManagerPolicy.AltBarPosition
299     private int mExtraNavBarAltPosition = ALT_BAR_UNKNOWN;
300 
301     /** See {@link #getNavigationBarFrameHeight} */
302     private int[] mNavigationBarFrameHeightForRotationDefault = new int[4];
303 
304     private boolean mIsFreeformWindowOverlappingWithNavBar;
305 
306     private boolean mLastImmersiveMode;
307 
308     private final SparseArray<Rect> mBarContentFrames = new SparseArray<>();
309 
310     // The windows we were told about in focusChanged.
311     private WindowState mFocusedWindow;
312     private WindowState mLastFocusedWindow;
313 
314     private WindowState mSystemUiControllingWindow;
315 
316     private int mLastDisableFlags;
317     private int mLastAppearance;
318     private int mLastFullscreenAppearance;
319     private int mLastDockedAppearance;
320     private int mLastBehavior;
321     private final Rect mNonDockedRootTaskBounds = new Rect();
322     private final Rect mDockedRootTaskBounds = new Rect();
323     private final Rect mLastNonDockedRootTaskBounds = new Rect();
324     private final Rect mLastDockedRootTaskBounds = new Rect();
325 
326     // What we last reported to system UI about whether the focused window is fullscreen/immersive.
327     private boolean mLastFocusIsFullscreen = false;
328 
329     // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
330     private long mPendingPanicGestureUptime;
331 
332     private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
333     private static final Rect sTmpRect = new Rect();
334     private static final Rect sTmpNavFrame = new Rect();
335     private static final Rect sTmpStatusFrame = new Rect();
336     private static final Rect sTmpScreenDecorFrame = new Rect();
337     private static final Rect sTmpLastParentFrame = new Rect();
338     private static final Rect sTmpDisplayFrameBounds = new Rect();
339 
340     private WindowState mTopFullscreenOpaqueWindowState;
341     private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
342     private WindowState mTopDockedOpaqueWindowState;
343     private WindowState mTopDockedOpaqueOrDimmingWindowState;
344     private boolean mTopIsFullscreen;
345     private boolean mForceStatusBar;
346     private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
347     private boolean mForcingShowNavBar;
348     private int mForcingShowNavBarLayer;
349     private boolean mForceShowSystemBars;
350 
351     private boolean mShowingDream;
352     private boolean mLastShowingDream;
353     private boolean mDreamingLockscreen;
354     private boolean mAllowLockscreenWhenOn;
355 
356     private PointerLocationView mPointerLocationView;
357 
358     /**
359      * The area covered by system windows which belong to another display. Forwarded insets is set
360      * in case this is a virtual display, this is displayed on another display that has insets, and
361      * the bounds of this display is overlapping with the insets of the host display (e.g. IME is
362      * displayed on the host display, and it covers a part of this virtual display.)
363      * The forwarded insets is used to compute display frames of this virtual display, which will
364      * be then used to layout windows in the virtual display.
365      */
366     @NonNull private Insets mForwardedInsets = Insets.NONE;
367 
368     private RefreshRatePolicy mRefreshRatePolicy;
369 
370     /**
371      * If true, attach the navigation bar to the current transition app.
372      * The value is read from config_attachNavBarToAppDuringTransition and could be overlaid by RRO
373      * when the navigation bar mode is changed.
374      */
375     private boolean mShouldAttachNavBarToAppDuringTransition;
376 
377     // -------- PolicyHandler --------
378     private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
379     private static final int MSG_DISPOSE_INPUT_CONSUMER = 3;
380     private static final int MSG_ENABLE_POINTER_LOCATION = 4;
381     private static final int MSG_DISABLE_POINTER_LOCATION = 5;
382 
383     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
384     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
385 
386     private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
387 
388     private final WindowManagerInternal.AppTransitionListener mAppTransitionListener;
389 
390     private class PolicyHandler extends Handler {
391 
PolicyHandler(Looper looper)392         PolicyHandler(Looper looper) {
393             super(looper);
394         }
395 
396         @Override
handleMessage(Message msg)397         public void handleMessage(Message msg) {
398             switch (msg.what) {
399                 case MSG_REQUEST_TRANSIENT_BARS:
400                     synchronized (mLock) {
401                         WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
402                                 ? getStatusBar() : getNavigationBar();
403                         if (targetBar != null) {
404                             requestTransientBars(targetBar);
405                         }
406                     }
407                     break;
408                 case MSG_DISPOSE_INPUT_CONSUMER:
409                     disposeInputConsumer((EventReceiverInputConsumer) msg.obj);
410                     break;
411                 case MSG_ENABLE_POINTER_LOCATION:
412                     enablePointerLocation();
413                     break;
414                 case MSG_DISABLE_POINTER_LOCATION:
415                     disablePointerLocation();
416                     break;
417             }
418         }
419     }
420 
DisplayPolicy(WindowManagerService service, DisplayContent displayContent)421     DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
422         mService = service;
423         mContext = displayContent.isDefaultDisplay ? service.mContext
424                 : service.mContext.createDisplayContext(displayContent.getDisplay());
425         mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.mUiContext
426                 : service.mAtmService.mSystemThread
427                         .createSystemUiContext(displayContent.getDisplayId());
428         mDisplayContent = displayContent;
429         mLock = service.getWindowManagerLock();
430 
431         final int displayId = displayContent.getDisplayId();
432 
433         mBarContentFrames.put(TYPE_STATUS_BAR, new Rect());
434         mBarContentFrames.put(TYPE_NAVIGATION_BAR, new Rect());
435 
436         final Resources r = mContext.getResources();
437         mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
438         mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
439 
440         mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
441                 Context.ACCESSIBILITY_SERVICE);
442         if (!displayContent.isDefaultDisplay) {
443             mAwake = true;
444             mScreenOnEarly = true;
445             mScreenOnFully = true;
446         }
447 
448         final Looper looper = UiThread.getHandler().getLooper();
449         mHandler = new PolicyHandler(looper);
450         // TODO(b/181821798) Migrate SystemGesturesPointerEventListener to use window context.
451         mSystemGestures = new SystemGesturesPointerEventListener(mUiContext, mHandler,
452                 new SystemGesturesPointerEventListener.Callbacks() {
453                     @Override
454                     public void onSwipeFromTop() {
455                         synchronized (mLock) {
456                             if (mStatusBar != null) {
457                                 requestTransientBars(mStatusBar);
458                             }
459                             checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
460                         }
461                     }
462 
463                     @Override
464                     public void onSwipeFromBottom() {
465                         synchronized (mLock) {
466                             if (mNavigationBar != null
467                                     && mNavigationBarPosition == NAV_BAR_BOTTOM) {
468                                 requestTransientBars(mNavigationBar);
469                             }
470                             checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
471                         }
472                     }
473 
474                     @Override
475                     public void onSwipeFromRight() {
476                         final Region excludedRegion = Region.obtain();
477                         synchronized (mLock) {
478                             mDisplayContent.calculateSystemGestureExclusion(
479                                     excludedRegion, null /* outUnrestricted */);
480                             final boolean excluded =
481                                     mSystemGestures.currentGestureStartedInRegion(excludedRegion);
482                             if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT
483                                     || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
484                                 requestTransientBars(mNavigationBar);
485                             }
486                             checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
487                         }
488                         excludedRegion.recycle();
489                     }
490 
491                     @Override
492                     public void onSwipeFromLeft() {
493                         final Region excludedRegion = Region.obtain();
494                         synchronized (mLock) {
495                             mDisplayContent.calculateSystemGestureExclusion(
496                                     excludedRegion, null /* outUnrestricted */);
497                             final boolean excluded =
498                                     mSystemGestures.currentGestureStartedInRegion(excludedRegion);
499                             if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT
500                                     || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
501                                 requestTransientBars(mNavigationBar);
502                             }
503                             checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
504                         }
505                         excludedRegion.recycle();
506                     }
507 
508                     @Override
509                     public void onFling(int duration) {
510                         if (mService.mPowerManagerInternal != null) {
511                             mService.mPowerManagerInternal.setPowerBoost(
512                                     Boost.INTERACTION, duration);
513                         }
514                     }
515 
516                     @Override
517                     public void onDebug() {
518                         // no-op
519                     }
520 
521                     private WindowOrientationListener getOrientationListener() {
522                         final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
523                         return rotation != null ? rotation.getOrientationListener() : null;
524                     }
525 
526                     @Override
527                     public void onDown() {
528                         final WindowOrientationListener listener = getOrientationListener();
529                         if (listener != null) {
530                             listener.onTouchStart();
531                         }
532                     }
533 
534                     @Override
535                     public void onUpOrCancel() {
536                         final WindowOrientationListener listener = getOrientationListener();
537                         if (listener != null) {
538                             listener.onTouchEnd();
539                         }
540                     }
541 
542                     @Override
543                     public void onMouseHoverAtTop() {
544                         mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
545                         Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
546                         msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
547                         mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
548                     }
549 
550                     @Override
551                     public void onMouseHoverAtBottom() {
552                         mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
553                         Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
554                         msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
555                         mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
556                     }
557 
558                     @Override
559                     public void onMouseLeaveFromEdge() {
560                         mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
561                     }
562                 });
563         displayContent.registerPointerEventListener(mSystemGestures);
564         mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() {
565 
566             private Runnable mAppTransitionPending = () -> {
567                 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
568                 if (statusBar != null) {
569                     statusBar.appTransitionPending(displayId);
570                 }
571             };
572 
573             private Runnable mAppTransitionCancelled = () -> {
574                 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
575                 if (statusBar != null) {
576                     statusBar.appTransitionCancelled(displayId);
577                 }
578             };
579 
580             private Runnable mAppTransitionFinished = () -> {
581                 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
582                 if (statusBar != null) {
583                     statusBar.appTransitionFinished(displayId);
584                 }
585             };
586 
587             @Override
588             public void onAppTransitionPendingLocked() {
589                 mHandler.post(mAppTransitionPending);
590             }
591 
592             @Override
593             public int onAppTransitionStartingLocked(boolean keyguardGoingAway, long duration,
594                     long statusBarAnimationStartTime, long statusBarAnimationDuration) {
595                 mHandler.post(() -> {
596                     StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
597                     if (statusBar != null) {
598                         statusBar.appTransitionStarting(mContext.getDisplayId(),
599                                 statusBarAnimationStartTime, statusBarAnimationDuration);
600                     }
601                 });
602                 return 0;
603             }
604 
605             @Override
606             public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) {
607                 mHandler.post(mAppTransitionCancelled);
608             }
609 
610             @Override
611             public void onAppTransitionFinishedLocked(IBinder token) {
612                 mHandler.post(mAppTransitionFinished);
613             }
614         };
615         displayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
616         mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
617                 mService.mVrModeEnabled);
618 
619         // TODO: Make it can take screenshot on external display
620         mScreenshotHelper = displayContent.isDefaultDisplay
621                 ? new ScreenshotHelper(mContext) : null;
622 
623         if (mDisplayContent.isDefaultDisplay) {
624             mHasStatusBar = true;
625             mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
626 
627             // Allow a system property to override this. Used by the emulator.
628             // See also hasNavigationBar().
629             String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
630             if ("1".equals(navBarOverride)) {
631                 mHasNavigationBar = false;
632             } else if ("0".equals(navBarOverride)) {
633                 mHasNavigationBar = true;
634             }
635         } else {
636             mHasStatusBar = false;
637             mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
638         }
639 
640         mRefreshRatePolicy = new RefreshRatePolicy(mService,
641                 mDisplayContent.getDisplayInfo(),
642                 mService.mHighRefreshRateDenylist);
643 
644         mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
645                 mContext, () -> {
646             synchronized (mLock) {
647                 onConfigurationChanged();
648                 mSystemGestures.onConfigurationChanged();
649                 mDisplayContent.updateSystemGestureExclusion();
650             }
651         });
652         mHandler.post(mGestureNavigationSettingsObserver::register);
653     }
654 
checkAltBarSwipeForTransientBars(@indowManagerPolicy.AltBarPosition int pos)655     private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos) {
656         if (mStatusBarAlt != null && mStatusBarAltPosition == pos) {
657             requestTransientBars(mStatusBarAlt);
658         }
659         if (mNavigationBarAlt != null && mNavigationBarAltPosition == pos) {
660             requestTransientBars(mNavigationBarAlt);
661         }
662         if (mClimateBarAlt != null && mClimateBarAltPosition == pos) {
663             requestTransientBars(mClimateBarAlt);
664         }
665         if (mExtraNavBarAlt != null && mExtraNavBarAltPosition == pos) {
666             requestTransientBars(mExtraNavBarAlt);
667         }
668     }
669 
systemReady()670     void systemReady() {
671         mSystemGestures.systemReady();
672         if (mService.mPointerLocationEnabled) {
673             setPointerLocationEnabled(true);
674         }
675     }
676 
getDisplayId()677     private int getDisplayId() {
678         return mDisplayContent.getDisplayId();
679     }
680 
setHdmiPlugged(boolean plugged)681     public void setHdmiPlugged(boolean plugged) {
682         setHdmiPlugged(plugged, false /* force */);
683     }
684 
setHdmiPlugged(boolean plugged, boolean force)685     public void setHdmiPlugged(boolean plugged, boolean force) {
686         if (force || mHdmiPlugged != plugged) {
687             mHdmiPlugged = plugged;
688             mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
689             final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
690             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
691             intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
692             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
693         }
694     }
695 
isHdmiPlugged()696     boolean isHdmiPlugged() {
697         return mHdmiPlugged;
698     }
699 
isCarDockEnablesAccelerometer()700     boolean isCarDockEnablesAccelerometer() {
701         return mCarDockEnablesAccelerometer;
702     }
703 
isDeskDockEnablesAccelerometer()704     boolean isDeskDockEnablesAccelerometer() {
705         return mDeskDockEnablesAccelerometer;
706     }
707 
setPersistentVrModeEnabled(boolean persistentVrModeEnabled)708     public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
709         mPersistentVrModeEnabled = persistentVrModeEnabled;
710     }
711 
isPersistentVrModeEnabled()712     public boolean isPersistentVrModeEnabled() {
713         return mPersistentVrModeEnabled;
714     }
715 
setDockMode(int dockMode)716     public void setDockMode(int dockMode) {
717         mDockMode = dockMode;
718     }
719 
getDockMode()720     public int getDockMode() {
721         return mDockMode;
722     }
723 
hasNavigationBar()724     public boolean hasNavigationBar() {
725         return mHasNavigationBar;
726     }
727 
hasStatusBar()728     public boolean hasStatusBar() {
729         return mHasStatusBar;
730     }
731 
hasSideGestures()732     boolean hasSideGestures() {
733         return mHasNavigationBar && (mLeftGestureInset > 0 || mRightGestureInset > 0);
734     }
735 
navigationBarCanMove()736     public boolean navigationBarCanMove() {
737         return mNavigationBarCanMove;
738     }
739 
setLidState(int lidState)740     public void setLidState(int lidState) {
741         mLidState = lidState;
742     }
743 
getLidState()744     public int getLidState() {
745         return mLidState;
746     }
747 
setAwake(boolean awake)748     public void setAwake(boolean awake) {
749         mAwake = awake;
750     }
751 
isAwake()752     public boolean isAwake() {
753         return mAwake;
754     }
755 
isScreenOnEarly()756     public boolean isScreenOnEarly() {
757         return mScreenOnEarly;
758     }
759 
isScreenOnFully()760     public boolean isScreenOnFully() {
761         return mScreenOnFully;
762     }
763 
isKeyguardDrawComplete()764     public boolean isKeyguardDrawComplete() {
765         return mKeyguardDrawComplete;
766     }
767 
isWindowManagerDrawComplete()768     public boolean isWindowManagerDrawComplete() {
769         return mWindowManagerDrawComplete;
770     }
771 
getScreenOnListener()772     public ScreenOnListener getScreenOnListener() {
773         return mScreenOnListener;
774     }
775 
screenTurnedOn(ScreenOnListener screenOnListener)776     public void screenTurnedOn(ScreenOnListener screenOnListener) {
777         synchronized (mLock) {
778             mScreenOnEarly = true;
779             mScreenOnFully = false;
780             mKeyguardDrawComplete = false;
781             mWindowManagerDrawComplete = false;
782             mScreenOnListener = screenOnListener;
783         }
784     }
785 
screenTurnedOff()786     public void screenTurnedOff() {
787         synchronized (mLock) {
788             mScreenOnEarly = false;
789             mScreenOnFully = false;
790             mKeyguardDrawComplete = false;
791             mWindowManagerDrawComplete = false;
792             mScreenOnListener = null;
793         }
794     }
795 
796     /** Return false if we are not awake yet or we have already informed of this event. */
finishKeyguardDrawn()797     public boolean finishKeyguardDrawn() {
798         synchronized (mLock) {
799             if (!mScreenOnEarly || mKeyguardDrawComplete) {
800                 return false;
801             }
802 
803             mKeyguardDrawComplete = true;
804             mWindowManagerDrawComplete = false;
805         }
806         return true;
807     }
808 
809     /** Return false if screen is not turned on or we did already handle this case earlier. */
finishWindowsDrawn()810     public boolean finishWindowsDrawn() {
811         synchronized (mLock) {
812             if (!mScreenOnEarly || mWindowManagerDrawComplete) {
813                 return false;
814             }
815 
816             mWindowManagerDrawComplete = true;
817         }
818         return true;
819     }
820 
821     /** Return false if it is not ready to turn on. */
finishScreenTurningOn()822     public boolean finishScreenTurningOn() {
823         synchronized (mLock) {
824             ProtoLog.d(WM_DEBUG_SCREEN_ON,
825                             "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, "
826                                     + "mScreenOnFully=%b, mKeyguardDrawComplete=%b, "
827                                     + "mWindowManagerDrawComplete=%b",
828                             mAwake, mScreenOnEarly, mScreenOnFully, mKeyguardDrawComplete,
829                             mWindowManagerDrawComplete);
830 
831             if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
832                     || (mAwake && !mKeyguardDrawComplete)) {
833                 return false;
834             }
835 
836             ProtoLog.i(WM_DEBUG_SCREEN_ON, "Finished screen turning on...");
837             mScreenOnListener = null;
838             mScreenOnFully = true;
839         }
840         return true;
841     }
842 
hasStatusBarServicePermission(int pid, int uid)843     private boolean hasStatusBarServicePermission(int pid, int uid) {
844         return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid)
845                 == PackageManager.PERMISSION_GRANTED;
846     }
847 
848     /**
849      * Sanitize the layout parameters coming from a client.  Allows the policy
850      * to do things like ensure that windows of a specific type can't take
851      * input focus.
852      *
853      * @param attrs The window layout parameters to be modified.  These values
854      * are modified in-place.
855      */
adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs)856     public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs) {
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                 // Toasts can't be clickable
896                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
897                 break;
898 
899             case TYPE_BASE_APPLICATION:
900 
901                 // A non-translucent main app window isn't allowed to fit insets, as it would create
902                 // a hole on the display!
903                 if (attrs.isFullscreen() && win.mActivityRecord != null
904                         && win.mActivityRecord.fillsParent()
905                         && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
906                         && attrs.getFitInsetsTypes() != 0) {
907                     throw new IllegalArgumentException("Illegal attributes: Main activity window"
908                             + " that isn't translucent trying to fit insets: "
909                             + attrs.getFitInsetsTypes()
910                             + " attrs=" + attrs);
911                 }
912                 break;
913         }
914 
915         // Check if alternate bars positions were updated.
916         if (mStatusBarAlt == win) {
917             mStatusBarAltPosition = getAltBarPosition(attrs);
918         }
919         if (mNavigationBarAlt == win) {
920             mNavigationBarAltPosition = getAltBarPosition(attrs);
921         }
922         if (mClimateBarAlt == win) {
923             mClimateBarAltPosition = getAltBarPosition(attrs);
924         }
925         if (mExtraNavBarAlt == win) {
926             mExtraNavBarAltPosition = getAltBarPosition(attrs);
927         }
928     }
929 
930     /**
931      * Check if a window can be added to the system.
932      *
933      * Currently enforces that two window types are singletons per display:
934      * <ul>
935      * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
936      * <li>{@link WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}</li>
937      * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
938      * </ul>
939      *
940      * @param attrs Information about the window to be added.
941      *
942      * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons,
943      * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
944      */
validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid)945     int validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid) {
946         if ((attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
947             mContext.enforcePermission(
948                     android.Manifest.permission.INTERNAL_SYSTEM_WINDOW, callingPid, callingUid,
949                     "DisplayPolicy");
950         }
951         if ((attrs.privateFlags & PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP) != 0) {
952             ActivityTaskManagerService.enforceTaskPermission("DisplayPolicy");
953         }
954 
955         switch (attrs.type) {
956             case TYPE_STATUS_BAR:
957                 mContext.enforcePermission(
958                         android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
959                         "DisplayPolicy");
960                 if ((mStatusBar != null && mStatusBar.isAlive())
961                         || (mStatusBarAlt != null && mStatusBarAlt.isAlive())) {
962                     return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
963                 }
964                 break;
965             case TYPE_NOTIFICATION_SHADE:
966                 mContext.enforcePermission(
967                         android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
968                         "DisplayPolicy");
969                 if (mNotificationShade != null) {
970                     if (mNotificationShade.isAlive()) {
971                         return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
972                     }
973                 }
974                 break;
975             case TYPE_NAVIGATION_BAR:
976                 mContext.enforcePermission(
977                         android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
978                         "DisplayPolicy");
979                 if ((mNavigationBar != null && mNavigationBar.isAlive())
980                         || (mNavigationBarAlt != null && mNavigationBarAlt.isAlive())) {
981                     return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
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_STATUS_BAR_PANEL:
1000                 return WindowManagerGlobal.ADD_INVALID_TYPE;
1001         }
1002 
1003         if (attrs.providesInsetsTypes != null) {
1004             // Recents component is allowed to add inset types.
1005             if (!mService.mAtmInternal.isCallerRecents(callingUid)) {
1006                 mContext.enforcePermission(
1007                         android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
1008                         "DisplayPolicy");
1009             }
1010             enforceSingleInsetsTypeCorrespondingToWindowType(attrs.providesInsetsTypes);
1011 
1012             for (@InternalInsetsType int insetType : attrs.providesInsetsTypes) {
1013                 switch (insetType) {
1014                     case ITYPE_STATUS_BAR:
1015                         if ((mStatusBar != null && mStatusBar.isAlive())
1016                                 || (mStatusBarAlt != null && mStatusBarAlt.isAlive())) {
1017                             return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
1018                         }
1019                         break;
1020                     case ITYPE_NAVIGATION_BAR:
1021                         if ((mNavigationBar != null && mNavigationBar.isAlive())
1022                                 || (mNavigationBarAlt != null && mNavigationBarAlt.isAlive())) {
1023                             return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
1024                         }
1025                         break;
1026                     case ITYPE_CLIMATE_BAR:
1027                         if (mClimateBarAlt != null && mClimateBarAlt.isAlive()) {
1028                             return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
1029                         }
1030                         break;
1031                     case ITYPE_EXTRA_NAVIGATION_BAR:
1032                         if (mExtraNavBarAlt != null && mExtraNavBarAlt.isAlive()) {
1033                             return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
1034                         }
1035                         break;
1036                 }
1037             }
1038         }
1039         return ADD_OKAY;
1040     }
1041 
getRotatedWindowBounds(DisplayFrames displayFrames, WindowState windowState, Rect outBounds)1042     private void getRotatedWindowBounds(DisplayFrames displayFrames, WindowState windowState,
1043             Rect outBounds) {
1044         outBounds.set(windowState.getBounds());
1045 
1046         int windowRotation = windowState.getWindowConfiguration().getRotation();
1047         if (windowRotation == displayFrames.mRotation) {
1048             return;
1049         }
1050 
1051         // Get displayFrames bounds as it is on WindowState's rotation.
1052         final int deltaRotation = deltaRotation(windowRotation, displayFrames.mRotation);
1053         if (deltaRotation == Surface.ROTATION_90 || deltaRotation == Surface.ROTATION_270) {
1054             sTmpDisplayFrameBounds.set(
1055                     0, 0, displayFrames.mDisplayHeight, displayFrames.mDisplayWidth);
1056         } else {
1057             sTmpDisplayFrameBounds.set(
1058                     0, 0, displayFrames.mDisplayWidth, displayFrames.mDisplayHeight);
1059         }
1060         // Rotate the WindowState's bounds based on the displayFrames rotation
1061         rotateBounds(outBounds, sTmpDisplayFrameBounds, deltaRotation);
1062     }
1063 
1064     /**
1065      * Called when a window is being added to the system.  Must not throw an exception.
1066      *
1067      * @param win The window being added.
1068      * @param attrs Information about the window to be added.
1069      */
addWindowLw(WindowState win, WindowManager.LayoutParams attrs)1070     void addWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
1071         switch (attrs.type) {
1072             case TYPE_NOTIFICATION_SHADE:
1073                 mNotificationShade = win;
1074                 if (mDisplayContent.isDefaultDisplay) {
1075                     mService.mPolicy.setKeyguardCandidateLw(win);
1076                 }
1077                 break;
1078             case TYPE_STATUS_BAR:
1079                 mStatusBar = win;
1080                 final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
1081                         (displayFrames, windowState, rect) -> {
1082                             rect.bottom = rect.top + getStatusBarHeight(displayFrames);
1083                         };
1084                 mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, frameProvider);
1085                 mDisplayContent.setInsetProvider(ITYPE_TOP_MANDATORY_GESTURES, win, frameProvider);
1086                 mDisplayContent.setInsetProvider(ITYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider);
1087                 break;
1088             case TYPE_NAVIGATION_BAR:
1089                 mNavigationBar = win;
1090                 mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win,
1091                         (displayFrames, windowState, inOutFrame) -> {
1092 
1093                             // In Gesture Nav, navigation bar frame is larger than frame to
1094                             // calculate inset.
1095                             if (navigationBarPosition(displayFrames.mDisplayWidth,
1096                                     displayFrames.mDisplayHeight,
1097                                     displayFrames.mRotation) == NAV_BAR_BOTTOM
1098                                     && !mNavButtonForcedVisible) {
1099                                 sTmpRect.set(inOutFrame);
1100                                 sTmpRect.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1101                                 inOutFrame.top = sTmpRect.bottom
1102                                         - getNavigationBarHeight(displayFrames.mRotation,
1103                                         mDisplayContent.getConfiguration().uiMode);
1104                             }
1105                         },
1106 
1107                         // For IME we use regular frame.
1108                         (displayFrames, windowState, inOutFrame) ->
1109                                 inOutFrame.set(windowState.getFrame()));
1110 
1111                 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_MANDATORY_GESTURES, win,
1112                         (displayFrames, windowState, inOutFrame) -> {
1113                             inOutFrame.top -= mBottomGestureAdditionalInset;
1114                         });
1115                 mDisplayContent.setInsetProvider(ITYPE_LEFT_GESTURES, win,
1116                         (displayFrames, windowState, inOutFrame) -> {
1117                             final int leftSafeInset =
1118                                     Math.max(displayFrames.mDisplayCutoutSafe.left, 0);
1119                             inOutFrame.left = 0;
1120                             inOutFrame.top = 0;
1121                             inOutFrame.bottom = displayFrames.mDisplayHeight;
1122                             inOutFrame.right = leftSafeInset + mLeftGestureInset;
1123                         });
1124                 mDisplayContent.setInsetProvider(ITYPE_RIGHT_GESTURES, win,
1125                         (displayFrames, windowState, inOutFrame) -> {
1126                             final int rightSafeInset =
1127                                     Math.min(displayFrames.mDisplayCutoutSafe.right,
1128                                             displayFrames.mUnrestricted.right);
1129                             inOutFrame.left = rightSafeInset - mRightGestureInset;
1130                             inOutFrame.top = 0;
1131                             inOutFrame.bottom = displayFrames.mDisplayHeight;
1132                             inOutFrame.right = displayFrames.mDisplayWidth;
1133                         });
1134                 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_TAPPABLE_ELEMENT, win,
1135                         (displayFrames, windowState, inOutFrame) -> {
1136                             if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
1137                                     || mNavigationBarLetsThroughTaps) {
1138                                 inOutFrame.setEmpty();
1139                             }
1140                         });
1141                 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
1142                 break;
1143             default:
1144                 if (attrs.providesInsetsTypes != null) {
1145                     for (@InternalInsetsType int insetsType : attrs.providesInsetsTypes) {
1146                         switch (insetsType) {
1147                             case ITYPE_STATUS_BAR:
1148                                 mStatusBarAlt = win;
1149                                 mStatusBarAltPosition = getAltBarPosition(attrs);
1150                                 break;
1151                             case ITYPE_NAVIGATION_BAR:
1152                                 mNavigationBarAlt = win;
1153                                 mNavigationBarAltPosition = getAltBarPosition(attrs);
1154                                 break;
1155                             case ITYPE_CLIMATE_BAR:
1156                                 mClimateBarAlt = win;
1157                                 mClimateBarAltPosition = getAltBarPosition(attrs);
1158                                 break;
1159                             case ITYPE_EXTRA_NAVIGATION_BAR:
1160                                 mExtraNavBarAlt = win;
1161                                 mExtraNavBarAltPosition = getAltBarPosition(attrs);
1162                                 break;
1163                         }
1164                         mDisplayContent.setInsetProvider(insetsType, win, null);
1165                     }
1166                 }
1167                 break;
1168         }
1169     }
1170 
1171     @WindowManagerPolicy.AltBarPosition
getAltBarPosition(WindowManager.LayoutParams params)1172     private int getAltBarPosition(WindowManager.LayoutParams params) {
1173         switch (params.gravity) {
1174             case Gravity.LEFT:
1175                 return ALT_BAR_LEFT;
1176             case Gravity.RIGHT:
1177                 return ALT_BAR_RIGHT;
1178             case Gravity.BOTTOM:
1179                 return ALT_BAR_BOTTOM;
1180             case Gravity.TOP:
1181                 return ALT_BAR_TOP;
1182             default:
1183                 return ALT_BAR_UNKNOWN;
1184         }
1185     }
1186 
getImeSourceFrameProvider()1187     TriConsumer<DisplayFrames, WindowState, Rect> getImeSourceFrameProvider() {
1188         return (displayFrames, windowState, inOutFrame) -> {
1189             if (mNavigationBar != null && navigationBarPosition(displayFrames.mDisplayWidth,
1190                     displayFrames.mDisplayHeight,
1191                     displayFrames.mRotation) == NAV_BAR_BOTTOM) {
1192                 // In gesture navigation, nav bar frame is larger than frame to calculate insets.
1193                 // IME should not provide frame which is smaller than the nav bar frame. Otherwise,
1194                 // nav bar might be overlapped with the content of the client when IME is shown.
1195                 sTmpRect.set(inOutFrame);
1196                 sTmpRect.intersectUnchecked(mNavigationBar.getFrame());
1197                 inOutFrame.inset(windowState.mGivenContentInsets);
1198                 inOutFrame.union(sTmpRect);
1199             } else {
1200                 inOutFrame.inset(windowState.mGivenContentInsets);
1201             }
1202         };
1203     }
1204 
1205     private static void enforceSingleInsetsTypeCorrespondingToWindowType(int[] insetsTypes) {
1206         int count = 0;
1207         for (int insetsType : insetsTypes) {
1208             switch (insetsType) {
1209                 case ITYPE_NAVIGATION_BAR:
1210                 case ITYPE_STATUS_BAR:
1211                 case ITYPE_CLIMATE_BAR:
1212                 case ITYPE_EXTRA_NAVIGATION_BAR:
1213                 case ITYPE_CAPTION_BAR:
1214                     if (++count > 1) {
1215                         throw new IllegalArgumentException(
1216                                 "Multiple InsetsTypes corresponding to Window type");
1217                     }
1218             }
1219         }
1220     }
1221 
1222     /**
1223      * Called when a window is being removed from a window manager.  Must not
1224      * throw an exception -- clean up as much as possible.
1225      *
1226      * @param win The window being removed.
1227      */
1228     void removeWindowLw(WindowState win) {
1229         if (mStatusBar == win || mStatusBarAlt == win) {
1230             mStatusBar = null;
1231             mStatusBarAlt = null;
1232             mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, null, null);
1233         } else if (mNavigationBar == win || mNavigationBarAlt == win) {
1234             mNavigationBar = null;
1235             mNavigationBarAlt = null;
1236             mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null);
1237         } else if (mNotificationShade == win) {
1238             mNotificationShade = null;
1239             if (mDisplayContent.isDefaultDisplay) {
1240                 mService.mPolicy.setKeyguardCandidateLw(null);
1241             }
1242         } else if (mClimateBarAlt == win) {
1243             mClimateBarAlt = null;
1244             mDisplayContent.setInsetProvider(ITYPE_CLIMATE_BAR, null, null);
1245         } else if (mExtraNavBarAlt == win) {
1246             mExtraNavBarAlt = null;
1247             mDisplayContent.setInsetProvider(ITYPE_EXTRA_NAVIGATION_BAR, null, null);
1248         }
1249         if (mLastFocusedWindow == win) {
1250             mLastFocusedWindow = null;
1251         }
1252     }
1253 
1254     private int getStatusBarHeight(DisplayFrames displayFrames) {
1255         return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
1256                 displayFrames.mDisplayCutoutSafe.top);
1257     }
1258 
1259     WindowState getStatusBar() {
1260         return mStatusBar != null ? mStatusBar : mStatusBarAlt;
1261     }
1262 
1263     WindowState getNotificationShade() {
1264         return mNotificationShade;
1265     }
1266 
1267     WindowState getNavigationBar() {
1268         return mNavigationBar != null ? mNavigationBar : mNavigationBarAlt;
1269     }
1270 
1271     /**
1272      * Control the animation to run when a window's state changes.  Return a positive number to
1273      * force the animation to a specific resource ID, {@link #ANIMATION_STYLEABLE} to use the
1274      * style resource defining the animation, or {@link #ANIMATION_NONE} for no animation.
1275      *
1276      * @param win The window that is changing.
1277      * @param transit What is happening to the window:
1278      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
1279      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
1280      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
1281      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
1282      *
1283      * @return Resource ID of the actual animation to use, or {@link #ANIMATION_NONE} for none.
1284      */
1285     int selectAnimation(WindowState win, int transit) {
1286         if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
1287                 + ": transit=" + transit);
1288         if (win == mStatusBar) {
1289             if (transit == TRANSIT_EXIT
1290                     || transit == TRANSIT_HIDE) {
1291                 return R.anim.dock_top_exit;
1292             } else if (transit == TRANSIT_ENTER
1293                     || transit == TRANSIT_SHOW) {
1294                 return R.anim.dock_top_enter;
1295             }
1296         } else if (win == mNavigationBar) {
1297             if (win.getAttrs().windowAnimations != 0) {
1298                 return ANIMATION_STYLEABLE;
1299             }
1300             // This can be on either the bottom or the right or the left.
1301             if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1302                 if (transit == TRANSIT_EXIT
1303                         || transit == TRANSIT_HIDE) {
1304                     if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
1305                         return R.anim.dock_bottom_exit_keyguard;
1306                     } else {
1307                         return R.anim.dock_bottom_exit;
1308                     }
1309                 } else if (transit == TRANSIT_ENTER
1310                         || transit == TRANSIT_SHOW) {
1311                     return R.anim.dock_bottom_enter;
1312                 }
1313             } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1314                 if (transit == TRANSIT_EXIT
1315                         || transit == TRANSIT_HIDE) {
1316                     return R.anim.dock_right_exit;
1317                 } else if (transit == TRANSIT_ENTER
1318                         || transit == TRANSIT_SHOW) {
1319                     return R.anim.dock_right_enter;
1320                 }
1321             } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1322                 if (transit == TRANSIT_EXIT
1323                         || transit == TRANSIT_HIDE) {
1324                     return R.anim.dock_left_exit;
1325                 } else if (transit == TRANSIT_ENTER
1326                         || transit == TRANSIT_SHOW) {
1327                     return R.anim.dock_left_enter;
1328                 }
1329             }
1330         } else if (win == mStatusBarAlt || win == mNavigationBarAlt || win == mClimateBarAlt
1331                 || win == mExtraNavBarAlt) {
1332             if (win.getAttrs().windowAnimations != 0) {
1333                 return ANIMATION_STYLEABLE;
1334             }
1335 
1336             int pos = (win == mStatusBarAlt) ? mStatusBarAltPosition : mNavigationBarAltPosition;
1337 
1338             boolean isExitOrHide = transit == TRANSIT_EXIT || transit == TRANSIT_HIDE;
1339             boolean isEnterOrShow = transit == TRANSIT_ENTER || transit == TRANSIT_SHOW;
1340 
1341             switch (pos) {
1342                 case ALT_BAR_LEFT:
1343                     if (isExitOrHide) {
1344                         return R.anim.dock_left_exit;
1345                     } else if (isEnterOrShow) {
1346                         return R.anim.dock_left_enter;
1347                     }
1348                     break;
1349                 case ALT_BAR_RIGHT:
1350                     if (isExitOrHide) {
1351                         return R.anim.dock_right_exit;
1352                     } else if (isEnterOrShow) {
1353                         return R.anim.dock_right_enter;
1354                     }
1355                     break;
1356                 case ALT_BAR_BOTTOM:
1357                     if (isExitOrHide) {
1358                         return R.anim.dock_bottom_exit;
1359                     } else if (isEnterOrShow) {
1360                         return R.anim.dock_bottom_enter;
1361                     }
1362                     break;
1363                 case ALT_BAR_TOP:
1364                     if (isExitOrHide) {
1365                         return R.anim.dock_top_exit;
1366                     } else if (isEnterOrShow) {
1367                         return R.anim.dock_top_enter;
1368                     }
1369                     break;
1370             }
1371         }
1372 
1373         if (transit == TRANSIT_PREVIEW_DONE) {
1374             if (win.hasAppShownWindows()) {
1375                 if (win.isActivityTypeHome()) {
1376                     // Dismiss the starting window as soon as possible to avoid the crossfade out
1377                     // with old content because home is easier to have different UI states.
1378                     return ANIMATION_NONE;
1379                 }
1380                 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
1381                 return R.anim.app_starting_exit;
1382             }
1383         }
1384 
1385         return ANIMATION_STYLEABLE;
1386     }
1387 
1388     /**
1389      * @return true if the system bars are forced to stay visible
1390      */
1391     public boolean areSystemBarsForcedShownLw(WindowState windowState) {
1392         return mForceShowSystemBars;
1393     }
1394 
1395     // TODO: Should probably be moved into DisplayFrames.
1396     /**
1397      * Return the layout hints for a newly added window. These values are computed on the
1398      * most recent layout, so they are not guaranteed to be correct.
1399      *
1400      * @param attrs The LayoutParams of the window.
1401      * @param windowToken The token of the window.
1402      * @param outInsetsState The insets state of this display from the client's perspective.
1403      * @param localClient Whether the client is from the our process.
1404      * @return Whether to always consume the system bars.
1405      *         See {@link #areSystemBarsForcedShownLw(WindowState)}.
1406      */
1407     boolean getLayoutHint(LayoutParams attrs, WindowToken windowToken, InsetsState outInsetsState,
1408             boolean localClient) {
1409         final InsetsState state =
1410                 mDisplayContent.getInsetsPolicy().getInsetsForWindowMetrics(attrs);
1411         final boolean hasCompatScale = WindowState.hasCompatScale(attrs, windowToken);
1412         outInsetsState.set(state, hasCompatScale || localClient);
1413         if (hasCompatScale) {
1414             final float compatScale = windowToken != null
1415                     ? windowToken.getSizeCompatScale()
1416                     : mDisplayContent.mCompatibleScreenScale;
1417             outInsetsState.scale(1f / compatScale);
1418         }
1419         return mForceShowSystemBars;
1420     }
1421 
1422     private void simulateLayoutDecorWindow(WindowState win, DisplayFrames displayFrames,
1423             WindowFrames simulatedWindowFrames, SparseArray<Rect> contentFrames,
1424             Consumer<Rect> layout) {
1425         win.setSimulatedWindowFrames(simulatedWindowFrames);
1426         final Rect contentFrame = new Rect();
1427         try {
1428             layout.accept(contentFrame);
1429         } finally {
1430             win.setSimulatedWindowFrames(null);
1431         }
1432         contentFrames.put(win.mAttrs.type, contentFrame);
1433         mDisplayContent.getInsetsStateController().computeSimulatedState(
1434                 win, displayFrames, simulatedWindowFrames);
1435     }
1436 
1437     /**
1438      * Computes the frames of display (its logical size, rotation and cutout should already be set)
1439      * used to layout window. This method only changes the given display frames, insets state and
1440      * some temporal states, but doesn't change the window frames used to show on screen.
1441      */
1442     void simulateLayoutDisplay(DisplayFrames displayFrames, SparseArray<Rect> barContentFrames) {
1443         final WindowFrames simulatedWindowFrames = new WindowFrames();
1444         if (mNavigationBar != null) {
1445             simulateLayoutDecorWindow(mNavigationBar, displayFrames, simulatedWindowFrames,
1446                     barContentFrames, contentFrame -> layoutNavigationBar(displayFrames,
1447                             contentFrame));
1448         }
1449         if (mStatusBar != null) {
1450             simulateLayoutDecorWindow(mStatusBar, displayFrames, simulatedWindowFrames,
1451                     barContentFrames, contentFrame -> layoutStatusBar(displayFrames, contentFrame));
1452         }
1453     }
1454 
1455     void onDisplayInfoChanged(DisplayInfo info) {
1456         mSystemGestures.onDisplayInfoChanged(info);
1457     }
1458 
1459     private void layoutStatusBar(DisplayFrames displayFrames, Rect contentFrame) {
1460         // decide where the status bar goes ahead of time
1461         if (mStatusBar == null) {
1462             return;
1463         }
1464         // apply any status bar insets
1465         getRotatedWindowBounds(displayFrames, mStatusBar, sTmpStatusFrame);
1466         final WindowFrames windowFrames = mStatusBar.getLayoutingWindowFrames();
1467         windowFrames.setFrames(sTmpStatusFrame /* parentFrame */,
1468                 sTmpStatusFrame /* displayFrame */);
1469         // Let the status bar determine its size.
1470         mStatusBar.computeFrameAndUpdateSourceFrame();
1471 
1472         // For layout, the status bar is always at the top with our fixed height.
1473         int statusBarBottom = displayFrames.mUnrestricted.top
1474                 + mStatusBarHeightForRotation[displayFrames.mRotation];
1475         // Make sure the status bar covers the entire cutout height
1476         statusBarBottom = Math.max(statusBarBottom, displayFrames.mDisplayCutoutSafe.top);
1477 
1478         if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
1479             // Make sure that the zone we're avoiding for the cutout is at least as tall as the
1480             // status bar; otherwise fullscreen apps will end up cutting halfway into the status
1481             // bar.
1482             displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
1483                     statusBarBottom);
1484         }
1485 
1486         sTmpRect.set(windowFrames.mFrame);
1487         sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
1488         sTmpRect.top = windowFrames.mFrame.top; // Ignore top display cutout inset
1489         sTmpRect.bottom = statusBarBottom; // Use collapsed status bar size
1490         contentFrame.set(sTmpRect);
1491     }
1492 
1493     private int layoutNavigationBar(DisplayFrames displayFrames, Rect contentFrame) {
1494         if (mNavigationBar == null) {
1495             return NAV_BAR_INVALID;
1496         }
1497 
1498         final int uiMode = mDisplayContent.getConfiguration().uiMode;
1499         final Rect navigationFrame = sTmpNavFrame;
1500         // Force the navigation bar to its appropriate place and size. We need to do this directly,
1501         // instead of relying on it to bubble up from the nav bar, because this needs to change
1502         // atomically with screen rotations.
1503         final int rotation = displayFrames.mRotation;
1504         final int displayHeight = displayFrames.mDisplayHeight;
1505         final int displayWidth = displayFrames.mDisplayWidth;
1506         final int navBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
1507 
1508         getRotatedWindowBounds(displayFrames, mNavigationBar, navigationFrame);
1509 
1510         final Rect cutoutSafeUnrestricted = sTmpRect;
1511         cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
1512         cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1513 
1514         if (navBarPosition == NAV_BAR_BOTTOM) {
1515             // It's a system nav bar or a portrait screen; nav bar goes on bottom.
1516             navigationFrame.top = Math.min(cutoutSafeUnrestricted.bottom, navigationFrame.bottom)
1517                     - getNavigationBarFrameHeight(rotation, uiMode);
1518         } else if (navBarPosition == NAV_BAR_RIGHT) {
1519             // Landscape screen; nav bar goes to the right.
1520             navigationFrame.left = Math.min(cutoutSafeUnrestricted.right, navigationFrame.right)
1521                     - getNavigationBarWidth(rotation, uiMode);
1522         } else if (navBarPosition == NAV_BAR_LEFT) {
1523             // Seascape screen; nav bar goes to the left.
1524             navigationFrame.right = Math.max(cutoutSafeUnrestricted.left, navigationFrame.left)
1525                     + getNavigationBarWidth(rotation, uiMode);
1526         }
1527 
1528         // Compute the final frame.
1529         final WindowFrames windowFrames = mNavigationBar.getLayoutingWindowFrames();
1530         windowFrames.setFrames(navigationFrame /* parentFrame */,
1531                 navigationFrame /* displayFrame */);
1532         mNavigationBar.computeFrameAndUpdateSourceFrame();
1533         sTmpRect.set(windowFrames.mFrame);
1534         sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
1535         contentFrame.set(sTmpRect);
1536 
1537         if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
1538         return navBarPosition;
1539     }
1540 
1541     private boolean canReceiveInput(WindowState win) {
1542         boolean notFocusable =
1543                 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
1544         boolean altFocusableIm =
1545                 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
1546         boolean notFocusableForIm = notFocusable ^ altFocusableIm;
1547         return !notFocusableForIm;
1548     }
1549 
1550     /**
1551      * Called for each window attached to the window manager as layout is proceeding. The
1552      * implementation of this function must take care of setting the window's frame, either here or
1553      * in finishLayout().
1554      *
1555      * @param win The window being positioned.
1556      * @param attached For sub-windows, the window it is attached to; this
1557      *                 window will already have had layoutWindow() called on it
1558      *                 so you can use its Rect.  Otherwise null.
1559      * @param displayFrames The display frames.
1560      */
1561     public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
1562         if (win == mNavigationBar) {
1563             mNavigationBarPosition = layoutNavigationBar(displayFrames,
1564                     mBarContentFrames.get(TYPE_NAVIGATION_BAR));
1565             return;
1566         }
1567         if ((win == mStatusBar && !canReceiveInput(win))) {
1568             layoutStatusBar(displayFrames, mBarContentFrames.get(TYPE_STATUS_BAR));
1569             return;
1570         }
1571         if (win.mActivityRecord != null && win.mActivityRecord.mWaitForEnteringPinnedMode) {
1572             // Skip layout of the window when in transition to pip mode.
1573             return;
1574         }
1575         final WindowManager.LayoutParams attrs = win.getAttrs();
1576 
1577         final int type = attrs.type;
1578         final int fl = attrs.flags;
1579         final int pfl = attrs.privateFlags;
1580         final int sim = attrs.softInputMode;
1581 
1582         displayFrames = win.getDisplayFrames(displayFrames);
1583         final WindowFrames windowFrames = win.getWindowFrames();
1584 
1585         sTmpLastParentFrame.set(windowFrames.mParentFrame);
1586         final Rect pf = windowFrames.mParentFrame;
1587         final Rect df = windowFrames.mDisplayFrame;
1588         windowFrames.setParentFrameWasClippedByDisplayCutout(false);
1589 
1590         final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
1591         final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
1592 
1593         final InsetsState state = win.getInsetsState();
1594         computeWindowBounds(attrs, state, win.mToken.getBounds(), df);
1595         if (attached == null) {
1596             pf.set(df);
1597             if ((pfl & PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME) != 0) {
1598                 final InsetsSource source = state.peekSource(ITYPE_IME);
1599                 if (source != null) {
1600                     pf.inset(source.calculateInsets(pf, false /* ignoreVisibility */));
1601                 }
1602             }
1603         } else {
1604             pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df);
1605         }
1606 
1607         final int cutoutMode = attrs.layoutInDisplayCutoutMode;
1608         // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
1609         // the cutout safe zone.
1610         if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) {
1611             final boolean attachedInParent = attached != null && !layoutInScreen;
1612             final boolean requestedFullscreen = !win.getRequestedVisibility(ITYPE_STATUS_BAR);
1613             final boolean requestedHideNavigation =
1614                     !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR);
1615 
1616             // TYPE_BASE_APPLICATION windows are never considered floating here because they don't
1617             // get cropped / shifted to the displayFrame in WindowState.
1618             final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
1619                     && type != TYPE_BASE_APPLICATION;
1620             final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
1621             displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
1622             if (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
1623                 if (displayFrames.mDisplayWidth < displayFrames.mDisplayHeight) {
1624                     displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
1625                     displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
1626                 } else {
1627                     displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
1628                     displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
1629                 }
1630             }
1631 
1632             if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
1633                     && (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
1634                     || cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)) {
1635                 // At the top we have the status bar, so apps that are
1636                 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
1637                 // already expect that there's an inset there and we don't need to exclude
1638                 // the window from that area.
1639                 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
1640             }
1641             if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
1642                     && (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
1643                     || cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)) {
1644                 // Same for the navigation bar.
1645                 switch (mNavigationBarPosition) {
1646                     case NAV_BAR_BOTTOM:
1647                         displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
1648                         break;
1649                     case NAV_BAR_RIGHT:
1650                         displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
1651                         break;
1652                     case NAV_BAR_LEFT:
1653                         displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
1654                         break;
1655                 }
1656             }
1657             if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
1658                 // The IME can always extend under the bottom cutout if the navbar is there.
1659                 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
1660             }
1661             // Windows that are attached to a parent and laid out in said parent already avoid
1662             // the cutout according to that parent and don't need to be further constrained.
1663             // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
1664             // They will later be cropped or shifted using the displayFrame in WindowState,
1665             // which prevents overlap with the DisplayCutout.
1666             if (!attachedInParent && !floatingInScreenWindow) {
1667                 sTmpRect.set(pf);
1668                 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
1669                 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
1670             }
1671             // Make sure that NO_LIMITS windows clipped to the display don't extend under the
1672             // cutout.
1673             df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
1674         }
1675 
1676         // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
1677         // Also, we don't allow windows in multi-window mode to extend out of the screen.
1678         if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
1679                 && !win.inMultiWindowMode()) {
1680             df.left = df.top = -10000;
1681             df.right = df.bottom = 10000;
1682         }
1683 
1684         if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
1685                 + ": sim=#" + Integer.toHexString(sim)
1686                 + " attach=" + attached + " type=" + type
1687                 + String.format(" flags=0x%08x", fl)
1688                 + " pf=" + pf.toShortString() + " df=" + df.toShortString());
1689 
1690         if (!sTmpLastParentFrame.equals(pf)) {
1691             windowFrames.setContentChanged(true);
1692         }
1693 
1694         win.computeFrameAndUpdateSourceFrame();
1695     }
1696 
1697     WindowState getTopFullscreenOpaqueWindow() {
1698         return mTopFullscreenOpaqueWindowState;
1699     }
1700 
1701     boolean isTopLayoutFullscreen() {
1702         return mTopIsFullscreen;
1703     }
1704 
1705     /**
1706      * Called following layout of all windows before each window has policy applied.
1707      */
1708     public void beginPostLayoutPolicyLw() {
1709         mTopFullscreenOpaqueWindowState = null;
1710         mTopFullscreenOpaqueOrDimmingWindowState = null;
1711         mTopDockedOpaqueWindowState = null;
1712         mTopDockedOpaqueOrDimmingWindowState = null;
1713         mForceStatusBar = false;
1714         mForcingShowNavBar = false;
1715         mForcingShowNavBarLayer = -1;
1716 
1717         mAllowLockscreenWhenOn = false;
1718         mShowingDream = false;
1719         mIsFreeformWindowOverlappingWithNavBar = false;
1720     }
1721 
1722     /**
1723      * Called following layout of all window to apply policy to each window.
1724      *
1725      * @param win The window being positioned.
1726      * @param attrs The LayoutParams of the window.
1727      * @param attached For sub-windows, the window it is attached to. Otherwise null.
1728      */
1729     public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
1730             WindowState attached, WindowState imeTarget) {
1731         final boolean affectsSystemUi = win.canAffectSystemUiFlags();
1732         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
1733         applyKeyguardPolicy(win, imeTarget);
1734         final int fl = attrs.flags;
1735         if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
1736                 && attrs.type == TYPE_INPUT_METHOD) {
1737             mForcingShowNavBar = true;
1738             mForcingShowNavBarLayer = win.getSurfaceLayer();
1739         }
1740 
1741         boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
1742                 && attrs.type < FIRST_SYSTEM_WINDOW;
1743         final int windowingMode = win.getWindowingMode();
1744         final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
1745                 windowingMode == WINDOWING_MODE_FULLSCREEN
1746                         || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
1747         if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
1748             if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
1749                 mForceStatusBar = true;
1750             }
1751             if (win.isDreamWindow()) {
1752                 // If the lockscreen was showing when the dream started then wait
1753                 // for the dream to draw before hiding the lockscreen.
1754                 if (!mDreamingLockscreen || (win.isVisible() && win.hasDrawn())) {
1755                     mShowingDream = true;
1756                     appWindow = true;
1757                 }
1758             }
1759 
1760             // For app windows that are not attached, we decide if all windows in the app they
1761             // represent should be hidden or if we should hide the lockscreen. For attached app
1762             // windows we defer the decision to the window it is attached to.
1763             if (appWindow && attached == null) {
1764                 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
1765                     if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
1766                     mTopFullscreenOpaqueWindowState = win;
1767                     if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
1768                         mTopFullscreenOpaqueOrDimmingWindowState = win;
1769                     }
1770                     if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
1771                         mAllowLockscreenWhenOn = true;
1772                     }
1773                 }
1774             }
1775         }
1776 
1777         // Voice interaction overrides both top fullscreen and top docked.
1778         if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION && attrs.isFullscreen()) {
1779             if (mTopFullscreenOpaqueWindowState == null) {
1780                 mTopFullscreenOpaqueWindowState = win;
1781                 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
1782                     mTopFullscreenOpaqueOrDimmingWindowState = win;
1783                 }
1784             }
1785             if (mTopDockedOpaqueWindowState == null) {
1786                 mTopDockedOpaqueWindowState = win;
1787                 if (mTopDockedOpaqueOrDimmingWindowState == null) {
1788                     mTopDockedOpaqueOrDimmingWindowState = win;
1789                 }
1790             }
1791         }
1792 
1793         // Keep track of the window if it's dimming but not necessarily fullscreen.
1794         if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
1795                 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
1796             mTopFullscreenOpaqueOrDimmingWindowState = win;
1797         }
1798 
1799         // We need to keep track of the top "fullscreen" opaque window for the docked root task
1800         // separately, because both the "real fullscreen" opaque window and the one for the docked
1801         // root task can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
1802         if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
1803                 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
1804             mTopDockedOpaqueWindowState = win;
1805             if (mTopDockedOpaqueOrDimmingWindowState == null) {
1806                 mTopDockedOpaqueOrDimmingWindowState = win;
1807             }
1808         }
1809 
1810         // Check if the freeform window overlaps with the navigation bar area.
1811         final WindowState navBarWin = hasNavigationBar() ? mNavigationBar : null;
1812         if (!mIsFreeformWindowOverlappingWithNavBar && win.inFreeformWindowingMode()
1813                 && isOverlappingWithNavBar(win, navBarWin)) {
1814             mIsFreeformWindowOverlappingWithNavBar = true;
1815         }
1816 
1817         // Also keep track of any windows that are dimming but not necessarily fullscreen in the
1818         // docked root task.
1819         if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
1820                 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
1821             mTopDockedOpaqueOrDimmingWindowState = win;
1822         }
1823     }
1824 
1825     /**
1826      * Called following layout of all windows and after policy has been applied
1827      * to each window. If in this function you do
1828      * something that may have modified the animation state of another window,
1829      * be sure to return non-zero in order to perform another pass through layout.
1830      *
1831      * @return Return any bit set of
1832      *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
1833      *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
1834      *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
1835      *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
1836      */
1837     public int finishPostLayoutPolicyLw() {
1838         int changes = 0;
1839         boolean topIsFullscreen = false;
1840 
1841         // If we are not currently showing a dream then remember the current
1842         // lockscreen state.  We will use this to determine whether the dream
1843         // started while the lockscreen was showing and remember this state
1844         // while the dream is showing.
1845         if (!mShowingDream) {
1846             mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
1847         }
1848 
1849         if (getStatusBar() != null) {
1850             if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
1851                     + " top=" + mTopFullscreenOpaqueWindowState);
1852             final boolean forceShowStatusBar = (getStatusBar().getAttrs().privateFlags
1853                     & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0;
1854 
1855             boolean topAppHidesStatusBar = topAppHidesStatusBar();
1856             if (mForceStatusBar || forceShowStatusBar) {
1857                 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
1858                 // Maintain fullscreen layout until incoming animation is complete.
1859                 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
1860             } else if (mTopFullscreenOpaqueWindowState != null) {
1861                 topIsFullscreen = topAppHidesStatusBar;
1862                 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
1863                 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
1864                 // requests to hide the status bar.  Not sure if there is another way that to be the
1865                 // case though.
1866                 if (!topIsFullscreen || mDisplayContent.getDefaultTaskDisplayArea()
1867                         .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
1868                     topAppHidesStatusBar = false;
1869                 }
1870             }
1871             StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
1872             if (statusBar != null) {
1873                 statusBar.setTopAppHidesStatusBar(topAppHidesStatusBar);
1874             }
1875         }
1876 
1877         if (mTopIsFullscreen != topIsFullscreen) {
1878             if (!topIsFullscreen) {
1879                 // Force another layout when status bar becomes fully shown.
1880                 changes |= FINISH_LAYOUT_REDO_LAYOUT;
1881             }
1882             mTopIsFullscreen = topIsFullscreen;
1883         }
1884 
1885         if (updateSystemUiVisibilityLw()) {
1886             // If the navigation bar has been hidden or shown, we need to do another
1887             // layout pass to update that window.
1888             changes |= FINISH_LAYOUT_REDO_LAYOUT;
1889         }
1890 
1891         if (mShowingDream != mLastShowingDream) {
1892             mLastShowingDream = mShowingDream;
1893             mService.notifyShowingDreamChanged();
1894         }
1895 
1896         mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
1897         return changes;
1898     }
1899 
1900     /**
1901      * Applies the keyguard policy to a specific window.
1902      *
1903      * @param win The window to apply the keyguard policy.
1904      * @param imeTarget The current IME target window.
1905      */
1906     private void applyKeyguardPolicy(WindowState win, WindowState imeTarget) {
1907         if (mService.mPolicy.canBeHiddenByKeyguardLw(win)) {
1908             if (shouldBeHiddenByKeyguard(win, imeTarget)) {
1909                 win.hide(false /* doAnimation */, true /* requestAnim */);
1910             } else {
1911                 win.show(false /* doAnimation */, true /* requestAnim */);
1912             }
1913         }
1914     }
1915 
1916     private boolean shouldBeHiddenByKeyguard(WindowState win, WindowState imeTarget) {
1917         // If AOD is showing, the IME should be hidden. However, sometimes the AOD is considered
1918         // hidden because it's in the process of hiding, but it's still being shown on screen.
1919         // In that case, we want to continue hiding the IME until the windows have completed
1920         // drawing. This way, we know that the IME can be safely shown since the other windows are
1921         // now shown.
1922         final boolean hideIme = win.mIsImWindow
1923                 && (mService.mAtmService.mKeyguardController.isAodShowing()
1924                         || (mDisplayContent.isDefaultDisplay && !mWindowManagerDrawComplete));
1925         if (hideIme) {
1926             return true;
1927         }
1928 
1929         if (!mDisplayContent.isDefaultDisplay || !isKeyguardShowing()) {
1930             return false;
1931         }
1932 
1933         // Show IME over the keyguard if the target allows it.
1934         final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisible()
1935                 && win.mIsImWindow && (imeTarget.canShowWhenLocked()
1936                         || !mService.mPolicy.canBeHiddenByKeyguardLw(imeTarget));
1937         if (showImeOverKeyguard) {
1938             return false;
1939         }
1940 
1941         // Show SHOW_WHEN_LOCKED windows if keyguard is occluded.
1942         final boolean allowShowWhenLocked = isKeyguardOccluded()
1943                 // Show error dialogs over apps that are shown on keyguard.
1944                 && (win.canShowWhenLocked()
1945                         || (win.mAttrs.privateFlags & LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR) != 0);
1946         return !allowShowWhenLocked;
1947     }
1948 
1949     /**
1950      * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
1951      *         window.
1952      */
1953     boolean topAppHidesStatusBar() {
1954         if (mTopFullscreenOpaqueWindowState == null || mForceShowSystemBars) {
1955             return false;
1956         }
1957         return !mTopFullscreenOpaqueWindowState.getRequestedVisibility(ITYPE_STATUS_BAR);
1958     }
1959 
1960     /**
1961      * Called when the user is switched.
1962      */
1963     public void switchUser() {
1964         updateCurrentUserResources();
1965     }
1966 
1967     /**
1968      * Called when the resource overlays change.
1969      */
1970     public void onOverlayChangedLw() {
1971         updateCurrentUserResources();
1972         onConfigurationChanged();
1973         mSystemGestures.onConfigurationChanged();
1974     }
1975 
1976     /**
1977      * Called when the configuration has changed, and it's safe to load new values from resources.
1978      */
1979     public void onConfigurationChanged() {
1980         final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
1981 
1982         final Resources res = getCurrentUserResources();
1983         final int portraitRotation = displayRotation.getPortraitRotation();
1984         final int upsideDownRotation = displayRotation.getUpsideDownRotation();
1985         final int landscapeRotation = displayRotation.getLandscapeRotation();
1986         final int seascapeRotation = displayRotation.getSeascapeRotation();
1987         final int uiMode = mService.mPolicy.getUiMode();
1988 
1989         if (hasStatusBar()) {
1990             mStatusBarHeightForRotation[portraitRotation] =
1991                     mStatusBarHeightForRotation[upsideDownRotation] =
1992                             res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
1993             mStatusBarHeightForRotation[landscapeRotation] =
1994                     mStatusBarHeightForRotation[seascapeRotation] =
1995                             res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
1996         } else {
1997             mStatusBarHeightForRotation[portraitRotation] =
1998                     mStatusBarHeightForRotation[upsideDownRotation] =
1999                             mStatusBarHeightForRotation[landscapeRotation] =
2000                                     mStatusBarHeightForRotation[seascapeRotation] = 0;
2001         }
2002 
2003         // Height of the navigation bar when presented horizontally at bottom
2004         mNavigationBarHeightForRotationDefault[portraitRotation] =
2005         mNavigationBarHeightForRotationDefault[upsideDownRotation] =
2006                 res.getDimensionPixelSize(R.dimen.navigation_bar_height);
2007         mNavigationBarHeightForRotationDefault[landscapeRotation] =
2008         mNavigationBarHeightForRotationDefault[seascapeRotation] =
2009                 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
2010 
2011         // Height of the navigation bar frame when presented horizontally at bottom
2012         mNavigationBarFrameHeightForRotationDefault[portraitRotation] =
2013         mNavigationBarFrameHeightForRotationDefault[upsideDownRotation] =
2014                 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
2015         mNavigationBarFrameHeightForRotationDefault[landscapeRotation] =
2016         mNavigationBarFrameHeightForRotationDefault[seascapeRotation] =
2017                 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height_landscape);
2018 
2019         // Width of the navigation bar when presented vertically along one side
2020         mNavigationBarWidthForRotationDefault[portraitRotation] =
2021         mNavigationBarWidthForRotationDefault[upsideDownRotation] =
2022         mNavigationBarWidthForRotationDefault[landscapeRotation] =
2023         mNavigationBarWidthForRotationDefault[seascapeRotation] =
2024                 res.getDimensionPixelSize(R.dimen.navigation_bar_width);
2025 
2026         if (ALTERNATE_CAR_MODE_NAV_SIZE) {
2027             // Height of the navigation bar when presented horizontally at bottom
2028             mNavigationBarHeightForRotationInCarMode[portraitRotation] =
2029             mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
2030                     res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
2031             mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
2032             mNavigationBarHeightForRotationInCarMode[seascapeRotation] =
2033                     res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode);
2034 
2035             // Width of the navigation bar when presented vertically along one side
2036             mNavigationBarWidthForRotationInCarMode[portraitRotation] =
2037             mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
2038             mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
2039             mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
2040                     res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
2041         }
2042 
2043         mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
2044         mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res);
2045         mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res);
2046         mNavButtonForcedVisible =
2047                 mGestureNavigationSettingsObserver.areNavigationButtonForcedVisible();
2048         mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
2049         mNavigationBarAlwaysShowOnSideGesture =
2050                 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
2051 
2052         // This should calculate how much above the frame we accept gestures.
2053         mBottomGestureAdditionalInset =
2054                 res.getDimensionPixelSize(R.dimen.navigation_bar_gesture_height)
2055                         - getNavigationBarFrameHeight(portraitRotation, uiMode);
2056 
2057         updateConfigurationAndScreenSizeDependentBehaviors();
2058 
2059         final boolean shouldAttach =
2060                 res.getBoolean(R.bool.config_attachNavBarToAppDuringTransition);
2061         if (mShouldAttachNavBarToAppDuringTransition != shouldAttach) {
2062             mShouldAttachNavBarToAppDuringTransition = shouldAttach;
2063         }
2064     }
2065 
2066     void updateConfigurationAndScreenSizeDependentBehaviors() {
2067         final Resources res = getCurrentUserResources();
2068         mNavigationBarCanMove =
2069                 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
2070                         && res.getBoolean(R.bool.config_navBarCanMove);
2071         mDisplayContent.getDisplayRotation().updateUserDependentConfiguration(res);
2072     }
2073 
2074     /**
2075      * Updates the current user's resources to pick up any changes for the current user (including
2076      * overlay paths)
2077      */
2078     private void updateCurrentUserResources() {
2079         final int userId = mService.mAmInternal.getCurrentUserId();
2080         final Context uiContext = getSystemUiContext();
2081 
2082         if (userId == UserHandle.USER_SYSTEM) {
2083             // Skip the (expensive) recreation of resources for the system user below and just
2084             // use the resources from the system ui context
2085             mCurrentUserResources = uiContext.getResources();
2086             return;
2087         }
2088 
2089         // For non-system users, ensure that the resources are loaded from the current
2090         // user's package info (see ContextImpl.createDisplayContext)
2091         final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
2092                 uiContext.getPackageName(), null, 0, userId);
2093         mCurrentUserResources = ResourcesManager.getInstance().getResources(null,
2094                 pi.getResDir(),
2095                 null /* splitResDirs */,
2096                 pi.getOverlayDirs(),
2097                 pi.getOverlayPaths(),
2098                 pi.getApplicationInfo().sharedLibraryFiles,
2099                 mDisplayContent.getDisplayId(),
2100                 null /* overrideConfig */,
2101                 uiContext.getResources().getCompatibilityInfo(),
2102                 null /* classLoader */,
2103                 null /* loaders */);
2104     }
2105 
2106     @VisibleForTesting
2107     Resources getCurrentUserResources() {
2108         if (mCurrentUserResources == null) {
2109             updateCurrentUserResources();
2110         }
2111         return mCurrentUserResources;
2112     }
2113 
2114     @VisibleForTesting
2115     Context getContext() {
2116         return mContext;
2117     }
2118 
2119     Context getSystemUiContext() {
2120         return mUiContext;
2121     }
2122 
2123     private int getNavigationBarWidth(int rotation, int uiMode) {
2124         if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2125             return mNavigationBarWidthForRotationInCarMode[rotation];
2126         } else {
2127             return mNavigationBarWidthForRotationDefault[rotation];
2128         }
2129     }
2130 
2131     void notifyDisplayReady() {
2132         mHandler.post(() -> {
2133             final int displayId = getDisplayId();
2134             getStatusBarManagerInternal().onDisplayReady(displayId);
2135             final WallpaperManagerInternal wpMgr = LocalServices
2136                     .getService(WallpaperManagerInternal.class);
2137             if (wpMgr != null) {
2138                 wpMgr.onDisplayReady(displayId);
2139             }
2140         });
2141     }
2142 
2143     /**
2144      * Return the display width available after excluding any screen
2145      * decorations that could never be removed in Honeycomb. That is, system bar or
2146      * button bar.
2147      */
2148     public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2149             DisplayCutout displayCutout) {
2150         int width = fullWidth;
2151         if (hasNavigationBar()) {
2152             final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2153             if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
2154                 width -= getNavigationBarWidth(rotation, uiMode);
2155             }
2156         }
2157         if (displayCutout != null) {
2158             width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
2159         }
2160         return width;
2161     }
2162 
2163     private int getNavigationBarHeight(int rotation, int uiMode) {
2164         if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2165             return mNavigationBarHeightForRotationInCarMode[rotation];
2166         } else {
2167             return mNavigationBarHeightForRotationDefault[rotation];
2168         }
2169     }
2170 
2171     /**
2172      * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that
2173      * is used for spacing to show additional buttons on the navigation bar (such as the ime
2174      * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible
2175      * height that we send to the app as content insets that can be smaller.
2176      * <p>
2177      * In car mode it will return the same height as {@link #getNavigationBarHeight}
2178      *
2179      * @param rotation specifies rotation to return dimension from
2180      * @param uiMode to determine if in car mode
2181      * @return navigation bar frame height
2182      */
2183     private int getNavigationBarFrameHeight(int rotation, int uiMode) {
2184         if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2185             return mNavigationBarHeightForRotationInCarMode[rotation];
2186         } else {
2187             return mNavigationBarFrameHeightForRotationDefault[rotation];
2188         }
2189     }
2190 
2191     /**
2192      * Return the display height available after excluding any screen
2193      * decorations that could never be removed in Honeycomb. That is, system bar or
2194      * button bar.
2195      */
2196     public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2197             DisplayCutout displayCutout) {
2198         int height = fullHeight;
2199         if (hasNavigationBar()) {
2200             final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2201             if (navBarPosition == NAV_BAR_BOTTOM) {
2202                 height -= getNavigationBarHeight(rotation, uiMode);
2203             }
2204         }
2205         if (displayCutout != null) {
2206             height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
2207         }
2208         return height;
2209     }
2210 
2211     /**
2212      * Return the available screen width that we should report for the
2213      * configuration.  This must be no larger than
2214      * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller
2215      * than that to account for more transient decoration like a status bar.
2216      */
2217     public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2218             DisplayCutout displayCutout) {
2219         return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout);
2220     }
2221 
2222     /**
2223      * Return the available screen height that we should report for the
2224      * configuration.  This must be no larger than
2225      * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller
2226      * than that to account for more transient decoration like a status bar.
2227      */
2228     public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2229             DisplayCutout displayCutout) {
2230         // There is a separate status bar at the top of the display.  We don't count that as part
2231         // of the fixed decor, since it can hide; however, for purposes of configurations,
2232         // we do want to exclude it since applications can't generally use that part
2233         // of the screen.
2234         int statusBarHeight = mStatusBarHeightForRotation[rotation];
2235         if (displayCutout != null) {
2236             // If there is a cutout, it may already have accounted for some part of the status
2237             // bar height.
2238             statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
2239         }
2240         return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
2241                 - statusBarHeight;
2242     }
2243 
2244     /**
2245      * Return corner radius in pixels that should be used on windows in order to cover the display.
2246      *
2247      * The radius is only valid for internal displays, since the corner radius of external displays
2248      * is not known at build time when window corners are configured.
2249      */
2250     float getWindowCornerRadius() {
2251         return mDisplayContent.getDisplay().getType() == TYPE_INTERNAL
2252                 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f;
2253     }
2254 
2255     boolean isShowingDreamLw() {
2256         return mShowingDream;
2257     }
2258 
2259     /**
2260      * Calculates the stable insets if we already have the non-decor insets.
2261      *
2262      * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
2263      * @param rotation The current display rotation.
2264      */
2265     void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
2266         inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
2267     }
2268 
2269     /**
2270      * Calculates the stable insets without running a layout.
2271      *
2272      * @param displayRotation the current display rotation
2273      * @param displayWidth the current display width
2274      * @param displayHeight the current display height
2275      * @param displayCutout the current display cutout
2276      * @param outInsets the insets to return
2277      */
2278     public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2279             DisplayCutout displayCutout, Rect outInsets) {
2280         outInsets.setEmpty();
2281 
2282         // Navigation bar and status bar.
2283         getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
2284         convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
2285     }
2286 
2287     /**
2288      * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
2289      * bar or button bar. See {@link #getNonDecorDisplayWidth}.
2290      *
2291      * @param displayRotation the current display rotation
2292      * @param displayWidth the current display width
2293      * @param displayHeight the current display height
2294      * @param displayCutout the current display cutout
2295      * @param outInsets the insets to return
2296      */
2297     public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2298             DisplayCutout displayCutout, Rect outInsets) {
2299         outInsets.setEmpty();
2300 
2301         // Only navigation bar
2302         if (hasNavigationBar()) {
2303             final int uiMode = mService.mPolicy.getUiMode();
2304             int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
2305             if (position == NAV_BAR_BOTTOM) {
2306                 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
2307             } else if (position == NAV_BAR_RIGHT) {
2308                 outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
2309             } else if (position == NAV_BAR_LEFT) {
2310                 outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
2311             }
2312         }
2313 
2314         if (displayCutout != null) {
2315             outInsets.left += displayCutout.getSafeInsetLeft();
2316             outInsets.top += displayCutout.getSafeInsetTop();
2317             outInsets.right += displayCutout.getSafeInsetRight();
2318             outInsets.bottom += displayCutout.getSafeInsetBottom();
2319         }
2320     }
2321 
2322     /**
2323      * @see IWindowManager#setForwardedInsets
2324      */
2325     public void setForwardedInsets(@NonNull Insets forwardedInsets) {
2326         mForwardedInsets = forwardedInsets;
2327     }
2328 
2329     @NonNull
2330     public Insets getForwardedInsets() {
2331         return mForwardedInsets;
2332     }
2333 
2334     @NavigationBarPosition
2335     int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
2336         if (navigationBarCanMove() && displayWidth > displayHeight) {
2337             if (displayRotation == Surface.ROTATION_270) {
2338                 return NAV_BAR_LEFT;
2339             } else if (displayRotation == Surface.ROTATION_90) {
2340                 return NAV_BAR_RIGHT;
2341             }
2342         }
2343         return NAV_BAR_BOTTOM;
2344     }
2345 
2346     /**
2347      * @return The side of the screen where navigation bar is positioned.
2348      * @see WindowManagerPolicyConstants#NAV_BAR_LEFT
2349      * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT
2350      * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM
2351      */
2352     @NavigationBarPosition
2353     public int getNavBarPosition() {
2354         return mNavigationBarPosition;
2355     }
2356 
2357     @WindowManagerPolicy.AltBarPosition
2358     int getAlternateStatusBarPosition() {
2359         return mStatusBarAltPosition;
2360     }
2361 
2362     @WindowManagerPolicy.AltBarPosition
2363     int getAlternateNavBarPosition() {
2364         return mNavigationBarAltPosition;
2365     }
2366 
2367     /**
2368      * A new window has been focused.
2369      */
2370     public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
2371         mFocusedWindow = newFocus;
2372         mLastFocusedWindow = lastFocus;
2373         if (mDisplayContent.isDefaultDisplay) {
2374             mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
2375         }
2376         if (updateSystemUiVisibilityLw()) {
2377             // If the navigation bar has been hidden or shown, we need to do another
2378             // layout pass to update that window.
2379             return FINISH_LAYOUT_REDO_LAYOUT;
2380         }
2381         return 0;
2382     }
2383 
2384     private void requestTransientBars(WindowState swipeTarget) {
2385         if (!mService.mPolicy.isUserSetupComplete()) {
2386             // Swipe-up for navigation bar is disabled during setup
2387             return;
2388         }
2389         final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
2390         final InsetsControlTarget controlTarget = provider != null
2391                 ? provider.getControlTarget() : null;
2392 
2393         if (controlTarget == null || controlTarget == getNotificationShade()) {
2394             // No transient mode on lockscreen (in notification shade window).
2395             return;
2396         }
2397 
2398         final @InsetsType int restorePositionTypes =
2399                 (controlTarget.getRequestedVisibility(ITYPE_NAVIGATION_BAR)
2400                         ? Type.navigationBars() : 0)
2401                 | (controlTarget.getRequestedVisibility(ITYPE_STATUS_BAR)
2402                         ? Type.statusBars() : 0)
2403                 | (mExtraNavBarAlt != null && controlTarget.getRequestedVisibility(
2404                                 ITYPE_EXTRA_NAVIGATION_BAR)
2405                         ? Type.navigationBars() : 0)
2406                 | (mClimateBarAlt != null && controlTarget.getRequestedVisibility(
2407                                 ITYPE_CLIMATE_BAR)
2408                         ? Type.statusBars() : 0);
2409 
2410         if (swipeTarget == mNavigationBar
2411                 && (restorePositionTypes & Type.navigationBars()) != 0) {
2412             // Don't show status bar when swiping on already visible navigation bar.
2413             // But restore the position of navigation bar if it has been moved by the control
2414             // target.
2415             controlTarget.showInsets(Type.navigationBars(), false);
2416             return;
2417         }
2418 
2419         if (controlTarget.canShowTransient()) {
2420             // Show transient bars if they are hidden; restore position if they are visible.
2421             mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE);
2422             controlTarget.showInsets(restorePositionTypes, false);
2423         } else {
2424             // Restore visibilities and positions of system bars.
2425             controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false);
2426             // To further allow the pull-down-from-the-top gesture to pull down the notification
2427             // shade as a consistent motion, we reroute the touch events here from the currently
2428             // touched window to the status bar after making it visible.
2429             if (swipeTarget == mStatusBar) {
2430                 final boolean transferred = mStatusBar.transferTouch();
2431                 if (!transferred) {
2432                     Slog.i(TAG, "Could not transfer touch to the status bar");
2433                 }
2434             }
2435         }
2436         mImmersiveModeConfirmation.confirmCurrentPrompt();
2437     }
2438 
2439     private void disposeInputConsumer(EventReceiverInputConsumer inputConsumer) {
2440         if (inputConsumer != null) {
2441             inputConsumer.dispose();
2442         }
2443     }
2444 
2445     boolean isKeyguardShowing() {
2446         return mService.mPolicy.isKeyguardShowing();
2447     }
2448     private boolean isKeyguardOccluded() {
2449         // TODO (b/113840485): Handle per display keyguard.
2450         return mService.mPolicy.isKeyguardOccluded();
2451     }
2452 
2453     InsetsPolicy getInsetsPolicy() {
2454         return mDisplayContent.getInsetsPolicy();
2455     }
2456 
2457     void resetSystemUiVisibilityLw() {
2458         mLastDisableFlags = 0;
2459         updateSystemUiVisibilityLw();
2460     }
2461 
2462     /**
2463      * @return {@code true} if the update may affect the layout.
2464      */
2465     boolean updateSystemUiVisibilityLw() {
2466         // If there is no window focused, there will be nobody to handle the events
2467         // anyway, so just hang on in whatever state we're in until things settle down.
2468         WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
2469                 : mTopFullscreenOpaqueWindowState;
2470         if (winCandidate == null) {
2471             return false;
2472         }
2473 
2474         // The immersive mode confirmation should never affect the system bar visibility, otherwise
2475         // it will unhide the navigation bar and hide itself.
2476         if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
2477 
2478             // The immersive mode confirmation took the focus from mLastFocusedWindow which was
2479             // controlling the system ui visibility. So if mLastFocusedWindow can still receive
2480             // keys, we let it keep controlling the visibility.
2481             final boolean lastFocusCanReceiveKeys =
2482                     (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
2483             winCandidate = isKeyguardShowing() && !isKeyguardOccluded() ? mNotificationShade
2484                     : lastFocusCanReceiveKeys ? mLastFocusedWindow
2485                             : mTopFullscreenOpaqueWindowState;
2486             if (winCandidate == null) {
2487                 return false;
2488             }
2489         }
2490         final WindowState win = winCandidate;
2491         mSystemUiControllingWindow = win;
2492 
2493         mDisplayContent.getInsetsPolicy().updateBarControlTarget(win);
2494 
2495         final boolean inSplitScreen =
2496                 mService.mRoot.getDefaultTaskDisplayArea().isSplitScreenModeActivated();
2497         if (inSplitScreen) {
2498             mService.getRootTaskBounds(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
2499                     mDockedRootTaskBounds);
2500         } else {
2501             mDockedRootTaskBounds.setEmpty();
2502         }
2503         mService.getRootTaskBounds(inSplitScreen ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
2504                         : WINDOWING_MODE_FULLSCREEN,
2505                 ACTIVITY_TYPE_UNDEFINED, mNonDockedRootTaskBounds);
2506         final int fullscreenAppearance = getStatusBarAppearance(mTopFullscreenOpaqueWindowState,
2507                 mTopFullscreenOpaqueOrDimmingWindowState);
2508         final int dockedAppearance = getStatusBarAppearance(mTopDockedOpaqueWindowState,
2509                 mTopDockedOpaqueOrDimmingWindowState);
2510         final int disableFlags = win.getDisableFlags();
2511         final int opaqueAppearance = updateSystemBarsLw(win, disableFlags);
2512         final WindowState navColorWin = chooseNavigationColorWindowLw(
2513                 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
2514                 mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
2515         final boolean isNavbarColorManagedByIme =
2516                 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
2517         final int appearance = updateLightNavigationBarLw(
2518                 win.mAttrs.insetsFlags.appearance, mTopFullscreenOpaqueWindowState,
2519                 mTopFullscreenOpaqueOrDimmingWindowState,
2520                 mDisplayContent.mInputMethodWindow, navColorWin) | opaqueAppearance;
2521         final int behavior = win.mAttrs.insetsFlags.behavior;
2522         final boolean isFullscreen = !win.getRequestedVisibility(ITYPE_STATUS_BAR)
2523                 || !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR);
2524         if (mLastDisableFlags == disableFlags
2525                 && mLastAppearance == appearance
2526                 && mLastFullscreenAppearance == fullscreenAppearance
2527                 && mLastDockedAppearance == dockedAppearance
2528                 && mLastBehavior == behavior
2529                 && mLastFocusIsFullscreen == isFullscreen
2530                 && mLastNonDockedRootTaskBounds.equals(mNonDockedRootTaskBounds)
2531                 && mLastDockedRootTaskBounds.equals(mDockedRootTaskBounds)) {
2532             return false;
2533         }
2534         if (mDisplayContent.isDefaultDisplay && mLastFocusIsFullscreen != isFullscreen
2535                 && ((mLastAppearance ^ appearance) & APPEARANCE_LOW_PROFILE_BARS) != 0) {
2536             mService.mInputManager.setSystemUiLightsOut(
2537                     isFullscreen || (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0);
2538         }
2539         mLastDisableFlags = disableFlags;
2540         mLastAppearance = appearance;
2541         mLastFullscreenAppearance = fullscreenAppearance;
2542         mLastDockedAppearance = dockedAppearance;
2543         mLastBehavior = behavior;
2544         mLastFocusIsFullscreen = isFullscreen;
2545         mLastNonDockedRootTaskBounds.set(mNonDockedRootTaskBounds);
2546         mLastDockedRootTaskBounds.set(mDockedRootTaskBounds);
2547         final Rect fullscreenRootTaskBounds = new Rect(mNonDockedRootTaskBounds);
2548         final Rect dockedRootTaskBounds = new Rect(mDockedRootTaskBounds);
2549         final AppearanceRegion[] appearanceRegions = inSplitScreen
2550                 ? new AppearanceRegion[]{
2551                         new AppearanceRegion(fullscreenAppearance, fullscreenRootTaskBounds),
2552                         new AppearanceRegion(dockedAppearance, dockedRootTaskBounds)}
2553                 : new AppearanceRegion[]{
2554                         new AppearanceRegion(fullscreenAppearance, fullscreenRootTaskBounds)};
2555         String cause = win.toString();
2556         mHandler.post(() -> {
2557             StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
2558             if (statusBar != null) {
2559                 final int displayId = getDisplayId();
2560                 statusBar.setDisableFlags(displayId, disableFlags, cause);
2561                 statusBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
2562                         isNavbarColorManagedByIme, behavior, isFullscreen);
2563 
2564             }
2565         });
2566         return true;
2567     }
2568 
2569     private int getStatusBarAppearance(WindowState opaque, WindowState opaqueOrDimming) {
2570         final boolean onKeyguard = isKeyguardShowing() && !isKeyguardOccluded();
2571         final WindowState colorWin = onKeyguard ? mNotificationShade : opaqueOrDimming;
2572         return isLightBarAllowed(colorWin, ITYPE_STATUS_BAR) && (colorWin == opaque || onKeyguard)
2573                 ? (colorWin.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_STATUS_BARS)
2574                 : 0;
2575     }
2576 
2577     @VisibleForTesting
2578     @Nullable
2579     static WindowState chooseNavigationColorWindowLw(WindowState opaque,
2580             WindowState opaqueOrDimming, WindowState imeWindow,
2581             @NavigationBarPosition int navBarPosition) {
2582         // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
2583         // window can be navigation color window.
2584         final boolean imeWindowCanNavColorWindow = imeWindow != null
2585                 && imeWindow.isVisible()
2586                 && navBarPosition == NAV_BAR_BOTTOM
2587                 && (imeWindow.mAttrs.flags
2588                         & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
2589 
2590         if (opaque != null && opaqueOrDimming == opaque) {
2591             // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
2592             // unless IME window is also eligible, since currently the IME window is always show
2593             // above the opaque fullscreen app window, regardless of the IME target window.
2594             // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
2595             return imeWindowCanNavColorWindow ? imeWindow : opaque;
2596         }
2597 
2598         if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
2599             // No dimming window is involved. Determine the result only with the IME window.
2600             return imeWindowCanNavColorWindow ? imeWindow : null;
2601         }
2602 
2603         if (!imeWindowCanNavColorWindow) {
2604             // No IME window is involved. Determine the result only with opaqueOrDimming.
2605             return opaqueOrDimming;
2606         }
2607 
2608         // The IME window and the dimming window are competing.  Check if the dimming window can be
2609         // IME target or not.
2610         if (LayoutParams.mayUseInputMethod(opaqueOrDimming.mAttrs.flags)) {
2611             // The IME window is above the dimming window.
2612             return imeWindow;
2613         } else {
2614             // The dimming window is above the IME window.
2615             return opaqueOrDimming;
2616         }
2617     }
2618 
2619     @VisibleForTesting
2620     int updateLightNavigationBarLw(int appearance, WindowState opaque,
2621             WindowState opaqueOrDimming, WindowState imeWindow, WindowState navColorWin) {
2622 
2623         if (navColorWin != null) {
2624             if (navColorWin == imeWindow || navColorWin == opaque) {
2625                 // Respect the light flag.
2626                 appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
2627                 appearance |= navColorWin.mAttrs.insetsFlags.appearance
2628                         & APPEARANCE_LIGHT_NAVIGATION_BARS;
2629             } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
2630                 // Clear the light flag for dimming window.
2631                 appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
2632             }
2633         }
2634         if (!isLightBarAllowed(navColorWin, ITYPE_NAVIGATION_BAR)) {
2635             appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
2636         }
2637         return appearance;
2638     }
2639 
2640     private int updateSystemBarsLw(WindowState win, int disableFlags) {
2641         final boolean dockedRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea()
2642                 .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
2643         final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
2644 
2645         // We need to force system bars when the docked root task is visible, when the freeform
2646         // root task is focused but also when we are resizing for the transitions when docked
2647         // root task visibility changes.
2648         mForceShowSystemBars = dockedRootTaskVisible || win.inFreeformWindowingMode() || resizing;
2649 
2650         int appearance = APPEARANCE_OPAQUE_NAVIGATION_BARS | APPEARANCE_OPAQUE_STATUS_BARS;
2651 
2652         appearance = configureStatusBarOpacity(appearance);
2653         appearance = configureNavBarOpacity(appearance, dockedRootTaskVisible, resizing);
2654 
2655         final boolean requestHideNavBar = !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR);
2656         final long now = SystemClock.uptimeMillis();
2657         final boolean pendingPanic = mPendingPanicGestureUptime != 0
2658                 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
2659         final DisplayPolicy defaultDisplayPolicy =
2660                 mService.getDefaultDisplayContentLocked().getDisplayPolicy();
2661         if (pendingPanic && requestHideNavBar && win != mNotificationShade
2662                 && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)
2663                 // TODO (b/111955725): Show keyguard presentation on all external displays
2664                 && defaultDisplayPolicy.isKeyguardDrawComplete()) {
2665             // The user performed the panic gesture recently, we're about to hide the bars,
2666             // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
2667             mPendingPanicGestureUptime = 0;
2668             if (!isNavBarEmpty(disableFlags)) {
2669                 mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_PANIC);
2670             }
2671         }
2672 
2673         // update navigation bar
2674         boolean oldImmersiveMode = mLastImmersiveMode;
2675         boolean newImmersiveMode = isImmersiveMode(win);
2676         if (oldImmersiveMode != newImmersiveMode) {
2677             mLastImmersiveMode = newImmersiveMode;
2678             // The immersive confirmation window should be attached to the immersive window root.
2679             final RootDisplayArea root = win.getRootDisplayArea();
2680             final int rootDisplayAreaId = root == null ? FEATURE_UNDEFINED : root.mFeatureId;
2681             mImmersiveModeConfirmation.immersiveModeChangedLw(rootDisplayAreaId, newImmersiveMode,
2682                     mService.mPolicy.isUserSetupComplete(),
2683                     isNavBarEmpty(disableFlags));
2684         }
2685 
2686         return appearance;
2687     }
2688 
2689     private boolean isLightBarAllowed(WindowState win, @InternalInsetsType int type) {
2690         if (win == null) {
2691             return false;
2692         }
2693         final InsetsSource source = win.getInsetsState().peekSource(type);
2694         return source != null && Rect.intersects(win.getFrame(), source.getFrame());
2695     }
2696 
2697     private Rect getBarContentFrameForWindow(WindowState win, int windowType) {
2698         final Rect rotatedBarFrame = win.mToken.getFixedRotationBarContentFrame(windowType);
2699         return rotatedBarFrame != null ? rotatedBarFrame : mBarContentFrames.get(windowType);
2700     }
2701 
2702     /**
2703      * @return {@code true} if bar is allowed to be fully transparent when given window is show.
2704      *
2705      * <p>Prevents showing a transparent bar over a letterboxed activity which can make
2706      * notification icons or navigation buttons unreadable due to contrast between letterbox
2707      * background and an activity. For instance, this happens when letterbox background is solid
2708      * black while activity is white. To resolve this, only semi-transparent bars are allowed to
2709      * be drawn over letterboxed activity.
2710      */
2711     @VisibleForTesting
2712     boolean isFullyTransparentAllowed(WindowState win, int windowType) {
2713         if (win == null) {
2714             return true;
2715         }
2716         return win.isFullyTransparentBarAllowed(getBarContentFrameForWindow(win, windowType));
2717     }
2718 
2719     private boolean drawsBarBackground(WindowState win) {
2720         if (win == null) {
2721             return true;
2722         }
2723 
2724         final boolean drawsSystemBars =
2725                 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
2726         final boolean forceDrawsSystemBars =
2727                 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
2728 
2729         return forceDrawsSystemBars || drawsSystemBars;
2730     }
2731 
2732     /** @return the current visibility flags with the status bar opacity related flags toggled. */
2733     private int configureStatusBarOpacity(int appearance) {
2734         final boolean fullscreenDrawsBackground =
2735                 drawsBarBackground(mTopFullscreenOpaqueWindowState);
2736         final boolean dockedDrawsBackground =
2737                 drawsBarBackground(mTopDockedOpaqueWindowState);
2738 
2739         if (fullscreenDrawsBackground && dockedDrawsBackground) {
2740             appearance &= ~APPEARANCE_OPAQUE_STATUS_BARS;
2741         }
2742 
2743         if (!isFullyTransparentAllowed(mTopFullscreenOpaqueWindowState, TYPE_STATUS_BAR)
2744                 || !isFullyTransparentAllowed(mTopDockedOpaqueWindowState, TYPE_STATUS_BAR)) {
2745             appearance |= APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS;
2746         }
2747 
2748         return appearance;
2749     }
2750 
2751     /**
2752      * @return the current visibility flags with the nav-bar opacity related flags toggled based
2753      *         on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
2754      */
2755     private int configureNavBarOpacity(int appearance, boolean dockedRootTaskVisible,
2756             boolean isDockedDividerResizing) {
2757         final boolean freeformRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea()
2758                 .isRootTaskVisible(WINDOWING_MODE_FREEFORM);
2759         final boolean fullscreenDrawsBackground =
2760                 drawsBarBackground(mTopFullscreenOpaqueWindowState);
2761         final boolean dockedDrawsBackground =
2762                 drawsBarBackground(mTopDockedOpaqueWindowState);
2763 
2764         if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
2765             if (fullscreenDrawsBackground && dockedDrawsBackground) {
2766                 appearance = clearNavBarOpaqueFlag(appearance);
2767             } else if (dockedRootTaskVisible) {
2768                 appearance = setNavBarOpaqueFlag(appearance);
2769             }
2770         } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
2771             if (dockedRootTaskVisible || freeformRootTaskVisible || isDockedDividerResizing) {
2772                 if (mIsFreeformWindowOverlappingWithNavBar) {
2773                     appearance = clearNavBarOpaqueFlag(appearance);
2774                 } else {
2775                     appearance = setNavBarOpaqueFlag(appearance);
2776                 }
2777             } else if (fullscreenDrawsBackground) {
2778                 appearance = clearNavBarOpaqueFlag(appearance);
2779             }
2780         } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
2781             if (isDockedDividerResizing) {
2782                 appearance = setNavBarOpaqueFlag(appearance);
2783             } else if (freeformRootTaskVisible) {
2784                 appearance = clearNavBarOpaqueFlag(appearance);
2785             } else {
2786                 appearance = setNavBarOpaqueFlag(appearance);
2787             }
2788         }
2789 
2790         if (!isFullyTransparentAllowed(mTopFullscreenOpaqueWindowState, TYPE_NAVIGATION_BAR)
2791                 || !isFullyTransparentAllowed(mTopDockedOpaqueWindowState, TYPE_NAVIGATION_BAR)) {
2792             appearance |= APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS;
2793         }
2794 
2795         return appearance;
2796     }
2797 
2798     private int setNavBarOpaqueFlag(int appearance) {
2799         return appearance | APPEARANCE_OPAQUE_NAVIGATION_BARS;
2800     }
2801 
2802     private int clearNavBarOpaqueFlag(int appearance) {
2803         return appearance & ~APPEARANCE_OPAQUE_NAVIGATION_BARS;
2804     }
2805 
2806     private boolean isImmersiveMode(WindowState win) {
2807         if (win == null) {
2808             return false;
2809         }
2810         return getNavigationBar() != null
2811                 && canHideNavigationBar()
2812                 && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)
2813                 && win != getNotificationShade()
2814                 && !win.isActivityTypeDream();
2815     }
2816 
2817     /**
2818      * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
2819      */
2820     private boolean canHideNavigationBar() {
2821         return hasNavigationBar();
2822     }
2823 
2824     private static boolean isNavBarEmpty(int systemUiFlags) {
2825         final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
2826                 | View.STATUS_BAR_DISABLE_BACK
2827                 | View.STATUS_BAR_DISABLE_RECENT);
2828 
2829         return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
2830     }
2831 
2832     private final Runnable mHiddenNavPanic = new Runnable() {
2833         @Override
2834         public void run() {
2835             synchronized (mLock) {
2836                 if (!mService.mPolicy.isUserSetupComplete()) {
2837                     // Swipe-up for navigation bar is disabled during setup
2838                     return;
2839                 }
2840                 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
2841                 updateSystemUiVisibilityLw();
2842             }
2843         }
2844     };
2845 
2846     void onPowerKeyDown(boolean isScreenOn) {
2847         // Detect user pressing the power button in panic when an application has
2848         // taken over the whole screen.
2849         boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
2850                 SystemClock.elapsedRealtime(), isImmersiveMode(mSystemUiControllingWindow),
2851                 isNavBarEmpty(mLastDisableFlags));
2852         if (panic) {
2853             mHandler.post(mHiddenNavPanic);
2854         }
2855     }
2856 
2857     void onVrStateChangedLw(boolean enabled) {
2858         mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
2859     }
2860 
2861     /**
2862      * Called when the state of lock task mode changes. This should be used to disable immersive
2863      * mode confirmation.
2864      *
2865      * @param lockTaskState the new lock task mode state. One of
2866      *                      {@link ActivityManager#LOCK_TASK_MODE_NONE},
2867      *                      {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
2868      *                      {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
2869      */
2870     public void onLockTaskStateChangedLw(int lockTaskState) {
2871         mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
2872     }
2873 
2874     boolean onSystemUiSettingsChanged() {
2875         return mImmersiveModeConfirmation.onSettingChanged(mService.mCurrentUserId);
2876     }
2877 
2878     /**
2879      * Request a screenshot be taken.
2880      *
2881      * @param screenshotType The type of screenshot, for example either
2882      *                       {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
2883      *                       {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
2884      * @param source Where the screenshot originated from (see WindowManager.ScreenshotSource)
2885      */
2886     public void takeScreenshot(int screenshotType, int source) {
2887         if (mScreenshotHelper != null) {
2888             mScreenshotHelper.takeScreenshot(screenshotType,
2889                     getStatusBar() != null && getStatusBar().isVisible(),
2890                     getNavigationBar() != null && getNavigationBar().isVisible(),
2891                     source, mHandler, null /* completionConsumer */);
2892         }
2893     }
2894 
2895     RefreshRatePolicy getRefreshRatePolicy() {
2896         return mRefreshRatePolicy;
2897     }
2898 
2899     void dump(String prefix, PrintWriter pw) {
2900         pw.print(prefix); pw.println("DisplayPolicy");
2901         prefix += "  ";
2902         pw.print(prefix);
2903         pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
2904         pw.print(" mDeskDockEnablesAccelerometer=");
2905         pw.println(mDeskDockEnablesAccelerometer);
2906         pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
2907         pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
2908         pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
2909         pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
2910         pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
2911         pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
2912         pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
2913         pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
2914         if (mLastDisableFlags != 0) {
2915             pw.print(prefix); pw.print("mLastDisableFlags=0x");
2916             pw.println(Integer.toHexString(mLastDisableFlags));
2917         }
2918         if (mLastAppearance != 0) {
2919             pw.print(prefix); pw.print("mLastAppearance=");
2920             pw.println(ViewDebug.flagsToString(InsetsFlags.class, "appearance", mLastAppearance));
2921         }
2922         if (mLastBehavior != 0) {
2923             pw.print(prefix); pw.print("mLastBehavior=");
2924             pw.println(ViewDebug.flagsToString(InsetsFlags.class, "behavior", mLastBehavior));
2925         }
2926         pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
2927         pw.print(" mDreamingLockscreen="); pw.println(mDreamingLockscreen);
2928         if (mStatusBar != null) {
2929             pw.print(prefix); pw.print("mStatusBar="); pw.println(mStatusBar);
2930         }
2931         if (mStatusBarAlt != null) {
2932             pw.print(prefix); pw.print("mStatusBarAlt="); pw.println(mStatusBarAlt);
2933             pw.print(prefix); pw.print("mStatusBarAltPosition=");
2934             pw.println(mStatusBarAltPosition);
2935         }
2936         if (mNotificationShade != null) {
2937             pw.print(prefix); pw.print("mExpandedPanel="); pw.println(mNotificationShade);
2938         }
2939         pw.print(prefix); pw.print("isKeyguardShowing="); pw.println(isKeyguardShowing());
2940         if (mNavigationBar != null) {
2941             pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
2942             pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
2943             pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove);
2944             pw.print(prefix); pw.print("mNavigationBarPosition=");
2945             pw.println(mNavigationBarPosition);
2946         }
2947         if (mNavigationBarAlt != null) {
2948             pw.print(prefix); pw.print("mNavigationBarAlt="); pw.println(mNavigationBarAlt);
2949             pw.print(prefix); pw.print("mNavigationBarAltPosition=");
2950             pw.println(mNavigationBarAltPosition);
2951         }
2952         if (mClimateBarAlt != null) {
2953             pw.print(prefix); pw.print("mClimateBarAlt="); pw.println(mClimateBarAlt);
2954             pw.print(prefix); pw.print("mClimateBarAltPosition=");
2955             pw.println(mClimateBarAltPosition);
2956         }
2957         if (mExtraNavBarAlt != null) {
2958             pw.print(prefix); pw.print("mExtraNavBarAlt="); pw.println(mExtraNavBarAlt);
2959             pw.print(prefix); pw.print("mExtraNavBarAltPosition=");
2960             pw.println(mExtraNavBarAltPosition);
2961         }
2962         if (mFocusedWindow != null) {
2963             pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
2964         }
2965         if (mTopFullscreenOpaqueWindowState != null) {
2966             pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
2967             pw.println(mTopFullscreenOpaqueWindowState);
2968         }
2969         if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
2970             pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
2971             pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
2972         }
2973         if (mForcingShowNavBar) {
2974             pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar);
2975             pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
2976             pw.println(mForcingShowNavBarLayer);
2977         }
2978         pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
2979         pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
2980         pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
2981         pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars=");
2982         pw.println(mDisplayContent.getInsetsPolicy().getRemoteInsetsControllerControlsSystemBars());
2983 
2984         pw.print(prefix); pw.println("Looper state:");
2985         mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + "  ");
2986     }
2987 
2988     private boolean supportsPointerLocation() {
2989         return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate();
2990     }
2991 
2992     void setPointerLocationEnabled(boolean pointerLocationEnabled) {
2993         if (!supportsPointerLocation()) {
2994             return;
2995         }
2996 
2997         mHandler.sendEmptyMessage(pointerLocationEnabled
2998                 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
2999     }
3000 
3001     private void enablePointerLocation() {
3002         if (mPointerLocationView != null) {
3003             return;
3004         }
3005 
3006         mPointerLocationView = new PointerLocationView(mContext);
3007         mPointerLocationView.setPrintCoords(false);
3008         final WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
3009         lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
3010         lp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
3011                 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
3012                 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
3013         lp.setFitInsetsTypes(0);
3014         lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3015         if (ActivityManager.isHighEndGfx()) {
3016             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
3017             lp.privateFlags |=
3018                     WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
3019         }
3020         lp.format = PixelFormat.TRANSLUCENT;
3021         lp.setTitle("PointerLocation - display " + getDisplayId());
3022         lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
3023         final WindowManager wm = mContext.getSystemService(WindowManager.class);
3024         wm.addView(mPointerLocationView, lp);
3025         mDisplayContent.registerPointerEventListener(mPointerLocationView);
3026     }
3027 
3028     private void disablePointerLocation() {
3029         if (mPointerLocationView == null) {
3030             return;
3031         }
3032 
3033         mDisplayContent.unregisterPointerEventListener(mPointerLocationView);
3034         final WindowManager wm = mContext.getSystemService(WindowManager.class);
3035         wm.removeView(mPointerLocationView);
3036         mPointerLocationView = null;
3037     }
3038 
3039     /**
3040      * Check if the window could be excluded from checking if the display has content.
3041      *
3042      * @param w WindowState to check if should be excluded.
3043      * @return True if the window type is PointerLocation which is excluded.
3044      */
3045     boolean isWindowExcludedFromContent(WindowState w) {
3046         if (w != null && mPointerLocationView != null) {
3047             return w.mClient == mPointerLocationView.getWindowToken();
3048         }
3049 
3050         return false;
3051     }
3052 
3053     void release() {
3054         mHandler.post(mGestureNavigationSettingsObserver::unregister);
3055     }
3056 
3057     @VisibleForTesting
3058     static boolean isOverlappingWithNavBar(WindowState targetWindow, WindowState navBarWindow) {
3059         if (navBarWindow == null || !navBarWindow.isVisible()
3060                 || targetWindow.mActivityRecord == null || !targetWindow.isVisible()) {
3061             return false;
3062         }
3063 
3064         return Rect.intersects(targetWindow.getFrame(), navBarWindow.getFrame());
3065     }
3066 
3067     /**
3068      * @return Whether we should attach navigation bar to the app during transition.
3069      */
3070     boolean shouldAttachNavBarToAppDuringTransition() {
3071         return mShouldAttachNavBarToAppDuringTransition && mNavigationBar != null;
3072     }
3073 }
3074