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.util.RotationUtils.deltaRotation; 28 import static android.util.RotationUtils.rotateBounds; 29 import static android.view.Display.TYPE_INTERNAL; 30 import static android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES; 31 import static android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT; 32 import static android.view.InsetsState.ITYPE_CAPTION_BAR; 33 import static android.view.InsetsState.ITYPE_CLIMATE_BAR; 34 import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; 35 import static android.view.InsetsState.ITYPE_IME; 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_GESTURES; 39 import static android.view.InsetsState.ITYPE_STATUS_BAR; 40 import static android.view.InsetsState.ITYPE_TOP_MANDATORY_GESTURES; 41 import static android.view.InsetsState.ITYPE_TOP_TAPPABLE_ELEMENT; 42 import static android.view.ViewRootImpl.computeWindowBounds; 43 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; 44 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; 45 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; 46 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS; 47 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS; 48 import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; 49 import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; 50 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 51 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW; 52 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; 53 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; 54 import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; 55 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; 56 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 57 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; 58 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 59 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 60 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT; 61 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 62 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS; 63 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; 64 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME; 65 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP; 66 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; 67 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 68 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 69 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; 70 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; 71 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; 72 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; 73 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; 74 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; 75 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; 76 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL; 77 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; 78 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; 79 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 80 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; 81 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING; 82 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 83 import static android.view.WindowManagerGlobal.ADD_OKAY; 84 import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED; 85 import static android.view.WindowManagerPolicyConstants.ALT_BAR_BOTTOM; 86 import static android.view.WindowManagerPolicyConstants.ALT_BAR_LEFT; 87 import static android.view.WindowManagerPolicyConstants.ALT_BAR_RIGHT; 88 import static android.view.WindowManagerPolicyConstants.ALT_BAR_TOP; 89 import static android.view.WindowManagerPolicyConstants.ALT_BAR_UNKNOWN; 90 import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE; 91 import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM; 92 import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID; 93 import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT; 94 import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT; 95 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; 96 97 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON; 98 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT; 99 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; 100 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER; 101 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT; 102 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_HIDE; 103 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE; 104 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_SHOW; 105 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; 106 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; 107 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; 108 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 109 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 110 111 import android.Manifest.permission; 112 import android.annotation.NonNull; 113 import android.annotation.Nullable; 114 import android.annotation.Px; 115 import android.app.ActivityManager; 116 import android.app.ActivityThread; 117 import android.app.LoadedApk; 118 import android.app.ResourcesManager; 119 import android.content.Context; 120 import android.content.Intent; 121 import android.content.pm.PackageManager; 122 import android.content.res.Resources; 123 import android.graphics.Insets; 124 import android.graphics.PixelFormat; 125 import android.graphics.Rect; 126 import android.graphics.Region; 127 import android.hardware.power.Boost; 128 import android.os.Handler; 129 import android.os.IBinder; 130 import android.os.Looper; 131 import android.os.Message; 132 import android.os.SystemClock; 133 import android.os.SystemProperties; 134 import android.os.UserHandle; 135 import android.util.PrintWriterPrinter; 136 import android.util.Slog; 137 import android.util.SparseArray; 138 import android.view.DisplayCutout; 139 import android.view.DisplayInfo; 140 import android.view.Gravity; 141 import android.view.InsetsFlags; 142 import android.view.InsetsSource; 143 import android.view.InsetsState; 144 import android.view.InsetsState.InternalInsetsType; 145 import android.view.Surface; 146 import android.view.View; 147 import android.view.ViewDebug; 148 import android.view.WindowInsets.Type; 149 import android.view.WindowInsets.Type.InsetsType; 150 import android.view.WindowManager; 151 import android.view.WindowManager.LayoutParams; 152 import android.view.WindowManagerGlobal; 153 import android.view.WindowManagerPolicyConstants; 154 import android.view.accessibility.AccessibilityManager; 155 156 import com.android.internal.R; 157 import com.android.internal.annotations.VisibleForTesting; 158 import com.android.internal.policy.GestureNavigationSettingsObserver; 159 import com.android.internal.policy.ScreenDecorationsUtils; 160 import com.android.internal.protolog.common.ProtoLog; 161 import com.android.internal.util.ScreenshotHelper; 162 import com.android.internal.util.function.TriConsumer; 163 import com.android.internal.view.AppearanceRegion; 164 import com.android.internal.widget.PointerLocationView; 165 import com.android.server.LocalServices; 166 import com.android.server.UiThread; 167 import com.android.server.policy.WindowManagerPolicy; 168 import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition; 169 import com.android.server.policy.WindowManagerPolicy.ScreenOnListener; 170 import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs; 171 import com.android.server.statusbar.StatusBarManagerInternal; 172 import com.android.server.wallpaper.WallpaperManagerInternal; 173 import com.android.server.wm.InputMonitor.EventReceiverInputConsumer; 174 175 import java.io.PrintWriter; 176 import java.util.function.Consumer; 177 178 /** 179 * The policy that provides the basic behaviors and states of a display to show UI. 180 */ 181 public class DisplayPolicy { 182 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM; 183 184 private static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false; 185 186 // The panic gesture may become active only after the keyguard is dismissed and the immersive 187 // app shows again. If that doesn't happen for 30s we drop the gesture. 188 private static final long PANIC_GESTURE_EXPIRATION = 30000; 189 190 // Controls navigation bar opacity depending on which workspace root tasks are currently 191 // visible. 192 // Nav bar is always opaque when either the freeform root task or docked root task is visible. 193 private static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0; 194 // Nav bar is always translucent when the freeform rootTask is visible, otherwise always opaque. 195 private static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1; 196 // Nav bar is never forced opaque. 197 private static final int NAV_BAR_FORCE_TRANSPARENT = 2; 198 199 /** Don't apply window animation (see {@link #selectAnimation}). */ 200 static final int ANIMATION_NONE = -1; 201 /** Use the transit animation in style resource (see {@link #selectAnimation}). */ 202 static final int ANIMATION_STYLEABLE = 0; 203 204 private static final int[] SHOW_TYPES_FOR_SWIPE = {ITYPE_NAVIGATION_BAR, ITYPE_STATUS_BAR, 205 ITYPE_CLIMATE_BAR, ITYPE_EXTRA_NAVIGATION_BAR}; 206 private static final int[] SHOW_TYPES_FOR_PANIC = {ITYPE_NAVIGATION_BAR}; 207 208 private final WindowManagerService mService; 209 private final Context mContext; 210 private final Context mUiContext; 211 private final DisplayContent mDisplayContent; 212 private final Object mLock; 213 private final Handler mHandler; 214 215 private Resources mCurrentUserResources; 216 217 private final boolean mCarDockEnablesAccelerometer; 218 private final boolean mDeskDockEnablesAccelerometer; 219 private final AccessibilityManager mAccessibilityManager; 220 private final ImmersiveModeConfirmation mImmersiveModeConfirmation; 221 private final ScreenshotHelper mScreenshotHelper; 222 223 private final Object mServiceAcquireLock = new Object(); 224 private StatusBarManagerInternal mStatusBarManagerInternal; 225 226 @Px 227 private int mBottomGestureAdditionalInset; 228 @Px 229 private int mLeftGestureInset; 230 @Px 231 private int mRightGestureInset; 232 233 private boolean mNavButtonForcedVisible; 234 getStatusBarManagerInternal()235 StatusBarManagerInternal getStatusBarManagerInternal() { 236 synchronized (mServiceAcquireLock) { 237 if (mStatusBarManagerInternal == null) { 238 mStatusBarManagerInternal = 239 LocalServices.getService(StatusBarManagerInternal.class); 240 } 241 return mStatusBarManagerInternal; 242 } 243 } 244 245 private final SystemGesturesPointerEventListener mSystemGestures; 246 247 private volatile int mLidState = LID_ABSENT; 248 private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; 249 private volatile boolean mHdmiPlugged; 250 251 private volatile boolean mHasStatusBar; 252 private volatile boolean mHasNavigationBar; 253 // Can the navigation bar ever move to the side? 254 private volatile boolean mNavigationBarCanMove; 255 private volatile boolean mNavigationBarLetsThroughTaps; 256 private volatile boolean mNavigationBarAlwaysShowOnSideGesture; 257 258 // Written by vr manager thread, only read in this class. 259 private volatile boolean mPersistentVrModeEnabled; 260 261 private volatile boolean mAwake; 262 private volatile boolean mScreenOnEarly; 263 private volatile boolean mScreenOnFully; 264 private volatile ScreenOnListener mScreenOnListener; 265 266 private volatile boolean mKeyguardDrawComplete; 267 private volatile boolean mWindowManagerDrawComplete; 268 269 private WindowState mStatusBar = null; 270 private WindowState mNotificationShade = null; 271 private final int[] mStatusBarHeightForRotation = new int[4]; 272 private WindowState mNavigationBar = null; 273 @NavigationBarPosition 274 private int mNavigationBarPosition = NAV_BAR_BOTTOM; 275 private int[] mNavigationBarHeightForRotationDefault = new int[4]; 276 private int[] mNavigationBarWidthForRotationDefault = new int[4]; 277 private int[] mNavigationBarHeightForRotationInCarMode = new int[4]; 278 private int[] mNavigationBarWidthForRotationInCarMode = new int[4]; 279 280 // Alternative status bar for when flexible insets mapping is used to place the status bar on 281 // another side of the screen. 282 private WindowState mStatusBarAlt = null; 283 @WindowManagerPolicy.AltBarPosition 284 private int mStatusBarAltPosition = ALT_BAR_UNKNOWN; 285 // Alternative navigation bar for when flexible insets mapping is used to place the navigation 286 // bar elsewhere on the screen. 287 private WindowState mNavigationBarAlt = null; 288 @WindowManagerPolicy.AltBarPosition 289 private int mNavigationBarAltPosition = ALT_BAR_UNKNOWN; 290 // Alternative climate bar for when flexible insets mapping is used to place a climate bar on 291 // the screen. 292 private WindowState mClimateBarAlt = null; 293 @WindowManagerPolicy.AltBarPosition 294 private int mClimateBarAltPosition = ALT_BAR_UNKNOWN; 295 // Alternative extra nav bar for when flexible insets mapping is used to place an extra nav bar 296 // on the screen. 297 private WindowState mExtraNavBarAlt = null; 298 @WindowManagerPolicy.AltBarPosition 299 private int mExtraNavBarAltPosition = ALT_BAR_UNKNOWN; 300 301 /** See {@link #getNavigationBarFrameHeight} */ 302 private int[] mNavigationBarFrameHeightForRotationDefault = new int[4]; 303 304 private boolean mIsFreeformWindowOverlappingWithNavBar; 305 306 private boolean mLastImmersiveMode; 307 308 private final SparseArray<Rect> mBarContentFrames = new SparseArray<>(); 309 310 // The windows we were told about in focusChanged. 311 private WindowState mFocusedWindow; 312 private WindowState mLastFocusedWindow; 313 314 private WindowState mSystemUiControllingWindow; 315 316 private int mLastDisableFlags; 317 private int mLastAppearance; 318 private int mLastFullscreenAppearance; 319 private int mLastDockedAppearance; 320 private int mLastBehavior; 321 private final Rect mNonDockedRootTaskBounds = new Rect(); 322 private final Rect mDockedRootTaskBounds = new Rect(); 323 private final Rect mLastNonDockedRootTaskBounds = new Rect(); 324 private final Rect mLastDockedRootTaskBounds = new Rect(); 325 326 // What we last reported to system UI about whether the focused window is fullscreen/immersive. 327 private boolean mLastFocusIsFullscreen = false; 328 329 // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending. 330 private long mPendingPanicGestureUptime; 331 332 private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect(); 333 private static final Rect sTmpRect = new Rect(); 334 private static final Rect sTmpNavFrame = new Rect(); 335 private static final Rect sTmpStatusFrame = new Rect(); 336 private static final Rect sTmpScreenDecorFrame = new Rect(); 337 private static final Rect sTmpLastParentFrame = new Rect(); 338 private static final Rect sTmpDisplayFrameBounds = new Rect(); 339 340 private WindowState mTopFullscreenOpaqueWindowState; 341 private WindowState mTopFullscreenOpaqueOrDimmingWindowState; 342 private WindowState mTopDockedOpaqueWindowState; 343 private WindowState mTopDockedOpaqueOrDimmingWindowState; 344 private boolean mTopIsFullscreen; 345 private boolean mForceStatusBar; 346 private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED; 347 private boolean mForcingShowNavBar; 348 private int mForcingShowNavBarLayer; 349 private boolean mForceShowSystemBars; 350 351 private boolean mShowingDream; 352 private boolean mLastShowingDream; 353 private boolean mDreamingLockscreen; 354 private boolean mAllowLockscreenWhenOn; 355 356 private PointerLocationView mPointerLocationView; 357 358 /** 359 * The area covered by system windows which belong to another display. Forwarded insets is set 360 * in case this is a virtual display, this is displayed on another display that has insets, and 361 * the bounds of this display is overlapping with the insets of the host display (e.g. IME is 362 * displayed on the host display, and it covers a part of this virtual display.) 363 * The forwarded insets is used to compute display frames of this virtual display, which will 364 * be then used to layout windows in the virtual display. 365 */ 366 @NonNull private Insets mForwardedInsets = Insets.NONE; 367 368 private RefreshRatePolicy mRefreshRatePolicy; 369 370 /** 371 * If true, attach the navigation bar to the current transition app. 372 * The value is read from config_attachNavBarToAppDuringTransition and could be overlaid by RRO 373 * when the navigation bar mode is changed. 374 */ 375 private boolean mShouldAttachNavBarToAppDuringTransition; 376 377 // -------- PolicyHandler -------- 378 private static final int MSG_REQUEST_TRANSIENT_BARS = 2; 379 private static final int MSG_DISPOSE_INPUT_CONSUMER = 3; 380 private static final int MSG_ENABLE_POINTER_LOCATION = 4; 381 private static final int MSG_DISABLE_POINTER_LOCATION = 5; 382 383 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0; 384 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1; 385 386 private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver; 387 388 private final WindowManagerInternal.AppTransitionListener mAppTransitionListener; 389 390 private class PolicyHandler extends Handler { 391 PolicyHandler(Looper looper)392 PolicyHandler(Looper looper) { 393 super(looper); 394 } 395 396 @Override handleMessage(Message msg)397 public void handleMessage(Message msg) { 398 switch (msg.what) { 399 case MSG_REQUEST_TRANSIENT_BARS: 400 synchronized (mLock) { 401 WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS) 402 ? getStatusBar() : getNavigationBar(); 403 if (targetBar != null) { 404 requestTransientBars(targetBar); 405 } 406 } 407 break; 408 case MSG_DISPOSE_INPUT_CONSUMER: 409 disposeInputConsumer((EventReceiverInputConsumer) msg.obj); 410 break; 411 case MSG_ENABLE_POINTER_LOCATION: 412 enablePointerLocation(); 413 break; 414 case MSG_DISABLE_POINTER_LOCATION: 415 disablePointerLocation(); 416 break; 417 } 418 } 419 } 420 DisplayPolicy(WindowManagerService service, DisplayContent displayContent)421 DisplayPolicy(WindowManagerService service, DisplayContent displayContent) { 422 mService = service; 423 mContext = displayContent.isDefaultDisplay ? service.mContext 424 : service.mContext.createDisplayContext(displayContent.getDisplay()); 425 mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.mUiContext 426 : service.mAtmService.mSystemThread 427 .createSystemUiContext(displayContent.getDisplayId()); 428 mDisplayContent = displayContent; 429 mLock = service.getWindowManagerLock(); 430 431 final int displayId = displayContent.getDisplayId(); 432 433 mBarContentFrames.put(TYPE_STATUS_BAR, new Rect()); 434 mBarContentFrames.put(TYPE_NAVIGATION_BAR, new Rect()); 435 436 final Resources r = mContext.getResources(); 437 mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer); 438 mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer); 439 440 mAccessibilityManager = (AccessibilityManager) mContext.getSystemService( 441 Context.ACCESSIBILITY_SERVICE); 442 if (!displayContent.isDefaultDisplay) { 443 mAwake = true; 444 mScreenOnEarly = true; 445 mScreenOnFully = true; 446 } 447 448 final Looper looper = UiThread.getHandler().getLooper(); 449 mHandler = new PolicyHandler(looper); 450 // TODO(b/181821798) Migrate SystemGesturesPointerEventListener to use window context. 451 mSystemGestures = new SystemGesturesPointerEventListener(mUiContext, mHandler, 452 new SystemGesturesPointerEventListener.Callbacks() { 453 @Override 454 public void onSwipeFromTop() { 455 synchronized (mLock) { 456 if (mStatusBar != null) { 457 requestTransientBars(mStatusBar); 458 } 459 checkAltBarSwipeForTransientBars(ALT_BAR_TOP); 460 } 461 } 462 463 @Override 464 public void onSwipeFromBottom() { 465 synchronized (mLock) { 466 if (mNavigationBar != null 467 && mNavigationBarPosition == NAV_BAR_BOTTOM) { 468 requestTransientBars(mNavigationBar); 469 } 470 checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM); 471 } 472 } 473 474 @Override 475 public void onSwipeFromRight() { 476 final Region excludedRegion = Region.obtain(); 477 synchronized (mLock) { 478 mDisplayContent.calculateSystemGestureExclusion( 479 excludedRegion, null /* outUnrestricted */); 480 final boolean excluded = 481 mSystemGestures.currentGestureStartedInRegion(excludedRegion); 482 if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT 483 || !excluded && mNavigationBarAlwaysShowOnSideGesture)) { 484 requestTransientBars(mNavigationBar); 485 } 486 checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT); 487 } 488 excludedRegion.recycle(); 489 } 490 491 @Override 492 public void onSwipeFromLeft() { 493 final Region excludedRegion = Region.obtain(); 494 synchronized (mLock) { 495 mDisplayContent.calculateSystemGestureExclusion( 496 excludedRegion, null /* outUnrestricted */); 497 final boolean excluded = 498 mSystemGestures.currentGestureStartedInRegion(excludedRegion); 499 if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT 500 || !excluded && mNavigationBarAlwaysShowOnSideGesture)) { 501 requestTransientBars(mNavigationBar); 502 } 503 checkAltBarSwipeForTransientBars(ALT_BAR_LEFT); 504 } 505 excludedRegion.recycle(); 506 } 507 508 @Override 509 public void onFling(int duration) { 510 if (mService.mPowerManagerInternal != null) { 511 mService.mPowerManagerInternal.setPowerBoost( 512 Boost.INTERACTION, duration); 513 } 514 } 515 516 @Override 517 public void onDebug() { 518 // no-op 519 } 520 521 private WindowOrientationListener getOrientationListener() { 522 final DisplayRotation rotation = mDisplayContent.getDisplayRotation(); 523 return rotation != null ? rotation.getOrientationListener() : null; 524 } 525 526 @Override 527 public void onDown() { 528 final WindowOrientationListener listener = getOrientationListener(); 529 if (listener != null) { 530 listener.onTouchStart(); 531 } 532 } 533 534 @Override 535 public void onUpOrCancel() { 536 final WindowOrientationListener listener = getOrientationListener(); 537 if (listener != null) { 538 listener.onTouchEnd(); 539 } 540 } 541 542 @Override 543 public void onMouseHoverAtTop() { 544 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); 545 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS); 546 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS; 547 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */); 548 } 549 550 @Override 551 public void onMouseHoverAtBottom() { 552 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); 553 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS); 554 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION; 555 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */); 556 } 557 558 @Override 559 public void onMouseLeaveFromEdge() { 560 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); 561 } 562 }); 563 displayContent.registerPointerEventListener(mSystemGestures); 564 mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() { 565 566 private Runnable mAppTransitionPending = () -> { 567 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 568 if (statusBar != null) { 569 statusBar.appTransitionPending(displayId); 570 } 571 }; 572 573 private Runnable mAppTransitionCancelled = () -> { 574 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 575 if (statusBar != null) { 576 statusBar.appTransitionCancelled(displayId); 577 } 578 }; 579 580 private Runnable mAppTransitionFinished = () -> { 581 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 582 if (statusBar != null) { 583 statusBar.appTransitionFinished(displayId); 584 } 585 }; 586 587 @Override 588 public void onAppTransitionPendingLocked() { 589 mHandler.post(mAppTransitionPending); 590 } 591 592 @Override 593 public int onAppTransitionStartingLocked(boolean keyguardGoingAway, long duration, 594 long statusBarAnimationStartTime, long statusBarAnimationDuration) { 595 mHandler.post(() -> { 596 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 597 if (statusBar != null) { 598 statusBar.appTransitionStarting(mContext.getDisplayId(), 599 statusBarAnimationStartTime, statusBarAnimationDuration); 600 } 601 }); 602 return 0; 603 } 604 605 @Override 606 public void onAppTransitionCancelledLocked(boolean keyguardGoingAway) { 607 mHandler.post(mAppTransitionCancelled); 608 } 609 610 @Override 611 public void onAppTransitionFinishedLocked(IBinder token) { 612 mHandler.post(mAppTransitionFinished); 613 } 614 }; 615 displayContent.mAppTransition.registerListenerLocked(mAppTransitionListener); 616 mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper, 617 mService.mVrModeEnabled); 618 619 // TODO: Make it can take screenshot on external display 620 mScreenshotHelper = displayContent.isDefaultDisplay 621 ? new ScreenshotHelper(mContext) : null; 622 623 if (mDisplayContent.isDefaultDisplay) { 624 mHasStatusBar = true; 625 mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar); 626 627 // Allow a system property to override this. Used by the emulator. 628 // See also hasNavigationBar(). 629 String navBarOverride = SystemProperties.get("qemu.hw.mainkeys"); 630 if ("1".equals(navBarOverride)) { 631 mHasNavigationBar = false; 632 } else if ("0".equals(navBarOverride)) { 633 mHasNavigationBar = true; 634 } 635 } else { 636 mHasStatusBar = false; 637 mHasNavigationBar = mDisplayContent.supportsSystemDecorations(); 638 } 639 640 mRefreshRatePolicy = new RefreshRatePolicy(mService, 641 mDisplayContent.getDisplayInfo(), 642 mService.mHighRefreshRateDenylist); 643 644 mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler, 645 mContext, () -> { 646 synchronized (mLock) { 647 onConfigurationChanged(); 648 mSystemGestures.onConfigurationChanged(); 649 mDisplayContent.updateSystemGestureExclusion(); 650 } 651 }); 652 mHandler.post(mGestureNavigationSettingsObserver::register); 653 } 654 checkAltBarSwipeForTransientBars(@indowManagerPolicy.AltBarPosition int pos)655 private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos) { 656 if (mStatusBarAlt != null && mStatusBarAltPosition == pos) { 657 requestTransientBars(mStatusBarAlt); 658 } 659 if (mNavigationBarAlt != null && mNavigationBarAltPosition == pos) { 660 requestTransientBars(mNavigationBarAlt); 661 } 662 if (mClimateBarAlt != null && mClimateBarAltPosition == pos) { 663 requestTransientBars(mClimateBarAlt); 664 } 665 if (mExtraNavBarAlt != null && mExtraNavBarAltPosition == pos) { 666 requestTransientBars(mExtraNavBarAlt); 667 } 668 } 669 systemReady()670 void systemReady() { 671 mSystemGestures.systemReady(); 672 if (mService.mPointerLocationEnabled) { 673 setPointerLocationEnabled(true); 674 } 675 } 676 getDisplayId()677 private int getDisplayId() { 678 return mDisplayContent.getDisplayId(); 679 } 680 setHdmiPlugged(boolean plugged)681 public void setHdmiPlugged(boolean plugged) { 682 setHdmiPlugged(plugged, false /* force */); 683 } 684 setHdmiPlugged(boolean plugged, boolean force)685 public void setHdmiPlugged(boolean plugged, boolean force) { 686 if (force || mHdmiPlugged != plugged) { 687 mHdmiPlugged = plugged; 688 mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */); 689 final Intent intent = new Intent(ACTION_HDMI_PLUGGED); 690 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 691 intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged); 692 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 693 } 694 } 695 isHdmiPlugged()696 boolean isHdmiPlugged() { 697 return mHdmiPlugged; 698 } 699 isCarDockEnablesAccelerometer()700 boolean isCarDockEnablesAccelerometer() { 701 return mCarDockEnablesAccelerometer; 702 } 703 isDeskDockEnablesAccelerometer()704 boolean isDeskDockEnablesAccelerometer() { 705 return mDeskDockEnablesAccelerometer; 706 } 707 setPersistentVrModeEnabled(boolean persistentVrModeEnabled)708 public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) { 709 mPersistentVrModeEnabled = persistentVrModeEnabled; 710 } 711 isPersistentVrModeEnabled()712 public boolean isPersistentVrModeEnabled() { 713 return mPersistentVrModeEnabled; 714 } 715 setDockMode(int dockMode)716 public void setDockMode(int dockMode) { 717 mDockMode = dockMode; 718 } 719 getDockMode()720 public int getDockMode() { 721 return mDockMode; 722 } 723 hasNavigationBar()724 public boolean hasNavigationBar() { 725 return mHasNavigationBar; 726 } 727 hasStatusBar()728 public boolean hasStatusBar() { 729 return mHasStatusBar; 730 } 731 hasSideGestures()732 boolean hasSideGestures() { 733 return mHasNavigationBar && (mLeftGestureInset > 0 || mRightGestureInset > 0); 734 } 735 navigationBarCanMove()736 public boolean navigationBarCanMove() { 737 return mNavigationBarCanMove; 738 } 739 setLidState(int lidState)740 public void setLidState(int lidState) { 741 mLidState = lidState; 742 } 743 getLidState()744 public int getLidState() { 745 return mLidState; 746 } 747 setAwake(boolean awake)748 public void setAwake(boolean awake) { 749 mAwake = awake; 750 } 751 isAwake()752 public boolean isAwake() { 753 return mAwake; 754 } 755 isScreenOnEarly()756 public boolean isScreenOnEarly() { 757 return mScreenOnEarly; 758 } 759 isScreenOnFully()760 public boolean isScreenOnFully() { 761 return mScreenOnFully; 762 } 763 isKeyguardDrawComplete()764 public boolean isKeyguardDrawComplete() { 765 return mKeyguardDrawComplete; 766 } 767 isWindowManagerDrawComplete()768 public boolean isWindowManagerDrawComplete() { 769 return mWindowManagerDrawComplete; 770 } 771 getScreenOnListener()772 public ScreenOnListener getScreenOnListener() { 773 return mScreenOnListener; 774 } 775 screenTurnedOn(ScreenOnListener screenOnListener)776 public void screenTurnedOn(ScreenOnListener screenOnListener) { 777 synchronized (mLock) { 778 mScreenOnEarly = true; 779 mScreenOnFully = false; 780 mKeyguardDrawComplete = false; 781 mWindowManagerDrawComplete = false; 782 mScreenOnListener = screenOnListener; 783 } 784 } 785 screenTurnedOff()786 public void screenTurnedOff() { 787 synchronized (mLock) { 788 mScreenOnEarly = false; 789 mScreenOnFully = false; 790 mKeyguardDrawComplete = false; 791 mWindowManagerDrawComplete = false; 792 mScreenOnListener = null; 793 } 794 } 795 796 /** Return false if we are not awake yet or we have already informed of this event. */ finishKeyguardDrawn()797 public boolean finishKeyguardDrawn() { 798 synchronized (mLock) { 799 if (!mScreenOnEarly || mKeyguardDrawComplete) { 800 return false; 801 } 802 803 mKeyguardDrawComplete = true; 804 mWindowManagerDrawComplete = false; 805 } 806 return true; 807 } 808 809 /** Return false if screen is not turned on or we did already handle this case earlier. */ finishWindowsDrawn()810 public boolean finishWindowsDrawn() { 811 synchronized (mLock) { 812 if (!mScreenOnEarly || mWindowManagerDrawComplete) { 813 return false; 814 } 815 816 mWindowManagerDrawComplete = true; 817 } 818 return true; 819 } 820 821 /** Return false if it is not ready to turn on. */ finishScreenTurningOn()822 public boolean finishScreenTurningOn() { 823 synchronized (mLock) { 824 ProtoLog.d(WM_DEBUG_SCREEN_ON, 825 "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, " 826 + "mScreenOnFully=%b, mKeyguardDrawComplete=%b, " 827 + "mWindowManagerDrawComplete=%b", 828 mAwake, mScreenOnEarly, mScreenOnFully, mKeyguardDrawComplete, 829 mWindowManagerDrawComplete); 830 831 if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete 832 || (mAwake && !mKeyguardDrawComplete)) { 833 return false; 834 } 835 836 ProtoLog.i(WM_DEBUG_SCREEN_ON, "Finished screen turning on..."); 837 mScreenOnListener = null; 838 mScreenOnFully = true; 839 } 840 return true; 841 } 842 hasStatusBarServicePermission(int pid, int uid)843 private boolean hasStatusBarServicePermission(int pid, int uid) { 844 return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid) 845 == PackageManager.PERMISSION_GRANTED; 846 } 847 848 /** 849 * Sanitize the layout parameters coming from a client. Allows the policy 850 * to do things like ensure that windows of a specific type can't take 851 * input focus. 852 * 853 * @param attrs The window layout parameters to be modified. These values 854 * are modified in-place. 855 */ adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs)856 public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs) { 857 switch (attrs.type) { 858 case TYPE_SYSTEM_OVERLAY: 859 case TYPE_SECURE_SYSTEM_OVERLAY: 860 // These types of windows can't receive input events. 861 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 862 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 863 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; 864 break; 865 case TYPE_WALLPAPER: 866 // Dreams and wallpapers don't have an app window token and can thus not be 867 // letterboxed. Hence always let them extend under the cutout. 868 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 869 break; 870 case TYPE_NOTIFICATION_SHADE: 871 // If the Keyguard is in a hidden state (occluded by another window), we force to 872 // remove the wallpaper and keyguard flag so that any change in-flight after setting 873 // the keyguard as occluded wouldn't set these flags again. 874 // See {@link #processKeyguardSetHiddenResultLw}. 875 if (mService.mPolicy.isKeyguardOccluded()) { 876 attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 877 } 878 break; 879 880 case TYPE_TOAST: 881 // While apps should use the dedicated toast APIs to add such windows 882 // it possible legacy apps to add the window directly. Therefore, we 883 // make windows added directly by the app behave as a toast as much 884 // as possible in terms of timeout and animation. 885 if (attrs.hideTimeoutMilliseconds < 0 886 || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) { 887 attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT; 888 } 889 // Accessibility users may need longer timeout duration. This api compares 890 // original timeout with user's preference and return longer one. It returns 891 // original timeout if there's no preference. 892 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis( 893 (int) attrs.hideTimeoutMilliseconds, 894 AccessibilityManager.FLAG_CONTENT_TEXT); 895 // Toasts can't be clickable 896 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 897 break; 898 899 case TYPE_BASE_APPLICATION: 900 901 // A non-translucent main app window isn't allowed to fit insets, as it would create 902 // a hole on the display! 903 if (attrs.isFullscreen() && win.mActivityRecord != null 904 && win.mActivityRecord.fillsParent() 905 && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0 906 && attrs.getFitInsetsTypes() != 0) { 907 throw new IllegalArgumentException("Illegal attributes: Main activity window" 908 + " that isn't translucent trying to fit insets: " 909 + attrs.getFitInsetsTypes() 910 + " attrs=" + attrs); 911 } 912 break; 913 } 914 915 // Check if alternate bars positions were updated. 916 if (mStatusBarAlt == win) { 917 mStatusBarAltPosition = getAltBarPosition(attrs); 918 } 919 if (mNavigationBarAlt == win) { 920 mNavigationBarAltPosition = getAltBarPosition(attrs); 921 } 922 if (mClimateBarAlt == win) { 923 mClimateBarAltPosition = getAltBarPosition(attrs); 924 } 925 if (mExtraNavBarAlt == win) { 926 mExtraNavBarAltPosition = getAltBarPosition(attrs); 927 } 928 } 929 930 /** 931 * Check if a window can be added to the system. 932 * 933 * Currently enforces that two window types are singletons per display: 934 * <ul> 935 * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li> 936 * <li>{@link WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}</li> 937 * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li> 938 * </ul> 939 * 940 * @param attrs Information about the window to be added. 941 * 942 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, 943 * WindowManagerImpl.ADD_MULTIPLE_SINGLETON 944 */ validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid)945 int validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid) { 946 if ((attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) { 947 mContext.enforcePermission( 948 android.Manifest.permission.INTERNAL_SYSTEM_WINDOW, callingPid, callingUid, 949 "DisplayPolicy"); 950 } 951 if ((attrs.privateFlags & PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP) != 0) { 952 ActivityTaskManagerService.enforceTaskPermission("DisplayPolicy"); 953 } 954 955 switch (attrs.type) { 956 case TYPE_STATUS_BAR: 957 mContext.enforcePermission( 958 android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, 959 "DisplayPolicy"); 960 if ((mStatusBar != null && mStatusBar.isAlive()) 961 || (mStatusBarAlt != null && mStatusBarAlt.isAlive())) { 962 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; 963 } 964 break; 965 case TYPE_NOTIFICATION_SHADE: 966 mContext.enforcePermission( 967 android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, 968 "DisplayPolicy"); 969 if (mNotificationShade != null) { 970 if (mNotificationShade.isAlive()) { 971 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; 972 } 973 } 974 break; 975 case TYPE_NAVIGATION_BAR: 976 mContext.enforcePermission( 977 android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, 978 "DisplayPolicy"); 979 if ((mNavigationBar != null && mNavigationBar.isAlive()) 980 || (mNavigationBarAlt != null && mNavigationBarAlt.isAlive())) { 981 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; 982 } 983 break; 984 case TYPE_NAVIGATION_BAR_PANEL: 985 // Check for permission if the caller is not the recents component. 986 if (!mService.mAtmInternal.isCallerRecents(callingUid)) { 987 mContext.enforcePermission( 988 android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, 989 "DisplayPolicy"); 990 } 991 break; 992 case TYPE_STATUS_BAR_ADDITIONAL: 993 case TYPE_STATUS_BAR_SUB_PANEL: 994 case TYPE_VOICE_INTERACTION_STARTING: 995 mContext.enforcePermission( 996 android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, 997 "DisplayPolicy"); 998 break; 999 case TYPE_STATUS_BAR_PANEL: 1000 return WindowManagerGlobal.ADD_INVALID_TYPE; 1001 } 1002 1003 if (attrs.providesInsetsTypes != null) { 1004 // Recents component is allowed to add inset types. 1005 if (!mService.mAtmInternal.isCallerRecents(callingUid)) { 1006 mContext.enforcePermission( 1007 android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, 1008 "DisplayPolicy"); 1009 } 1010 enforceSingleInsetsTypeCorrespondingToWindowType(attrs.providesInsetsTypes); 1011 1012 for (@InternalInsetsType int insetType : attrs.providesInsetsTypes) { 1013 switch (insetType) { 1014 case ITYPE_STATUS_BAR: 1015 if ((mStatusBar != null && mStatusBar.isAlive()) 1016 || (mStatusBarAlt != null && mStatusBarAlt.isAlive())) { 1017 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; 1018 } 1019 break; 1020 case ITYPE_NAVIGATION_BAR: 1021 if ((mNavigationBar != null && mNavigationBar.isAlive()) 1022 || (mNavigationBarAlt != null && mNavigationBarAlt.isAlive())) { 1023 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; 1024 } 1025 break; 1026 case ITYPE_CLIMATE_BAR: 1027 if (mClimateBarAlt != null && mClimateBarAlt.isAlive()) { 1028 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; 1029 } 1030 break; 1031 case ITYPE_EXTRA_NAVIGATION_BAR: 1032 if (mExtraNavBarAlt != null && mExtraNavBarAlt.isAlive()) { 1033 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; 1034 } 1035 break; 1036 } 1037 } 1038 } 1039 return ADD_OKAY; 1040 } 1041 getRotatedWindowBounds(DisplayFrames displayFrames, WindowState windowState, Rect outBounds)1042 private void getRotatedWindowBounds(DisplayFrames displayFrames, WindowState windowState, 1043 Rect outBounds) { 1044 outBounds.set(windowState.getBounds()); 1045 1046 int windowRotation = windowState.getWindowConfiguration().getRotation(); 1047 if (windowRotation == displayFrames.mRotation) { 1048 return; 1049 } 1050 1051 // Get displayFrames bounds as it is on WindowState's rotation. 1052 final int deltaRotation = deltaRotation(windowRotation, displayFrames.mRotation); 1053 if (deltaRotation == Surface.ROTATION_90 || deltaRotation == Surface.ROTATION_270) { 1054 sTmpDisplayFrameBounds.set( 1055 0, 0, displayFrames.mDisplayHeight, displayFrames.mDisplayWidth); 1056 } else { 1057 sTmpDisplayFrameBounds.set( 1058 0, 0, displayFrames.mDisplayWidth, displayFrames.mDisplayHeight); 1059 } 1060 // Rotate the WindowState's bounds based on the displayFrames rotation 1061 rotateBounds(outBounds, sTmpDisplayFrameBounds, deltaRotation); 1062 } 1063 1064 /** 1065 * Called when a window is being added to the system. Must not throw an exception. 1066 * 1067 * @param win The window being added. 1068 * @param attrs Information about the window to be added. 1069 */ addWindowLw(WindowState win, WindowManager.LayoutParams attrs)1070 void addWindowLw(WindowState win, WindowManager.LayoutParams attrs) { 1071 switch (attrs.type) { 1072 case TYPE_NOTIFICATION_SHADE: 1073 mNotificationShade = win; 1074 if (mDisplayContent.isDefaultDisplay) { 1075 mService.mPolicy.setKeyguardCandidateLw(win); 1076 } 1077 break; 1078 case TYPE_STATUS_BAR: 1079 mStatusBar = win; 1080 final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider = 1081 (displayFrames, windowState, rect) -> { 1082 rect.bottom = rect.top + getStatusBarHeight(displayFrames); 1083 }; 1084 mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, frameProvider); 1085 mDisplayContent.setInsetProvider(ITYPE_TOP_MANDATORY_GESTURES, win, frameProvider); 1086 mDisplayContent.setInsetProvider(ITYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider); 1087 break; 1088 case TYPE_NAVIGATION_BAR: 1089 mNavigationBar = win; 1090 mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, win, 1091 (displayFrames, windowState, inOutFrame) -> { 1092 1093 // In Gesture Nav, navigation bar frame is larger than frame to 1094 // calculate inset. 1095 if (navigationBarPosition(displayFrames.mDisplayWidth, 1096 displayFrames.mDisplayHeight, 1097 displayFrames.mRotation) == NAV_BAR_BOTTOM 1098 && !mNavButtonForcedVisible) { 1099 sTmpRect.set(inOutFrame); 1100 sTmpRect.intersectUnchecked(displayFrames.mDisplayCutoutSafe); 1101 inOutFrame.top = sTmpRect.bottom 1102 - getNavigationBarHeight(displayFrames.mRotation, 1103 mDisplayContent.getConfiguration().uiMode); 1104 } 1105 }, 1106 1107 // For IME we use regular frame. 1108 (displayFrames, windowState, inOutFrame) -> 1109 inOutFrame.set(windowState.getFrame())); 1110 1111 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_MANDATORY_GESTURES, win, 1112 (displayFrames, windowState, inOutFrame) -> { 1113 inOutFrame.top -= mBottomGestureAdditionalInset; 1114 }); 1115 mDisplayContent.setInsetProvider(ITYPE_LEFT_GESTURES, win, 1116 (displayFrames, windowState, inOutFrame) -> { 1117 final int leftSafeInset = 1118 Math.max(displayFrames.mDisplayCutoutSafe.left, 0); 1119 inOutFrame.left = 0; 1120 inOutFrame.top = 0; 1121 inOutFrame.bottom = displayFrames.mDisplayHeight; 1122 inOutFrame.right = leftSafeInset + mLeftGestureInset; 1123 }); 1124 mDisplayContent.setInsetProvider(ITYPE_RIGHT_GESTURES, win, 1125 (displayFrames, windowState, inOutFrame) -> { 1126 final int rightSafeInset = 1127 Math.min(displayFrames.mDisplayCutoutSafe.right, 1128 displayFrames.mUnrestricted.right); 1129 inOutFrame.left = rightSafeInset - mRightGestureInset; 1130 inOutFrame.top = 0; 1131 inOutFrame.bottom = displayFrames.mDisplayHeight; 1132 inOutFrame.right = displayFrames.mDisplayWidth; 1133 }); 1134 mDisplayContent.setInsetProvider(ITYPE_BOTTOM_TAPPABLE_ELEMENT, win, 1135 (displayFrames, windowState, inOutFrame) -> { 1136 if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0 1137 || mNavigationBarLetsThroughTaps) { 1138 inOutFrame.setEmpty(); 1139 } 1140 }); 1141 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar); 1142 break; 1143 default: 1144 if (attrs.providesInsetsTypes != null) { 1145 for (@InternalInsetsType int insetsType : attrs.providesInsetsTypes) { 1146 switch (insetsType) { 1147 case ITYPE_STATUS_BAR: 1148 mStatusBarAlt = win; 1149 mStatusBarAltPosition = getAltBarPosition(attrs); 1150 break; 1151 case ITYPE_NAVIGATION_BAR: 1152 mNavigationBarAlt = win; 1153 mNavigationBarAltPosition = getAltBarPosition(attrs); 1154 break; 1155 case ITYPE_CLIMATE_BAR: 1156 mClimateBarAlt = win; 1157 mClimateBarAltPosition = getAltBarPosition(attrs); 1158 break; 1159 case ITYPE_EXTRA_NAVIGATION_BAR: 1160 mExtraNavBarAlt = win; 1161 mExtraNavBarAltPosition = getAltBarPosition(attrs); 1162 break; 1163 } 1164 mDisplayContent.setInsetProvider(insetsType, win, null); 1165 } 1166 } 1167 break; 1168 } 1169 } 1170 1171 @WindowManagerPolicy.AltBarPosition getAltBarPosition(WindowManager.LayoutParams params)1172 private int getAltBarPosition(WindowManager.LayoutParams params) { 1173 switch (params.gravity) { 1174 case Gravity.LEFT: 1175 return ALT_BAR_LEFT; 1176 case Gravity.RIGHT: 1177 return ALT_BAR_RIGHT; 1178 case Gravity.BOTTOM: 1179 return ALT_BAR_BOTTOM; 1180 case Gravity.TOP: 1181 return ALT_BAR_TOP; 1182 default: 1183 return ALT_BAR_UNKNOWN; 1184 } 1185 } 1186 getImeSourceFrameProvider()1187 TriConsumer<DisplayFrames, WindowState, Rect> getImeSourceFrameProvider() { 1188 return (displayFrames, windowState, inOutFrame) -> { 1189 if (mNavigationBar != null && navigationBarPosition(displayFrames.mDisplayWidth, 1190 displayFrames.mDisplayHeight, 1191 displayFrames.mRotation) == NAV_BAR_BOTTOM) { 1192 // In gesture navigation, nav bar frame is larger than frame to calculate insets. 1193 // IME should not provide frame which is smaller than the nav bar frame. Otherwise, 1194 // nav bar might be overlapped with the content of the client when IME is shown. 1195 sTmpRect.set(inOutFrame); 1196 sTmpRect.intersectUnchecked(mNavigationBar.getFrame()); 1197 inOutFrame.inset(windowState.mGivenContentInsets); 1198 inOutFrame.union(sTmpRect); 1199 } else { 1200 inOutFrame.inset(windowState.mGivenContentInsets); 1201 } 1202 }; 1203 } 1204 1205 private static void enforceSingleInsetsTypeCorrespondingToWindowType(int[] insetsTypes) { 1206 int count = 0; 1207 for (int insetsType : insetsTypes) { 1208 switch (insetsType) { 1209 case ITYPE_NAVIGATION_BAR: 1210 case ITYPE_STATUS_BAR: 1211 case ITYPE_CLIMATE_BAR: 1212 case ITYPE_EXTRA_NAVIGATION_BAR: 1213 case ITYPE_CAPTION_BAR: 1214 if (++count > 1) { 1215 throw new IllegalArgumentException( 1216 "Multiple InsetsTypes corresponding to Window type"); 1217 } 1218 } 1219 } 1220 } 1221 1222 /** 1223 * Called when a window is being removed from a window manager. Must not 1224 * throw an exception -- clean up as much as possible. 1225 * 1226 * @param win The window being removed. 1227 */ 1228 void removeWindowLw(WindowState win) { 1229 if (mStatusBar == win || mStatusBarAlt == win) { 1230 mStatusBar = null; 1231 mStatusBarAlt = null; 1232 mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, null, null); 1233 } else if (mNavigationBar == win || mNavigationBarAlt == win) { 1234 mNavigationBar = null; 1235 mNavigationBarAlt = null; 1236 mDisplayContent.setInsetProvider(ITYPE_NAVIGATION_BAR, null, null); 1237 } else if (mNotificationShade == win) { 1238 mNotificationShade = null; 1239 if (mDisplayContent.isDefaultDisplay) { 1240 mService.mPolicy.setKeyguardCandidateLw(null); 1241 } 1242 } else if (mClimateBarAlt == win) { 1243 mClimateBarAlt = null; 1244 mDisplayContent.setInsetProvider(ITYPE_CLIMATE_BAR, null, null); 1245 } else if (mExtraNavBarAlt == win) { 1246 mExtraNavBarAlt = null; 1247 mDisplayContent.setInsetProvider(ITYPE_EXTRA_NAVIGATION_BAR, null, null); 1248 } 1249 if (mLastFocusedWindow == win) { 1250 mLastFocusedWindow = null; 1251 } 1252 } 1253 1254 private int getStatusBarHeight(DisplayFrames displayFrames) { 1255 return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation], 1256 displayFrames.mDisplayCutoutSafe.top); 1257 } 1258 1259 WindowState getStatusBar() { 1260 return mStatusBar != null ? mStatusBar : mStatusBarAlt; 1261 } 1262 1263 WindowState getNotificationShade() { 1264 return mNotificationShade; 1265 } 1266 1267 WindowState getNavigationBar() { 1268 return mNavigationBar != null ? mNavigationBar : mNavigationBarAlt; 1269 } 1270 1271 /** 1272 * Control the animation to run when a window's state changes. Return a positive number to 1273 * force the animation to a specific resource ID, {@link #ANIMATION_STYLEABLE} to use the 1274 * style resource defining the animation, or {@link #ANIMATION_NONE} for no animation. 1275 * 1276 * @param win The window that is changing. 1277 * @param transit What is happening to the window: 1278 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER}, 1279 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT}, 1280 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or 1281 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}. 1282 * 1283 * @return Resource ID of the actual animation to use, or {@link #ANIMATION_NONE} for none. 1284 */ 1285 int selectAnimation(WindowState win, int transit) { 1286 if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win 1287 + ": transit=" + transit); 1288 if (win == mStatusBar) { 1289 if (transit == TRANSIT_EXIT 1290 || transit == TRANSIT_HIDE) { 1291 return R.anim.dock_top_exit; 1292 } else if (transit == TRANSIT_ENTER 1293 || transit == TRANSIT_SHOW) { 1294 return R.anim.dock_top_enter; 1295 } 1296 } else if (win == mNavigationBar) { 1297 if (win.getAttrs().windowAnimations != 0) { 1298 return ANIMATION_STYLEABLE; 1299 } 1300 // This can be on either the bottom or the right or the left. 1301 if (mNavigationBarPosition == NAV_BAR_BOTTOM) { 1302 if (transit == TRANSIT_EXIT 1303 || transit == TRANSIT_HIDE) { 1304 if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) { 1305 return R.anim.dock_bottom_exit_keyguard; 1306 } else { 1307 return R.anim.dock_bottom_exit; 1308 } 1309 } else if (transit == TRANSIT_ENTER 1310 || transit == TRANSIT_SHOW) { 1311 return R.anim.dock_bottom_enter; 1312 } 1313 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) { 1314 if (transit == TRANSIT_EXIT 1315 || transit == TRANSIT_HIDE) { 1316 return R.anim.dock_right_exit; 1317 } else if (transit == TRANSIT_ENTER 1318 || transit == TRANSIT_SHOW) { 1319 return R.anim.dock_right_enter; 1320 } 1321 } else if (mNavigationBarPosition == NAV_BAR_LEFT) { 1322 if (transit == TRANSIT_EXIT 1323 || transit == TRANSIT_HIDE) { 1324 return R.anim.dock_left_exit; 1325 } else if (transit == TRANSIT_ENTER 1326 || transit == TRANSIT_SHOW) { 1327 return R.anim.dock_left_enter; 1328 } 1329 } 1330 } else if (win == mStatusBarAlt || win == mNavigationBarAlt || win == mClimateBarAlt 1331 || win == mExtraNavBarAlt) { 1332 if (win.getAttrs().windowAnimations != 0) { 1333 return ANIMATION_STYLEABLE; 1334 } 1335 1336 int pos = (win == mStatusBarAlt) ? mStatusBarAltPosition : mNavigationBarAltPosition; 1337 1338 boolean isExitOrHide = transit == TRANSIT_EXIT || transit == TRANSIT_HIDE; 1339 boolean isEnterOrShow = transit == TRANSIT_ENTER || transit == TRANSIT_SHOW; 1340 1341 switch (pos) { 1342 case ALT_BAR_LEFT: 1343 if (isExitOrHide) { 1344 return R.anim.dock_left_exit; 1345 } else if (isEnterOrShow) { 1346 return R.anim.dock_left_enter; 1347 } 1348 break; 1349 case ALT_BAR_RIGHT: 1350 if (isExitOrHide) { 1351 return R.anim.dock_right_exit; 1352 } else if (isEnterOrShow) { 1353 return R.anim.dock_right_enter; 1354 } 1355 break; 1356 case ALT_BAR_BOTTOM: 1357 if (isExitOrHide) { 1358 return R.anim.dock_bottom_exit; 1359 } else if (isEnterOrShow) { 1360 return R.anim.dock_bottom_enter; 1361 } 1362 break; 1363 case ALT_BAR_TOP: 1364 if (isExitOrHide) { 1365 return R.anim.dock_top_exit; 1366 } else if (isEnterOrShow) { 1367 return R.anim.dock_top_enter; 1368 } 1369 break; 1370 } 1371 } 1372 1373 if (transit == TRANSIT_PREVIEW_DONE) { 1374 if (win.hasAppShownWindows()) { 1375 if (win.isActivityTypeHome()) { 1376 // Dismiss the starting window as soon as possible to avoid the crossfade out 1377 // with old content because home is easier to have different UI states. 1378 return ANIMATION_NONE; 1379 } 1380 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT"); 1381 return R.anim.app_starting_exit; 1382 } 1383 } 1384 1385 return ANIMATION_STYLEABLE; 1386 } 1387 1388 /** 1389 * @return true if the system bars are forced to stay visible 1390 */ 1391 public boolean areSystemBarsForcedShownLw(WindowState windowState) { 1392 return mForceShowSystemBars; 1393 } 1394 1395 // TODO: Should probably be moved into DisplayFrames. 1396 /** 1397 * Return the layout hints for a newly added window. These values are computed on the 1398 * most recent layout, so they are not guaranteed to be correct. 1399 * 1400 * @param attrs The LayoutParams of the window. 1401 * @param windowToken The token of the window. 1402 * @param outInsetsState The insets state of this display from the client's perspective. 1403 * @param localClient Whether the client is from the our process. 1404 * @return Whether to always consume the system bars. 1405 * See {@link #areSystemBarsForcedShownLw(WindowState)}. 1406 */ 1407 boolean getLayoutHint(LayoutParams attrs, WindowToken windowToken, InsetsState outInsetsState, 1408 boolean localClient) { 1409 final InsetsState state = 1410 mDisplayContent.getInsetsPolicy().getInsetsForWindowMetrics(attrs); 1411 final boolean hasCompatScale = WindowState.hasCompatScale(attrs, windowToken); 1412 outInsetsState.set(state, hasCompatScale || localClient); 1413 if (hasCompatScale) { 1414 final float compatScale = windowToken != null 1415 ? windowToken.getSizeCompatScale() 1416 : mDisplayContent.mCompatibleScreenScale; 1417 outInsetsState.scale(1f / compatScale); 1418 } 1419 return mForceShowSystemBars; 1420 } 1421 1422 private void simulateLayoutDecorWindow(WindowState win, DisplayFrames displayFrames, 1423 WindowFrames simulatedWindowFrames, SparseArray<Rect> contentFrames, 1424 Consumer<Rect> layout) { 1425 win.setSimulatedWindowFrames(simulatedWindowFrames); 1426 final Rect contentFrame = new Rect(); 1427 try { 1428 layout.accept(contentFrame); 1429 } finally { 1430 win.setSimulatedWindowFrames(null); 1431 } 1432 contentFrames.put(win.mAttrs.type, contentFrame); 1433 mDisplayContent.getInsetsStateController().computeSimulatedState( 1434 win, displayFrames, simulatedWindowFrames); 1435 } 1436 1437 /** 1438 * Computes the frames of display (its logical size, rotation and cutout should already be set) 1439 * used to layout window. This method only changes the given display frames, insets state and 1440 * some temporal states, but doesn't change the window frames used to show on screen. 1441 */ 1442 void simulateLayoutDisplay(DisplayFrames displayFrames, SparseArray<Rect> barContentFrames) { 1443 final WindowFrames simulatedWindowFrames = new WindowFrames(); 1444 if (mNavigationBar != null) { 1445 simulateLayoutDecorWindow(mNavigationBar, displayFrames, simulatedWindowFrames, 1446 barContentFrames, contentFrame -> layoutNavigationBar(displayFrames, 1447 contentFrame)); 1448 } 1449 if (mStatusBar != null) { 1450 simulateLayoutDecorWindow(mStatusBar, displayFrames, simulatedWindowFrames, 1451 barContentFrames, contentFrame -> layoutStatusBar(displayFrames, contentFrame)); 1452 } 1453 } 1454 1455 void onDisplayInfoChanged(DisplayInfo info) { 1456 mSystemGestures.onDisplayInfoChanged(info); 1457 } 1458 1459 private void layoutStatusBar(DisplayFrames displayFrames, Rect contentFrame) { 1460 // decide where the status bar goes ahead of time 1461 if (mStatusBar == null) { 1462 return; 1463 } 1464 // apply any status bar insets 1465 getRotatedWindowBounds(displayFrames, mStatusBar, sTmpStatusFrame); 1466 final WindowFrames windowFrames = mStatusBar.getLayoutingWindowFrames(); 1467 windowFrames.setFrames(sTmpStatusFrame /* parentFrame */, 1468 sTmpStatusFrame /* displayFrame */); 1469 // Let the status bar determine its size. 1470 mStatusBar.computeFrameAndUpdateSourceFrame(); 1471 1472 // For layout, the status bar is always at the top with our fixed height. 1473 int statusBarBottom = displayFrames.mUnrestricted.top 1474 + mStatusBarHeightForRotation[displayFrames.mRotation]; 1475 // Make sure the status bar covers the entire cutout height 1476 statusBarBottom = Math.max(statusBarBottom, displayFrames.mDisplayCutoutSafe.top); 1477 1478 if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) { 1479 // Make sure that the zone we're avoiding for the cutout is at least as tall as the 1480 // status bar; otherwise fullscreen apps will end up cutting halfway into the status 1481 // bar. 1482 displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top, 1483 statusBarBottom); 1484 } 1485 1486 sTmpRect.set(windowFrames.mFrame); 1487 sTmpRect.intersect(displayFrames.mDisplayCutoutSafe); 1488 sTmpRect.top = windowFrames.mFrame.top; // Ignore top display cutout inset 1489 sTmpRect.bottom = statusBarBottom; // Use collapsed status bar size 1490 contentFrame.set(sTmpRect); 1491 } 1492 1493 private int layoutNavigationBar(DisplayFrames displayFrames, Rect contentFrame) { 1494 if (mNavigationBar == null) { 1495 return NAV_BAR_INVALID; 1496 } 1497 1498 final int uiMode = mDisplayContent.getConfiguration().uiMode; 1499 final Rect navigationFrame = sTmpNavFrame; 1500 // Force the navigation bar to its appropriate place and size. We need to do this directly, 1501 // instead of relying on it to bubble up from the nav bar, because this needs to change 1502 // atomically with screen rotations. 1503 final int rotation = displayFrames.mRotation; 1504 final int displayHeight = displayFrames.mDisplayHeight; 1505 final int displayWidth = displayFrames.mDisplayWidth; 1506 final int navBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation); 1507 1508 getRotatedWindowBounds(displayFrames, mNavigationBar, navigationFrame); 1509 1510 final Rect cutoutSafeUnrestricted = sTmpRect; 1511 cutoutSafeUnrestricted.set(displayFrames.mUnrestricted); 1512 cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe); 1513 1514 if (navBarPosition == NAV_BAR_BOTTOM) { 1515 // It's a system nav bar or a portrait screen; nav bar goes on bottom. 1516 navigationFrame.top = Math.min(cutoutSafeUnrestricted.bottom, navigationFrame.bottom) 1517 - getNavigationBarFrameHeight(rotation, uiMode); 1518 } else if (navBarPosition == NAV_BAR_RIGHT) { 1519 // Landscape screen; nav bar goes to the right. 1520 navigationFrame.left = Math.min(cutoutSafeUnrestricted.right, navigationFrame.right) 1521 - getNavigationBarWidth(rotation, uiMode); 1522 } else if (navBarPosition == NAV_BAR_LEFT) { 1523 // Seascape screen; nav bar goes to the left. 1524 navigationFrame.right = Math.max(cutoutSafeUnrestricted.left, navigationFrame.left) 1525 + getNavigationBarWidth(rotation, uiMode); 1526 } 1527 1528 // Compute the final frame. 1529 final WindowFrames windowFrames = mNavigationBar.getLayoutingWindowFrames(); 1530 windowFrames.setFrames(navigationFrame /* parentFrame */, 1531 navigationFrame /* displayFrame */); 1532 mNavigationBar.computeFrameAndUpdateSourceFrame(); 1533 sTmpRect.set(windowFrames.mFrame); 1534 sTmpRect.intersect(displayFrames.mDisplayCutoutSafe); 1535 contentFrame.set(sTmpRect); 1536 1537 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame); 1538 return navBarPosition; 1539 } 1540 1541 private boolean canReceiveInput(WindowState win) { 1542 boolean notFocusable = 1543 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0; 1544 boolean altFocusableIm = 1545 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0; 1546 boolean notFocusableForIm = notFocusable ^ altFocusableIm; 1547 return !notFocusableForIm; 1548 } 1549 1550 /** 1551 * Called for each window attached to the window manager as layout is proceeding. The 1552 * implementation of this function must take care of setting the window's frame, either here or 1553 * in finishLayout(). 1554 * 1555 * @param win The window being positioned. 1556 * @param attached For sub-windows, the window it is attached to; this 1557 * window will already have had layoutWindow() called on it 1558 * so you can use its Rect. Otherwise null. 1559 * @param displayFrames The display frames. 1560 */ 1561 public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) { 1562 if (win == mNavigationBar) { 1563 mNavigationBarPosition = layoutNavigationBar(displayFrames, 1564 mBarContentFrames.get(TYPE_NAVIGATION_BAR)); 1565 return; 1566 } 1567 if ((win == mStatusBar && !canReceiveInput(win))) { 1568 layoutStatusBar(displayFrames, mBarContentFrames.get(TYPE_STATUS_BAR)); 1569 return; 1570 } 1571 if (win.mActivityRecord != null && win.mActivityRecord.mWaitForEnteringPinnedMode) { 1572 // Skip layout of the window when in transition to pip mode. 1573 return; 1574 } 1575 final WindowManager.LayoutParams attrs = win.getAttrs(); 1576 1577 final int type = attrs.type; 1578 final int fl = attrs.flags; 1579 final int pfl = attrs.privateFlags; 1580 final int sim = attrs.softInputMode; 1581 1582 displayFrames = win.getDisplayFrames(displayFrames); 1583 final WindowFrames windowFrames = win.getWindowFrames(); 1584 1585 sTmpLastParentFrame.set(windowFrames.mParentFrame); 1586 final Rect pf = windowFrames.mParentFrame; 1587 final Rect df = windowFrames.mDisplayFrame; 1588 windowFrames.setParentFrameWasClippedByDisplayCutout(false); 1589 1590 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN; 1591 final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR; 1592 1593 final InsetsState state = win.getInsetsState(); 1594 computeWindowBounds(attrs, state, win.mToken.getBounds(), df); 1595 if (attached == null) { 1596 pf.set(df); 1597 if ((pfl & PRIVATE_FLAG_INSET_PARENT_FRAME_BY_IME) != 0) { 1598 final InsetsSource source = state.peekSource(ITYPE_IME); 1599 if (source != null) { 1600 pf.inset(source.calculateInsets(pf, false /* ignoreVisibility */)); 1601 } 1602 } 1603 } else { 1604 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrame() : df); 1605 } 1606 1607 final int cutoutMode = attrs.layoutInDisplayCutoutMode; 1608 // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in 1609 // the cutout safe zone. 1610 if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) { 1611 final boolean attachedInParent = attached != null && !layoutInScreen; 1612 final boolean requestedFullscreen = !win.getRequestedVisibility(ITYPE_STATUS_BAR); 1613 final boolean requestedHideNavigation = 1614 !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR); 1615 1616 // TYPE_BASE_APPLICATION windows are never considered floating here because they don't 1617 // get cropped / shifted to the displayFrame in WindowState. 1618 final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen 1619 && type != TYPE_BASE_APPLICATION; 1620 final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect; 1621 displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe); 1622 if (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) { 1623 if (displayFrames.mDisplayWidth < displayFrames.mDisplayHeight) { 1624 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE; 1625 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE; 1626 } else { 1627 displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE; 1628 displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE; 1629 } 1630 } 1631 1632 if (layoutInScreen && layoutInsetDecor && !requestedFullscreen 1633 && (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 1634 || cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)) { 1635 // At the top we have the status bar, so apps that are 1636 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN 1637 // already expect that there's an inset there and we don't need to exclude 1638 // the window from that area. 1639 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE; 1640 } 1641 if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation 1642 && (cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 1643 || cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES)) { 1644 // Same for the navigation bar. 1645 switch (mNavigationBarPosition) { 1646 case NAV_BAR_BOTTOM: 1647 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE; 1648 break; 1649 case NAV_BAR_RIGHT: 1650 displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE; 1651 break; 1652 case NAV_BAR_LEFT: 1653 displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE; 1654 break; 1655 } 1656 } 1657 if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) { 1658 // The IME can always extend under the bottom cutout if the navbar is there. 1659 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE; 1660 } 1661 // Windows that are attached to a parent and laid out in said parent already avoid 1662 // the cutout according to that parent and don't need to be further constrained. 1663 // Floating IN_SCREEN windows get what they ask for and lay out in the full screen. 1664 // They will later be cropped or shifted using the displayFrame in WindowState, 1665 // which prevents overlap with the DisplayCutout. 1666 if (!attachedInParent && !floatingInScreenWindow) { 1667 sTmpRect.set(pf); 1668 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars); 1669 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf)); 1670 } 1671 // Make sure that NO_LIMITS windows clipped to the display don't extend under the 1672 // cutout. 1673 df.intersectUnchecked(displayCutoutSafeExceptMaybeBars); 1674 } 1675 1676 // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it. 1677 // Also, we don't allow windows in multi-window mode to extend out of the screen. 1678 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR 1679 && !win.inMultiWindowMode()) { 1680 df.left = df.top = -10000; 1681 df.right = df.bottom = 10000; 1682 } 1683 1684 if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle() 1685 + ": sim=#" + Integer.toHexString(sim) 1686 + " attach=" + attached + " type=" + type 1687 + String.format(" flags=0x%08x", fl) 1688 + " pf=" + pf.toShortString() + " df=" + df.toShortString()); 1689 1690 if (!sTmpLastParentFrame.equals(pf)) { 1691 windowFrames.setContentChanged(true); 1692 } 1693 1694 win.computeFrameAndUpdateSourceFrame(); 1695 } 1696 1697 WindowState getTopFullscreenOpaqueWindow() { 1698 return mTopFullscreenOpaqueWindowState; 1699 } 1700 1701 boolean isTopLayoutFullscreen() { 1702 return mTopIsFullscreen; 1703 } 1704 1705 /** 1706 * Called following layout of all windows before each window has policy applied. 1707 */ 1708 public void beginPostLayoutPolicyLw() { 1709 mTopFullscreenOpaqueWindowState = null; 1710 mTopFullscreenOpaqueOrDimmingWindowState = null; 1711 mTopDockedOpaqueWindowState = null; 1712 mTopDockedOpaqueOrDimmingWindowState = null; 1713 mForceStatusBar = false; 1714 mForcingShowNavBar = false; 1715 mForcingShowNavBarLayer = -1; 1716 1717 mAllowLockscreenWhenOn = false; 1718 mShowingDream = false; 1719 mIsFreeformWindowOverlappingWithNavBar = false; 1720 } 1721 1722 /** 1723 * Called following layout of all window to apply policy to each window. 1724 * 1725 * @param win The window being positioned. 1726 * @param attrs The LayoutParams of the window. 1727 * @param attached For sub-windows, the window it is attached to. Otherwise null. 1728 */ 1729 public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs, 1730 WindowState attached, WindowState imeTarget) { 1731 final boolean affectsSystemUi = win.canAffectSystemUiFlags(); 1732 if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi); 1733 applyKeyguardPolicy(win, imeTarget); 1734 final int fl = attrs.flags; 1735 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi 1736 && attrs.type == TYPE_INPUT_METHOD) { 1737 mForcingShowNavBar = true; 1738 mForcingShowNavBarLayer = win.getSurfaceLayer(); 1739 } 1740 1741 boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW 1742 && attrs.type < FIRST_SYSTEM_WINDOW; 1743 final int windowingMode = win.getWindowingMode(); 1744 final boolean inFullScreenOrSplitScreenSecondaryWindowingMode = 1745 windowingMode == WINDOWING_MODE_FULLSCREEN 1746 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 1747 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) { 1748 if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) { 1749 mForceStatusBar = true; 1750 } 1751 if (win.isDreamWindow()) { 1752 // If the lockscreen was showing when the dream started then wait 1753 // for the dream to draw before hiding the lockscreen. 1754 if (!mDreamingLockscreen || (win.isVisible() && win.hasDrawn())) { 1755 mShowingDream = true; 1756 appWindow = true; 1757 } 1758 } 1759 1760 // For app windows that are not attached, we decide if all windows in the app they 1761 // represent should be hidden or if we should hide the lockscreen. For attached app 1762 // windows we defer the decision to the window it is attached to. 1763 if (appWindow && attached == null) { 1764 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) { 1765 if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win); 1766 mTopFullscreenOpaqueWindowState = win; 1767 if (mTopFullscreenOpaqueOrDimmingWindowState == null) { 1768 mTopFullscreenOpaqueOrDimmingWindowState = win; 1769 } 1770 if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { 1771 mAllowLockscreenWhenOn = true; 1772 } 1773 } 1774 } 1775 } 1776 1777 // Voice interaction overrides both top fullscreen and top docked. 1778 if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION && attrs.isFullscreen()) { 1779 if (mTopFullscreenOpaqueWindowState == null) { 1780 mTopFullscreenOpaqueWindowState = win; 1781 if (mTopFullscreenOpaqueOrDimmingWindowState == null) { 1782 mTopFullscreenOpaqueOrDimmingWindowState = win; 1783 } 1784 } 1785 if (mTopDockedOpaqueWindowState == null) { 1786 mTopDockedOpaqueWindowState = win; 1787 if (mTopDockedOpaqueOrDimmingWindowState == null) { 1788 mTopDockedOpaqueOrDimmingWindowState = win; 1789 } 1790 } 1791 } 1792 1793 // Keep track of the window if it's dimming but not necessarily fullscreen. 1794 if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi 1795 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) { 1796 mTopFullscreenOpaqueOrDimmingWindowState = win; 1797 } 1798 1799 // We need to keep track of the top "fullscreen" opaque window for the docked root task 1800 // separately, because both the "real fullscreen" opaque window and the one for the docked 1801 // root task can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR. 1802 if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null 1803 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { 1804 mTopDockedOpaqueWindowState = win; 1805 if (mTopDockedOpaqueOrDimmingWindowState == null) { 1806 mTopDockedOpaqueOrDimmingWindowState = win; 1807 } 1808 } 1809 1810 // Check if the freeform window overlaps with the navigation bar area. 1811 final WindowState navBarWin = hasNavigationBar() ? mNavigationBar : null; 1812 if (!mIsFreeformWindowOverlappingWithNavBar && win.inFreeformWindowingMode() 1813 && isOverlappingWithNavBar(win, navBarWin)) { 1814 mIsFreeformWindowOverlappingWithNavBar = true; 1815 } 1816 1817 // Also keep track of any windows that are dimming but not necessarily fullscreen in the 1818 // docked root task. 1819 if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming() 1820 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { 1821 mTopDockedOpaqueOrDimmingWindowState = win; 1822 } 1823 } 1824 1825 /** 1826 * Called following layout of all windows and after policy has been applied 1827 * to each window. If in this function you do 1828 * something that may have modified the animation state of another window, 1829 * be sure to return non-zero in order to perform another pass through layout. 1830 * 1831 * @return Return any bit set of 1832 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT}, 1833 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG}, 1834 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or 1835 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}. 1836 */ 1837 public int finishPostLayoutPolicyLw() { 1838 int changes = 0; 1839 boolean topIsFullscreen = false; 1840 1841 // If we are not currently showing a dream then remember the current 1842 // lockscreen state. We will use this to determine whether the dream 1843 // started while the lockscreen was showing and remember this state 1844 // while the dream is showing. 1845 if (!mShowingDream) { 1846 mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded(); 1847 } 1848 1849 if (getStatusBar() != null) { 1850 if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar 1851 + " top=" + mTopFullscreenOpaqueWindowState); 1852 final boolean forceShowStatusBar = (getStatusBar().getAttrs().privateFlags 1853 & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0; 1854 1855 boolean topAppHidesStatusBar = topAppHidesStatusBar(); 1856 if (mForceStatusBar || forceShowStatusBar) { 1857 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced"); 1858 // Maintain fullscreen layout until incoming animation is complete. 1859 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw(); 1860 } else if (mTopFullscreenOpaqueWindowState != null) { 1861 topIsFullscreen = topAppHidesStatusBar; 1862 // The subtle difference between the window for mTopFullscreenOpaqueWindowState 1863 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window 1864 // requests to hide the status bar. Not sure if there is another way that to be the 1865 // case though. 1866 if (!topIsFullscreen || mDisplayContent.getDefaultTaskDisplayArea() 1867 .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) { 1868 topAppHidesStatusBar = false; 1869 } 1870 } 1871 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 1872 if (statusBar != null) { 1873 statusBar.setTopAppHidesStatusBar(topAppHidesStatusBar); 1874 } 1875 } 1876 1877 if (mTopIsFullscreen != topIsFullscreen) { 1878 if (!topIsFullscreen) { 1879 // Force another layout when status bar becomes fully shown. 1880 changes |= FINISH_LAYOUT_REDO_LAYOUT; 1881 } 1882 mTopIsFullscreen = topIsFullscreen; 1883 } 1884 1885 if (updateSystemUiVisibilityLw()) { 1886 // If the navigation bar has been hidden or shown, we need to do another 1887 // layout pass to update that window. 1888 changes |= FINISH_LAYOUT_REDO_LAYOUT; 1889 } 1890 1891 if (mShowingDream != mLastShowingDream) { 1892 mLastShowingDream = mShowingDream; 1893 mService.notifyShowingDreamChanged(); 1894 } 1895 1896 mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn); 1897 return changes; 1898 } 1899 1900 /** 1901 * Applies the keyguard policy to a specific window. 1902 * 1903 * @param win The window to apply the keyguard policy. 1904 * @param imeTarget The current IME target window. 1905 */ 1906 private void applyKeyguardPolicy(WindowState win, WindowState imeTarget) { 1907 if (mService.mPolicy.canBeHiddenByKeyguardLw(win)) { 1908 if (shouldBeHiddenByKeyguard(win, imeTarget)) { 1909 win.hide(false /* doAnimation */, true /* requestAnim */); 1910 } else { 1911 win.show(false /* doAnimation */, true /* requestAnim */); 1912 } 1913 } 1914 } 1915 1916 private boolean shouldBeHiddenByKeyguard(WindowState win, WindowState imeTarget) { 1917 // If AOD is showing, the IME should be hidden. However, sometimes the AOD is considered 1918 // hidden because it's in the process of hiding, but it's still being shown on screen. 1919 // In that case, we want to continue hiding the IME until the windows have completed 1920 // drawing. This way, we know that the IME can be safely shown since the other windows are 1921 // now shown. 1922 final boolean hideIme = win.mIsImWindow 1923 && (mService.mAtmService.mKeyguardController.isAodShowing() 1924 || (mDisplayContent.isDefaultDisplay && !mWindowManagerDrawComplete)); 1925 if (hideIme) { 1926 return true; 1927 } 1928 1929 if (!mDisplayContent.isDefaultDisplay || !isKeyguardShowing()) { 1930 return false; 1931 } 1932 1933 // Show IME over the keyguard if the target allows it. 1934 final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisible() 1935 && win.mIsImWindow && (imeTarget.canShowWhenLocked() 1936 || !mService.mPolicy.canBeHiddenByKeyguardLw(imeTarget)); 1937 if (showImeOverKeyguard) { 1938 return false; 1939 } 1940 1941 // Show SHOW_WHEN_LOCKED windows if keyguard is occluded. 1942 final boolean allowShowWhenLocked = isKeyguardOccluded() 1943 // Show error dialogs over apps that are shown on keyguard. 1944 && (win.canShowWhenLocked() 1945 || (win.mAttrs.privateFlags & LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR) != 0); 1946 return !allowShowWhenLocked; 1947 } 1948 1949 /** 1950 * @return Whether the top app should hide the statusbar based on the top fullscreen opaque 1951 * window. 1952 */ 1953 boolean topAppHidesStatusBar() { 1954 if (mTopFullscreenOpaqueWindowState == null || mForceShowSystemBars) { 1955 return false; 1956 } 1957 return !mTopFullscreenOpaqueWindowState.getRequestedVisibility(ITYPE_STATUS_BAR); 1958 } 1959 1960 /** 1961 * Called when the user is switched. 1962 */ 1963 public void switchUser() { 1964 updateCurrentUserResources(); 1965 } 1966 1967 /** 1968 * Called when the resource overlays change. 1969 */ 1970 public void onOverlayChangedLw() { 1971 updateCurrentUserResources(); 1972 onConfigurationChanged(); 1973 mSystemGestures.onConfigurationChanged(); 1974 } 1975 1976 /** 1977 * Called when the configuration has changed, and it's safe to load new values from resources. 1978 */ 1979 public void onConfigurationChanged() { 1980 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation(); 1981 1982 final Resources res = getCurrentUserResources(); 1983 final int portraitRotation = displayRotation.getPortraitRotation(); 1984 final int upsideDownRotation = displayRotation.getUpsideDownRotation(); 1985 final int landscapeRotation = displayRotation.getLandscapeRotation(); 1986 final int seascapeRotation = displayRotation.getSeascapeRotation(); 1987 final int uiMode = mService.mPolicy.getUiMode(); 1988 1989 if (hasStatusBar()) { 1990 mStatusBarHeightForRotation[portraitRotation] = 1991 mStatusBarHeightForRotation[upsideDownRotation] = 1992 res.getDimensionPixelSize(R.dimen.status_bar_height_portrait); 1993 mStatusBarHeightForRotation[landscapeRotation] = 1994 mStatusBarHeightForRotation[seascapeRotation] = 1995 res.getDimensionPixelSize(R.dimen.status_bar_height_landscape); 1996 } else { 1997 mStatusBarHeightForRotation[portraitRotation] = 1998 mStatusBarHeightForRotation[upsideDownRotation] = 1999 mStatusBarHeightForRotation[landscapeRotation] = 2000 mStatusBarHeightForRotation[seascapeRotation] = 0; 2001 } 2002 2003 // Height of the navigation bar when presented horizontally at bottom 2004 mNavigationBarHeightForRotationDefault[portraitRotation] = 2005 mNavigationBarHeightForRotationDefault[upsideDownRotation] = 2006 res.getDimensionPixelSize(R.dimen.navigation_bar_height); 2007 mNavigationBarHeightForRotationDefault[landscapeRotation] = 2008 mNavigationBarHeightForRotationDefault[seascapeRotation] = 2009 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape); 2010 2011 // Height of the navigation bar frame when presented horizontally at bottom 2012 mNavigationBarFrameHeightForRotationDefault[portraitRotation] = 2013 mNavigationBarFrameHeightForRotationDefault[upsideDownRotation] = 2014 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height); 2015 mNavigationBarFrameHeightForRotationDefault[landscapeRotation] = 2016 mNavigationBarFrameHeightForRotationDefault[seascapeRotation] = 2017 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height_landscape); 2018 2019 // Width of the navigation bar when presented vertically along one side 2020 mNavigationBarWidthForRotationDefault[portraitRotation] = 2021 mNavigationBarWidthForRotationDefault[upsideDownRotation] = 2022 mNavigationBarWidthForRotationDefault[landscapeRotation] = 2023 mNavigationBarWidthForRotationDefault[seascapeRotation] = 2024 res.getDimensionPixelSize(R.dimen.navigation_bar_width); 2025 2026 if (ALTERNATE_CAR_MODE_NAV_SIZE) { 2027 // Height of the navigation bar when presented horizontally at bottom 2028 mNavigationBarHeightForRotationInCarMode[portraitRotation] = 2029 mNavigationBarHeightForRotationInCarMode[upsideDownRotation] = 2030 res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode); 2031 mNavigationBarHeightForRotationInCarMode[landscapeRotation] = 2032 mNavigationBarHeightForRotationInCarMode[seascapeRotation] = 2033 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode); 2034 2035 // Width of the navigation bar when presented vertically along one side 2036 mNavigationBarWidthForRotationInCarMode[portraitRotation] = 2037 mNavigationBarWidthForRotationInCarMode[upsideDownRotation] = 2038 mNavigationBarWidthForRotationInCarMode[landscapeRotation] = 2039 mNavigationBarWidthForRotationInCarMode[seascapeRotation] = 2040 res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode); 2041 } 2042 2043 mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode); 2044 mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res); 2045 mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res); 2046 mNavButtonForcedVisible = 2047 mGestureNavigationSettingsObserver.areNavigationButtonForcedVisible(); 2048 mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough); 2049 mNavigationBarAlwaysShowOnSideGesture = 2050 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture); 2051 2052 // This should calculate how much above the frame we accept gestures. 2053 mBottomGestureAdditionalInset = 2054 res.getDimensionPixelSize(R.dimen.navigation_bar_gesture_height) 2055 - getNavigationBarFrameHeight(portraitRotation, uiMode); 2056 2057 updateConfigurationAndScreenSizeDependentBehaviors(); 2058 2059 final boolean shouldAttach = 2060 res.getBoolean(R.bool.config_attachNavBarToAppDuringTransition); 2061 if (mShouldAttachNavBarToAppDuringTransition != shouldAttach) { 2062 mShouldAttachNavBarToAppDuringTransition = shouldAttach; 2063 } 2064 } 2065 2066 void updateConfigurationAndScreenSizeDependentBehaviors() { 2067 final Resources res = getCurrentUserResources(); 2068 mNavigationBarCanMove = 2069 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight 2070 && res.getBoolean(R.bool.config_navBarCanMove); 2071 mDisplayContent.getDisplayRotation().updateUserDependentConfiguration(res); 2072 } 2073 2074 /** 2075 * Updates the current user's resources to pick up any changes for the current user (including 2076 * overlay paths) 2077 */ 2078 private void updateCurrentUserResources() { 2079 final int userId = mService.mAmInternal.getCurrentUserId(); 2080 final Context uiContext = getSystemUiContext(); 2081 2082 if (userId == UserHandle.USER_SYSTEM) { 2083 // Skip the (expensive) recreation of resources for the system user below and just 2084 // use the resources from the system ui context 2085 mCurrentUserResources = uiContext.getResources(); 2086 return; 2087 } 2088 2089 // For non-system users, ensure that the resources are loaded from the current 2090 // user's package info (see ContextImpl.createDisplayContext) 2091 final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo( 2092 uiContext.getPackageName(), null, 0, userId); 2093 mCurrentUserResources = ResourcesManager.getInstance().getResources(null, 2094 pi.getResDir(), 2095 null /* splitResDirs */, 2096 pi.getOverlayDirs(), 2097 pi.getOverlayPaths(), 2098 pi.getApplicationInfo().sharedLibraryFiles, 2099 mDisplayContent.getDisplayId(), 2100 null /* overrideConfig */, 2101 uiContext.getResources().getCompatibilityInfo(), 2102 null /* classLoader */, 2103 null /* loaders */); 2104 } 2105 2106 @VisibleForTesting 2107 Resources getCurrentUserResources() { 2108 if (mCurrentUserResources == null) { 2109 updateCurrentUserResources(); 2110 } 2111 return mCurrentUserResources; 2112 } 2113 2114 @VisibleForTesting 2115 Context getContext() { 2116 return mContext; 2117 } 2118 2119 Context getSystemUiContext() { 2120 return mUiContext; 2121 } 2122 2123 private int getNavigationBarWidth(int rotation, int uiMode) { 2124 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) { 2125 return mNavigationBarWidthForRotationInCarMode[rotation]; 2126 } else { 2127 return mNavigationBarWidthForRotationDefault[rotation]; 2128 } 2129 } 2130 2131 void notifyDisplayReady() { 2132 mHandler.post(() -> { 2133 final int displayId = getDisplayId(); 2134 getStatusBarManagerInternal().onDisplayReady(displayId); 2135 final WallpaperManagerInternal wpMgr = LocalServices 2136 .getService(WallpaperManagerInternal.class); 2137 if (wpMgr != null) { 2138 wpMgr.onDisplayReady(displayId); 2139 } 2140 }); 2141 } 2142 2143 /** 2144 * Return the display width available after excluding any screen 2145 * decorations that could never be removed in Honeycomb. That is, system bar or 2146 * button bar. 2147 */ 2148 public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, 2149 DisplayCutout displayCutout) { 2150 int width = fullWidth; 2151 if (hasNavigationBar()) { 2152 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation); 2153 if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) { 2154 width -= getNavigationBarWidth(rotation, uiMode); 2155 } 2156 } 2157 if (displayCutout != null) { 2158 width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight(); 2159 } 2160 return width; 2161 } 2162 2163 private int getNavigationBarHeight(int rotation, int uiMode) { 2164 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) { 2165 return mNavigationBarHeightForRotationInCarMode[rotation]; 2166 } else { 2167 return mNavigationBarHeightForRotationDefault[rotation]; 2168 } 2169 } 2170 2171 /** 2172 * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that 2173 * is used for spacing to show additional buttons on the navigation bar (such as the ime 2174 * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible 2175 * height that we send to the app as content insets that can be smaller. 2176 * <p> 2177 * In car mode it will return the same height as {@link #getNavigationBarHeight} 2178 * 2179 * @param rotation specifies rotation to return dimension from 2180 * @param uiMode to determine if in car mode 2181 * @return navigation bar frame height 2182 */ 2183 private int getNavigationBarFrameHeight(int rotation, int uiMode) { 2184 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) { 2185 return mNavigationBarHeightForRotationInCarMode[rotation]; 2186 } else { 2187 return mNavigationBarFrameHeightForRotationDefault[rotation]; 2188 } 2189 } 2190 2191 /** 2192 * Return the display height available after excluding any screen 2193 * decorations that could never be removed in Honeycomb. That is, system bar or 2194 * button bar. 2195 */ 2196 public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, 2197 DisplayCutout displayCutout) { 2198 int height = fullHeight; 2199 if (hasNavigationBar()) { 2200 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation); 2201 if (navBarPosition == NAV_BAR_BOTTOM) { 2202 height -= getNavigationBarHeight(rotation, uiMode); 2203 } 2204 } 2205 if (displayCutout != null) { 2206 height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom(); 2207 } 2208 return height; 2209 } 2210 2211 /** 2212 * Return the available screen width that we should report for the 2213 * configuration. This must be no larger than 2214 * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller 2215 * than that to account for more transient decoration like a status bar. 2216 */ 2217 public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, 2218 DisplayCutout displayCutout) { 2219 return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout); 2220 } 2221 2222 /** 2223 * Return the available screen height that we should report for the 2224 * configuration. This must be no larger than 2225 * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller 2226 * than that to account for more transient decoration like a status bar. 2227 */ 2228 public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, 2229 DisplayCutout displayCutout) { 2230 // There is a separate status bar at the top of the display. We don't count that as part 2231 // of the fixed decor, since it can hide; however, for purposes of configurations, 2232 // we do want to exclude it since applications can't generally use that part 2233 // of the screen. 2234 int statusBarHeight = mStatusBarHeightForRotation[rotation]; 2235 if (displayCutout != null) { 2236 // If there is a cutout, it may already have accounted for some part of the status 2237 // bar height. 2238 statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop()); 2239 } 2240 return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout) 2241 - statusBarHeight; 2242 } 2243 2244 /** 2245 * Return corner radius in pixels that should be used on windows in order to cover the display. 2246 * 2247 * The radius is only valid for internal displays, since the corner radius of external displays 2248 * is not known at build time when window corners are configured. 2249 */ 2250 float getWindowCornerRadius() { 2251 return mDisplayContent.getDisplay().getType() == TYPE_INTERNAL 2252 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f; 2253 } 2254 2255 boolean isShowingDreamLw() { 2256 return mShowingDream; 2257 } 2258 2259 /** 2260 * Calculates the stable insets if we already have the non-decor insets. 2261 * 2262 * @param inOutInsets The known non-decor insets. It will be modified to stable insets. 2263 * @param rotation The current display rotation. 2264 */ 2265 void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) { 2266 inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]); 2267 } 2268 2269 /** 2270 * Calculates the stable insets without running a layout. 2271 * 2272 * @param displayRotation the current display rotation 2273 * @param displayWidth the current display width 2274 * @param displayHeight the current display height 2275 * @param displayCutout the current display cutout 2276 * @param outInsets the insets to return 2277 */ 2278 public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight, 2279 DisplayCutout displayCutout, Rect outInsets) { 2280 outInsets.setEmpty(); 2281 2282 // Navigation bar and status bar. 2283 getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets); 2284 convertNonDecorInsetsToStableInsets(outInsets, displayRotation); 2285 } 2286 2287 /** 2288 * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system 2289 * bar or button bar. See {@link #getNonDecorDisplayWidth}. 2290 * 2291 * @param displayRotation the current display rotation 2292 * @param displayWidth the current display width 2293 * @param displayHeight the current display height 2294 * @param displayCutout the current display cutout 2295 * @param outInsets the insets to return 2296 */ 2297 public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight, 2298 DisplayCutout displayCutout, Rect outInsets) { 2299 outInsets.setEmpty(); 2300 2301 // Only navigation bar 2302 if (hasNavigationBar()) { 2303 final int uiMode = mService.mPolicy.getUiMode(); 2304 int position = navigationBarPosition(displayWidth, displayHeight, displayRotation); 2305 if (position == NAV_BAR_BOTTOM) { 2306 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode); 2307 } else if (position == NAV_BAR_RIGHT) { 2308 outInsets.right = getNavigationBarWidth(displayRotation, uiMode); 2309 } else if (position == NAV_BAR_LEFT) { 2310 outInsets.left = getNavigationBarWidth(displayRotation, uiMode); 2311 } 2312 } 2313 2314 if (displayCutout != null) { 2315 outInsets.left += displayCutout.getSafeInsetLeft(); 2316 outInsets.top += displayCutout.getSafeInsetTop(); 2317 outInsets.right += displayCutout.getSafeInsetRight(); 2318 outInsets.bottom += displayCutout.getSafeInsetBottom(); 2319 } 2320 } 2321 2322 /** 2323 * @see IWindowManager#setForwardedInsets 2324 */ 2325 public void setForwardedInsets(@NonNull Insets forwardedInsets) { 2326 mForwardedInsets = forwardedInsets; 2327 } 2328 2329 @NonNull 2330 public Insets getForwardedInsets() { 2331 return mForwardedInsets; 2332 } 2333 2334 @NavigationBarPosition 2335 int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) { 2336 if (navigationBarCanMove() && displayWidth > displayHeight) { 2337 if (displayRotation == Surface.ROTATION_270) { 2338 return NAV_BAR_LEFT; 2339 } else if (displayRotation == Surface.ROTATION_90) { 2340 return NAV_BAR_RIGHT; 2341 } 2342 } 2343 return NAV_BAR_BOTTOM; 2344 } 2345 2346 /** 2347 * @return The side of the screen where navigation bar is positioned. 2348 * @see WindowManagerPolicyConstants#NAV_BAR_LEFT 2349 * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT 2350 * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM 2351 */ 2352 @NavigationBarPosition 2353 public int getNavBarPosition() { 2354 return mNavigationBarPosition; 2355 } 2356 2357 @WindowManagerPolicy.AltBarPosition 2358 int getAlternateStatusBarPosition() { 2359 return mStatusBarAltPosition; 2360 } 2361 2362 @WindowManagerPolicy.AltBarPosition 2363 int getAlternateNavBarPosition() { 2364 return mNavigationBarAltPosition; 2365 } 2366 2367 /** 2368 * A new window has been focused. 2369 */ 2370 public int focusChangedLw(WindowState lastFocus, WindowState newFocus) { 2371 mFocusedWindow = newFocus; 2372 mLastFocusedWindow = lastFocus; 2373 if (mDisplayContent.isDefaultDisplay) { 2374 mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus); 2375 } 2376 if (updateSystemUiVisibilityLw()) { 2377 // If the navigation bar has been hidden or shown, we need to do another 2378 // layout pass to update that window. 2379 return FINISH_LAYOUT_REDO_LAYOUT; 2380 } 2381 return 0; 2382 } 2383 2384 private void requestTransientBars(WindowState swipeTarget) { 2385 if (!mService.mPolicy.isUserSetupComplete()) { 2386 // Swipe-up for navigation bar is disabled during setup 2387 return; 2388 } 2389 final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider(); 2390 final InsetsControlTarget controlTarget = provider != null 2391 ? provider.getControlTarget() : null; 2392 2393 if (controlTarget == null || controlTarget == getNotificationShade()) { 2394 // No transient mode on lockscreen (in notification shade window). 2395 return; 2396 } 2397 2398 final @InsetsType int restorePositionTypes = 2399 (controlTarget.getRequestedVisibility(ITYPE_NAVIGATION_BAR) 2400 ? Type.navigationBars() : 0) 2401 | (controlTarget.getRequestedVisibility(ITYPE_STATUS_BAR) 2402 ? Type.statusBars() : 0) 2403 | (mExtraNavBarAlt != null && controlTarget.getRequestedVisibility( 2404 ITYPE_EXTRA_NAVIGATION_BAR) 2405 ? Type.navigationBars() : 0) 2406 | (mClimateBarAlt != null && controlTarget.getRequestedVisibility( 2407 ITYPE_CLIMATE_BAR) 2408 ? Type.statusBars() : 0); 2409 2410 if (swipeTarget == mNavigationBar 2411 && (restorePositionTypes & Type.navigationBars()) != 0) { 2412 // Don't show status bar when swiping on already visible navigation bar. 2413 // But restore the position of navigation bar if it has been moved by the control 2414 // target. 2415 controlTarget.showInsets(Type.navigationBars(), false); 2416 return; 2417 } 2418 2419 if (controlTarget.canShowTransient()) { 2420 // Show transient bars if they are hidden; restore position if they are visible. 2421 mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE); 2422 controlTarget.showInsets(restorePositionTypes, false); 2423 } else { 2424 // Restore visibilities and positions of system bars. 2425 controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), false); 2426 // To further allow the pull-down-from-the-top gesture to pull down the notification 2427 // shade as a consistent motion, we reroute the touch events here from the currently 2428 // touched window to the status bar after making it visible. 2429 if (swipeTarget == mStatusBar) { 2430 final boolean transferred = mStatusBar.transferTouch(); 2431 if (!transferred) { 2432 Slog.i(TAG, "Could not transfer touch to the status bar"); 2433 } 2434 } 2435 } 2436 mImmersiveModeConfirmation.confirmCurrentPrompt(); 2437 } 2438 2439 private void disposeInputConsumer(EventReceiverInputConsumer inputConsumer) { 2440 if (inputConsumer != null) { 2441 inputConsumer.dispose(); 2442 } 2443 } 2444 2445 boolean isKeyguardShowing() { 2446 return mService.mPolicy.isKeyguardShowing(); 2447 } 2448 private boolean isKeyguardOccluded() { 2449 // TODO (b/113840485): Handle per display keyguard. 2450 return mService.mPolicy.isKeyguardOccluded(); 2451 } 2452 2453 InsetsPolicy getInsetsPolicy() { 2454 return mDisplayContent.getInsetsPolicy(); 2455 } 2456 2457 void resetSystemUiVisibilityLw() { 2458 mLastDisableFlags = 0; 2459 updateSystemUiVisibilityLw(); 2460 } 2461 2462 /** 2463 * @return {@code true} if the update may affect the layout. 2464 */ 2465 boolean updateSystemUiVisibilityLw() { 2466 // If there is no window focused, there will be nobody to handle the events 2467 // anyway, so just hang on in whatever state we're in until things settle down. 2468 WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow 2469 : mTopFullscreenOpaqueWindowState; 2470 if (winCandidate == null) { 2471 return false; 2472 } 2473 2474 // The immersive mode confirmation should never affect the system bar visibility, otherwise 2475 // it will unhide the navigation bar and hide itself. 2476 if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) { 2477 2478 // The immersive mode confirmation took the focus from mLastFocusedWindow which was 2479 // controlling the system ui visibility. So if mLastFocusedWindow can still receive 2480 // keys, we let it keep controlling the visibility. 2481 final boolean lastFocusCanReceiveKeys = 2482 (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys()); 2483 winCandidate = isKeyguardShowing() && !isKeyguardOccluded() ? mNotificationShade 2484 : lastFocusCanReceiveKeys ? mLastFocusedWindow 2485 : mTopFullscreenOpaqueWindowState; 2486 if (winCandidate == null) { 2487 return false; 2488 } 2489 } 2490 final WindowState win = winCandidate; 2491 mSystemUiControllingWindow = win; 2492 2493 mDisplayContent.getInsetsPolicy().updateBarControlTarget(win); 2494 2495 final boolean inSplitScreen = 2496 mService.mRoot.getDefaultTaskDisplayArea().isSplitScreenModeActivated(); 2497 if (inSplitScreen) { 2498 mService.getRootTaskBounds(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, 2499 mDockedRootTaskBounds); 2500 } else { 2501 mDockedRootTaskBounds.setEmpty(); 2502 } 2503 mService.getRootTaskBounds(inSplitScreen ? WINDOWING_MODE_SPLIT_SCREEN_SECONDARY 2504 : WINDOWING_MODE_FULLSCREEN, 2505 ACTIVITY_TYPE_UNDEFINED, mNonDockedRootTaskBounds); 2506 final int fullscreenAppearance = getStatusBarAppearance(mTopFullscreenOpaqueWindowState, 2507 mTopFullscreenOpaqueOrDimmingWindowState); 2508 final int dockedAppearance = getStatusBarAppearance(mTopDockedOpaqueWindowState, 2509 mTopDockedOpaqueOrDimmingWindowState); 2510 final int disableFlags = win.getDisableFlags(); 2511 final int opaqueAppearance = updateSystemBarsLw(win, disableFlags); 2512 final WindowState navColorWin = chooseNavigationColorWindowLw( 2513 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState, 2514 mDisplayContent.mInputMethodWindow, mNavigationBarPosition); 2515 final boolean isNavbarColorManagedByIme = 2516 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow; 2517 final int appearance = updateLightNavigationBarLw( 2518 win.mAttrs.insetsFlags.appearance, mTopFullscreenOpaqueWindowState, 2519 mTopFullscreenOpaqueOrDimmingWindowState, 2520 mDisplayContent.mInputMethodWindow, navColorWin) | opaqueAppearance; 2521 final int behavior = win.mAttrs.insetsFlags.behavior; 2522 final boolean isFullscreen = !win.getRequestedVisibility(ITYPE_STATUS_BAR) 2523 || !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR); 2524 if (mLastDisableFlags == disableFlags 2525 && mLastAppearance == appearance 2526 && mLastFullscreenAppearance == fullscreenAppearance 2527 && mLastDockedAppearance == dockedAppearance 2528 && mLastBehavior == behavior 2529 && mLastFocusIsFullscreen == isFullscreen 2530 && mLastNonDockedRootTaskBounds.equals(mNonDockedRootTaskBounds) 2531 && mLastDockedRootTaskBounds.equals(mDockedRootTaskBounds)) { 2532 return false; 2533 } 2534 if (mDisplayContent.isDefaultDisplay && mLastFocusIsFullscreen != isFullscreen 2535 && ((mLastAppearance ^ appearance) & APPEARANCE_LOW_PROFILE_BARS) != 0) { 2536 mService.mInputManager.setSystemUiLightsOut( 2537 isFullscreen || (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0); 2538 } 2539 mLastDisableFlags = disableFlags; 2540 mLastAppearance = appearance; 2541 mLastFullscreenAppearance = fullscreenAppearance; 2542 mLastDockedAppearance = dockedAppearance; 2543 mLastBehavior = behavior; 2544 mLastFocusIsFullscreen = isFullscreen; 2545 mLastNonDockedRootTaskBounds.set(mNonDockedRootTaskBounds); 2546 mLastDockedRootTaskBounds.set(mDockedRootTaskBounds); 2547 final Rect fullscreenRootTaskBounds = new Rect(mNonDockedRootTaskBounds); 2548 final Rect dockedRootTaskBounds = new Rect(mDockedRootTaskBounds); 2549 final AppearanceRegion[] appearanceRegions = inSplitScreen 2550 ? new AppearanceRegion[]{ 2551 new AppearanceRegion(fullscreenAppearance, fullscreenRootTaskBounds), 2552 new AppearanceRegion(dockedAppearance, dockedRootTaskBounds)} 2553 : new AppearanceRegion[]{ 2554 new AppearanceRegion(fullscreenAppearance, fullscreenRootTaskBounds)}; 2555 String cause = win.toString(); 2556 mHandler.post(() -> { 2557 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 2558 if (statusBar != null) { 2559 final int displayId = getDisplayId(); 2560 statusBar.setDisableFlags(displayId, disableFlags, cause); 2561 statusBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions, 2562 isNavbarColorManagedByIme, behavior, isFullscreen); 2563 2564 } 2565 }); 2566 return true; 2567 } 2568 2569 private int getStatusBarAppearance(WindowState opaque, WindowState opaqueOrDimming) { 2570 final boolean onKeyguard = isKeyguardShowing() && !isKeyguardOccluded(); 2571 final WindowState colorWin = onKeyguard ? mNotificationShade : opaqueOrDimming; 2572 return isLightBarAllowed(colorWin, ITYPE_STATUS_BAR) && (colorWin == opaque || onKeyguard) 2573 ? (colorWin.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_STATUS_BARS) 2574 : 0; 2575 } 2576 2577 @VisibleForTesting 2578 @Nullable 2579 static WindowState chooseNavigationColorWindowLw(WindowState opaque, 2580 WindowState opaqueOrDimming, WindowState imeWindow, 2581 @NavigationBarPosition int navBarPosition) { 2582 // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME 2583 // window can be navigation color window. 2584 final boolean imeWindowCanNavColorWindow = imeWindow != null 2585 && imeWindow.isVisible() 2586 && navBarPosition == NAV_BAR_BOTTOM 2587 && (imeWindow.mAttrs.flags 2588 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; 2589 2590 if (opaque != null && opaqueOrDimming == opaque) { 2591 // If the top fullscreen-or-dimming window is also the top fullscreen, respect it 2592 // unless IME window is also eligible, since currently the IME window is always show 2593 // above the opaque fullscreen app window, regardless of the IME target window. 2594 // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed. 2595 return imeWindowCanNavColorWindow ? imeWindow : opaque; 2596 } 2597 2598 if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) { 2599 // No dimming window is involved. Determine the result only with the IME window. 2600 return imeWindowCanNavColorWindow ? imeWindow : null; 2601 } 2602 2603 if (!imeWindowCanNavColorWindow) { 2604 // No IME window is involved. Determine the result only with opaqueOrDimming. 2605 return opaqueOrDimming; 2606 } 2607 2608 // The IME window and the dimming window are competing. Check if the dimming window can be 2609 // IME target or not. 2610 if (LayoutParams.mayUseInputMethod(opaqueOrDimming.mAttrs.flags)) { 2611 // The IME window is above the dimming window. 2612 return imeWindow; 2613 } else { 2614 // The dimming window is above the IME window. 2615 return opaqueOrDimming; 2616 } 2617 } 2618 2619 @VisibleForTesting 2620 int updateLightNavigationBarLw(int appearance, WindowState opaque, 2621 WindowState opaqueOrDimming, WindowState imeWindow, WindowState navColorWin) { 2622 2623 if (navColorWin != null) { 2624 if (navColorWin == imeWindow || navColorWin == opaque) { 2625 // Respect the light flag. 2626 appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS; 2627 appearance |= navColorWin.mAttrs.insetsFlags.appearance 2628 & APPEARANCE_LIGHT_NAVIGATION_BARS; 2629 } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) { 2630 // Clear the light flag for dimming window. 2631 appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS; 2632 } 2633 } 2634 if (!isLightBarAllowed(navColorWin, ITYPE_NAVIGATION_BAR)) { 2635 appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS; 2636 } 2637 return appearance; 2638 } 2639 2640 private int updateSystemBarsLw(WindowState win, int disableFlags) { 2641 final boolean dockedRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea() 2642 .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); 2643 final boolean resizing = mDisplayContent.getDockedDividerController().isResizing(); 2644 2645 // We need to force system bars when the docked root task is visible, when the freeform 2646 // root task is focused but also when we are resizing for the transitions when docked 2647 // root task visibility changes. 2648 mForceShowSystemBars = dockedRootTaskVisible || win.inFreeformWindowingMode() || resizing; 2649 2650 int appearance = APPEARANCE_OPAQUE_NAVIGATION_BARS | APPEARANCE_OPAQUE_STATUS_BARS; 2651 2652 appearance = configureStatusBarOpacity(appearance); 2653 appearance = configureNavBarOpacity(appearance, dockedRootTaskVisible, resizing); 2654 2655 final boolean requestHideNavBar = !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR); 2656 final long now = SystemClock.uptimeMillis(); 2657 final boolean pendingPanic = mPendingPanicGestureUptime != 0 2658 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION; 2659 final DisplayPolicy defaultDisplayPolicy = 2660 mService.getDefaultDisplayContentLocked().getDisplayPolicy(); 2661 if (pendingPanic && requestHideNavBar && win != mNotificationShade 2662 && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR) 2663 // TODO (b/111955725): Show keyguard presentation on all external displays 2664 && defaultDisplayPolicy.isKeyguardDrawComplete()) { 2665 // The user performed the panic gesture recently, we're about to hide the bars, 2666 // we're no longer on the Keyguard and the screen is ready. We can now request the bars. 2667 mPendingPanicGestureUptime = 0; 2668 if (!isNavBarEmpty(disableFlags)) { 2669 mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_PANIC); 2670 } 2671 } 2672 2673 // update navigation bar 2674 boolean oldImmersiveMode = mLastImmersiveMode; 2675 boolean newImmersiveMode = isImmersiveMode(win); 2676 if (oldImmersiveMode != newImmersiveMode) { 2677 mLastImmersiveMode = newImmersiveMode; 2678 // The immersive confirmation window should be attached to the immersive window root. 2679 final RootDisplayArea root = win.getRootDisplayArea(); 2680 final int rootDisplayAreaId = root == null ? FEATURE_UNDEFINED : root.mFeatureId; 2681 mImmersiveModeConfirmation.immersiveModeChangedLw(rootDisplayAreaId, newImmersiveMode, 2682 mService.mPolicy.isUserSetupComplete(), 2683 isNavBarEmpty(disableFlags)); 2684 } 2685 2686 return appearance; 2687 } 2688 2689 private boolean isLightBarAllowed(WindowState win, @InternalInsetsType int type) { 2690 if (win == null) { 2691 return false; 2692 } 2693 final InsetsSource source = win.getInsetsState().peekSource(type); 2694 return source != null && Rect.intersects(win.getFrame(), source.getFrame()); 2695 } 2696 2697 private Rect getBarContentFrameForWindow(WindowState win, int windowType) { 2698 final Rect rotatedBarFrame = win.mToken.getFixedRotationBarContentFrame(windowType); 2699 return rotatedBarFrame != null ? rotatedBarFrame : mBarContentFrames.get(windowType); 2700 } 2701 2702 /** 2703 * @return {@code true} if bar is allowed to be fully transparent when given window is show. 2704 * 2705 * <p>Prevents showing a transparent bar over a letterboxed activity which can make 2706 * notification icons or navigation buttons unreadable due to contrast between letterbox 2707 * background and an activity. For instance, this happens when letterbox background is solid 2708 * black while activity is white. To resolve this, only semi-transparent bars are allowed to 2709 * be drawn over letterboxed activity. 2710 */ 2711 @VisibleForTesting 2712 boolean isFullyTransparentAllowed(WindowState win, int windowType) { 2713 if (win == null) { 2714 return true; 2715 } 2716 return win.isFullyTransparentBarAllowed(getBarContentFrameForWindow(win, windowType)); 2717 } 2718 2719 private boolean drawsBarBackground(WindowState win) { 2720 if (win == null) { 2721 return true; 2722 } 2723 2724 final boolean drawsSystemBars = 2725 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; 2726 final boolean forceDrawsSystemBars = 2727 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0; 2728 2729 return forceDrawsSystemBars || drawsSystemBars; 2730 } 2731 2732 /** @return the current visibility flags with the status bar opacity related flags toggled. */ 2733 private int configureStatusBarOpacity(int appearance) { 2734 final boolean fullscreenDrawsBackground = 2735 drawsBarBackground(mTopFullscreenOpaqueWindowState); 2736 final boolean dockedDrawsBackground = 2737 drawsBarBackground(mTopDockedOpaqueWindowState); 2738 2739 if (fullscreenDrawsBackground && dockedDrawsBackground) { 2740 appearance &= ~APPEARANCE_OPAQUE_STATUS_BARS; 2741 } 2742 2743 if (!isFullyTransparentAllowed(mTopFullscreenOpaqueWindowState, TYPE_STATUS_BAR) 2744 || !isFullyTransparentAllowed(mTopDockedOpaqueWindowState, TYPE_STATUS_BAR)) { 2745 appearance |= APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; 2746 } 2747 2748 return appearance; 2749 } 2750 2751 /** 2752 * @return the current visibility flags with the nav-bar opacity related flags toggled based 2753 * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}. 2754 */ 2755 private int configureNavBarOpacity(int appearance, boolean dockedRootTaskVisible, 2756 boolean isDockedDividerResizing) { 2757 final boolean freeformRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea() 2758 .isRootTaskVisible(WINDOWING_MODE_FREEFORM); 2759 final boolean fullscreenDrawsBackground = 2760 drawsBarBackground(mTopFullscreenOpaqueWindowState); 2761 final boolean dockedDrawsBackground = 2762 drawsBarBackground(mTopDockedOpaqueWindowState); 2763 2764 if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) { 2765 if (fullscreenDrawsBackground && dockedDrawsBackground) { 2766 appearance = clearNavBarOpaqueFlag(appearance); 2767 } else if (dockedRootTaskVisible) { 2768 appearance = setNavBarOpaqueFlag(appearance); 2769 } 2770 } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) { 2771 if (dockedRootTaskVisible || freeformRootTaskVisible || isDockedDividerResizing) { 2772 if (mIsFreeformWindowOverlappingWithNavBar) { 2773 appearance = clearNavBarOpaqueFlag(appearance); 2774 } else { 2775 appearance = setNavBarOpaqueFlag(appearance); 2776 } 2777 } else if (fullscreenDrawsBackground) { 2778 appearance = clearNavBarOpaqueFlag(appearance); 2779 } 2780 } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) { 2781 if (isDockedDividerResizing) { 2782 appearance = setNavBarOpaqueFlag(appearance); 2783 } else if (freeformRootTaskVisible) { 2784 appearance = clearNavBarOpaqueFlag(appearance); 2785 } else { 2786 appearance = setNavBarOpaqueFlag(appearance); 2787 } 2788 } 2789 2790 if (!isFullyTransparentAllowed(mTopFullscreenOpaqueWindowState, TYPE_NAVIGATION_BAR) 2791 || !isFullyTransparentAllowed(mTopDockedOpaqueWindowState, TYPE_NAVIGATION_BAR)) { 2792 appearance |= APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; 2793 } 2794 2795 return appearance; 2796 } 2797 2798 private int setNavBarOpaqueFlag(int appearance) { 2799 return appearance | APPEARANCE_OPAQUE_NAVIGATION_BARS; 2800 } 2801 2802 private int clearNavBarOpaqueFlag(int appearance) { 2803 return appearance & ~APPEARANCE_OPAQUE_NAVIGATION_BARS; 2804 } 2805 2806 private boolean isImmersiveMode(WindowState win) { 2807 if (win == null) { 2808 return false; 2809 } 2810 return getNavigationBar() != null 2811 && canHideNavigationBar() 2812 && getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR) 2813 && win != getNotificationShade() 2814 && !win.isActivityTypeDream(); 2815 } 2816 2817 /** 2818 * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar 2819 */ 2820 private boolean canHideNavigationBar() { 2821 return hasNavigationBar(); 2822 } 2823 2824 private static boolean isNavBarEmpty(int systemUiFlags) { 2825 final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME 2826 | View.STATUS_BAR_DISABLE_BACK 2827 | View.STATUS_BAR_DISABLE_RECENT); 2828 2829 return (systemUiFlags & disableNavigationBar) == disableNavigationBar; 2830 } 2831 2832 private final Runnable mHiddenNavPanic = new Runnable() { 2833 @Override 2834 public void run() { 2835 synchronized (mLock) { 2836 if (!mService.mPolicy.isUserSetupComplete()) { 2837 // Swipe-up for navigation bar is disabled during setup 2838 return; 2839 } 2840 mPendingPanicGestureUptime = SystemClock.uptimeMillis(); 2841 updateSystemUiVisibilityLw(); 2842 } 2843 } 2844 }; 2845 2846 void onPowerKeyDown(boolean isScreenOn) { 2847 // Detect user pressing the power button in panic when an application has 2848 // taken over the whole screen. 2849 boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn, 2850 SystemClock.elapsedRealtime(), isImmersiveMode(mSystemUiControllingWindow), 2851 isNavBarEmpty(mLastDisableFlags)); 2852 if (panic) { 2853 mHandler.post(mHiddenNavPanic); 2854 } 2855 } 2856 2857 void onVrStateChangedLw(boolean enabled) { 2858 mImmersiveModeConfirmation.onVrStateChangedLw(enabled); 2859 } 2860 2861 /** 2862 * Called when the state of lock task mode changes. This should be used to disable immersive 2863 * mode confirmation. 2864 * 2865 * @param lockTaskState the new lock task mode state. One of 2866 * {@link ActivityManager#LOCK_TASK_MODE_NONE}, 2867 * {@link ActivityManager#LOCK_TASK_MODE_LOCKED}, 2868 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}. 2869 */ 2870 public void onLockTaskStateChangedLw(int lockTaskState) { 2871 mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState); 2872 } 2873 2874 boolean onSystemUiSettingsChanged() { 2875 return mImmersiveModeConfirmation.onSettingChanged(mService.mCurrentUserId); 2876 } 2877 2878 /** 2879 * Request a screenshot be taken. 2880 * 2881 * @param screenshotType The type of screenshot, for example either 2882 * {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or 2883 * {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION} 2884 * @param source Where the screenshot originated from (see WindowManager.ScreenshotSource) 2885 */ 2886 public void takeScreenshot(int screenshotType, int source) { 2887 if (mScreenshotHelper != null) { 2888 mScreenshotHelper.takeScreenshot(screenshotType, 2889 getStatusBar() != null && getStatusBar().isVisible(), 2890 getNavigationBar() != null && getNavigationBar().isVisible(), 2891 source, mHandler, null /* completionConsumer */); 2892 } 2893 } 2894 2895 RefreshRatePolicy getRefreshRatePolicy() { 2896 return mRefreshRatePolicy; 2897 } 2898 2899 void dump(String prefix, PrintWriter pw) { 2900 pw.print(prefix); pw.println("DisplayPolicy"); 2901 prefix += " "; 2902 pw.print(prefix); 2903 pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer); 2904 pw.print(" mDeskDockEnablesAccelerometer="); 2905 pw.println(mDeskDockEnablesAccelerometer); 2906 pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode)); 2907 pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState)); 2908 pw.print(prefix); pw.print("mAwake="); pw.print(mAwake); 2909 pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly); 2910 pw.print(" mScreenOnFully="); pw.println(mScreenOnFully); 2911 pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete); 2912 pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete); 2913 pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged); 2914 if (mLastDisableFlags != 0) { 2915 pw.print(prefix); pw.print("mLastDisableFlags=0x"); 2916 pw.println(Integer.toHexString(mLastDisableFlags)); 2917 } 2918 if (mLastAppearance != 0) { 2919 pw.print(prefix); pw.print("mLastAppearance="); 2920 pw.println(ViewDebug.flagsToString(InsetsFlags.class, "appearance", mLastAppearance)); 2921 } 2922 if (mLastBehavior != 0) { 2923 pw.print(prefix); pw.print("mLastBehavior="); 2924 pw.println(ViewDebug.flagsToString(InsetsFlags.class, "behavior", mLastBehavior)); 2925 } 2926 pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream); 2927 pw.print(" mDreamingLockscreen="); pw.println(mDreamingLockscreen); 2928 if (mStatusBar != null) { 2929 pw.print(prefix); pw.print("mStatusBar="); pw.println(mStatusBar); 2930 } 2931 if (mStatusBarAlt != null) { 2932 pw.print(prefix); pw.print("mStatusBarAlt="); pw.println(mStatusBarAlt); 2933 pw.print(prefix); pw.print("mStatusBarAltPosition="); 2934 pw.println(mStatusBarAltPosition); 2935 } 2936 if (mNotificationShade != null) { 2937 pw.print(prefix); pw.print("mExpandedPanel="); pw.println(mNotificationShade); 2938 } 2939 pw.print(prefix); pw.print("isKeyguardShowing="); pw.println(isKeyguardShowing()); 2940 if (mNavigationBar != null) { 2941 pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar); 2942 pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode); 2943 pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove); 2944 pw.print(prefix); pw.print("mNavigationBarPosition="); 2945 pw.println(mNavigationBarPosition); 2946 } 2947 if (mNavigationBarAlt != null) { 2948 pw.print(prefix); pw.print("mNavigationBarAlt="); pw.println(mNavigationBarAlt); 2949 pw.print(prefix); pw.print("mNavigationBarAltPosition="); 2950 pw.println(mNavigationBarAltPosition); 2951 } 2952 if (mClimateBarAlt != null) { 2953 pw.print(prefix); pw.print("mClimateBarAlt="); pw.println(mClimateBarAlt); 2954 pw.print(prefix); pw.print("mClimateBarAltPosition="); 2955 pw.println(mClimateBarAltPosition); 2956 } 2957 if (mExtraNavBarAlt != null) { 2958 pw.print(prefix); pw.print("mExtraNavBarAlt="); pw.println(mExtraNavBarAlt); 2959 pw.print(prefix); pw.print("mExtraNavBarAltPosition="); 2960 pw.println(mExtraNavBarAltPosition); 2961 } 2962 if (mFocusedWindow != null) { 2963 pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow); 2964 } 2965 if (mTopFullscreenOpaqueWindowState != null) { 2966 pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState="); 2967 pw.println(mTopFullscreenOpaqueWindowState); 2968 } 2969 if (mTopFullscreenOpaqueOrDimmingWindowState != null) { 2970 pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState="); 2971 pw.println(mTopFullscreenOpaqueOrDimmingWindowState); 2972 } 2973 if (mForcingShowNavBar) { 2974 pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar); 2975 pw.print(prefix); pw.print("mForcingShowNavBarLayer="); 2976 pw.println(mForcingShowNavBarLayer); 2977 } 2978 pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen); 2979 pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar); 2980 pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn); 2981 pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars="); 2982 pw.println(mDisplayContent.getInsetsPolicy().getRemoteInsetsControllerControlsSystemBars()); 2983 2984 pw.print(prefix); pw.println("Looper state:"); 2985 mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " "); 2986 } 2987 2988 private boolean supportsPointerLocation() { 2989 return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate(); 2990 } 2991 2992 void setPointerLocationEnabled(boolean pointerLocationEnabled) { 2993 if (!supportsPointerLocation()) { 2994 return; 2995 } 2996 2997 mHandler.sendEmptyMessage(pointerLocationEnabled 2998 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION); 2999 } 3000 3001 private void enablePointerLocation() { 3002 if (mPointerLocationView != null) { 3003 return; 3004 } 3005 3006 mPointerLocationView = new PointerLocationView(mContext); 3007 mPointerLocationView.setPrintCoords(false); 3008 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); 3009 lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; 3010 lp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 3011 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 3012 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 3013 lp.setFitInsetsTypes(0); 3014 lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 3015 if (ActivityManager.isHighEndGfx()) { 3016 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 3017 lp.privateFlags |= 3018 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED; 3019 } 3020 lp.format = PixelFormat.TRANSLUCENT; 3021 lp.setTitle("PointerLocation - display " + getDisplayId()); 3022 lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; 3023 final WindowManager wm = mContext.getSystemService(WindowManager.class); 3024 wm.addView(mPointerLocationView, lp); 3025 mDisplayContent.registerPointerEventListener(mPointerLocationView); 3026 } 3027 3028 private void disablePointerLocation() { 3029 if (mPointerLocationView == null) { 3030 return; 3031 } 3032 3033 mDisplayContent.unregisterPointerEventListener(mPointerLocationView); 3034 final WindowManager wm = mContext.getSystemService(WindowManager.class); 3035 wm.removeView(mPointerLocationView); 3036 mPointerLocationView = null; 3037 } 3038 3039 /** 3040 * Check if the window could be excluded from checking if the display has content. 3041 * 3042 * @param w WindowState to check if should be excluded. 3043 * @return True if the window type is PointerLocation which is excluded. 3044 */ 3045 boolean isWindowExcludedFromContent(WindowState w) { 3046 if (w != null && mPointerLocationView != null) { 3047 return w.mClient == mPointerLocationView.getWindowToken(); 3048 } 3049 3050 return false; 3051 } 3052 3053 void release() { 3054 mHandler.post(mGestureNavigationSettingsObserver::unregister); 3055 } 3056 3057 @VisibleForTesting 3058 static boolean isOverlappingWithNavBar(WindowState targetWindow, WindowState navBarWindow) { 3059 if (navBarWindow == null || !navBarWindow.isVisible() 3060 || targetWindow.mActivityRecord == null || !targetWindow.isVisible()) { 3061 return false; 3062 } 3063 3064 return Rect.intersects(targetWindow.getFrame(), navBarWindow.getFrame()); 3065 } 3066 3067 /** 3068 * @return Whether we should attach navigation bar to the app during transition. 3069 */ 3070 boolean shouldAttachNavBarToAppDuringTransition() { 3071 return mShouldAttachNavBarToAppDuringTransition && mNavigationBar != null; 3072 } 3073 } 3074