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