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.ACTIVITY_TYPE_HOME;
20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
25 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
26 import static android.content.res.Configuration.UI_MODE_TYPE_CAR;
27 import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
28 import static android.view.Display.TYPE_BUILT_IN;
29 import static android.view.InsetsState.TYPE_TOP_BAR;
30 import static android.view.InsetsState.TYPE_TOP_GESTURES;
31 import static android.view.InsetsState.TYPE_TOP_TAPPABLE_ELEMENT;
32 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
33 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
34 import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
35 import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
36 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
37 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
38 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
39 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
40 import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN;
41 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
42 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR;
43 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
44 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN;
45 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
46 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
47 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
48 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
49 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
50 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
51 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
52 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT;
53 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
54 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
55 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
56 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR;
57 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
58 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
59 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
60 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE;
61 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT;
62 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE;
63 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
64 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
65 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
66 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
67 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
68 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
69 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
70 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
71 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER;
72 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
73 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
74 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
75 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
76 import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT;
77 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
78 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
79 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL;
80 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL;
81 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
82 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
83 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
84 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
85 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
86 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING;
87 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY;
88 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
89 import static android.view.WindowManagerGlobal.ADD_OKAY;
90 import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED;
91 import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE;
92 import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
93 import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
94 import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT;
95 
96 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
97 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
98 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
99 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
100 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE;
101 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
102 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW;
103 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
104 import static com.android.server.wm.ActivityTaskManagerInternal.SleepToken;
105 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
106 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
107 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
108 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
109 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
110 import static com.android.server.wm.WindowManagerService.localLOGV;
111 
112 import android.Manifest.permission;
113 import android.annotation.NonNull;
114 import android.annotation.Nullable;
115 import android.annotation.Px;
116 import android.app.ActivityManager;
117 import android.app.ActivityThread;
118 import android.app.LoadedApk;
119 import android.app.ResourcesManager;
120 import android.app.StatusBarManager;
121 import android.content.Context;
122 import android.content.Intent;
123 import android.content.pm.PackageManager;
124 import android.content.res.Resources;
125 import android.graphics.Insets;
126 import android.graphics.PixelFormat;
127 import android.graphics.Rect;
128 import android.graphics.Region;
129 import android.hardware.input.InputManager;
130 import android.hardware.power.V1_0.PowerHint;
131 import android.os.Handler;
132 import android.os.Looper;
133 import android.os.Message;
134 import android.os.SystemClock;
135 import android.os.SystemProperties;
136 import android.os.UserHandle;
137 import android.util.ArraySet;
138 import android.util.Pair;
139 import android.util.PrintWriterPrinter;
140 import android.util.Slog;
141 import android.view.DisplayCutout;
142 import android.view.Gravity;
143 import android.view.IApplicationToken;
144 import android.view.InputChannel;
145 import android.view.InputDevice;
146 import android.view.InputEvent;
147 import android.view.InputEventReceiver;
148 import android.view.InsetsState;
149 import android.view.MotionEvent;
150 import android.view.PointerIcon;
151 import android.view.Surface;
152 import android.view.View;
153 import android.view.ViewRootImpl;
154 import android.view.WindowManager;
155 import android.view.WindowManager.LayoutParams;
156 import android.view.WindowManagerGlobal;
157 import android.view.WindowManagerPolicyConstants;
158 import android.view.accessibility.AccessibilityManager;
159 
160 import com.android.internal.R;
161 import com.android.internal.annotations.GuardedBy;
162 import com.android.internal.annotations.VisibleForTesting;
163 import com.android.internal.policy.ScreenDecorationsUtils;
164 import com.android.internal.util.ScreenShapeHelper;
165 import com.android.internal.util.ScreenshotHelper;
166 import com.android.internal.util.function.TriConsumer;
167 import com.android.internal.widget.PointerLocationView;
168 import com.android.server.LocalServices;
169 import com.android.server.UiThread;
170 import com.android.server.policy.WindowManagerPolicy;
171 import com.android.server.policy.WindowManagerPolicy.InputConsumer;
172 import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition;
173 import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
174 import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
175 import com.android.server.policy.WindowOrientationListener;
176 import com.android.server.statusbar.StatusBarManagerInternal;
177 import com.android.server.wallpaper.WallpaperManagerInternal;
178 import com.android.server.wm.utils.InsetUtils;
179 
180 import java.io.PrintWriter;
181 
182 /**
183  * The policy that provides the basic behaviors and states of a display to show UI.
184  */
185 public class DisplayPolicy {
186     private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM;
187     private static final boolean DEBUG = false;
188 
189     private static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
190 
191     // The panic gesture may become active only after the keyguard is dismissed and the immersive
192     // app shows again. If that doesn't happen for 30s we drop the gesture.
193     private static final long PANIC_GESTURE_EXPIRATION = 30000;
194 
195     // Controls navigation bar opacity depending on which workspace stacks are currently
196     // visible.
197     // Nav bar is always opaque when either the freeform stack or docked stack is visible.
198     private static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0;
199     // Nav bar is always translucent when the freeform stack is visible, otherwise always opaque.
200     private static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1;
201     // Nav bar is never forced opaque.
202     private static final int NAV_BAR_FORCE_TRANSPARENT = 2;
203 
204     /**
205      * These are the system UI flags that, when changing, can cause the layout
206      * of the screen to change.
207      */
208     private static final int SYSTEM_UI_CHANGING_LAYOUT =
209             View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
210                     | View.SYSTEM_UI_FLAG_FULLSCREEN
211                     | View.STATUS_BAR_TRANSLUCENT
212                     | View.NAVIGATION_BAR_TRANSLUCENT
213                     | View.STATUS_BAR_TRANSPARENT
214                     | View.NAVIGATION_BAR_TRANSPARENT;
215 
216     private final WindowManagerService mService;
217     private final Context mContext;
218     private final DisplayContent mDisplayContent;
219     private final Object mLock;
220     private final Handler mHandler;
221 
222     private Resources mCurrentUserResources;
223 
224     private final boolean mCarDockEnablesAccelerometer;
225     private final boolean mDeskDockEnablesAccelerometer;
226     private final AccessibilityManager mAccessibilityManager;
227     private final ImmersiveModeConfirmation mImmersiveModeConfirmation;
228     private final ScreenshotHelper mScreenshotHelper;
229 
230     private final Object mServiceAcquireLock = new Object();
231     private StatusBarManagerInternal mStatusBarManagerInternal;
232 
233     @Px
234     private int mBottomGestureAdditionalInset;
235     @Px
236     private int mSideGestureInset;
237 
getStatusBarManagerInternal()238     private StatusBarManagerInternal getStatusBarManagerInternal() {
239         synchronized (mServiceAcquireLock) {
240             if (mStatusBarManagerInternal == null) {
241                 mStatusBarManagerInternal =
242                         LocalServices.getService(StatusBarManagerInternal.class);
243             }
244             return mStatusBarManagerInternal;
245         }
246     }
247 
248     private final SystemGesturesPointerEventListener mSystemGestures;
249 
250     private volatile int mLidState = LID_ABSENT;
251     private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
252     private volatile boolean mHdmiPlugged;
253 
254     private volatile boolean mHasStatusBar;
255     private volatile boolean mHasNavigationBar;
256     // Can the navigation bar ever move to the side?
257     private volatile boolean mNavigationBarCanMove;
258     private volatile boolean mNavigationBarLetsThroughTaps;
259     private volatile boolean mNavigationBarAlwaysShowOnSideGesture;
260     private volatile boolean mAllowSeamlessRotationDespiteNavBarMoving;
261 
262     // Written by vr manager thread, only read in this class.
263     private volatile boolean mPersistentVrModeEnabled;
264 
265     private volatile boolean mAwake;
266     private volatile boolean mScreenOnEarly;
267     private volatile boolean mScreenOnFully;
268     private volatile ScreenOnListener mScreenOnListener;
269 
270     private volatile boolean mKeyguardDrawComplete;
271     private volatile boolean mWindowManagerDrawComplete;
272 
273     private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
274     private WindowState mStatusBar = null;
275     private final int[] mStatusBarHeightForRotation = new int[4];
276     private WindowState mNavigationBar = null;
277     @NavigationBarPosition
278     private int mNavigationBarPosition = NAV_BAR_BOTTOM;
279     private int[] mNavigationBarHeightForRotationDefault = new int[4];
280     private int[] mNavigationBarWidthForRotationDefault = new int[4];
281     private int[] mNavigationBarHeightForRotationInCarMode = new int[4];
282     private int[] mNavigationBarWidthForRotationInCarMode = new int[4];
283 
284     /** See {@link #getNavigationBarFrameHeight} */
285     private int[] mNavigationBarFrameHeightForRotationDefault = new int[4];
286 
287     /** Cached value of {@link ScreenShapeHelper#getWindowOutsetBottomPx} */
288     @Px private int mWindowOutsetBottom;
289 
290     private final StatusBarController mStatusBarController;
291 
292     private final BarController mNavigationBarController;
293 
294     private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
295             new BarController.OnBarVisibilityChangedListener() {
296                 @Override
297                 public void onBarVisibilityChanged(boolean visible) {
298                     if (mAccessibilityManager == null) {
299                         return;
300                     }
301                     mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
302                 }
303             };
304 
305     @GuardedBy("mHandler")
306     private SleepToken mDreamingSleepToken;
307 
308     @GuardedBy("mHandler")
309     private SleepToken mWindowSleepToken;
310 
311     private final Runnable mAcquireSleepTokenRunnable;
312     private final Runnable mReleaseSleepTokenRunnable;
313 
314     // The windows we were told about in focusChanged.
315     private WindowState mFocusedWindow;
316     private WindowState mLastFocusedWindow;
317 
318     IApplicationToken mFocusedApp;
319 
320     int mLastSystemUiFlags;
321     // Bits that we are in the process of clearing, so we want to prevent
322     // them from being set by applications until everything has been updated
323     // to have them clear.
324     private int mResettingSystemUiFlags = 0;
325     // Bits that we are currently always keeping cleared.
326     private int mForceClearedSystemUiFlags = 0;
327     private int mLastFullscreenStackSysUiFlags;
328     private int mLastDockedStackSysUiFlags;
329     private final Rect mNonDockedStackBounds = new Rect();
330     private final Rect mDockedStackBounds = new Rect();
331     private final Rect mLastNonDockedStackBounds = new Rect();
332     private final Rect mLastDockedStackBounds = new Rect();
333 
334     // What we last reported to system UI about whether the compatibility
335     // menu needs to be displayed.
336     private boolean mLastFocusNeedsMenu = false;
337     // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending.
338     private long mPendingPanicGestureUptime;
339 
340     private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect();
341     private static final Rect sTmpRect = new Rect();
342     private static final Rect sTmpDockedFrame = new Rect();
343     private static final Rect sTmpNavFrame = new Rect();
344     private static final Rect sTmpLastParentFrame = new Rect();
345 
346     private WindowState mTopFullscreenOpaqueWindowState;
347     private WindowState mTopFullscreenOpaqueOrDimmingWindowState;
348     private WindowState mTopDockedOpaqueWindowState;
349     private WindowState mTopDockedOpaqueOrDimmingWindowState;
350     private boolean mTopIsFullscreen;
351     private boolean mForceStatusBar;
352     private boolean mForceStatusBarFromKeyguard;
353     private boolean mForceStatusBarTransparent;
354     private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;
355     private boolean mForcingShowNavBar;
356     private int mForcingShowNavBarLayer;
357     private boolean mForceShowSystemBars;
358 
359     /**
360      * Force the display of system bars regardless of other settings.
361      */
362     private boolean mForceShowSystemBarsFromExternal;
363 
364     private boolean mShowingDream;
365     private boolean mLastShowingDream;
366     private boolean mDreamingLockscreen;
367     private boolean mDreamingSleepTokenNeeded;
368     private boolean mWindowSleepTokenNeeded;
369     private boolean mLastWindowSleepTokenNeeded;
370     private boolean mAllowLockscreenWhenOn;
371 
372     private InputConsumer mInputConsumer = null;
373 
374     private PointerLocationView mPointerLocationView;
375 
376     /**
377      * The area covered by system windows which belong to another display. Forwarded insets is set
378      * in case this is a virtual display, this is displayed on another display that has insets, and
379      * the bounds of this display is overlapping with the insets of the host display (e.g. IME is
380      * displayed on the host display, and it covers a part of this virtual display.)
381      * The forwarded insets is used to compute display frames of this virtual display, which will
382      * be then used to layout windows in the virtual display.
383      */
384     @NonNull private Insets mForwardedInsets = Insets.NONE;
385 
386     private RefreshRatePolicy mRefreshRatePolicy;
387 
388     // -------- PolicyHandler --------
389     private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
390     private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
391     private static final int MSG_DISPOSE_INPUT_CONSUMER = 3;
392     private static final int MSG_ENABLE_POINTER_LOCATION = 4;
393     private static final int MSG_DISABLE_POINTER_LOCATION = 5;
394 
395     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
396     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
397 
398     private class PolicyHandler extends Handler {
399 
PolicyHandler(Looper looper)400         PolicyHandler(Looper looper) {
401             super(looper);
402         }
403 
404         @Override
handleMessage(Message msg)405         public void handleMessage(Message msg) {
406             switch (msg.what) {
407                 case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
408                     updateDreamingSleepToken(msg.arg1 != 0);
409                     break;
410                 case MSG_REQUEST_TRANSIENT_BARS:
411                     WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
412                             ? mStatusBar : mNavigationBar;
413                     if (targetBar != null) {
414                         requestTransientBars(targetBar);
415                     }
416                     break;
417                 case MSG_DISPOSE_INPUT_CONSUMER:
418                     disposeInputConsumer((InputConsumer) msg.obj);
419                     break;
420                 case MSG_ENABLE_POINTER_LOCATION:
421                     enablePointerLocation();
422                     break;
423                 case MSG_DISABLE_POINTER_LOCATION:
424                     disablePointerLocation();
425                     break;
426             }
427         }
428     }
429 
DisplayPolicy(WindowManagerService service, DisplayContent displayContent)430     DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
431         mService = service;
432         mContext = displayContent.isDefaultDisplay ? service.mContext
433                 : service.mContext.createDisplayContext(displayContent.getDisplay());
434         mDisplayContent = displayContent;
435         mLock = service.getWindowManagerLock();
436 
437         final int displayId = displayContent.getDisplayId();
438         mStatusBarController = new StatusBarController(displayId);
439         mNavigationBarController = new BarController("NavigationBar",
440                 displayId,
441                 View.NAVIGATION_BAR_TRANSIENT,
442                 View.NAVIGATION_BAR_UNHIDE,
443                 View.NAVIGATION_BAR_TRANSLUCENT,
444                 StatusBarManager.WINDOW_NAVIGATION_BAR,
445                 FLAG_TRANSLUCENT_NAVIGATION,
446                 View.NAVIGATION_BAR_TRANSPARENT);
447 
448         final Resources r = mContext.getResources();
449         mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer);
450         mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
451         mForceShowSystemBarsFromExternal = r.getBoolean(R.bool.config_forceShowSystemBars);
452 
453         mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
454                 Context.ACCESSIBILITY_SERVICE);
455         if (!displayContent.isDefaultDisplay) {
456             mAwake = true;
457             mScreenOnEarly = true;
458             mScreenOnFully = true;
459         }
460 
461         final Looper looper = UiThread.getHandler().getLooper();
462         mHandler = new PolicyHandler(looper);
463         mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
464                 new SystemGesturesPointerEventListener.Callbacks() {
465                     @Override
466                     public void onSwipeFromTop() {
467                         if (mStatusBar != null) {
468                             requestTransientBars(mStatusBar);
469                         }
470                     }
471 
472                     @Override
473                     public void onSwipeFromBottom() {
474                         if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
475                             requestTransientBars(mNavigationBar);
476                         }
477                     }
478 
479                     @Override
480                     public void onSwipeFromRight() {
481                         final Region excludedRegion;
482                         synchronized (mLock) {
483                             excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
484                         }
485                         final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
486                                 || mNavigationBarPosition == NAV_BAR_RIGHT;
487                         if (mNavigationBar != null && sideAllowed
488                                 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
489                             requestTransientBars(mNavigationBar);
490                         }
491                     }
492 
493                     @Override
494                     public void onSwipeFromLeft() {
495                         final Region excludedRegion;
496                         synchronized (mLock) {
497                             excludedRegion = mDisplayContent.calculateSystemGestureExclusion();
498                         }
499                         final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
500                                 || mNavigationBarPosition == NAV_BAR_LEFT;
501                         if (mNavigationBar != null && sideAllowed
502                                 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
503                             requestTransientBars(mNavigationBar);
504                         }
505                     }
506 
507                     @Override
508                     public void onFling(int duration) {
509                         if (mService.mPowerManagerInternal != null) {
510                             mService.mPowerManagerInternal.powerHint(
511                                     PowerHint.INTERACTION, duration);
512                         }
513                     }
514 
515                     @Override
516                     public void onDebug() {
517                         // no-op
518                     }
519 
520                     private WindowOrientationListener getOrientationListener() {
521                         final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
522                         return rotation != null ? rotation.getOrientationListener() : null;
523                     }
524 
525                     @Override
526                     public void onDown() {
527                         final WindowOrientationListener listener = getOrientationListener();
528                         if (listener != null) {
529                             listener.onTouchStart();
530                         }
531                     }
532 
533                     @Override
534                     public void onUpOrCancel() {
535                         final WindowOrientationListener listener = getOrientationListener();
536                         if (listener != null) {
537                             listener.onTouchEnd();
538                         }
539                     }
540 
541                     @Override
542                     public void onMouseHoverAtTop() {
543                         mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
544                         Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
545                         msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
546                         mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
547                     }
548 
549                     @Override
550                     public void onMouseHoverAtBottom() {
551                         mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
552                         Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
553                         msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
554                         mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
555                     }
556 
557                     @Override
558                     public void onMouseLeaveFromEdge() {
559                         mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
560                     }
561                 });
562         displayContent.registerPointerEventListener(mSystemGestures);
563         displayContent.mAppTransition.registerListenerLocked(
564                 mStatusBarController.getAppTransitionListener());
565         mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
566                 mService.mVrModeEnabled);
567         mAcquireSleepTokenRunnable = () -> {
568             if (mWindowSleepToken != null) {
569                 return;
570             }
571             mWindowSleepToken = service.mAtmInternal.acquireSleepToken(
572                     "WindowSleepTokenOnDisplay" + displayId, displayId);
573         };
574         mReleaseSleepTokenRunnable = () -> {
575             if (mWindowSleepToken == null) {
576                 return;
577             }
578             mWindowSleepToken.release();
579             mWindowSleepToken = null;
580         };
581 
582         // TODO: Make it can take screenshot on external display
583         mScreenshotHelper = displayContent.isDefaultDisplay
584                 ? new ScreenshotHelper(mContext) : null;
585 
586         if (mDisplayContent.isDefaultDisplay) {
587             mHasStatusBar = true;
588             mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
589 
590             // Allow a system property to override this. Used by the emulator.
591             // See also hasNavigationBar().
592             String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
593             if ("1".equals(navBarOverride)) {
594                 mHasNavigationBar = false;
595             } else if ("0".equals(navBarOverride)) {
596                 mHasNavigationBar = true;
597             }
598         } else {
599             mHasStatusBar = false;
600             mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
601         }
602 
603         mRefreshRatePolicy = new RefreshRatePolicy(mService,
604                 mDisplayContent.getDisplayInfo(),
605                 mService.mHighRefreshRateBlacklist);
606     }
607 
systemReady()608     void systemReady() {
609         mSystemGestures.systemReady();
610         if (mService.mPointerLocationEnabled) {
611             setPointerLocationEnabled(true);
612         }
613     }
614 
getDisplayId()615     private int getDisplayId() {
616         return mDisplayContent.getDisplayId();
617     }
618 
setHdmiPlugged(boolean plugged)619     public void setHdmiPlugged(boolean plugged) {
620         setHdmiPlugged(plugged, false /* force */);
621     }
622 
setHdmiPlugged(boolean plugged, boolean force)623     public void setHdmiPlugged(boolean plugged, boolean force) {
624         if (force || mHdmiPlugged != plugged) {
625             mHdmiPlugged = plugged;
626             mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
627             final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
628             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
629             intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
630             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
631         }
632     }
633 
isHdmiPlugged()634     boolean isHdmiPlugged() {
635         return mHdmiPlugged;
636     }
637 
isCarDockEnablesAccelerometer()638     boolean isCarDockEnablesAccelerometer() {
639         return mCarDockEnablesAccelerometer;
640     }
641 
isDeskDockEnablesAccelerometer()642     boolean isDeskDockEnablesAccelerometer() {
643         return mDeskDockEnablesAccelerometer;
644     }
645 
setPersistentVrModeEnabled(boolean persistentVrModeEnabled)646     public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
647         mPersistentVrModeEnabled = persistentVrModeEnabled;
648     }
649 
isPersistentVrModeEnabled()650     public boolean isPersistentVrModeEnabled() {
651         return mPersistentVrModeEnabled;
652     }
653 
setDockMode(int dockMode)654     public void setDockMode(int dockMode) {
655         mDockMode = dockMode;
656     }
657 
getDockMode()658     public int getDockMode() {
659         return mDockMode;
660     }
661 
662     /**
663      * @see WindowManagerService.setForceShowSystemBars
664      */
setForceShowSystemBars(boolean forceShowSystemBars)665     void setForceShowSystemBars(boolean forceShowSystemBars) {
666         mForceShowSystemBarsFromExternal = forceShowSystemBars;
667     }
668 
hasNavigationBar()669     public boolean hasNavigationBar() {
670         return mHasNavigationBar;
671     }
672 
hasStatusBar()673     public boolean hasStatusBar() {
674         return mHasStatusBar;
675     }
676 
navigationBarCanMove()677     public boolean navigationBarCanMove() {
678         return mNavigationBarCanMove;
679     }
680 
setLidState(int lidState)681     public void setLidState(int lidState) {
682         mLidState = lidState;
683     }
684 
getLidState()685     public int getLidState() {
686         return mLidState;
687     }
688 
setAwake(boolean awake)689     public void setAwake(boolean awake) {
690         mAwake = awake;
691     }
692 
isAwake()693     public boolean isAwake() {
694         return mAwake;
695     }
696 
isScreenOnEarly()697     public boolean isScreenOnEarly() {
698         return mScreenOnEarly;
699     }
700 
isScreenOnFully()701     public boolean isScreenOnFully() {
702         return mScreenOnFully;
703     }
704 
isKeyguardDrawComplete()705     public boolean isKeyguardDrawComplete() {
706         return mKeyguardDrawComplete;
707     }
708 
isWindowManagerDrawComplete()709     public boolean isWindowManagerDrawComplete() {
710         return mWindowManagerDrawComplete;
711     }
712 
getScreenOnListener()713     public ScreenOnListener getScreenOnListener() {
714         return mScreenOnListener;
715     }
716 
screenTurnedOn(ScreenOnListener screenOnListener)717     public void screenTurnedOn(ScreenOnListener screenOnListener) {
718         synchronized (mLock) {
719             mScreenOnEarly = true;
720             mScreenOnFully = false;
721             mKeyguardDrawComplete = false;
722             mWindowManagerDrawComplete = false;
723             mScreenOnListener = screenOnListener;
724         }
725     }
726 
screenTurnedOff()727     public void screenTurnedOff() {
728         synchronized (mLock) {
729             mScreenOnEarly = false;
730             mScreenOnFully = false;
731             mKeyguardDrawComplete = false;
732             mWindowManagerDrawComplete = false;
733             mScreenOnListener = null;
734         }
735     }
736 
737     /** Return false if we are not awake yet or we have already informed of this event. */
finishKeyguardDrawn()738     public boolean finishKeyguardDrawn() {
739         synchronized (mLock) {
740             if (!mScreenOnEarly || mKeyguardDrawComplete) {
741                 return false;
742             }
743 
744             mKeyguardDrawComplete = true;
745             mWindowManagerDrawComplete = false;
746         }
747         return true;
748     }
749 
750     /** Return false if screen is not turned on or we did already handle this case earlier. */
finishWindowsDrawn()751     public boolean finishWindowsDrawn() {
752         synchronized (mLock) {
753             if (!mScreenOnEarly || mWindowManagerDrawComplete) {
754                 return false;
755             }
756 
757             mWindowManagerDrawComplete = true;
758         }
759         return true;
760     }
761 
762     /** Return false if it is not ready to turn on. */
finishScreenTurningOn()763     public boolean finishScreenTurningOn() {
764         synchronized (mLock) {
765             if (DEBUG_SCREEN_ON) Slog.d(TAG,
766                     "finishScreenTurningOn: mAwake=" + mAwake
767                             + ", mScreenOnEarly=" + mScreenOnEarly
768                             + ", mScreenOnFully=" + mScreenOnFully
769                             + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
770                             + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
771 
772             if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
773                     || (mAwake && !mKeyguardDrawComplete)) {
774                 return false;
775             }
776 
777             if (DEBUG_SCREEN_ON) Slog.i(TAG, "Finished screen turning on...");
778             mScreenOnListener = null;
779             mScreenOnFully = true;
780         }
781         return true;
782     }
783 
hasStatusBarServicePermission(int pid, int uid)784     private boolean hasStatusBarServicePermission(int pid, int uid) {
785         return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid)
786                 == PackageManager.PERMISSION_GRANTED;
787     }
788 
789     /**
790      * Sanitize the layout parameters coming from a client.  Allows the policy
791      * to do things like ensure that windows of a specific type can't take
792      * input focus.
793      *
794      * @param attrs The window layout parameters to be modified.  These values
795      * are modified in-place.
796      */
adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs, int callingPid, int callingUid)797     public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
798             int callingPid, int callingUid) {
799 
800         final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
801         if (mScreenDecorWindows.contains(win)) {
802             if (!isScreenDecor) {
803                 // No longer has the flag set, so remove from the set.
804                 mScreenDecorWindows.remove(win);
805             }
806         } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
807             mScreenDecorWindows.add(win);
808         }
809 
810         switch (attrs.type) {
811             case TYPE_SYSTEM_OVERLAY:
812             case TYPE_SECURE_SYSTEM_OVERLAY:
813                 // These types of windows can't receive input events.
814                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
815                         | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
816                 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
817                 break;
818             case TYPE_DREAM:
819             case TYPE_WALLPAPER:
820                 // Dreams and wallpapers don't have an app window token and can thus not be
821                 // letterboxed. Hence always let them extend under the cutout.
822                 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
823                 break;
824             case TYPE_STATUS_BAR:
825 
826                 // If the Keyguard is in a hidden state (occluded by another window), we force to
827                 // remove the wallpaper and keyguard flag so that any change in-flight after setting
828                 // the keyguard as occluded wouldn't set these flags again.
829                 // See {@link #processKeyguardSetHiddenResultLw}.
830                 if (mService.mPolicy.isKeyguardOccluded()) {
831                     attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
832                     attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
833                 }
834                 break;
835 
836             case TYPE_SCREENSHOT:
837                 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
838                 break;
839 
840             case TYPE_TOAST:
841                 // While apps should use the dedicated toast APIs to add such windows
842                 // it possible legacy apps to add the window directly. Therefore, we
843                 // make windows added directly by the app behave as a toast as much
844                 // as possible in terms of timeout and animation.
845                 if (attrs.hideTimeoutMilliseconds < 0
846                         || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
847                     attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
848                 }
849                 // Accessibility users may need longer timeout duration. This api compares
850                 // original timeout with user's preference and return longer one. It returns
851                 // original timeout if there's no preference.
852                 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
853                         (int) attrs.hideTimeoutMilliseconds,
854                         AccessibilityManager.FLAG_CONTENT_TEXT);
855                 attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
856                 // Toast can show with below conditions when the screen is locked.
857                 if (canToastShowWhenLocked(callingPid)) {
858                     attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
859                 }
860                 break;
861         }
862 
863         if (attrs.type != TYPE_STATUS_BAR) {
864             // The status bar is the only window allowed to exhibit keyguard behavior.
865             attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
866         }
867     }
868 
869     /**
870      * @return {@code true} if the calling activity initiate toast and is visible with
871      * {@link WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} flag.
872      */
canToastShowWhenLocked(int callingPid)873     boolean canToastShowWhenLocked(int callingPid) {
874         return mDisplayContent.forAllWindows(w -> {
875             return callingPid == w.mSession.mPid && w.isVisible() && w.canShowWhenLocked();
876         }, true /* traverseTopToBottom */);
877     }
878 
879     /**
880      * Preflight adding a window to the system.
881      *
882      * Currently enforces that three window types are singletons per display:
883      * <ul>
884      * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
885      * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
886      * </ul>
887      *
888      * @param win The window to be added
889      * @param attrs Information about the window to be added
890      *
891      * @return If ok, WindowManagerImpl.ADD_OKAY.  If too many singletons,
892      * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
893      */
prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs)894     public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
895 
896         if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
897             mContext.enforceCallingOrSelfPermission(
898                     android.Manifest.permission.STATUS_BAR_SERVICE,
899                     "DisplayPolicy");
900             mScreenDecorWindows.add(win);
901         }
902 
903         switch (attrs.type) {
904             case TYPE_STATUS_BAR:
905                 mContext.enforceCallingOrSelfPermission(
906                         android.Manifest.permission.STATUS_BAR_SERVICE,
907                         "DisplayPolicy");
908                 if (mStatusBar != null) {
909                     if (mStatusBar.isAlive()) {
910                         return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
911                     }
912                 }
913                 mStatusBar = win;
914                 mStatusBarController.setWindow(win);
915                 if (mDisplayContent.isDefaultDisplay) {
916                     mService.mPolicy.setKeyguardCandidateLw(win);
917                 }
918                 final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
919                         (displayFrames, windowState, rect) -> {
920                             rect.top = 0;
921                             rect.bottom = getStatusBarHeight(displayFrames);
922                         };
923                 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, win, frameProvider);
924                 mDisplayContent.setInsetProvider(TYPE_TOP_GESTURES, win, frameProvider);
925                 mDisplayContent.setInsetProvider(TYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider);
926                 break;
927             case TYPE_NAVIGATION_BAR:
928                 mContext.enforceCallingOrSelfPermission(
929                         android.Manifest.permission.STATUS_BAR_SERVICE,
930                         "DisplayPolicy");
931                 if (mNavigationBar != null) {
932                     if (mNavigationBar.isAlive()) {
933                         return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
934                     }
935                 }
936                 mNavigationBar = win;
937                 mNavigationBarController.setWindow(win);
938                 mNavigationBarController.setOnBarVisibilityChangedListener(
939                         mNavBarVisibilityListener, true);
940                 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR,
941                         win, null /* frameProvider */);
942                 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_GESTURES, win,
943                         (displayFrames, windowState, inOutFrame) -> {
944                             inOutFrame.top -= mBottomGestureAdditionalInset;
945                         });
946                 mDisplayContent.setInsetProvider(InsetsState.TYPE_LEFT_GESTURES, win,
947                         (displayFrames, windowState, inOutFrame) -> {
948                             inOutFrame.left = 0;
949                             inOutFrame.top = 0;
950                             inOutFrame.bottom = displayFrames.mDisplayHeight;
951                             inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset;
952                         });
953                 mDisplayContent.setInsetProvider(InsetsState.TYPE_RIGHT_GESTURES, win,
954                         (displayFrames, windowState, inOutFrame) -> {
955                             inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset;
956                             inOutFrame.top = 0;
957                             inOutFrame.bottom = displayFrames.mDisplayHeight;
958                             inOutFrame.right = displayFrames.mDisplayWidth;
959                         });
960                 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_TAPPABLE_ELEMENT, win,
961                         (displayFrames, windowState, inOutFrame) -> {
962                             if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
963                                     || mNavigationBarLetsThroughTaps) {
964                                 inOutFrame.setEmpty();
965                             }
966                         });
967                 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
968                 break;
969             case TYPE_NAVIGATION_BAR_PANEL:
970             case TYPE_STATUS_BAR_PANEL:
971             case TYPE_STATUS_BAR_SUB_PANEL:
972             case TYPE_VOICE_INTERACTION_STARTING:
973                 mContext.enforceCallingOrSelfPermission(
974                         android.Manifest.permission.STATUS_BAR_SERVICE,
975                         "DisplayPolicy");
976                 break;
977         }
978         return ADD_OKAY;
979     }
980 
981     /**
982      * Called when a window is being removed from a window manager.  Must not
983      * throw an exception -- clean up as much as possible.
984      *
985      * @param win The window being removed.
986      */
removeWindowLw(WindowState win)987     public void removeWindowLw(WindowState win) {
988         if (mStatusBar == win) {
989             mStatusBar = null;
990             mStatusBarController.setWindow(null);
991             if (mDisplayContent.isDefaultDisplay) {
992                 mService.mPolicy.setKeyguardCandidateLw(null);
993             }
994             mDisplayContent.setInsetProvider(TYPE_TOP_BAR, null, null);
995         } else if (mNavigationBar == win) {
996             mNavigationBar = null;
997             mNavigationBarController.setWindow(null);
998             mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR, null, null);
999         }
1000         if (mLastFocusedWindow == win) {
1001             mLastFocusedWindow = null;
1002         }
1003         mScreenDecorWindows.remove(win);
1004     }
1005 
getStatusBarHeight(DisplayFrames displayFrames)1006     private int getStatusBarHeight(DisplayFrames displayFrames) {
1007         return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
1008                 displayFrames.mDisplayCutoutSafe.top);
1009     }
1010 
1011     /**
1012      * Control the animation to run when a window's state changes.  Return a
1013      * non-0 number to force the animation to a specific resource ID, or 0
1014      * to use the default animation.
1015      *
1016      * @param win The window that is changing.
1017      * @param transit What is happening to the window:
1018      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
1019      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
1020      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
1021      *                {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
1022      *
1023      * @return Resource ID of the actual animation to use, or 0 for none.
1024      */
selectAnimationLw(WindowState win, int transit)1025     public int selectAnimationLw(WindowState win, int transit) {
1026         if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
1027                 + ": transit=" + transit);
1028         if (win == mStatusBar) {
1029             final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
1030             final boolean expanded = win.getAttrs().height == MATCH_PARENT
1031                     && win.getAttrs().width == MATCH_PARENT;
1032             if (isKeyguard || expanded) {
1033                 return -1;
1034             }
1035             if (transit == TRANSIT_EXIT
1036                     || transit == TRANSIT_HIDE) {
1037                 return R.anim.dock_top_exit;
1038             } else if (transit == TRANSIT_ENTER
1039                     || transit == TRANSIT_SHOW) {
1040                 return R.anim.dock_top_enter;
1041             }
1042         } else if (win == mNavigationBar) {
1043             if (win.getAttrs().windowAnimations != 0) {
1044                 return 0;
1045             }
1046             // This can be on either the bottom or the right or the left.
1047             if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1048                 if (transit == TRANSIT_EXIT
1049                         || transit == TRANSIT_HIDE) {
1050                     if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
1051                         return R.anim.dock_bottom_exit_keyguard;
1052                     } else {
1053                         return R.anim.dock_bottom_exit;
1054                     }
1055                 } else if (transit == TRANSIT_ENTER
1056                         || transit == TRANSIT_SHOW) {
1057                     return R.anim.dock_bottom_enter;
1058                 }
1059             } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1060                 if (transit == TRANSIT_EXIT
1061                         || transit == TRANSIT_HIDE) {
1062                     return R.anim.dock_right_exit;
1063                 } else if (transit == TRANSIT_ENTER
1064                         || transit == TRANSIT_SHOW) {
1065                     return R.anim.dock_right_enter;
1066                 }
1067             } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1068                 if (transit == TRANSIT_EXIT
1069                         || transit == TRANSIT_HIDE) {
1070                     return R.anim.dock_left_exit;
1071                 } else if (transit == TRANSIT_ENTER
1072                         || transit == TRANSIT_SHOW) {
1073                     return R.anim.dock_left_enter;
1074                 }
1075             }
1076         } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
1077             return selectDockedDividerAnimationLw(win, transit);
1078         }
1079 
1080         if (transit == TRANSIT_PREVIEW_DONE) {
1081             if (win.hasAppShownWindows()) {
1082                 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
1083                 return R.anim.app_starting_exit;
1084             }
1085         } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
1086                 && transit == TRANSIT_ENTER) {
1087             // Special case: we are animating in a dream, while the keyguard
1088             // is shown.  We don't want an animation on the dream, because
1089             // we need it shown immediately with the keyguard animating away
1090             // to reveal it.
1091             return -1;
1092         }
1093 
1094         return 0;
1095     }
1096 
selectDockedDividerAnimationLw(WindowState win, int transit)1097     private int selectDockedDividerAnimationLw(WindowState win, int transit) {
1098         int insets = mDisplayContent.getDockedDividerController().getContentInsets();
1099 
1100         // If the divider is behind the navigation bar, don't animate.
1101         final Rect frame = win.getFrameLw();
1102         final boolean behindNavBar = mNavigationBar != null
1103                 && ((mNavigationBarPosition == NAV_BAR_BOTTOM
1104                 && frame.top + insets >= mNavigationBar.getFrameLw().top)
1105                 || (mNavigationBarPosition == NAV_BAR_RIGHT
1106                 && frame.left + insets >= mNavigationBar.getFrameLw().left)
1107                 || (mNavigationBarPosition == NAV_BAR_LEFT
1108                 && frame.right - insets <= mNavigationBar.getFrameLw().right));
1109         final boolean landscape = frame.height() > frame.width();
1110         final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
1111                 || frame.left + insets >= win.getDisplayFrameLw().right);
1112         final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
1113                 || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
1114         final boolean offscreen = offscreenLandscape || offscreenPortrait;
1115         if (behindNavBar || offscreen) {
1116             return 0;
1117         }
1118         if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
1119             return R.anim.fade_in;
1120         } else if (transit == TRANSIT_EXIT) {
1121             return R.anim.fade_out;
1122         } else {
1123             return 0;
1124         }
1125     }
1126 
1127     /**
1128      * Determine the animation to run for a rotation transition based on the
1129      * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation}
1130      * and whether it is currently fullscreen and frontmost.
1131      *
1132      * @param anim The exiting animation resource id is stored in anim[0], the
1133      * entering animation resource id is stored in anim[1].
1134      */
selectRotationAnimationLw(int anim[])1135     public void selectRotationAnimationLw(int anim[]) {
1136         // If the screen is off or non-interactive, force a jumpcut.
1137         final boolean forceJumpcut = !mScreenOnFully || !mService.mPolicy.okToAnimate();
1138         if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
1139                 + mTopFullscreenOpaqueWindowState + " rotationAnimation="
1140                 + (mTopFullscreenOpaqueWindowState == null
1141                 ? "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation)
1142                 + " forceJumpcut=" + forceJumpcut);
1143         if (forceJumpcut) {
1144             anim[0] = R.anim.rotation_animation_jump_exit;
1145             anim[1] = R.anim.rotation_animation_enter;
1146             return;
1147         }
1148         if (mTopFullscreenOpaqueWindowState != null) {
1149             int animationHint = mTopFullscreenOpaqueWindowState.getRotationAnimationHint();
1150             if (animationHint < 0 && mTopIsFullscreen) {
1151                 animationHint = mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation;
1152             }
1153             switch (animationHint) {
1154                 case ROTATION_ANIMATION_CROSSFADE:
1155                 case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless.
1156                     anim[0] = R.anim.rotation_animation_xfade_exit;
1157                     anim[1] = R.anim.rotation_animation_enter;
1158                     break;
1159                 case ROTATION_ANIMATION_JUMPCUT:
1160                     anim[0] = R.anim.rotation_animation_jump_exit;
1161                     anim[1] = R.anim.rotation_animation_enter;
1162                     break;
1163                 case ROTATION_ANIMATION_ROTATE:
1164                 default:
1165                     anim[0] = anim[1] = 0;
1166                     break;
1167             }
1168         } else {
1169             anim[0] = anim[1] = 0;
1170         }
1171     }
1172 
1173     /**
1174      * Validate whether the current top fullscreen has specified the same
1175      * {@link WindowManager.LayoutParams#rotationAnimation} value as that
1176      * being passed in from the previous top fullscreen window.
1177      *
1178      * @param exitAnimId exiting resource id from the previous window.
1179      * @param enterAnimId entering resource id from the previous window.
1180      * @param forceDefault For rotation animations only, if true ignore the
1181      * animation values and just return false.
1182      * @return true if the previous values are still valid, false if they
1183      * should be replaced with the default.
1184      */
validateRotationAnimationLw(int exitAnimId, int enterAnimId, boolean forceDefault)1185     public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
1186             boolean forceDefault) {
1187         switch (exitAnimId) {
1188             case R.anim.rotation_animation_xfade_exit:
1189             case R.anim.rotation_animation_jump_exit:
1190                 // These are the only cases that matter.
1191                 if (forceDefault) {
1192                     return false;
1193                 }
1194                 int anim[] = new int[2];
1195                 selectRotationAnimationLw(anim);
1196                 return (exitAnimId == anim[0] && enterAnimId == anim[1]);
1197             default:
1198                 return true;
1199         }
1200     }
1201 
1202     /**
1203      * Called when a new system UI visibility is being reported, allowing
1204      * the policy to adjust what is actually reported.
1205      * @param visibility The raw visibility reported by the status bar.
1206      * @return The new desired visibility.
1207      */
adjustSystemUiVisibilityLw(int visibility)1208     public int adjustSystemUiVisibilityLw(int visibility) {
1209         mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1210         mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1211 
1212         // Reset any bits in mForceClearingStatusBarVisibility that
1213         // are now clear.
1214         mResettingSystemUiFlags &= visibility;
1215         // Clear any bits in the new visibility that are currently being
1216         // force cleared, before reporting it.
1217         return visibility & ~mResettingSystemUiFlags
1218                 & ~mForceClearedSystemUiFlags;
1219     }
1220 
1221     /**
1222      * @return true if the system bars are forced to stay visible
1223      */
areSystemBarsForcedShownLw(WindowState windowState)1224     public boolean areSystemBarsForcedShownLw(WindowState windowState) {
1225         return mForceShowSystemBars;
1226     }
1227 
1228     // TODO: Should probably be moved into DisplayFrames.
1229     /**
1230      * Return the layout hints for a newly added window. These values are computed on the
1231      * most recent layout, so they are not guaranteed to be correct.
1232      *
1233      * @param attrs The LayoutParams of the window.
1234      * @param taskBounds The bounds of the task this window is on or {@code null} if no task is
1235      *                   associated with the window.
1236      * @param displayFrames display frames.
1237      * @param floatingStack Whether the window's stack is floating.
1238      * @param outFrame The frame of the window.
1239      * @param outContentInsets The areas covered by system windows, expressed as positive insets.
1240      * @param outStableInsets The areas covered by stable system windows irrespective of their
1241      *                        current visibility. Expressed as positive insets.
1242      * @param outOutsets The areas that are not real display, but we would like to treat as such.
1243      * @param outDisplayCutout The area that has been cut away from the display.
1244      * @return Whether to always consume the system bars.
1245      *         See {@link #areSystemBarsForcedShownLw(WindowState)}.
1246      */
getLayoutHintLw(LayoutParams attrs, Rect taskBounds, DisplayFrames displayFrames, boolean floatingStack, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout)1247     public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
1248             DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
1249             Rect outContentInsets, Rect outStableInsets,
1250             Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
1251         final int fl = PolicyControl.getWindowFlags(null, attrs);
1252         final int pfl = attrs.privateFlags;
1253         final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
1254         final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
1255         final int displayRotation = displayFrames.mRotation;
1256 
1257         final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
1258         if (useOutsets) {
1259             int outset = mWindowOutsetBottom;
1260             if (outset > 0) {
1261                 if (displayRotation == Surface.ROTATION_0) {
1262                     outOutsets.bottom += outset;
1263                 } else if (displayRotation == Surface.ROTATION_90) {
1264                     outOutsets.right += outset;
1265                 } else if (displayRotation == Surface.ROTATION_180) {
1266                     outOutsets.top += outset;
1267                 } else if (displayRotation == Surface.ROTATION_270) {
1268                     outOutsets.left += outset;
1269                 }
1270             }
1271         }
1272 
1273         final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
1274         final boolean layoutInScreenAndInsetDecor = layoutInScreen
1275                 && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
1276         final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
1277 
1278         if (layoutInScreenAndInsetDecor && !screenDecor) {
1279             if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
1280                 outFrame.set(displayFrames.mUnrestricted);
1281             } else {
1282                 outFrame.set(displayFrames.mRestricted);
1283             }
1284 
1285             final Rect sf;
1286             if (floatingStack) {
1287                 sf = null;
1288             } else {
1289                 sf = displayFrames.mStable;
1290             }
1291 
1292             final Rect cf;
1293             if (floatingStack) {
1294                 cf = null;
1295             } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
1296                 if ((fl & FLAG_FULLSCREEN) != 0) {
1297                     cf = displayFrames.mStableFullscreen;
1298                 } else {
1299                     cf = displayFrames.mStable;
1300                 }
1301             } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
1302                 cf = displayFrames.mOverscan;
1303             } else {
1304                 cf = displayFrames.mCurrent;
1305             }
1306 
1307             if (taskBounds != null) {
1308                 outFrame.intersect(taskBounds);
1309             }
1310             InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets);
1311             InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
1312             outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
1313                     .getDisplayCutout());
1314             return mForceShowSystemBars;
1315         } else {
1316             if (layoutInScreen) {
1317                 outFrame.set(displayFrames.mUnrestricted);
1318             } else {
1319                 outFrame.set(displayFrames.mStable);
1320             }
1321             if (taskBounds != null) {
1322                 outFrame.intersect(taskBounds);
1323             }
1324 
1325             outContentInsets.setEmpty();
1326             outStableInsets.setEmpty();
1327             outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
1328             return mForceShowSystemBars;
1329         }
1330     }
1331 
getImpliedSysUiFlagsForLayout(LayoutParams attrs)1332     private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
1333         int impliedFlags = 0;
1334         final boolean forceWindowDrawsBarBackgrounds =
1335                 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1336                 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
1337         if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
1338                 || forceWindowDrawsBarBackgrounds) {
1339             impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1340             impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1341         }
1342         return impliedFlags;
1343     }
1344 
shouldUseOutsets(WindowManager.LayoutParams attrs, int fl)1345     private static boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) {
1346         return attrs.type == TYPE_WALLPAPER || (fl & (WindowManager.LayoutParams.FLAG_FULLSCREEN
1347                 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)) != 0;
1348     }
1349 
1350     private final Runnable mClearHideNavigationFlag = new Runnable() {
1351         @Override
1352         public void run() {
1353             synchronized (mLock) {
1354                 mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1355                 mDisplayContent.reevaluateStatusBarVisibility();
1356             }
1357         }
1358     };
1359 
1360     /**
1361      * Input handler used while nav bar is hidden.  Captures any touch on the screen,
1362      * to determine when the nav bar should be shown and prevent applications from
1363      * receiving those touches.
1364      */
1365     private final class HideNavInputEventReceiver extends InputEventReceiver {
HideNavInputEventReceiver(InputChannel inputChannel, Looper looper)1366         HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
1367             super(inputChannel, looper);
1368         }
1369 
1370         @Override
onInputEvent(InputEvent event)1371         public void onInputEvent(InputEvent event) {
1372             try {
1373                 if (event instanceof MotionEvent
1374                         && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1375                     final MotionEvent motionEvent = (MotionEvent) event;
1376                     if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
1377                         // When the user taps down, we re-show the nav bar.
1378                         boolean changed = false;
1379                         synchronized (mLock) {
1380                             if (mInputConsumer == null) {
1381                                 return;
1382                             }
1383                             // Any user activity always causes us to show the
1384                             // navigation controls, if they had been hidden.
1385                             // We also clear the low profile and only content
1386                             // flags so that tapping on the screen will atomically
1387                             // restore all currently hidden screen decorations.
1388                             int newVal = mResettingSystemUiFlags
1389                                     | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
1390                                     | View.SYSTEM_UI_FLAG_LOW_PROFILE
1391                                     | View.SYSTEM_UI_FLAG_FULLSCREEN;
1392                             if (mResettingSystemUiFlags != newVal) {
1393                                 mResettingSystemUiFlags = newVal;
1394                                 changed = true;
1395                             }
1396                             // We don't allow the system's nav bar to be hidden
1397                             // again for 1 second, to prevent applications from
1398                             // spamming us and keeping it from being shown.
1399                             newVal = mForceClearedSystemUiFlags
1400                                     | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1401                             if (mForceClearedSystemUiFlags != newVal) {
1402                                 mForceClearedSystemUiFlags = newVal;
1403                                 changed = true;
1404                                 mHandler.postDelayed(mClearHideNavigationFlag, 1000);
1405                             }
1406                             if (changed) {
1407                                 mDisplayContent.reevaluateStatusBarVisibility();
1408                             }
1409                         }
1410                     }
1411                 }
1412             } finally {
1413                 finishInputEvent(event, false /* handled */);
1414             }
1415         }
1416     }
1417 
1418     /**
1419      * Called when layout of the windows is about to start.
1420      *
1421      * @param displayFrames frames of the display we are doing layout on.
1422      * @param uiMode The current uiMode in configuration.
1423      */
beginLayoutLw(DisplayFrames displayFrames, int uiMode)1424     public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
1425         displayFrames.onBeginLayout();
1426         mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
1427         mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
1428 
1429         // For purposes of putting out fake window up to steal focus, we will
1430         // drive nav being hidden only by whether it is requested.
1431         final int sysui = mLastSystemUiFlags;
1432         boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
1433         boolean navTranslucent = (sysui
1434                 & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
1435         boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
1436         boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
1437         boolean navAllowedHidden = immersive || immersiveSticky;
1438         navTranslucent &= !immersiveSticky;  // transient trumps translucent
1439         boolean isKeyguardShowing = isStatusBarKeyguard()
1440                 && !mService.mPolicy.isKeyguardOccluded();
1441         boolean statusBarForcesShowingNavigation = !isKeyguardShowing && mStatusBar != null
1442                 && (mStatusBar.getAttrs().privateFlags
1443                 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
1444 
1445         // When the navigation bar isn't visible, we put up a fake input window to catch all
1446         // touch events. This way we can detect when the user presses anywhere to bring back the
1447         // nav bar and ensure the application doesn't see the event.
1448         if (navVisible || navAllowedHidden) {
1449             if (mInputConsumer != null) {
1450                 mHandler.sendMessage(
1451                         mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
1452                 mInputConsumer = null;
1453             }
1454         } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
1455             mInputConsumer = mService.createInputConsumer(mHandler.getLooper(),
1456                     INPUT_CONSUMER_NAVIGATION,
1457                     HideNavInputEventReceiver::new,
1458                     displayFrames.mDisplayId);
1459             // As long as mInputConsumer is active, hover events are not dispatched to the app
1460             // and the pointer icon is likely to become stale. Hide it to avoid confusion.
1461             InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
1462         }
1463 
1464         // For purposes of positioning and showing the nav bar, if we have decided that it can't
1465         // be hidden (because of the screen aspect ratio), then take that into account.
1466         navVisible |= !canHideNavigationBar();
1467 
1468         boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
1469                 navTranslucent, navAllowedHidden, statusBarForcesShowingNavigation);
1470         if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
1471         updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
1472         if (updateSysUiVisibility) {
1473             updateSystemUiVisibilityLw();
1474         }
1475         layoutScreenDecorWindows(displayFrames);
1476 
1477         if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
1478             // Make sure that the zone we're avoiding for the cutout is at least as tall as the
1479             // status bar; otherwise fullscreen apps will end up cutting halfway into the status
1480             // bar.
1481             displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
1482                     displayFrames.mStable.top);
1483         }
1484 
1485         // In case this is a virtual display, and the host display has insets that overlap this
1486         // virtual display, apply the insets of the overlapped area onto the current and content
1487         // frame of this virtual display. This let us layout windows in the virtual display as
1488         // expected when the window needs to avoid overlap with the system windows.
1489         // TODO: Generalize the forwarded insets, so that we can handle system windows other than
1490         // IME.
1491         displayFrames.mCurrent.inset(mForwardedInsets);
1492         displayFrames.mContent.inset(mForwardedInsets);
1493     }
1494 
layoutScreenDecorWindows(DisplayFrames displayFrames)1495     private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
1496         if (mScreenDecorWindows.isEmpty()) {
1497             return;
1498         }
1499 
1500         sTmpRect.setEmpty();
1501         final int displayId = displayFrames.mDisplayId;
1502         final Rect dockFrame = displayFrames.mDock;
1503         final int displayHeight = displayFrames.mDisplayHeight;
1504         final int displayWidth = displayFrames.mDisplayWidth;
1505 
1506         for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
1507             final WindowState w = mScreenDecorWindows.valueAt(i);
1508             if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
1509                 // Skip if not on the same display or not visible.
1510                 continue;
1511             }
1512 
1513             w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
1514                     displayFrames.mUnrestricted /* displayFrame */,
1515                     displayFrames.mUnrestricted /* overscanFrame */,
1516                     displayFrames.mUnrestricted /* contentFrame */,
1517                     displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
1518                     displayFrames.mUnrestricted /* stableFrame */,
1519                     displayFrames.mUnrestricted /* outsetFrame */);
1520             w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1521             w.computeFrameLw();
1522             final Rect frame = w.getFrameLw();
1523 
1524             if (frame.left <= 0 && frame.top <= 0) {
1525                 // Docked at left or top.
1526                 if (frame.bottom >= displayHeight) {
1527                     // Docked left.
1528                     dockFrame.left = Math.max(frame.right, dockFrame.left);
1529                 } else if (frame.right >= displayWidth) {
1530                     // Docked top.
1531                     dockFrame.top = Math.max(frame.bottom, dockFrame.top);
1532                 } else {
1533                     Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1534                             + " not docked on left or top of display. frame=" + frame
1535                             + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1536                 }
1537             } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
1538                 // Docked at right or bottom.
1539                 if (frame.top <= 0) {
1540                     // Docked right.
1541                     dockFrame.right = Math.min(frame.left, dockFrame.right);
1542                 } else if (frame.left <= 0) {
1543                     // Docked bottom.
1544                     dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
1545                 } else {
1546                     Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1547                             + " not docked on right or bottom" + " of display. frame=" + frame
1548                             + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1549                 }
1550             } else {
1551                 // Screen decor windows are required to be docked on one of the sides of the screen.
1552                 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1553                         + " not docked on one of the sides of the display. frame=" + frame
1554                         + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1555             }
1556         }
1557 
1558         displayFrames.mRestricted.set(dockFrame);
1559         displayFrames.mCurrent.set(dockFrame);
1560         displayFrames.mVoiceContent.set(dockFrame);
1561         displayFrames.mSystem.set(dockFrame);
1562         displayFrames.mContent.set(dockFrame);
1563         displayFrames.mRestrictedOverscan.set(dockFrame);
1564     }
1565 
layoutStatusBar(DisplayFrames displayFrames, int sysui, boolean isKeyguardShowing)1566     private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
1567             boolean isKeyguardShowing) {
1568         // decide where the status bar goes ahead of time
1569         if (mStatusBar == null) {
1570             return false;
1571         }
1572         // apply any navigation bar insets
1573         sTmpRect.setEmpty();
1574         final WindowFrames windowFrames = mStatusBar.getWindowFrames();
1575         windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
1576                 displayFrames.mUnrestricted /* displayFrame */,
1577                 displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
1578                 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
1579                 displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
1580         windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1581 
1582         // Let the status bar determine its size.
1583         mStatusBar.computeFrameLw();
1584 
1585         // For layout, the status bar is always at the top with our fixed height.
1586         displayFrames.mStable.top = displayFrames.mUnrestricted.top
1587                 + mStatusBarHeightForRotation[displayFrames.mRotation];
1588         // Make sure the status bar covers the entire cutout height
1589         displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
1590                 displayFrames.mDisplayCutoutSafe.top);
1591 
1592         // Tell the bar controller where the collapsed status bar content is
1593         sTmpRect.set(mStatusBar.getContentFrameLw());
1594         sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
1595         sTmpRect.top = mStatusBar.getContentFrameLw().top;  // Ignore top display cutout inset
1596         sTmpRect.bottom = displayFrames.mStable.top;  // Use collapsed status bar size
1597         mStatusBarController.setContentFrame(sTmpRect);
1598 
1599         boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
1600         boolean statusBarTranslucent = (sysui
1601                 & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
1602 
1603         // If the status bar is hidden, we don't want to cause windows behind it to scroll.
1604         if (mStatusBar.isVisibleLw() && !statusBarTransient) {
1605             // Status bar may go away, so the screen area it occupies is available to apps but just
1606             // covering them when the status bar is visible.
1607             final Rect dockFrame = displayFrames.mDock;
1608             dockFrame.top = displayFrames.mStable.top;
1609             displayFrames.mContent.set(dockFrame);
1610             displayFrames.mVoiceContent.set(dockFrame);
1611             displayFrames.mCurrent.set(dockFrame);
1612 
1613             if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
1614                     "dock=%s content=%s cur=%s", dockFrame.toString(),
1615                     displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
1616 
1617             if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent()
1618                     && !mStatusBar.isAnimatingLw()) {
1619 
1620                 // If the opaque status bar is currently requested to be visible, and not in the
1621                 // process of animating on or off, then we can tell the app that it is covered by
1622                 // it.
1623                 displayFrames.mSystem.top = displayFrames.mStable.top;
1624             }
1625         }
1626         return mStatusBarController.checkHiddenLw();
1627     }
1628 
layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible, boolean navTranslucent, boolean navAllowedHidden, boolean statusBarForcesShowingNavigation)1629     private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
1630             boolean navTranslucent, boolean navAllowedHidden,
1631             boolean statusBarForcesShowingNavigation) {
1632         if (mNavigationBar == null) {
1633             return false;
1634         }
1635 
1636         final Rect navigationFrame = sTmpNavFrame;
1637         boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
1638         // Force the navigation bar to its appropriate place and size. We need to do this directly,
1639         // instead of relying on it to bubble up from the nav bar, because this needs to change
1640         // atomically with screen rotations.
1641         final int rotation = displayFrames.mRotation;
1642         final int displayHeight = displayFrames.mDisplayHeight;
1643         final int displayWidth = displayFrames.mDisplayWidth;
1644         final Rect dockFrame = displayFrames.mDock;
1645         mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
1646 
1647         final Rect cutoutSafeUnrestricted = sTmpRect;
1648         cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
1649         cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1650 
1651         if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1652             // It's a system nav bar or a portrait screen; nav bar goes on bottom.
1653             final int top = cutoutSafeUnrestricted.bottom
1654                     - getNavigationBarHeight(rotation, uiMode);
1655             final int topNavBar = cutoutSafeUnrestricted.bottom
1656                     - getNavigationBarFrameHeight(rotation, uiMode);
1657             navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom);
1658             displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
1659             if (transientNavBarShowing) {
1660                 mNavigationBarController.setBarShowingLw(true);
1661             } else if (navVisible) {
1662                 mNavigationBarController.setBarShowingLw(true);
1663                 dockFrame.bottom = displayFrames.mRestricted.bottom =
1664                         displayFrames.mRestrictedOverscan.bottom = top;
1665             } else {
1666                 // We currently want to hide the navigation UI - unless we expanded the status bar.
1667                 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1668             }
1669             if (navVisible && !navTranslucent && !navAllowedHidden
1670                     && !mNavigationBar.isAnimatingLw()
1671                     && !mNavigationBarController.wasRecentlyTranslucent()) {
1672                 // If the opaque nav bar is currently requested to be visible and not in the process
1673                 // of animating on or off, then we can tell the app that it is covered by it.
1674                 displayFrames.mSystem.bottom = top;
1675             }
1676         } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1677             // Landscape screen; nav bar goes to the right.
1678             final int left = cutoutSafeUnrestricted.right
1679                     - getNavigationBarWidth(rotation, uiMode);
1680             navigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
1681             displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
1682             if (transientNavBarShowing) {
1683                 mNavigationBarController.setBarShowingLw(true);
1684             } else if (navVisible) {
1685                 mNavigationBarController.setBarShowingLw(true);
1686                 dockFrame.right = displayFrames.mRestricted.right =
1687                         displayFrames.mRestrictedOverscan.right = left;
1688             } else {
1689                 // We currently want to hide the navigation UI - unless we expanded the status bar.
1690                 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1691             }
1692             if (navVisible && !navTranslucent && !navAllowedHidden
1693                     && !mNavigationBar.isAnimatingLw()
1694                     && !mNavigationBarController.wasRecentlyTranslucent()) {
1695                 // If the nav bar is currently requested to be visible, and not in the process of
1696                 // animating on or off, then we can tell the app that it is covered by it.
1697                 displayFrames.mSystem.right = left;
1698             }
1699         } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1700             // Seascape screen; nav bar goes to the left.
1701             final int right = cutoutSafeUnrestricted.left
1702                     + getNavigationBarWidth(rotation, uiMode);
1703             navigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
1704             displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
1705             if (transientNavBarShowing) {
1706                 mNavigationBarController.setBarShowingLw(true);
1707             } else if (navVisible) {
1708                 mNavigationBarController.setBarShowingLw(true);
1709                 dockFrame.left = displayFrames.mRestricted.left =
1710                         displayFrames.mRestrictedOverscan.left = right;
1711             } else {
1712                 // We currently want to hide the navigation UI - unless we expanded the status bar.
1713                 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1714             }
1715             if (navVisible && !navTranslucent && !navAllowedHidden
1716                     && !mNavigationBar.isAnimatingLw()
1717                     && !mNavigationBarController.wasRecentlyTranslucent()) {
1718                 // If the nav bar is currently requested to be visible, and not in the process of
1719                 // animating on or off, then we can tell the app that it is covered by it.
1720                 displayFrames.mSystem.left = right;
1721             }
1722         }
1723 
1724         // Make sure the content and current rectangles are updated to account for the restrictions
1725         // from the navigation bar.
1726         displayFrames.mCurrent.set(dockFrame);
1727         displayFrames.mVoiceContent.set(dockFrame);
1728         displayFrames.mContent.set(dockFrame);
1729         // And compute the final frame.
1730         sTmpRect.setEmpty();
1731         mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
1732                 navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
1733                 displayFrames.mDisplayCutoutSafe /* contentFrame */,
1734                 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
1735                 navigationFrame /* stableFrame */,
1736                 displayFrames.mDisplayCutoutSafe /* outsetFrame */);
1737         mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1738         mNavigationBar.computeFrameLw();
1739         mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
1740 
1741         if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
1742         return mNavigationBarController.checkHiddenLw();
1743     }
1744 
setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf, DisplayFrames displayFrames)1745     private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
1746             boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf,
1747             DisplayFrames displayFrames) {
1748         if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
1749             // Here's a special case: if the child window is not the 'dock window'
1750             // or input method target, and the window it is attached to is below
1751             // the dock window, then the frames we computed for the window it is
1752             // attached to can not be used because the dock is effectively part
1753             // of the underlying window and the attached window is floating on top
1754             // of the whole thing. So, we ignore the attached window and explicitly
1755             // compute the frames that would be appropriate without the dock.
1756             vf.set(displayFrames.mDock);
1757             cf.set(displayFrames.mDock);
1758             of.set(displayFrames.mDock);
1759             df.set(displayFrames.mDock);
1760         } else {
1761 
1762             // In case we forced the window to draw behind the navigation bar, restrict df/of to
1763             // DF.RestrictedOverscan to simulate old compat behavior.
1764             Rect parentDisplayFrame = attached.getDisplayFrameLw();
1765             Rect parentOverscan = attached.getOverscanFrameLw();
1766             final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
1767             if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1768                     && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1769                     && (attachedAttrs.systemUiVisibility
1770                             & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
1771                 parentOverscan = new Rect(parentOverscan);
1772                 parentOverscan.intersect(displayFrames.mRestrictedOverscan);
1773                 parentDisplayFrame = new Rect(parentDisplayFrame);
1774                 parentDisplayFrame.intersect(displayFrames.mRestrictedOverscan);
1775             }
1776 
1777             // The effective display frame of the attached window depends on whether it is taking
1778             // care of insetting its content. If not, we need to use the parent's content frame so
1779             // that the entire window is positioned within that content. Otherwise we can use the
1780             // overscan frame and let the attached window take care of positioning its content
1781             // appropriately.
1782             if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1783                 // Set the content frame of the attached window to the parent's decor frame
1784                 // (same as content frame when IME isn't present) if specifically requested by
1785                 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
1786                 // Otherwise, use the overscan frame.
1787                 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
1788                         ? attached.getContentFrameLw() : parentOverscan);
1789             } else {
1790                 // If the window is resizing, then we want to base the content frame on our attached
1791                 // content frame to resize...however, things can be tricky if the attached window is
1792                 // NOT in resize mode, in which case its content frame will be larger.
1793                 // Ungh. So to deal with that, make sure the content frame we end up using is not
1794                 // covering the IM dock.
1795                 cf.set(attached.getContentFrameLw());
1796                 if (attached.isVoiceInteraction()) {
1797                     cf.intersectUnchecked(displayFrames.mVoiceContent);
1798                 } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
1799                     cf.intersectUnchecked(displayFrames.mContent);
1800                 }
1801             }
1802             df.set(insetDecors ? parentDisplayFrame : cf);
1803             of.set(insetDecors ? parentOverscan : cf);
1804             vf.set(attached.getVisibleFrameLw());
1805         }
1806         // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
1807         // positioned relative to its parent or the entire screen.
1808         pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1809     }
1810 
applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames)1811     private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
1812         if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
1813             return;
1814         }
1815         // If app is requesting a stable layout, don't let the content insets go below the stable
1816         // values.
1817         if ((fl & FLAG_FULLSCREEN) != 0) {
1818             r.intersectUnchecked(displayFrames.mStableFullscreen);
1819         } else {
1820             r.intersectUnchecked(displayFrames.mStable);
1821         }
1822     }
1823 
canReceiveInput(WindowState win)1824     private boolean canReceiveInput(WindowState win) {
1825         boolean notFocusable =
1826                 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
1827         boolean altFocusableIm =
1828                 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
1829         boolean notFocusableForIm = notFocusable ^ altFocusableIm;
1830         return !notFocusableForIm;
1831     }
1832 
1833     /**
1834      * Called for each window attached to the window manager as layout is proceeding. The
1835      * implementation of this function must take care of setting the window's frame, either here or
1836      * in finishLayout().
1837      *
1838      * @param win The window being positioned.
1839      * @param attached For sub-windows, the window it is attached to; this
1840      *                 window will already have had layoutWindow() called on it
1841      *                 so you can use its Rect.  Otherwise null.
1842      * @param displayFrames The display frames.
1843      */
layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames)1844     public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
1845         // We've already done the navigation bar, status bar, and all screen decor windows. If the
1846         // status bar can receive input, we need to layout it again to accommodate for the IME
1847         // window.
1848         if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
1849                 || mScreenDecorWindows.contains(win)) {
1850             return;
1851         }
1852         final WindowManager.LayoutParams attrs = win.getAttrs();
1853         final boolean isDefaultDisplay = win.isDefaultDisplay();
1854 
1855         final int type = attrs.type;
1856         final int fl = PolicyControl.getWindowFlags(win, attrs);
1857         final int pfl = attrs.privateFlags;
1858         final int sim = attrs.softInputMode;
1859         final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
1860         final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
1861 
1862         final WindowFrames windowFrames = win.getWindowFrames();
1863 
1864         windowFrames.setHasOutsets(false);
1865         sTmpLastParentFrame.set(windowFrames.mParentFrame);
1866         final Rect pf = windowFrames.mParentFrame;
1867         final Rect df = windowFrames.mDisplayFrame;
1868         final Rect of = windowFrames.mOverscanFrame;
1869         final Rect cf = windowFrames.mContentFrame;
1870         final Rect vf = windowFrames.mVisibleFrame;
1871         final Rect dcf = windowFrames.mDecorFrame;
1872         final Rect sf = windowFrames.mStableFrame;
1873         dcf.setEmpty();
1874         windowFrames.setParentFrameWasClippedByDisplayCutout(false);
1875         windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1876 
1877         final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
1878                 && mNavigationBar.isVisibleLw();
1879 
1880         final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
1881 
1882         final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
1883                 || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
1884 
1885         final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
1886         final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
1887 
1888         sf.set(displayFrames.mStable);
1889 
1890         if (type == TYPE_INPUT_METHOD) {
1891             vf.set(displayFrames.mDock);
1892             cf.set(displayFrames.mDock);
1893             of.set(displayFrames.mDock);
1894             df.set(displayFrames.mDock);
1895             windowFrames.mParentFrame.set(displayFrames.mDock);
1896             // IM dock windows layout below the nav bar...
1897             pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
1898             // ...with content insets above the nav bar
1899             cf.bottom = vf.bottom = displayFrames.mStable.bottom;
1900             if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
1901                 // The status bar forces the navigation bar while it's visible. Make sure the IME
1902                 // avoids the navigation bar in that case.
1903                 if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1904                     pf.right = df.right = of.right = cf.right = vf.right =
1905                             displayFrames.mStable.right;
1906                 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1907                     pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left;
1908                 }
1909             }
1910 
1911             // In case the navigation bar is on the bottom, we use the frame height instead of the
1912             // regular height for the insets we send to the IME as we need some space to show
1913             // additional buttons in SystemUI when the IME is up.
1914             if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1915                 final int rotation = displayFrames.mRotation;
1916                 final int uimode = mService.mPolicy.getUiMode();
1917                 final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode)
1918                         - getNavigationBarHeight(rotation, uimode);
1919                 if (navHeightOffset > 0) {
1920                     cf.bottom -= navHeightOffset;
1921                     sf.bottom -= navHeightOffset;
1922                     vf.bottom -= navHeightOffset;
1923                     dcf.bottom -= navHeightOffset;
1924                 }
1925             }
1926 
1927             // IM dock windows always go to the bottom of the screen.
1928             attrs.gravity = Gravity.BOTTOM;
1929         } else if (type == TYPE_VOICE_INTERACTION) {
1930             of.set(displayFrames.mUnrestricted);
1931             df.set(displayFrames.mUnrestricted);
1932             pf.set(displayFrames.mUnrestricted);
1933             if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1934                 cf.set(displayFrames.mDock);
1935             } else {
1936                 cf.set(displayFrames.mContent);
1937             }
1938             if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1939                 vf.set(displayFrames.mCurrent);
1940             } else {
1941                 vf.set(cf);
1942             }
1943         } else if (type == TYPE_WALLPAPER) {
1944             layoutWallpaper(displayFrames, pf, df, of, cf);
1945         } else if (win == mStatusBar) {
1946             of.set(displayFrames.mUnrestricted);
1947             df.set(displayFrames.mUnrestricted);
1948             pf.set(displayFrames.mUnrestricted);
1949             cf.set(displayFrames.mStable);
1950             vf.set(displayFrames.mStable);
1951 
1952             if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
1953                 cf.bottom = displayFrames.mContent.bottom;
1954             } else {
1955                 cf.bottom = displayFrames.mDock.bottom;
1956                 vf.bottom = displayFrames.mContent.bottom;
1957             }
1958         } else {
1959             dcf.set(displayFrames.mSystem);
1960             final boolean inheritTranslucentDecor =
1961                     (attrs.privateFlags & PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
1962             final boolean isAppWindow =
1963                     type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
1964             final boolean topAtRest =
1965                     win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
1966             if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
1967                 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
1968                         && (fl & FLAG_FULLSCREEN) == 0
1969                         && (fl & FLAG_TRANSLUCENT_STATUS) == 0
1970                         && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1971                         && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
1972                     // Ensure policy decor includes status bar
1973                     dcf.top = displayFrames.mStable.top;
1974                 }
1975                 if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
1976                         && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
1977                         && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1978                         && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
1979                     // Ensure policy decor includes navigation bar
1980                     dcf.bottom = displayFrames.mStable.bottom;
1981                     dcf.right = displayFrames.mStable.right;
1982                 }
1983             }
1984 
1985             if (layoutInScreen && layoutInsetDecor) {
1986                 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
1987                         + "): IN_SCREEN, INSET_DECOR");
1988                 // This is the case for a normal activity window: we want it to cover all of the
1989                 // screen space, and it can take care of moving its contents to account for screen
1990                 // decorations that intrude into that space.
1991                 if (attached != null) {
1992                     // If this window is attached to another, our display
1993                     // frame is the same as the one we are attached to.
1994                     setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf,
1995                             displayFrames);
1996                 } else {
1997                     if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
1998                         // Status bar panels are the only windows who can go on top of the status
1999                         // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
2000                         // have the same privileges as the status bar itself.
2001                         //
2002                         // However, they should still dodge the navigation bar if it exists.
2003 
2004                         pf.left = df.left = of.left = hasNavBar
2005                                 ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
2006                         pf.top = df.top = of.top = displayFrames.mUnrestricted.top;
2007                         pf.right = df.right = of.right = hasNavBar
2008                                 ? displayFrames.mRestricted.right
2009                                 : displayFrames.mUnrestricted.right;
2010                         pf.bottom = df.bottom = of.bottom = hasNavBar
2011                                 ? displayFrames.mRestricted.bottom
2012                                 : displayFrames.mUnrestricted.bottom;
2013 
2014                         if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
2015                     } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
2016                             && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
2017                         // Asking to layout into the overscan region, so give it that pure
2018                         // unrestricted area.
2019                         of.set(displayFrames.mOverscan);
2020                         df.set(displayFrames.mOverscan);
2021                         pf.set(displayFrames.mOverscan);
2022                     } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
2023                             && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
2024                             || type == TYPE_VOLUME_OVERLAY
2025                             || type == TYPE_KEYGUARD_DIALOG)) {
2026                         // Asking for layout as if the nav bar is hidden, lets the application
2027                         // extend into the unrestricted overscan screen area. We only do this for
2028                         // application windows and certain system windows to ensure no window that
2029                         // can be above the nav bar can do this.
2030                         df.set(displayFrames.mOverscan);
2031                         pf.set(displayFrames.mOverscan);
2032                         // We need to tell the app about where the frame inside the overscan is, so
2033                         // it can inset its content by that amount -- it didn't ask to actually
2034                         // extend itself into the overscan region.
2035                         of.set(displayFrames.mUnrestricted);
2036                     } else {
2037                         df.set(displayFrames.mRestrictedOverscan);
2038                         pf.set(displayFrames.mRestrictedOverscan);
2039                         // We need to tell the app about where the frame inside the overscan
2040                         // is, so it can inset its content by that amount -- it didn't ask
2041                         // to actually extend itself into the overscan region.
2042                         of.set(displayFrames.mUnrestricted);
2043                     }
2044 
2045                     if ((fl & FLAG_FULLSCREEN) == 0) {
2046                         if (win.isVoiceInteraction()) {
2047                             cf.set(displayFrames.mVoiceContent);
2048                         } else {
2049                             // IME Insets are handled on the client for ADJUST_RESIZE in the new
2050                             // insets world
2051                             if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2052                                     || adjust != SOFT_INPUT_ADJUST_RESIZE) {
2053                                 cf.set(displayFrames.mDock);
2054                             } else {
2055                                 cf.set(displayFrames.mContent);
2056                             }
2057                         }
2058                     } else {
2059                         // Full screen windows are always given a layout that is as if the status
2060                         // bar and other transient decors are gone. This is to avoid bad states when
2061                         // moving from a window that is not hiding the status bar to one that is.
2062                         cf.set(displayFrames.mRestricted);
2063                     }
2064                     applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2065                     if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2066                         vf.set(displayFrames.mCurrent);
2067                     } else {
2068                         vf.set(cf);
2069                     }
2070                 }
2071             } else if (layoutInScreen || (sysUiFl
2072                     & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
2073                     | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
2074                 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2075                         + "): IN_SCREEN");
2076                 // A window that has requested to fill the entire screen just
2077                 // gets everything, period.
2078                 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2079                     cf.set(displayFrames.mUnrestricted);
2080                     of.set(displayFrames.mUnrestricted);
2081                     df.set(displayFrames.mUnrestricted);
2082                     pf.set(displayFrames.mUnrestricted);
2083                     if (hasNavBar) {
2084                         pf.left = df.left = of.left = cf.left = displayFrames.mDock.left;
2085                         pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right;
2086                         pf.bottom = df.bottom = of.bottom = cf.bottom =
2087                                 displayFrames.mRestricted.bottom;
2088                     }
2089                     if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
2090                 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
2091                     // The navigation bar has Real Ultimate Power.
2092                     of.set(displayFrames.mUnrestricted);
2093                     df.set(displayFrames.mUnrestricted);
2094                     pf.set(displayFrames.mUnrestricted);
2095                     if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
2096                 } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
2097                         && ((fl & FLAG_FULLSCREEN) != 0)) {
2098                     // Fullscreen secure system overlays get what they ask for. Screenshot region
2099                     // selection overlay should also expand to full screen.
2100                     cf.set(displayFrames.mOverscan);
2101                     of.set(displayFrames.mOverscan);
2102                     df.set(displayFrames.mOverscan);
2103                     pf.set(displayFrames.mOverscan);
2104                 } else if (type == TYPE_BOOT_PROGRESS) {
2105                     // Boot progress screen always covers entire display.
2106                     cf.set(displayFrames.mOverscan);
2107                     of.set(displayFrames.mOverscan);
2108                     df.set(displayFrames.mOverscan);
2109                     pf.set(displayFrames.mOverscan);
2110                 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
2111                         && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
2112                     // Asking to layout into the overscan region, so give it that pure unrestricted
2113                     // area.
2114                     cf.set(displayFrames.mOverscan);
2115                     of.set(displayFrames.mOverscan);
2116                     df.set(displayFrames.mOverscan);
2117                     pf.set(displayFrames.mOverscan);
2118                 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
2119                         && (type == TYPE_STATUS_BAR
2120                         || type == TYPE_TOAST
2121                         || type == TYPE_DOCK_DIVIDER
2122                         || type == TYPE_VOICE_INTERACTION_STARTING
2123                         || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
2124                     // Asking for layout as if the nav bar is hidden, lets the
2125                     // application extend into the unrestricted screen area.  We
2126                     // only do this for application windows (or toasts) to ensure no window that
2127                     // can be above the nav bar can do this.
2128                     // XXX This assumes that an app asking for this will also
2129                     // ask for layout in only content.  We can't currently figure out
2130                     // what the screen would be if only laying out to hide the nav bar.
2131                     cf.set(displayFrames.mUnrestricted);
2132                     of.set(displayFrames.mUnrestricted);
2133                     df.set(displayFrames.mUnrestricted);
2134                     pf.set(displayFrames.mUnrestricted);
2135                 } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
2136                     of.set(displayFrames.mRestricted);
2137                     df.set(displayFrames.mRestricted);
2138                     pf.set(displayFrames.mRestricted);
2139 
2140                     // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
2141                     // world
2142                     if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2143                             || adjust != SOFT_INPUT_ADJUST_RESIZE) {
2144                         cf.set(displayFrames.mDock);
2145                     } else {
2146                         cf.set(displayFrames.mContent);
2147                     }
2148                 } else {
2149                     cf.set(displayFrames.mRestricted);
2150                     of.set(displayFrames.mRestricted);
2151                     df.set(displayFrames.mRestricted);
2152                     pf.set(displayFrames.mRestricted);
2153                 }
2154 
2155                 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2156 
2157                 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2158                     vf.set(displayFrames.mCurrent);
2159                 } else {
2160                     vf.set(cf);
2161                 }
2162             } else if (attached != null) {
2163                 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2164                         + "): attached to " + attached);
2165                 // A child window should be placed inside of the same visible
2166                 // frame that its parent had.
2167                 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf,
2168                         displayFrames);
2169             } else {
2170                 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2171                         + "): normal window");
2172                 // Otherwise, a normal window must be placed inside the content
2173                 // of all screen decorations.
2174                 if (type == TYPE_STATUS_BAR_PANEL) {
2175                     // Status bar panels can go on
2176                     // top of the status bar. They are protected by the STATUS_BAR_SERVICE
2177                     // permission, so they have the same privileges as the status bar itself.
2178                     cf.set(displayFrames.mRestricted);
2179                     of.set(displayFrames.mRestricted);
2180                     df.set(displayFrames.mRestricted);
2181                     pf.set(displayFrames.mRestricted);
2182                 } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
2183                     // These dialogs are stable to interim decor changes.
2184                     cf.set(displayFrames.mStable);
2185                     of.set(displayFrames.mStable);
2186                     df.set(displayFrames.mStable);
2187                     pf.set(displayFrames.mStable);
2188                 } else {
2189                     pf.set(displayFrames.mContent);
2190                     if (win.isVoiceInteraction()) {
2191                         cf.set(displayFrames.mVoiceContent);
2192                         of.set(displayFrames.mVoiceContent);
2193                         df.set(displayFrames.mVoiceContent);
2194                     } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2195                         cf.set(displayFrames.mDock);
2196                         of.set(displayFrames.mDock);
2197                         df.set(displayFrames.mDock);
2198                     } else {
2199                         cf.set(displayFrames.mContent);
2200                         of.set(displayFrames.mContent);
2201                         df.set(displayFrames.mContent);
2202                     }
2203                     if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2204                         vf.set(displayFrames.mCurrent);
2205                     } else {
2206                         vf.set(cf);
2207                     }
2208                 }
2209             }
2210         }
2211 
2212         final int cutoutMode = attrs.layoutInDisplayCutoutMode;
2213         final boolean attachedInParent = attached != null && !layoutInScreen;
2214         final boolean requestedHideNavigation =
2215                 (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
2216 
2217         // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
2218         // cropped / shifted to the displayFrame in WindowState.
2219         final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
2220                 && type != TYPE_BASE_APPLICATION;
2221 
2222         // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
2223         // the cutout safe zone.
2224         if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
2225             final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
2226             displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
2227             if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
2228                     && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2229                 // At the top we have the status bar, so apps that are
2230                 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
2231                 // already expect that there's an inset there and we don't need to exclude
2232                 // the window from that area.
2233                 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
2234             }
2235             if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
2236                     && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2237                 // Same for the navigation bar.
2238                 switch (mNavigationBarPosition) {
2239                     case NAV_BAR_BOTTOM:
2240                         displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2241                         break;
2242                     case NAV_BAR_RIGHT:
2243                         displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
2244                         break;
2245                     case NAV_BAR_LEFT:
2246                         displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
2247                         break;
2248                 }
2249             }
2250             if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
2251                 // The IME can always extend under the bottom cutout if the navbar is there.
2252                 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2253             }
2254             // Windows that are attached to a parent and laid out in said parent already avoid
2255             // the cutout according to that parent and don't need to be further constrained.
2256             // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
2257             // They will later be cropped or shifted using the displayFrame in WindowState,
2258             // which prevents overlap with the DisplayCutout.
2259             if (!attachedInParent && !floatingInScreenWindow) {
2260                 sTmpRect.set(pf);
2261                 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2262                 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
2263             }
2264             // Make sure that NO_LIMITS windows clipped to the display don't extend under the
2265             // cutout.
2266             df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2267         }
2268 
2269         // Content should never appear in the cutout.
2270         cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
2271 
2272         // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
2273         // Also, we don't allow windows in multi-window mode to extend out of the screen.
2274         if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
2275                 && !win.inMultiWindowMode()) {
2276             df.left = df.top = -10000;
2277             df.right = df.bottom = 10000;
2278             if (type != TYPE_WALLPAPER) {
2279                 of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
2280                 of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
2281             }
2282         }
2283 
2284         // If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we
2285         // need to provide information to the clients that want to pretend that you can draw there.
2286         // We only want to apply outsets to certain types of windows. For example, we never want to
2287         // apply the outsets to floating dialogs, because they wouldn't make sense there.
2288         final boolean useOutsets = shouldUseOutsets(attrs, fl);
2289         if (isDefaultDisplay && useOutsets) {
2290             final Rect osf = windowFrames.mOutsetFrame;
2291             osf.set(cf.left, cf.top, cf.right, cf.bottom);
2292             windowFrames.setHasOutsets(true);
2293             int outset = mWindowOutsetBottom;
2294             if (outset > 0) {
2295                 int rotation = displayFrames.mRotation;
2296                 if (rotation == Surface.ROTATION_0) {
2297                     osf.bottom += outset;
2298                 } else if (rotation == Surface.ROTATION_90) {
2299                     osf.right += outset;
2300                 } else if (rotation == Surface.ROTATION_180) {
2301                     osf.top -= outset;
2302                 } else if (rotation == Surface.ROTATION_270) {
2303                     osf.left -= outset;
2304                 }
2305                 if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset
2306                         + " with rotation " + rotation + ", result: " + osf);
2307             }
2308         }
2309 
2310         if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
2311                 + ": sim=#" + Integer.toHexString(sim)
2312                 + " attach=" + attached + " type=" + type
2313                 + String.format(" flags=0x%08x", fl)
2314                 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
2315                 + " of=" + of.toShortString()
2316                 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
2317                 + " dcf=" + dcf.toShortString()
2318                 + " sf=" + sf.toShortString()
2319                 + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win);
2320 
2321         if (!sTmpLastParentFrame.equals(pf)) {
2322             windowFrames.setContentChanged(true);
2323         }
2324 
2325         win.computeFrameLw();
2326         // Dock windows carve out the bottom of the screen, so normal windows
2327         // can't appear underneath them.
2328         if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
2329                 && !win.getGivenInsetsPendingLw()) {
2330             offsetInputMethodWindowLw(win, displayFrames);
2331         }
2332         if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
2333                 && !win.getGivenInsetsPendingLw()) {
2334             offsetVoiceInputWindowLw(win, displayFrames);
2335         }
2336     }
2337 
layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf)2338     private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf) {
2339         // The wallpaper has Real Ultimate Power, but we want to tell it about the overscan area.
2340         df.set(displayFrames.mOverscan);
2341         pf.set(displayFrames.mOverscan);
2342         cf.set(displayFrames.mUnrestricted);
2343         of.set(displayFrames.mUnrestricted);
2344     }
2345 
offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames)2346     private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
2347         int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2348         top += win.getGivenContentInsetsLw().top;
2349         displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
2350         displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2351         top = win.getVisibleFrameLw().top;
2352         top += win.getGivenVisibleInsetsLw().top;
2353         displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
2354         if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
2355                 + displayFrames.mDock.bottom + " mContentBottom="
2356                 + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
2357     }
2358 
offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames)2359     private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
2360         int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2361         top += win.getGivenContentInsetsLw().top;
2362         displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2363     }
2364 
2365     /**
2366      * Called following layout of all windows before each window has policy applied.
2367      */
beginPostLayoutPolicyLw()2368     public void beginPostLayoutPolicyLw() {
2369         mTopFullscreenOpaqueWindowState = null;
2370         mTopFullscreenOpaqueOrDimmingWindowState = null;
2371         mTopDockedOpaqueWindowState = null;
2372         mTopDockedOpaqueOrDimmingWindowState = null;
2373         mForceStatusBar = false;
2374         mForceStatusBarFromKeyguard = false;
2375         mForceStatusBarTransparent = false;
2376         mForcingShowNavBar = false;
2377         mForcingShowNavBarLayer = -1;
2378 
2379         mAllowLockscreenWhenOn = false;
2380         mShowingDream = false;
2381         mWindowSleepTokenNeeded = false;
2382     }
2383 
2384     /**
2385      * Called following layout of all window to apply policy to each window.
2386      *
2387      * @param win The window being positioned.
2388      * @param attrs The LayoutParams of the window.
2389      * @param attached For sub-windows, the window it is attached to. Otherwise null.
2390      */
applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached, WindowState imeTarget)2391     public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
2392             WindowState attached, WindowState imeTarget) {
2393         final boolean affectsSystemUi = win.canAffectSystemUiFlags();
2394         if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
2395         mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
2396         final int fl = PolicyControl.getWindowFlags(win, attrs);
2397         if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
2398                 && attrs.type == TYPE_INPUT_METHOD) {
2399             mForcingShowNavBar = true;
2400             mForcingShowNavBarLayer = win.getSurfaceLayer();
2401         }
2402         if (attrs.type == TYPE_STATUS_BAR) {
2403             if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
2404                 mForceStatusBarFromKeyguard = true;
2405             }
2406             if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
2407                 mForceStatusBarTransparent = true;
2408             }
2409         }
2410 
2411         boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
2412                 && attrs.type < FIRST_SYSTEM_WINDOW;
2413         final int windowingMode = win.getWindowingMode();
2414         final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
2415                 windowingMode == WINDOWING_MODE_FULLSCREEN
2416                         || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
2417         if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
2418             if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2419                 mForceStatusBar = true;
2420             }
2421             if (attrs.type == TYPE_DREAM) {
2422                 // If the lockscreen was showing when the dream started then wait
2423                 // for the dream to draw before hiding the lockscreen.
2424                 if (!mDreamingLockscreen
2425                         || (win.isVisibleLw() && win.hasDrawnLw())) {
2426                     mShowingDream = true;
2427                     appWindow = true;
2428                 }
2429             }
2430 
2431             // For app windows that are not attached, we decide if all windows in the app they
2432             // represent should be hidden or if we should hide the lockscreen. For attached app
2433             // windows we defer the decision to the window it is attached to.
2434             if (appWindow && attached == null) {
2435                 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2436                     if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
2437                     mTopFullscreenOpaqueWindowState = win;
2438                     if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2439                         mTopFullscreenOpaqueOrDimmingWindowState = win;
2440                     }
2441                     if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2442                         mAllowLockscreenWhenOn = true;
2443                     }
2444                 }
2445             }
2446         }
2447 
2448         // Voice interaction overrides both top fullscreen and top docked.
2449         if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION) {
2450             if (mTopFullscreenOpaqueWindowState == null) {
2451                 mTopFullscreenOpaqueWindowState = win;
2452                 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2453                     mTopFullscreenOpaqueOrDimmingWindowState = win;
2454                 }
2455             }
2456             if (mTopDockedOpaqueWindowState == null) {
2457                 mTopDockedOpaqueWindowState = win;
2458                 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2459                     mTopDockedOpaqueOrDimmingWindowState = win;
2460                 }
2461             }
2462         }
2463 
2464         // Keep track of the window if it's dimming but not necessarily fullscreen.
2465         if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
2466                 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2467             mTopFullscreenOpaqueOrDimmingWindowState = win;
2468         }
2469 
2470         // We need to keep track of the top "fullscreen" opaque window for the docked stack
2471         // separately, because both the "real fullscreen" opaque window and the one for the docked
2472         // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
2473         if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
2474                 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2475             mTopDockedOpaqueWindowState = win;
2476             if (mTopDockedOpaqueOrDimmingWindowState == null) {
2477                 mTopDockedOpaqueOrDimmingWindowState = win;
2478             }
2479         }
2480 
2481         // Also keep track of any windows that are dimming but not necessarily fullscreen in the
2482         // docked stack.
2483         if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
2484                 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2485             mTopDockedOpaqueOrDimmingWindowState = win;
2486         }
2487     }
2488 
2489     /**
2490      * Called following layout of all windows and after policy has been applied
2491      * to each window. If in this function you do
2492      * something that may have modified the animation state of another window,
2493      * be sure to return non-zero in order to perform another pass through layout.
2494      *
2495      * @return Return any bit set of
2496      *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
2497      *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
2498      *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
2499      *         {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
2500      */
2501     public int finishPostLayoutPolicyLw() {
2502         int changes = 0;
2503         boolean topIsFullscreen = false;
2504 
2505         // If we are not currently showing a dream then remember the current
2506         // lockscreen state.  We will use this to determine whether the dream
2507         // started while the lockscreen was showing and remember this state
2508         // while the dream is showing.
2509         if (!mShowingDream) {
2510             mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
2511             if (mDreamingSleepTokenNeeded) {
2512                 mDreamingSleepTokenNeeded = false;
2513                 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
2514             }
2515         } else {
2516             if (!mDreamingSleepTokenNeeded) {
2517                 mDreamingSleepTokenNeeded = true;
2518                 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
2519             }
2520         }
2521 
2522         if (mStatusBar != null) {
2523             if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
2524                     + " forcefkg=" + mForceStatusBarFromKeyguard
2525                     + " top=" + mTopFullscreenOpaqueWindowState);
2526             boolean shouldBeTransparent = mForceStatusBarTransparent
2527                     && !mForceStatusBar
2528                     && !mForceStatusBarFromKeyguard;
2529             if (!shouldBeTransparent) {
2530                 mStatusBarController.setShowTransparent(false /* transparent */);
2531             } else if (!mStatusBar.isVisibleLw()) {
2532                 mStatusBarController.setShowTransparent(true /* transparent */);
2533             }
2534 
2535             boolean statusBarForcesShowingNavigation =
2536                     (mStatusBar.getAttrs().privateFlags
2537                             & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
2538             boolean topAppHidesStatusBar = topAppHidesStatusBar();
2539             if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent
2540                     || statusBarForcesShowingNavigation) {
2541                 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
2542                 if (mStatusBarController.setBarShowingLw(true)) {
2543                     changes |= FINISH_LAYOUT_REDO_LAYOUT;
2544                 }
2545                 // Maintain fullscreen layout until incoming animation is complete.
2546                 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
2547                 // Transient status bar is not allowed if status bar is on lockscreen or status bar
2548                 // is expecting the navigation keys from the user.
2549                 if ((mForceStatusBarFromKeyguard || statusBarForcesShowingNavigation)
2550                         && mStatusBarController.isTransientShowing()) {
2551                     mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
2552                             mLastSystemUiFlags, mLastSystemUiFlags);
2553                 }
2554             } else if (mTopFullscreenOpaqueWindowState != null) {
2555                 topIsFullscreen = topAppHidesStatusBar;
2556                 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2557                 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
2558                 // has the FLAG_FULLSCREEN set.  Not sure if there is another way that to be the
2559                 // case though.
2560                 if (mStatusBarController.isTransientShowing()) {
2561                     if (mStatusBarController.setBarShowingLw(true)) {
2562                         changes |= FINISH_LAYOUT_REDO_LAYOUT;
2563                     }
2564                 } else if (topIsFullscreen
2565                         && !mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM)
2566                         && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
2567                     if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
2568                     if (mStatusBarController.setBarShowingLw(false)) {
2569                         changes |= FINISH_LAYOUT_REDO_LAYOUT;
2570                     } else {
2571                         if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
2572                     }
2573                 } else {
2574                     if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
2575                     if (mStatusBarController.setBarShowingLw(true)) {
2576                         changes |= FINISH_LAYOUT_REDO_LAYOUT;
2577                     }
2578                     topAppHidesStatusBar = false;
2579                 }
2580             }
2581             mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
2582         }
2583 
2584         if (mTopIsFullscreen != topIsFullscreen) {
2585             if (!topIsFullscreen) {
2586                 // Force another layout when status bar becomes fully shown.
2587                 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2588             }
2589             mTopIsFullscreen = topIsFullscreen;
2590         }
2591 
2592         if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
2593             // If the navigation bar has been hidden or shown, we need to do another
2594             // layout pass to update that window.
2595             changes |= FINISH_LAYOUT_REDO_LAYOUT;
2596         }
2597 
2598         if (mShowingDream != mLastShowingDream) {
2599             mLastShowingDream = mShowingDream;
2600             mService.notifyShowingDreamChanged();
2601         }
2602 
2603         updateWindowSleepToken();
2604 
2605         mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
2606         return changes;
2607     }
2608 
2609     private void updateWindowSleepToken() {
2610         if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) {
2611             mHandler.removeCallbacks(mReleaseSleepTokenRunnable);
2612             mHandler.post(mAcquireSleepTokenRunnable);
2613         } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) {
2614             mHandler.removeCallbacks(mAcquireSleepTokenRunnable);
2615             mHandler.post(mReleaseSleepTokenRunnable);
2616         }
2617         mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded;
2618     }
2619 
2620     /**
2621      * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
2622      *         window.
2623      */
2624     private boolean topAppHidesStatusBar() {
2625         if (mTopFullscreenOpaqueWindowState == null) {
2626             return false;
2627         }
2628         final int fl = PolicyControl.getWindowFlags(null,
2629                 mTopFullscreenOpaqueWindowState.getAttrs());
2630         if (localLOGV) {
2631             Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
2632             Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2633                     + " lp.flags=0x" + Integer.toHexString(fl));
2634         }
2635         return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
2636                 || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
2637     }
2638 
2639     /**
2640      * Called when the user is switched.
2641      */
2642     public void switchUser() {
2643         updateCurrentUserResources();
2644     }
2645 
2646     /**
2647      * Called when the resource overlays change.
2648      */
2649     public void onOverlayChangedLw() {
2650         updateCurrentUserResources();
2651         onConfigurationChanged();
2652         mSystemGestures.onConfigurationChanged();
2653     }
2654 
2655     /**
2656      * Called when the configuration has changed, and it's safe to load new values from resources.
2657      */
2658     public void onConfigurationChanged() {
2659         final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
2660 
2661         final Resources res = getCurrentUserResources();
2662         final int portraitRotation = displayRotation.getPortraitRotation();
2663         final int upsideDownRotation = displayRotation.getUpsideDownRotation();
2664         final int landscapeRotation = displayRotation.getLandscapeRotation();
2665         final int seascapeRotation = displayRotation.getSeascapeRotation();
2666         final int uiMode = mService.mPolicy.getUiMode();
2667 
2668         if (hasStatusBar()) {
2669             mStatusBarHeightForRotation[portraitRotation] =
2670                     mStatusBarHeightForRotation[upsideDownRotation] =
2671                             res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
2672             mStatusBarHeightForRotation[landscapeRotation] =
2673                     mStatusBarHeightForRotation[seascapeRotation] =
2674                             res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
2675         } else {
2676             mStatusBarHeightForRotation[portraitRotation] =
2677                     mStatusBarHeightForRotation[upsideDownRotation] =
2678                             mStatusBarHeightForRotation[landscapeRotation] =
2679                                     mStatusBarHeightForRotation[seascapeRotation] = 0;
2680         }
2681 
2682         // Height of the navigation bar when presented horizontally at bottom
2683         mNavigationBarHeightForRotationDefault[portraitRotation] =
2684         mNavigationBarHeightForRotationDefault[upsideDownRotation] =
2685                 res.getDimensionPixelSize(R.dimen.navigation_bar_height);
2686         mNavigationBarHeightForRotationDefault[landscapeRotation] =
2687         mNavigationBarHeightForRotationDefault[seascapeRotation] =
2688                 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
2689 
2690         // Height of the navigation bar frame when presented horizontally at bottom
2691         mNavigationBarFrameHeightForRotationDefault[portraitRotation] =
2692         mNavigationBarFrameHeightForRotationDefault[upsideDownRotation] =
2693                 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
2694         mNavigationBarFrameHeightForRotationDefault[landscapeRotation] =
2695         mNavigationBarFrameHeightForRotationDefault[seascapeRotation] =
2696                 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height_landscape);
2697 
2698         // Width of the navigation bar when presented vertically along one side
2699         mNavigationBarWidthForRotationDefault[portraitRotation] =
2700         mNavigationBarWidthForRotationDefault[upsideDownRotation] =
2701         mNavigationBarWidthForRotationDefault[landscapeRotation] =
2702         mNavigationBarWidthForRotationDefault[seascapeRotation] =
2703                 res.getDimensionPixelSize(R.dimen.navigation_bar_width);
2704 
2705         if (ALTERNATE_CAR_MODE_NAV_SIZE) {
2706             // Height of the navigation bar when presented horizontally at bottom
2707             mNavigationBarHeightForRotationInCarMode[portraitRotation] =
2708             mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
2709                     res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
2710             mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
2711             mNavigationBarHeightForRotationInCarMode[seascapeRotation] =
2712                     res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode);
2713 
2714             // Width of the navigation bar when presented vertically along one side
2715             mNavigationBarWidthForRotationInCarMode[portraitRotation] =
2716             mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
2717             mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
2718             mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
2719                     res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
2720         }
2721 
2722         mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
2723         mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset);
2724         mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
2725         mNavigationBarAlwaysShowOnSideGesture =
2726                 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
2727 
2728         // This should calculate how much above the frame we accept gestures.
2729         mBottomGestureAdditionalInset =
2730                 res.getDimensionPixelSize(R.dimen.navigation_bar_gesture_height)
2731                         - getNavigationBarFrameHeight(portraitRotation, uiMode);
2732 
2733         updateConfigurationAndScreenSizeDependentBehaviors();
2734         mWindowOutsetBottom = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
2735     }
2736 
2737     void updateConfigurationAndScreenSizeDependentBehaviors() {
2738         final Resources res = getCurrentUserResources();
2739         mNavigationBarCanMove =
2740                 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
2741                         && res.getBoolean(R.bool.config_navBarCanMove);
2742         mAllowSeamlessRotationDespiteNavBarMoving =
2743                 res.getBoolean(R.bool.config_allowSeamlessRotationDespiteNavBarMoving);
2744     }
2745 
2746     /**
2747      * Updates the current user's resources to pick up any changes for the current user (including
2748      * overlay paths)
2749      */
2750     private void updateCurrentUserResources() {
2751         final int userId = mService.mAmInternal.getCurrentUserId();
2752         final Context uiContext = getSystemUiContext();
2753 
2754         if (userId == UserHandle.USER_SYSTEM) {
2755             // Skip the (expensive) recreation of resources for the system user below and just
2756             // use the resources from the system ui context
2757             mCurrentUserResources = uiContext.getResources();
2758             return;
2759         }
2760 
2761         // For non-system users, ensure that the resources are loaded from the current
2762         // user's package info (see ContextImpl.createDisplayContext)
2763         final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
2764                 uiContext.getPackageName(), null, 0, userId);
2765         mCurrentUserResources = ResourcesManager.getInstance().getResources(null,
2766                 pi.getResDir(),
2767                 null /* splitResDirs */,
2768                 pi.getOverlayDirs(),
2769                 pi.getApplicationInfo().sharedLibraryFiles,
2770                 mDisplayContent.getDisplayId(),
2771                 null /* overrideConfig */,
2772                 uiContext.getResources().getCompatibilityInfo(),
2773                 null /* classLoader */);
2774     }
2775 
2776     @VisibleForTesting
2777     Resources getCurrentUserResources() {
2778         if (mCurrentUserResources == null) {
2779             updateCurrentUserResources();
2780         }
2781         return mCurrentUserResources;
2782     }
2783 
2784     @VisibleForTesting
2785     Context getContext() {
2786         return mContext;
2787     }
2788 
2789     private Context getSystemUiContext() {
2790         final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
2791         return mDisplayContent.isDefaultDisplay
2792                 ? uiContext : uiContext.createDisplayContext(mDisplayContent.getDisplay());
2793     }
2794 
2795     private int getNavigationBarWidth(int rotation, int uiMode) {
2796         if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2797             return mNavigationBarWidthForRotationInCarMode[rotation];
2798         } else {
2799             return mNavigationBarWidthForRotationDefault[rotation];
2800         }
2801     }
2802 
2803     void notifyDisplayReady() {
2804         mHandler.post(() -> {
2805             final int displayId = getDisplayId();
2806             getStatusBarManagerInternal().onDisplayReady(displayId);
2807             LocalServices.getService(WallpaperManagerInternal.class).onDisplayReady(displayId);
2808         });
2809     }
2810 
2811     /**
2812      * Return the display width available after excluding any screen
2813      * decorations that could never be removed in Honeycomb. That is, system bar or
2814      * button bar.
2815      */
getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, DisplayCutout displayCutout)2816     public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2817             DisplayCutout displayCutout) {
2818         int width = fullWidth;
2819         if (hasNavigationBar()) {
2820             final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2821             if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
2822                 width -= getNavigationBarWidth(rotation, uiMode);
2823             }
2824         }
2825         if (displayCutout != null) {
2826             width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
2827         }
2828         return width;
2829     }
2830 
getNavigationBarHeight(int rotation, int uiMode)2831     private int getNavigationBarHeight(int rotation, int uiMode) {
2832         if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2833             return mNavigationBarHeightForRotationInCarMode[rotation];
2834         } else {
2835             return mNavigationBarHeightForRotationDefault[rotation];
2836         }
2837     }
2838 
2839     /**
2840      * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that
2841      * is used for spacing to show additional buttons on the navigation bar (such as the ime
2842      * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible
2843      * height that we send to the app as content insets that can be smaller.
2844      * <p>
2845      * In car mode it will return the same height as {@link #getNavigationBarHeight}
2846      *
2847      * @param rotation specifies rotation to return dimension from
2848      * @param uiMode to determine if in car mode
2849      * @return navigation bar frame height
2850      */
getNavigationBarFrameHeight(int rotation, int uiMode)2851     private int getNavigationBarFrameHeight(int rotation, int uiMode) {
2852         if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2853             return mNavigationBarHeightForRotationInCarMode[rotation];
2854         } else {
2855             return mNavigationBarFrameHeightForRotationDefault[rotation];
2856         }
2857     }
2858 
2859     /**
2860      * Return the display height available after excluding any screen
2861      * decorations that could never be removed in Honeycomb. That is, system bar or
2862      * button bar.
2863      */
getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, DisplayCutout displayCutout)2864     public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2865             DisplayCutout displayCutout) {
2866         int height = fullHeight;
2867         if (hasNavigationBar()) {
2868             final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2869             if (navBarPosition == NAV_BAR_BOTTOM) {
2870                 height -= getNavigationBarHeight(rotation, uiMode);
2871             }
2872         }
2873         if (displayCutout != null) {
2874             height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
2875         }
2876         return height;
2877     }
2878 
2879     /**
2880      * Return the available screen width that we should report for the
2881      * configuration.  This must be no larger than
2882      * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller
2883      * than that to account for more transient decoration like a status bar.
2884      */
getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, DisplayCutout displayCutout)2885     public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2886             DisplayCutout displayCutout) {
2887         return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout);
2888     }
2889 
2890     /**
2891      * Return the available screen height that we should report for the
2892      * configuration.  This must be no larger than
2893      * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller
2894      * than that to account for more transient decoration like a status bar.
2895      */
getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, DisplayCutout displayCutout)2896     public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2897             DisplayCutout displayCutout) {
2898         // There is a separate status bar at the top of the display.  We don't count that as part
2899         // of the fixed decor, since it can hide; however, for purposes of configurations,
2900         // we do want to exclude it since applications can't generally use that part
2901         // of the screen.
2902         int statusBarHeight = mStatusBarHeightForRotation[rotation];
2903         if (displayCutout != null) {
2904             // If there is a cutout, it may already have accounted for some part of the status
2905             // bar height.
2906             statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
2907         }
2908         return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
2909                 - statusBarHeight;
2910     }
2911 
2912     /**
2913      * Return corner radius in pixels that should be used on windows in order to cover the display.
2914      * The radius is only valid for built-in displays since the one who configures window corner
2915      * radius cannot know the corner radius of non-built-in display.
2916      */
getWindowCornerRadius()2917     float getWindowCornerRadius() {
2918         return mDisplayContent.getDisplay().getType() == TYPE_BUILT_IN
2919                 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f;
2920     }
2921 
isShowingDreamLw()2922     boolean isShowingDreamLw() {
2923         return mShowingDream;
2924     }
2925 
2926     /**
2927      * Calculates the stable insets if we already have the non-decor insets.
2928      *
2929      * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
2930      * @param rotation The current display rotation.
2931      */
convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation)2932     void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
2933         inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
2934     }
2935 
2936     /**
2937      * Calculates the stable insets without running a layout.
2938      *
2939      * @param displayRotation the current display rotation
2940      * @param displayWidth the current display width
2941      * @param displayHeight the current display height
2942      * @param displayCutout the current display cutout
2943      * @param outInsets the insets to return
2944      */
getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight, DisplayCutout displayCutout, Rect outInsets)2945     public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2946             DisplayCutout displayCutout, Rect outInsets) {
2947         outInsets.setEmpty();
2948 
2949         // Navigation bar and status bar.
2950         getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
2951         convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
2952     }
2953 
2954     /**
2955      * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
2956      * bar or button bar. See {@link #getNonDecorDisplayWidth}.
2957      *
2958      * @param displayRotation the current display rotation
2959      * @param displayWidth the current display width
2960      * @param displayHeight the current display height
2961      * @param displayCutout the current display cutout
2962      * @param outInsets the insets to return
2963      */
getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight, DisplayCutout displayCutout, Rect outInsets)2964     public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2965             DisplayCutout displayCutout, Rect outInsets) {
2966         outInsets.setEmpty();
2967 
2968         // Only navigation bar
2969         if (hasNavigationBar()) {
2970             final int uiMode = mService.mPolicy.getUiMode();
2971             int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
2972             if (position == NAV_BAR_BOTTOM) {
2973                 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
2974             } else if (position == NAV_BAR_RIGHT) {
2975                 outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
2976             } else if (position == NAV_BAR_LEFT) {
2977                 outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
2978             }
2979         }
2980 
2981         if (displayCutout != null) {
2982             outInsets.left += displayCutout.getSafeInsetLeft();
2983             outInsets.top += displayCutout.getSafeInsetTop();
2984             outInsets.right += displayCutout.getSafeInsetRight();
2985             outInsets.bottom += displayCutout.getSafeInsetBottom();
2986         }
2987     }
2988 
2989     /**
2990      * @see IWindowManager#setForwardedInsets
2991      */
setForwardedInsets(@onNull Insets forwardedInsets)2992     public void setForwardedInsets(@NonNull Insets forwardedInsets) {
2993         mForwardedInsets = forwardedInsets;
2994     }
2995 
2996     @NonNull
getForwardedInsets()2997     public Insets getForwardedInsets() {
2998         return mForwardedInsets;
2999     }
3000 
3001     @NavigationBarPosition
navigationBarPosition(int displayWidth, int displayHeight, int displayRotation)3002     int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
3003         if (navigationBarCanMove() && displayWidth > displayHeight) {
3004             if (displayRotation == Surface.ROTATION_270) {
3005                 return NAV_BAR_LEFT;
3006             } else if (displayRotation == Surface.ROTATION_90) {
3007                 return NAV_BAR_RIGHT;
3008             }
3009         }
3010         return NAV_BAR_BOTTOM;
3011     }
3012 
3013     /**
3014      * @return The side of the screen where navigation bar is positioned.
3015      * @see WindowManagerPolicyConstants#NAV_BAR_LEFT
3016      * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT
3017      * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM
3018      */
3019     @NavigationBarPosition
getNavBarPosition()3020     public int getNavBarPosition() {
3021         return mNavigationBarPosition;
3022     }
3023 
3024     /**
3025      * A new window has been focused.
3026      */
focusChangedLw(WindowState lastFocus, WindowState newFocus)3027     public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
3028         mFocusedWindow = newFocus;
3029         mLastFocusedWindow = lastFocus;
3030         if (mDisplayContent.isDefaultDisplay) {
3031             mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
3032         }
3033         if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
3034             // If the navigation bar has been hidden or shown, we need to do another
3035             // layout pass to update that window.
3036             return FINISH_LAYOUT_REDO_LAYOUT;
3037         }
3038         return 0;
3039     }
3040 
3041     /**
3042      * Return true if it is okay to perform animations for an app transition
3043      * that is about to occur. You may return false for this if, for example,
3044      * the dream window is currently displayed so the switch should happen
3045      * immediately.
3046      */
allowAppAnimationsLw()3047     public boolean allowAppAnimationsLw() {
3048         return !mShowingDream;
3049     }
3050 
updateDreamingSleepToken(boolean acquire)3051     private void updateDreamingSleepToken(boolean acquire) {
3052         if (acquire) {
3053             final int displayId = getDisplayId();
3054             if (mDreamingSleepToken == null) {
3055                 mDreamingSleepToken = mService.mAtmInternal.acquireSleepToken(
3056                         "DreamOnDisplay" + displayId, displayId);
3057             }
3058         } else {
3059             if (mDreamingSleepToken != null) {
3060                 mDreamingSleepToken.release();
3061                 mDreamingSleepToken = null;
3062             }
3063         }
3064     }
3065 
requestTransientBars(WindowState swipeTarget)3066     private void requestTransientBars(WindowState swipeTarget) {
3067         synchronized (mLock) {
3068             if (!mService.mPolicy.isUserSetupComplete()) {
3069                 // Swipe-up for navigation bar is disabled during setup
3070                 return;
3071             }
3072             boolean sb = mStatusBarController.checkShowTransientBarLw();
3073             boolean nb = mNavigationBarController.checkShowTransientBarLw()
3074                     && !isNavBarEmpty(mLastSystemUiFlags);
3075             if (sb || nb) {
3076                 // Don't show status bar when swiping on already visible navigation bar
3077                 if (!nb && swipeTarget == mNavigationBar) {
3078                     if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
3079                     return;
3080                 }
3081                 if (sb) mStatusBarController.showTransient();
3082                 if (nb) mNavigationBarController.showTransient();
3083                 mImmersiveModeConfirmation.confirmCurrentPrompt();
3084                 updateSystemUiVisibilityLw();
3085             }
3086         }
3087     }
3088 
disposeInputConsumer(InputConsumer inputConsumer)3089     private void disposeInputConsumer(InputConsumer inputConsumer) {
3090         if (inputConsumer != null) {
3091             inputConsumer.dismiss();
3092         }
3093     }
3094 
isStatusBarKeyguard()3095     private boolean isStatusBarKeyguard() {
3096         return mStatusBar != null
3097                 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
3098     }
3099 
isKeyguardOccluded()3100     private boolean isKeyguardOccluded() {
3101         // TODO (b/113840485): Handle per display keyguard.
3102         return mService.mPolicy.isKeyguardOccluded();
3103     }
3104 
resetSystemUiVisibilityLw()3105     void resetSystemUiVisibilityLw() {
3106         mLastSystemUiFlags = 0;
3107         updateSystemUiVisibilityLw();
3108     }
3109 
updateSystemUiVisibilityLw()3110     private int updateSystemUiVisibilityLw() {
3111         // If there is no window focused, there will be nobody to handle the events
3112         // anyway, so just hang on in whatever state we're in until things settle down.
3113         WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
3114                 : mTopFullscreenOpaqueWindowState;
3115         if (winCandidate == null) {
3116             return 0;
3117         }
3118 
3119         // The immersive mode confirmation should never affect the system bar visibility, otherwise
3120         // it will unhide the navigation bar and hide itself.
3121         if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
3122 
3123             // The immersive mode confirmation took the focus from mLastFocusedWindow which was
3124             // controlling the system ui visibility. So if mLastFocusedWindow can still receive
3125             // keys, we let it keep controlling the visibility.
3126             final boolean lastFocusCanReceiveKeys =
3127                     (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
3128             winCandidate = isStatusBarKeyguard() ? mStatusBar
3129                     : lastFocusCanReceiveKeys ? mLastFocusedWindow
3130                             : mTopFullscreenOpaqueWindowState;
3131             if (winCandidate == null) {
3132                 return 0;
3133             }
3134         }
3135         final WindowState win = winCandidate;
3136         if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && isKeyguardOccluded()) {
3137             // We are updating at a point where the keyguard has gotten
3138             // focus, but we were last in a state where the top window is
3139             // hiding it.  This is probably because the keyguard as been
3140             // shown while the top window was displayed, so we want to ignore
3141             // it here because this is just a very transient change and it
3142             // will quickly lose focus once it correctly gets hidden.
3143             return 0;
3144         }
3145 
3146         mDisplayContent.getInsetsStateController().onBarControllingWindowChanged(
3147                 mTopFullscreenOpaqueWindowState);
3148 
3149         int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
3150                 & ~mResettingSystemUiFlags
3151                 & ~mForceClearedSystemUiFlags;
3152         if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
3153             tmpVisibility
3154                     &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
3155         }
3156 
3157         final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
3158                 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
3159         final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
3160                 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
3161         mService.getStackBounds(
3162                 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds);
3163         mService.getStackBounds(
3164                 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
3165         final Pair<Integer, Boolean> result =
3166                 updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
3167         final int visibility = result.first;
3168         final int diff = visibility ^ mLastSystemUiFlags;
3169         final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
3170         final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
3171         final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
3172         if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
3173                 && mFocusedApp == win.getAppToken()
3174                 && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
3175                 && mLastDockedStackBounds.equals(mDockedStackBounds)) {
3176             return 0;
3177         }
3178         mLastSystemUiFlags = visibility;
3179         mLastFullscreenStackSysUiFlags = fullscreenVisibility;
3180         mLastDockedStackSysUiFlags = dockedVisibility;
3181         mLastFocusNeedsMenu = needsMenu;
3182         mFocusedApp = win.getAppToken();
3183         mLastNonDockedStackBounds.set(mNonDockedStackBounds);
3184         mLastDockedStackBounds.set(mDockedStackBounds);
3185         final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
3186         final Rect dockedStackBounds = new Rect(mDockedStackBounds);
3187         final boolean isNavbarColorManagedByIme = result.second;
3188         mHandler.post(() -> {
3189             StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
3190             if (statusBar != null) {
3191                 final int displayId = getDisplayId();
3192                 statusBar.setSystemUiVisibility(displayId, visibility, fullscreenVisibility,
3193                         dockedVisibility, 0xffffffff, fullscreenStackBounds,
3194                         dockedStackBounds, isNavbarColorManagedByIme, win.toString());
3195                 statusBar.topAppWindowChanged(displayId, needsMenu);
3196             }
3197         });
3198         return diff;
3199     }
3200 
updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming)3201     private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
3202         final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded();
3203         final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming;
3204         if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
3205             // If the top fullscreen-or-dimming window is also the top fullscreen, respect
3206             // its light flag.
3207             vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3208             vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
3209                     & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3210         } else if (statusColorWin != null && statusColorWin.isDimming()) {
3211             // Otherwise if it's dimming, clear the light flag.
3212             vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3213         }
3214         return vis;
3215     }
3216 
3217     @VisibleForTesting
3218     @Nullable
chooseNavigationColorWindowLw(WindowState opaque, WindowState opaqueOrDimming, WindowState imeWindow, @NavigationBarPosition int navBarPosition)3219     static WindowState chooseNavigationColorWindowLw(WindowState opaque,
3220             WindowState opaqueOrDimming, WindowState imeWindow,
3221             @NavigationBarPosition int navBarPosition) {
3222         // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
3223         // window can be navigation color window.
3224         final boolean imeWindowCanNavColorWindow = imeWindow != null
3225                 && imeWindow.isVisibleLw()
3226                 && navBarPosition == NAV_BAR_BOTTOM
3227                 && (PolicyControl.getWindowFlags(imeWindow, null)
3228                 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3229 
3230         if (opaque != null && opaqueOrDimming == opaque) {
3231             // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
3232             // unless IME window is also eligible, since currently the IME window is always show
3233             // above the opaque fullscreen app window, regardless of the IME target window.
3234             // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
3235             return imeWindowCanNavColorWindow ? imeWindow : opaque;
3236         }
3237 
3238         if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
3239             // No dimming window is involved. Determine the result only with the IME window.
3240             return imeWindowCanNavColorWindow ? imeWindow : null;
3241         }
3242 
3243         if (!imeWindowCanNavColorWindow) {
3244             // No IME window is involved. Determine the result only with opaqueOrDimming.
3245             return opaqueOrDimming;
3246         }
3247 
3248         // The IME window and the dimming window are competing.  Check if the dimming window can be
3249         // IME target or not.
3250         if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
3251             // The IME window is above the dimming window.
3252             return imeWindow;
3253         } else {
3254             // The dimming window is above the IME window.
3255             return opaqueOrDimming;
3256         }
3257     }
3258 
3259     @VisibleForTesting
updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming, WindowState imeWindow, WindowState navColorWin)3260     static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
3261             WindowState imeWindow, WindowState navColorWin) {
3262 
3263         if (navColorWin != null) {
3264             if (navColorWin == imeWindow || navColorWin == opaque) {
3265                 // Respect the light flag.
3266                 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3267                 vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
3268                         & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3269             } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
3270                 // Clear the light flag for dimming window.
3271                 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3272             }
3273         }
3274         return vis;
3275     }
3276 
updateSystemBarsLw(WindowState win, int oldVis, int vis)3277     private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
3278         final boolean dockedStackVisible =
3279                 mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
3280         final boolean freeformStackVisible =
3281                 mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
3282         final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
3283 
3284         // We need to force system bars when the docked stack is visible, when the freeform stack
3285         // is visible but also when we are resizing for the transitions when docked stack
3286         // visibility changes.
3287         mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing
3288                 || mForceShowSystemBarsFromExternal;
3289         final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
3290 
3291         // apply translucent bar vis flags
3292         WindowState fullscreenTransWin = isStatusBarKeyguard() && !isKeyguardOccluded()
3293                 ? mStatusBar
3294                 : mTopFullscreenOpaqueWindowState;
3295         vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3296         vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3297         int dockedVis = mStatusBarController.applyTranslucentFlagLw(
3298                 mTopDockedOpaqueWindowState, 0, 0);
3299         dockedVis = mNavigationBarController.applyTranslucentFlagLw(
3300                 mTopDockedOpaqueWindowState, dockedVis, 0);
3301 
3302         final boolean fullscreenDrawsStatusBarBackground =
3303                 drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
3304         final boolean dockedDrawsStatusBarBackground =
3305                 drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
3306         final boolean fullscreenDrawsNavBarBackground =
3307                 drawsNavigationBarBackground(vis, mTopFullscreenOpaqueWindowState);
3308         final boolean dockedDrawsNavigationBarBackground =
3309                 drawsNavigationBarBackground(dockedVis, mTopDockedOpaqueWindowState);
3310 
3311         // prevent status bar interaction from clearing certain flags
3312         int type = win.getAttrs().type;
3313         boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
3314         if (statusBarHasFocus && !isStatusBarKeyguard()) {
3315             int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
3316                     | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
3317                     | View.SYSTEM_UI_FLAG_IMMERSIVE
3318                     | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
3319                     | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3320             if (isKeyguardOccluded()) {
3321                 flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
3322             }
3323             vis = (vis & ~flags) | (oldVis & flags);
3324         }
3325 
3326         if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
3327             vis |= View.STATUS_BAR_TRANSPARENT;
3328             vis &= ~View.STATUS_BAR_TRANSLUCENT;
3329         } else if (forceOpaqueStatusBar) {
3330             vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
3331         }
3332 
3333         vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing,
3334                 fullscreenDrawsNavBarBackground, dockedDrawsNavigationBarBackground);
3335 
3336         // update status bar
3337         boolean immersiveSticky =
3338                 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3339         final boolean hideStatusBarWM =
3340                 mTopFullscreenOpaqueWindowState != null
3341                         && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
3342                         & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
3343         final boolean hideStatusBarSysui =
3344                 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
3345         final boolean hideNavBarSysui =
3346                 (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
3347 
3348         final boolean transientStatusBarAllowed = mStatusBar != null
3349                 && (statusBarHasFocus || (!mForceShowSystemBars
3350                 && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
3351 
3352         final boolean transientNavBarAllowed = mNavigationBar != null
3353                 && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
3354 
3355         final long now = SystemClock.uptimeMillis();
3356         final boolean pendingPanic = mPendingPanicGestureUptime != 0
3357                 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
3358         final DisplayPolicy defaultDisplayPolicy =
3359                 mService.getDefaultDisplayContentLocked().getDisplayPolicy();
3360         if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard()
3361                 // TODO (b/111955725): Show keyguard presentation on all external displays
3362                 && defaultDisplayPolicy.isKeyguardDrawComplete()) {
3363             // The user performed the panic gesture recently, we're about to hide the bars,
3364             // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
3365             mPendingPanicGestureUptime = 0;
3366             mStatusBarController.showTransient();
3367             if (!isNavBarEmpty(vis)) {
3368                 mNavigationBarController.showTransient();
3369             }
3370         }
3371 
3372         final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
3373                 && !transientStatusBarAllowed && hideStatusBarSysui;
3374         final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
3375                 && !transientNavBarAllowed;
3376         if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
3377             // clear the clearable flags instead
3378             clearClearableFlagsLw();
3379             vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
3380         }
3381 
3382         final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
3383         immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3384         final boolean navAllowedHidden = immersive || immersiveSticky;
3385 
3386         if (hideNavBarSysui && !navAllowedHidden
3387                 && mService.mPolicy.getWindowLayerLw(win)
3388                         > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
3389             // We can't hide the navbar from this window otherwise the input consumer would not get
3390             // the input events.
3391             vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
3392         }
3393 
3394         vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
3395 
3396         // update navigation bar
3397         boolean oldImmersiveMode = isImmersiveMode(oldVis);
3398         boolean newImmersiveMode = isImmersiveMode(vis);
3399         if (oldImmersiveMode != newImmersiveMode) {
3400             final String pkg = win.getOwningPackage();
3401             mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
3402                     mService.mPolicy.isUserSetupComplete(),
3403                     isNavBarEmpty(win.getSystemUiVisibility()));
3404         }
3405 
3406         vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
3407 
3408         final WindowState navColorWin = chooseNavigationColorWindowLw(
3409                 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
3410                 mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
3411         vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
3412                 mTopFullscreenOpaqueOrDimmingWindowState,
3413                 mDisplayContent.mInputMethodWindow, navColorWin);
3414         // Navbar color is controlled by the IME.
3415         final boolean isManagedByIme =
3416                 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
3417 
3418         return Pair.create(vis, isManagedByIme);
3419     }
3420 
drawsBarBackground(int vis, WindowState win, BarController controller, int translucentFlag)3421     private boolean drawsBarBackground(int vis, WindowState win, BarController controller,
3422             int translucentFlag) {
3423         if (!controller.isTransparentAllowed(win)) {
3424             return false;
3425         }
3426         if (win == null) {
3427             return true;
3428         }
3429 
3430         final boolean drawsSystemBars =
3431                 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3432         final boolean forceDrawsSystemBars =
3433                 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
3434 
3435         return forceDrawsSystemBars || drawsSystemBars && (vis & translucentFlag) == 0;
3436     }
3437 
drawsStatusBarBackground(int vis, WindowState win)3438     private boolean drawsStatusBarBackground(int vis, WindowState win) {
3439         return drawsBarBackground(vis, win, mStatusBarController, FLAG_TRANSLUCENT_STATUS);
3440     }
3441 
drawsNavigationBarBackground(int vis, WindowState win)3442     private boolean drawsNavigationBarBackground(int vis, WindowState win) {
3443         return drawsBarBackground(vis, win, mNavigationBarController, FLAG_TRANSLUCENT_NAVIGATION);
3444     }
3445 
3446     /**
3447      * @return the current visibility flags with the nav-bar opacity related flags toggled based
3448      *         on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
3449      */
configureNavBarOpacity(int visibility, boolean dockedStackVisible, boolean freeformStackVisible, boolean isDockedDividerResizing, boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground)3450     private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
3451             boolean freeformStackVisible, boolean isDockedDividerResizing,
3452             boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground) {
3453         if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
3454             if (fullscreenDrawsBackground && dockedDrawsNavigationBarBackground) {
3455                 visibility = setNavBarTransparentFlag(visibility);
3456             } else if (dockedStackVisible) {
3457                 visibility = setNavBarOpaqueFlag(visibility);
3458             }
3459         } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
3460             if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
3461                 visibility = setNavBarOpaqueFlag(visibility);
3462             } else if (fullscreenDrawsBackground) {
3463                 visibility = setNavBarTransparentFlag(visibility);
3464             }
3465         } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
3466             if (isDockedDividerResizing) {
3467                 visibility = setNavBarOpaqueFlag(visibility);
3468             } else if (freeformStackVisible) {
3469                 visibility = setNavBarTranslucentFlag(visibility);
3470             } else {
3471                 visibility = setNavBarOpaqueFlag(visibility);
3472             }
3473         }
3474 
3475         return visibility;
3476     }
3477 
setNavBarOpaqueFlag(int visibility)3478     private int setNavBarOpaqueFlag(int visibility) {
3479         return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
3480     }
3481 
setNavBarTranslucentFlag(int visibility)3482     private int setNavBarTranslucentFlag(int visibility) {
3483         visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
3484         return visibility | View.NAVIGATION_BAR_TRANSLUCENT;
3485     }
3486 
setNavBarTransparentFlag(int visibility)3487     private int setNavBarTransparentFlag(int visibility) {
3488         visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
3489         return visibility | View.NAVIGATION_BAR_TRANSPARENT;
3490     }
3491 
clearClearableFlagsLw()3492     private void clearClearableFlagsLw() {
3493         int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
3494         if (newVal != mResettingSystemUiFlags) {
3495             mResettingSystemUiFlags = newVal;
3496             mDisplayContent.reevaluateStatusBarVisibility();
3497         }
3498     }
3499 
isImmersiveMode(int vis)3500     private boolean isImmersiveMode(int vis) {
3501         final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
3502         return mNavigationBar != null
3503                 && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
3504                 && (vis & flags) != 0
3505                 && canHideNavigationBar();
3506     }
3507 
3508     /**
3509      * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
3510      */
canHideNavigationBar()3511     private boolean canHideNavigationBar() {
3512         return hasNavigationBar();
3513     }
3514 
isNavBarEmpty(int systemUiFlags)3515     private static boolean isNavBarEmpty(int systemUiFlags) {
3516         final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
3517                 | View.STATUS_BAR_DISABLE_BACK
3518                 | View.STATUS_BAR_DISABLE_RECENT);
3519 
3520         return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
3521     }
3522 
shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation, int newRotation)3523     boolean shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation,
3524             int newRotation) {
3525         // For the upside down rotation we don't rotate seamlessly as the navigation
3526         // bar moves position.
3527         // Note most apps (using orientation:sensor or user as opposed to fullSensor)
3528         // will not enter the reverse portrait orientation, so actually the
3529         // orientation won't change at all.
3530         if (oldRotation == displayRotation.getUpsideDownRotation()
3531                 || newRotation == displayRotation.getUpsideDownRotation()) {
3532             return false;
3533         }
3534         // If the navigation bar can't change sides, then it will
3535         // jump when we change orientations and we don't rotate
3536         // seamlessly - unless that is allowed, eg. with gesture
3537         // navigation where the navbar is low-profile enough that this isn't very noticeable.
3538         if (!navigationBarCanMove() && !mAllowSeamlessRotationDespiteNavBarMoving) {
3539             return false;
3540         }
3541 
3542         final WindowState w = mTopFullscreenOpaqueWindowState;
3543         if (w == null || w != mFocusedWindow) {
3544             return false;
3545         }
3546         // If the bounds of activity window is different from its parent, then reject to be seamless
3547         // because the window position may change after rotation that will look like a sudden jump.
3548         if (w.mAppToken != null && !w.mAppToken.matchParentBounds()) {
3549             return false;
3550         }
3551 
3552         // We only enable seamless rotation if the top window has requested
3553         // it and is in the fullscreen opaque state. Seamless rotation
3554         // requires freezing various Surface states and won't work well
3555         // with animations, so we disable it in the animation case for now.
3556         if (!w.isAnimatingLw() && w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS) {
3557             return true;
3558         }
3559         return false;
3560     }
3561 
3562     private final Runnable mHiddenNavPanic = new Runnable() {
3563         @Override
3564         public void run() {
3565             synchronized (mLock) {
3566                 if (!mService.mPolicy.isUserSetupComplete()) {
3567                     // Swipe-up for navigation bar is disabled during setup
3568                     return;
3569                 }
3570                 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
3571                 if (!isNavBarEmpty(mLastSystemUiFlags)) {
3572                     mNavigationBarController.showTransient();
3573                 }
3574             }
3575         }
3576     };
3577 
onPowerKeyDown(boolean isScreenOn)3578     void onPowerKeyDown(boolean isScreenOn) {
3579         // Detect user pressing the power button in panic when an application has
3580         // taken over the whole screen.
3581         boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
3582                 SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
3583                 isNavBarEmpty(mLastSystemUiFlags));
3584         if (panic) {
3585             mHandler.post(mHiddenNavPanic);
3586         }
3587     }
3588 
onVrStateChangedLw(boolean enabled)3589     void onVrStateChangedLw(boolean enabled) {
3590         mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
3591     }
3592 
3593     /**
3594      * Called when the state of lock task mode changes. This should be used to disable immersive
3595      * mode confirmation.
3596      *
3597      * @param lockTaskState the new lock task mode state. One of
3598      *                      {@link ActivityManager#LOCK_TASK_MODE_NONE},
3599      *                      {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
3600      *                      {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
3601      */
onLockTaskStateChangedLw(int lockTaskState)3602     public void onLockTaskStateChangedLw(int lockTaskState) {
3603         mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
3604     }
3605 
3606     /**
3607      * Request a screenshot be taken.
3608      *
3609      * @param screenshotType The type of screenshot, for example either
3610      *                       {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
3611      *                       {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
3612      */
takeScreenshot(int screenshotType)3613     public void takeScreenshot(int screenshotType) {
3614         if (mScreenshotHelper != null) {
3615             mScreenshotHelper.takeScreenshot(screenshotType,
3616                     mStatusBar != null && mStatusBar.isVisibleLw(),
3617                     mNavigationBar != null && mNavigationBar.isVisibleLw(), mHandler);
3618         }
3619     }
3620 
getRefreshRatePolicy()3621     RefreshRatePolicy getRefreshRatePolicy() {
3622         return mRefreshRatePolicy;
3623     }
3624 
dump(String prefix, PrintWriter pw)3625     void dump(String prefix, PrintWriter pw) {
3626         pw.print(prefix); pw.print("DisplayPolicy");
3627         prefix += "  ";
3628         pw.print(prefix);
3629         pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
3630         pw.print(" mDeskDockEnablesAccelerometer=");
3631         pw.println(mDeskDockEnablesAccelerometer);
3632         pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
3633         pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
3634         pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
3635         pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
3636         pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
3637         pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
3638         pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
3639         pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
3640         if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
3641                 || mForceClearedSystemUiFlags != 0) {
3642             pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
3643             pw.print(Integer.toHexString(mLastSystemUiFlags));
3644             pw.print(" mResettingSystemUiFlags=0x");
3645             pw.print(Integer.toHexString(mResettingSystemUiFlags));
3646             pw.print(" mForceClearedSystemUiFlags=0x");
3647             pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
3648         }
3649         if (mLastFocusNeedsMenu) {
3650             pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu);
3651         }
3652         pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
3653         pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
3654         pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
3655         if (mStatusBar != null) {
3656             pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
3657                     pw.print(" isStatusBarKeyguard="); pw.println(isStatusBarKeyguard());
3658         }
3659         if (mNavigationBar != null) {
3660             pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
3661             pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
3662             pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove);
3663             pw.print(prefix); pw.print("mNavigationBarPosition=");
3664             pw.println(mNavigationBarPosition);
3665         }
3666         if (mFocusedWindow != null) {
3667             pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
3668         }
3669         if (mFocusedApp != null) {
3670             pw.print(prefix); pw.print("mFocusedApp="); pw.println(mFocusedApp);
3671         }
3672         if (mTopFullscreenOpaqueWindowState != null) {
3673             pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
3674             pw.println(mTopFullscreenOpaqueWindowState);
3675         }
3676         if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
3677             pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
3678             pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
3679         }
3680         if (mForcingShowNavBar) {
3681             pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar);
3682             pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
3683             pw.println(mForcingShowNavBarLayer);
3684         }
3685         pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
3686         pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
3687         pw.print(" mForceStatusBarFromKeyguard="); pw.println(mForceStatusBarFromKeyguard);
3688         pw.print(" mForceShowSystemBarsFromExternal=");
3689         pw.println(mForceShowSystemBarsFromExternal);
3690         pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
3691         mStatusBarController.dump(pw, prefix);
3692         mNavigationBarController.dump(pw, prefix);
3693 
3694         pw.print(prefix); pw.println("Looper state:");
3695         mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + "  ");
3696     }
3697 
supportsPointerLocation()3698     private boolean supportsPointerLocation() {
3699         return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate();
3700     }
3701 
setPointerLocationEnabled(boolean pointerLocationEnabled)3702     void setPointerLocationEnabled(boolean pointerLocationEnabled) {
3703         if (!supportsPointerLocation()) {
3704             return;
3705         }
3706 
3707         mHandler.sendEmptyMessage(pointerLocationEnabled
3708                 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
3709     }
3710 
enablePointerLocation()3711     private void enablePointerLocation() {
3712         if (mPointerLocationView != null) {
3713             return;
3714         }
3715 
3716         mPointerLocationView = new PointerLocationView(mContext);
3717         mPointerLocationView.setPrintCoords(false);
3718         final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
3719                 WindowManager.LayoutParams.MATCH_PARENT,
3720                 WindowManager.LayoutParams.MATCH_PARENT);
3721         lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
3722         lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
3723                 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
3724                 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
3725                 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
3726         lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3727         if (ActivityManager.isHighEndGfx()) {
3728             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
3729             lp.privateFlags |=
3730                     WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
3731         }
3732         lp.format = PixelFormat.TRANSLUCENT;
3733         lp.setTitle("PointerLocation - display " + getDisplayId());
3734         lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
3735         final WindowManager wm = mContext.getSystemService(WindowManager.class);
3736         wm.addView(mPointerLocationView, lp);
3737         mDisplayContent.registerPointerEventListener(mPointerLocationView);
3738     }
3739 
disablePointerLocation()3740     private void disablePointerLocation() {
3741         if (mPointerLocationView == null) {
3742             return;
3743         }
3744 
3745         mDisplayContent.unregisterPointerEventListener(mPointerLocationView);
3746         final WindowManager wm = mContext.getSystemService(WindowManager.class);
3747         wm.removeView(mPointerLocationView);
3748         mPointerLocationView = null;
3749     }
3750 }
3751