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