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