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.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR;
21 import static android.view.Display.TYPE_INTERNAL;
22 import static android.view.InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE;
23 import static android.view.InsetsFrameProvider.SOURCE_CONTAINER_BOUNDS;
24 import static android.view.InsetsFrameProvider.SOURCE_DISPLAY;
25 import static android.view.InsetsFrameProvider.SOURCE_FRAME;
26 import static android.view.ViewRootImpl.CLIENT_IMMERSIVE_CONFIRMATION;
27 import static android.view.ViewRootImpl.CLIENT_TRANSIENT;
28 import static android.view.WindowInsetsController.APPEARANCE_FORCE_LIGHT_NAVIGATION_BARS;
29 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
30 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
31 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
32 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
33 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS;
34 import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS;
35 import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS;
36 import static android.view.WindowLayout.UNSPECIFIED_LENGTH;
37 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
38 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
39 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
40 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
41 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
42 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
43 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_CONSUME_IME_INSETS;
44 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
45 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW;
46 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP;
47 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
48 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
49 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION;
50 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
51 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
52 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
53 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
54 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE;
55 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
56 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
57 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL;
58 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
59 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
60 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
61 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
62 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
63 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
64 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
65 import static android.view.WindowManagerGlobal.ADD_OKAY;
66 import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
67 import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE;
68 import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
69 import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID;
70 import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
71 import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
72 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED;
73 
74 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM;
75 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
76 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
77 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
78 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
79 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
80 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
81 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
82 
83 import android.annotation.NonNull;
84 import android.annotation.Nullable;
85 import android.annotation.Px;
86 import android.app.ActivityManager;
87 import android.app.ActivityThread;
88 import android.app.LoadedApk;
89 import android.app.ResourcesManager;
90 import android.content.Context;
91 import android.content.Intent;
92 import android.content.res.Resources;
93 import android.graphics.Insets;
94 import android.graphics.PixelFormat;
95 import android.graphics.Rect;
96 import android.graphics.Region;
97 import android.gui.DropInputMode;
98 import android.hardware.power.Boost;
99 import android.os.Handler;
100 import android.os.IBinder;
101 import android.os.Looper;
102 import android.os.Message;
103 import android.os.SystemClock;
104 import android.os.SystemProperties;
105 import android.os.Trace;
106 import android.os.UserHandle;
107 import android.util.ArraySet;
108 import android.util.Slog;
109 import android.util.SparseArray;
110 import android.view.DisplayInfo;
111 import android.view.Gravity;
112 import android.view.InsetsFlags;
113 import android.view.InsetsFrameProvider;
114 import android.view.InsetsSource;
115 import android.view.InsetsState;
116 import android.view.Surface;
117 import android.view.View;
118 import android.view.ViewDebug;
119 import android.view.WindowInsets;
120 import android.view.WindowInsets.Type;
121 import android.view.WindowInsets.Type.InsetsType;
122 import android.view.WindowLayout;
123 import android.view.WindowManager;
124 import android.view.WindowManager.LayoutParams;
125 import android.view.WindowManagerGlobal;
126 import android.view.accessibility.AccessibilityManager;
127 import android.window.ClientWindowFrames;
128 
129 import com.android.internal.R;
130 import com.android.internal.annotations.VisibleForTesting;
131 import com.android.internal.os.BackgroundThread;
132 import com.android.internal.policy.ForceShowNavBarSettingsObserver;
133 import com.android.internal.policy.GestureNavigationSettingsObserver;
134 import com.android.internal.policy.ScreenDecorationsUtils;
135 import com.android.internal.protolog.common.ProtoLog;
136 import com.android.internal.statusbar.LetterboxDetails;
137 import com.android.internal.util.ScreenshotHelper;
138 import com.android.internal.util.ScreenshotRequest;
139 import com.android.internal.util.function.TriFunction;
140 import com.android.internal.view.AppearanceRegion;
141 import com.android.internal.widget.PointerLocationView;
142 import com.android.server.LocalServices;
143 import com.android.server.UiThread;
144 import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition;
145 import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
146 import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
147 import com.android.server.statusbar.StatusBarManagerInternal;
148 import com.android.server.wallpaper.WallpaperManagerInternal;
149 import com.android.wm.shell.Flags;
150 
151 import java.io.PrintWriter;
152 import java.util.ArrayList;
153 import java.util.Arrays;
154 import java.util.Objects;
155 import java.util.function.Consumer;
156 
157 /**
158  * The policy that provides the basic behaviors and states of a display to show UI.
159  */
160 public class DisplayPolicy {
161     private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM;
162 
163     // The panic gesture may become active only after the keyguard is dismissed and the immersive
164     // app shows again. If that doesn't happen for 30s we drop the gesture.
165     private static final long PANIC_GESTURE_EXPIRATION = 30000;
166 
167     // Controls navigation bar opacity depending on which workspace root tasks are currently
168     // visible.
169     // Nav bar is always opaque when either the freeform root task or docked root task is visible.
170     private static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0;
171     // Nav bar is always translucent when the freeform rootTask is visible, otherwise always opaque.
172     private static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
173     // Nav bar is never forced opaque.
174     private static final int NAV_BAR_FORCE_TRANSPARENT = 2;
175 
176     /** Don't apply window animation (see {@link #selectAnimation}). */
177     static final int ANIMATION_NONE = -1;
178     /** Use the transit animation in style resource (see {@link #selectAnimation}). */
179     static final int ANIMATION_STYLEABLE = 0;
180 
181     private static final int SHOW_TYPES_FOR_SWIPE = Type.statusBars() | Type.navigationBars();
182     private static final int SHOW_TYPES_FOR_PANIC = Type.navigationBars();
183 
184     private static final int INSETS_OVERRIDE_INDEX_INVALID = -1;
185 
186     // TODO(b/266197298): Remove this by a more general protocol from the insets providers.
187     private static final boolean USE_CACHED_INSETS_FOR_DISPLAY_SWITCH =
188             SystemProperties.getBoolean("persist.wm.debug.cached_insets_switch", true);
189 
190     private final WindowManagerService mService;
191     private final Context mContext;
192     private final Context mUiContext;
193     private final DisplayContent mDisplayContent;
194     private final Object mLock;
195     private final Handler mHandler;
196 
197     private Resources mCurrentUserResources;
198 
199     private final boolean mCarDockEnablesAccelerometer;
200     private final boolean mDeskDockEnablesAccelerometer;
201     private final AccessibilityManager mAccessibilityManager;
202     private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
203     private final ScreenshotHelper mScreenshotHelper;
204 
205     private final Object mServiceAcquireLock = new Object();
206     private long mPanicTime;
207     private final long mPanicThresholdMs;
208     private StatusBarManagerInternal mStatusBarManagerInternal;
209 
210     @Px
211     private int mLeftGestureInset;
212     @Px
213     private int mRightGestureInset;
214 
215     private boolean mCanSystemBarsBeShownByUser;
216 
217     /**
218      * Let remote insets controller control system bars regardless of other settings.
219      */
220     private boolean mRemoteInsetsControllerControlsSystemBars;
221 
getStatusBarManagerInternal()222     StatusBarManagerInternal getStatusBarManagerInternal() {
223         synchronized (mServiceAcquireLock) {
224             if (mStatusBarManagerInternal == null) {
225                 mStatusBarManagerInternal =
226                         LocalServices.getService(StatusBarManagerInternal.class);
227             }
228             return mStatusBarManagerInternal;
229         }
230     }
231 
232     // Will be null in client transient mode.
233     private SystemGesturesPointerEventListener mSystemGestures;
234 
235     final DecorInsets mDecorInsets;
236     /** Currently it can only be non-null when physical display switch happens. */
237     private DecorInsets.Cache mCachedDecorInsets;
238 
239     private volatile int mLidState = LID_ABSENT;
240     private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
241     private volatile boolean mHdmiPlugged;
242 
243     private volatile boolean mHasStatusBar;
244     private volatile boolean mHasNavigationBar;
245     // Can the navigation bar ever move to the side?
246     private volatile boolean mNavigationBarCanMove;
247     private volatile boolean mNavigationBarAlwaysShowOnSideGesture;
248 
249     // Written by vr manager thread, only read in this class.
250     private volatile boolean mPersistentVrModeEnabled;
251 
252     private volatile boolean mAwake;
253     private volatile boolean mScreenOnEarly;
254     private volatile boolean mScreenOnFully;
255     private volatile ScreenOnListener mScreenOnListener;
256 
257     private volatile boolean mKeyguardDrawComplete;
258     private volatile boolean mWindowManagerDrawComplete;
259 
260     private boolean mImmersiveConfirmationWindowExists;
261 
262     private WindowState mStatusBar = null;
263     private volatile WindowState mNotificationShade;
264     private WindowState mNavigationBar = null;
265     @NavigationBarPosition
266     private int mNavigationBarPosition = NAV_BAR_BOTTOM;
267 
268     private final ArraySet<WindowState> mInsetsSourceWindowsExceptIme = new ArraySet<>();
269 
270     /** Apps which are controlling the appearance of system bars */
271     private final ArraySet<ActivityRecord> mSystemBarColorApps = new ArraySet<>();
272 
273     /** Apps which are relaunching and were controlling the appearance of system bars */
274     private final ArraySet<ActivityRecord> mRelaunchingSystemBarColorApps = new ArraySet<>();
275 
276     private boolean mIsFreeformWindowOverlappingWithNavBar;
277 
278     private @InsetsType int mForciblyShownTypes;
279 
280     private boolean mImeInsetsConsumed;
281 
282     private boolean mIsImmersiveMode;
283 
284     // The windows we were told about in focusChanged.
285     private WindowState mFocusedWindow;
286     private WindowState mLastFocusedWindow;
287 
288     private WindowState mSystemUiControllingWindow;
289 
290     // Candidate window to determine the color of navigation bar. The window needs to be top
291     // fullscreen-app windows or dim layers that are intersecting with the window frame of
292     // navigation bar.
293     private WindowState mNavBarColorWindowCandidate;
294 
295     // Candidate window to determine opacity and background of translucent navigation bar.
296     // The window frame must intersect the frame of navigation bar.
297     private WindowState mNavBarBackgroundWindowCandidate;
298 
299     /**
300      * A collection of {@link AppearanceRegion} to indicate that which region of status bar applies
301      * which appearance.
302      */
303     private final ArrayList<AppearanceRegion> mStatusBarAppearanceRegionList = new ArrayList<>();
304 
305     /**
306      * Windows to determine opacity and background of translucent status bar. The window needs to be
307      * opaque
308      */
309     private final ArrayList<WindowState> mStatusBarBackgroundWindows = new ArrayList<>();
310 
311     /**
312      * A collection of {@link LetterboxDetails} of all visible activities to be sent to SysUI in
313      * order to determine status bar appearance
314      */
315     private final ArrayList<LetterboxDetails> mLetterboxDetails = new ArrayList<>();
316 
317     private String mFocusedApp;
318     private int mLastDisableFlags;
319     private int mLastAppearance;
320     private int mLastBehavior;
321     private int mLastRequestedVisibleTypes = Type.defaultVisible();
322     private AppearanceRegion[] mLastStatusBarAppearanceRegions;
323     private LetterboxDetails[] mLastLetterboxDetails;
324 
325     /** The union of checked bounds while building {@link #mStatusBarAppearanceRegionList}. */
326     private final Rect mStatusBarColorCheckedBounds = new Rect();
327 
328     /** The union of checked bounds while fetching {@link #mStatusBarBackgroundWindows}. */
329     private final Rect mStatusBarBackgroundCheckedBounds = new Rect();
330 
331     // What we last reported to input dispatcher about whether the focused window is fullscreen.
332     private boolean mLastFocusIsFullscreen = false;
333 
334     // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
335     private long mPendingPanicGestureUptime;
336 
337     private static final Rect sTmpRect = new Rect();
338     private static final Rect sTmpRect2 = new Rect();
339     private static final Rect sTmpDisplayCutoutSafe = new Rect();
340     private static final ClientWindowFrames sTmpClientFrames = new ClientWindowFrames();
341 
342     private final WindowLayout mWindowLayout = new WindowLayout();
343 
344     private WindowState mTopFullscreenOpaqueWindowState;
345     private boolean mTopIsFullscreen;
346     private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
347 
348     /**
349      * Windows that provides gesture insets. If multiple windows provide gesture insets at the same
350      * side, the window with the highest z-order wins.
351      */
352     private WindowState mLeftGestureHost;
353     private WindowState mTopGestureHost;
354     private WindowState mRightGestureHost;
355     private WindowState mBottomGestureHost;
356 
357     private boolean mShowingDream;
358     private boolean mLastShowingDream;
359     private boolean mDreamingLockscreen;
360     private boolean mAllowLockscreenWhenOn;
361 
362     private PointerLocationView mPointerLocationView;
363 
364     private RefreshRatePolicy mRefreshRatePolicy;
365 
366     /**
367      * If true, attach the navigation bar to the current transition app.
368      * The value is read from config_attachNavBarToAppDuringTransition and could be overlaid by RRO
369      * when the navigation bar mode is changed.
370      */
371     private boolean mShouldAttachNavBarToAppDuringTransition;
372 
373     // -------- PolicyHandler --------
374     private static final int MSG_ENABLE_POINTER_LOCATION = 4;
375     private static final int MSG_DISABLE_POINTER_LOCATION = 5;
376 
377     private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver;
378 
379     private final WindowManagerInternal.AppTransitionListener mAppTransitionListener;
380 
381     private final ForceShowNavBarSettingsObserver mForceShowNavBarSettingsObserver;
382     private boolean mForceShowNavigationBarEnabled;
383 
384     private class PolicyHandler extends Handler {
385 
PolicyHandler(Looper looper)386         PolicyHandler(Looper looper) {
387             super(looper);
388         }
389 
390         @Override
handleMessage(Message msg)391         public void handleMessage(Message msg) {
392             switch (msg.what) {
393                 case MSG_ENABLE_POINTER_LOCATION:
394                     enablePointerLocation();
395                     break;
396                 case MSG_DISABLE_POINTER_LOCATION:
397                     disablePointerLocation();
398                     break;
399             }
400         }
401     }
402 
DisplayPolicy(WindowManagerService service, DisplayContent displayContent)403     DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
404         mService = service;
405         mContext = displayContent.isDefaultDisplay ? service.mContext
406                 : service.mContext.createDisplayContext(displayContent.getDisplay());
407         mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.getUiContext()
408                 : service.mAtmService.mSystemThread
409                         .getSystemUiContext(displayContent.getDisplayId());
410         mDisplayContent = displayContent;
411         mDecorInsets = new DecorInsets(displayContent);
412         mLock = service.getWindowManagerLock();
413 
414         final int displayId = displayContent.getDisplayId();
415 
416         final Resources r = mContext.getResources();
417         mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
418         mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
419         mCanSystemBarsBeShownByUser = !r.getBoolean(
420                 R.bool.config_remoteInsetsControllerControlsSystemBars) || r.getBoolean(
421                 R.bool.config_remoteInsetsControllerSystemBarsCanBeShownByUserAction);
422         mPanicThresholdMs = r.getInteger(R.integer.config_immersive_mode_confirmation_panic);
423 
424         mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
425                 Context.ACCESSIBILITY_SERVICE);
426         if (!displayContent.isDefaultDisplay) {
427             mAwake = true;
428             mScreenOnEarly = true;
429             mScreenOnFully = true;
430         }
431 
432         final Looper looper = UiThread.getHandler().getLooper();
433         mHandler = new PolicyHandler(looper);
434         // TODO(b/181821798) Migrate SystemGesturesPointerEventListener to use window context.
435         if (!CLIENT_TRANSIENT) {
436             SystemGesturesPointerEventListener.Callbacks gesturesPointerEventCallbacks =
437                     new SystemGesturesPointerEventListener.Callbacks() {
438 
439                 private static final long MOUSE_GESTURE_DELAY_MS = 500;
440 
441                 private Runnable mOnSwipeFromLeft = this::onSwipeFromLeft;
442                 private Runnable mOnSwipeFromTop = this::onSwipeFromTop;
443                 private Runnable mOnSwipeFromRight = this::onSwipeFromRight;
444                 private Runnable mOnSwipeFromBottom = this::onSwipeFromBottom;
445 
446                 private Insets getControllableInsets(WindowState win) {
447                     if (win == null) {
448                         return Insets.NONE;
449                     }
450                     final InsetsSourceProvider provider = win.getControllableInsetProvider();
451                     if (provider == null) {
452                         return Insets.NONE;
453                     }
454                     return provider.getSource().calculateInsets(win.getBounds(),
455                             true /* ignoreVisibility */);
456                 }
457 
458                 @Override
459                 public void onSwipeFromTop() {
460                     synchronized (mLock) {
461                         requestTransientBars(mTopGestureHost,
462                                 getControllableInsets(mTopGestureHost).top > 0);
463                     }
464                 }
465 
466                 @Override
467                 public void onSwipeFromBottom() {
468                     synchronized (mLock) {
469                         requestTransientBars(mBottomGestureHost,
470                                 getControllableInsets(mBottomGestureHost).bottom > 0);
471                     }
472                 }
473 
474                 private boolean allowsSideSwipe(Region excludedRegion) {
475                     return mNavigationBarAlwaysShowOnSideGesture
476                             && !mSystemGestures.currentGestureStartedInRegion(excludedRegion);
477                 }
478 
479                 @Override
480                 public void onSwipeFromRight() {
481                     final Region excludedRegion = Region.obtain();
482                     synchronized (mLock) {
483                         mDisplayContent.calculateSystemGestureExclusion(
484                                 excludedRegion, null /* outUnrestricted */);
485                         final boolean hasWindow =
486                                 getControllableInsets(mRightGestureHost).right > 0;
487                         if (hasWindow || allowsSideSwipe(excludedRegion)) {
488                             requestTransientBars(mRightGestureHost, hasWindow);
489                         }
490                     }
491                     excludedRegion.recycle();
492                 }
493 
494                 @Override
495                 public void onSwipeFromLeft() {
496                     final Region excludedRegion = Region.obtain();
497                     synchronized (mLock) {
498                         mDisplayContent.calculateSystemGestureExclusion(
499                                 excludedRegion, null /* outUnrestricted */);
500                         final boolean hasWindow =
501                                 getControllableInsets(mLeftGestureHost).left > 0;
502                         if (hasWindow || allowsSideSwipe(excludedRegion)) {
503                             requestTransientBars(mLeftGestureHost, hasWindow);
504                         }
505                     }
506                     excludedRegion.recycle();
507                 }
508 
509                 @Override
510                 public void onFling(int duration) {
511                     if (mService.mPowerManagerInternal != null) {
512                         mService.mPowerManagerInternal.setPowerBoost(
513                                 Boost.INTERACTION, duration);
514                     }
515                 }
516 
517                 @Override
518                 public void onDebug() {
519                     // no-op
520                 }
521 
522                 private WindowOrientationListener getOrientationListener() {
523                     final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
524                     return rotation != null ? rotation.getOrientationListener() : null;
525                 }
526 
527                 @Override
528                 public void onDown() {
529                     final WindowOrientationListener listener = getOrientationListener();
530                     if (listener != null) {
531                         listener.onTouchStart();
532                     }
533                 }
534 
535                 @Override
536                 public void onUpOrCancel() {
537                     final WindowOrientationListener listener = getOrientationListener();
538                     if (listener != null) {
539                         listener.onTouchEnd();
540                     }
541                 }
542 
543                 @Override
544                 public void onMouseHoverAtLeft() {
545                     mHandler.removeCallbacks(mOnSwipeFromLeft);
546                     mHandler.postDelayed(mOnSwipeFromLeft, MOUSE_GESTURE_DELAY_MS);
547                 }
548 
549                 @Override
550                 public void onMouseHoverAtTop() {
551                     mHandler.removeCallbacks(mOnSwipeFromTop);
552                     mHandler.postDelayed(mOnSwipeFromTop, MOUSE_GESTURE_DELAY_MS);
553                 }
554 
555                 @Override
556                 public void onMouseHoverAtRight() {
557                     mHandler.removeCallbacks(mOnSwipeFromRight);
558                     mHandler.postDelayed(mOnSwipeFromRight, MOUSE_GESTURE_DELAY_MS);
559                 }
560 
561                 @Override
562                 public void onMouseHoverAtBottom() {
563                     mHandler.removeCallbacks(mOnSwipeFromBottom);
564                     mHandler.postDelayed(mOnSwipeFromBottom, MOUSE_GESTURE_DELAY_MS);
565                 }
566 
567                 @Override
568                 public void onMouseLeaveFromLeft() {
569                     mHandler.removeCallbacks(mOnSwipeFromLeft);
570                 }
571 
572                 @Override
573                 public void onMouseLeaveFromTop() {
574                     mHandler.removeCallbacks(mOnSwipeFromTop);
575                 }
576 
577                 @Override
578                 public void onMouseLeaveFromRight() {
579                     mHandler.removeCallbacks(mOnSwipeFromRight);
580                 }
581 
582                 @Override
583                 public void onMouseLeaveFromBottom() {
584                     mHandler.removeCallbacks(mOnSwipeFromBottom);
585                 }
586             };
587             mSystemGestures = new SystemGesturesPointerEventListener(mUiContext, mHandler,
588                     gesturesPointerEventCallbacks);
589             displayContent.registerPointerEventListener(mSystemGestures);
590         }
591         mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() {
592 
593             private Runnable mAppTransitionPending = () -> {
594                 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
595                 if (statusBar != null) {
596                     statusBar.appTransitionPending(displayId);
597                 }
598             };
599 
600             private Runnable mAppTransitionCancelled = () -> {
601                 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
602                 if (statusBar != null) {
603                     statusBar.appTransitionCancelled(displayId);
604                 }
605             };
606 
607             private Runnable mAppTransitionFinished = () -> {
608                 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
609                 if (statusBar != null) {
610                     statusBar.appTransitionFinished(displayId);
611                 }
612             };
613 
614             @Override
615             public void onAppTransitionPendingLocked() {
616                 mHandler.post(mAppTransitionPending);
617             }
618 
619             @Override
620             public int onAppTransitionStartingLocked(long statusBarAnimationStartTime,
621                     long statusBarAnimationDuration) {
622                 mHandler.post(() -> {
623                     StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
624                     if (statusBar != null) {
625                         statusBar.appTransitionStarting(mContext.getDisplayId(),
626                                 statusBarAnimationStartTime, statusBarAnimationDuration);
627                     }
628                 });
629                 return 0;
630             }
631 
632             @Override
633             public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled) {
634                 mHandler.post(mAppTransitionCancelled);
635             }
636 
637             @Override
638             public void onAppTransitionFinishedLocked(IBinder token) {
639                 mHandler.post(mAppTransitionFinished);
640             }
641         };
642         displayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
643         displayContent.mTransitionController.registerLegacyListener(mAppTransitionListener);
644         if (CLIENT_TRANSIENT || CLIENT_IMMERSIVE_CONFIRMATION) {
645             mImmersiveModeConfirmation = null;
646         } else {
647             mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
648                     mService.mVrModeEnabled, mCanSystemBarsBeShownByUser);
649         }
650 
651         // TODO: Make it can take screenshot on external display
652         mScreenshotHelper = displayContent.isDefaultDisplay
653                 ? new ScreenshotHelper(mContext) : null;
654 
655         if (mDisplayContent.isDefaultDisplay) {
656             mHasStatusBar = true;
657             mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
658 
659             // Allow a system property to override this. Used by the emulator.
660             // See also hasNavigationBar().
661             String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
662             if ("1".equals(navBarOverride)) {
663                 mHasNavigationBar = false;
664             } else if ("0".equals(navBarOverride)) {
665                 mHasNavigationBar = true;
666             }
667         } else {
668             mHasStatusBar = false;
669             mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
670         }
671 
672         mRefreshRatePolicy = new RefreshRatePolicy(mService,
673                 mDisplayContent.getDisplayInfo(),
674                 mService.mHighRefreshRateDenylist);
675 
676         mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler,
677                 BackgroundThread.getHandler(),
678                 mContext, () -> {
679             synchronized (mLock) {
680                 onConfigurationChanged();
681                 if (!CLIENT_TRANSIENT) {
682                     mSystemGestures.onConfigurationChanged();
683                 }
684                 mDisplayContent.updateSystemGestureExclusion();
685             }
686         });
687         mHandler.post(mGestureNavigationSettingsObserver::register);
688 
689         mForceShowNavBarSettingsObserver = new ForceShowNavBarSettingsObserver(
690                 mHandler, mContext);
691         mForceShowNavBarSettingsObserver.setOnChangeRunnable(this::updateForceShowNavBarSettings);
692         mForceShowNavigationBarEnabled = mForceShowNavBarSettingsObserver.isEnabled();
693         mHandler.post(mForceShowNavBarSettingsObserver::register);
694     }
695 
updateForceShowNavBarSettings()696     private void updateForceShowNavBarSettings() {
697         synchronized (mLock) {
698             mForceShowNavigationBarEnabled =
699                     mForceShowNavBarSettingsObserver.isEnabled();
700             updateSystemBarAttributes();
701         }
702     }
703 
systemReady()704     void systemReady() {
705         if (!CLIENT_TRANSIENT) {
706             mSystemGestures.systemReady();
707         }
708         if (mService.mPointerLocationEnabled) {
709             setPointerLocationEnabled(true);
710         }
711     }
712 
getDisplayId()713     private int getDisplayId() {
714         return mDisplayContent.getDisplayId();
715     }
716 
setHdmiPlugged(boolean plugged)717     public void setHdmiPlugged(boolean plugged) {
718         setHdmiPlugged(plugged, false /* force */);
719     }
720 
setHdmiPlugged(boolean plugged, boolean force)721     public void setHdmiPlugged(boolean plugged, boolean force) {
722         if (force || mHdmiPlugged != plugged) {
723             mHdmiPlugged = plugged;
724             mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
725             final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
726             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
727             intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
728             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
729         }
730     }
731 
isHdmiPlugged()732     boolean isHdmiPlugged() {
733         return mHdmiPlugged;
734     }
735 
isCarDockEnablesAccelerometer()736     boolean isCarDockEnablesAccelerometer() {
737         return mCarDockEnablesAccelerometer;
738     }
739 
isDeskDockEnablesAccelerometer()740     boolean isDeskDockEnablesAccelerometer() {
741         return mDeskDockEnablesAccelerometer;
742     }
743 
setPersistentVrModeEnabled(boolean persistentVrModeEnabled)744     public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
745         mPersistentVrModeEnabled = persistentVrModeEnabled;
746     }
747 
isPersistentVrModeEnabled()748     public boolean isPersistentVrModeEnabled() {
749         return mPersistentVrModeEnabled;
750     }
751 
setDockMode(int dockMode)752     public void setDockMode(int dockMode) {
753         mDockMode = dockMode;
754     }
755 
getDockMode()756     public int getDockMode() {
757         return mDockMode;
758     }
759 
hasNavigationBar()760     public boolean hasNavigationBar() {
761         return mHasNavigationBar;
762     }
763 
hasStatusBar()764     public boolean hasStatusBar() {
765         return mHasStatusBar;
766     }
767 
hasSideGestures()768     boolean hasSideGestures() {
769         return mHasNavigationBar && (mLeftGestureInset > 0 || mRightGestureInset > 0);
770     }
771 
navigationBarCanMove()772     public boolean navigationBarCanMove() {
773         return mNavigationBarCanMove;
774     }
775 
setLidState(int lidState)776     public void setLidState(int lidState) {
777         mLidState = lidState;
778     }
779 
getLidState()780     public int getLidState() {
781         return mLidState;
782     }
783 
onDisplaySwitchFinished()784     private void onDisplaySwitchFinished() {
785         mDisplayContent.mWallpaperController.onDisplaySwitchFinished();
786         mDisplayContent.mDisplayUpdater.onDisplaySwitching(false);
787     }
788 
setAwake(boolean awake)789     public void setAwake(boolean awake) {
790         synchronized (mLock) {
791             if (awake == mAwake) {
792                 return;
793             }
794             mAwake = awake;
795             if (!mDisplayContent.isDefaultDisplay) {
796                 return;
797             }
798             if (awake) {
799                 mService.mAtmService.mVisibleDozeUiProcess = null;
800             } else if (mScreenOnFully && mNotificationShade != null) {
801                 // Screen is still on, so it may be showing an always-on UI.
802                 mService.mAtmService.mVisibleDozeUiProcess = mNotificationShade.getProcess();
803             }
804             mService.mAtmService.mKeyguardController.updateDeferTransitionForAod(
805                     mAwake /* waiting */);
806             if (!awake) {
807                 onDisplaySwitchFinished();
808             }
809         }
810     }
811 
isAwake()812     public boolean isAwake() {
813         return mAwake;
814     }
815 
isScreenOnEarly()816     public boolean isScreenOnEarly() {
817         return mScreenOnEarly;
818     }
819 
isScreenOnFully()820     public boolean isScreenOnFully() {
821         return mScreenOnFully;
822     }
823 
isKeyguardDrawComplete()824     public boolean isKeyguardDrawComplete() {
825         return mKeyguardDrawComplete;
826     }
827 
isWindowManagerDrawComplete()828     public boolean isWindowManagerDrawComplete() {
829         return mWindowManagerDrawComplete;
830     }
831 
isForceShowNavigationBarEnabled()832     public boolean isForceShowNavigationBarEnabled() {
833         return mForceShowNavigationBarEnabled;
834     }
835 
getScreenOnListener()836     public ScreenOnListener getScreenOnListener() {
837         return mScreenOnListener;
838     }
839 
840 
isRemoteInsetsControllerControllingSystemBars()841     boolean isRemoteInsetsControllerControllingSystemBars() {
842         return mRemoteInsetsControllerControlsSystemBars;
843     }
844 
845     @VisibleForTesting
setRemoteInsetsControllerControlsSystemBars( boolean remoteInsetsControllerControlsSystemBars)846     void setRemoteInsetsControllerControlsSystemBars(
847             boolean remoteInsetsControllerControlsSystemBars) {
848         mRemoteInsetsControllerControlsSystemBars = remoteInsetsControllerControlsSystemBars;
849     }
850 
851     /** Prepares to turn on screen. The given listener is used to notify that it is ready. */
screenTurningOn(ScreenOnListener screenOnListener)852     public void screenTurningOn(ScreenOnListener screenOnListener) {
853         WindowProcessController visibleDozeUiProcess = null;
854         synchronized (mLock) {
855             mScreenOnEarly = true;
856             mScreenOnFully = false;
857             mKeyguardDrawComplete = false;
858             mWindowManagerDrawComplete = false;
859             mScreenOnListener = screenOnListener;
860             if (!mAwake && mNotificationShade != null) {
861                 // The screen is turned on without awake state. It is usually triggered by an
862                 // adding notification, so make the UI process have a higher priority.
863                 visibleDozeUiProcess = mNotificationShade.getProcess();
864                 mService.mAtmService.mVisibleDozeUiProcess = visibleDozeUiProcess;
865             }
866         }
867         // The method calls AM directly, so invoke it outside the lock.
868         if (visibleDozeUiProcess != null) {
869             Trace.instant(Trace.TRACE_TAG_WINDOW_MANAGER, "screenTurnedOnWhileDozing");
870             mService.mAtmService.setProcessAnimatingWhileDozing(visibleDozeUiProcess);
871         }
872     }
873 
874     /** It is called after {@link #finishScreenTurningOn}. This runs on PowerManager's thread. */
screenTurnedOn()875     public void screenTurnedOn() {
876         onDisplaySwitchFinished();
877     }
878 
screenTurnedOff()879     public void screenTurnedOff() {
880         synchronized (mLock) {
881             mScreenOnEarly = false;
882             mScreenOnFully = false;
883             mKeyguardDrawComplete = false;
884             mWindowManagerDrawComplete = false;
885             mScreenOnListener = null;
886             mService.mAtmService.mVisibleDozeUiProcess = null;
887         }
888     }
889 
890     /** Return false if we are not awake yet or we have already informed of this event. */
finishKeyguardDrawn()891     public boolean finishKeyguardDrawn() {
892         synchronized (mLock) {
893             if (!mScreenOnEarly || mKeyguardDrawComplete) {
894                 return false;
895             }
896 
897             mKeyguardDrawComplete = true;
898             mWindowManagerDrawComplete = false;
899         }
900         return true;
901     }
902 
903     /** Return false if screen is not turned on or we did already handle this case earlier. */
finishWindowsDrawn()904     public boolean finishWindowsDrawn() {
905         synchronized (mLock) {
906             if (!mScreenOnEarly || mWindowManagerDrawComplete) {
907                 return false;
908             }
909 
910             mWindowManagerDrawComplete = true;
911         }
912         return true;
913     }
914 
915     /** Return false if it is not ready to turn on. */
finishScreenTurningOn()916     public boolean finishScreenTurningOn() {
917         synchronized (mLock) {
918             ProtoLog.d(WM_DEBUG_SCREEN_ON,
919                             "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, "
920                                     + "mScreenOnFully=%b, mKeyguardDrawComplete=%b, "
921                                     + "mWindowManagerDrawComplete=%b",
922                             mAwake, mScreenOnEarly, mScreenOnFully, mKeyguardDrawComplete,
923                             mWindowManagerDrawComplete);
924 
925             if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
926                     || (mAwake && !mKeyguardDrawComplete)) {
927                 return false;
928             }
929 
930             ProtoLog.i(WM_DEBUG_SCREEN_ON, "Finished screen turning on...");
931             mScreenOnListener = null;
932             mScreenOnFully = true;
933         }
934         return true;
935     }
936 
937     /**
938      * Sanitize the layout parameters coming from a client.  Allows the policy
939      * to do things like ensure that windows of a specific type can't take
940      * input focus.
941      *
942      * @param attrs The window layout parameters to be modified.  These values
943      * are modified in-place.
944      */
adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs)945     public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs) {
946         switch (attrs.type) {
947             case TYPE_SYSTEM_OVERLAY:
948             case TYPE_SECURE_SYSTEM_OVERLAY:
949                 // These types of windows can't receive input events.
950                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
951                         | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
952                 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
953                 break;
954             case TYPE_WALLPAPER:
955                 // Dreams and wallpapers don't have an app window token and can thus not be
956                 // letterboxed. Hence always let them extend under the cutout.
957                 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
958                 break;
959 
960             case TYPE_TOAST:
961                 // While apps should use the dedicated toast APIs to add such windows
962                 // it possible legacy apps to add the window directly. Therefore, we
963                 // make windows added directly by the app behave as a toast as much
964                 // as possible in terms of timeout and animation.
965                 if (attrs.hideTimeoutMilliseconds < 0
966                         || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
967                     attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
968                 }
969                 // Accessibility users may need longer timeout duration. This api compares
970                 // original timeout with user's preference and return longer one. It returns
971                 // original timeout if there's no preference.
972                 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
973                         (int) attrs.hideTimeoutMilliseconds,
974                         AccessibilityManager.FLAG_CONTENT_TEXT);
975                 // Toasts can't be clickable
976                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
977                 break;
978 
979             case TYPE_BASE_APPLICATION:
980                 if (attrs.isFullscreen() && win.mActivityRecord != null
981                         && win.mActivityRecord.fillsParent()
982                         && (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0) {
983                     if (attrs.getFitInsetsTypes() != 0) {
984                         // A non-translucent main app window isn't allowed to fit insets,
985                         // as it would create a hole on the display!
986                         throw new IllegalArgumentException("Illegal attributes: Main window of "
987                                 + win.mActivityRecord.getName() + " that isn't translucent trying"
988                                 + " to fit insets. fitInsetsTypes=" + WindowInsets.Type.toString(
989                                         attrs.getFitInsetsTypes()));
990                     }
991                 }
992                 break;
993         }
994         if ((attrs.insetsFlags.appearance & APPEARANCE_FORCE_LIGHT_NAVIGATION_BARS) != 0) {
995             attrs.insetsFlags.appearance |= APPEARANCE_LIGHT_NAVIGATION_BARS;
996         }
997 
998         if (LayoutParams.isSystemAlertWindowType(attrs.type)) {
999             float maxOpacity = mService.mMaximumObscuringOpacityForTouch;
1000             if (attrs.alpha > maxOpacity
1001                     && (attrs.flags & FLAG_NOT_TOUCHABLE) != 0
1002                     && !win.isTrustedOverlay()) {
1003                 // The app is posting a SAW with the intent of letting touches pass through, but
1004                 // they are going to be deemed untrusted and will be blocked. Try to honor the
1005                 // intent of letting touches pass through at the cost of 0.2 opacity for app
1006                 // compatibility reasons. More details on b/218777508.
1007                 Slog.w(TAG, String.format(
1008                         "App %s has a system alert window (type = %d) with FLAG_NOT_TOUCHABLE and "
1009                                 + "LayoutParams.alpha = %.2f > %.2f, setting alpha to %.2f to "
1010                                 + "let touches pass through (if this is isn't desirable, remove "
1011                                 + "flag FLAG_NOT_TOUCHABLE).",
1012                         attrs.packageName, attrs.type, attrs.alpha, maxOpacity, maxOpacity));
1013                 attrs.alpha = maxOpacity;
1014                 win.mWinAnimator.mAlpha = maxOpacity;
1015             }
1016         }
1017 
1018         if (!win.mSession.mCanSetUnrestrictedGestureExclusion) {
1019             attrs.privateFlags &= ~PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION;
1020         }
1021     }
1022 
1023     /**
1024      * Add additional policy if needed to ensure the window or its children should not receive any
1025      * input.
1026      */
setDropInputModePolicy(WindowState win, LayoutParams attrs)1027     public void setDropInputModePolicy(WindowState win, LayoutParams attrs) {
1028         if (attrs.type == TYPE_TOAST
1029                 && (attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) == 0) {
1030             // Toasts should not receive input. These windows should not have any children, so
1031             // force this hierarchy of windows to drop all input.
1032             mService.mTransactionFactory.get()
1033                     .setDropInputMode(win.getSurfaceControl(), DropInputMode.ALL).apply();
1034         }
1035     }
1036 
1037     /**
1038      * Check if a window can be added to the system.
1039      *
1040      * Currently enforces that two window types are singletons per display:
1041      * <ul>
1042      * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
1043      * <li>{@link WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}</li>
1044      * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
1045      * </ul>
1046      *
1047      * @param attrs Information about the window to be added.
1048      *
1049      * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons,
1050      * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
1051      */
validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid)1052     int validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid) {
1053         if ((attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) {
1054             mContext.enforcePermission(
1055                     android.Manifest.permission.INTERNAL_SYSTEM_WINDOW, callingPid, callingUid,
1056                     "DisplayPolicy");
1057         }
1058         if ((attrs.privateFlags & PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP) != 0) {
1059             ActivityTaskManagerService.enforceTaskPermission("DisplayPolicy");
1060         }
1061 
1062         switch (attrs.type) {
1063             case TYPE_STATUS_BAR:
1064                 mContext.enforcePermission(
1065                         android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
1066                         "DisplayPolicy");
1067                 if (mStatusBar != null && mStatusBar.isAlive()) {
1068                     return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
1069                 }
1070                 break;
1071             case TYPE_NOTIFICATION_SHADE:
1072                 mContext.enforcePermission(
1073                         android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
1074                         "DisplayPolicy");
1075                 if (mNotificationShade != null) {
1076                     if (mNotificationShade.isAlive()) {
1077                         return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
1078                     }
1079                 }
1080                 break;
1081             case TYPE_NAVIGATION_BAR:
1082                 mContext.enforcePermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1083                         callingPid, callingUid, "DisplayPolicy");
1084                 if (mNavigationBar != null && mNavigationBar.isAlive()) {
1085                     return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
1086                 }
1087                 break;
1088             case TYPE_NAVIGATION_BAR_PANEL:
1089                 mContext.enforcePermission(android.Manifest.permission.STATUS_BAR_SERVICE,
1090                         callingPid, callingUid, "DisplayPolicy");
1091                 break;
1092             case TYPE_STATUS_BAR_ADDITIONAL:
1093             case TYPE_STATUS_BAR_SUB_PANEL:
1094             case TYPE_VOICE_INTERACTION_STARTING:
1095                 mContext.enforcePermission(
1096                         android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
1097                         "DisplayPolicy");
1098                 break;
1099             case TYPE_STATUS_BAR_PANEL:
1100                 return WindowManagerGlobal.ADD_INVALID_TYPE;
1101         }
1102 
1103         if (attrs.providedInsets != null) {
1104             // Recents component is allowed to add inset types.
1105             if (!mService.mAtmService.isCallerRecents(callingUid)) {
1106                 mContext.enforcePermission(
1107                         android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid,
1108                         "DisplayPolicy");
1109             }
1110         }
1111         return ADD_OKAY;
1112     }
1113 
1114     /**
1115      * Called when a window is being added to the system.  Must not throw an exception.
1116      *
1117      * @param win The window being added.
1118      * @param attrs Information about the window to be added.
1119      */
addWindowLw(WindowState win, WindowManager.LayoutParams attrs)1120     void addWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
1121         switch (attrs.type) {
1122             case TYPE_NOTIFICATION_SHADE:
1123                 mNotificationShade = win;
1124                 break;
1125             case TYPE_STATUS_BAR:
1126                 mStatusBar = win;
1127                 break;
1128             case TYPE_NAVIGATION_BAR:
1129                 mNavigationBar = win;
1130                 break;
1131         }
1132         if ((attrs.privateFlags & PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW) != 0) {
1133             mImmersiveConfirmationWindowExists = true;
1134         }
1135         if (attrs.providedInsets != null) {
1136             for (int i = attrs.providedInsets.length - 1; i >= 0; i--) {
1137                 final InsetsFrameProvider provider = attrs.providedInsets[i];
1138                 // The index of the provider and corresponding insets types cannot change at
1139                 // runtime as ensured in WMS. Make use of the index in the provider directly
1140                 // to access the latest provided size at runtime.
1141                 final TriFunction<DisplayFrames, WindowContainer, Rect, Integer> frameProvider =
1142                         getFrameProvider(win, i, INSETS_OVERRIDE_INDEX_INVALID);
1143                 final InsetsFrameProvider.InsetsSizeOverride[] overrides =
1144                         provider.getInsetsSizeOverrides();
1145                 final SparseArray<TriFunction<DisplayFrames, WindowContainer, Rect, Integer>>
1146                         overrideProviders;
1147                 if (overrides != null) {
1148                     overrideProviders = new SparseArray<>();
1149                     for (int j = overrides.length - 1; j >= 0; j--) {
1150                         overrideProviders.put(
1151                                 overrides[j].getWindowType(), getFrameProvider(win, i, j));
1152                     }
1153                 } else {
1154                     overrideProviders = null;
1155                 }
1156                 final InsetsSourceProvider sourceProvider = mDisplayContent
1157                         .getInsetsStateController().getOrCreateSourceProvider(provider.getId(),
1158                                 provider.getType());
1159                 sourceProvider.getSource().setFlags(provider.getFlags());
1160                 sourceProvider.setWindowContainer(win, frameProvider, overrideProviders);
1161                 mInsetsSourceWindowsExceptIme.add(win);
1162             }
1163         }
1164     }
1165 
getFrameProvider( WindowState win, int index, int overrideIndex)1166     private static TriFunction<DisplayFrames, WindowContainer, Rect, Integer> getFrameProvider(
1167             WindowState win, int index, int overrideIndex) {
1168         return (displayFrames, windowContainer, inOutFrame) -> {
1169             final LayoutParams lp = win.mAttrs.forRotation(displayFrames.mRotation);
1170             final InsetsFrameProvider ifp = lp.providedInsets[index];
1171             final Rect displayFrame = displayFrames.mUnrestricted;
1172             final Rect safe = displayFrames.mDisplayCutoutSafe;
1173             boolean extendByCutout = false;
1174             switch (ifp.getSource()) {
1175                 case SOURCE_DISPLAY:
1176                     inOutFrame.set(displayFrame);
1177                     break;
1178                 case SOURCE_CONTAINER_BOUNDS:
1179                     inOutFrame.set(windowContainer.getBounds());
1180                     break;
1181                 case SOURCE_FRAME:
1182                     extendByCutout =
1183                             (lp.privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0;
1184                     break;
1185                 case SOURCE_ARBITRARY_RECTANGLE:
1186                     inOutFrame.set(ifp.getArbitraryRectangle());
1187                     break;
1188             }
1189             final Insets insetsSize = overrideIndex == INSETS_OVERRIDE_INDEX_INVALID
1190                     ? ifp.getInsetsSize()
1191                     : ifp.getInsetsSizeOverrides()[overrideIndex].getInsetsSize();
1192 
1193             if (ifp.getMinimalInsetsSizeInDisplayCutoutSafe() != null) {
1194                 sTmpRect2.set(inOutFrame);
1195             }
1196             calculateInsetsFrame(inOutFrame, insetsSize);
1197 
1198             if (extendByCutout && insetsSize != null) {
1199                 WindowLayout.extendFrameByCutout(safe, displayFrame, inOutFrame, sTmpRect);
1200             }
1201 
1202             if (ifp.getMinimalInsetsSizeInDisplayCutoutSafe() != null) {
1203                 // The insets is at least with the given size within the display cutout safe area.
1204                 // Calculate the smallest size.
1205                 calculateInsetsFrame(sTmpRect2, ifp.getMinimalInsetsSizeInDisplayCutoutSafe());
1206                 WindowLayout.extendFrameByCutout(safe, displayFrame, sTmpRect2, sTmpRect);
1207                 // If it's larger than previous calculation, use it.
1208                 if (sTmpRect2.contains(inOutFrame)) {
1209                     inOutFrame.set(sTmpRect2);
1210                 }
1211             }
1212             return ifp.getFlags();
1213         };
1214     }
1215 
1216     /**
1217      * Calculate the insets frame given the insets size and the source frame.
1218      * @param inOutFrame the source frame.
1219      * @param insetsSize the insets size. Only the first non-zero value will be taken.
1220      */
calculateInsetsFrame(Rect inOutFrame, Insets insetsSize)1221     private static void calculateInsetsFrame(Rect inOutFrame, Insets insetsSize) {
1222         if (insetsSize == null) {
1223             return;
1224         }
1225         // Only one side of the provider shall be applied. Check in the order of left - top -
1226         // right - bottom, only the first non-zero value will be applied.
1227         if (insetsSize.left != 0) {
1228             inOutFrame.right = inOutFrame.left + insetsSize.left;
1229         } else if (insetsSize.top != 0) {
1230             inOutFrame.bottom = inOutFrame.top + insetsSize.top;
1231         } else if (insetsSize.right != 0) {
1232             inOutFrame.left = inOutFrame.right - insetsSize.right;
1233         } else if (insetsSize.bottom != 0) {
1234             inOutFrame.top = inOutFrame.bottom - insetsSize.bottom;
1235         } else {
1236             inOutFrame.setEmpty();
1237         }
1238     }
1239 
getImeSourceFrameProvider()1240     TriFunction<DisplayFrames, WindowContainer, Rect, Integer> getImeSourceFrameProvider() {
1241         return (displayFrames, windowContainer, inOutFrame) -> {
1242             WindowState windowState = windowContainer.asWindowState();
1243             if (windowState == null) {
1244                 throw new IllegalArgumentException("IME insets must be provided by a window.");
1245             }
1246 
1247             if (!ENABLE_HIDE_IME_CAPTION_BAR && mNavigationBar != null
1248                     && navigationBarPosition(displayFrames.mRotation) == NAV_BAR_BOTTOM) {
1249                 // In gesture navigation, nav bar frame is larger than frame to calculate insets.
1250                 // IME should not provide frame which is smaller than the nav bar frame. Otherwise,
1251                 // nav bar might be overlapped with the content of the client when IME is shown.
1252                 sTmpRect.set(inOutFrame);
1253                 sTmpRect.intersectUnchecked(mNavigationBar.getFrame());
1254                 inOutFrame.inset(windowState.mGivenContentInsets);
1255                 inOutFrame.union(sTmpRect);
1256             } else {
1257                 inOutFrame.inset(windowState.mGivenContentInsets);
1258             }
1259             return 0;
1260         };
1261     }
1262 
1263     /**
1264      * Called when a window is being removed from a window manager.  Must not
1265      * throw an exception -- clean up as much as possible.
1266      *
1267      * @param win The window being removed.
1268      */
1269     void removeWindowLw(WindowState win) {
1270         if (mStatusBar == win) {
1271             mStatusBar = null;
1272         } else if (mNavigationBar == win) {
1273             mNavigationBar = null;
1274         } else if (mNotificationShade == win) {
1275             mNotificationShade = null;
1276         }
1277         if (mLastFocusedWindow == win) {
1278             mLastFocusedWindow = null;
1279         }
1280 
1281         if (win.hasInsetsSourceProvider()) {
1282             final SparseArray<InsetsSourceProvider> providers = win.getInsetsSourceProviders();
1283             final InsetsStateController controller = mDisplayContent.getInsetsStateController();
1284             for (int index = providers.size() - 1; index >= 0; index--) {
1285                 final InsetsSourceProvider provider = providers.valueAt(index);
1286                 provider.setWindowContainer(
1287                         null /* windowContainer */,
1288                         null /* frameProvider */,
1289                         null /* overrideFrameProviders */);
1290                 controller.removeSourceProvider(provider.getSource().getId());
1291             }
1292         }
1293         mInsetsSourceWindowsExceptIme.remove(win);
1294         if ((win.mAttrs.privateFlags & PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW) != 0) {
1295             mImmersiveConfirmationWindowExists = false;
1296         }
1297     }
1298 
1299     WindowState getStatusBar() {
1300         return mStatusBar;
1301     }
1302 
1303     WindowState getNotificationShade() {
1304         return mNotificationShade;
1305     }
1306 
1307     WindowState getNavigationBar() {
1308         return mNavigationBar;
1309     }
1310 
1311     boolean isImmersiveMode() {
1312         return mIsImmersiveMode;
1313     }
1314 
1315     /**
1316      * Control the animation to run when a window's state changes.  Return a positive number to
1317      * force the animation to a specific resource ID, {@link #ANIMATION_STYLEABLE} to use the
1318      * style resource defining the animation, or {@link #ANIMATION_NONE} for no animation.
1319      *
1320      * @param win The window that is changing.
1321      * @param transit What is happening to the window:
1322      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
1323      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
1324      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
1325      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
1326      *
1327      * @return Resource ID of the actual animation to use, or {@link #ANIMATION_NONE} for none.
1328      */
1329     int selectAnimation(WindowState win, int transit) {
1330         ProtoLog.i(WM_DEBUG_ANIM, "selectAnimation in %s: transit=%d", win, transit);
1331 
1332         if (transit == TRANSIT_PREVIEW_DONE) {
1333             if (win.hasAppShownWindows()) {
1334                 if (win.isActivityTypeHome()) {
1335                     // Dismiss the starting window as soon as possible to avoid the crossfade out
1336                     // with old content because home is easier to have different UI states.
1337                     return ANIMATION_NONE;
1338                 }
1339                 ProtoLog.i(WM_DEBUG_ANIM, "**** STARTING EXIT");
1340                 return R.anim.app_starting_exit;
1341             }
1342         }
1343 
1344         return ANIMATION_STYLEABLE;
1345     }
1346 
1347     // TODO (b/277891341): Remove this and related usages. This has been replaced by
1348     //                     InsetsSource#FLAG_FORCE_CONSUMING.
1349     public boolean areSystemBarsForcedConsumedLw() {
1350         return false;
1351     }
1352 
1353     /**
1354      * Computes the frames of display (its logical size, rotation and cutout should already be set)
1355      * used to layout window. This method only changes the given display frames, insets state and
1356      * some temporal states, but doesn't change the window frames used to show on screen.
1357      */
1358     void simulateLayoutDisplay(DisplayFrames displayFrames) {
1359         sTmpClientFrames.attachedFrame = null;
1360         for (int i = mInsetsSourceWindowsExceptIme.size() - 1; i >= 0; i--) {
1361             final WindowState win = mInsetsSourceWindowsExceptIme.valueAt(i);
1362             mWindowLayout.computeFrames(win.mAttrs.forRotation(displayFrames.mRotation),
1363                     displayFrames.mInsetsState, displayFrames.mDisplayCutoutSafe,
1364                     displayFrames.mUnrestricted, win.getWindowingMode(), UNSPECIFIED_LENGTH,
1365                     UNSPECIFIED_LENGTH, win.getRequestedVisibleTypes(), win.mGlobalScale,
1366                     sTmpClientFrames);
1367             final SparseArray<InsetsSourceProvider> providers = win.getInsetsSourceProviders();
1368             final InsetsState state = displayFrames.mInsetsState;
1369             for (int index = providers.size() - 1; index >= 0; index--) {
1370                 state.addSource(providers.valueAt(index).createSimulatedSource(
1371                         displayFrames, sTmpClientFrames.frame));
1372             }
1373         }
1374     }
1375 
1376     void onDisplayInfoChanged(DisplayInfo info) {
1377         if (!CLIENT_TRANSIENT) {
1378             mSystemGestures.onDisplayInfoChanged(info);
1379         }
1380     }
1381 
1382     /**
1383      * Called for each window attached to the window manager as layout is proceeding. The
1384      * implementation of this function must take care of setting the window's frame, either here or
1385      * in finishLayout().
1386      *
1387      * @param win The window being positioned.
1388      * @param attached For sub-windows, the window it is attached to; this
1389      *                 window will already have had layoutWindow() called on it
1390      *                 so you can use its Rect.  Otherwise null.
1391      * @param displayFrames The display frames.
1392      */
1393     public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
1394         if (win.skipLayout()) {
1395             return;
1396         }
1397 
1398         // This window might be in the simulated environment.
1399         // We invoke this to get the proper DisplayFrames.
1400         displayFrames = win.getDisplayFrames(displayFrames);
1401 
1402         final WindowManager.LayoutParams attrs = win.mAttrs.forRotation(displayFrames.mRotation);
1403         sTmpClientFrames.attachedFrame = attached != null ? attached.getFrame() : null;
1404 
1405         // If this window has different LayoutParams for rotations, we cannot trust its requested
1406         // size. Because it might have not sent its requested size for the new rotation.
1407         final boolean trustedSize = attrs == win.mAttrs;
1408         final int requestedWidth = trustedSize ? win.mRequestedWidth : UNSPECIFIED_LENGTH;
1409         final int requestedHeight = trustedSize ? win.mRequestedHeight : UNSPECIFIED_LENGTH;
1410 
1411         mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe,
1412                 win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight,
1413                 win.getRequestedVisibleTypes(), win.mGlobalScale, sTmpClientFrames);
1414 
1415         win.setFrames(sTmpClientFrames, win.mRequestedWidth, win.mRequestedHeight);
1416     }
1417 
1418     WindowState getTopFullscreenOpaqueWindow() {
1419         return mTopFullscreenOpaqueWindowState;
1420     }
1421 
1422     boolean isTopLayoutFullscreen() {
1423         return mTopIsFullscreen;
1424     }
1425 
1426     /**
1427      * Called following layout of all windows before each window has policy applied.
1428      */
1429     public void beginPostLayoutPolicyLw() {
1430         mLeftGestureHost = null;
1431         mTopGestureHost = null;
1432         mRightGestureHost = null;
1433         mBottomGestureHost = null;
1434         mTopFullscreenOpaqueWindowState = null;
1435         mNavBarColorWindowCandidate = null;
1436         mNavBarBackgroundWindowCandidate = null;
1437         mStatusBarAppearanceRegionList.clear();
1438         mLetterboxDetails.clear();
1439         mStatusBarBackgroundWindows.clear();
1440         mStatusBarColorCheckedBounds.setEmpty();
1441         mStatusBarBackgroundCheckedBounds.setEmpty();
1442         mSystemBarColorApps.clear();
1443 
1444         mAllowLockscreenWhenOn = false;
1445         mShowingDream = false;
1446         mIsFreeformWindowOverlappingWithNavBar = false;
1447         mForciblyShownTypes = 0;
1448         mImeInsetsConsumed = false;
1449     }
1450 
1451     /**
1452      * Called following layout of all window to apply policy to each window.
1453      *
1454      * @param win The window being positioned.
1455      * @param attrs The LayoutParams of the window.
1456      * @param attached For sub-windows, the window it is attached to. Otherwise null.
1457      */
1458     public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
1459             WindowState attached, WindowState imeTarget) {
1460         if (attrs.type == TYPE_NAVIGATION_BAR) {
1461             // Keep mNavigationBarPosition updated to make sure the transient detection and bar
1462             // color control is working correctly.
1463             final DisplayFrames displayFrames = mDisplayContent.mDisplayFrames;
1464             mNavigationBarPosition = navigationBarPosition(displayFrames.mRotation);
1465         }
1466         final boolean affectsSystemUi = win.canAffectSystemUiFlags();
1467         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
1468         applyKeyguardPolicy(win, imeTarget);
1469 
1470         // Check if the freeform window overlaps with the navigation bar area.
1471         if (!mIsFreeformWindowOverlappingWithNavBar && win.inFreeformWindowingMode()
1472                 && win.mActivityRecord != null && isOverlappingWithNavBar(win)) {
1473             mIsFreeformWindowOverlappingWithNavBar = true;
1474         }
1475 
1476         if (win.hasInsetsSourceProvider()) {
1477             final SparseArray<InsetsSourceProvider> providers = win.getInsetsSourceProviders();
1478             final Rect bounds = win.getBounds();
1479             for (int index = providers.size() - 1; index >= 0; index--) {
1480                 final InsetsSourceProvider provider = providers.valueAt(index);
1481                 final InsetsSource source = provider.getSource();
1482                 if ((source.getType()
1483                         & (Type.systemGestures() | Type.mandatorySystemGestures())) == 0) {
1484                     continue;
1485                 }
1486                 if (mLeftGestureHost != null && mTopGestureHost != null
1487                         && mRightGestureHost != null && mBottomGestureHost != null) {
1488                     continue;
1489                 }
1490                 final Insets insets = source.calculateInsets(bounds, false /* ignoreVisibility */);
1491                 if (mLeftGestureHost == null && insets.left > 0) {
1492                     mLeftGestureHost = win;
1493                 }
1494                 if (mTopGestureHost == null && insets.top > 0) {
1495                     mTopGestureHost = win;
1496                 }
1497                 if (mRightGestureHost == null && insets.right > 0) {
1498                     mRightGestureHost = win;
1499                 }
1500                 if (mBottomGestureHost == null && insets.bottom > 0) {
1501                     mBottomGestureHost = win;
1502                 }
1503             }
1504         }
1505 
1506         if (win.mSession.mCanForceShowingInsets) {
1507             mForciblyShownTypes |= win.mAttrs.forciblyShownTypes;
1508         }
1509 
1510         if (win.mImeInsetsConsumed != mImeInsetsConsumed) {
1511             win.mImeInsetsConsumed = mImeInsetsConsumed;
1512             final WindowState imeWin = mDisplayContent.mInputMethodWindow;
1513             if (win.isReadyToDispatchInsetsState() && imeWin != null && imeWin.isVisible()) {
1514                 win.notifyInsetsChanged();
1515             }
1516         }
1517         if ((attrs.privateFlags & PRIVATE_FLAG_CONSUME_IME_INSETS) != 0 && win.isVisible()) {
1518             mImeInsetsConsumed = true;
1519         }
1520 
1521         if (!affectsSystemUi) {
1522             return;
1523         }
1524 
1525         boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
1526                 && attrs.type < FIRST_SYSTEM_WINDOW;
1527         if (mTopFullscreenOpaqueWindowState == null) {
1528             final int fl = attrs.flags;
1529             if (win.isDreamWindow()) {
1530                 // If the lockscreen was showing when the dream started then wait
1531                 // for the dream to draw before hiding the lockscreen.
1532                 if (!mDreamingLockscreen || (win.isVisible() && win.hasDrawn())) {
1533                     mShowingDream = true;
1534                     appWindow = true;
1535                 }
1536             }
1537 
1538             if (appWindow && attached == null && attrs.isFullscreen()
1539                     && (fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
1540                 mAllowLockscreenWhenOn = true;
1541             }
1542         }
1543 
1544         // Check the windows that overlap with system bars to determine system bars' appearance.
1545         if ((appWindow && attached == null && attrs.isFullscreen())
1546                 || attrs.type == TYPE_VOICE_INTERACTION) {
1547 
1548             // If this is the exiting starting window, don't let it control the system bars.
1549             // The app window behind it should be the controlling window instead. Reason: when an
1550             // activity starts another activity behind a starting window, the app window of the
1551             // first activity will lose the window focus. And then mTopFullscreenOpaqueWindowState
1552             // will control the system bars. The logic here is to let first app window keep
1553             // controlling system bars until the second app window is ready.
1554             final boolean exitingStartingWindow =
1555                     attrs.type == TYPE_APPLICATION_STARTING && win.mAnimatingExit;
1556 
1557             // Record the top-fullscreen-app-window which will be used to determine the system UI
1558             // controlling window.
1559             if (mTopFullscreenOpaqueWindowState == null && !exitingStartingWindow) {
1560                 mTopFullscreenOpaqueWindowState = win;
1561             }
1562 
1563             // Cache app windows that is overlapping with the status bar to determine appearance
1564             // of status bar.
1565             if (mStatusBar != null
1566                     && sTmpRect.setIntersect(win.getFrame(), mStatusBar.getFrame())
1567                     && !mStatusBarBackgroundCheckedBounds.contains(sTmpRect)) {
1568                 mStatusBarBackgroundWindows.add(win);
1569                 mStatusBarBackgroundCheckedBounds.union(sTmpRect);
1570                 if (!mStatusBarColorCheckedBounds.contains(sTmpRect)) {
1571                     mStatusBarAppearanceRegionList.add(new AppearanceRegion(
1572                             win.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_STATUS_BARS,
1573                             new Rect(win.getFrame())));
1574                     mStatusBarColorCheckedBounds.union(sTmpRect);
1575                     addSystemBarColorApp(win);
1576                 }
1577             }
1578 
1579             // Cache app window that overlaps with the navigation bar area to determine opacity
1580             // and appearance of the navigation bar. We only need to cache one window because
1581             // there should be only one overlapping window if it's not in gesture navigation
1582             // mode; if it's in gesture navigation mode, the navigation bar will be
1583             // NAV_BAR_FORCE_TRANSPARENT and its appearance won't be decided by overlapping
1584             // windows.
1585             if (isOverlappingWithNavBar(win)) {
1586                 if (mNavBarColorWindowCandidate == null) {
1587                     mNavBarColorWindowCandidate = win;
1588                     addSystemBarColorApp(win);
1589                 }
1590                 if (mNavBarBackgroundWindowCandidate == null) {
1591                     mNavBarBackgroundWindowCandidate = win;
1592                 }
1593             }
1594 
1595             // Check if current activity is letterboxed in order create a LetterboxDetails
1596             // component to be passed to SysUI for status bar treatment
1597             final ActivityRecord currentActivity = win.getActivityRecord();
1598             if (currentActivity != null) {
1599                 final LetterboxDetails currentLetterboxDetails = currentActivity
1600                         .mLetterboxUiController.getLetterboxDetails();
1601                 if (currentLetterboxDetails != null) {
1602                     mLetterboxDetails.add(currentLetterboxDetails);
1603                 }
1604             }
1605         } else if (win.isDimming()) {
1606             if (mStatusBar != null) {
1607                 // If the dim window is below status bar window, we should update the appearance
1608                 // region if needed. Otherwise, leave it as it is.
1609                 final int statusBarLayer = mStatusBar.mToken.getWindowLayerFromType();
1610                 final int targetWindowLayer = win.mToken.getWindowLayerFromType();
1611                 if (targetWindowLayer < statusBarLayer
1612                         && addStatusBarAppearanceRegionsForDimmingWindow(
1613                                 win.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_STATUS_BARS,
1614                                 mStatusBar.getFrame(), win.getBounds(), win.getFrame())) {
1615                     addSystemBarColorApp(win);
1616                 }
1617             }
1618             if (isOverlappingWithNavBar(win) && mNavBarColorWindowCandidate == null) {
1619                 mNavBarColorWindowCandidate = win;
1620                 addSystemBarColorApp(win);
1621             }
1622         } else if (appWindow && attached == null
1623                 && (mNavBarColorWindowCandidate == null || mNavBarBackgroundWindowCandidate == null)
1624                 && win.getFrame().contains(
1625                         getBarContentFrameForWindow(win, Type.navigationBars()))) {
1626             if (mNavBarColorWindowCandidate == null) {
1627                 mNavBarColorWindowCandidate = win;
1628                 addSystemBarColorApp(win);
1629             }
1630             if (mNavBarBackgroundWindowCandidate == null) {
1631                 mNavBarBackgroundWindowCandidate = win;
1632             }
1633         }
1634     }
1635 
1636     /**
1637      * Returns true if mStatusBarAppearanceRegionList is changed.
1638      */
1639     private boolean addStatusBarAppearanceRegionsForDimmingWindow(
1640             int appearance, Rect statusBarFrame, Rect winBounds, Rect winFrame) {
1641         if (!sTmpRect.setIntersect(winBounds, statusBarFrame)) {
1642             return false;
1643         }
1644         if (mStatusBarColorCheckedBounds.contains(sTmpRect)) {
1645             return false;
1646         }
1647         if (appearance == 0 || !sTmpRect2.setIntersect(winFrame, statusBarFrame)) {
1648             mStatusBarAppearanceRegionList.add(new AppearanceRegion(0, new Rect(winBounds)));
1649             mStatusBarColorCheckedBounds.union(sTmpRect);
1650             return true;
1651         }
1652         // A dimming window can divide status bar into different appearance regions (up to 3).
1653         // +---------+-------------+---------+
1654         // |/////////|             |/////////| <-- Status Bar
1655         // +---------+-------------+---------+
1656         // |/////////|             |/////////|
1657         // |/////////|             |/////////|
1658         // |/////////|             |/////////|
1659         // |/////////|             |/////////|
1660         // |/////////|             |/////////|
1661         // +---------+-------------+---------+
1662         //      ^           ^           ^
1663         //  dim layer     window    dim layer
1664         mStatusBarAppearanceRegionList.add(new AppearanceRegion(appearance, new Rect(winFrame)));
1665         if (!sTmpRect.equals(sTmpRect2)) {
1666             if (sTmpRect.height() == sTmpRect2.height()) {
1667                 if (sTmpRect.left != sTmpRect2.left) {
1668                     mStatusBarAppearanceRegionList.add(new AppearanceRegion(0, new Rect(
1669                             winBounds.left, winBounds.top, sTmpRect2.left, winBounds.bottom)));
1670                 }
1671                 if (sTmpRect.right != sTmpRect2.right) {
1672                     mStatusBarAppearanceRegionList.add(new AppearanceRegion(0, new Rect(
1673                             sTmpRect2.right, winBounds.top, winBounds.right, winBounds.bottom)));
1674                 }
1675             }
1676             // We don't have vertical status bar yet, so we don't handle the other orientation.
1677         }
1678         mStatusBarColorCheckedBounds.union(sTmpRect);
1679         return true;
1680     }
1681 
1682     private void addSystemBarColorApp(WindowState win) {
1683         final ActivityRecord app = win.mActivityRecord;
1684         if (app != null) {
1685             mSystemBarColorApps.add(app);
1686         }
1687     }
1688 
1689     /**
1690      * Called following layout of all windows and after policy has been applied to each window.
1691      */
1692     public void finishPostLayoutPolicyLw() {
1693         // If we are not currently showing a dream then remember the current
1694         // lockscreen state.  We will use this to determine whether the dream
1695         // started while the lockscreen was showing and remember this state
1696         // while the dream is showing.
1697         if (!mShowingDream) {
1698             mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
1699         }
1700 
1701         updateSystemBarAttributes();
1702 
1703         if (mShowingDream != mLastShowingDream) {
1704             mLastShowingDream = mShowingDream;
1705             // Notify that isShowingDreamLw (which is checked in KeyguardController) has changed.
1706             mDisplayContent.notifyKeyguardFlagsChanged();
1707         }
1708 
1709         mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
1710     }
1711 
1712     boolean areTypesForciblyShownTransiently(@InsetsType int types) {
1713         return (mForciblyShownTypes & types) == types;
1714     }
1715 
1716     /**
1717      * Applies the keyguard policy to a specific window.
1718      *
1719      * @param win The window to apply the keyguard policy.
1720      * @param imeTarget The current IME target window.
1721      */
1722     private void applyKeyguardPolicy(WindowState win, WindowState imeTarget) {
1723         if (win.canBeHiddenByKeyguard()) {
1724             final boolean shouldBeHiddenByKeyguard = shouldBeHiddenByKeyguard(win, imeTarget);
1725             if (win.mIsImWindow) {
1726                 // Notify IME insets provider to freeze the IME insets. In case when turning off
1727                 // the screen, the IME insets source window will be hidden because of keyguard
1728                 // policy change and affects the system to freeze the last insets state. (And
1729                 // unfreeze when the IME is going to show)
1730                 mDisplayContent.getInsetsStateController().getImeSourceProvider().setFrozen(
1731                         shouldBeHiddenByKeyguard);
1732             }
1733             if (shouldBeHiddenByKeyguard) {
1734                 win.hide(false /* doAnimation */, true /* requestAnim */);
1735             } else {
1736                 win.show(false /* doAnimation */, true /* requestAnim */);
1737             }
1738         }
1739     }
1740 
1741     private boolean shouldBeHiddenByKeyguard(WindowState win, WindowState imeTarget) {
1742         if (!mDisplayContent.isDefaultDisplay || !isKeyguardShowing()) {
1743             return false;
1744         }
1745 
1746         // Show IME over the keyguard if the target allows it.
1747         final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisible()
1748                 && win.mIsImWindow && (imeTarget.canShowWhenLocked()
1749                         || !imeTarget.canBeHiddenByKeyguard());
1750         if (showImeOverKeyguard) {
1751             return false;
1752         }
1753 
1754         // Show SHOW_WHEN_LOCKED windows if keyguard is occluded.
1755         final boolean allowShowWhenLocked = isKeyguardOccluded()
1756                 // Show error dialogs over apps that are shown on keyguard.
1757                 && (win.canShowWhenLocked()
1758                         || (win.mAttrs.privateFlags & LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR) != 0);
1759         return !allowShowWhenLocked;
1760     }
1761 
1762     /**
1763      * @return Whether the top fullscreen app hides the given type of system bar.
1764      */
1765     boolean topAppHidesSystemBar(@InsetsType int type) {
1766         if (mTopFullscreenOpaqueWindowState == null
1767                 || getInsetsPolicy().areTypesForciblyShowing(type)) {
1768             return false;
1769         }
1770         return !mTopFullscreenOpaqueWindowState.isRequestedVisible(type);
1771     }
1772 
1773     /**
1774      * Called when the user is switched.
1775      */
1776     public void switchUser() {
1777         updateCurrentUserResources();
1778         updateForceShowNavBarSettings();
1779     }
1780 
1781     /**
1782      * Called when the resource overlays change.
1783      */
1784     void onOverlayChanged() {
1785         updateCurrentUserResources();
1786         // Update the latest display size, cutout.
1787         mDisplayContent.requestDisplayUpdate(() -> {
1788             onConfigurationChanged();
1789             if (!CLIENT_TRANSIENT) {
1790                 mSystemGestures.onConfigurationChanged();
1791             }
1792         });
1793     }
1794 
1795     /**
1796      * Called when the configuration has changed, and it's safe to load new values from resources.
1797      */
1798     public void onConfigurationChanged() {
1799         final Resources res = getCurrentUserResources();
1800         mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
1801         mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res);
1802         mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res);
1803         mNavigationBarAlwaysShowOnSideGesture =
1804                 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
1805         mRemoteInsetsControllerControlsSystemBars = res.getBoolean(
1806                 R.bool.config_remoteInsetsControllerControlsSystemBars);
1807 
1808         updateConfigurationAndScreenSizeDependentBehaviors();
1809 
1810         final boolean shouldAttach =
1811                 res.getBoolean(R.bool.config_attachNavBarToAppDuringTransition)
1812                         && !Flags.enableTinyTaskbar();
1813         if (mShouldAttachNavBarToAppDuringTransition != shouldAttach) {
1814             mShouldAttachNavBarToAppDuringTransition = shouldAttach;
1815         }
1816     }
1817 
1818     void updateConfigurationAndScreenSizeDependentBehaviors() {
1819         final Resources res = getCurrentUserResources();
1820         mNavigationBarCanMove =
1821                 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
1822                         && res.getBoolean(R.bool.config_navBarCanMove);
1823         mDisplayContent.getDisplayRotation().updateUserDependentConfiguration(res);
1824     }
1825 
1826     /**
1827      * Updates the current user's resources to pick up any changes for the current user (including
1828      * overlay paths)
1829      */
1830     private void updateCurrentUserResources() {
1831         final int userId = mService.mAmInternal.getCurrentUserId();
1832         final Context uiContext = getSystemUiContext();
1833 
1834         if (userId == UserHandle.USER_SYSTEM) {
1835             // Skip the (expensive) recreation of resources for the system user below and just
1836             // use the resources from the system ui context
1837             mCurrentUserResources = uiContext.getResources();
1838             return;
1839         }
1840 
1841         // For non-system users, ensure that the resources are loaded from the current
1842         // user's package info (see ContextImpl.createDisplayContext)
1843         final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
1844                 uiContext.getPackageName(), null, 0, userId);
1845         mCurrentUserResources = ResourcesManager.getInstance().getResources(
1846                 uiContext.getWindowContextToken(),
1847                 pi.getResDir(),
1848                 null /* splitResDirs */,
1849                 pi.getOverlayDirs(),
1850                 pi.getOverlayPaths(),
1851                 pi.getApplicationInfo().sharedLibraryFiles,
1852                 mDisplayContent.getDisplayId(),
1853                 null /* overrideConfig */,
1854                 uiContext.getResources().getCompatibilityInfo(),
1855                 null /* classLoader */,
1856                 null /* loaders */);
1857     }
1858 
1859     @VisibleForTesting
1860     Resources getCurrentUserResources() {
1861         if (mCurrentUserResources == null) {
1862             updateCurrentUserResources();
1863         }
1864         return mCurrentUserResources;
1865     }
1866 
1867     @VisibleForTesting
1868     Context getContext() {
1869         return mContext;
1870     }
1871 
1872     Context getSystemUiContext() {
1873         return mUiContext;
1874     }
1875 
1876     @VisibleForTesting
1877     void setCanSystemBarsBeShownByUser(boolean canBeShown) {
1878         mCanSystemBarsBeShownByUser = canBeShown;
1879     }
1880 
1881     void notifyDisplayReady() {
1882         mHandler.post(() -> {
1883             final int displayId = getDisplayId();
1884             StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
1885             if (statusBar != null) {
1886                 statusBar.onDisplayReady(displayId);
1887             }
1888             final WallpaperManagerInternal wpMgr = LocalServices
1889                     .getService(WallpaperManagerInternal.class);
1890             if (wpMgr != null) {
1891                 wpMgr.onDisplayReady(displayId);
1892             }
1893         });
1894     }
1895 
1896     /**
1897      * Return corner radius in pixels that should be used on windows in order to cover the display.
1898      *
1899      * The radius is only valid for internal displays, since the corner radius of external displays
1900      * is not known at build time when window corners are configured.
1901      */
1902     float getWindowCornerRadius() {
1903         return mDisplayContent.getDisplay().getType() == TYPE_INTERNAL
1904                 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext) : 0f;
1905     }
1906 
1907     boolean isShowingDreamLw() {
1908         return mShowingDream;
1909     }
1910 
1911     /** The latest insets and frames for screen configuration calculation. */
1912     static class DecorInsets {
1913         static class Info {
1914             /**
1915              * The insets for the areas that could never be removed, i.e. display cutout and
1916              * navigation bar. Note that its meaning is actually "decor insets". The "non" is just
1917              * because it is used to calculate {@link #mNonDecorFrame}.
1918              */
1919             final Rect mNonDecorInsets = new Rect();
1920 
1921             /**
1922              * The stable insets that can affect configuration. The sources are usually from
1923              * display cutout, navigation bar, and status bar.
1924              */
1925             final Rect mConfigInsets = new Rect();
1926 
1927             /**
1928              * Override value of mConfigInsets for app compatibility purpose.
1929              */
1930             final Rect mOverrideConfigInsets = new Rect();
1931 
1932             /**
1933              * Override value of mNonDecorInsets for app compatibility purpose.
1934              */
1935             final Rect mOverrideNonDecorInsets = new Rect();
1936 
1937             /** The display frame available after excluding {@link #mNonDecorInsets}. */
1938             final Rect mNonDecorFrame = new Rect();
1939 
1940             /**
1941              * The available (stable) screen size that we should report for the configuration.
1942              * This must be no larger than {@link #mNonDecorFrame}; it may be smaller than that
1943              * to account for more transient decoration like a status bar.
1944              */
1945             final Rect mConfigFrame = new Rect();
1946 
1947             /**
1948              * Override value of mConfigFrame for app compatibility purpose.
1949              */
1950             final Rect mOverrideConfigFrame = new Rect();
1951 
1952             /**
1953              * Override value of mNonDecorFrame for app compatibility purpose.
1954              */
1955             final Rect mOverrideNonDecorFrame = new Rect();
1956 
1957             private boolean mNeedUpdate = true;
1958 
1959             InsetsState update(DisplayContent dc, int rotation, int w, int h) {
1960                 final DisplayFrames df = new DisplayFrames();
1961                 dc.updateDisplayFrames(df, rotation, w, h);
1962                 dc.getDisplayPolicy().simulateLayoutDisplay(df);
1963                 final InsetsState insetsState = df.mInsetsState;
1964                 final Rect displayFrame = insetsState.getDisplayFrame();
1965                 final Insets decor = insetsState.calculateInsets(displayFrame,
1966                         dc.mWmService.mDecorTypes, true /* ignoreVisibility */);
1967                 final Insets configInsets = dc.mWmService.mConfigTypes == dc.mWmService.mDecorTypes
1968                         ? decor
1969                         : insetsState.calculateInsets(displayFrame, dc.mWmService.mConfigTypes,
1970                                 true /* ignoreVisibility */);
1971                 final Insets overrideConfigInsets = dc.mWmService.mConfigTypes
1972                         == dc.mWmService.mOverrideConfigTypes
1973                         ? configInsets
1974                         : insetsState.calculateInsets(displayFrame,
1975                                 dc.mWmService.mOverrideConfigTypes, true /* ignoreVisibility */);
1976                 final Insets overrideDecorInsets = dc.mWmService.mDecorTypes
1977                         == dc.mWmService.mOverrideDecorTypes
1978                         ? decor
1979                         : insetsState.calculateInsets(displayFrame,
1980                                 dc.mWmService.mOverrideDecorTypes, true /* ignoreVisibility */);
1981                 mNonDecorInsets.set(decor.left, decor.top, decor.right, decor.bottom);
1982                 mConfigInsets.set(configInsets.left, configInsets.top, configInsets.right,
1983                         configInsets.bottom);
1984                 mOverrideConfigInsets.set(overrideConfigInsets.left, overrideConfigInsets.top,
1985                         overrideConfigInsets.right, overrideConfigInsets.bottom);
1986                 mOverrideNonDecorInsets.set(overrideDecorInsets.left, overrideDecorInsets.top,
1987                         overrideDecorInsets.right, overrideDecorInsets.bottom);
1988                 mNonDecorFrame.set(displayFrame);
1989                 mNonDecorFrame.inset(mNonDecorInsets);
1990                 mConfigFrame.set(displayFrame);
1991                 mConfigFrame.inset(mConfigInsets);
1992                 mOverrideConfigFrame.set(displayFrame);
1993                 mOverrideConfigFrame.inset(mOverrideConfigInsets);
1994                 mOverrideNonDecorFrame.set(displayFrame);
1995                 mOverrideNonDecorFrame.inset(mOverrideNonDecorInsets);
1996                 mNeedUpdate = false;
1997                 return insetsState;
1998             }
1999 
2000             void set(Info other) {
2001                 mNonDecorInsets.set(other.mNonDecorInsets);
2002                 mConfigInsets.set(other.mConfigInsets);
2003                 mOverrideConfigInsets.set(other.mOverrideConfigInsets);
2004                 mOverrideNonDecorInsets.set(other.mOverrideNonDecorInsets);
2005                 mNonDecorFrame.set(other.mNonDecorFrame);
2006                 mConfigFrame.set(other.mConfigFrame);
2007                 mOverrideConfigFrame.set(other.mOverrideConfigFrame);
2008                 mOverrideNonDecorFrame.set(other.mOverrideNonDecorFrame);
2009                 mNeedUpdate = false;
2010             }
2011 
2012             @Override
2013             public String toString() {
2014                 final StringBuilder tmpSb = new StringBuilder(32);
2015                 return "{nonDecorInsets=" + mNonDecorInsets.toShortString(tmpSb)
2016                         + ", overrideNonDecorInsets=" + mOverrideNonDecorInsets.toShortString(tmpSb)
2017                         + ", configInsets=" + mConfigInsets.toShortString(tmpSb)
2018                         + ", overrideConfigInsets=" + mOverrideConfigInsets.toShortString(tmpSb)
2019                         + ", nonDecorFrame=" + mNonDecorFrame.toShortString(tmpSb)
2020                         + ", overrideNonDecorFrame=" + mOverrideNonDecorFrame.toShortString(tmpSb)
2021                         + ", configFrame=" + mConfigFrame.toShortString(tmpSb)
2022                         + ", overrideConfigFrame=" + mOverrideConfigFrame.toShortString(tmpSb)
2023                         + '}';
2024             }
2025         }
2026 
2027         private final DisplayContent mDisplayContent;
2028         private final Info[] mInfoForRotation = new Info[4];
2029         final Info mTmpInfo = new Info();
2030 
2031         DecorInsets(DisplayContent dc) {
2032             mDisplayContent = dc;
2033             for (int i = mInfoForRotation.length - 1; i >= 0; i--) {
2034                 mInfoForRotation[i] = new Info();
2035             }
2036         }
2037 
2038         Info get(int rotation, int w, int h) {
2039             final Info info = mInfoForRotation[rotation];
2040             if (info.mNeedUpdate) {
2041                 info.update(mDisplayContent, rotation, w, h);
2042             }
2043             return info;
2044         }
2045 
2046         /** Called when the screen decor insets providers have changed. */
2047         void invalidate() {
2048             for (Info info : mInfoForRotation) {
2049                 info.mNeedUpdate = true;
2050             }
2051         }
2052 
2053         void setTo(DecorInsets src) {
2054             for (int i = mInfoForRotation.length - 1; i >= 0; i--) {
2055                 mInfoForRotation[i].set(src.mInfoForRotation[i]);
2056             }
2057         }
2058 
2059         void dump(String prefix, PrintWriter pw) {
2060             for (int rotation = 0; rotation < mInfoForRotation.length; rotation++) {
2061                 final DecorInsets.Info info = mInfoForRotation[rotation];
2062                 pw.println(prefix + Surface.rotationToString(rotation) + "=" + info);
2063             }
2064         }
2065 
2066         static boolean hasInsetsFrameDiff(InsetsState s1, InsetsState s2, int insetsTypes) {
2067             int insetsCount1 = 0;
2068             for (int i = s1.sourceSize() - 1; i >= 0; i--) {
2069                 final InsetsSource source1 = s1.sourceAt(i);
2070                 if ((source1.getType() & insetsTypes) == 0) {
2071                     continue;
2072                 }
2073                 insetsCount1++;
2074                 final InsetsSource source2 = s2.peekSource(source1.getId());
2075                 if (source2 == null || !source2.getFrame().equals(source1.getFrame())) {
2076                     return true;
2077                 }
2078             }
2079             int insetsCount2 = 0;
2080             for (int i = s2.sourceSize() - 1; i >= 0; i--) {
2081                 final InsetsSource source2 = s2.sourceAt(i);
2082                 if ((source2.getType() & insetsTypes) != 0) {
2083                     insetsCount2++;
2084                 }
2085             }
2086             return insetsCount1 != insetsCount2;
2087         }
2088 
2089         private static class Cache {
2090             /**
2091              * If {@link #mPreserveId} is this value, it is in the middle of updating display
2092              * configuration before a transition is started. Then the active cache should be used.
2093              */
2094             static final int ID_UPDATING_CONFIG = -1;
2095             final DecorInsets mDecorInsets;
2096             int mPreserveId;
2097             boolean mActive;
2098 
2099             Cache(DisplayContent dc) {
2100                 mDecorInsets = new DecorInsets(dc);
2101             }
2102 
2103             boolean canPreserve() {
2104                 return mPreserveId == ID_UPDATING_CONFIG || mDecorInsets.mDisplayContent
2105                         .mTransitionController.inTransition(mPreserveId);
2106             }
2107         }
2108     }
2109 
2110     /**
2111      * If the decor insets changes, the display configuration may be affected. The caller should
2112      * call {@link DisplayContent#sendNewConfiguration()} if this method returns {@code true}.
2113      */
2114     boolean updateDecorInsetsInfo() {
2115         if (shouldKeepCurrentDecorInsets()) {
2116             return false;
2117         }
2118         final DisplayFrames displayFrames = mDisplayContent.mDisplayFrames;
2119         final int rotation = displayFrames.mRotation;
2120         final int dw = displayFrames.mWidth;
2121         final int dh = displayFrames.mHeight;
2122         final DecorInsets.Info newInfo = mDecorInsets.mTmpInfo;
2123         final InsetsState newInsetsState = newInfo.update(mDisplayContent, rotation, dw, dh);
2124         final DecorInsets.Info currentInfo = getDecorInsetsInfo(rotation, dw, dh);
2125         if (newInfo.mConfigFrame.equals(currentInfo.mConfigFrame)
2126                 && newInfo.mOverrideConfigFrame.equals(currentInfo.mOverrideConfigFrame)) {
2127             // Even if the config frame is not changed in current rotation, it may change the
2128             // insets in other rotations if the frame of insets source is changed.
2129             final InsetsState currentInsetsState = mDisplayContent.mDisplayFrames.mInsetsState;
2130             if (DecorInsets.hasInsetsFrameDiff(
2131                     newInsetsState, currentInsetsState, mService.mConfigTypes)) {
2132                 for (int i = mDecorInsets.mInfoForRotation.length - 1; i >= 0; i--) {
2133                     if (i != rotation) {
2134                         final boolean flipSize = (i + rotation) % 2 == 1;
2135                         final int w = flipSize ? dh : dw;
2136                         final int h = flipSize ? dw : dh;
2137                         mDecorInsets.mInfoForRotation[i].update(mDisplayContent, i, w, h);
2138                     }
2139                 }
2140                 mDecorInsets.mInfoForRotation[rotation].set(newInfo);
2141             }
2142             return false;
2143         }
2144         if (mCachedDecorInsets != null && !mCachedDecorInsets.canPreserve() && mScreenOnFully) {
2145             mCachedDecorInsets = null;
2146         }
2147         mDecorInsets.invalidate();
2148         mDecorInsets.mInfoForRotation[rotation].set(newInfo);
2149         return true;
2150     }
2151 
2152     DecorInsets.Info getDecorInsetsInfo(int rotation, int w, int h) {
2153         return mDecorInsets.get(rotation, w, h);
2154     }
2155 
2156     /** Returns {@code true} to trust that {@link #mDecorInsets} already has the expected state. */
2157     boolean shouldKeepCurrentDecorInsets() {
2158         return mCachedDecorInsets != null && mCachedDecorInsets.mActive
2159                 && mCachedDecorInsets.canPreserve();
2160     }
2161 
2162     void physicalDisplayChanged() {
2163         if (USE_CACHED_INSETS_FOR_DISPLAY_SWITCH) {
2164             updateCachedDecorInsets();
2165         }
2166     }
2167 
2168     /**
2169      * Caches the current insets and switches current insets to previous cached insets. This is to
2170      * reduce multiple display configuration changes if there are multiple insets provider windows
2171      * which may trigger {@link #updateDecorInsetsInfo()} individually.
2172      */
2173     @VisibleForTesting
2174     void updateCachedDecorInsets() {
2175         DecorInsets prevCache = null;
2176         if (mCachedDecorInsets == null) {
2177             mCachedDecorInsets = new DecorInsets.Cache(mDisplayContent);
2178         } else {
2179             prevCache = new DecorInsets(mDisplayContent);
2180             prevCache.setTo(mCachedDecorInsets.mDecorInsets);
2181         }
2182         // Set a special id to preserve it before a real id is available from transition.
2183         mCachedDecorInsets.mPreserveId = DecorInsets.Cache.ID_UPDATING_CONFIG;
2184         // Cache the current insets.
2185         mCachedDecorInsets.mDecorInsets.setTo(mDecorInsets);
2186         // Switch current to previous cache.
2187         if (prevCache != null) {
2188             mDecorInsets.setTo(prevCache);
2189             mCachedDecorInsets.mActive = true;
2190         }
2191     }
2192 
2193     /**
2194      * Called after the display configuration is updated according to the physical change. Suppose
2195      * there should be a display change transition, so associate the cached decor insets with the
2196      * transition to limit the lifetime of using the cache.
2197      */
2198     void physicalDisplayUpdated() {
2199         if (mCachedDecorInsets == null) {
2200             return;
2201         }
2202         if (!mDisplayContent.mTransitionController.isCollecting()) {
2203             // Unable to know when the display switch is finished.
2204             mCachedDecorInsets = null;
2205             return;
2206         }
2207         mCachedDecorInsets.mPreserveId =
2208                 mDisplayContent.mTransitionController.getCollectingTransitionId();
2209     }
2210 
2211     /** If this is called, expect that there will be an onDisplayChanged about unique id. */
2212     public void onDisplaySwitchStart() {
2213         mDisplayContent.mDisplayUpdater.onDisplaySwitching(true);
2214     }
2215 
2216     @NavigationBarPosition
2217     int navigationBarPosition(int displayRotation) {
2218         if (mNavigationBar != null) {
2219             final int gravity = mNavigationBar.mAttrs.forRotation(displayRotation).gravity;
2220             switch (gravity) {
2221                 case Gravity.LEFT:
2222                     return NAV_BAR_LEFT;
2223                 case Gravity.RIGHT:
2224                     return NAV_BAR_RIGHT;
2225                 default:
2226                     return NAV_BAR_BOTTOM;
2227             }
2228         }
2229         return NAV_BAR_INVALID;
2230     }
2231 
2232     /**
2233      * A new window has been focused.
2234      */
2235     public void focusChangedLw(WindowState lastFocus, WindowState newFocus) {
2236         mFocusedWindow = newFocus;
2237         mLastFocusedWindow = lastFocus;
2238         if (mDisplayContent.isDefaultDisplay) {
2239             mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
2240         }
2241         updateSystemBarAttributes();
2242     }
2243 
2244     @VisibleForTesting
2245     void requestTransientBars(WindowState swipeTarget, boolean isGestureOnSystemBar) {
2246         if (CLIENT_TRANSIENT) {
2247             return;
2248         }
2249         if (swipeTarget == null || !mService.mPolicy.isUserSetupComplete()) {
2250             // Swipe-up for navigation bar is disabled during setup
2251             return;
2252         }
2253         if (!mCanSystemBarsBeShownByUser) {
2254             Slog.d(TAG, "Remote insets controller disallows showing system bars - ignoring "
2255                     + "request");
2256             return;
2257         }
2258         final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
2259         final InsetsControlTarget controlTarget = provider != null
2260                 ? provider.getControlTarget() : null;
2261 
2262         if (controlTarget == null || controlTarget == getNotificationShade()) {
2263             // No transient mode on lockscreen (in notification shade window).
2264             return;
2265         }
2266 
2267         if (controlTarget != null) {
2268             final WindowState win = controlTarget.getWindow();
2269 
2270             if (win != null && win.isActivityTypeDream()) {
2271                 return;
2272             }
2273         }
2274 
2275         final @InsetsType int restorePositionTypes = (Type.statusBars() | Type.navigationBars())
2276                 & controlTarget.getRequestedVisibleTypes();
2277 
2278         final InsetsSourceProvider sp = swipeTarget.getControllableInsetProvider();
2279         if (sp != null && sp.getSource().getType() == Type.navigationBars()
2280                 && (restorePositionTypes & Type.navigationBars()) != 0) {
2281             // Don't show status bar when swiping on already visible navigation bar.
2282             // But restore the position of navigation bar if it has been moved by the control
2283             // target.
2284             controlTarget.showInsets(Type.navigationBars(), false /* fromIme */,
2285                     null /* statsToken */);
2286             return;
2287         }
2288 
2289         if (controlTarget.canShowTransient()) {
2290             // Show transient bars if they are hidden; restore position if they are visible.
2291             mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE,
2292                     isGestureOnSystemBar);
2293             controlTarget.showInsets(restorePositionTypes, false /* fromIme */,
2294                     null /* statsToken */);
2295         } else {
2296             // Restore visibilities and positions of system bars.
2297             controlTarget.showInsets(Type.statusBars() | Type.navigationBars(),
2298                     false /* fromIme */, null /* statsToken */);
2299             // To further allow the pull-down-from-the-top gesture to pull down the notification
2300             // shade as a consistent motion, we reroute the touch events here from the currently
2301             // touched window to the status bar after making it visible.
2302             if (swipeTarget == mStatusBar) {
2303                 final boolean transferred = mStatusBar.transferTouch();
2304                 if (!transferred) {
2305                     Slog.i(TAG, "Could not transfer touch to the status bar");
2306                 }
2307             }
2308         }
2309         if (CLIENT_IMMERSIVE_CONFIRMATION || CLIENT_TRANSIENT) {
2310             mStatusBarManagerInternal.confirmImmersivePrompt();
2311         } else {
2312             mImmersiveModeConfirmation.confirmCurrentPrompt();
2313         }
2314     }
2315 
2316     boolean isKeyguardShowing() {
2317         return mService.mPolicy.isKeyguardShowing();
2318     }
2319     private boolean isKeyguardOccluded() {
2320         // TODO (b/113840485): Handle per display keyguard.
2321         return mService.mPolicy.isKeyguardOccluded();
2322     }
2323 
2324     InsetsPolicy getInsetsPolicy() {
2325         return mDisplayContent.getInsetsPolicy();
2326     }
2327 
2328     /**
2329      * Called when an app has started replacing its main window.
2330      */
2331     void addRelaunchingApp(ActivityRecord app) {
2332         if (mSystemBarColorApps.contains(app) && !app.hasStartingWindow()) {
2333             mRelaunchingSystemBarColorApps.add(app);
2334         }
2335     }
2336 
2337     /**
2338      * Called when an app has finished replacing its main window or aborted.
2339      */
2340     void removeRelaunchingApp(ActivityRecord app) {
2341         final boolean removed = mRelaunchingSystemBarColorApps.remove(app);
2342         if (removed & mRelaunchingSystemBarColorApps.isEmpty()) {
2343             updateSystemBarAttributes();
2344         }
2345     }
2346 
2347     void resetSystemBarAttributes() {
2348         mLastDisableFlags = 0;
2349         updateSystemBarAttributes();
2350     }
2351 
2352     void updateSystemBarAttributes() {
2353         // If there is no window focused, there will be nobody to handle the events
2354         // anyway, so just hang on in whatever state we're in until things settle down.
2355         WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
2356                 : mTopFullscreenOpaqueWindowState;
2357         if (winCandidate == null) {
2358             return;
2359         }
2360 
2361         // Immersive mode confirmation should never affect the system bar visibility, otherwise
2362         // it will unhide the navigation bar and hide itself.
2363         if ((winCandidate.getAttrs().privateFlags
2364                 & PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW) != 0) {
2365             if (mNotificationShade != null && mNotificationShade.canReceiveKeys()) {
2366                 // Let notification shade control the system bar visibility.
2367                 winCandidate = mNotificationShade;
2368             } else if (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys()) {
2369                 // Immersive mode confirmation took the focus from mLastFocusedWindow which was
2370                 // controlling the system bar visibility. Let it keep controlling the visibility.
2371                 winCandidate = mLastFocusedWindow;
2372             } else {
2373                 winCandidate = mTopFullscreenOpaqueWindowState;
2374             }
2375             if (winCandidate == null) {
2376                 return;
2377             }
2378         }
2379         final WindowState win = winCandidate;
2380         mSystemUiControllingWindow = win;
2381 
2382         final int displayId = getDisplayId();
2383         final int disableFlags = win.getDisableFlags();
2384         final int opaqueAppearance = updateSystemBarsLw(win, disableFlags);
2385         if (!mRelaunchingSystemBarColorApps.isEmpty()) {
2386             // The appearance of system bars might change while relaunching apps. We don't report
2387             // the intermediate state to system UI. Otherwise, it might trigger redundant effects.
2388             return;
2389         }
2390         final WindowState navColorWin = chooseNavigationColorWindowLw(mNavBarColorWindowCandidate,
2391                 mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
2392         final boolean isNavbarColorManagedByIme =
2393                 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
2394         final int appearance = updateLightNavigationBarLw(win.mAttrs.insetsFlags.appearance,
2395                 navColorWin) | opaqueAppearance;
2396         final WindowState navBarControlWin = topAppHidesSystemBar(Type.navigationBars())
2397                 ? mTopFullscreenOpaqueWindowState
2398                 : win;
2399         final int behavior = navBarControlWin.mAttrs.insetsFlags.behavior;
2400         final String focusedApp = win.mAttrs.packageName;
2401         final boolean isFullscreen = !win.isRequestedVisible(Type.statusBars())
2402                 || !win.isRequestedVisible(Type.navigationBars());
2403         final AppearanceRegion[] statusBarAppearanceRegions =
2404                 new AppearanceRegion[mStatusBarAppearanceRegionList.size()];
2405         mStatusBarAppearanceRegionList.toArray(statusBarAppearanceRegions);
2406         if (mLastDisableFlags != disableFlags) {
2407             mLastDisableFlags = disableFlags;
2408             final String cause = win.toString();
2409             callStatusBarSafely(statusBar -> statusBar.setDisableFlags(displayId, disableFlags,
2410                     cause));
2411         }
2412         final @InsetsType int requestedVisibleTypes = win.getRequestedVisibleTypes();
2413         final LetterboxDetails[] letterboxDetails = new LetterboxDetails[mLetterboxDetails.size()];
2414         mLetterboxDetails.toArray(letterboxDetails);
2415         if (mLastAppearance == appearance
2416                 && mLastBehavior == behavior
2417                 && mLastRequestedVisibleTypes == requestedVisibleTypes
2418                 && Objects.equals(mFocusedApp, focusedApp)
2419                 && mLastFocusIsFullscreen == isFullscreen
2420                 && Arrays.equals(mLastStatusBarAppearanceRegions, statusBarAppearanceRegions)
2421                 && Arrays.equals(mLastLetterboxDetails, letterboxDetails)) {
2422             return;
2423         }
2424         if (mDisplayContent.isDefaultDisplay && (mLastFocusIsFullscreen != isFullscreen
2425                 || ((mLastAppearance ^ appearance) & APPEARANCE_LOW_PROFILE_BARS) != 0)) {
2426             mService.mInputManager.setSystemUiLightsOut(
2427                     isFullscreen || (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0);
2428         }
2429         mLastAppearance = appearance;
2430         mLastBehavior = behavior;
2431         mLastRequestedVisibleTypes = requestedVisibleTypes;
2432         mFocusedApp = focusedApp;
2433         mLastFocusIsFullscreen = isFullscreen;
2434         mLastStatusBarAppearanceRegions = statusBarAppearanceRegions;
2435         mLastLetterboxDetails = letterboxDetails;
2436         callStatusBarSafely(statusBar -> statusBar.onSystemBarAttributesChanged(displayId,
2437                 appearance, statusBarAppearanceRegions, isNavbarColorManagedByIme, behavior,
2438                 requestedVisibleTypes, focusedApp, letterboxDetails));
2439     }
2440 
2441     private void callStatusBarSafely(Consumer<StatusBarManagerInternal> consumer) {
2442         mHandler.post(() -> {
2443             StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
2444             if (statusBar != null) {
2445                 consumer.accept(statusBar);
2446             }
2447         });
2448     }
2449 
2450     @VisibleForTesting
2451     @Nullable
2452     static WindowState chooseNavigationColorWindowLw(WindowState candidate, WindowState imeWindow,
2453             @NavigationBarPosition int navBarPosition) {
2454         // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
2455         // window can be navigation color window.
2456         final boolean imeWindowCanNavColorWindow = imeWindow != null
2457                 && imeWindow.isVisible()
2458                 && navBarPosition == NAV_BAR_BOTTOM
2459                 && (imeWindow.mAttrs.flags
2460                         & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
2461         if (!imeWindowCanNavColorWindow) {
2462             // No IME window is involved. Determine the result only with candidate window.
2463             return candidate;
2464         }
2465 
2466         if (candidate != null && candidate.isDimming()) {
2467             // The IME window and the dimming window are competing. Check if the dimming window can
2468             // be IME target or not.
2469             if (LayoutParams.mayUseInputMethod(candidate.mAttrs.flags)) {
2470                 // The IME window is above the dimming window.
2471                 return imeWindow;
2472             } else {
2473                 // The dimming window is above the IME window.
2474                 return candidate;
2475             }
2476         }
2477 
2478         return imeWindow;
2479     }
2480 
2481     @VisibleForTesting
2482     int updateLightNavigationBarLw(int appearance, WindowState navColorWin) {
2483         if (navColorWin == null || !isLightBarAllowed(navColorWin, Type.navigationBars())) {
2484             // Clear the light flag while not allowed.
2485             appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
2486             return appearance;
2487         }
2488 
2489         // Respect the light flag of navigation color window.
2490         appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS;
2491         appearance |= navColorWin.mAttrs.insetsFlags.appearance
2492                 & APPEARANCE_LIGHT_NAVIGATION_BARS;
2493         return appearance;
2494     }
2495 
2496     private int updateSystemBarsLw(WindowState win, int disableFlags) {
2497         final TaskDisplayArea defaultTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea();
2498         final boolean adjacentTasksVisible =
2499                 defaultTaskDisplayArea.getRootTask(task -> task.isVisible()
2500                         && task.getTopLeafTask().getAdjacentTask() != null)
2501                         != null;
2502         final boolean freeformRootTaskVisible =
2503                 defaultTaskDisplayArea.isRootTaskVisible(WINDOWING_MODE_FREEFORM);
2504 
2505         getInsetsPolicy().updateSystemBars(win, adjacentTasksVisible, freeformRootTaskVisible);
2506 
2507         final boolean topAppHidesStatusBar = topAppHidesSystemBar(Type.statusBars());
2508         if (getStatusBar() != null) {
2509             final StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
2510             if (statusBar != null) {
2511                 statusBar.setTopAppHidesStatusBar(topAppHidesStatusBar);
2512             }
2513         }
2514 
2515         // If the top app is not fullscreen, only the default rotation animation is allowed.
2516         mTopIsFullscreen = topAppHidesStatusBar
2517                 && (mNotificationShade == null || !mNotificationShade.isVisible());
2518 
2519         int appearance = APPEARANCE_OPAQUE_NAVIGATION_BARS | APPEARANCE_OPAQUE_STATUS_BARS;
2520         appearance = configureStatusBarOpacity(appearance);
2521         appearance = configureNavBarOpacity(appearance, adjacentTasksVisible,
2522                 freeformRootTaskVisible);
2523 
2524         // Show immersive mode confirmation if needed.
2525         final boolean wasImmersiveMode = mIsImmersiveMode;
2526         final boolean isImmersiveMode = isImmersiveMode(win);
2527         if (wasImmersiveMode != isImmersiveMode) {
2528             mIsImmersiveMode = isImmersiveMode;
2529             // The immersive confirmation window should be attached to the immersive window root.
2530             final RootDisplayArea root = win.getRootDisplayArea();
2531             final int rootDisplayAreaId = root == null ? FEATURE_UNDEFINED : root.mFeatureId;
2532             if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) {
2533                 mImmersiveModeConfirmation.immersiveModeChangedLw(rootDisplayAreaId,
2534                         isImmersiveMode,
2535                         mService.mPolicy.isUserSetupComplete(),
2536                         isNavBarEmpty(disableFlags));
2537             } else {
2538                 // TODO (b/277290737): Move this to the client side, instead of using a proxy.
2539                 callStatusBarSafely(statusBar -> statusBar.immersiveModeChanged(rootDisplayAreaId,
2540                         isImmersiveMode));
2541             }
2542         }
2543 
2544         // Show transient bars for panic if needed.
2545         final boolean requestHideNavBar = !win.isRequestedVisible(Type.navigationBars());
2546         final long now = SystemClock.uptimeMillis();
2547         final boolean pendingPanic = mPendingPanicGestureUptime != 0
2548                 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
2549         final DisplayPolicy defaultDisplayPolicy =
2550                 mService.getDefaultDisplayContentLocked().getDisplayPolicy();
2551         if (pendingPanic && requestHideNavBar && isImmersiveMode
2552                 // TODO (b/111955725): Show keyguard presentation on all external displays
2553                 && defaultDisplayPolicy.isKeyguardDrawComplete()) {
2554             // The user performed the panic gesture recently, we're about to hide the bars,
2555             // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
2556             mPendingPanicGestureUptime = 0;
2557             if (!isNavBarEmpty(disableFlags)) {
2558                 mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_PANIC,
2559                         true /* isGestureOnSystemBar */);
2560             }
2561         }
2562 
2563         return appearance;
2564     }
2565 
2566     private static boolean isLightBarAllowed(WindowState win, @InsetsType int type) {
2567         if (win == null) {
2568             return false;
2569         }
2570         return intersectsAnyInsets(win.getFrame(), win.getInsetsState(), type);
2571     }
2572 
2573     private Rect getBarContentFrameForWindow(WindowState win, @InsetsType int type) {
2574         final DisplayFrames displayFrames = win.getDisplayFrames(mDisplayContent.mDisplayFrames);
2575         final InsetsState state = displayFrames.mInsetsState;
2576         final Rect df = displayFrames.mUnrestricted;
2577         final Rect safe = sTmpDisplayCutoutSafe;
2578         final Insets waterfallInsets = state.getDisplayCutout().getWaterfallInsets();
2579         final Rect outRect = new Rect();
2580         final Rect sourceContent = sTmpRect;
2581         safe.set(displayFrames.mDisplayCutoutSafe);
2582         for (int i = state.sourceSize() - 1; i >= 0; i--) {
2583             final InsetsSource source = state.sourceAt(i);
2584             if (source.getType() != type) {
2585                 continue;
2586             }
2587             if (type == Type.statusBars()) {
2588                 safe.set(displayFrames.mDisplayCutoutSafe);
2589                 final Insets insets = source.calculateInsets(df, true /* ignoreVisibility */);
2590                 // The status bar content can extend into regular display cutout insets if they are
2591                 // at the same side, but the content cannot extend into waterfall insets.
2592                 if (insets.left > 0) {
2593                     safe.left = Math.max(df.left + waterfallInsets.left, df.left);
2594                 } else if (insets.top > 0) {
2595                     safe.top = Math.max(df.top + waterfallInsets.top, df.top);
2596                 } else if (insets.right > 0) {
2597                     safe.right = Math.max(df.right - waterfallInsets.right, df.right);
2598                 } else if (insets.bottom > 0) {
2599                     safe.bottom = Math.max(df.bottom - waterfallInsets.bottom, df.bottom);
2600                 }
2601             }
2602             sourceContent.set(source.getFrame());
2603             sourceContent.intersect(safe);
2604             outRect.union(sourceContent);
2605         }
2606         return outRect;
2607     }
2608 
2609     /**
2610      * @return {@code true} if bar is allowed to be fully transparent when given window is show.
2611      *
2612      * <p>Prevents showing a transparent bar over a letterboxed activity which can make
2613      * notification icons or navigation buttons unreadable due to contrast between letterbox
2614      * background and an activity. For instance, this happens when letterbox background is solid
2615      * black while activity is white. To resolve this, only semi-transparent bars are allowed to
2616      * be drawn over letterboxed activity.
2617      */
2618     @VisibleForTesting
2619     boolean isFullyTransparentAllowed(WindowState win, @InsetsType int type) {
2620         if (win == null) {
2621             return true;
2622         }
2623         return win.isFullyTransparentBarAllowed(getBarContentFrameForWindow(win, type));
2624     }
2625 
2626     private static boolean drawsBarBackground(WindowState win) {
2627         if (win == null) {
2628             return true;
2629         }
2630 
2631         final boolean drawsSystemBars =
2632                 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
2633         final boolean forceDrawsSystemBars =
2634                 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
2635 
2636         return forceDrawsSystemBars || drawsSystemBars;
2637     }
2638 
2639     /** @return the current visibility flags with the status bar opacity related flags toggled. */
2640     private int configureStatusBarOpacity(int appearance) {
2641         boolean drawBackground = true;
2642         boolean isFullyTransparentAllowed = true;
2643         for (int i = mStatusBarBackgroundWindows.size() - 1; i >= 0; i--) {
2644             final WindowState window = mStatusBarBackgroundWindows.get(i);
2645             drawBackground &= drawsBarBackground(window);
2646             isFullyTransparentAllowed &= isFullyTransparentAllowed(window, Type.statusBars());
2647         }
2648 
2649         if (drawBackground) {
2650             appearance &= ~APPEARANCE_OPAQUE_STATUS_BARS;
2651         }
2652 
2653         if (!isFullyTransparentAllowed) {
2654             appearance |= APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS;
2655         }
2656 
2657         return appearance;
2658     }
2659 
2660     /**
2661      * @return the current visibility flags with the nav-bar opacity related flags toggled based
2662      *         on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
2663      */
2664     private int configureNavBarOpacity(int appearance, boolean multiWindowTaskVisible,
2665             boolean freeformRootTaskVisible) {
2666         final WindowState navBackgroundWin = chooseNavigationBackgroundWindow(
2667                 mNavBarBackgroundWindowCandidate,
2668                 mDisplayContent.mInputMethodWindow,
2669                 mNavigationBarPosition);
2670         final boolean drawBackground = navBackgroundWin != null
2671                 // There is no app window showing underneath nav bar. (e.g., The screen is locked.)
2672                 // Let system windows (ex: notification shade) draw nav bar background.
2673                 || mNavBarBackgroundWindowCandidate == null;
2674 
2675         if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
2676             if (drawBackground) {
2677                 appearance = clearNavBarOpaqueFlag(appearance);
2678             }
2679         } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
2680             if (multiWindowTaskVisible || freeformRootTaskVisible) {
2681                 if (mIsFreeformWindowOverlappingWithNavBar) {
2682                     appearance = clearNavBarOpaqueFlag(appearance);
2683                 }
2684             } else if (drawBackground) {
2685                 appearance = clearNavBarOpaqueFlag(appearance);
2686             }
2687         } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
2688             if (freeformRootTaskVisible) {
2689                 appearance = clearNavBarOpaqueFlag(appearance);
2690             }
2691         }
2692 
2693         if (!isFullyTransparentAllowed(navBackgroundWin, Type.navigationBars())) {
2694             appearance |= APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS;
2695         }
2696 
2697         return appearance;
2698     }
2699 
2700     private int clearNavBarOpaqueFlag(int appearance) {
2701         return appearance & ~APPEARANCE_OPAQUE_NAVIGATION_BARS;
2702     }
2703 
2704     @VisibleForTesting
2705     @Nullable
2706     static WindowState chooseNavigationBackgroundWindow(WindowState candidate,
2707             WindowState imeWindow, @NavigationBarPosition int navBarPosition) {
2708         if (imeWindow != null && imeWindow.isVisible() && navBarPosition == NAV_BAR_BOTTOM
2709                 && drawsBarBackground(imeWindow)) {
2710             return imeWindow;
2711         }
2712         if (drawsBarBackground(candidate)) {
2713             return candidate;
2714         }
2715         return null;
2716     }
2717 
2718     private boolean isImmersiveMode(WindowState win) {
2719         if (win == null) {
2720             return false;
2721         }
2722         if (win.mPolicy.getWindowLayerLw(win) > win.mPolicy.getWindowLayerFromTypeLw(
2723                 WindowManager.LayoutParams.TYPE_STATUS_BAR) || win.isActivityTypeDream()) {
2724             return false;
2725         }
2726         return getInsetsPolicy().hasHiddenSources(Type.navigationBars());
2727     }
2728 
2729     private static boolean isNavBarEmpty(int systemUiFlags) {
2730         final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
2731                 | View.STATUS_BAR_DISABLE_BACK
2732                 | View.STATUS_BAR_DISABLE_RECENT);
2733 
2734         return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
2735     }
2736 
2737     private final Runnable mHiddenNavPanic = new Runnable() {
2738         @Override
2739         public void run() {
2740             synchronized (mLock) {
2741                 if (!mService.mPolicy.isUserSetupComplete()) {
2742                     // Swipe-up for navigation bar is disabled during setup
2743                     return;
2744                 }
2745                 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
2746                 updateSystemBarAttributes();
2747             }
2748         }
2749     };
2750 
2751     void onPowerKeyDown(boolean isScreenOn) {
2752         // Detect user pressing the power button in panic when an application has
2753         // taken over the whole screen.
2754         boolean panic = false;
2755         if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) {
2756             panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
2757                     SystemClock.elapsedRealtime(), isImmersiveMode(mSystemUiControllingWindow),
2758                     isNavBarEmpty(mLastDisableFlags));
2759         } else {
2760             panic = isPowerKeyDownPanic(isScreenOn, SystemClock.elapsedRealtime(),
2761                     isImmersiveMode(mSystemUiControllingWindow), isNavBarEmpty(mLastDisableFlags));
2762         }
2763         if (panic) {
2764             mHandler.post(mHiddenNavPanic);
2765         }
2766     }
2767 
2768     private boolean isPowerKeyDownPanic(boolean isScreenOn, long time, boolean inImmersiveMode,
2769             boolean navBarEmpty) {
2770         if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
2771             // turning the screen back on within the panic threshold
2772             return !mImmersiveConfirmationWindowExists;
2773         }
2774         if (isScreenOn && inImmersiveMode && !navBarEmpty) {
2775             // turning the screen off, remember if we were in immersive mode
2776             mPanicTime = time;
2777         } else {
2778             mPanicTime = 0;
2779         }
2780         return false;
2781     }
2782 
2783     void onVrStateChangedLw(boolean enabled) {
2784         if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) {
2785             mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
2786         }
2787     }
2788 
2789     /**
2790      * Called when the state of lock task mode changes. This should be used to disable immersive
2791      * mode confirmation.
2792      *
2793      * @param lockTaskState the new lock task mode state. One of
2794      *                      {@link ActivityManager#LOCK_TASK_MODE_NONE},
2795      *                      {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
2796      *                      {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
2797      */
2798     public void onLockTaskStateChangedLw(int lockTaskState) {
2799         if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) {
2800             mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
2801         }
2802     }
2803 
2804     /** Called when a {@link android.os.PowerManager#USER_ACTIVITY_EVENT_TOUCH} is sent. */
2805     public void onUserActivityEventTouch() {
2806         // If there is keyguard, it may use INPUT_FEATURE_DISABLE_USER_ACTIVITY (InputDispatcher
2807         // won't trigger user activity for touch). So while the device is not interactive, the user
2808         // event is only sent explicitly from SystemUI.
2809         if (mAwake) return;
2810         // If the event is triggered while the display is not awake, the screen may be showing
2811         // dozing UI such as AOD or overlay UI of under display fingerprint. Then set the animating
2812         // state temporarily to make the process more responsive.
2813         final WindowState w = mNotificationShade;
2814         mService.mAtmService.setProcessAnimatingWhileDozing(w != null ? w.getProcess() : null);
2815     }
2816 
2817     boolean onSystemUiSettingsChanged() {
2818         if (CLIENT_TRANSIENT || CLIENT_IMMERSIVE_CONFIRMATION) {
2819             return false;
2820         } else {
2821             return mImmersiveModeConfirmation.onSettingChanged(mService.mCurrentUserId);
2822         }
2823     }
2824 
2825     /**
2826      * Request a screenshot be taken.
2827      *
2828      * @param screenshotType The type of screenshot, for example either
2829      *                       {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
2830      *                       {@link WindowManager#TAKE_SCREENSHOT_PROVIDED_IMAGE}
2831      * @param source Where the screenshot originated from (see WindowManager.ScreenshotSource)
2832      */
2833     public void takeScreenshot(int screenshotType, int source) {
2834         if (mScreenshotHelper != null) {
2835             ScreenshotRequest request =
2836                     new ScreenshotRequest.Builder(screenshotType, source).build();
2837             mScreenshotHelper.takeScreenshot(request, mHandler, null /* completionConsumer */);
2838         }
2839     }
2840 
2841     RefreshRatePolicy getRefreshRatePolicy() {
2842         return mRefreshRatePolicy;
2843     }
2844 
2845     void dump(String prefix, PrintWriter pw) {
2846         pw.print(prefix); pw.println("DisplayPolicy");
2847         prefix += "  ";
2848         final String prefixInner = prefix + "  ";
2849         pw.print(prefix);
2850         pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
2851         pw.print(" mDeskDockEnablesAccelerometer=");
2852         pw.println(mDeskDockEnablesAccelerometer);
2853         pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
2854         pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
2855         pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
2856         pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
2857         pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
2858         pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
2859         pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
2860         pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
2861         if (mLastDisableFlags != 0) {
2862             pw.print(prefix); pw.print("mLastDisableFlags=0x");
2863             pw.println(Integer.toHexString(mLastDisableFlags));
2864         }
2865         if (mLastAppearance != 0) {
2866             pw.print(prefix); pw.print("mLastAppearance=");
2867             pw.println(ViewDebug.flagsToString(InsetsFlags.class, "appearance", mLastAppearance));
2868         }
2869         if (mLastBehavior != 0) {
2870             pw.print(prefix); pw.print("mLastBehavior=");
2871             pw.println(ViewDebug.flagsToString(InsetsFlags.class, "behavior", mLastBehavior));
2872         }
2873         pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
2874         pw.print(" mDreamingLockscreen="); pw.println(mDreamingLockscreen);
2875         if (mStatusBar != null) {
2876             pw.print(prefix); pw.print("mStatusBar="); pw.println(mStatusBar);
2877         }
2878         if (mNotificationShade != null) {
2879             pw.print(prefix); pw.print("mExpandedPanel="); pw.println(mNotificationShade);
2880         }
2881         pw.print(prefix); pw.print("isKeyguardShowing="); pw.println(isKeyguardShowing());
2882         if (mNavigationBar != null) {
2883             pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
2884             pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
2885             pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove);
2886             pw.print(prefix); pw.print("mNavigationBarPosition=");
2887             pw.println(mNavigationBarPosition);
2888         }
2889         if (mLeftGestureHost != null) {
2890             pw.print(prefix); pw.print("mLeftGestureHost="); pw.println(mLeftGestureHost);
2891         }
2892         if (mTopGestureHost != null) {
2893             pw.print(prefix); pw.print("mTopGestureHost="); pw.println(mTopGestureHost);
2894         }
2895         if (mRightGestureHost != null) {
2896             pw.print(prefix); pw.print("mRightGestureHost="); pw.println(mRightGestureHost);
2897         }
2898         if (mBottomGestureHost != null) {
2899             pw.print(prefix); pw.print("mBottomGestureHost="); pw.println(mBottomGestureHost);
2900         }
2901         if (mFocusedWindow != null) {
2902             pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
2903         }
2904         if (mTopFullscreenOpaqueWindowState != null) {
2905             pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
2906             pw.println(mTopFullscreenOpaqueWindowState);
2907         }
2908         if (!mSystemBarColorApps.isEmpty()) {
2909             pw.print(prefix); pw.print("mSystemBarColorApps=");
2910             pw.println(mSystemBarColorApps);
2911         }
2912         if (!mRelaunchingSystemBarColorApps.isEmpty()) {
2913             pw.print(prefix); pw.print("mRelaunchingSystemBarColorApps=");
2914             pw.println(mRelaunchingSystemBarColorApps);
2915         }
2916         if (mNavBarColorWindowCandidate != null) {
2917             pw.print(prefix); pw.print("mNavBarColorWindowCandidate=");
2918             pw.println(mNavBarColorWindowCandidate);
2919         }
2920         if (mNavBarBackgroundWindowCandidate != null) {
2921             pw.print(prefix); pw.print("mNavBarBackgroundWindowCandidate=");
2922             pw.println(mNavBarBackgroundWindowCandidate);
2923         }
2924         if (mLastStatusBarAppearanceRegions != null) {
2925             pw.print(prefix); pw.println("mLastStatusBarAppearanceRegions=");
2926             for (int i = mLastStatusBarAppearanceRegions.length - 1; i >= 0; i--) {
2927                 pw.print(prefixInner);  pw.println(mLastStatusBarAppearanceRegions[i]);
2928             }
2929         }
2930         if (mLastLetterboxDetails != null) {
2931             pw.print(prefix); pw.println("mLastLetterboxDetails=");
2932             for (int i = mLastLetterboxDetails.length - 1; i >= 0; i--) {
2933                 pw.print(prefixInner);  pw.println(mLastLetterboxDetails[i]);
2934             }
2935         }
2936         if (!mStatusBarBackgroundWindows.isEmpty()) {
2937             pw.print(prefix); pw.println("mStatusBarBackgroundWindows=");
2938             for (int i = mStatusBarBackgroundWindows.size() - 1; i >= 0; i--) {
2939                 final WindowState win = mStatusBarBackgroundWindows.get(i);
2940                 pw.print(prefixInner);  pw.println(win);
2941             }
2942         }
2943         pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen);
2944         pw.print(prefix); pw.print("mImeInsetsConsumed="); pw.println(mImeInsetsConsumed);
2945         pw.print(prefix); pw.print("mForceShowNavigationBarEnabled=");
2946         pw.print(mForceShowNavigationBarEnabled);
2947         pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
2948         pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars=");
2949         pw.println(mRemoteInsetsControllerControlsSystemBars);
2950         pw.print(prefix); pw.println("mDecorInsetsInfo:");
2951         mDecorInsets.dump(prefixInner, pw);
2952         if (mCachedDecorInsets != null) {
2953             pw.print(prefix); pw.println("mCachedDecorInsets:");
2954             mCachedDecorInsets.mDecorInsets.dump(prefixInner, pw);
2955         }
2956         if (!CLIENT_TRANSIENT) {
2957             mSystemGestures.dump(pw, prefix);
2958         }
2959     }
2960 
2961     private boolean supportsPointerLocation() {
2962         return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate();
2963     }
2964 
2965     void setPointerLocationEnabled(boolean pointerLocationEnabled) {
2966         if (!supportsPointerLocation()) {
2967             return;
2968         }
2969 
2970         mHandler.sendEmptyMessage(pointerLocationEnabled
2971                 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
2972     }
2973 
2974     private void enablePointerLocation() {
2975         if (mPointerLocationView != null) {
2976             return;
2977         }
2978 
2979         mPointerLocationView = new PointerLocationView(mContext);
2980         mPointerLocationView.setPrintCoords(false);
2981         final WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
2982         lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
2983         lp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
2984                 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
2985                 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
2986         lp.privateFlags |= LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
2987         lp.setFitInsetsTypes(0);
2988         lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
2989         if (ActivityManager.isHighEndGfx()) {
2990             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
2991             lp.privateFlags |=
2992                     WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
2993         }
2994         lp.format = PixelFormat.TRANSLUCENT;
2995         lp.setTitle("PointerLocation - display " + getDisplayId());
2996         lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
2997         final WindowManager wm = mContext.getSystemService(WindowManager.class);
2998         wm.addView(mPointerLocationView, lp);
2999         mDisplayContent.registerPointerEventListener(mPointerLocationView);
3000     }
3001 
3002     private void disablePointerLocation() {
3003         if (mPointerLocationView == null) {
3004             return;
3005         }
3006 
3007         if (!mDisplayContent.isRemoved()) {
3008             mDisplayContent.unregisterPointerEventListener(mPointerLocationView);
3009         }
3010 
3011         final WindowManager wm = mContext.getSystemService(WindowManager.class);
3012         wm.removeView(mPointerLocationView);
3013         mPointerLocationView = null;
3014     }
3015 
3016     /**
3017      * Check if the window could be excluded from checking if the display has content.
3018      *
3019      * @param w WindowState to check if should be excluded.
3020      * @return True if the window type is PointerLocation which is excluded.
3021      */
3022     boolean isWindowExcludedFromContent(WindowState w) {
3023         if (w != null && mPointerLocationView != null) {
3024             return w.mClient == mPointerLocationView.getWindowToken();
3025         }
3026 
3027         return false;
3028     }
3029 
3030     void release() {
3031         mDisplayContent.mTransitionController.unregisterLegacyListener(mAppTransitionListener);
3032         mHandler.post(mGestureNavigationSettingsObserver::unregister);
3033         mHandler.post(mForceShowNavBarSettingsObserver::unregister);
3034         if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) {
3035             mImmersiveModeConfirmation.release();
3036         }
3037         if (mService.mPointerLocationEnabled) {
3038             setPointerLocationEnabled(false);
3039         }
3040     }
3041 
3042     @VisibleForTesting
3043     static boolean isOverlappingWithNavBar(@NonNull WindowState win) {
3044         if (!win.isVisible()) {
3045             return false;
3046         }
3047 
3048         // When the window is dimming means it's requesting dim layer to its host container, so
3049         // checking whether it's overlapping with a navigation bar by its container's bounds.
3050         return intersectsAnyInsets(win.isDimming() ? win.getBounds() : win.getFrame(),
3051                 win.getInsetsState(), Type.navigationBars());
3052     }
3053 
3054     /**
3055      * Returns whether the given {@param bounds} intersects with any insets of the
3056      * provided {@param insetsType}.
3057      */
3058     private static boolean intersectsAnyInsets(Rect bounds, InsetsState insetsState,
3059             @InsetsType int insetsType) {
3060         for (int i = insetsState.sourceSize() - 1; i >= 0; i--) {
3061             final InsetsSource source = insetsState.sourceAt(i);
3062             if ((source.getType() & insetsType) == 0 || !source.isVisible()) {
3063                 continue;
3064             }
3065             if (Rect.intersects(bounds, source.getFrame())) {
3066                 return true;
3067             }
3068         }
3069         return false;
3070     }
3071 
3072     /**
3073      * @return Whether we should attach navigation bar to the app during transition.
3074      */
3075     boolean shouldAttachNavBarToAppDuringTransition() {
3076         return mShouldAttachNavBarToAppDuringTransition && mNavigationBar != null;
3077     }
3078 }
3079