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