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