2 * Copyright (C) 2018 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.wm;
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;
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;
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;
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;
180 import java.io.PrintWriter;
183 * The policy that provides the basic behaviors and states of a display to show UI.
185 public class DisplayPolicy {
186 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM;
187 private static final boolean DEBUG = false;
189 private static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false;
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;
195 // Controls navigation bar opacity depending on which workspace stacks are currently
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;
205 * These are the system UI flags that, when changing, can cause the layout
206 * of the screen to change.
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;
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;
222 private Resources mCurrentUserResources;
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;
230 private final Object mServiceAcquireLock = new Object();
231 private StatusBarManagerInternal mStatusBarManagerInternal;
234 private int mBottomGestureAdditionalInset;
236 private int mSideGestureInset;
238 private StatusBarManagerInternal getStatusBarManagerInternal() {
239 synchronized (mServiceAcquireLock) {
240 if (mStatusBarManagerInternal == null) {
241 mStatusBarManagerInternal =
242 LocalServices.getService(StatusBarManagerInternal.class);
244 return mStatusBarManagerInternal;
248 private final SystemGesturesPointerEventListener mSystemGestures;
250 private volatile int mLidState = LID_ABSENT;
251 private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED;
252 private volatile boolean mHdmiPlugged;
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;
262 // Written by vr manager thread, only read in this class.
263 private volatile boolean mPersistentVrModeEnabled;
265 private volatile boolean mAwake;
266 private volatile boolean mScreenOnEarly;
267 private volatile boolean mScreenOnFully;
268 private volatile ScreenOnListener mScreenOnListener;
270 private volatile boolean mKeyguardDrawComplete;
271 private volatile boolean mWindowManagerDrawComplete;
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];
284 /** See {@link #getNavigationBarFrameHeight} */
285 private int[] mNavigationBarFrameHeightForRotationDefault = new int[4];
287 /** Cached value of {@link ScreenShapeHelper#getWindowOutsetBottomPx} */
288 @Px private int mWindowOutsetBottom;
290 private final StatusBarController mStatusBarController;
292 private final BarController mNavigationBarController;
294 private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener =
295 new BarController.OnBarVisibilityChangedListener() {
297 public void onBarVisibilityChanged(boolean visible) {
298 if (mAccessibilityManager == null) {
301 mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible);
305 @GuardedBy("mHandler")
306 private SleepToken mDreamingSleepToken;
308 @GuardedBy("mHandler")
309 private SleepToken mWindowSleepToken;
311 private final Runnable mAcquireSleepTokenRunnable;
312 private final Runnable mReleaseSleepTokenRunnable;
314 // The windows we were told about in focusChanged.
315 private WindowState mFocusedWindow;
316 private WindowState mLastFocusedWindow;
318 IApplicationToken mFocusedApp;
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();
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;
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();
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;
360 * Force the display of system bars regardless of other settings.
362 private boolean mForceShowSystemBarsFromExternal;
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;
372 private InputConsumer mInputConsumer = null;
374 private PointerLocationView mPointerLocationView;
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.
384 @NonNull private Insets mForwardedInsets = Insets.NONE;
386 private RefreshRatePolicy mRefreshRatePolicy;
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;
395 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
396 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
398 private class PolicyHandler extends Handler {
400 PolicyHandler(Looper looper) {
405 public void handleMessage(Message msg) {
407 case MSG_UPDATE_DREAMING_SLEEP_TOKEN:
408 updateDreamingSleepToken(msg.arg1 != 0);
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);
417 case MSG_DISPOSE_INPUT_CONSUMER:
418 disposeInputConsumer((InputConsumer) msg.obj);
420 case MSG_ENABLE_POINTER_LOCATION:
421 enablePointerLocation();
423 case MSG_DISABLE_POINTER_LOCATION:
424 disablePointerLocation();
430 DisplayPolicy(WindowManagerService service, DisplayContent displayContent) {
432 mContext = displayContent.isDefaultDisplay ? service.mContext
433 : service.mContext.createDisplayContext(displayContent.getDisplay());
434 mDisplayContent = displayContent;
435 mLock = service.getWindowManagerLock();
437 final int displayId = displayContent.getDisplayId();
438 mStatusBarController = new StatusBarController(displayId);
439 mNavigationBarController = new BarController("NavigationBar",
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);
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);
453 mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
454 Context.ACCESSIBILITY_SERVICE);
455 if (!displayContent.isDefaultDisplay) {
457 mScreenOnEarly = true;
458 mScreenOnFully = true;
461 final Looper looper = UiThread.getHandler().getLooper();
462 mHandler = new PolicyHandler(looper);
463 mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
464 new SystemGesturesPointerEventListener.Callbacks() {
466 public void onSwipeFromTop() {
467 if (mStatusBar != null) {
468 requestTransientBars(mStatusBar);
473 public void onSwipeFromBottom() {
474 if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
475 requestTransientBars(mNavigationBar);
480 public void onSwipeFromRight() {
481 final Region excludedRegion = Region.obtain();
482 synchronized (mLock) {
483 mDisplayContent.calculateSystemGestureExclusion(
484 excludedRegion, null /* outUnrestricted */);
486 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
487 || mNavigationBarPosition == NAV_BAR_RIGHT;
488 if (mNavigationBar != null && sideAllowed
489 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
490 requestTransientBars(mNavigationBar);
492 excludedRegion.recycle();
496 public void onSwipeFromLeft() {
497 final Region excludedRegion = Region.obtain();
498 synchronized (mLock) {
499 mDisplayContent.calculateSystemGestureExclusion(
500 excludedRegion, null /* outUnrestricted */);
502 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
503 || mNavigationBarPosition == NAV_BAR_LEFT;
504 if (mNavigationBar != null && sideAllowed
505 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
506 requestTransientBars(mNavigationBar);
508 excludedRegion.recycle();
512 public void onFling(int duration) {
513 if (mService.mPowerManagerInternal != null) {
514 mService.mPowerManagerInternal.powerHint(
515 PowerHint.INTERACTION, duration);
520 public void onDebug() {
524 private WindowOrientationListener getOrientationListener() {
525 final DisplayRotation rotation = mDisplayContent.getDisplayRotation();
526 return rotation != null ? rotation.getOrientationListener() : null;
530 public void onDown() {
531 final WindowOrientationListener listener = getOrientationListener();
532 if (listener != null) {
533 listener.onTouchStart();
538 public void onUpOrCancel() {
539 final WindowOrientationListener listener = getOrientationListener();
540 if (listener != null) {
541 listener.onTouchEnd();
546 public void onMouseHoverAtTop() {
547 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
548 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
549 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS;
550 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
554 public void onMouseHoverAtBottom() {
555 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
556 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS);
557 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION;
558 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */);
562 public void onMouseLeaveFromEdge() {
563 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS);
566 displayContent.registerPointerEventListener(mSystemGestures);
567 displayContent.mAppTransition.registerListenerLocked(
568 mStatusBarController.getAppTransitionListener());
569 mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper,
570 mService.mVrModeEnabled);
571 mAcquireSleepTokenRunnable = () -> {
572 if (mWindowSleepToken != null) {
575 mWindowSleepToken = service.mAtmInternal.acquireSleepToken(
576 "WindowSleepTokenOnDisplay" + displayId, displayId);
578 mReleaseSleepTokenRunnable = () -> {
579 if (mWindowSleepToken == null) {
582 mWindowSleepToken.release();
583 mWindowSleepToken = null;
586 // TODO: Make it can take screenshot on external display
587 mScreenshotHelper = displayContent.isDefaultDisplay
588 ? new ScreenshotHelper(mContext) : null;
590 if (mDisplayContent.isDefaultDisplay) {
591 mHasStatusBar = true;
592 mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar);
594 // Allow a system property to override this. Used by the emulator.
595 // See also hasNavigationBar().
596 String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");
597 if ("1".equals(navBarOverride)) {
598 mHasNavigationBar = false;
599 } else if ("0".equals(navBarOverride)) {
600 mHasNavigationBar = true;
603 mHasStatusBar = false;
604 mHasNavigationBar = mDisplayContent.supportsSystemDecorations();
607 mRefreshRatePolicy = new RefreshRatePolicy(mService,
608 mDisplayContent.getDisplayInfo(),
609 mService.mHighRefreshRateBlacklist);
613 mSystemGestures.systemReady();
614 if (mService.mPointerLocationEnabled) {
615 setPointerLocationEnabled(true);
619 private int getDisplayId() {
620 return mDisplayContent.getDisplayId();
623 public void setHdmiPlugged(boolean plugged) {
624 setHdmiPlugged(plugged, false /* force */);
627 public void setHdmiPlugged(boolean plugged, boolean force) {
628 if (force || mHdmiPlugged != plugged) {
629 mHdmiPlugged = plugged;
630 mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */);
631 final Intent intent = new Intent(ACTION_HDMI_PLUGGED);
632 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
633 intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged);
634 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
638 boolean isHdmiPlugged() {
642 boolean isCarDockEnablesAccelerometer() {
643 return mCarDockEnablesAccelerometer;
646 boolean isDeskDockEnablesAccelerometer() {
647 return mDeskDockEnablesAccelerometer;
650 public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) {
651 mPersistentVrModeEnabled = persistentVrModeEnabled;
654 public boolean isPersistentVrModeEnabled() {
655 return mPersistentVrModeEnabled;
658 public void setDockMode(int dockMode) {
659 mDockMode = dockMode;
662 public int getDockMode() {
667 * @see WindowManagerService.setForceShowSystemBars
669 void setForceShowSystemBars(boolean forceShowSystemBars) {
670 mForceShowSystemBarsFromExternal = forceShowSystemBars;
673 public boolean hasNavigationBar() {
674 return mHasNavigationBar;
677 public boolean hasStatusBar() {
678 return mHasStatusBar;
681 boolean hasSideGestures() {
682 return mHasNavigationBar && mSideGestureInset > 0;
685 public boolean navigationBarCanMove() {
686 return mNavigationBarCanMove;
689 public void setLidState(int lidState) {
690 mLidState = lidState;
693 public int getLidState() {
697 public void setAwake(boolean awake) {
701 public boolean isAwake() {
705 public boolean isScreenOnEarly() {
706 return mScreenOnEarly;
709 public boolean isScreenOnFully() {
710 return mScreenOnFully;
713 public boolean isKeyguardDrawComplete() {
714 return mKeyguardDrawComplete;
717 public boolean isWindowManagerDrawComplete() {
718 return mWindowManagerDrawComplete;
721 public ScreenOnListener getScreenOnListener() {
722 return mScreenOnListener;
725 public void screenTurnedOn(ScreenOnListener screenOnListener) {
726 synchronized (mLock) {
727 mScreenOnEarly = true;
728 mScreenOnFully = false;
729 mKeyguardDrawComplete = false;
730 mWindowManagerDrawComplete = false;
731 mScreenOnListener = screenOnListener;
735 public void screenTurnedOff() {
736 synchronized (mLock) {
737 mScreenOnEarly = false;
738 mScreenOnFully = false;
739 mKeyguardDrawComplete = false;
740 mWindowManagerDrawComplete = false;
741 mScreenOnListener = null;
745 /** Return false if we are not awake yet or we have already informed of this event. */
746 public boolean finishKeyguardDrawn() {
747 synchronized (mLock) {
748 if (!mScreenOnEarly || mKeyguardDrawComplete) {
752 mKeyguardDrawComplete = true;
753 mWindowManagerDrawComplete = false;
758 /** Return false if screen is not turned on or we did already handle this case earlier. */
759 public boolean finishWindowsDrawn() {
760 synchronized (mLock) {
761 if (!mScreenOnEarly || mWindowManagerDrawComplete) {
765 mWindowManagerDrawComplete = true;
770 /** Return false if it is not ready to turn on. */
771 public boolean finishScreenTurningOn() {
772 synchronized (mLock) {
773 if (DEBUG_SCREEN_ON) Slog.d(TAG,
774 "finishScreenTurningOn: mAwake=" + mAwake
775 + ", mScreenOnEarly=" + mScreenOnEarly
776 + ", mScreenOnFully=" + mScreenOnFully
777 + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
778 + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
780 if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete
781 || (mAwake && !mKeyguardDrawComplete)) {
785 if (DEBUG_SCREEN_ON) Slog.i(TAG, "Finished screen turning on...");
786 mScreenOnListener = null;
787 mScreenOnFully = true;
792 private boolean hasStatusBarServicePermission(int pid, int uid) {
793 return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid)
794 == PackageManager.PERMISSION_GRANTED;
798 * Sanitize the layout parameters coming from a client. Allows the policy
799 * to do things like ensure that windows of a specific type can't take
802 * @param attrs The window layout parameters to be modified. These values
803 * are modified in-place.
805 public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
806 int callingPid, int callingUid) {
808 final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
809 if (mScreenDecorWindows.contains(win)) {
810 if (!isScreenDecor) {
811 // No longer has the flag set, so remove from the set.
812 mScreenDecorWindows.remove(win);
814 } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) {
815 mScreenDecorWindows.add(win);
818 switch (attrs.type) {
819 case TYPE_SYSTEM_OVERLAY:
820 case TYPE_SECURE_SYSTEM_OVERLAY:
821 // These types of windows can't receive input events.
822 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
823 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
824 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
828 // Dreams and wallpapers don't have an app window token and can thus not be
829 // letterboxed. Hence always let them extend under the cutout.
830 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
832 case TYPE_STATUS_BAR:
834 // If the Keyguard is in a hidden state (occluded by another window), we force to
835 // remove the wallpaper and keyguard flag so that any change in-flight after setting
836 // the keyguard as occluded wouldn't set these flags again.
837 // See {@link #processKeyguardSetHiddenResultLw}.
838 if (mService.mPolicy.isKeyguardOccluded()) {
839 attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
840 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
844 case TYPE_SCREENSHOT:
845 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
849 // While apps should use the dedicated toast APIs to add such windows
850 // it possible legacy apps to add the window directly. Therefore, we
851 // make windows added directly by the app behave as a toast as much
852 // as possible in terms of timeout and animation.
853 if (attrs.hideTimeoutMilliseconds < 0
854 || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) {
855 attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT;
857 // Accessibility users may need longer timeout duration. This api compares
858 // original timeout with user's preference and return longer one. It returns
859 // original timeout if there's no preference.
860 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis(
861 (int) attrs.hideTimeoutMilliseconds,
862 AccessibilityManager.FLAG_CONTENT_TEXT);
863 attrs.windowAnimations = com.android.internal.R.style.Animation_Toast;
864 // Toast can show with below conditions when the screen is locked.
865 if (canToastShowWhenLocked(callingPid)) {
866 attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
868 // Toasts can't be clickable
869 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
873 if (attrs.type != TYPE_STATUS_BAR) {
874 // The status bar is the only window allowed to exhibit keyguard behavior.
875 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
880 * @return {@code true} if the calling activity initiate toast and is visible with
881 * {@link WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} flag.
883 boolean canToastShowWhenLocked(int callingPid) {
884 return mDisplayContent.forAllWindows(w -> {
885 return callingPid == w.mSession.mPid && w.isVisible() && w.canShowWhenLocked();
886 }, true /* traverseTopToBottom */);
890 * Preflight adding a window to the system.
892 * Currently enforces that three window types are singletons per display:
894 * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li>
895 * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li>
898 * @param win The window to be added
899 * @param attrs Information about the window to be added
901 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,
902 * WindowManagerImpl.ADD_MULTIPLE_SINGLETON
904 public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
906 if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
907 mContext.enforceCallingOrSelfPermission(
908 android.Manifest.permission.STATUS_BAR_SERVICE,
910 mScreenDecorWindows.add(win);
913 switch (attrs.type) {
914 case TYPE_STATUS_BAR:
915 mContext.enforceCallingOrSelfPermission(
916 android.Manifest.permission.STATUS_BAR_SERVICE,
918 if (mStatusBar != null) {
919 if (mStatusBar.isAlive()) {
920 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
924 mStatusBarController.setWindow(win);
925 if (mDisplayContent.isDefaultDisplay) {
926 mService.mPolicy.setKeyguardCandidateLw(win);
928 final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider =
929 (displayFrames, windowState, rect) -> {
931 rect.bottom = getStatusBarHeight(displayFrames);
933 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, win, frameProvider);
934 mDisplayContent.setInsetProvider(TYPE_TOP_GESTURES, win, frameProvider);
935 mDisplayContent.setInsetProvider(TYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider);
937 case TYPE_NAVIGATION_BAR:
938 mContext.enforceCallingOrSelfPermission(
939 android.Manifest.permission.STATUS_BAR_SERVICE,
941 if (mNavigationBar != null) {
942 if (mNavigationBar.isAlive()) {
943 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
946 mNavigationBar = win;
947 mNavigationBarController.setWindow(win);
948 mNavigationBarController.setOnBarVisibilityChangedListener(
949 mNavBarVisibilityListener, true);
950 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR,
951 win, null /* frameProvider */);
952 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_GESTURES, win,
953 (displayFrames, windowState, inOutFrame) -> {
954 inOutFrame.top -= mBottomGestureAdditionalInset;
956 mDisplayContent.setInsetProvider(InsetsState.TYPE_LEFT_GESTURES, win,
957 (displayFrames, windowState, inOutFrame) -> {
960 inOutFrame.bottom = displayFrames.mDisplayHeight;
961 inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset;
963 mDisplayContent.setInsetProvider(InsetsState.TYPE_RIGHT_GESTURES, win,
964 (displayFrames, windowState, inOutFrame) -> {
965 inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset;
967 inOutFrame.bottom = displayFrames.mDisplayHeight;
968 inOutFrame.right = displayFrames.mDisplayWidth;
970 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_TAPPABLE_ELEMENT, win,
971 (displayFrames, windowState, inOutFrame) -> {
972 if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0
973 || mNavigationBarLetsThroughTaps) {
974 inOutFrame.setEmpty();
977 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);
979 case TYPE_NAVIGATION_BAR_PANEL:
980 case TYPE_STATUS_BAR_PANEL:
981 case TYPE_STATUS_BAR_SUB_PANEL:
982 case TYPE_VOICE_INTERACTION_STARTING:
983 mContext.enforceCallingOrSelfPermission(
984 android.Manifest.permission.STATUS_BAR_SERVICE,
992 * Called when a window is being removed from a window manager. Must not
993 * throw an exception -- clean up as much as possible.
995 * @param win The window being removed.
997 public void removeWindowLw(WindowState win) {
998 if (mStatusBar == win) {
1000 mStatusBarController.setWindow(null);
1001 if (mDisplayContent.isDefaultDisplay) {
1002 mService.mPolicy.setKeyguardCandidateLw(null);
1004 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, null, null);
1005 } else if (mNavigationBar == win) {
1006 mNavigationBar = null;
1007 mNavigationBarController.setWindow(null);
1008 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR, null, null);
1010 if (mLastFocusedWindow == win) {
1011 mLastFocusedWindow = null;
1013 mScreenDecorWindows.remove(win);
1016 private int getStatusBarHeight(DisplayFrames displayFrames) {
1017 return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation],
1018 displayFrames.mDisplayCutoutSafe.top);
1022 * Control the animation to run when a window's state changes. Return a
1023 * non-0 number to force the animation to a specific resource ID, or 0
1024 * to use the default animation.
1026 * @param win The window that is changing.
1027 * @param transit What is happening to the window:
1028 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER},
1029 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT},
1030 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or
1031 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}.
1033 * @return Resource ID of the actual animation to use, or 0 for none.
1035 public int selectAnimationLw(WindowState win, int transit) {
1036 if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win
1037 + ": transit=" + transit);
1038 if (win == mStatusBar) {
1039 final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
1040 final boolean expanded = win.getAttrs().height == MATCH_PARENT
1041 && win.getAttrs().width == MATCH_PARENT;
1042 if (isKeyguard || expanded) {
1045 if (transit == TRANSIT_EXIT
1046 || transit == TRANSIT_HIDE) {
1047 return R.anim.dock_top_exit;
1048 } else if (transit == TRANSIT_ENTER
1049 || transit == TRANSIT_SHOW) {
1050 return R.anim.dock_top_enter;
1052 } else if (win == mNavigationBar) {
1053 if (win.getAttrs().windowAnimations != 0) {
1056 // This can be on either the bottom or the right or the left.
1057 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1058 if (transit == TRANSIT_EXIT
1059 || transit == TRANSIT_HIDE) {
1060 if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) {
1061 return R.anim.dock_bottom_exit_keyguard;
1063 return R.anim.dock_bottom_exit;
1065 } else if (transit == TRANSIT_ENTER
1066 || transit == TRANSIT_SHOW) {
1067 return R.anim.dock_bottom_enter;
1069 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1070 if (transit == TRANSIT_EXIT
1071 || transit == TRANSIT_HIDE) {
1072 return R.anim.dock_right_exit;
1073 } else if (transit == TRANSIT_ENTER
1074 || transit == TRANSIT_SHOW) {
1075 return R.anim.dock_right_enter;
1077 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1078 if (transit == TRANSIT_EXIT
1079 || transit == TRANSIT_HIDE) {
1080 return R.anim.dock_left_exit;
1081 } else if (transit == TRANSIT_ENTER
1082 || transit == TRANSIT_SHOW) {
1083 return R.anim.dock_left_enter;
1086 } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) {
1087 return selectDockedDividerAnimationLw(win, transit);
1090 if (transit == TRANSIT_PREVIEW_DONE) {
1091 if (win.hasAppShownWindows()) {
1092 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT");
1093 return R.anim.app_starting_exit;
1095 } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen
1096 && transit == TRANSIT_ENTER) {
1097 // Special case: we are animating in a dream, while the keyguard
1098 // is shown. We don't want an animation on the dream, because
1099 // we need it shown immediately with the keyguard animating away
1107 private int selectDockedDividerAnimationLw(WindowState win, int transit) {
1108 int insets = mDisplayContent.getDockedDividerController().getContentInsets();
1110 // If the divider is behind the navigation bar, don't animate.
1111 final Rect frame = win.getFrameLw();
1112 final boolean behindNavBar = mNavigationBar != null
1113 && ((mNavigationBarPosition == NAV_BAR_BOTTOM
1114 && frame.top + insets >= mNavigationBar.getFrameLw().top)
1115 || (mNavigationBarPosition == NAV_BAR_RIGHT
1116 && frame.left + insets >= mNavigationBar.getFrameLw().left)
1117 || (mNavigationBarPosition == NAV_BAR_LEFT
1118 && frame.right - insets <= mNavigationBar.getFrameLw().right));
1119 final boolean landscape = frame.height() > frame.width();
1120 final boolean offscreenLandscape = landscape && (frame.right - insets <= 0
1121 || frame.left + insets >= win.getDisplayFrameLw().right);
1122 final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0
1123 || frame.bottom + insets >= win.getDisplayFrameLw().bottom);
1124 final boolean offscreen = offscreenLandscape || offscreenPortrait;
1125 if (behindNavBar || offscreen) {
1128 if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) {
1129 return R.anim.fade_in;
1130 } else if (transit == TRANSIT_EXIT) {
1131 return R.anim.fade_out;
1138 * Determine the animation to run for a rotation transition based on the
1139 * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation}
1140 * and whether it is currently fullscreen and frontmost.
1142 * @param anim The exiting animation resource id is stored in anim[0], the
1143 * entering animation resource id is stored in anim[1].
1145 public void selectRotationAnimationLw(int anim[]) {
1146 // If the screen is off or non-interactive, force a jumpcut.
1147 final boolean forceJumpcut = !mScreenOnFully || !mService.mPolicy.okToAnimate();
1148 if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen="
1149 + mTopFullscreenOpaqueWindowState + " rotationAnimation="
1150 + (mTopFullscreenOpaqueWindowState == null
1151 ? "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation)
1152 + " forceJumpcut=" + forceJumpcut);
1154 anim[0] = R.anim.rotation_animation_jump_exit;
1155 anim[1] = R.anim.rotation_animation_enter;
1158 if (mTopFullscreenOpaqueWindowState != null) {
1159 int animationHint = mTopFullscreenOpaqueWindowState.getRotationAnimationHint();
1160 if (animationHint < 0 && mTopIsFullscreen) {
1161 animationHint = mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation;
1163 switch (animationHint) {
1164 case ROTATION_ANIMATION_CROSSFADE:
1165 case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless.
1166 anim[0] = R.anim.rotation_animation_xfade_exit;
1167 anim[1] = R.anim.rotation_animation_enter;
1169 case ROTATION_ANIMATION_JUMPCUT:
1170 anim[0] = R.anim.rotation_animation_jump_exit;
1171 anim[1] = R.anim.rotation_animation_enter;
1173 case ROTATION_ANIMATION_ROTATE:
1175 anim[0] = anim[1] = 0;
1179 anim[0] = anim[1] = 0;
1184 * Validate whether the current top fullscreen has specified the same
1185 * {@link WindowManager.LayoutParams#rotationAnimation} value as that
1186 * being passed in from the previous top fullscreen window.
1188 * @param exitAnimId exiting resource id from the previous window.
1189 * @param enterAnimId entering resource id from the previous window.
1190 * @param forceDefault For rotation animations only, if true ignore the
1191 * animation values and just return false.
1192 * @return true if the previous values are still valid, false if they
1193 * should be replaced with the default.
1195 public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId,
1196 boolean forceDefault) {
1197 switch (exitAnimId) {
1198 case R.anim.rotation_animation_xfade_exit:
1199 case R.anim.rotation_animation_jump_exit:
1200 // These are the only cases that matter.
1204 int anim[] = new int[2];
1205 selectRotationAnimationLw(anim);
1206 return (exitAnimId == anim[0] && enterAnimId == anim[1]);
1213 * Called when a new system UI visibility is being reported, allowing
1214 * the policy to adjust what is actually reported.
1215 * @param visibility The raw visibility reported by the status bar.
1216 * @return The new desired visibility.
1218 public int adjustSystemUiVisibilityLw(int visibility) {
1219 mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1220 mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);
1222 // Reset any bits in mForceClearingStatusBarVisibility that
1224 mResettingSystemUiFlags &= visibility;
1225 // Clear any bits in the new visibility that are currently being
1226 // force cleared, before reporting it.
1227 return visibility & ~mResettingSystemUiFlags
1228 & ~mForceClearedSystemUiFlags;
1232 * @return true if the system bars are forced to stay visible
1234 public boolean areSystemBarsForcedShownLw(WindowState windowState) {
1235 return mForceShowSystemBars;
1238 // TODO: Should probably be moved into DisplayFrames.
1240 * Return the layout hints for a newly added window. These values are computed on the
1241 * most recent layout, so they are not guaranteed to be correct.
1243 * @param attrs The LayoutParams of the window.
1244 * @param taskBounds The bounds of the task this window is on or {@code null} if no task is
1245 * associated with the window.
1246 * @param displayFrames display frames.
1247 * @param floatingStack Whether the window's stack is floating.
1248 * @param outFrame The frame of the window.
1249 * @param outContentInsets The areas covered by system windows, expressed as positive insets.
1250 * @param outStableInsets The areas covered by stable system windows irrespective of their
1251 * current visibility. Expressed as positive insets.
1252 * @param outOutsets The areas that are not real display, but we would like to treat as such.
1253 * @param outDisplayCutout The area that has been cut away from the display.
1254 * @return Whether to always consume the system bars.
1255 * See {@link #areSystemBarsForcedShownLw(WindowState)}.
1257 public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds,
1258 DisplayFrames displayFrames, boolean floatingStack, Rect outFrame,
1259 Rect outContentInsets, Rect outStableInsets,
1260 Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) {
1261 final int fl = PolicyControl.getWindowFlags(null, attrs);
1262 final int pfl = attrs.privateFlags;
1263 final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs);
1264 final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs);
1265 final int displayRotation = displayFrames.mRotation;
1267 final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl);
1269 int outset = mWindowOutsetBottom;
1271 if (displayRotation == Surface.ROTATION_0) {
1272 outOutsets.bottom += outset;
1273 } else if (displayRotation == Surface.ROTATION_90) {
1274 outOutsets.right += outset;
1275 } else if (displayRotation == Surface.ROTATION_180) {
1276 outOutsets.top += outset;
1277 } else if (displayRotation == Surface.ROTATION_270) {
1278 outOutsets.left += outset;
1283 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0;
1284 final boolean layoutInScreenAndInsetDecor = layoutInScreen
1285 && (fl & FLAG_LAYOUT_INSET_DECOR) != 0;
1286 final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
1288 if (layoutInScreenAndInsetDecor && !screenDecor) {
1289 if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) {
1290 outFrame.set(displayFrames.mUnrestricted);
1292 outFrame.set(displayFrames.mRestricted);
1296 if (floatingStack) {
1299 sf = displayFrames.mStable;
1303 if (floatingStack) {
1305 } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) {
1306 if ((fl & FLAG_FULLSCREEN) != 0) {
1307 cf = displayFrames.mStableFullscreen;
1309 cf = displayFrames.mStable;
1311 } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) {
1312 cf = displayFrames.mOverscan;
1314 cf = displayFrames.mCurrent;
1317 if (taskBounds != null) {
1318 outFrame.intersect(taskBounds);
1320 InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets);
1321 InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets);
1322 outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame)
1323 .getDisplayCutout());
1324 return mForceShowSystemBars;
1326 if (layoutInScreen) {
1327 outFrame.set(displayFrames.mUnrestricted);
1329 outFrame.set(displayFrames.mStable);
1331 if (taskBounds != null) {
1332 outFrame.intersect(taskBounds);
1335 outContentInsets.setEmpty();
1336 outStableInsets.setEmpty();
1337 outDisplayCutout.set(DisplayCutout.NO_CUTOUT);
1338 return mForceShowSystemBars;
1342 private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) {
1343 int impliedFlags = 0;
1344 final boolean forceWindowDrawsBarBackgrounds =
1345 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1346 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT;
1347 if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
1348 || forceWindowDrawsBarBackgrounds) {
1349 impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
1350 impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
1352 return impliedFlags;
1355 private static boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) {
1356 return attrs.type == TYPE_WALLPAPER || (fl & (WindowManager.LayoutParams.FLAG_FULLSCREEN
1357 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)) != 0;
1360 private final Runnable mClearHideNavigationFlag = new Runnable() {
1363 synchronized (mLock) {
1364 mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1365 mDisplayContent.reevaluateStatusBarVisibility();
1371 * Input handler used while nav bar is hidden. Captures any touch on the screen,
1372 * to determine when the nav bar should be shown and prevent applications from
1373 * receiving those touches.
1375 private final class HideNavInputEventReceiver extends InputEventReceiver {
1376 HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) {
1377 super(inputChannel, looper);
1381 public void onInputEvent(InputEvent event) {
1383 if (event instanceof MotionEvent
1384 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {
1385 final MotionEvent motionEvent = (MotionEvent) event;
1386 if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
1387 // When the user taps down, we re-show the nav bar.
1388 boolean changed = false;
1389 synchronized (mLock) {
1390 if (mInputConsumer == null) {
1393 // Any user activity always causes us to show the
1394 // navigation controls, if they had been hidden.
1395 // We also clear the low profile and only content
1396 // flags so that tapping on the screen will atomically
1397 // restore all currently hidden screen decorations.
1398 int newVal = mResettingSystemUiFlags
1399 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
1400 | View.SYSTEM_UI_FLAG_LOW_PROFILE
1401 | View.SYSTEM_UI_FLAG_FULLSCREEN;
1402 if (mResettingSystemUiFlags != newVal) {
1403 mResettingSystemUiFlags = newVal;
1406 // We don't allow the system's nav bar to be hidden
1407 // again for 1 second, to prevent applications from
1408 // spamming us and keeping it from being shown.
1409 newVal = mForceClearedSystemUiFlags
1410 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
1411 if (mForceClearedSystemUiFlags != newVal) {
1412 mForceClearedSystemUiFlags = newVal;
1414 mHandler.postDelayed(mClearHideNavigationFlag, 1000);
1417 mDisplayContent.reevaluateStatusBarVisibility();
1423 finishInputEvent(event, false /* handled */);
1429 * Called when layout of the windows is about to start.
1431 * @param displayFrames frames of the display we are doing layout on.
1432 * @param uiMode The current uiMode in configuration.
1434 public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
1435 displayFrames.onBeginLayout();
1436 mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
1437 mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
1439 // For purposes of putting out fake window up to steal focus, we will
1440 // drive nav being hidden only by whether it is requested.
1441 final int sysui = mLastSystemUiFlags;
1442 boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
1443 boolean navTranslucent = (sysui
1444 & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0;
1445 boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
1446 boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
1447 boolean navAllowedHidden = immersive || immersiveSticky;
1448 navTranslucent &= !immersiveSticky; // transient trumps translucent
1449 boolean isKeyguardShowing = isStatusBarKeyguard()
1450 && !mService.mPolicy.isKeyguardOccluded();
1451 boolean statusBarForcesShowingNavigation = !isKeyguardShowing && mStatusBar != null
1452 && (mStatusBar.getAttrs().privateFlags
1453 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
1455 // When the navigation bar isn't visible, we put up a fake input window to catch all
1456 // touch events. This way we can detect when the user presses anywhere to bring back the
1457 // nav bar and ensure the application doesn't see the event.
1458 if (navVisible || navAllowedHidden) {
1459 if (mInputConsumer != null) {
1460 mHandler.sendMessage(
1461 mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer));
1462 mInputConsumer = null;
1464 } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) {
1465 mInputConsumer = mService.createInputConsumer(mHandler.getLooper(),
1466 INPUT_CONSUMER_NAVIGATION,
1467 HideNavInputEventReceiver::new,
1468 displayFrames.mDisplayId);
1469 // As long as mInputConsumer is active, hover events are not dispatched to the app
1470 // and the pointer icon is likely to become stale. Hide it to avoid confusion.
1471 InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL);
1474 // For purposes of positioning and showing the nav bar, if we have decided that it can't
1475 // be hidden (because of the screen aspect ratio), then take that into account.
1476 navVisible |= !canHideNavigationBar();
1478 boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
1479 navTranslucent, navAllowedHidden, statusBarForcesShowingNavigation);
1480 if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
1481 updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
1482 if (updateSysUiVisibility) {
1483 updateSystemUiVisibilityLw();
1485 layoutScreenDecorWindows(displayFrames);
1487 if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
1488 // Make sure that the zone we're avoiding for the cutout is at least as tall as the
1489 // status bar; otherwise fullscreen apps will end up cutting halfway into the status
1491 displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
1492 displayFrames.mStable.top);
1495 // In case this is a virtual display, and the host display has insets that overlap this
1496 // virtual display, apply the insets of the overlapped area onto the current and content
1497 // frame of this virtual display. This let us layout windows in the virtual display as
1498 // expected when the window needs to avoid overlap with the system windows.
1499 // TODO: Generalize the forwarded insets, so that we can handle system windows other than
1501 displayFrames.mCurrent.inset(mForwardedInsets);
1502 displayFrames.mContent.inset(mForwardedInsets);
1505 private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
1506 if (mScreenDecorWindows.isEmpty()) {
1510 sTmpRect.setEmpty();
1511 final int displayId = displayFrames.mDisplayId;
1512 final Rect dockFrame = displayFrames.mDock;
1513 final int displayHeight = displayFrames.mDisplayHeight;
1514 final int displayWidth = displayFrames.mDisplayWidth;
1516 for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
1517 final WindowState w = mScreenDecorWindows.valueAt(i);
1518 if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
1519 // Skip if not on the same display or not visible.
1523 w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
1524 displayFrames.mUnrestricted /* displayFrame */,
1525 displayFrames.mUnrestricted /* overscanFrame */,
1526 displayFrames.mUnrestricted /* contentFrame */,
1527 displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
1528 displayFrames.mUnrestricted /* stableFrame */,
1529 displayFrames.mUnrestricted /* outsetFrame */);
1530 w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1532 final Rect frame = w.getFrameLw();
1534 if (frame.left <= 0 && frame.top <= 0) {
1535 // Docked at left or top.
1536 if (frame.bottom >= displayHeight) {
1538 dockFrame.left = Math.max(frame.right, dockFrame.left);
1539 } else if (frame.right >= displayWidth) {
1541 dockFrame.top = Math.max(frame.bottom, dockFrame.top);
1543 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1544 + " not docked on left or top of display. frame=" + frame
1545 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1547 } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
1548 // Docked at right or bottom.
1549 if (frame.top <= 0) {
1551 dockFrame.right = Math.min(frame.left, dockFrame.right);
1552 } else if (frame.left <= 0) {
1554 dockFrame.bottom = Math.min(frame.top, dockFrame.bottom);
1556 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1557 + " not docked on right or bottom" + " of display. frame=" + frame
1558 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1561 // Screen decor windows are required to be docked on one of the sides of the screen.
1562 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
1563 + " not docked on one of the sides of the display. frame=" + frame
1564 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
1568 displayFrames.mRestricted.set(dockFrame);
1569 displayFrames.mCurrent.set(dockFrame);
1570 displayFrames.mVoiceContent.set(dockFrame);
1571 displayFrames.mSystem.set(dockFrame);
1572 displayFrames.mContent.set(dockFrame);
1573 displayFrames.mRestrictedOverscan.set(dockFrame);
1576 private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
1577 boolean isKeyguardShowing) {
1578 // decide where the status bar goes ahead of time
1579 if (mStatusBar == null) {
1582 // apply any navigation bar insets
1583 sTmpRect.setEmpty();
1584 final WindowFrames windowFrames = mStatusBar.getWindowFrames();
1585 windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
1586 displayFrames.mUnrestricted /* displayFrame */,
1587 displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */,
1588 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
1589 displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */);
1590 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1592 // Let the status bar determine its size.
1593 mStatusBar.computeFrameLw();
1595 // For layout, the status bar is always at the top with our fixed height.
1596 displayFrames.mStable.top = displayFrames.mUnrestricted.top
1597 + mStatusBarHeightForRotation[displayFrames.mRotation];
1598 // Make sure the status bar covers the entire cutout height
1599 displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
1600 displayFrames.mDisplayCutoutSafe.top);
1602 // Tell the bar controller where the collapsed status bar content is
1603 sTmpRect.set(mStatusBar.getContentFrameLw());
1604 sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
1605 sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
1606 sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
1607 mStatusBarController.setContentFrame(sTmpRect);
1609 boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
1610 boolean statusBarTranslucent = (sysui
1611 & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;
1613 // If the status bar is hidden, we don't want to cause windows behind it to scroll.
1614 if (mStatusBar.isVisibleLw() && !statusBarTransient) {
1615 // Status bar may go away, so the screen area it occupies is available to apps but just
1616 // covering them when the status bar is visible.
1617 final Rect dockFrame = displayFrames.mDock;
1618 dockFrame.top = displayFrames.mStable.top;
1619 displayFrames.mContent.set(dockFrame);
1620 displayFrames.mVoiceContent.set(dockFrame);
1621 displayFrames.mCurrent.set(dockFrame);
1623 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format(
1624 "dock=%s content=%s cur=%s", dockFrame.toString(),
1625 displayFrames.mContent.toString(), displayFrames.mCurrent.toString()));
1627 if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent()
1628 && !mStatusBar.isAnimatingLw()) {
1630 // If the opaque status bar is currently requested to be visible, and not in the
1631 // process of animating on or off, then we can tell the app that it is covered by
1633 displayFrames.mSystem.top = displayFrames.mStable.top;
1636 return mStatusBarController.checkHiddenLw();
1639 private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
1640 boolean navTranslucent, boolean navAllowedHidden,
1641 boolean statusBarForcesShowingNavigation) {
1642 if (mNavigationBar == null) {
1646 final Rect navigationFrame = sTmpNavFrame;
1647 boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();
1648 // Force the navigation bar to its appropriate place and size. We need to do this directly,
1649 // instead of relying on it to bubble up from the nav bar, because this needs to change
1650 // atomically with screen rotations.
1651 final int rotation = displayFrames.mRotation;
1652 final int displayHeight = displayFrames.mDisplayHeight;
1653 final int displayWidth = displayFrames.mDisplayWidth;
1654 final Rect dockFrame = displayFrames.mDock;
1655 mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
1657 final Rect cutoutSafeUnrestricted = sTmpRect;
1658 cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
1659 cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
1661 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1662 // It's a system nav bar or a portrait screen; nav bar goes on bottom.
1663 final int top = cutoutSafeUnrestricted.bottom
1664 - getNavigationBarHeight(rotation, uiMode);
1665 final int topNavBar = cutoutSafeUnrestricted.bottom
1666 - getNavigationBarFrameHeight(rotation, uiMode);
1667 navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom);
1668 displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top;
1669 if (transientNavBarShowing) {
1670 mNavigationBarController.setBarShowingLw(true);
1671 } else if (navVisible) {
1672 mNavigationBarController.setBarShowingLw(true);
1673 dockFrame.bottom = displayFrames.mRestricted.bottom =
1674 displayFrames.mRestrictedOverscan.bottom = top;
1676 // We currently want to hide the navigation UI - unless we expanded the status bar.
1677 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1679 if (navVisible && !navTranslucent && !navAllowedHidden
1680 && !mNavigationBar.isAnimatingLw()
1681 && !mNavigationBarController.wasRecentlyTranslucent()) {
1682 // If the opaque nav bar is currently requested to be visible and not in the process
1683 // of animating on or off, then we can tell the app that it is covered by it.
1684 displayFrames.mSystem.bottom = top;
1686 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1687 // Landscape screen; nav bar goes to the right.
1688 final int left = cutoutSafeUnrestricted.right
1689 - getNavigationBarWidth(rotation, uiMode);
1690 navigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight);
1691 displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left;
1692 if (transientNavBarShowing) {
1693 mNavigationBarController.setBarShowingLw(true);
1694 } else if (navVisible) {
1695 mNavigationBarController.setBarShowingLw(true);
1696 dockFrame.right = displayFrames.mRestricted.right =
1697 displayFrames.mRestrictedOverscan.right = left;
1699 // We currently want to hide the navigation UI - unless we expanded the status bar.
1700 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1702 if (navVisible && !navTranslucent && !navAllowedHidden
1703 && !mNavigationBar.isAnimatingLw()
1704 && !mNavigationBarController.wasRecentlyTranslucent()) {
1705 // If the nav bar is currently requested to be visible, and not in the process of
1706 // animating on or off, then we can tell the app that it is covered by it.
1707 displayFrames.mSystem.right = left;
1709 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1710 // Seascape screen; nav bar goes to the left.
1711 final int right = cutoutSafeUnrestricted.left
1712 + getNavigationBarWidth(rotation, uiMode);
1713 navigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight);
1714 displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right;
1715 if (transientNavBarShowing) {
1716 mNavigationBarController.setBarShowingLw(true);
1717 } else if (navVisible) {
1718 mNavigationBarController.setBarShowingLw(true);
1719 dockFrame.left = displayFrames.mRestricted.left =
1720 displayFrames.mRestrictedOverscan.left = right;
1722 // We currently want to hide the navigation UI - unless we expanded the status bar.
1723 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation);
1725 if (navVisible && !navTranslucent && !navAllowedHidden
1726 && !mNavigationBar.isAnimatingLw()
1727 && !mNavigationBarController.wasRecentlyTranslucent()) {
1728 // If the nav bar is currently requested to be visible, and not in the process of
1729 // animating on or off, then we can tell the app that it is covered by it.
1730 displayFrames.mSystem.left = right;
1734 // Make sure the content and current rectangles are updated to account for the restrictions
1735 // from the navigation bar.
1736 displayFrames.mCurrent.set(dockFrame);
1737 displayFrames.mVoiceContent.set(dockFrame);
1738 displayFrames.mContent.set(dockFrame);
1739 // And compute the final frame.
1740 sTmpRect.setEmpty();
1741 mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
1742 navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */,
1743 displayFrames.mDisplayCutoutSafe /* contentFrame */,
1744 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
1745 navigationFrame /* stableFrame */,
1746 displayFrames.mDisplayCutoutSafe /* outsetFrame */);
1747 mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
1748 mNavigationBar.computeFrameLw();
1749 mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
1751 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
1752 return mNavigationBarController.checkHiddenLw();
1755 private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached,
1756 boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf,
1757 DisplayFrames displayFrames) {
1758 if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) {
1759 // Here's a special case: if the child window is not the 'dock window'
1760 // or input method target, and the window it is attached to is below
1761 // the dock window, then the frames we computed for the window it is
1762 // attached to can not be used because the dock is effectively part
1763 // of the underlying window and the attached window is floating on top
1764 // of the whole thing. So, we ignore the attached window and explicitly
1765 // compute the frames that would be appropriate without the dock.
1766 vf.set(displayFrames.mDock);
1767 cf.set(displayFrames.mDock);
1768 of.set(displayFrames.mDock);
1769 df.set(displayFrames.mDock);
1772 // In case we forced the window to draw behind the navigation bar, restrict df/of to
1773 // DF.RestrictedOverscan to simulate old compat behavior.
1774 Rect parentDisplayFrame = attached.getDisplayFrameLw();
1775 Rect parentOverscan = attached.getOverscanFrameLw();
1776 final WindowManager.LayoutParams attachedAttrs = attached.mAttrs;
1777 if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0
1778 && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1779 && (attachedAttrs.systemUiVisibility
1780 & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) {
1781 parentOverscan = new Rect(parentOverscan);
1782 parentOverscan.intersect(displayFrames.mRestrictedOverscan);
1783 parentDisplayFrame = new Rect(parentDisplayFrame);
1784 parentDisplayFrame.intersect(displayFrames.mRestrictedOverscan);
1787 // The effective display frame of the attached window depends on whether it is taking
1788 // care of insetting its content. If not, we need to use the parent's content frame so
1789 // that the entire window is positioned within that content. Otherwise we can use the
1790 // overscan frame and let the attached window take care of positioning its content
1792 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1793 // Set the content frame of the attached window to the parent's decor frame
1794 // (same as content frame when IME isn't present) if specifically requested by
1795 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag.
1796 // Otherwise, use the overscan frame.
1797 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0
1798 ? attached.getContentFrameLw() : parentOverscan);
1800 // If the window is resizing, then we want to base the content frame on our attached
1801 // content frame to resize...however, things can be tricky if the attached window is
1802 // NOT in resize mode, in which case its content frame will be larger.
1803 // Ungh. So to deal with that, make sure the content frame we end up using is not
1804 // covering the IM dock.
1805 cf.set(attached.getContentFrameLw());
1806 if (attached.isVoiceInteraction()) {
1807 cf.intersectUnchecked(displayFrames.mVoiceContent);
1808 } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) {
1809 cf.intersectUnchecked(displayFrames.mContent);
1812 df.set(insetDecors ? parentDisplayFrame : cf);
1813 of.set(insetDecors ? parentOverscan : cf);
1814 vf.set(attached.getVisibleFrameLw());
1816 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be
1817 // positioned relative to its parent or the entire screen.
1818 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df);
1821 private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) {
1822 if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) {
1825 // If app is requesting a stable layout, don't let the content insets go below the stable
1827 if ((fl & FLAG_FULLSCREEN) != 0) {
1828 r.intersectUnchecked(displayFrames.mStableFullscreen);
1830 r.intersectUnchecked(displayFrames.mStable);
1834 private boolean canReceiveInput(WindowState win) {
1835 boolean notFocusable =
1836 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0;
1837 boolean altFocusableIm =
1838 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0;
1839 boolean notFocusableForIm = notFocusable ^ altFocusableIm;
1840 return !notFocusableForIm;
1844 * Called for each window attached to the window manager as layout is proceeding. The
1845 * implementation of this function must take care of setting the window's frame, either here or
1846 * in finishLayout().
1848 * @param win The window being positioned.
1849 * @param attached For sub-windows, the window it is attached to; this
1850 * window will already have had layoutWindow() called on it
1851 * so you can use its Rect. Otherwise null.
1852 * @param displayFrames The display frames.
1854 public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) {
1855 // We've already done the navigation bar, status bar, and all screen decor windows. If the
1856 // status bar can receive input, we need to layout it again to accommodate for the IME
1858 if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
1859 || mScreenDecorWindows.contains(win)) {
1862 final WindowManager.LayoutParams attrs = win.getAttrs();
1863 final boolean isDefaultDisplay = win.isDefaultDisplay();
1865 final int type = attrs.type;
1866 final int fl = PolicyControl.getWindowFlags(win, attrs);
1867 final int pfl = attrs.privateFlags;
1868 final int sim = attrs.softInputMode;
1869 final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs);
1870 final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs);
1872 final WindowFrames windowFrames = win.getWindowFrames();
1874 windowFrames.setHasOutsets(false);
1875 sTmpLastParentFrame.set(windowFrames.mParentFrame);
1876 final Rect pf = windowFrames.mParentFrame;
1877 final Rect df = windowFrames.mDisplayFrame;
1878 final Rect of = windowFrames.mOverscanFrame;
1879 final Rect cf = windowFrames.mContentFrame;
1880 final Rect vf = windowFrames.mVisibleFrame;
1881 final Rect dcf = windowFrames.mDecorFrame;
1882 final Rect sf = windowFrames.mStableFrame;
1884 windowFrames.setParentFrameWasClippedByDisplayCutout(false);
1885 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
1887 final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
1888 && mNavigationBar.isVisibleLw();
1890 final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
1892 final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0
1893 || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
1895 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN;
1896 final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR;
1898 sf.set(displayFrames.mStable);
1900 if (type == TYPE_INPUT_METHOD) {
1901 vf.set(displayFrames.mDock);
1902 cf.set(displayFrames.mDock);
1903 of.set(displayFrames.mDock);
1904 df.set(displayFrames.mDock);
1905 windowFrames.mParentFrame.set(displayFrames.mDock);
1906 // IM dock windows layout below the nav bar...
1907 pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom;
1908 // ...with content insets above the nav bar
1909 cf.bottom = vf.bottom = displayFrames.mStable.bottom;
1910 if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) {
1911 // The status bar forces the navigation bar while it's visible. Make sure the IME
1912 // avoids the navigation bar in that case.
1913 if (mNavigationBarPosition == NAV_BAR_RIGHT) {
1914 pf.right = df.right = of.right = cf.right = vf.right =
1915 displayFrames.mStable.right;
1916 } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
1917 pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left;
1921 // In case the navigation bar is on the bottom, we use the frame height instead of the
1922 // regular height for the insets we send to the IME as we need some space to show
1923 // additional buttons in SystemUI when the IME is up.
1924 if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
1925 final int rotation = displayFrames.mRotation;
1926 final int uimode = mService.mPolicy.getUiMode();
1927 final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode)
1928 - getNavigationBarHeight(rotation, uimode);
1929 if (navHeightOffset > 0) {
1930 cf.bottom -= navHeightOffset;
1931 sf.bottom -= navHeightOffset;
1932 vf.bottom -= navHeightOffset;
1933 dcf.bottom -= navHeightOffset;
1937 // IM dock windows always go to the bottom of the screen.
1938 attrs.gravity = Gravity.BOTTOM;
1939 } else if (type == TYPE_VOICE_INTERACTION) {
1940 of.set(displayFrames.mUnrestricted);
1941 df.set(displayFrames.mUnrestricted);
1942 pf.set(displayFrames.mUnrestricted);
1943 if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
1944 cf.set(displayFrames.mDock);
1946 cf.set(displayFrames.mContent);
1948 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
1949 vf.set(displayFrames.mCurrent);
1953 } else if (type == TYPE_WALLPAPER) {
1954 layoutWallpaper(displayFrames, pf, df, of, cf);
1955 } else if (win == mStatusBar) {
1956 of.set(displayFrames.mUnrestricted);
1957 df.set(displayFrames.mUnrestricted);
1958 pf.set(displayFrames.mUnrestricted);
1959 cf.set(displayFrames.mStable);
1960 vf.set(displayFrames.mStable);
1962 if (adjust == SOFT_INPUT_ADJUST_RESIZE) {
1963 cf.bottom = displayFrames.mContent.bottom;
1965 cf.bottom = displayFrames.mDock.bottom;
1966 vf.bottom = displayFrames.mContent.bottom;
1969 dcf.set(displayFrames.mSystem);
1970 final boolean inheritTranslucentDecor =
1971 (attrs.privateFlags & PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0;
1972 final boolean isAppWindow =
1973 type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW;
1974 final boolean topAtRest =
1975 win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw();
1976 if (isAppWindow && !inheritTranslucentDecor && !topAtRest) {
1977 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0
1978 && (fl & FLAG_FULLSCREEN) == 0
1979 && (fl & FLAG_TRANSLUCENT_STATUS) == 0
1980 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1981 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
1982 // Ensure policy decor includes status bar
1983 dcf.top = displayFrames.mStable.top;
1985 if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0
1986 && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0
1987 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0
1988 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) {
1989 // Ensure policy decor includes navigation bar
1990 dcf.bottom = displayFrames.mStable.bottom;
1991 dcf.right = displayFrames.mStable.right;
1995 if (layoutInScreen && layoutInsetDecor) {
1996 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
1997 + "): IN_SCREEN, INSET_DECOR");
1998 // This is the case for a normal activity window: we want it to cover all of the
1999 // screen space, and it can take care of moving its contents to account for screen
2000 // decorations that intrude into that space.
2001 if (attached != null) {
2002 // If this window is attached to another, our display
2003 // frame is the same as the one we are attached to.
2004 setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf,
2007 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2008 // Status bar panels are the only windows who can go on top of the status
2009 // bar. They are protected by the STATUS_BAR_SERVICE permission, so they
2010 // have the same privileges as the status bar itself.
2012 // However, they should still dodge the navigation bar if it exists.
2014 pf.left = df.left = of.left = hasNavBar
2015 ? displayFrames.mDock.left : displayFrames.mUnrestricted.left;
2016 pf.top = df.top = of.top = displayFrames.mUnrestricted.top;
2017 pf.right = df.right = of.right = hasNavBar
2018 ? displayFrames.mRestricted.right
2019 : displayFrames.mUnrestricted.right;
2020 pf.bottom = df.bottom = of.bottom = hasNavBar
2021 ? displayFrames.mRestricted.bottom
2022 : displayFrames.mUnrestricted.bottom;
2024 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf);
2025 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
2026 && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
2027 // Asking to layout into the overscan region, so give it that pure
2028 // unrestricted area.
2029 of.set(displayFrames.mOverscan);
2030 df.set(displayFrames.mOverscan);
2031 pf.set(displayFrames.mOverscan);
2032 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
2033 && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW
2034 || type == TYPE_VOLUME_OVERLAY
2035 || type == TYPE_KEYGUARD_DIALOG)) {
2036 // Asking for layout as if the nav bar is hidden, lets the application
2037 // extend into the unrestricted overscan screen area. We only do this for
2038 // application windows and certain system windows to ensure no window that
2039 // can be above the nav bar can do this.
2040 df.set(displayFrames.mOverscan);
2041 pf.set(displayFrames.mOverscan);
2042 // We need to tell the app about where the frame inside the overscan is, so
2043 // it can inset its content by that amount -- it didn't ask to actually
2044 // extend itself into the overscan region.
2045 of.set(displayFrames.mUnrestricted);
2047 df.set(displayFrames.mRestrictedOverscan);
2048 pf.set(displayFrames.mRestrictedOverscan);
2049 // We need to tell the app about where the frame inside the overscan
2050 // is, so it can inset its content by that amount -- it didn't ask
2051 // to actually extend itself into the overscan region.
2052 of.set(displayFrames.mUnrestricted);
2055 if ((fl & FLAG_FULLSCREEN) == 0) {
2056 if (win.isVoiceInteraction()) {
2057 cf.set(displayFrames.mVoiceContent);
2059 // IME Insets are handled on the client for ADJUST_RESIZE in the new
2061 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2062 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
2063 cf.set(displayFrames.mDock);
2065 cf.set(displayFrames.mContent);
2069 // Full screen windows are always given a layout that is as if the status
2070 // bar and other transient decors are gone. This is to avoid bad states when
2071 // moving from a window that is not hiding the status bar to one that is.
2072 cf.set(displayFrames.mRestricted);
2074 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2075 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2076 vf.set(displayFrames.mCurrent);
2081 } else if (layoutInScreen || (sysUiFl
2082 & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
2083 | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) {
2084 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2086 // A window that has requested to fill the entire screen just
2087 // gets everything, period.
2088 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) {
2089 cf.set(displayFrames.mUnrestricted);
2090 of.set(displayFrames.mUnrestricted);
2091 df.set(displayFrames.mUnrestricted);
2092 pf.set(displayFrames.mUnrestricted);
2094 pf.left = df.left = of.left = cf.left = displayFrames.mDock.left;
2095 pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right;
2096 pf.bottom = df.bottom = of.bottom = cf.bottom =
2097 displayFrames.mRestricted.bottom;
2099 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf);
2100 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) {
2101 // The navigation bar has Real Ultimate Power.
2102 of.set(displayFrames.mUnrestricted);
2103 df.set(displayFrames.mUnrestricted);
2104 pf.set(displayFrames.mUnrestricted);
2105 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf);
2106 } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT)
2107 && ((fl & FLAG_FULLSCREEN) != 0)) {
2108 // Fullscreen secure system overlays get what they ask for. Screenshot region
2109 // selection overlay should also expand to full screen.
2110 cf.set(displayFrames.mOverscan);
2111 of.set(displayFrames.mOverscan);
2112 df.set(displayFrames.mOverscan);
2113 pf.set(displayFrames.mOverscan);
2114 } else if (type == TYPE_BOOT_PROGRESS) {
2115 // Boot progress screen always covers entire display.
2116 cf.set(displayFrames.mOverscan);
2117 of.set(displayFrames.mOverscan);
2118 df.set(displayFrames.mOverscan);
2119 pf.set(displayFrames.mOverscan);
2120 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
2121 && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) {
2122 // Asking to layout into the overscan region, so give it that pure unrestricted
2124 cf.set(displayFrames.mOverscan);
2125 of.set(displayFrames.mOverscan);
2126 df.set(displayFrames.mOverscan);
2127 pf.set(displayFrames.mOverscan);
2128 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
2129 && (type == TYPE_STATUS_BAR
2130 || type == TYPE_TOAST
2131 || type == TYPE_DOCK_DIVIDER
2132 || type == TYPE_VOICE_INTERACTION_STARTING
2133 || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) {
2134 // Asking for layout as if the nav bar is hidden, lets the
2135 // application extend into the unrestricted screen area. We
2136 // only do this for application windows (or toasts) to ensure no window that
2137 // can be above the nav bar can do this.
2138 // XXX This assumes that an app asking for this will also
2139 // ask for layout in only content. We can't currently figure out
2140 // what the screen would be if only laying out to hide the nav bar.
2141 cf.set(displayFrames.mUnrestricted);
2142 of.set(displayFrames.mUnrestricted);
2143 df.set(displayFrames.mUnrestricted);
2144 pf.set(displayFrames.mUnrestricted);
2145 } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) {
2146 of.set(displayFrames.mRestricted);
2147 df.set(displayFrames.mRestricted);
2148 pf.set(displayFrames.mRestricted);
2150 // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
2152 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
2153 || adjust != SOFT_INPUT_ADJUST_RESIZE) {
2154 cf.set(displayFrames.mDock);
2156 cf.set(displayFrames.mContent);
2159 cf.set(displayFrames.mRestricted);
2160 of.set(displayFrames.mRestricted);
2161 df.set(displayFrames.mRestricted);
2162 pf.set(displayFrames.mRestricted);
2165 applyStableConstraints(sysUiFl, fl, cf, displayFrames);
2167 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2168 vf.set(displayFrames.mCurrent);
2172 } else if (attached != null) {
2173 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2174 + "): attached to " + attached);
2175 // A child window should be placed inside of the same visible
2176 // frame that its parent had.
2177 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf,
2180 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle()
2181 + "): normal window");
2182 // Otherwise, a normal window must be placed inside the content
2183 // of all screen decorations.
2184 if (type == TYPE_STATUS_BAR_PANEL) {
2185 // Status bar panels can go on
2186 // top of the status bar. They are protected by the STATUS_BAR_SERVICE
2187 // permission, so they have the same privileges as the status bar itself.
2188 cf.set(displayFrames.mRestricted);
2189 of.set(displayFrames.mRestricted);
2190 df.set(displayFrames.mRestricted);
2191 pf.set(displayFrames.mRestricted);
2192 } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) {
2193 // These dialogs are stable to interim decor changes.
2194 cf.set(displayFrames.mStable);
2195 of.set(displayFrames.mStable);
2196 df.set(displayFrames.mStable);
2197 pf.set(displayFrames.mStable);
2199 pf.set(displayFrames.mContent);
2200 if (win.isVoiceInteraction()) {
2201 cf.set(displayFrames.mVoiceContent);
2202 of.set(displayFrames.mVoiceContent);
2203 df.set(displayFrames.mVoiceContent);
2204 } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
2205 cf.set(displayFrames.mDock);
2206 of.set(displayFrames.mDock);
2207 df.set(displayFrames.mDock);
2209 cf.set(displayFrames.mContent);
2210 of.set(displayFrames.mContent);
2211 df.set(displayFrames.mContent);
2213 if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
2214 vf.set(displayFrames.mCurrent);
2222 final int cutoutMode = attrs.layoutInDisplayCutoutMode;
2223 final boolean attachedInParent = attached != null && !layoutInScreen;
2224 final boolean requestedHideNavigation =
2225 (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
2227 // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get
2228 // cropped / shifted to the displayFrame in WindowState.
2229 final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen
2230 && type != TYPE_BASE_APPLICATION;
2232 // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in
2233 // the cutout safe zone.
2234 if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) {
2235 final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect;
2236 displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe);
2237 if (layoutInScreen && layoutInsetDecor && !requestedFullscreen
2238 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2239 // At the top we have the status bar, so apps that are
2240 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN
2241 // already expect that there's an inset there and we don't need to exclude
2242 // the window from that area.
2243 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE;
2245 if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation
2246 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) {
2247 // Same for the navigation bar.
2248 switch (mNavigationBarPosition) {
2249 case NAV_BAR_BOTTOM:
2250 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2253 displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE;
2256 displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE;
2260 if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) {
2261 // The IME can always extend under the bottom cutout if the navbar is there.
2262 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE;
2264 // Windows that are attached to a parent and laid out in said parent already avoid
2265 // the cutout according to that parent and don't need to be further constrained.
2266 // Floating IN_SCREEN windows get what they ask for and lay out in the full screen.
2267 // They will later be cropped or shifted using the displayFrame in WindowState,
2268 // which prevents overlap with the DisplayCutout.
2269 if (!attachedInParent && !floatingInScreenWindow) {
2271 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2272 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf));
2274 // Make sure that NO_LIMITS windows clipped to the display don't extend under the
2276 df.intersectUnchecked(displayCutoutSafeExceptMaybeBars);
2279 // Content should never appear in the cutout.
2280 cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
2282 // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it.
2283 // Also, we don't allow windows in multi-window mode to extend out of the screen.
2284 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR
2285 && !win.inMultiWindowMode()) {
2286 df.left = df.top = -10000;
2287 df.right = df.bottom = 10000;
2288 if (type != TYPE_WALLPAPER) {
2289 of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000;
2290 of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000;
2294 // If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we
2295 // need to provide information to the clients that want to pretend that you can draw there.
2296 // We only want to apply outsets to certain types of windows. For example, we never want to
2297 // apply the outsets to floating dialogs, because they wouldn't make sense there.
2298 final boolean useOutsets = shouldUseOutsets(attrs, fl);
2299 if (isDefaultDisplay && useOutsets) {
2300 final Rect osf = windowFrames.mOutsetFrame;
2301 osf.set(cf.left, cf.top, cf.right, cf.bottom);
2302 windowFrames.setHasOutsets(true);
2303 int outset = mWindowOutsetBottom;
2305 int rotation = displayFrames.mRotation;
2306 if (rotation == Surface.ROTATION_0) {
2307 osf.bottom += outset;
2308 } else if (rotation == Surface.ROTATION_90) {
2309 osf.right += outset;
2310 } else if (rotation == Surface.ROTATION_180) {
2312 } else if (rotation == Surface.ROTATION_270) {
2315 if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset
2316 + " with rotation " + rotation + ", result: " + osf);
2320 if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle()
2321 + ": sim=#" + Integer.toHexString(sim)
2322 + " attach=" + attached + " type=" + type
2323 + String.format(" flags=0x%08x", fl)
2324 + " pf=" + pf.toShortString() + " df=" + df.toShortString()
2325 + " of=" + of.toShortString()
2326 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString()
2327 + " dcf=" + dcf.toShortString()
2328 + " sf=" + sf.toShortString()
2329 + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win);
2331 if (!sTmpLastParentFrame.equals(pf)) {
2332 windowFrames.setContentChanged(true);
2335 win.computeFrameLw();
2336 // Dock windows carve out the bottom of the screen, so normal windows
2337 // can't appear underneath them.
2338 if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
2339 && !win.getGivenInsetsPendingLw()) {
2340 offsetInputMethodWindowLw(win, displayFrames);
2342 if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw()
2343 && !win.getGivenInsetsPendingLw()) {
2344 offsetVoiceInputWindowLw(win, displayFrames);
2348 private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf) {
2349 // The wallpaper has Real Ultimate Power, but we want to tell it about the overscan area.
2350 df.set(displayFrames.mOverscan);
2351 pf.set(displayFrames.mOverscan);
2352 cf.set(displayFrames.mUnrestricted);
2353 of.set(displayFrames.mUnrestricted);
2356 private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) {
2357 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2358 top += win.getGivenContentInsetsLw().top;
2359 displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top);
2360 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2361 top = win.getVisibleFrameLw().top;
2362 top += win.getGivenVisibleInsetsLw().top;
2363 displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top);
2364 if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom="
2365 + displayFrames.mDock.bottom + " mContentBottom="
2366 + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom);
2369 private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) {
2370 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
2371 top += win.getGivenContentInsetsLw().top;
2372 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top);
2376 * Called following layout of all windows before each window has policy applied.
2378 public void beginPostLayoutPolicyLw() {
2379 mTopFullscreenOpaqueWindowState = null;
2380 mTopFullscreenOpaqueOrDimmingWindowState = null;
2381 mTopDockedOpaqueWindowState = null;
2382 mTopDockedOpaqueOrDimmingWindowState = null;
2383 mForceStatusBar = false;
2384 mForceStatusBarFromKeyguard = false;
2385 mForceStatusBarTransparent = false;
2386 mForcingShowNavBar = false;
2387 mForcingShowNavBarLayer = -1;
2389 mAllowLockscreenWhenOn = false;
2390 mShowingDream = false;
2391 mWindowSleepTokenNeeded = false;
2395 * Called following layout of all window to apply policy to each window.
2397 * @param win The window being positioned.
2398 * @param attrs The LayoutParams of the window.
2399 * @param attached For sub-windows, the window it is attached to. Otherwise null.
2401 public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs,
2402 WindowState attached, WindowState imeTarget) {
2403 final boolean affectsSystemUi = win.canAffectSystemUiFlags();
2404 if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi);
2405 mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget);
2406 final int fl = PolicyControl.getWindowFlags(win, attrs);
2407 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi
2408 && attrs.type == TYPE_INPUT_METHOD) {
2409 mForcingShowNavBar = true;
2410 mForcingShowNavBarLayer = win.getSurfaceLayer();
2412 if (attrs.type == TYPE_STATUS_BAR) {
2413 if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
2414 mForceStatusBarFromKeyguard = true;
2416 if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
2417 mForceStatusBarTransparent = true;
2421 boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW
2422 && attrs.type < FIRST_SYSTEM_WINDOW;
2423 final int windowingMode = win.getWindowingMode();
2424 final boolean inFullScreenOrSplitScreenSecondaryWindowingMode =
2425 windowingMode == WINDOWING_MODE_FULLSCREEN
2426 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
2427 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) {
2428 if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) {
2429 mForceStatusBar = true;
2431 if (attrs.type == TYPE_DREAM) {
2432 // If the lockscreen was showing when the dream started then wait
2433 // for the dream to draw before hiding the lockscreen.
2434 if (!mDreamingLockscreen
2435 || (win.isVisibleLw() && win.hasDrawnLw())) {
2436 mShowingDream = true;
2441 // For app windows that are not attached, we decide if all windows in the app they
2442 // represent should be hidden or if we should hide the lockscreen. For attached app
2443 // windows we defer the decision to the window it is attached to.
2444 if (appWindow && attached == null) {
2445 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2446 if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
2447 mTopFullscreenOpaqueWindowState = win;
2448 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2449 mTopFullscreenOpaqueOrDimmingWindowState = win;
2451 if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) {
2452 mAllowLockscreenWhenOn = true;
2458 // Voice interaction overrides both top fullscreen and top docked.
2459 if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION) {
2460 if (mTopFullscreenOpaqueWindowState == null) {
2461 mTopFullscreenOpaqueWindowState = win;
2462 if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
2463 mTopFullscreenOpaqueOrDimmingWindowState = win;
2466 if (mTopDockedOpaqueWindowState == null) {
2467 mTopDockedOpaqueWindowState = win;
2468 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2469 mTopDockedOpaqueOrDimmingWindowState = win;
2474 // Keep track of the window if it's dimming but not necessarily fullscreen.
2475 if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi
2476 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) {
2477 mTopFullscreenOpaqueOrDimmingWindowState = win;
2480 // We need to keep track of the top "fullscreen" opaque window for the docked stack
2481 // separately, because both the "real fullscreen" opaque window and the one for the docked
2482 // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.
2483 if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null
2484 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2485 mTopDockedOpaqueWindowState = win;
2486 if (mTopDockedOpaqueOrDimmingWindowState == null) {
2487 mTopDockedOpaqueOrDimmingWindowState = win;
2491 // Also keep track of any windows that are dimming but not necessarily fullscreen in the
2493 if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming()
2494 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
2495 mTopDockedOpaqueOrDimmingWindowState = win;
2500 * Called following layout of all windows and after policy has been applied
2501 * to each window. If in this function you do
2502 * something that may have modified the animation state of another window,
2503 * be sure to return non-zero in order to perform another pass through layout.
2505 * @return Return any bit set of
2506 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT},
2507 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG},
2508 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or
2509 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}.
2511 public int finishPostLayoutPolicyLw() {
2513 boolean topIsFullscreen = false;
2515 // If we are not currently showing a dream then remember the current
2516 // lockscreen state. We will use this to determine whether the dream
2517 // started while the lockscreen was showing and remember this state
2518 // while the dream is showing.
2519 if (!mShowingDream) {
2520 mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded();
2521 if (mDreamingSleepTokenNeeded) {
2522 mDreamingSleepTokenNeeded = false;
2523 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget();
2526 if (!mDreamingSleepTokenNeeded) {
2527 mDreamingSleepTokenNeeded = true;
2528 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget();
2532 if (mStatusBar != null) {
2533 if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar
2534 + " forcefkg=" + mForceStatusBarFromKeyguard
2535 + " top=" + mTopFullscreenOpaqueWindowState);
2536 boolean shouldBeTransparent = mForceStatusBarTransparent
2538 && !mForceStatusBarFromKeyguard;
2539 if (!shouldBeTransparent) {
2540 mStatusBarController.setShowTransparent(false /* transparent */);
2541 } else if (!mStatusBar.isVisibleLw()) {
2542 mStatusBarController.setShowTransparent(true /* transparent */);
2545 boolean statusBarForcesShowingNavigation =
2546 (mStatusBar.getAttrs().privateFlags
2547 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0;
2548 boolean topAppHidesStatusBar = topAppHidesStatusBar();
2549 if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent
2550 || statusBarForcesShowingNavigation) {
2551 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced");
2552 if (mStatusBarController.setBarShowingLw(true)) {
2553 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2555 // Maintain fullscreen layout until incoming animation is complete.
2556 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
2557 // Transient status bar is not allowed if status bar is on lockscreen or status bar
2558 // is expecting the navigation keys from the user.
2559 if ((mForceStatusBarFromKeyguard || statusBarForcesShowingNavigation)
2560 && mStatusBarController.isTransientShowing()) {
2561 mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
2562 mLastSystemUiFlags, mLastSystemUiFlags);
2564 } else if (mTopFullscreenOpaqueWindowState != null) {
2565 topIsFullscreen = topAppHidesStatusBar;
2566 // The subtle difference between the window for mTopFullscreenOpaqueWindowState
2567 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
2568 // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
2570 if (mStatusBarController.isTransientShowing()) {
2571 if (mStatusBarController.setBarShowingLw(true)) {
2572 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2574 } else if (topIsFullscreen
2575 && !mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM)
2576 && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) {
2577 if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar");
2578 if (mStatusBarController.setBarShowingLw(false)) {
2579 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2581 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding");
2584 if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen");
2585 if (mStatusBarController.setBarShowingLw(true)) {
2586 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2588 topAppHidesStatusBar = false;
2591 mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar);
2594 if (mTopIsFullscreen != topIsFullscreen) {
2595 if (!topIsFullscreen) {
2596 // Force another layout when status bar becomes fully shown.
2597 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2599 mTopIsFullscreen = topIsFullscreen;
2602 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
2603 // If the navigation bar has been hidden or shown, we need to do another
2604 // layout pass to update that window.
2605 changes |= FINISH_LAYOUT_REDO_LAYOUT;
2608 if (mShowingDream != mLastShowingDream) {
2609 mLastShowingDream = mShowingDream;
2610 mService.notifyShowingDreamChanged();
2613 updateWindowSleepToken();
2615 mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn);
2619 private void updateWindowSleepToken() {
2620 if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) {
2621 mHandler.removeCallbacks(mReleaseSleepTokenRunnable);
2622 mHandler.post(mAcquireSleepTokenRunnable);
2623 } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) {
2624 mHandler.removeCallbacks(mAcquireSleepTokenRunnable);
2625 mHandler.post(mReleaseSleepTokenRunnable);
2627 mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded;
2631 * @return Whether the top app should hide the statusbar based on the top fullscreen opaque
2634 private boolean topAppHidesStatusBar() {
2635 if (mTopFullscreenOpaqueWindowState == null) {
2638 final int fl = PolicyControl.getWindowFlags(null,
2639 mTopFullscreenOpaqueWindowState.getAttrs());
2641 Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw());
2642 Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs()
2643 + " lp.flags=0x" + Integer.toHexString(fl));
2645 return (fl & LayoutParams.FLAG_FULLSCREEN) != 0
2646 || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
2650 * Called when the user is switched.
2652 public void switchUser() {
2653 updateCurrentUserResources();
2657 * Called when the resource overlays change.
2659 public void onOverlayChangedLw() {
2660 updateCurrentUserResources();
2661 onConfigurationChanged();
2662 mSystemGestures.onConfigurationChanged();
2666 * Called when the configuration has changed, and it's safe to load new values from resources.
2668 public void onConfigurationChanged() {
2669 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation();
2671 final Resources res = getCurrentUserResources();
2672 final int portraitRotation = displayRotation.getPortraitRotation();
2673 final int upsideDownRotation = displayRotation.getUpsideDownRotation();
2674 final int landscapeRotation = displayRotation.getLandscapeRotation();
2675 final int seascapeRotation = displayRotation.getSeascapeRotation();
2676 final int uiMode = mService.mPolicy.getUiMode();
2678 if (hasStatusBar()) {
2679 mStatusBarHeightForRotation[portraitRotation] =
2680 mStatusBarHeightForRotation[upsideDownRotation] =
2681 res.getDimensionPixelSize(R.dimen.status_bar_height_portrait);
2682 mStatusBarHeightForRotation[landscapeRotation] =
2683 mStatusBarHeightForRotation[seascapeRotation] =
2684 res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
2686 mStatusBarHeightForRotation[portraitRotation] =
2687 mStatusBarHeightForRotation[upsideDownRotation] =
2688 mStatusBarHeightForRotation[landscapeRotation] =
2689 mStatusBarHeightForRotation[seascapeRotation] = 0;
2692 // Height of the navigation bar when presented horizontally at bottom
2693 mNavigationBarHeightForRotationDefault[portraitRotation] =
2694 mNavigationBarHeightForRotationDefault[upsideDownRotation] =
2695 res.getDimensionPixelSize(R.dimen.navigation_bar_height);
2696 mNavigationBarHeightForRotationDefault[landscapeRotation] =
2697 mNavigationBarHeightForRotationDefault[seascapeRotation] =
2698 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape);
2700 // Height of the navigation bar frame when presented horizontally at bottom
2701 mNavigationBarFrameHeightForRotationDefault[portraitRotation] =
2702 mNavigationBarFrameHeightForRotationDefault[upsideDownRotation] =
2703 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height);
2704 mNavigationBarFrameHeightForRotationDefault[landscapeRotation] =
2705 mNavigationBarFrameHeightForRotationDefault[seascapeRotation] =
2706 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height_landscape);
2708 // Width of the navigation bar when presented vertically along one side
2709 mNavigationBarWidthForRotationDefault[portraitRotation] =
2710 mNavigationBarWidthForRotationDefault[upsideDownRotation] =
2711 mNavigationBarWidthForRotationDefault[landscapeRotation] =
2712 mNavigationBarWidthForRotationDefault[seascapeRotation] =
2713 res.getDimensionPixelSize(R.dimen.navigation_bar_width);
2715 if (ALTERNATE_CAR_MODE_NAV_SIZE) {
2716 // Height of the navigation bar when presented horizontally at bottom
2717 mNavigationBarHeightForRotationInCarMode[portraitRotation] =
2718 mNavigationBarHeightForRotationInCarMode[upsideDownRotation] =
2719 res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode);
2720 mNavigationBarHeightForRotationInCarMode[landscapeRotation] =
2721 mNavigationBarHeightForRotationInCarMode[seascapeRotation] =
2722 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode);
2724 // Width of the navigation bar when presented vertically along one side
2725 mNavigationBarWidthForRotationInCarMode[portraitRotation] =
2726 mNavigationBarWidthForRotationInCarMode[upsideDownRotation] =
2727 mNavigationBarWidthForRotationInCarMode[landscapeRotation] =
2728 mNavigationBarWidthForRotationInCarMode[seascapeRotation] =
2729 res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
2732 mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
2733 mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset);
2734 mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough);
2735 mNavigationBarAlwaysShowOnSideGesture =
2736 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture);
2738 // This should calculate how much above the frame we accept gestures.
2739 mBottomGestureAdditionalInset =
2740 res.getDimensionPixelSize(R.dimen.navigation_bar_gesture_height)
2741 - getNavigationBarFrameHeight(portraitRotation, uiMode);
2743 updateConfigurationAndScreenSizeDependentBehaviors();
2744 mWindowOutsetBottom = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources());
2747 void updateConfigurationAndScreenSizeDependentBehaviors() {
2748 final Resources res = getCurrentUserResources();
2749 mNavigationBarCanMove =
2750 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
2751 && res.getBoolean(R.bool.config_navBarCanMove);
2752 mAllowSeamlessRotationDespiteNavBarMoving =
2753 res.getBoolean(R.bool.config_allowSeamlessRotationDespiteNavBarMoving);
2757 * Updates the current user's resources to pick up any changes for the current user (including
2760 private void updateCurrentUserResources() {
2761 final int userId = mService.mAmInternal.getCurrentUserId();
2762 final Context uiContext = getSystemUiContext();
2764 if (userId == UserHandle.USER_SYSTEM) {
2765 // Skip the (expensive) recreation of resources for the system user below and just
2766 // use the resources from the system ui context
2767 mCurrentUserResources = uiContext.getResources();
2771 // For non-system users, ensure that the resources are loaded from the current
2772 // user's package info (see ContextImpl.createDisplayContext)
2773 final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo(
2774 uiContext.getPackageName(), null, 0, userId);
2775 mCurrentUserResources = ResourcesManager.getInstance().getResources(null,
2777 null /* splitResDirs */,
2778 pi.getOverlayDirs(),
2779 pi.getApplicationInfo().sharedLibraryFiles,
2780 mDisplayContent.getDisplayId(),
2781 null /* overrideConfig */,
2782 uiContext.getResources().getCompatibilityInfo(),
2783 null /* classLoader */);
2787 Resources getCurrentUserResources() {
2788 if (mCurrentUserResources == null) {
2789 updateCurrentUserResources();
2791 return mCurrentUserResources;
2795 Context getContext() {
2799 private Context getSystemUiContext() {
2800 final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
2801 return mDisplayContent.isDefaultDisplay
2802 ? uiContext : uiContext.createDisplayContext(mDisplayContent.getDisplay());
2805 private int getNavigationBarWidth(int rotation, int uiMode) {
2806 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2807 return mNavigationBarWidthForRotationInCarMode[rotation];
2809 return mNavigationBarWidthForRotationDefault[rotation];
2813 void notifyDisplayReady() {
2814 mHandler.post(() -> {
2815 final int displayId = getDisplayId();
2816 getStatusBarManagerInternal().onDisplayReady(displayId);
2817 final WallpaperManagerInternal wpMgr = LocalServices
2818 .getService(WallpaperManagerInternal.class);
2819 if (wpMgr != null) {
2820 wpMgr.onDisplayReady(displayId);
2826 * Return the display width available after excluding any screen
2827 * decorations that could never be removed in Honeycomb. That is, system bar or
2830 public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2831 DisplayCutout displayCutout) {
2832 int width = fullWidth;
2833 if (hasNavigationBar()) {
2834 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2835 if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) {
2836 width -= getNavigationBarWidth(rotation, uiMode);
2839 if (displayCutout != null) {
2840 width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight();
2845 private int getNavigationBarHeight(int rotation, int uiMode) {
2846 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2847 return mNavigationBarHeightForRotationInCarMode[rotation];
2849 return mNavigationBarHeightForRotationDefault[rotation];
2854 * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that
2855 * is used for spacing to show additional buttons on the navigation bar (such as the ime
2856 * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible
2857 * height that we send to the app as content insets that can be smaller.
2859 * In car mode it will return the same height as {@link #getNavigationBarHeight}
2861 * @param rotation specifies rotation to return dimension from
2862 * @param uiMode to determine if in car mode
2863 * @return navigation bar frame height
2865 private int getNavigationBarFrameHeight(int rotation, int uiMode) {
2866 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {
2867 return mNavigationBarHeightForRotationInCarMode[rotation];
2869 return mNavigationBarFrameHeightForRotationDefault[rotation];
2874 * Return the display height available after excluding any screen
2875 * decorations that could never be removed in Honeycomb. That is, system bar or
2878 public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2879 DisplayCutout displayCutout) {
2880 int height = fullHeight;
2881 if (hasNavigationBar()) {
2882 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation);
2883 if (navBarPosition == NAV_BAR_BOTTOM) {
2884 height -= getNavigationBarHeight(rotation, uiMode);
2887 if (displayCutout != null) {
2888 height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom();
2894 * Return the available screen width that we should report for the
2895 * configuration. This must be no larger than
2896 * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller
2897 * than that to account for more transient decoration like a status bar.
2899 public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode,
2900 DisplayCutout displayCutout) {
2901 return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout);
2905 * Return the available screen height that we should report for the
2906 * configuration. This must be no larger than
2907 * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller
2908 * than that to account for more transient decoration like a status bar.
2910 public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode,
2911 DisplayCutout displayCutout) {
2912 // There is a separate status bar at the top of the display. We don't count that as part
2913 // of the fixed decor, since it can hide; however, for purposes of configurations,
2914 // we do want to exclude it since applications can't generally use that part
2916 int statusBarHeight = mStatusBarHeightForRotation[rotation];
2917 if (displayCutout != null) {
2918 // If there is a cutout, it may already have accounted for some part of the status
2920 statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
2922 return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout)
2927 * Return corner radius in pixels that should be used on windows in order to cover the display.
2928 * The radius is only valid for built-in displays since the one who configures window corner
2929 * radius cannot know the corner radius of non-built-in display.
2931 float getWindowCornerRadius() {
2932 return mDisplayContent.getDisplay().getType() == TYPE_BUILT_IN
2933 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f;
2936 boolean isShowingDreamLw() {
2937 return mShowingDream;
2941 * Calculates the stable insets if we already have the non-decor insets.
2943 * @param inOutInsets The known non-decor insets. It will be modified to stable insets.
2944 * @param rotation The current display rotation.
2946 void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) {
2947 inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]);
2951 * Calculates the stable insets without running a layout.
2953 * @param displayRotation the current display rotation
2954 * @param displayWidth the current display width
2955 * @param displayHeight the current display height
2956 * @param displayCutout the current display cutout
2957 * @param outInsets the insets to return
2959 public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2960 DisplayCutout displayCutout, Rect outInsets) {
2961 outInsets.setEmpty();
2963 // Navigation bar and status bar.
2964 getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
2965 convertNonDecorInsetsToStableInsets(outInsets, displayRotation);
2969 * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system
2970 * bar or button bar. See {@link #getNonDecorDisplayWidth}.
2972 * @param displayRotation the current display rotation
2973 * @param displayWidth the current display width
2974 * @param displayHeight the current display height
2975 * @param displayCutout the current display cutout
2976 * @param outInsets the insets to return
2978 public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight,
2979 DisplayCutout displayCutout, Rect outInsets) {
2980 outInsets.setEmpty();
2982 // Only navigation bar
2983 if (hasNavigationBar()) {
2984 final int uiMode = mService.mPolicy.getUiMode();
2985 int position = navigationBarPosition(displayWidth, displayHeight, displayRotation);
2986 if (position == NAV_BAR_BOTTOM) {
2987 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode);
2988 } else if (position == NAV_BAR_RIGHT) {
2989 outInsets.right = getNavigationBarWidth(displayRotation, uiMode);
2990 } else if (position == NAV_BAR_LEFT) {
2991 outInsets.left = getNavigationBarWidth(displayRotation, uiMode);
2995 if (displayCutout != null) {
2996 outInsets.left += displayCutout.getSafeInsetLeft();
2997 outInsets.top += displayCutout.getSafeInsetTop();
2998 outInsets.right += displayCutout.getSafeInsetRight();
2999 outInsets.bottom += displayCutout.getSafeInsetBottom();
3004 * @see IWindowManager#setForwardedInsets
3006 public void setForwardedInsets(@NonNull Insets forwardedInsets) {
3007 mForwardedInsets = forwardedInsets;
3011 public Insets getForwardedInsets() {
3012 return mForwardedInsets;
3015 @NavigationBarPosition
3016 int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
3017 if (navigationBarCanMove() && displayWidth > displayHeight) {
3018 if (displayRotation == Surface.ROTATION_270) {
3019 return NAV_BAR_LEFT;
3020 } else if (displayRotation == Surface.ROTATION_90) {
3021 return NAV_BAR_RIGHT;
3024 return NAV_BAR_BOTTOM;
3028 * @return The side of the screen where navigation bar is positioned.
3029 * @see WindowManagerPolicyConstants#NAV_BAR_LEFT
3030 * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT
3031 * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM
3033 @NavigationBarPosition
3034 public int getNavBarPosition() {
3035 return mNavigationBarPosition;
3039 * A new window has been focused.
3041 public int focusChangedLw(WindowState lastFocus, WindowState newFocus) {
3042 mFocusedWindow = newFocus;
3043 mLastFocusedWindow = lastFocus;
3044 if (mDisplayContent.isDefaultDisplay) {
3045 mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus);
3047 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) {
3048 // If the navigation bar has been hidden or shown, we need to do another
3049 // layout pass to update that window.
3050 return FINISH_LAYOUT_REDO_LAYOUT;
3056 * Return true if it is okay to perform animations for an app transition
3057 * that is about to occur. You may return false for this if, for example,
3058 * the dream window is currently displayed so the switch should happen
3061 public boolean allowAppAnimationsLw() {
3062 return !mShowingDream;
3065 private void updateDreamingSleepToken(boolean acquire) {
3067 final int displayId = getDisplayId();
3068 if (mDreamingSleepToken == null) {
3069 mDreamingSleepToken = mService.mAtmInternal.acquireSleepToken(
3070 "DreamOnDisplay" + displayId, displayId);
3073 if (mDreamingSleepToken != null) {
3074 mDreamingSleepToken.release();
3075 mDreamingSleepToken = null;
3080 private void requestTransientBars(WindowState swipeTarget) {
3081 synchronized (mLock) {
3082 if (!mService.mPolicy.isUserSetupComplete()) {
3083 // Swipe-up for navigation bar is disabled during setup
3086 boolean sb = mStatusBarController.checkShowTransientBarLw();
3087 boolean nb = mNavigationBarController.checkShowTransientBarLw()
3088 && !isNavBarEmpty(mLastSystemUiFlags);
3090 // Don't show status bar when swiping on already visible navigation bar
3091 if (!nb && swipeTarget == mNavigationBar) {
3092 if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
3095 if (sb) mStatusBarController.showTransient();
3096 if (nb) mNavigationBarController.showTransient();
3097 mImmersiveModeConfirmation.confirmCurrentPrompt();
3098 updateSystemUiVisibilityLw();
3103 private void disposeInputConsumer(InputConsumer inputConsumer) {
3104 if (inputConsumer != null) {
3105 inputConsumer.dismiss();
3109 private boolean isStatusBarKeyguard() {
3110 return mStatusBar != null
3111 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;
3114 private boolean isKeyguardOccluded() {
3115 // TODO (b/113840485): Handle per display keyguard.
3116 return mService.mPolicy.isKeyguardOccluded();
3119 void resetSystemUiVisibilityLw() {
3120 mLastSystemUiFlags = 0;
3121 updateSystemUiVisibilityLw();
3124 private int updateSystemUiVisibilityLw() {
3125 // If there is no window focused, there will be nobody to handle the events
3126 // anyway, so just hang on in whatever state we're in until things settle down.
3127 WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow
3128 : mTopFullscreenOpaqueWindowState;
3129 if (winCandidate == null) {
3133 // The immersive mode confirmation should never affect the system bar visibility, otherwise
3134 // it will unhide the navigation bar and hide itself.
3135 if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) {
3137 // The immersive mode confirmation took the focus from mLastFocusedWindow which was
3138 // controlling the system ui visibility. So if mLastFocusedWindow can still receive
3139 // keys, we let it keep controlling the visibility.
3140 final boolean lastFocusCanReceiveKeys =
3141 (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys());
3142 winCandidate = isStatusBarKeyguard() ? mStatusBar
3143 : lastFocusCanReceiveKeys ? mLastFocusedWindow
3144 : mTopFullscreenOpaqueWindowState;
3145 if (winCandidate == null) {
3149 final WindowState win = winCandidate;
3150 if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && isKeyguardOccluded()) {
3151 // We are updating at a point where the keyguard has gotten
3152 // focus, but we were last in a state where the top window is
3153 // hiding it. This is probably because the keyguard as been
3154 // shown while the top window was displayed, so we want to ignore
3155 // it here because this is just a very transient change and it
3156 // will quickly lose focus once it correctly gets hidden.
3160 mDisplayContent.getInsetsStateController().onBarControllingWindowChanged(
3161 mTopFullscreenOpaqueWindowState);
3163 int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null)
3164 & ~mResettingSystemUiFlags
3165 & ~mForceClearedSystemUiFlags;
3166 if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
3168 &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
3171 final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
3172 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
3173 final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
3174 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState);
3175 mService.getStackBounds(
3176 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds);
3177 mService.getStackBounds(
3178 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds);
3179 final Pair<Integer, Boolean> result =
3180 updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
3181 final int visibility = result.first;
3182 final int diff = visibility ^ mLastSystemUiFlags;
3183 final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags;
3184 final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags;
3185 final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
3186 if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu
3187 && mFocusedApp == win.getAppToken()
3188 && mLastNonDockedStackBounds.equals(mNonDockedStackBounds)
3189 && mLastDockedStackBounds.equals(mDockedStackBounds)) {
3192 mLastSystemUiFlags = visibility;
3193 mLastFullscreenStackSysUiFlags = fullscreenVisibility;
3194 mLastDockedStackSysUiFlags = dockedVisibility;
3195 mLastFocusNeedsMenu = needsMenu;
3196 mFocusedApp = win.getAppToken();
3197 mLastNonDockedStackBounds.set(mNonDockedStackBounds);
3198 mLastDockedStackBounds.set(mDockedStackBounds);
3199 final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
3200 final Rect dockedStackBounds = new Rect(mDockedStackBounds);
3201 final boolean isNavbarColorManagedByIme = result.second;
3202 mHandler.post(() -> {
3203 StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
3204 if (statusBar != null) {
3205 final int displayId = getDisplayId();
3206 statusBar.setSystemUiVisibility(displayId, visibility, fullscreenVisibility,
3207 dockedVisibility, 0xffffffff, fullscreenStackBounds,
3208 dockedStackBounds, isNavbarColorManagedByIme, win.toString());
3209 statusBar.topAppWindowChanged(displayId, needsMenu);
3215 private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) {
3216 final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded();
3217 final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming;
3218 if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) {
3219 // If the top fullscreen-or-dimming window is also the top fullscreen, respect
3221 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3222 vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
3223 & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3224 } else if (statusColorWin != null && statusColorWin.isDimming()) {
3225 // Otherwise if it's dimming, clear the light flag.
3226 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3233 static WindowState chooseNavigationColorWindowLw(WindowState opaque,
3234 WindowState opaqueOrDimming, WindowState imeWindow,
3235 @NavigationBarPosition int navBarPosition) {
3236 // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME
3237 // window can be navigation color window.
3238 final boolean imeWindowCanNavColorWindow = imeWindow != null
3239 && imeWindow.isVisibleLw()
3240 && navBarPosition == NAV_BAR_BOTTOM
3241 && (PolicyControl.getWindowFlags(imeWindow, null)
3242 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3244 if (opaque != null && opaqueOrDimming == opaque) {
3245 // If the top fullscreen-or-dimming window is also the top fullscreen, respect it
3246 // unless IME window is also eligible, since currently the IME window is always show
3247 // above the opaque fullscreen app window, regardless of the IME target window.
3248 // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed.
3249 return imeWindowCanNavColorWindow ? imeWindow : opaque;
3252 if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) {
3253 // No dimming window is involved. Determine the result only with the IME window.
3254 return imeWindowCanNavColorWindow ? imeWindow : null;
3257 if (!imeWindowCanNavColorWindow) {
3258 // No IME window is involved. Determine the result only with opaqueOrDimming.
3259 return opaqueOrDimming;
3262 // The IME window and the dimming window are competing. Check if the dimming window can be
3263 // IME target or not.
3264 if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) {
3265 // The IME window is above the dimming window.
3268 // The dimming window is above the IME window.
3269 return opaqueOrDimming;
3274 static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming,
3275 WindowState imeWindow, WindowState navColorWin) {
3277 if (navColorWin != null) {
3278 if (navColorWin == imeWindow || navColorWin == opaque) {
3279 // Respect the light flag.
3280 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3281 vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
3282 & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3283 } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) {
3284 // Clear the light flag for dimming window.
3285 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
3291 private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) {
3292 final boolean dockedStackVisible =
3293 mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
3294 final boolean freeformStackVisible =
3295 mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM);
3296 final boolean resizing = mDisplayContent.getDockedDividerController().isResizing();
3298 // We need to force system bars when the docked stack is visible, when the freeform stack
3299 // is visible but also when we are resizing for the transitions when docked stack
3300 // visibility changes.
3301 mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing
3302 || mForceShowSystemBarsFromExternal;
3303 final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard;
3305 // apply translucent bar vis flags
3306 WindowState fullscreenTransWin = isStatusBarKeyguard() && !isKeyguardOccluded()
3308 : mTopFullscreenOpaqueWindowState;
3309 vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3310 vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis);
3311 int dockedVis = mStatusBarController.applyTranslucentFlagLw(
3312 mTopDockedOpaqueWindowState, 0, 0);
3313 dockedVis = mNavigationBarController.applyTranslucentFlagLw(
3314 mTopDockedOpaqueWindowState, dockedVis, 0);
3316 final boolean fullscreenDrawsStatusBarBackground =
3317 drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState);
3318 final boolean dockedDrawsStatusBarBackground =
3319 drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState);
3320 final boolean fullscreenDrawsNavBarBackground =
3321 drawsNavigationBarBackground(vis, mTopFullscreenOpaqueWindowState);
3322 final boolean dockedDrawsNavigationBarBackground =
3323 drawsNavigationBarBackground(dockedVis, mTopDockedOpaqueWindowState);
3325 // prevent status bar interaction from clearing certain flags
3326 int type = win.getAttrs().type;
3327 boolean statusBarHasFocus = type == TYPE_STATUS_BAR;
3328 if (statusBarHasFocus && !isStatusBarKeyguard()) {
3329 int flags = View.SYSTEM_UI_FLAG_FULLSCREEN
3330 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
3331 | View.SYSTEM_UI_FLAG_IMMERSIVE
3332 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
3333 | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
3334 if (isKeyguardOccluded()) {
3335 flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT;
3337 vis = (vis & ~flags) | (oldVis & flags);
3340 if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) {
3341 vis |= View.STATUS_BAR_TRANSPARENT;
3342 vis &= ~View.STATUS_BAR_TRANSLUCENT;
3343 } else if (forceOpaqueStatusBar) {
3344 vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT);
3347 vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing,
3348 fullscreenDrawsNavBarBackground, dockedDrawsNavigationBarBackground);
3350 // update status bar
3351 boolean immersiveSticky =
3352 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3353 final boolean hideStatusBarWM =
3354 mTopFullscreenOpaqueWindowState != null
3355 && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null)
3356 & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0;
3357 final boolean hideStatusBarSysui =
3358 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
3359 final boolean hideNavBarSysui =
3360 (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;
3362 final boolean transientStatusBarAllowed = mStatusBar != null
3363 && (statusBarHasFocus || (!mForceShowSystemBars
3364 && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky))));
3366 final boolean transientNavBarAllowed = mNavigationBar != null
3367 && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky;
3369 final long now = SystemClock.uptimeMillis();
3370 final boolean pendingPanic = mPendingPanicGestureUptime != 0
3371 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION;
3372 final DisplayPolicy defaultDisplayPolicy =
3373 mService.getDefaultDisplayContentLocked().getDisplayPolicy();
3374 if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard()
3375 // TODO (b/111955725): Show keyguard presentation on all external displays
3376 && defaultDisplayPolicy.isKeyguardDrawComplete()) {
3377 // The user performed the panic gesture recently, we're about to hide the bars,
3378 // we're no longer on the Keyguard and the screen is ready. We can now request the bars.
3379 mPendingPanicGestureUptime = 0;
3380 mStatusBarController.showTransient();
3381 if (!isNavBarEmpty(vis)) {
3382 mNavigationBarController.showTransient();
3386 final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested()
3387 && !transientStatusBarAllowed && hideStatusBarSysui;
3388 final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested()
3389 && !transientNavBarAllowed;
3390 if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) {
3391 // clear the clearable flags instead
3392 clearClearableFlagsLw();
3393 vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS;
3396 final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0;
3397 immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0;
3398 final boolean navAllowedHidden = immersive || immersiveSticky;
3400 if (hideNavBarSysui && !navAllowedHidden
3401 && mService.mPolicy.getWindowLayerLw(win)
3402 > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) {
3403 // We can't hide the navbar from this window otherwise the input consumer would not get
3404 // the input events.
3405 vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
3408 vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis);
3410 // update navigation bar
3411 boolean oldImmersiveMode = isImmersiveMode(oldVis);
3412 boolean newImmersiveMode = isImmersiveMode(vis);
3413 if (oldImmersiveMode != newImmersiveMode) {
3414 final String pkg = win.getOwningPackage();
3415 mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode,
3416 mService.mPolicy.isUserSetupComplete(),
3417 isNavBarEmpty(win.getSystemUiVisibility()));
3420 vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis);
3422 final WindowState navColorWin = chooseNavigationColorWindowLw(
3423 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState,
3424 mDisplayContent.mInputMethodWindow, mNavigationBarPosition);
3425 vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState,
3426 mTopFullscreenOpaqueOrDimmingWindowState,
3427 mDisplayContent.mInputMethodWindow, navColorWin);
3428 // Navbar color is controlled by the IME.
3429 final boolean isManagedByIme =
3430 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow;
3432 return Pair.create(vis, isManagedByIme);
3435 private boolean drawsBarBackground(int vis, WindowState win, BarController controller,
3436 int translucentFlag) {
3437 if (!controller.isTransparentAllowed(win)) {
3444 final boolean drawsSystemBars =
3445 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0;
3446 final boolean forceDrawsSystemBars =
3447 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
3449 return forceDrawsSystemBars || drawsSystemBars && (vis & translucentFlag) == 0;
3452 private boolean drawsStatusBarBackground(int vis, WindowState win) {
3453 return drawsBarBackground(vis, win, mStatusBarController, FLAG_TRANSLUCENT_STATUS);
3456 private boolean drawsNavigationBarBackground(int vis, WindowState win) {
3457 return drawsBarBackground(vis, win, mNavigationBarController, FLAG_TRANSLUCENT_NAVIGATION);
3461 * @return the current visibility flags with the nav-bar opacity related flags toggled based
3462 * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}.
3464 private int configureNavBarOpacity(int visibility, boolean dockedStackVisible,
3465 boolean freeformStackVisible, boolean isDockedDividerResizing,
3466 boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground) {
3467 if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) {
3468 if (fullscreenDrawsBackground && dockedDrawsNavigationBarBackground) {
3469 visibility = setNavBarTransparentFlag(visibility);
3470 } else if (dockedStackVisible) {
3471 visibility = setNavBarOpaqueFlag(visibility);
3473 } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) {
3474 if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) {
3475 visibility = setNavBarOpaqueFlag(visibility);
3476 } else if (fullscreenDrawsBackground) {
3477 visibility = setNavBarTransparentFlag(visibility);
3479 } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) {
3480 if (isDockedDividerResizing) {
3481 visibility = setNavBarOpaqueFlag(visibility);
3482 } else if (freeformStackVisible) {
3483 visibility = setNavBarTranslucentFlag(visibility);
3485 visibility = setNavBarOpaqueFlag(visibility);
3492 private int setNavBarOpaqueFlag(int visibility) {
3493 return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
3496 private int setNavBarTranslucentFlag(int visibility) {
3497 visibility &= ~View.NAVIGATION_BAR_TRANSPARENT;
3498 return visibility | View.NAVIGATION_BAR_TRANSLUCENT;
3501 private int setNavBarTransparentFlag(int visibility) {
3502 visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT;
3503 return visibility | View.NAVIGATION_BAR_TRANSPARENT;
3506 private void clearClearableFlagsLw() {
3507 int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS;
3508 if (newVal != mResettingSystemUiFlags) {
3509 mResettingSystemUiFlags = newVal;
3510 mDisplayContent.reevaluateStatusBarVisibility();
3514 private boolean isImmersiveMode(int vis) {
3515 final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
3516 return mNavigationBar != null
3517 && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
3518 && (vis & flags) != 0
3519 && canHideNavigationBar();
3523 * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar
3525 private boolean canHideNavigationBar() {
3526 return hasNavigationBar();
3529 private static boolean isNavBarEmpty(int systemUiFlags) {
3530 final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME
3531 | View.STATUS_BAR_DISABLE_BACK
3532 | View.STATUS_BAR_DISABLE_RECENT);
3534 return (systemUiFlags & disableNavigationBar) == disableNavigationBar;
3537 boolean shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation,
3539 // For the upside down rotation we don't rotate seamlessly as the navigation
3540 // bar moves position.
3541 // Note most apps (using orientation:sensor or user as opposed to fullSensor)
3542 // will not enter the reverse portrait orientation, so actually the
3543 // orientation won't change at all.
3544 if (oldRotation == displayRotation.getUpsideDownRotation()
3545 || newRotation == displayRotation.getUpsideDownRotation()) {
3548 // If the navigation bar can't change sides, then it will
3549 // jump when we change orientations and we don't rotate
3550 // seamlessly - unless that is allowed, eg. with gesture
3551 // navigation where the navbar is low-profile enough that this isn't very noticeable.
3552 if (!navigationBarCanMove() && !mAllowSeamlessRotationDespiteNavBarMoving) {
3556 final WindowState w = mTopFullscreenOpaqueWindowState;
3557 if (w == null || w != mFocusedWindow) {
3560 // If the bounds of activity window is different from its parent, then reject to be seamless
3561 // because the window position may change after rotation that will look like a sudden jump.
3562 if (w.mAppToken != null && !w.mAppToken.matchParentBounds()) {
3566 // We only enable seamless rotation if the top window has requested
3567 // it and is in the fullscreen opaque state. Seamless rotation
3568 // requires freezing various Surface states and won't work well
3569 // with animations, so we disable it in the animation case for now.
3570 if (!w.isAnimatingLw() && w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS) {
3576 private final Runnable mHiddenNavPanic = new Runnable() {
3579 synchronized (mLock) {
3580 if (!mService.mPolicy.isUserSetupComplete()) {
3581 // Swipe-up for navigation bar is disabled during setup
3584 mPendingPanicGestureUptime = SystemClock.uptimeMillis();
3585 if (!isNavBarEmpty(mLastSystemUiFlags)) {
3586 mNavigationBarController.showTransient();
3592 void onPowerKeyDown(boolean isScreenOn) {
3593 // Detect user pressing the power button in panic when an application has
3594 // taken over the whole screen.
3595 boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn,
3596 SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags),
3597 isNavBarEmpty(mLastSystemUiFlags));
3599 mHandler.post(mHiddenNavPanic);
3603 void onVrStateChangedLw(boolean enabled) {
3604 mImmersiveModeConfirmation.onVrStateChangedLw(enabled);
3608 * Called when the state of lock task mode changes. This should be used to disable immersive
3609 * mode confirmation.
3611 * @param lockTaskState the new lock task mode state. One of
3612 * {@link ActivityManager#LOCK_TASK_MODE_NONE},
3613 * {@link ActivityManager#LOCK_TASK_MODE_LOCKED},
3614 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}.
3616 public void onLockTaskStateChangedLw(int lockTaskState) {
3617 mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState);
3621 * Request a screenshot be taken.
3623 * @param screenshotType The type of screenshot, for example either
3624 * {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or
3625 * {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION}
3627 public void takeScreenshot(int screenshotType) {
3628 if (mScreenshotHelper != null) {
3629 mScreenshotHelper.takeScreenshot(screenshotType,
3630 mStatusBar != null && mStatusBar.isVisibleLw(),
3631 mNavigationBar != null && mNavigationBar.isVisibleLw(),
3632 mHandler, null /* completionConsumer */);
3636 RefreshRatePolicy getRefreshRatePolicy() {
3637 return mRefreshRatePolicy;
3640 void dump(String prefix, PrintWriter pw) {
3641 pw.print(prefix); pw.print("DisplayPolicy");
3644 pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer);
3645 pw.print(" mDeskDockEnablesAccelerometer=");
3646 pw.println(mDeskDockEnablesAccelerometer);
3647 pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode));
3648 pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState));
3649 pw.print(prefix); pw.print("mAwake="); pw.print(mAwake);
3650 pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly);
3651 pw.print(" mScreenOnFully="); pw.println(mScreenOnFully);
3652 pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete);
3653 pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete);
3654 pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged);
3655 if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0
3656 || mForceClearedSystemUiFlags != 0) {
3657 pw.print(prefix); pw.print("mLastSystemUiFlags=0x");
3658 pw.print(Integer.toHexString(mLastSystemUiFlags));
3659 pw.print(" mResettingSystemUiFlags=0x");
3660 pw.print(Integer.toHexString(mResettingSystemUiFlags));
3661 pw.print(" mForceClearedSystemUiFlags=0x");
3662 pw.println(Integer.toHexString(mForceClearedSystemUiFlags));
3664 if (mLastFocusNeedsMenu) {
3665 pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu);
3667 pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream);
3668 pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen);
3669 pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken);
3670 if (mStatusBar != null) {
3671 pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar);
3672 pw.print(" isStatusBarKeyguard="); pw.println(isStatusBarKeyguard());
3674 if (mNavigationBar != null) {
3675 pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
3676 pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
3677 pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove);
3678 pw.print(prefix); pw.print("mNavigationBarPosition=");
3679 pw.println(mNavigationBarPosition);
3681 if (mFocusedWindow != null) {
3682 pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
3684 if (mFocusedApp != null) {
3685 pw.print(prefix); pw.print("mFocusedApp="); pw.println(mFocusedApp);
3687 if (mTopFullscreenOpaqueWindowState != null) {
3688 pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
3689 pw.println(mTopFullscreenOpaqueWindowState);
3691 if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
3692 pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
3693 pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
3695 if (mForcingShowNavBar) {
3696 pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar);
3697 pw.print(prefix); pw.print("mForcingShowNavBarLayer=");
3698 pw.println(mForcingShowNavBarLayer);
3700 pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen);
3701 pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar);
3702 pw.print(" mForceStatusBarFromKeyguard="); pw.println(mForceStatusBarFromKeyguard);
3703 pw.print(" mForceShowSystemBarsFromExternal=");
3704 pw.println(mForceShowSystemBarsFromExternal);
3705 pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn);
3706 mStatusBarController.dump(pw, prefix);
3707 mNavigationBarController.dump(pw, prefix);
3709 pw.print(prefix); pw.println("Looper state:");
3710 mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " ");
3713 private boolean supportsPointerLocation() {
3714 return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate();
3717 void setPointerLocationEnabled(boolean pointerLocationEnabled) {
3718 if (!supportsPointerLocation()) {
3722 mHandler.sendEmptyMessage(pointerLocationEnabled
3723 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION);
3726 private void enablePointerLocation() {
3727 if (mPointerLocationView != null) {
3731 mPointerLocationView = new PointerLocationView(mContext);
3732 mPointerLocationView.setPrintCoords(false);
3733 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
3734 WindowManager.LayoutParams.MATCH_PARENT,
3735 WindowManager.LayoutParams.MATCH_PARENT);
3736 lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY;
3737 lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN
3738 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
3739 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
3740 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
3741 lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
3742 if (ActivityManager.isHighEndGfx()) {
3743 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
3745 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
3747 lp.format = PixelFormat.TRANSLUCENT;
3748 lp.setTitle("PointerLocation - display " + getDisplayId());
3749 lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
3750 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3751 wm.addView(mPointerLocationView, lp);
3752 mDisplayContent.registerPointerEventListener(mPointerLocationView);
3755 private void disablePointerLocation() {
3756 if (mPointerLocationView == null) {
3760 mDisplayContent.unregisterPointerEventListener(mPointerLocationView);
3761 final WindowManager wm = mContext.getSystemService(WindowManager.class);
3762 wm.removeView(mPointerLocationView);
3763 mPointerLocationView = null;