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