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