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.WINDOWING_MODE_FREEFORM; 20 import static android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR; 21 import static android.view.Display.TYPE_INTERNAL; 22 import static android.view.InsetsFrameProvider.SOURCE_ARBITRARY_RECTANGLE; 23 import static android.view.InsetsFrameProvider.SOURCE_CONTAINER_BOUNDS; 24 import static android.view.InsetsFrameProvider.SOURCE_DISPLAY; 25 import static android.view.InsetsFrameProvider.SOURCE_FRAME; 26 import static android.view.ViewRootImpl.CLIENT_IMMERSIVE_CONFIRMATION; 27 import static android.view.ViewRootImpl.CLIENT_TRANSIENT; 28 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS; 29 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS; 30 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS; 31 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS; 32 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_STATUS_BARS; 33 import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; 34 import static android.view.WindowInsetsController.APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; 35 import static android.view.WindowLayout.UNSPECIFIED_LENGTH; 36 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 37 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW; 38 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; 39 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; 40 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 41 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 42 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS; 43 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW; 44 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP; 45 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT; 46 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY; 47 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION; 48 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 49 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; 50 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; 51 import static android.view.WindowManager.LayoutParams.TYPE_NOTIFICATION_SHADE; 52 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; 53 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; 54 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_ADDITIONAL; 55 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; 56 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL; 57 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; 58 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 59 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; 60 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING; 61 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 62 import static android.view.WindowManagerGlobal.ADD_OKAY; 63 import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED; 64 import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE; 65 import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM; 66 import static android.view.WindowManagerPolicyConstants.NAV_BAR_INVALID; 67 import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT; 68 import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT; 69 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; 70 71 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ANIM; 72 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON; 73 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT; 74 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE; 75 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; 76 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; 77 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 78 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 79 80 import android.annotation.NonNull; 81 import android.annotation.Nullable; 82 import android.annotation.Px; 83 import android.app.ActivityManager; 84 import android.app.ActivityThread; 85 import android.app.LoadedApk; 86 import android.app.ResourcesManager; 87 import android.content.Context; 88 import android.content.Intent; 89 import android.content.res.Resources; 90 import android.graphics.Insets; 91 import android.graphics.PixelFormat; 92 import android.graphics.Rect; 93 import android.graphics.Region; 94 import android.gui.DropInputMode; 95 import android.hardware.power.Boost; 96 import android.os.Handler; 97 import android.os.IBinder; 98 import android.os.Looper; 99 import android.os.Message; 100 import android.os.SystemClock; 101 import android.os.SystemProperties; 102 import android.os.UserHandle; 103 import android.util.ArraySet; 104 import android.util.PrintWriterPrinter; 105 import android.util.Slog; 106 import android.util.SparseArray; 107 import android.view.DisplayInfo; 108 import android.view.Gravity; 109 import android.view.InsetsFlags; 110 import android.view.InsetsFrameProvider; 111 import android.view.InsetsSource; 112 import android.view.InsetsState; 113 import android.view.Surface; 114 import android.view.View; 115 import android.view.ViewDebug; 116 import android.view.WindowInsets.Type; 117 import android.view.WindowInsets.Type.InsetsType; 118 import android.view.WindowLayout; 119 import android.view.WindowManager; 120 import android.view.WindowManager.LayoutParams; 121 import android.view.WindowManagerGlobal; 122 import android.view.accessibility.AccessibilityManager; 123 import android.window.ClientWindowFrames; 124 125 import com.android.internal.R; 126 import com.android.internal.annotations.VisibleForTesting; 127 import com.android.internal.policy.ForceShowNavBarSettingsObserver; 128 import com.android.internal.policy.GestureNavigationSettingsObserver; 129 import com.android.internal.policy.ScreenDecorationsUtils; 130 import com.android.internal.protolog.common.ProtoLog; 131 import com.android.internal.statusbar.LetterboxDetails; 132 import com.android.internal.util.ScreenshotHelper; 133 import com.android.internal.util.ScreenshotRequest; 134 import com.android.internal.util.function.TriFunction; 135 import com.android.internal.view.AppearanceRegion; 136 import com.android.internal.widget.PointerLocationView; 137 import com.android.server.LocalServices; 138 import com.android.server.UiThread; 139 import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition; 140 import com.android.server.policy.WindowManagerPolicy.ScreenOnListener; 141 import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs; 142 import com.android.server.statusbar.StatusBarManagerInternal; 143 import com.android.server.wallpaper.WallpaperManagerInternal; 144 145 import java.io.PrintWriter; 146 import java.util.ArrayList; 147 import java.util.Arrays; 148 import java.util.Objects; 149 import java.util.function.Consumer; 150 151 /** 152 * The policy that provides the basic behaviors and states of a display to show UI. 153 */ 154 public class DisplayPolicy { 155 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM; 156 157 // The panic gesture may become active only after the keyguard is dismissed and the immersive 158 // app shows again. If that doesn't happen for 30s we drop the gesture. 159 private static final long PANIC_GESTURE_EXPIRATION = 30000; 160 161 // Controls navigation bar opacity depending on which workspace root tasks are currently 162 // visible. 163 // Nav bar is always opaque when either the freeform root task or docked root task is visible. 164 private static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0; 165 // Nav bar is always translucent when the freeform rootTask is visible, otherwise always opaque. 166 private static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1; 167 // Nav bar is never forced opaque. 168 private static final int NAV_BAR_FORCE_TRANSPARENT = 2; 169 170 /** Don't apply window animation (see {@link #selectAnimation}). */ 171 static final int ANIMATION_NONE = -1; 172 /** Use the transit animation in style resource (see {@link #selectAnimation}). */ 173 static final int ANIMATION_STYLEABLE = 0; 174 175 private static final int SHOW_TYPES_FOR_SWIPE = Type.statusBars() | Type.navigationBars(); 176 private static final int SHOW_TYPES_FOR_PANIC = Type.navigationBars(); 177 178 private static final int INSETS_OVERRIDE_INDEX_INVALID = -1; 179 180 // TODO(b/266197298): Remove this by a more general protocol from the insets providers. 181 private static final boolean USE_CACHED_INSETS_FOR_DISPLAY_SWITCH = 182 SystemProperties.getBoolean("persist.wm.debug.cached_insets_switch", true); 183 184 private final WindowManagerService mService; 185 private final Context mContext; 186 private final Context mUiContext; 187 private final DisplayContent mDisplayContent; 188 private final Object mLock; 189 private final Handler mHandler; 190 191 private Resources mCurrentUserResources; 192 193 private final boolean mCarDockEnablesAccelerometer; 194 private final boolean mDeskDockEnablesAccelerometer; 195 private final AccessibilityManager mAccessibilityManager; 196 private final ImmersiveModeConfirmation mImmersiveModeConfirmation; 197 private final ScreenshotHelper mScreenshotHelper; 198 199 private final Object mServiceAcquireLock = new Object(); 200 private long mPanicTime; 201 private final long mPanicThresholdMs; 202 private StatusBarManagerInternal mStatusBarManagerInternal; 203 204 @Px 205 private int mLeftGestureInset; 206 @Px 207 private int mRightGestureInset; 208 209 private boolean mCanSystemBarsBeShownByUser; 210 211 /** 212 * Let remote insets controller control system bars regardless of other settings. 213 */ 214 private boolean mRemoteInsetsControllerControlsSystemBars; 215 getStatusBarManagerInternal()216 StatusBarManagerInternal getStatusBarManagerInternal() { 217 synchronized (mServiceAcquireLock) { 218 if (mStatusBarManagerInternal == null) { 219 mStatusBarManagerInternal = 220 LocalServices.getService(StatusBarManagerInternal.class); 221 } 222 return mStatusBarManagerInternal; 223 } 224 } 225 226 // Will be null in client transient mode. 227 private SystemGesturesPointerEventListener mSystemGestures; 228 229 final DecorInsets mDecorInsets; 230 /** Currently it can only be non-null when physical display switch happens. */ 231 private DecorInsets.Cache mCachedDecorInsets; 232 233 private volatile int mLidState = LID_ABSENT; 234 private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; 235 private volatile boolean mHdmiPlugged; 236 237 private volatile boolean mHasStatusBar; 238 private volatile boolean mHasNavigationBar; 239 // Can the navigation bar ever move to the side? 240 private volatile boolean mNavigationBarCanMove; 241 private volatile boolean mNavigationBarAlwaysShowOnSideGesture; 242 243 // Written by vr manager thread, only read in this class. 244 private volatile boolean mPersistentVrModeEnabled; 245 246 private volatile boolean mAwake; 247 private volatile boolean mScreenOnEarly; 248 private volatile boolean mScreenOnFully; 249 private volatile ScreenOnListener mScreenOnListener; 250 251 private volatile boolean mKeyguardDrawComplete; 252 private volatile boolean mWindowManagerDrawComplete; 253 254 private boolean mImmersiveConfirmationWindowExists; 255 256 private WindowState mStatusBar = null; 257 private volatile WindowState mNotificationShade; 258 private WindowState mNavigationBar = null; 259 @NavigationBarPosition 260 private int mNavigationBarPosition = NAV_BAR_BOTTOM; 261 262 private final ArraySet<WindowState> mInsetsSourceWindowsExceptIme = new ArraySet<>(); 263 264 /** Apps which are controlling the appearance of system bars */ 265 private final ArraySet<ActivityRecord> mSystemBarColorApps = new ArraySet<>(); 266 267 /** Apps which are relaunching and were controlling the appearance of system bars */ 268 private final ArraySet<ActivityRecord> mRelaunchingSystemBarColorApps = new ArraySet<>(); 269 270 private boolean mIsFreeformWindowOverlappingWithNavBar; 271 272 private @InsetsType int mForciblyShownTypes; 273 274 private boolean mIsImmersiveMode; 275 276 // The windows we were told about in focusChanged. 277 private WindowState mFocusedWindow; 278 private WindowState mLastFocusedWindow; 279 280 private WindowState mSystemUiControllingWindow; 281 282 // Candidate window to determine the color of navigation bar. The window needs to be top 283 // fullscreen-app windows or dim layers that are intersecting with the window frame of 284 // navigation bar. 285 private WindowState mNavBarColorWindowCandidate; 286 287 // Candidate window to determine opacity and background of translucent navigation bar. 288 // The window frame must intersect the frame of navigation bar. 289 private WindowState mNavBarBackgroundWindowCandidate; 290 291 /** 292 * A collection of {@link AppearanceRegion} to indicate that which region of status bar applies 293 * which appearance. 294 */ 295 private final ArrayList<AppearanceRegion> mStatusBarAppearanceRegionList = new ArrayList<>(); 296 297 /** 298 * Windows to determine opacity and background of translucent status bar. The window needs to be 299 * opaque 300 */ 301 private final ArrayList<WindowState> mStatusBarBackgroundWindows = new ArrayList<>(); 302 303 /** 304 * A collection of {@link LetterboxDetails} of all visible activities to be sent to SysUI in 305 * order to determine status bar appearance 306 */ 307 private final ArrayList<LetterboxDetails> mLetterboxDetails = new ArrayList<>(); 308 309 private String mFocusedApp; 310 private int mLastDisableFlags; 311 private int mLastAppearance; 312 private int mLastBehavior; 313 private int mLastRequestedVisibleTypes = Type.defaultVisible(); 314 private AppearanceRegion[] mLastStatusBarAppearanceRegions; 315 private LetterboxDetails[] mLastLetterboxDetails; 316 317 /** The union of checked bounds while building {@link #mStatusBarAppearanceRegionList}. */ 318 private final Rect mStatusBarColorCheckedBounds = new Rect(); 319 320 /** The union of checked bounds while fetching {@link #mStatusBarBackgroundWindows}. */ 321 private final Rect mStatusBarBackgroundCheckedBounds = new Rect(); 322 323 // What we last reported to input dispatcher about whether the focused window is fullscreen. 324 private boolean mLastFocusIsFullscreen = false; 325 326 // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending. 327 private long mPendingPanicGestureUptime; 328 329 private static final Rect sTmpRect = new Rect(); 330 private static final Rect sTmpRect2 = new Rect(); 331 private static final Rect sTmpDisplayCutoutSafe = new Rect(); 332 private static final ClientWindowFrames sTmpClientFrames = new ClientWindowFrames(); 333 334 private final WindowLayout mWindowLayout = new WindowLayout(); 335 336 private WindowState mTopFullscreenOpaqueWindowState; 337 private boolean mTopIsFullscreen; 338 private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED; 339 340 /** 341 * Windows that provides gesture insets. If multiple windows provide gesture insets at the same 342 * side, the window with the highest z-order wins. 343 */ 344 private WindowState mLeftGestureHost; 345 private WindowState mTopGestureHost; 346 private WindowState mRightGestureHost; 347 private WindowState mBottomGestureHost; 348 349 private boolean mShowingDream; 350 private boolean mLastShowingDream; 351 private boolean mDreamingLockscreen; 352 private boolean mAllowLockscreenWhenOn; 353 354 private PointerLocationView mPointerLocationView; 355 356 private RefreshRatePolicy mRefreshRatePolicy; 357 358 /** 359 * If true, attach the navigation bar to the current transition app. 360 * The value is read from config_attachNavBarToAppDuringTransition and could be overlaid by RRO 361 * when the navigation bar mode is changed. 362 */ 363 private boolean mShouldAttachNavBarToAppDuringTransition; 364 365 // -------- PolicyHandler -------- 366 private static final int MSG_ENABLE_POINTER_LOCATION = 4; 367 private static final int MSG_DISABLE_POINTER_LOCATION = 5; 368 369 private final GestureNavigationSettingsObserver mGestureNavigationSettingsObserver; 370 371 private final WindowManagerInternal.AppTransitionListener mAppTransitionListener; 372 373 private final ForceShowNavBarSettingsObserver mForceShowNavBarSettingsObserver; 374 private boolean mForceShowNavigationBarEnabled; 375 376 private class PolicyHandler extends Handler { 377 PolicyHandler(Looper looper)378 PolicyHandler(Looper looper) { 379 super(looper); 380 } 381 382 @Override handleMessage(Message msg)383 public void handleMessage(Message msg) { 384 switch (msg.what) { 385 case MSG_ENABLE_POINTER_LOCATION: 386 enablePointerLocation(); 387 break; 388 case MSG_DISABLE_POINTER_LOCATION: 389 disablePointerLocation(); 390 break; 391 } 392 } 393 } 394 DisplayPolicy(WindowManagerService service, DisplayContent displayContent)395 DisplayPolicy(WindowManagerService service, DisplayContent displayContent) { 396 mService = service; 397 mContext = displayContent.isDefaultDisplay ? service.mContext 398 : service.mContext.createDisplayContext(displayContent.getDisplay()); 399 mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.getUiContext() 400 : service.mAtmService.mSystemThread 401 .getSystemUiContext(displayContent.getDisplayId()); 402 mDisplayContent = displayContent; 403 mDecorInsets = new DecorInsets(displayContent); 404 mLock = service.getWindowManagerLock(); 405 406 final int displayId = displayContent.getDisplayId(); 407 408 final Resources r = mContext.getResources(); 409 mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer); 410 mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer); 411 mCanSystemBarsBeShownByUser = !r.getBoolean( 412 R.bool.config_remoteInsetsControllerControlsSystemBars) || r.getBoolean( 413 R.bool.config_remoteInsetsControllerSystemBarsCanBeShownByUserAction); 414 mPanicThresholdMs = r.getInteger(R.integer.config_immersive_mode_confirmation_panic); 415 416 mAccessibilityManager = (AccessibilityManager) mContext.getSystemService( 417 Context.ACCESSIBILITY_SERVICE); 418 if (!displayContent.isDefaultDisplay) { 419 mAwake = true; 420 mScreenOnEarly = true; 421 mScreenOnFully = true; 422 } 423 424 final Looper looper = UiThread.getHandler().getLooper(); 425 mHandler = new PolicyHandler(looper); 426 // TODO(b/181821798) Migrate SystemGesturesPointerEventListener to use window context. 427 if (!CLIENT_TRANSIENT) { 428 SystemGesturesPointerEventListener.Callbacks gesturesPointerEventCallbacks = 429 new SystemGesturesPointerEventListener.Callbacks() { 430 431 private static final long MOUSE_GESTURE_DELAY_MS = 500; 432 433 private Runnable mOnSwipeFromLeft = this::onSwipeFromLeft; 434 private Runnable mOnSwipeFromTop = this::onSwipeFromTop; 435 private Runnable mOnSwipeFromRight = this::onSwipeFromRight; 436 private Runnable mOnSwipeFromBottom = this::onSwipeFromBottom; 437 438 private Insets getControllableInsets(WindowState win) { 439 if (win == null) { 440 return Insets.NONE; 441 } 442 final InsetsSourceProvider provider = win.getControllableInsetProvider(); 443 if (provider == null) { 444 return Insets.NONE; 445 } 446 return provider.getSource().calculateInsets(win.getBounds(), 447 true /* ignoreVisibility */); 448 } 449 450 @Override 451 public void onSwipeFromTop() { 452 synchronized (mLock) { 453 requestTransientBars(mTopGestureHost, 454 getControllableInsets(mTopGestureHost).top > 0); 455 } 456 } 457 458 @Override 459 public void onSwipeFromBottom() { 460 synchronized (mLock) { 461 requestTransientBars(mBottomGestureHost, 462 getControllableInsets(mBottomGestureHost).bottom > 0); 463 } 464 } 465 466 private boolean allowsSideSwipe(Region excludedRegion) { 467 return mNavigationBarAlwaysShowOnSideGesture 468 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion); 469 } 470 471 @Override 472 public void onSwipeFromRight() { 473 final Region excludedRegion = Region.obtain(); 474 synchronized (mLock) { 475 mDisplayContent.calculateSystemGestureExclusion( 476 excludedRegion, null /* outUnrestricted */); 477 final boolean hasWindow = 478 getControllableInsets(mRightGestureHost).right > 0; 479 if (hasWindow || allowsSideSwipe(excludedRegion)) { 480 requestTransientBars(mRightGestureHost, hasWindow); 481 } 482 } 483 excludedRegion.recycle(); 484 } 485 486 @Override 487 public void onSwipeFromLeft() { 488 final Region excludedRegion = Region.obtain(); 489 synchronized (mLock) { 490 mDisplayContent.calculateSystemGestureExclusion( 491 excludedRegion, null /* outUnrestricted */); 492 final boolean hasWindow = 493 getControllableInsets(mLeftGestureHost).left > 0; 494 if (hasWindow || allowsSideSwipe(excludedRegion)) { 495 requestTransientBars(mLeftGestureHost, hasWindow); 496 } 497 } 498 excludedRegion.recycle(); 499 } 500 501 @Override 502 public void onFling(int duration) { 503 if (mService.mPowerManagerInternal != null) { 504 mService.mPowerManagerInternal.setPowerBoost( 505 Boost.INTERACTION, duration); 506 } 507 } 508 509 @Override 510 public void onDebug() { 511 // no-op 512 } 513 514 private WindowOrientationListener getOrientationListener() { 515 final DisplayRotation rotation = mDisplayContent.getDisplayRotation(); 516 return rotation != null ? rotation.getOrientationListener() : null; 517 } 518 519 @Override 520 public void onDown() { 521 final WindowOrientationListener listener = getOrientationListener(); 522 if (listener != null) { 523 listener.onTouchStart(); 524 } 525 } 526 527 @Override 528 public void onUpOrCancel() { 529 final WindowOrientationListener listener = getOrientationListener(); 530 if (listener != null) { 531 listener.onTouchEnd(); 532 } 533 } 534 535 @Override 536 public void onMouseHoverAtLeft() { 537 mHandler.removeCallbacks(mOnSwipeFromLeft); 538 mHandler.postDelayed(mOnSwipeFromLeft, MOUSE_GESTURE_DELAY_MS); 539 } 540 541 @Override 542 public void onMouseHoverAtTop() { 543 mHandler.removeCallbacks(mOnSwipeFromTop); 544 mHandler.postDelayed(mOnSwipeFromTop, MOUSE_GESTURE_DELAY_MS); 545 } 546 547 @Override 548 public void onMouseHoverAtRight() { 549 mHandler.removeCallbacks(mOnSwipeFromRight); 550 mHandler.postDelayed(mOnSwipeFromRight, MOUSE_GESTURE_DELAY_MS); 551 } 552 553 @Override 554 public void onMouseHoverAtBottom() { 555 mHandler.removeCallbacks(mOnSwipeFromBottom); 556 mHandler.postDelayed(mOnSwipeFromBottom, MOUSE_GESTURE_DELAY_MS); 557 } 558 559 @Override 560 public void onMouseLeaveFromLeft() { 561 mHandler.removeCallbacks(mOnSwipeFromLeft); 562 } 563 564 @Override 565 public void onMouseLeaveFromTop() { 566 mHandler.removeCallbacks(mOnSwipeFromTop); 567 } 568 569 @Override 570 public void onMouseLeaveFromRight() { 571 mHandler.removeCallbacks(mOnSwipeFromRight); 572 } 573 574 @Override 575 public void onMouseLeaveFromBottom() { 576 mHandler.removeCallbacks(mOnSwipeFromBottom); 577 } 578 }; 579 mSystemGestures = new SystemGesturesPointerEventListener(mUiContext, mHandler, 580 gesturesPointerEventCallbacks); 581 displayContent.registerPointerEventListener(mSystemGestures); 582 } 583 mAppTransitionListener = new WindowManagerInternal.AppTransitionListener() { 584 585 private Runnable mAppTransitionPending = () -> { 586 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 587 if (statusBar != null) { 588 statusBar.appTransitionPending(displayId); 589 } 590 }; 591 592 private Runnable mAppTransitionCancelled = () -> { 593 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 594 if (statusBar != null) { 595 statusBar.appTransitionCancelled(displayId); 596 } 597 }; 598 599 private Runnable mAppTransitionFinished = () -> { 600 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 601 if (statusBar != null) { 602 statusBar.appTransitionFinished(displayId); 603 } 604 }; 605 606 @Override 607 public void onAppTransitionPendingLocked() { 608 mHandler.post(mAppTransitionPending); 609 } 610 611 @Override 612 public int onAppTransitionStartingLocked(long statusBarAnimationStartTime, 613 long statusBarAnimationDuration) { 614 mHandler.post(() -> { 615 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 616 if (statusBar != null) { 617 statusBar.appTransitionStarting(mContext.getDisplayId(), 618 statusBarAnimationStartTime, statusBarAnimationDuration); 619 } 620 }); 621 return 0; 622 } 623 624 @Override 625 public void onAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled) { 626 mHandler.post(mAppTransitionCancelled); 627 } 628 629 @Override 630 public void onAppTransitionFinishedLocked(IBinder token) { 631 mHandler.post(mAppTransitionFinished); 632 } 633 }; 634 displayContent.mAppTransition.registerListenerLocked(mAppTransitionListener); 635 displayContent.mTransitionController.registerLegacyListener(mAppTransitionListener); 636 if (CLIENT_TRANSIENT || CLIENT_IMMERSIVE_CONFIRMATION) { 637 mImmersiveModeConfirmation = null; 638 } else { 639 mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper, 640 mService.mVrModeEnabled, mCanSystemBarsBeShownByUser); 641 } 642 643 // TODO: Make it can take screenshot on external display 644 mScreenshotHelper = displayContent.isDefaultDisplay 645 ? new ScreenshotHelper(mContext) : null; 646 647 if (mDisplayContent.isDefaultDisplay) { 648 mHasStatusBar = true; 649 mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar); 650 651 // Allow a system property to override this. Used by the emulator. 652 // See also hasNavigationBar(). 653 String navBarOverride = SystemProperties.get("qemu.hw.mainkeys"); 654 if ("1".equals(navBarOverride)) { 655 mHasNavigationBar = false; 656 } else if ("0".equals(navBarOverride)) { 657 mHasNavigationBar = true; 658 } 659 } else { 660 mHasStatusBar = false; 661 mHasNavigationBar = mDisplayContent.supportsSystemDecorations(); 662 } 663 664 mRefreshRatePolicy = new RefreshRatePolicy(mService, 665 mDisplayContent.getDisplayInfo(), 666 mService.mHighRefreshRateDenylist); 667 668 mGestureNavigationSettingsObserver = new GestureNavigationSettingsObserver(mHandler, 669 mContext, () -> { 670 synchronized (mLock) { 671 onConfigurationChanged(); 672 if (!CLIENT_TRANSIENT) { 673 mSystemGestures.onConfigurationChanged(); 674 } 675 mDisplayContent.updateSystemGestureExclusion(); 676 } 677 }); 678 mHandler.post(mGestureNavigationSettingsObserver::register); 679 680 mForceShowNavBarSettingsObserver = new ForceShowNavBarSettingsObserver( 681 mHandler, mContext); 682 mForceShowNavBarSettingsObserver.setOnChangeRunnable(this::updateForceShowNavBarSettings); 683 mForceShowNavigationBarEnabled = mForceShowNavBarSettingsObserver.isEnabled(); 684 mHandler.post(mForceShowNavBarSettingsObserver::register); 685 } 686 updateForceShowNavBarSettings()687 private void updateForceShowNavBarSettings() { 688 synchronized (mLock) { 689 mForceShowNavigationBarEnabled = 690 mForceShowNavBarSettingsObserver.isEnabled(); 691 updateSystemBarAttributes(); 692 } 693 } 694 systemReady()695 void systemReady() { 696 if (!CLIENT_TRANSIENT) { 697 mSystemGestures.systemReady(); 698 } 699 if (mService.mPointerLocationEnabled) { 700 setPointerLocationEnabled(true); 701 } 702 } 703 getDisplayId()704 private int getDisplayId() { 705 return mDisplayContent.getDisplayId(); 706 } 707 setHdmiPlugged(boolean plugged)708 public void setHdmiPlugged(boolean plugged) { 709 setHdmiPlugged(plugged, false /* force */); 710 } 711 setHdmiPlugged(boolean plugged, boolean force)712 public void setHdmiPlugged(boolean plugged, boolean force) { 713 if (force || mHdmiPlugged != plugged) { 714 mHdmiPlugged = plugged; 715 mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */); 716 final Intent intent = new Intent(ACTION_HDMI_PLUGGED); 717 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 718 intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged); 719 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 720 } 721 } 722 isHdmiPlugged()723 boolean isHdmiPlugged() { 724 return mHdmiPlugged; 725 } 726 isCarDockEnablesAccelerometer()727 boolean isCarDockEnablesAccelerometer() { 728 return mCarDockEnablesAccelerometer; 729 } 730 isDeskDockEnablesAccelerometer()731 boolean isDeskDockEnablesAccelerometer() { 732 return mDeskDockEnablesAccelerometer; 733 } 734 setPersistentVrModeEnabled(boolean persistentVrModeEnabled)735 public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) { 736 mPersistentVrModeEnabled = persistentVrModeEnabled; 737 } 738 isPersistentVrModeEnabled()739 public boolean isPersistentVrModeEnabled() { 740 return mPersistentVrModeEnabled; 741 } 742 setDockMode(int dockMode)743 public void setDockMode(int dockMode) { 744 mDockMode = dockMode; 745 } 746 getDockMode()747 public int getDockMode() { 748 return mDockMode; 749 } 750 hasNavigationBar()751 public boolean hasNavigationBar() { 752 return mHasNavigationBar; 753 } 754 hasStatusBar()755 public boolean hasStatusBar() { 756 return mHasStatusBar; 757 } 758 hasSideGestures()759 boolean hasSideGestures() { 760 return mHasNavigationBar && (mLeftGestureInset > 0 || mRightGestureInset > 0); 761 } 762 navigationBarCanMove()763 public boolean navigationBarCanMove() { 764 return mNavigationBarCanMove; 765 } 766 setLidState(int lidState)767 public void setLidState(int lidState) { 768 mLidState = lidState; 769 } 770 getLidState()771 public int getLidState() { 772 return mLidState; 773 } 774 setAwake(boolean awake)775 public void setAwake(boolean awake) { 776 synchronized (mLock) { 777 if (awake == mAwake) { 778 return; 779 } 780 mAwake = awake; 781 if (!mDisplayContent.isDefaultDisplay) { 782 return; 783 } 784 mService.mAtmService.mKeyguardController.updateDeferTransitionForAod( 785 mAwake /* waiting */); 786 } 787 } 788 isAwake()789 public boolean isAwake() { 790 return mAwake; 791 } 792 isScreenOnEarly()793 public boolean isScreenOnEarly() { 794 return mScreenOnEarly; 795 } 796 isScreenOnFully()797 public boolean isScreenOnFully() { 798 return mScreenOnFully; 799 } 800 isKeyguardDrawComplete()801 public boolean isKeyguardDrawComplete() { 802 return mKeyguardDrawComplete; 803 } 804 isWindowManagerDrawComplete()805 public boolean isWindowManagerDrawComplete() { 806 return mWindowManagerDrawComplete; 807 } 808 isForceShowNavigationBarEnabled()809 public boolean isForceShowNavigationBarEnabled() { 810 return mForceShowNavigationBarEnabled; 811 } 812 getScreenOnListener()813 public ScreenOnListener getScreenOnListener() { 814 return mScreenOnListener; 815 } 816 817 isRemoteInsetsControllerControllingSystemBars()818 boolean isRemoteInsetsControllerControllingSystemBars() { 819 return mRemoteInsetsControllerControlsSystemBars; 820 } 821 822 @VisibleForTesting setRemoteInsetsControllerControlsSystemBars( boolean remoteInsetsControllerControlsSystemBars)823 void setRemoteInsetsControllerControlsSystemBars( 824 boolean remoteInsetsControllerControlsSystemBars) { 825 mRemoteInsetsControllerControlsSystemBars = remoteInsetsControllerControlsSystemBars; 826 } 827 screenTurnedOn(ScreenOnListener screenOnListener)828 public void screenTurnedOn(ScreenOnListener screenOnListener) { 829 synchronized (mLock) { 830 mScreenOnEarly = true; 831 mScreenOnFully = false; 832 mKeyguardDrawComplete = false; 833 mWindowManagerDrawComplete = false; 834 mScreenOnListener = screenOnListener; 835 } 836 } 837 screenTurnedOff()838 public void screenTurnedOff() { 839 synchronized (mLock) { 840 mScreenOnEarly = false; 841 mScreenOnFully = false; 842 mKeyguardDrawComplete = false; 843 mWindowManagerDrawComplete = false; 844 mScreenOnListener = null; 845 } 846 } 847 848 /** Return false if we are not awake yet or we have already informed of this event. */ finishKeyguardDrawn()849 public boolean finishKeyguardDrawn() { 850 synchronized (mLock) { 851 if (!mScreenOnEarly || mKeyguardDrawComplete) { 852 return false; 853 } 854 855 mKeyguardDrawComplete = true; 856 mWindowManagerDrawComplete = false; 857 } 858 return true; 859 } 860 861 /** Return false if screen is not turned on or we did already handle this case earlier. */ finishWindowsDrawn()862 public boolean finishWindowsDrawn() { 863 synchronized (mLock) { 864 if (!mScreenOnEarly || mWindowManagerDrawComplete) { 865 return false; 866 } 867 868 mWindowManagerDrawComplete = true; 869 } 870 return true; 871 } 872 873 /** Return false if it is not ready to turn on. */ finishScreenTurningOn()874 public boolean finishScreenTurningOn() { 875 synchronized (mLock) { 876 ProtoLog.d(WM_DEBUG_SCREEN_ON, 877 "finishScreenTurningOn: mAwake=%b, mScreenOnEarly=%b, " 878 + "mScreenOnFully=%b, mKeyguardDrawComplete=%b, " 879 + "mWindowManagerDrawComplete=%b", 880 mAwake, mScreenOnEarly, mScreenOnFully, mKeyguardDrawComplete, 881 mWindowManagerDrawComplete); 882 883 if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete 884 || (mAwake && !mKeyguardDrawComplete)) { 885 return false; 886 } 887 888 ProtoLog.i(WM_DEBUG_SCREEN_ON, "Finished screen turning on..."); 889 mScreenOnListener = null; 890 mScreenOnFully = true; 891 } 892 return true; 893 } 894 895 /** 896 * Sanitize the layout parameters coming from a client. Allows the policy 897 * to do things like ensure that windows of a specific type can't take 898 * input focus. 899 * 900 * @param attrs The window layout parameters to be modified. These values 901 * are modified in-place. 902 */ adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs)903 public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs) { 904 switch (attrs.type) { 905 case TYPE_SYSTEM_OVERLAY: 906 case TYPE_SECURE_SYSTEM_OVERLAY: 907 // These types of windows can't receive input events. 908 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 909 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 910 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; 911 break; 912 case TYPE_WALLPAPER: 913 // Dreams and wallpapers don't have an app window token and can thus not be 914 // letterboxed. Hence always let them extend under the cutout. 915 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 916 break; 917 918 case TYPE_TOAST: 919 // While apps should use the dedicated toast APIs to add such windows 920 // it possible legacy apps to add the window directly. Therefore, we 921 // make windows added directly by the app behave as a toast as much 922 // as possible in terms of timeout and animation. 923 if (attrs.hideTimeoutMilliseconds < 0 924 || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) { 925 attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT; 926 } 927 // Accessibility users may need longer timeout duration. This api compares 928 // original timeout with user's preference and return longer one. It returns 929 // original timeout if there's no preference. 930 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis( 931 (int) attrs.hideTimeoutMilliseconds, 932 AccessibilityManager.FLAG_CONTENT_TEXT); 933 // Toasts can't be clickable 934 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 935 break; 936 937 case TYPE_BASE_APPLICATION: 938 939 // A non-translucent main app window isn't allowed to fit insets, as it would create 940 // a hole on the display! 941 if (attrs.isFullscreen() && win.mActivityRecord != null 942 && win.mActivityRecord.fillsParent() 943 && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0 944 && attrs.getFitInsetsTypes() != 0) { 945 throw new IllegalArgumentException("Illegal attributes: Main activity window" 946 + " that isn't translucent trying to fit insets: " 947 + attrs.getFitInsetsTypes() 948 + " attrs=" + attrs); 949 } 950 break; 951 } 952 953 if (LayoutParams.isSystemAlertWindowType(attrs.type)) { 954 float maxOpacity = mService.mMaximumObscuringOpacityForTouch; 955 if (attrs.alpha > maxOpacity 956 && (attrs.flags & FLAG_NOT_TOUCHABLE) != 0 957 && (attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) == 0) { 958 // The app is posting a SAW with the intent of letting touches pass through, but 959 // they are going to be deemed untrusted and will be blocked. Try to honor the 960 // intent of letting touches pass through at the cost of 0.2 opacity for app 961 // compatibility reasons. More details on b/218777508. 962 Slog.w(TAG, String.format( 963 "App %s has a system alert window (type = %d) with FLAG_NOT_TOUCHABLE and " 964 + "LayoutParams.alpha = %.2f > %.2f, setting alpha to %.2f to " 965 + "let touches pass through (if this is isn't desirable, remove " 966 + "flag FLAG_NOT_TOUCHABLE).", 967 attrs.packageName, attrs.type, attrs.alpha, maxOpacity, maxOpacity)); 968 attrs.alpha = maxOpacity; 969 win.mWinAnimator.mAlpha = maxOpacity; 970 } 971 } 972 973 if (!win.mSession.mCanSetUnrestrictedGestureExclusion) { 974 attrs.privateFlags &= ~PRIVATE_FLAG_UNRESTRICTED_GESTURE_EXCLUSION; 975 } 976 } 977 978 /** 979 * Add additional policy if needed to ensure the window or its children should not receive any 980 * input. 981 */ setDropInputModePolicy(WindowState win, LayoutParams attrs)982 public void setDropInputModePolicy(WindowState win, LayoutParams attrs) { 983 if (attrs.type == TYPE_TOAST 984 && (attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) == 0) { 985 // Toasts should not receive input. These windows should not have any children, so 986 // force this hierarchy of windows to drop all input. 987 mService.mTransactionFactory.get() 988 .setDropInputMode(win.getSurfaceControl(), DropInputMode.ALL).apply(); 989 } 990 } 991 992 /** 993 * Check if a window can be added to the system. 994 * 995 * Currently enforces that two window types are singletons per display: 996 * <ul> 997 * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li> 998 * <li>{@link WindowManager.LayoutParams#TYPE_NOTIFICATION_SHADE}</li> 999 * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li> 1000 * </ul> 1001 * 1002 * @param attrs Information about the window to be added. 1003 * 1004 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, 1005 * WindowManagerImpl.ADD_MULTIPLE_SINGLETON 1006 */ validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid)1007 int validateAddingWindowLw(WindowManager.LayoutParams attrs, int callingPid, int callingUid) { 1008 if ((attrs.privateFlags & PRIVATE_FLAG_TRUSTED_OVERLAY) != 0) { 1009 mContext.enforcePermission( 1010 android.Manifest.permission.INTERNAL_SYSTEM_WINDOW, callingPid, callingUid, 1011 "DisplayPolicy"); 1012 } 1013 if ((attrs.privateFlags & PRIVATE_FLAG_INTERCEPT_GLOBAL_DRAG_AND_DROP) != 0) { 1014 ActivityTaskManagerService.enforceTaskPermission("DisplayPolicy"); 1015 } 1016 1017 switch (attrs.type) { 1018 case TYPE_STATUS_BAR: 1019 mContext.enforcePermission( 1020 android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, 1021 "DisplayPolicy"); 1022 if (mStatusBar != null && mStatusBar.isAlive()) { 1023 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; 1024 } 1025 break; 1026 case TYPE_NOTIFICATION_SHADE: 1027 mContext.enforcePermission( 1028 android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, 1029 "DisplayPolicy"); 1030 if (mNotificationShade != null) { 1031 if (mNotificationShade.isAlive()) { 1032 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; 1033 } 1034 } 1035 break; 1036 case TYPE_NAVIGATION_BAR: 1037 mContext.enforcePermission( 1038 android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, 1039 "DisplayPolicy"); 1040 if (mNavigationBar != null && mNavigationBar.isAlive()) { 1041 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; 1042 } 1043 break; 1044 case TYPE_NAVIGATION_BAR_PANEL: 1045 // Check for permission if the caller is not the recents component. 1046 if (!mService.mAtmService.isCallerRecents(callingUid)) { 1047 mContext.enforcePermission( 1048 android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, 1049 "DisplayPolicy"); 1050 } 1051 break; 1052 case TYPE_STATUS_BAR_ADDITIONAL: 1053 case TYPE_STATUS_BAR_SUB_PANEL: 1054 case TYPE_VOICE_INTERACTION_STARTING: 1055 mContext.enforcePermission( 1056 android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, 1057 "DisplayPolicy"); 1058 break; 1059 case TYPE_STATUS_BAR_PANEL: 1060 return WindowManagerGlobal.ADD_INVALID_TYPE; 1061 } 1062 1063 if (attrs.providedInsets != null) { 1064 // Recents component is allowed to add inset types. 1065 if (!mService.mAtmService.isCallerRecents(callingUid)) { 1066 mContext.enforcePermission( 1067 android.Manifest.permission.STATUS_BAR_SERVICE, callingPid, callingUid, 1068 "DisplayPolicy"); 1069 } 1070 } 1071 return ADD_OKAY; 1072 } 1073 1074 /** 1075 * Called when a window is being added to the system. Must not throw an exception. 1076 * 1077 * @param win The window being added. 1078 * @param attrs Information about the window to be added. 1079 */ addWindowLw(WindowState win, WindowManager.LayoutParams attrs)1080 void addWindowLw(WindowState win, WindowManager.LayoutParams attrs) { 1081 switch (attrs.type) { 1082 case TYPE_NOTIFICATION_SHADE: 1083 mNotificationShade = win; 1084 break; 1085 case TYPE_STATUS_BAR: 1086 mStatusBar = win; 1087 break; 1088 case TYPE_NAVIGATION_BAR: 1089 mNavigationBar = win; 1090 break; 1091 } 1092 if ((attrs.privateFlags & PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW) != 0) { 1093 mImmersiveConfirmationWindowExists = true; 1094 } 1095 if (attrs.providedInsets != null) { 1096 for (int i = attrs.providedInsets.length - 1; i >= 0; i--) { 1097 final InsetsFrameProvider provider = attrs.providedInsets[i]; 1098 // The index of the provider and corresponding insets types cannot change at 1099 // runtime as ensured in WMS. Make use of the index in the provider directly 1100 // to access the latest provided size at runtime. 1101 final TriFunction<DisplayFrames, WindowContainer, Rect, Integer> frameProvider = 1102 getFrameProvider(win, i, INSETS_OVERRIDE_INDEX_INVALID); 1103 final InsetsFrameProvider.InsetsSizeOverride[] overrides = 1104 provider.getInsetsSizeOverrides(); 1105 final SparseArray<TriFunction<DisplayFrames, WindowContainer, Rect, Integer>> 1106 overrideProviders; 1107 if (overrides != null) { 1108 overrideProviders = new SparseArray<>(); 1109 for (int j = overrides.length - 1; j >= 0; j--) { 1110 overrideProviders.put( 1111 overrides[j].getWindowType(), getFrameProvider(win, i, j)); 1112 } 1113 } else { 1114 overrideProviders = null; 1115 } 1116 final InsetsSourceProvider sourceProvider = mDisplayContent 1117 .getInsetsStateController().getOrCreateSourceProvider(provider.getId(), 1118 provider.getType()); 1119 sourceProvider.getSource().setFlags(provider.getFlags()); 1120 sourceProvider.setWindowContainer(win, frameProvider, overrideProviders); 1121 mInsetsSourceWindowsExceptIme.add(win); 1122 } 1123 } 1124 } 1125 getFrameProvider( WindowState win, int index, int overrideIndex)1126 private static TriFunction<DisplayFrames, WindowContainer, Rect, Integer> getFrameProvider( 1127 WindowState win, int index, int overrideIndex) { 1128 return (displayFrames, windowContainer, inOutFrame) -> { 1129 final LayoutParams lp = win.mAttrs.forRotation(displayFrames.mRotation); 1130 final InsetsFrameProvider ifp = lp.providedInsets[index]; 1131 final Rect displayFrame = displayFrames.mUnrestricted; 1132 final Rect safe = displayFrames.mDisplayCutoutSafe; 1133 boolean extendByCutout = false; 1134 switch (ifp.getSource()) { 1135 case SOURCE_DISPLAY: 1136 inOutFrame.set(displayFrame); 1137 break; 1138 case SOURCE_CONTAINER_BOUNDS: 1139 inOutFrame.set(windowContainer.getBounds()); 1140 break; 1141 case SOURCE_FRAME: 1142 extendByCutout = 1143 (lp.privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0; 1144 break; 1145 case SOURCE_ARBITRARY_RECTANGLE: 1146 inOutFrame.set(ifp.getArbitraryRectangle()); 1147 break; 1148 } 1149 final Insets insetsSize = overrideIndex == INSETS_OVERRIDE_INDEX_INVALID 1150 ? ifp.getInsetsSize() 1151 : ifp.getInsetsSizeOverrides()[overrideIndex].getInsetsSize(); 1152 1153 if (ifp.getMinimalInsetsSizeInDisplayCutoutSafe() != null) { 1154 sTmpRect2.set(inOutFrame); 1155 } 1156 calculateInsetsFrame(inOutFrame, insetsSize); 1157 1158 if (extendByCutout && insetsSize != null) { 1159 WindowLayout.extendFrameByCutout(safe, displayFrame, inOutFrame, sTmpRect); 1160 } 1161 1162 if (ifp.getMinimalInsetsSizeInDisplayCutoutSafe() != null) { 1163 // The insets is at least with the given size within the display cutout safe area. 1164 // Calculate the smallest size. 1165 calculateInsetsFrame(sTmpRect2, ifp.getMinimalInsetsSizeInDisplayCutoutSafe()); 1166 WindowLayout.extendFrameByCutout(safe, displayFrame, sTmpRect2, sTmpRect); 1167 // If it's larger than previous calculation, use it. 1168 if (sTmpRect2.contains(inOutFrame)) { 1169 inOutFrame.set(sTmpRect2); 1170 } 1171 } 1172 return ifp.getFlags(); 1173 }; 1174 } 1175 1176 /** 1177 * Calculate the insets frame given the insets size and the source frame. 1178 * @param inOutFrame the source frame. 1179 * @param insetsSize the insets size. Only the first non-zero value will be taken. 1180 */ calculateInsetsFrame(Rect inOutFrame, Insets insetsSize)1181 private static void calculateInsetsFrame(Rect inOutFrame, Insets insetsSize) { 1182 if (insetsSize == null) { 1183 return; 1184 } 1185 // Only one side of the provider shall be applied. Check in the order of left - top - 1186 // right - bottom, only the first non-zero value will be applied. 1187 if (insetsSize.left != 0) { 1188 inOutFrame.right = inOutFrame.left + insetsSize.left; 1189 } else if (insetsSize.top != 0) { 1190 inOutFrame.bottom = inOutFrame.top + insetsSize.top; 1191 } else if (insetsSize.right != 0) { 1192 inOutFrame.left = inOutFrame.right - insetsSize.right; 1193 } else if (insetsSize.bottom != 0) { 1194 inOutFrame.top = inOutFrame.bottom - insetsSize.bottom; 1195 } else { 1196 inOutFrame.setEmpty(); 1197 } 1198 } 1199 getImeSourceFrameProvider()1200 TriFunction<DisplayFrames, WindowContainer, Rect, Integer> getImeSourceFrameProvider() { 1201 return (displayFrames, windowContainer, inOutFrame) -> { 1202 WindowState windowState = windowContainer.asWindowState(); 1203 if (windowState == null) { 1204 throw new IllegalArgumentException("IME insets must be provided by a window."); 1205 } 1206 1207 if (!ENABLE_HIDE_IME_CAPTION_BAR && mNavigationBar != null 1208 && navigationBarPosition(displayFrames.mRotation) == NAV_BAR_BOTTOM) { 1209 // In gesture navigation, nav bar frame is larger than frame to calculate insets. 1210 // IME should not provide frame which is smaller than the nav bar frame. Otherwise, 1211 // nav bar might be overlapped with the content of the client when IME is shown. 1212 sTmpRect.set(inOutFrame); 1213 sTmpRect.intersectUnchecked(mNavigationBar.getFrame()); 1214 inOutFrame.inset(windowState.mGivenContentInsets); 1215 inOutFrame.union(sTmpRect); 1216 } else { 1217 inOutFrame.inset(windowState.mGivenContentInsets); 1218 } 1219 return 0; 1220 }; 1221 } 1222 1223 /** 1224 * Called when a window is being removed from a window manager. Must not 1225 * throw an exception -- clean up as much as possible. 1226 * 1227 * @param win The window being removed. 1228 */ 1229 void removeWindowLw(WindowState win) { 1230 if (mStatusBar == win) { 1231 mStatusBar = null; 1232 } else if (mNavigationBar == win) { 1233 mNavigationBar = null; 1234 } else if (mNotificationShade == win) { 1235 mNotificationShade = null; 1236 } 1237 if (mLastFocusedWindow == win) { 1238 mLastFocusedWindow = null; 1239 } 1240 1241 if (win.hasInsetsSourceProvider()) { 1242 final SparseArray<InsetsSourceProvider> providers = win.getInsetsSourceProviders(); 1243 final InsetsStateController controller = mDisplayContent.getInsetsStateController(); 1244 for (int index = providers.size() - 1; index >= 0; index--) { 1245 final InsetsSourceProvider provider = providers.valueAt(index); 1246 provider.setWindowContainer( 1247 null /* windowContainer */, 1248 null /* frameProvider */, 1249 null /* overrideFrameProviders */); 1250 controller.removeSourceProvider(provider.getSource().getId()); 1251 } 1252 } 1253 mInsetsSourceWindowsExceptIme.remove(win); 1254 if ((win.mAttrs.privateFlags & PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW) != 0) { 1255 mImmersiveConfirmationWindowExists = false; 1256 } 1257 } 1258 1259 WindowState getStatusBar() { 1260 return mStatusBar; 1261 } 1262 1263 WindowState getNotificationShade() { 1264 return mNotificationShade; 1265 } 1266 1267 WindowState getNavigationBar() { 1268 return mNavigationBar; 1269 } 1270 1271 boolean isImmersiveMode() { 1272 return mIsImmersiveMode; 1273 } 1274 1275 /** 1276 * Control the animation to run when a window's state changes. Return a positive number to 1277 * force the animation to a specific resource ID, {@link #ANIMATION_STYLEABLE} to use the 1278 * style resource defining the animation, or {@link #ANIMATION_NONE} for no animation. 1279 * 1280 * @param win The window that is changing. 1281 * @param transit What is happening to the window: 1282 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER}, 1283 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT}, 1284 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or 1285 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}. 1286 * 1287 * @return Resource ID of the actual animation to use, or {@link #ANIMATION_NONE} for none. 1288 */ 1289 int selectAnimation(WindowState win, int transit) { 1290 ProtoLog.i(WM_DEBUG_ANIM, "selectAnimation in %s: transit=%d", win, transit); 1291 1292 if (transit == TRANSIT_PREVIEW_DONE) { 1293 if (win.hasAppShownWindows()) { 1294 if (win.isActivityTypeHome()) { 1295 // Dismiss the starting window as soon as possible to avoid the crossfade out 1296 // with old content because home is easier to have different UI states. 1297 return ANIMATION_NONE; 1298 } 1299 ProtoLog.i(WM_DEBUG_ANIM, "**** STARTING EXIT"); 1300 return R.anim.app_starting_exit; 1301 } 1302 } 1303 1304 return ANIMATION_STYLEABLE; 1305 } 1306 1307 // TODO (b/277891341): Remove this and related usages. This has been replaced by 1308 // InsetsSource#FLAG_FORCE_CONSUMING. 1309 public boolean areSystemBarsForcedConsumedLw() { 1310 return false; 1311 } 1312 1313 /** 1314 * Computes the frames of display (its logical size, rotation and cutout should already be set) 1315 * used to layout window. This method only changes the given display frames, insets state and 1316 * some temporal states, but doesn't change the window frames used to show on screen. 1317 */ 1318 void simulateLayoutDisplay(DisplayFrames displayFrames) { 1319 sTmpClientFrames.attachedFrame = null; 1320 for (int i = mInsetsSourceWindowsExceptIme.size() - 1; i >= 0; i--) { 1321 final WindowState win = mInsetsSourceWindowsExceptIme.valueAt(i); 1322 mWindowLayout.computeFrames(win.mAttrs.forRotation(displayFrames.mRotation), 1323 displayFrames.mInsetsState, displayFrames.mDisplayCutoutSafe, 1324 displayFrames.mUnrestricted, win.getWindowingMode(), UNSPECIFIED_LENGTH, 1325 UNSPECIFIED_LENGTH, win.getRequestedVisibleTypes(), win.mGlobalScale, 1326 sTmpClientFrames); 1327 final SparseArray<InsetsSourceProvider> providers = win.getInsetsSourceProviders(); 1328 final InsetsState state = displayFrames.mInsetsState; 1329 for (int index = providers.size() - 1; index >= 0; index--) { 1330 state.addSource(providers.valueAt(index).createSimulatedSource( 1331 displayFrames, sTmpClientFrames.frame)); 1332 } 1333 } 1334 } 1335 1336 void onDisplayInfoChanged(DisplayInfo info) { 1337 if (!CLIENT_TRANSIENT) { 1338 mSystemGestures.onDisplayInfoChanged(info); 1339 } 1340 } 1341 1342 /** 1343 * Called for each window attached to the window manager as layout is proceeding. The 1344 * implementation of this function must take care of setting the window's frame, either here or 1345 * in finishLayout(). 1346 * 1347 * @param win The window being positioned. 1348 * @param attached For sub-windows, the window it is attached to; this 1349 * window will already have had layoutWindow() called on it 1350 * so you can use its Rect. Otherwise null. 1351 * @param displayFrames The display frames. 1352 */ 1353 public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) { 1354 if (win.skipLayout()) { 1355 return; 1356 } 1357 1358 // This window might be in the simulated environment. 1359 // We invoke this to get the proper DisplayFrames. 1360 displayFrames = win.getDisplayFrames(displayFrames); 1361 1362 final WindowManager.LayoutParams attrs = win.mAttrs.forRotation(displayFrames.mRotation); 1363 sTmpClientFrames.attachedFrame = attached != null ? attached.getFrame() : null; 1364 1365 // If this window has different LayoutParams for rotations, we cannot trust its requested 1366 // size. Because it might have not sent its requested size for the new rotation. 1367 final boolean trustedSize = attrs == win.mAttrs; 1368 final int requestedWidth = trustedSize ? win.mRequestedWidth : UNSPECIFIED_LENGTH; 1369 final int requestedHeight = trustedSize ? win.mRequestedHeight : UNSPECIFIED_LENGTH; 1370 1371 mWindowLayout.computeFrames(attrs, win.getInsetsState(), displayFrames.mDisplayCutoutSafe, 1372 win.getBounds(), win.getWindowingMode(), requestedWidth, requestedHeight, 1373 win.getRequestedVisibleTypes(), win.mGlobalScale, sTmpClientFrames); 1374 1375 win.setFrames(sTmpClientFrames, win.mRequestedWidth, win.mRequestedHeight); 1376 } 1377 1378 WindowState getTopFullscreenOpaqueWindow() { 1379 return mTopFullscreenOpaqueWindowState; 1380 } 1381 1382 boolean isTopLayoutFullscreen() { 1383 return mTopIsFullscreen; 1384 } 1385 1386 /** 1387 * Called following layout of all windows before each window has policy applied. 1388 */ 1389 public void beginPostLayoutPolicyLw() { 1390 mLeftGestureHost = null; 1391 mTopGestureHost = null; 1392 mRightGestureHost = null; 1393 mBottomGestureHost = null; 1394 mTopFullscreenOpaqueWindowState = null; 1395 mNavBarColorWindowCandidate = null; 1396 mNavBarBackgroundWindowCandidate = null; 1397 mStatusBarAppearanceRegionList.clear(); 1398 mLetterboxDetails.clear(); 1399 mStatusBarBackgroundWindows.clear(); 1400 mStatusBarColorCheckedBounds.setEmpty(); 1401 mStatusBarBackgroundCheckedBounds.setEmpty(); 1402 mSystemBarColorApps.clear(); 1403 1404 mAllowLockscreenWhenOn = false; 1405 mShowingDream = false; 1406 mIsFreeformWindowOverlappingWithNavBar = false; 1407 mForciblyShownTypes = 0; 1408 } 1409 1410 /** 1411 * Called following layout of all window to apply policy to each window. 1412 * 1413 * @param win The window being positioned. 1414 * @param attrs The LayoutParams of the window. 1415 * @param attached For sub-windows, the window it is attached to. Otherwise null. 1416 */ 1417 public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs, 1418 WindowState attached, WindowState imeTarget) { 1419 if (attrs.type == TYPE_NAVIGATION_BAR) { 1420 // Keep mNavigationBarPosition updated to make sure the transient detection and bar 1421 // color control is working correctly. 1422 final DisplayFrames displayFrames = mDisplayContent.mDisplayFrames; 1423 mNavigationBarPosition = navigationBarPosition(displayFrames.mRotation); 1424 } 1425 final boolean affectsSystemUi = win.canAffectSystemUiFlags(); 1426 if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi); 1427 applyKeyguardPolicy(win, imeTarget); 1428 1429 // Check if the freeform window overlaps with the navigation bar area. 1430 if (!mIsFreeformWindowOverlappingWithNavBar && win.inFreeformWindowingMode() 1431 && win.mActivityRecord != null && isOverlappingWithNavBar(win)) { 1432 mIsFreeformWindowOverlappingWithNavBar = true; 1433 } 1434 1435 if (win.hasInsetsSourceProvider()) { 1436 final SparseArray<InsetsSourceProvider> providers = win.getInsetsSourceProviders(); 1437 final Rect bounds = win.getBounds(); 1438 for (int index = providers.size() - 1; index >= 0; index--) { 1439 final InsetsSourceProvider provider = providers.valueAt(index); 1440 final InsetsSource source = provider.getSource(); 1441 if ((source.getType() 1442 & (Type.systemGestures() | Type.mandatorySystemGestures())) == 0) { 1443 continue; 1444 } 1445 if (mLeftGestureHost != null && mTopGestureHost != null 1446 && mRightGestureHost != null && mBottomGestureHost != null) { 1447 continue; 1448 } 1449 final Insets insets = source.calculateInsets(bounds, false /* ignoreVisibility */); 1450 if (mLeftGestureHost == null && insets.left > 0) { 1451 mLeftGestureHost = win; 1452 } 1453 if (mTopGestureHost == null && insets.top > 0) { 1454 mTopGestureHost = win; 1455 } 1456 if (mRightGestureHost == null && insets.right > 0) { 1457 mRightGestureHost = win; 1458 } 1459 if (mBottomGestureHost == null && insets.bottom > 0) { 1460 mBottomGestureHost = win; 1461 } 1462 } 1463 } 1464 1465 if (win.mSession.mCanForceShowingInsets) { 1466 mForciblyShownTypes |= win.mAttrs.forciblyShownTypes; 1467 } 1468 1469 if (!affectsSystemUi) { 1470 return; 1471 } 1472 1473 boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW 1474 && attrs.type < FIRST_SYSTEM_WINDOW; 1475 if (mTopFullscreenOpaqueWindowState == null) { 1476 final int fl = attrs.flags; 1477 if (win.isDreamWindow()) { 1478 // If the lockscreen was showing when the dream started then wait 1479 // for the dream to draw before hiding the lockscreen. 1480 if (!mDreamingLockscreen || (win.isVisible() && win.hasDrawn())) { 1481 mShowingDream = true; 1482 appWindow = true; 1483 } 1484 } 1485 1486 if (appWindow && attached == null && attrs.isFullscreen() 1487 && (fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { 1488 mAllowLockscreenWhenOn = true; 1489 } 1490 } 1491 1492 // Check the windows that overlap with system bars to determine system bars' appearance. 1493 if ((appWindow && attached == null && attrs.isFullscreen()) 1494 || attrs.type == TYPE_VOICE_INTERACTION) { 1495 // Record the top-fullscreen-app-window which will be used to determine system UI 1496 // controlling window. 1497 if (mTopFullscreenOpaqueWindowState == null) { 1498 mTopFullscreenOpaqueWindowState = win; 1499 } 1500 1501 // Cache app windows that is overlapping with the status bar to determine appearance 1502 // of status bar. 1503 if (mStatusBar != null 1504 && sTmpRect.setIntersect(win.getFrame(), mStatusBar.getFrame()) 1505 && !mStatusBarBackgroundCheckedBounds.contains(sTmpRect)) { 1506 mStatusBarBackgroundWindows.add(win); 1507 mStatusBarBackgroundCheckedBounds.union(sTmpRect); 1508 if (!mStatusBarColorCheckedBounds.contains(sTmpRect)) { 1509 mStatusBarAppearanceRegionList.add(new AppearanceRegion( 1510 win.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_STATUS_BARS, 1511 new Rect(win.getFrame()))); 1512 mStatusBarColorCheckedBounds.union(sTmpRect); 1513 addSystemBarColorApp(win); 1514 } 1515 } 1516 1517 // Cache app window that overlaps with the navigation bar area to determine opacity 1518 // and appearance of the navigation bar. We only need to cache one window because 1519 // there should be only one overlapping window if it's not in gesture navigation 1520 // mode; if it's in gesture navigation mode, the navigation bar will be 1521 // NAV_BAR_FORCE_TRANSPARENT and its appearance won't be decided by overlapping 1522 // windows. 1523 if (isOverlappingWithNavBar(win)) { 1524 if (mNavBarColorWindowCandidate == null) { 1525 mNavBarColorWindowCandidate = win; 1526 addSystemBarColorApp(win); 1527 } 1528 if (mNavBarBackgroundWindowCandidate == null) { 1529 mNavBarBackgroundWindowCandidate = win; 1530 } 1531 } 1532 1533 // Check if current activity is letterboxed in order create a LetterboxDetails 1534 // component to be passed to SysUI for status bar treatment 1535 final ActivityRecord currentActivity = win.getActivityRecord(); 1536 if (currentActivity != null) { 1537 final LetterboxDetails currentLetterboxDetails = currentActivity 1538 .mLetterboxUiController.getLetterboxDetails(); 1539 if (currentLetterboxDetails != null) { 1540 mLetterboxDetails.add(currentLetterboxDetails); 1541 } 1542 } 1543 } else if (win.isDimming()) { 1544 if (mStatusBar != null) { 1545 // If the dim window is below status bar window, we should update the appearance 1546 // region if needed. Otherwise, leave it as it is. 1547 final int statusBarLayer = mStatusBar.mToken.getWindowLayerFromType(); 1548 final int targetWindowLayer = win.mToken.getWindowLayerFromType(); 1549 if (targetWindowLayer < statusBarLayer 1550 && addStatusBarAppearanceRegionsForDimmingWindow( 1551 win.mAttrs.insetsFlags.appearance & APPEARANCE_LIGHT_STATUS_BARS, 1552 mStatusBar.getFrame(), win.getBounds(), win.getFrame())) { 1553 addSystemBarColorApp(win); 1554 } 1555 } 1556 if (isOverlappingWithNavBar(win) && mNavBarColorWindowCandidate == null) { 1557 mNavBarColorWindowCandidate = win; 1558 addSystemBarColorApp(win); 1559 } 1560 } else if (appWindow && attached == null 1561 && (mNavBarColorWindowCandidate == null || mNavBarBackgroundWindowCandidate == null) 1562 && win.getFrame().contains( 1563 getBarContentFrameForWindow(win, Type.navigationBars()))) { 1564 if (mNavBarColorWindowCandidate == null) { 1565 mNavBarColorWindowCandidate = win; 1566 addSystemBarColorApp(win); 1567 } 1568 if (mNavBarBackgroundWindowCandidate == null) { 1569 mNavBarBackgroundWindowCandidate = win; 1570 } 1571 } 1572 } 1573 1574 /** 1575 * Returns true if mStatusBarAppearanceRegionList is changed. 1576 */ 1577 private boolean addStatusBarAppearanceRegionsForDimmingWindow( 1578 int appearance, Rect statusBarFrame, Rect winBounds, Rect winFrame) { 1579 if (!sTmpRect.setIntersect(winBounds, statusBarFrame)) { 1580 return false; 1581 } 1582 if (mStatusBarColorCheckedBounds.contains(sTmpRect)) { 1583 return false; 1584 } 1585 if (appearance == 0 || !sTmpRect2.setIntersect(winFrame, statusBarFrame)) { 1586 mStatusBarAppearanceRegionList.add(new AppearanceRegion(0, new Rect(winBounds))); 1587 mStatusBarColorCheckedBounds.union(sTmpRect); 1588 return true; 1589 } 1590 // A dimming window can divide status bar into different appearance regions (up to 3). 1591 // +---------+-------------+---------+ 1592 // |/////////| |/////////| <-- Status Bar 1593 // +---------+-------------+---------+ 1594 // |/////////| |/////////| 1595 // |/////////| |/////////| 1596 // |/////////| |/////////| 1597 // |/////////| |/////////| 1598 // |/////////| |/////////| 1599 // +---------+-------------+---------+ 1600 // ^ ^ ^ 1601 // dim layer window dim layer 1602 mStatusBarAppearanceRegionList.add(new AppearanceRegion(appearance, new Rect(winFrame))); 1603 if (!sTmpRect.equals(sTmpRect2)) { 1604 if (sTmpRect.height() == sTmpRect2.height()) { 1605 if (sTmpRect.left != sTmpRect2.left) { 1606 mStatusBarAppearanceRegionList.add(new AppearanceRegion(0, new Rect( 1607 winBounds.left, winBounds.top, sTmpRect2.left, winBounds.bottom))); 1608 } 1609 if (sTmpRect.right != sTmpRect2.right) { 1610 mStatusBarAppearanceRegionList.add(new AppearanceRegion(0, new Rect( 1611 sTmpRect2.right, winBounds.top, winBounds.right, winBounds.bottom))); 1612 } 1613 } 1614 // We don't have vertical status bar yet, so we don't handle the other orientation. 1615 } 1616 mStatusBarColorCheckedBounds.union(sTmpRect); 1617 return true; 1618 } 1619 1620 private void addSystemBarColorApp(WindowState win) { 1621 final ActivityRecord app = win.mActivityRecord; 1622 if (app != null) { 1623 mSystemBarColorApps.add(app); 1624 } 1625 } 1626 1627 /** 1628 * Called following layout of all windows and after policy has been applied to each window. 1629 */ 1630 public void finishPostLayoutPolicyLw() { 1631 // If we are not currently showing a dream then remember the current 1632 // lockscreen state. We will use this to determine whether the dream 1633 // started while the lockscreen was showing and remember this state 1634 // while the dream is showing. 1635 if (!mShowingDream) { 1636 mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded(); 1637 } 1638 1639 updateSystemBarAttributes(); 1640 1641 if (mShowingDream != mLastShowingDream) { 1642 mLastShowingDream = mShowingDream; 1643 // Notify that isShowingDreamLw (which is checked in KeyguardController) has changed. 1644 mDisplayContent.notifyKeyguardFlagsChanged(); 1645 } 1646 1647 mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn); 1648 } 1649 1650 boolean areTypesForciblyShownTransiently(@InsetsType int types) { 1651 return (mForciblyShownTypes & types) == types; 1652 } 1653 1654 /** 1655 * Applies the keyguard policy to a specific window. 1656 * 1657 * @param win The window to apply the keyguard policy. 1658 * @param imeTarget The current IME target window. 1659 */ 1660 private void applyKeyguardPolicy(WindowState win, WindowState imeTarget) { 1661 if (win.canBeHiddenByKeyguard()) { 1662 final boolean shouldBeHiddenByKeyguard = shouldBeHiddenByKeyguard(win, imeTarget); 1663 if (win.mIsImWindow) { 1664 // Notify IME insets provider to freeze the IME insets. In case when turning off 1665 // the screen, the IME insets source window will be hidden because of keyguard 1666 // policy change and affects the system to freeze the last insets state. (And 1667 // unfreeze when the IME is going to show) 1668 mDisplayContent.getInsetsStateController().getImeSourceProvider().setFrozen( 1669 shouldBeHiddenByKeyguard); 1670 } 1671 if (shouldBeHiddenByKeyguard) { 1672 win.hide(false /* doAnimation */, true /* requestAnim */); 1673 } else { 1674 win.show(false /* doAnimation */, true /* requestAnim */); 1675 } 1676 } 1677 } 1678 1679 private boolean shouldBeHiddenByKeyguard(WindowState win, WindowState imeTarget) { 1680 if (!mDisplayContent.isDefaultDisplay || !isKeyguardShowing()) { 1681 return false; 1682 } 1683 1684 // Show IME over the keyguard if the target allows it. 1685 final boolean showImeOverKeyguard = imeTarget != null && imeTarget.isVisible() 1686 && win.mIsImWindow && (imeTarget.canShowWhenLocked() 1687 || !imeTarget.canBeHiddenByKeyguard()); 1688 if (showImeOverKeyguard) { 1689 return false; 1690 } 1691 1692 // Show SHOW_WHEN_LOCKED windows if keyguard is occluded. 1693 final boolean allowShowWhenLocked = isKeyguardOccluded() 1694 // Show error dialogs over apps that are shown on keyguard. 1695 && (win.canShowWhenLocked() 1696 || (win.mAttrs.privateFlags & LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR) != 0); 1697 return !allowShowWhenLocked; 1698 } 1699 1700 /** 1701 * @return Whether the top fullscreen app hides the given type of system bar. 1702 */ 1703 boolean topAppHidesSystemBar(@InsetsType int type) { 1704 if (mTopFullscreenOpaqueWindowState == null 1705 || getInsetsPolicy().areTypesForciblyShowing(type)) { 1706 return false; 1707 } 1708 return !mTopFullscreenOpaqueWindowState.isRequestedVisible(type); 1709 } 1710 1711 /** 1712 * Called when the user is switched. 1713 */ 1714 public void switchUser() { 1715 updateCurrentUserResources(); 1716 updateForceShowNavBarSettings(); 1717 } 1718 1719 /** 1720 * Called when the resource overlays change. 1721 */ 1722 void onOverlayChanged() { 1723 updateCurrentUserResources(); 1724 // Update the latest display size, cutout. 1725 mDisplayContent.updateDisplayInfo(); 1726 onConfigurationChanged(); 1727 if (!CLIENT_TRANSIENT) { 1728 mSystemGestures.onConfigurationChanged(); 1729 } 1730 } 1731 1732 /** 1733 * Called when the configuration has changed, and it's safe to load new values from resources. 1734 */ 1735 public void onConfigurationChanged() { 1736 final Resources res = getCurrentUserResources(); 1737 mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode); 1738 mLeftGestureInset = mGestureNavigationSettingsObserver.getLeftSensitivity(res); 1739 mRightGestureInset = mGestureNavigationSettingsObserver.getRightSensitivity(res); 1740 mNavigationBarAlwaysShowOnSideGesture = 1741 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture); 1742 mRemoteInsetsControllerControlsSystemBars = res.getBoolean( 1743 R.bool.config_remoteInsetsControllerControlsSystemBars); 1744 1745 updateConfigurationAndScreenSizeDependentBehaviors(); 1746 1747 final boolean shouldAttach = 1748 res.getBoolean(R.bool.config_attachNavBarToAppDuringTransition); 1749 if (mShouldAttachNavBarToAppDuringTransition != shouldAttach) { 1750 mShouldAttachNavBarToAppDuringTransition = shouldAttach; 1751 } 1752 } 1753 1754 void updateConfigurationAndScreenSizeDependentBehaviors() { 1755 final Resources res = getCurrentUserResources(); 1756 mNavigationBarCanMove = 1757 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight 1758 && res.getBoolean(R.bool.config_navBarCanMove); 1759 mDisplayContent.getDisplayRotation().updateUserDependentConfiguration(res); 1760 } 1761 1762 /** 1763 * Updates the current user's resources to pick up any changes for the current user (including 1764 * overlay paths) 1765 */ 1766 private void updateCurrentUserResources() { 1767 final int userId = mService.mAmInternal.getCurrentUserId(); 1768 final Context uiContext = getSystemUiContext(); 1769 1770 if (userId == UserHandle.USER_SYSTEM) { 1771 // Skip the (expensive) recreation of resources for the system user below and just 1772 // use the resources from the system ui context 1773 mCurrentUserResources = uiContext.getResources(); 1774 return; 1775 } 1776 1777 // For non-system users, ensure that the resources are loaded from the current 1778 // user's package info (see ContextImpl.createDisplayContext) 1779 final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo( 1780 uiContext.getPackageName(), null, 0, userId); 1781 mCurrentUserResources = ResourcesManager.getInstance().getResources( 1782 uiContext.getWindowContextToken(), 1783 pi.getResDir(), 1784 null /* splitResDirs */, 1785 pi.getOverlayDirs(), 1786 pi.getOverlayPaths(), 1787 pi.getApplicationInfo().sharedLibraryFiles, 1788 mDisplayContent.getDisplayId(), 1789 null /* overrideConfig */, 1790 uiContext.getResources().getCompatibilityInfo(), 1791 null /* classLoader */, 1792 null /* loaders */); 1793 } 1794 1795 @VisibleForTesting 1796 Resources getCurrentUserResources() { 1797 if (mCurrentUserResources == null) { 1798 updateCurrentUserResources(); 1799 } 1800 return mCurrentUserResources; 1801 } 1802 1803 @VisibleForTesting 1804 Context getContext() { 1805 return mContext; 1806 } 1807 1808 Context getSystemUiContext() { 1809 return mUiContext; 1810 } 1811 1812 @VisibleForTesting 1813 void setCanSystemBarsBeShownByUser(boolean canBeShown) { 1814 mCanSystemBarsBeShownByUser = canBeShown; 1815 } 1816 1817 void notifyDisplayReady() { 1818 mHandler.post(() -> { 1819 final int displayId = getDisplayId(); 1820 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 1821 if (statusBar != null) { 1822 statusBar.onDisplayReady(displayId); 1823 } 1824 final WallpaperManagerInternal wpMgr = LocalServices 1825 .getService(WallpaperManagerInternal.class); 1826 if (wpMgr != null) { 1827 wpMgr.onDisplayReady(displayId); 1828 } 1829 }); 1830 } 1831 1832 /** 1833 * Return corner radius in pixels that should be used on windows in order to cover the display. 1834 * 1835 * The radius is only valid for internal displays, since the corner radius of external displays 1836 * is not known at build time when window corners are configured. 1837 */ 1838 float getWindowCornerRadius() { 1839 return mDisplayContent.getDisplay().getType() == TYPE_INTERNAL 1840 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext) : 0f; 1841 } 1842 1843 boolean isShowingDreamLw() { 1844 return mShowingDream; 1845 } 1846 1847 /** The latest insets and frames for screen configuration calculation. */ 1848 static class DecorInsets { 1849 static class Info { 1850 /** 1851 * The insets for the areas that could never be removed, i.e. display cutout and 1852 * navigation bar. Note that its meaning is actually "decor insets". The "non" is just 1853 * because it is used to calculate {@link #mNonDecorFrame}. 1854 */ 1855 final Rect mNonDecorInsets = new Rect(); 1856 1857 /** 1858 * The stable insets that can affect configuration. The sources are usually from 1859 * display cutout, navigation bar, and status bar. 1860 */ 1861 final Rect mConfigInsets = new Rect(); 1862 1863 /** The display frame available after excluding {@link #mNonDecorInsets}. */ 1864 final Rect mNonDecorFrame = new Rect(); 1865 1866 /** 1867 * The available (stable) screen size that we should report for the configuration. 1868 * This must be no larger than {@link #mNonDecorFrame}; it may be smaller than that 1869 * to account for more transient decoration like a status bar. 1870 */ 1871 final Rect mConfigFrame = new Rect(); 1872 1873 /** The count of insets sources when calculating this info. */ 1874 int mLastInsetsSourceCount; 1875 1876 private boolean mNeedUpdate = true; 1877 1878 void update(DisplayContent dc, int rotation, int w, int h) { 1879 final DisplayFrames df = new DisplayFrames(); 1880 dc.updateDisplayFrames(df, rotation, w, h); 1881 dc.getDisplayPolicy().simulateLayoutDisplay(df); 1882 final InsetsState insetsState = df.mInsetsState; 1883 final Rect displayFrame = insetsState.getDisplayFrame(); 1884 final Insets decor = insetsState.calculateInsets(displayFrame, DECOR_TYPES, 1885 true /* ignoreVisibility */); 1886 final Insets statusBar = insetsState.calculateInsets(displayFrame, 1887 Type.statusBars(), true /* ignoreVisibility */); 1888 mNonDecorInsets.set(decor.left, decor.top, decor.right, decor.bottom); 1889 mConfigInsets.set(Math.max(statusBar.left, decor.left), 1890 Math.max(statusBar.top, decor.top), 1891 Math.max(statusBar.right, decor.right), 1892 Math.max(statusBar.bottom, decor.bottom)); 1893 mNonDecorFrame.set(displayFrame); 1894 mNonDecorFrame.inset(mNonDecorInsets); 1895 mConfigFrame.set(displayFrame); 1896 mConfigFrame.inset(mConfigInsets); 1897 mLastInsetsSourceCount = dc.getDisplayPolicy().mInsetsSourceWindowsExceptIme.size(); 1898 mNeedUpdate = false; 1899 } 1900 1901 void set(Info other) { 1902 mNonDecorInsets.set(other.mNonDecorInsets); 1903 mConfigInsets.set(other.mConfigInsets); 1904 mNonDecorFrame.set(other.mNonDecorFrame); 1905 mConfigFrame.set(other.mConfigFrame); 1906 mLastInsetsSourceCount = other.mLastInsetsSourceCount; 1907 mNeedUpdate = false; 1908 } 1909 1910 @Override 1911 public String toString() { 1912 final StringBuilder tmpSb = new StringBuilder(32); 1913 return "{nonDecorInsets=" + mNonDecorInsets.toShortString(tmpSb) 1914 + ", configInsets=" + mConfigInsets.toShortString(tmpSb) 1915 + ", nonDecorFrame=" + mNonDecorFrame.toShortString(tmpSb) 1916 + ", configFrame=" + mConfigFrame.toShortString(tmpSb) + '}'; 1917 } 1918 } 1919 1920 1921 static final int DECOR_TYPES = Type.displayCutout() | Type.navigationBars(); 1922 1923 /** 1924 * The types that may affect display configuration. This excludes cutout because it is 1925 * known from display info. 1926 */ 1927 static final int CONFIG_TYPES = Type.statusBars() | Type.navigationBars(); 1928 1929 private final DisplayContent mDisplayContent; 1930 private final Info[] mInfoForRotation = new Info[4]; 1931 final Info mTmpInfo = new Info(); 1932 1933 DecorInsets(DisplayContent dc) { 1934 mDisplayContent = dc; 1935 for (int i = mInfoForRotation.length - 1; i >= 0; i--) { 1936 mInfoForRotation[i] = new Info(); 1937 } 1938 } 1939 1940 Info get(int rotation, int w, int h) { 1941 final Info info = mInfoForRotation[rotation]; 1942 if (info.mNeedUpdate) { 1943 info.update(mDisplayContent, rotation, w, h); 1944 } 1945 return info; 1946 } 1947 1948 /** Called when the screen decor insets providers have changed. */ 1949 void invalidate() { 1950 for (Info info : mInfoForRotation) { 1951 info.mNeedUpdate = true; 1952 } 1953 } 1954 1955 void setTo(DecorInsets src) { 1956 for (int i = mInfoForRotation.length - 1; i >= 0; i--) { 1957 mInfoForRotation[i].set(src.mInfoForRotation[i]); 1958 } 1959 } 1960 1961 void dump(String prefix, PrintWriter pw) { 1962 for (int rotation = 0; rotation < mInfoForRotation.length; rotation++) { 1963 final DecorInsets.Info info = mInfoForRotation[rotation]; 1964 pw.println(prefix + Surface.rotationToString(rotation) + "=" + info); 1965 } 1966 } 1967 1968 private static class Cache { 1969 /** 1970 * If {@link #mPreserveId} is this value, it is in the middle of updating display 1971 * configuration before a transition is started. Then the active cache should be used. 1972 */ 1973 static final int ID_UPDATING_CONFIG = -1; 1974 final DecorInsets mDecorInsets; 1975 int mPreserveId; 1976 boolean mActive; 1977 1978 Cache(DisplayContent dc) { 1979 mDecorInsets = new DecorInsets(dc); 1980 } 1981 1982 boolean canPreserve() { 1983 return mPreserveId == ID_UPDATING_CONFIG || mDecorInsets.mDisplayContent 1984 .mTransitionController.inTransition(mPreserveId); 1985 } 1986 } 1987 } 1988 1989 /** 1990 * If the decor insets changes, the display configuration may be affected. The caller should 1991 * call {@link DisplayContent#sendNewConfiguration()} if this method returns {@code true}. 1992 */ 1993 boolean updateDecorInsetsInfo() { 1994 if (shouldKeepCurrentDecorInsets()) { 1995 return false; 1996 } 1997 final DisplayFrames displayFrames = mDisplayContent.mDisplayFrames; 1998 final int rotation = displayFrames.mRotation; 1999 final int dw = displayFrames.mWidth; 2000 final int dh = displayFrames.mHeight; 2001 final DecorInsets.Info newInfo = mDecorInsets.mTmpInfo; 2002 newInfo.update(mDisplayContent, rotation, dw, dh); 2003 final DecorInsets.Info currentInfo = getDecorInsetsInfo(rotation, dw, dh); 2004 if (newInfo.mConfigFrame.equals(currentInfo.mConfigFrame)) { 2005 // Even if the config frame is not changed in current rotation, it may change the 2006 // insets in other rotations if the source count is changed. 2007 if (newInfo.mLastInsetsSourceCount != currentInfo.mLastInsetsSourceCount) { 2008 for (int i = mDecorInsets.mInfoForRotation.length - 1; i >= 0; i--) { 2009 if (i != rotation) { 2010 final boolean flipSize = (i + rotation) % 2 == 1; 2011 final int w = flipSize ? dh : dw; 2012 final int h = flipSize ? dw : dh; 2013 mDecorInsets.mInfoForRotation[i].update(mDisplayContent, i, w, h); 2014 } 2015 } 2016 mDecorInsets.mInfoForRotation[rotation].set(newInfo); 2017 } 2018 return false; 2019 } 2020 if (mCachedDecorInsets != null && !mCachedDecorInsets.canPreserve() 2021 && !mDisplayContent.isSleeping()) { 2022 mCachedDecorInsets = null; 2023 } 2024 mDecorInsets.invalidate(); 2025 mDecorInsets.mInfoForRotation[rotation].set(newInfo); 2026 return true; 2027 } 2028 2029 DecorInsets.Info getDecorInsetsInfo(int rotation, int w, int h) { 2030 return mDecorInsets.get(rotation, w, h); 2031 } 2032 2033 /** Returns {@code true} to trust that {@link #mDecorInsets} already has the expected state. */ 2034 boolean shouldKeepCurrentDecorInsets() { 2035 return mCachedDecorInsets != null && mCachedDecorInsets.mActive 2036 && mCachedDecorInsets.canPreserve(); 2037 } 2038 2039 void physicalDisplayChanged() { 2040 if (USE_CACHED_INSETS_FOR_DISPLAY_SWITCH) { 2041 updateCachedDecorInsets(); 2042 } 2043 } 2044 2045 /** 2046 * Caches the current insets and switches current insets to previous cached insets. This is to 2047 * reduce multiple display configuration changes if there are multiple insets provider windows 2048 * which may trigger {@link #updateDecorInsetsInfo()} individually. 2049 */ 2050 @VisibleForTesting 2051 void updateCachedDecorInsets() { 2052 DecorInsets prevCache = null; 2053 if (mCachedDecorInsets == null) { 2054 mCachedDecorInsets = new DecorInsets.Cache(mDisplayContent); 2055 } else { 2056 prevCache = new DecorInsets(mDisplayContent); 2057 prevCache.setTo(mCachedDecorInsets.mDecorInsets); 2058 } 2059 // Set a special id to preserve it before a real id is available from transition. 2060 mCachedDecorInsets.mPreserveId = DecorInsets.Cache.ID_UPDATING_CONFIG; 2061 // Cache the current insets. 2062 mCachedDecorInsets.mDecorInsets.setTo(mDecorInsets); 2063 // Switch current to previous cache. 2064 if (prevCache != null) { 2065 mDecorInsets.setTo(prevCache); 2066 mCachedDecorInsets.mActive = true; 2067 } 2068 } 2069 2070 /** 2071 * Called after the display configuration is updated according to the physical change. Suppose 2072 * there should be a display change transition, so associate the cached decor insets with the 2073 * transition to limit the lifetime of using the cache. 2074 */ 2075 void physicalDisplayUpdated() { 2076 if (mCachedDecorInsets == null) { 2077 return; 2078 } 2079 if (!mDisplayContent.mTransitionController.isCollecting()) { 2080 // Unable to know when the display switch is finished. 2081 mCachedDecorInsets = null; 2082 return; 2083 } 2084 mCachedDecorInsets.mPreserveId = 2085 mDisplayContent.mTransitionController.getCollectingTransitionId(); 2086 // The validator will run after the transition is finished. So if the insets are changed 2087 // during the transition, it can update to the latest state. 2088 mDisplayContent.mTransitionController.mStateValidators.add(() -> { 2089 // The insets provider client may defer to change its window until screen is on. So 2090 // only validate when awake to avoid the cache being always dropped. 2091 if (!mDisplayContent.isSleeping() && updateDecorInsetsInfo()) { 2092 Slog.d(TAG, "Insets changed after display switch transition"); 2093 mDisplayContent.sendNewConfiguration(); 2094 } 2095 }); 2096 } 2097 2098 @NavigationBarPosition 2099 int navigationBarPosition(int displayRotation) { 2100 if (mNavigationBar != null) { 2101 final int gravity = mNavigationBar.mAttrs.forRotation(displayRotation).gravity; 2102 switch (gravity) { 2103 case Gravity.LEFT: 2104 return NAV_BAR_LEFT; 2105 case Gravity.RIGHT: 2106 return NAV_BAR_RIGHT; 2107 default: 2108 return NAV_BAR_BOTTOM; 2109 } 2110 } 2111 return NAV_BAR_INVALID; 2112 } 2113 2114 /** 2115 * A new window has been focused. 2116 */ 2117 public void focusChangedLw(WindowState lastFocus, WindowState newFocus) { 2118 mFocusedWindow = newFocus; 2119 mLastFocusedWindow = lastFocus; 2120 if (mDisplayContent.isDefaultDisplay) { 2121 mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus); 2122 } 2123 updateSystemBarAttributes(); 2124 } 2125 2126 @VisibleForTesting 2127 void requestTransientBars(WindowState swipeTarget, boolean isGestureOnSystemBar) { 2128 if (CLIENT_TRANSIENT) { 2129 return; 2130 } 2131 if (swipeTarget == null || !mService.mPolicy.isUserSetupComplete()) { 2132 // Swipe-up for navigation bar is disabled during setup 2133 return; 2134 } 2135 if (!mCanSystemBarsBeShownByUser) { 2136 Slog.d(TAG, "Remote insets controller disallows showing system bars - ignoring " 2137 + "request"); 2138 return; 2139 } 2140 final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider(); 2141 final InsetsControlTarget controlTarget = provider != null 2142 ? provider.getControlTarget() : null; 2143 2144 if (controlTarget == null || controlTarget == getNotificationShade()) { 2145 // No transient mode on lockscreen (in notification shade window). 2146 return; 2147 } 2148 2149 if (controlTarget != null) { 2150 final WindowState win = controlTarget.getWindow(); 2151 2152 if (win != null && win.isActivityTypeDream()) { 2153 return; 2154 } 2155 } 2156 2157 final @InsetsType int restorePositionTypes = (Type.statusBars() | Type.navigationBars()) 2158 & controlTarget.getRequestedVisibleTypes(); 2159 2160 final InsetsSourceProvider sp = swipeTarget.getControllableInsetProvider(); 2161 if (sp != null && sp.getSource().getType() == Type.navigationBars() 2162 && (restorePositionTypes & Type.navigationBars()) != 0) { 2163 // Don't show status bar when swiping on already visible navigation bar. 2164 // But restore the position of navigation bar if it has been moved by the control 2165 // target. 2166 controlTarget.showInsets(Type.navigationBars(), false /* fromIme */, 2167 null /* statsToken */); 2168 return; 2169 } 2170 2171 if (controlTarget.canShowTransient()) { 2172 // Show transient bars if they are hidden; restore position if they are visible. 2173 mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_SWIPE, 2174 isGestureOnSystemBar); 2175 controlTarget.showInsets(restorePositionTypes, false /* fromIme */, 2176 null /* statsToken */); 2177 } else { 2178 // Restore visibilities and positions of system bars. 2179 controlTarget.showInsets(Type.statusBars() | Type.navigationBars(), 2180 false /* fromIme */, null /* statsToken */); 2181 // To further allow the pull-down-from-the-top gesture to pull down the notification 2182 // shade as a consistent motion, we reroute the touch events here from the currently 2183 // touched window to the status bar after making it visible. 2184 if (swipeTarget == mStatusBar) { 2185 final boolean transferred = mStatusBar.transferTouch(); 2186 if (!transferred) { 2187 Slog.i(TAG, "Could not transfer touch to the status bar"); 2188 } 2189 } 2190 } 2191 if (CLIENT_IMMERSIVE_CONFIRMATION || CLIENT_TRANSIENT) { 2192 mStatusBarManagerInternal.confirmImmersivePrompt(); 2193 } else { 2194 mImmersiveModeConfirmation.confirmCurrentPrompt(); 2195 } 2196 } 2197 2198 boolean isKeyguardShowing() { 2199 return mService.mPolicy.isKeyguardShowing(); 2200 } 2201 private boolean isKeyguardOccluded() { 2202 // TODO (b/113840485): Handle per display keyguard. 2203 return mService.mPolicy.isKeyguardOccluded(); 2204 } 2205 2206 InsetsPolicy getInsetsPolicy() { 2207 return mDisplayContent.getInsetsPolicy(); 2208 } 2209 2210 /** 2211 * Called when an app has started replacing its main window. 2212 */ 2213 void addRelaunchingApp(ActivityRecord app) { 2214 if (mSystemBarColorApps.contains(app) && !app.hasStartingWindow()) { 2215 mRelaunchingSystemBarColorApps.add(app); 2216 } 2217 } 2218 2219 /** 2220 * Called when an app has finished replacing its main window or aborted. 2221 */ 2222 void removeRelaunchingApp(ActivityRecord app) { 2223 final boolean removed = mRelaunchingSystemBarColorApps.remove(app); 2224 if (removed & mRelaunchingSystemBarColorApps.isEmpty()) { 2225 updateSystemBarAttributes(); 2226 } 2227 } 2228 2229 void resetSystemBarAttributes() { 2230 mLastDisableFlags = 0; 2231 updateSystemBarAttributes(); 2232 } 2233 2234 void updateSystemBarAttributes() { 2235 // If there is no window focused, there will be nobody to handle the events 2236 // anyway, so just hang on in whatever state we're in until things settle down. 2237 WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow 2238 : mTopFullscreenOpaqueWindowState; 2239 if (winCandidate == null) { 2240 return; 2241 } 2242 2243 // Immersive mode confirmation should never affect the system bar visibility, otherwise 2244 // it will unhide the navigation bar and hide itself. 2245 if ((winCandidate.getAttrs().privateFlags 2246 & PRIVATE_FLAG_IMMERSIVE_CONFIRMATION_WINDOW) != 0) { 2247 if (mNotificationShade != null && mNotificationShade.canReceiveKeys()) { 2248 // Let notification shade control the system bar visibility. 2249 winCandidate = mNotificationShade; 2250 } else if (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys()) { 2251 // Immersive mode confirmation took the focus from mLastFocusedWindow which was 2252 // controlling the system bar visibility. Let it keep controlling the visibility. 2253 winCandidate = mLastFocusedWindow; 2254 } else { 2255 winCandidate = mTopFullscreenOpaqueWindowState; 2256 } 2257 if (winCandidate == null) { 2258 return; 2259 } 2260 } 2261 final WindowState win = winCandidate; 2262 mSystemUiControllingWindow = win; 2263 2264 final int displayId = getDisplayId(); 2265 final int disableFlags = win.getDisableFlags(); 2266 final int opaqueAppearance = updateSystemBarsLw(win, disableFlags); 2267 if (!mRelaunchingSystemBarColorApps.isEmpty()) { 2268 // The appearance of system bars might change while relaunching apps. We don't report 2269 // the intermediate state to system UI. Otherwise, it might trigger redundant effects. 2270 return; 2271 } 2272 final WindowState navColorWin = chooseNavigationColorWindowLw(mNavBarColorWindowCandidate, 2273 mDisplayContent.mInputMethodWindow, mNavigationBarPosition); 2274 final boolean isNavbarColorManagedByIme = 2275 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow; 2276 final int appearance = updateLightNavigationBarLw(win.mAttrs.insetsFlags.appearance, 2277 navColorWin) | opaqueAppearance; 2278 final WindowState navBarControlWin = topAppHidesSystemBar(Type.navigationBars()) 2279 ? mTopFullscreenOpaqueWindowState 2280 : win; 2281 final int behavior = navBarControlWin.mAttrs.insetsFlags.behavior; 2282 final String focusedApp = win.mAttrs.packageName; 2283 final boolean isFullscreen = !win.isRequestedVisible(Type.statusBars()) 2284 || !win.isRequestedVisible(Type.navigationBars()); 2285 final AppearanceRegion[] statusBarAppearanceRegions = 2286 new AppearanceRegion[mStatusBarAppearanceRegionList.size()]; 2287 mStatusBarAppearanceRegionList.toArray(statusBarAppearanceRegions); 2288 if (mLastDisableFlags != disableFlags) { 2289 mLastDisableFlags = disableFlags; 2290 final String cause = win.toString(); 2291 callStatusBarSafely(statusBar -> statusBar.setDisableFlags(displayId, disableFlags, 2292 cause)); 2293 } 2294 final @InsetsType int requestedVisibleTypes = win.getRequestedVisibleTypes(); 2295 final LetterboxDetails[] letterboxDetails = new LetterboxDetails[mLetterboxDetails.size()]; 2296 mLetterboxDetails.toArray(letterboxDetails); 2297 if (mLastAppearance == appearance 2298 && mLastBehavior == behavior 2299 && mLastRequestedVisibleTypes == requestedVisibleTypes 2300 && Objects.equals(mFocusedApp, focusedApp) 2301 && mLastFocusIsFullscreen == isFullscreen 2302 && Arrays.equals(mLastStatusBarAppearanceRegions, statusBarAppearanceRegions) 2303 && Arrays.equals(mLastLetterboxDetails, letterboxDetails)) { 2304 return; 2305 } 2306 if (mDisplayContent.isDefaultDisplay && (mLastFocusIsFullscreen != isFullscreen 2307 || ((mLastAppearance ^ appearance) & APPEARANCE_LOW_PROFILE_BARS) != 0)) { 2308 mService.mInputManager.setSystemUiLightsOut( 2309 isFullscreen || (appearance & APPEARANCE_LOW_PROFILE_BARS) != 0); 2310 } 2311 mLastAppearance = appearance; 2312 mLastBehavior = behavior; 2313 mLastRequestedVisibleTypes = requestedVisibleTypes; 2314 mFocusedApp = focusedApp; 2315 mLastFocusIsFullscreen = isFullscreen; 2316 mLastStatusBarAppearanceRegions = statusBarAppearanceRegions; 2317 mLastLetterboxDetails = letterboxDetails; 2318 callStatusBarSafely(statusBar -> statusBar.onSystemBarAttributesChanged(displayId, 2319 appearance, statusBarAppearanceRegions, isNavbarColorManagedByIme, behavior, 2320 requestedVisibleTypes, focusedApp, letterboxDetails)); 2321 } 2322 2323 private void callStatusBarSafely(Consumer<StatusBarManagerInternal> consumer) { 2324 mHandler.post(() -> { 2325 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 2326 if (statusBar != null) { 2327 consumer.accept(statusBar); 2328 } 2329 }); 2330 } 2331 2332 @VisibleForTesting 2333 @Nullable 2334 static WindowState chooseNavigationColorWindowLw(WindowState candidate, WindowState imeWindow, 2335 @NavigationBarPosition int navBarPosition) { 2336 // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME 2337 // window can be navigation color window. 2338 final boolean imeWindowCanNavColorWindow = imeWindow != null 2339 && imeWindow.isVisible() 2340 && navBarPosition == NAV_BAR_BOTTOM 2341 && (imeWindow.mAttrs.flags 2342 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; 2343 if (!imeWindowCanNavColorWindow) { 2344 // No IME window is involved. Determine the result only with candidate window. 2345 return candidate; 2346 } 2347 2348 if (candidate != null && candidate.isDimming()) { 2349 // The IME window and the dimming window are competing. Check if the dimming window can 2350 // be IME target or not. 2351 if (LayoutParams.mayUseInputMethod(candidate.mAttrs.flags)) { 2352 // The IME window is above the dimming window. 2353 return imeWindow; 2354 } else { 2355 // The dimming window is above the IME window. 2356 return candidate; 2357 } 2358 } 2359 2360 return imeWindow; 2361 } 2362 2363 @VisibleForTesting 2364 int updateLightNavigationBarLw(int appearance, WindowState navColorWin) { 2365 if (navColorWin == null || !isLightBarAllowed(navColorWin, Type.navigationBars())) { 2366 // Clear the light flag while not allowed. 2367 appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS; 2368 return appearance; 2369 } 2370 2371 // Respect the light flag of navigation color window. 2372 appearance &= ~APPEARANCE_LIGHT_NAVIGATION_BARS; 2373 appearance |= navColorWin.mAttrs.insetsFlags.appearance 2374 & APPEARANCE_LIGHT_NAVIGATION_BARS; 2375 return appearance; 2376 } 2377 2378 private int updateSystemBarsLw(WindowState win, int disableFlags) { 2379 final TaskDisplayArea defaultTaskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); 2380 final boolean adjacentTasksVisible = 2381 defaultTaskDisplayArea.getRootTask(task -> task.isVisible() 2382 && task.getTopLeafTask().getAdjacentTask() != null) 2383 != null; 2384 final boolean freeformRootTaskVisible = 2385 defaultTaskDisplayArea.isRootTaskVisible(WINDOWING_MODE_FREEFORM); 2386 2387 getInsetsPolicy().updateSystemBars(win, adjacentTasksVisible, freeformRootTaskVisible); 2388 2389 final boolean topAppHidesStatusBar = topAppHidesSystemBar(Type.statusBars()); 2390 if (getStatusBar() != null) { 2391 final StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 2392 if (statusBar != null) { 2393 statusBar.setTopAppHidesStatusBar(topAppHidesStatusBar); 2394 } 2395 } 2396 2397 // If the top app is not fullscreen, only the default rotation animation is allowed. 2398 mTopIsFullscreen = topAppHidesStatusBar 2399 && (mNotificationShade == null || !mNotificationShade.isVisible()); 2400 2401 int appearance = APPEARANCE_OPAQUE_NAVIGATION_BARS | APPEARANCE_OPAQUE_STATUS_BARS; 2402 appearance = configureStatusBarOpacity(appearance); 2403 appearance = configureNavBarOpacity(appearance, adjacentTasksVisible, 2404 freeformRootTaskVisible); 2405 2406 // Show immersive mode confirmation if needed. 2407 final boolean wasImmersiveMode = mIsImmersiveMode; 2408 final boolean isImmersiveMode = isImmersiveMode(win); 2409 if (wasImmersiveMode != isImmersiveMode) { 2410 mIsImmersiveMode = isImmersiveMode; 2411 // The immersive confirmation window should be attached to the immersive window root. 2412 final RootDisplayArea root = win.getRootDisplayArea(); 2413 final int rootDisplayAreaId = root == null ? FEATURE_UNDEFINED : root.mFeatureId; 2414 if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) { 2415 mImmersiveModeConfirmation.immersiveModeChangedLw(rootDisplayAreaId, 2416 isImmersiveMode, 2417 mService.mPolicy.isUserSetupComplete(), 2418 isNavBarEmpty(disableFlags)); 2419 } else { 2420 // TODO (b/277290737): Move this to the client side, instead of using a proxy. 2421 callStatusBarSafely(statusBar -> statusBar.immersiveModeChanged(rootDisplayAreaId, 2422 isImmersiveMode)); 2423 } 2424 } 2425 2426 // Show transient bars for panic if needed. 2427 final boolean requestHideNavBar = !win.isRequestedVisible(Type.navigationBars()); 2428 final long now = SystemClock.uptimeMillis(); 2429 final boolean pendingPanic = mPendingPanicGestureUptime != 0 2430 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION; 2431 final DisplayPolicy defaultDisplayPolicy = 2432 mService.getDefaultDisplayContentLocked().getDisplayPolicy(); 2433 if (pendingPanic && requestHideNavBar && isImmersiveMode 2434 // TODO (b/111955725): Show keyguard presentation on all external displays 2435 && defaultDisplayPolicy.isKeyguardDrawComplete()) { 2436 // The user performed the panic gesture recently, we're about to hide the bars, 2437 // we're no longer on the Keyguard and the screen is ready. We can now request the bars. 2438 mPendingPanicGestureUptime = 0; 2439 if (!isNavBarEmpty(disableFlags)) { 2440 mDisplayContent.getInsetsPolicy().showTransient(SHOW_TYPES_FOR_PANIC, 2441 true /* isGestureOnSystemBar */); 2442 } 2443 } 2444 2445 return appearance; 2446 } 2447 2448 private static boolean isLightBarAllowed(WindowState win, @InsetsType int type) { 2449 if (win == null) { 2450 return false; 2451 } 2452 return intersectsAnyInsets(win.getFrame(), win.getInsetsState(), type); 2453 } 2454 2455 private Rect getBarContentFrameForWindow(WindowState win, @InsetsType int type) { 2456 final DisplayFrames displayFrames = win.getDisplayFrames(mDisplayContent.mDisplayFrames); 2457 final InsetsState state = displayFrames.mInsetsState; 2458 final Rect df = displayFrames.mUnrestricted; 2459 final Rect safe = sTmpDisplayCutoutSafe; 2460 final Insets waterfallInsets = state.getDisplayCutout().getWaterfallInsets(); 2461 final Rect outRect = new Rect(); 2462 final Rect sourceContent = sTmpRect; 2463 safe.set(displayFrames.mDisplayCutoutSafe); 2464 for (int i = state.sourceSize() - 1; i >= 0; i--) { 2465 final InsetsSource source = state.sourceAt(i); 2466 if (source.getType() != type) { 2467 continue; 2468 } 2469 if (type == Type.statusBars()) { 2470 safe.set(displayFrames.mDisplayCutoutSafe); 2471 final Insets insets = source.calculateInsets(df, true /* ignoreVisibility */); 2472 // The status bar content can extend into regular display cutout insets if they are 2473 // at the same side, but the content cannot extend into waterfall insets. 2474 if (insets.left > 0) { 2475 safe.left = Math.max(df.left + waterfallInsets.left, df.left); 2476 } else if (insets.top > 0) { 2477 safe.top = Math.max(df.top + waterfallInsets.top, df.top); 2478 } else if (insets.right > 0) { 2479 safe.right = Math.max(df.right - waterfallInsets.right, df.right); 2480 } else if (insets.bottom > 0) { 2481 safe.bottom = Math.max(df.bottom - waterfallInsets.bottom, df.bottom); 2482 } 2483 } 2484 sourceContent.set(source.getFrame()); 2485 sourceContent.intersect(safe); 2486 outRect.union(sourceContent); 2487 } 2488 return outRect; 2489 } 2490 2491 /** 2492 * @return {@code true} if bar is allowed to be fully transparent when given window is show. 2493 * 2494 * <p>Prevents showing a transparent bar over a letterboxed activity which can make 2495 * notification icons or navigation buttons unreadable due to contrast between letterbox 2496 * background and an activity. For instance, this happens when letterbox background is solid 2497 * black while activity is white. To resolve this, only semi-transparent bars are allowed to 2498 * be drawn over letterboxed activity. 2499 */ 2500 @VisibleForTesting 2501 boolean isFullyTransparentAllowed(WindowState win, @InsetsType int type) { 2502 if (win == null) { 2503 return true; 2504 } 2505 return win.isFullyTransparentBarAllowed(getBarContentFrameForWindow(win, type)); 2506 } 2507 2508 private static boolean drawsBarBackground(WindowState win) { 2509 if (win == null) { 2510 return true; 2511 } 2512 2513 final boolean drawsSystemBars = 2514 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; 2515 final boolean forceDrawsSystemBars = 2516 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0; 2517 2518 return forceDrawsSystemBars || drawsSystemBars; 2519 } 2520 2521 /** @return the current visibility flags with the status bar opacity related flags toggled. */ 2522 private int configureStatusBarOpacity(int appearance) { 2523 boolean drawBackground = true; 2524 boolean isFullyTransparentAllowed = true; 2525 for (int i = mStatusBarBackgroundWindows.size() - 1; i >= 0; i--) { 2526 final WindowState window = mStatusBarBackgroundWindows.get(i); 2527 drawBackground &= drawsBarBackground(window); 2528 isFullyTransparentAllowed &= isFullyTransparentAllowed(window, Type.statusBars()); 2529 } 2530 2531 if (drawBackground) { 2532 appearance &= ~APPEARANCE_OPAQUE_STATUS_BARS; 2533 } 2534 2535 if (!isFullyTransparentAllowed) { 2536 appearance |= APPEARANCE_SEMI_TRANSPARENT_STATUS_BARS; 2537 } 2538 2539 return appearance; 2540 } 2541 2542 /** 2543 * @return the current visibility flags with the nav-bar opacity related flags toggled based 2544 * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}. 2545 */ 2546 private int configureNavBarOpacity(int appearance, boolean multiWindowTaskVisible, 2547 boolean freeformRootTaskVisible) { 2548 final WindowState navBackgroundWin = chooseNavigationBackgroundWindow( 2549 mNavBarBackgroundWindowCandidate, 2550 mDisplayContent.mInputMethodWindow, 2551 mNavigationBarPosition); 2552 final boolean drawBackground = navBackgroundWin != null 2553 // There is no app window showing underneath nav bar. (e.g., The screen is locked.) 2554 // Let system windows (ex: notification shade) draw nav bar background. 2555 || mNavBarBackgroundWindowCandidate == null; 2556 2557 if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) { 2558 if (drawBackground) { 2559 appearance = clearNavBarOpaqueFlag(appearance); 2560 } 2561 } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) { 2562 if (multiWindowTaskVisible || freeformRootTaskVisible) { 2563 if (mIsFreeformWindowOverlappingWithNavBar) { 2564 appearance = clearNavBarOpaqueFlag(appearance); 2565 } 2566 } else if (drawBackground) { 2567 appearance = clearNavBarOpaqueFlag(appearance); 2568 } 2569 } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) { 2570 if (freeformRootTaskVisible) { 2571 appearance = clearNavBarOpaqueFlag(appearance); 2572 } 2573 } 2574 2575 if (!isFullyTransparentAllowed(navBackgroundWin, Type.navigationBars())) { 2576 appearance |= APPEARANCE_SEMI_TRANSPARENT_NAVIGATION_BARS; 2577 } 2578 2579 return appearance; 2580 } 2581 2582 private int clearNavBarOpaqueFlag(int appearance) { 2583 return appearance & ~APPEARANCE_OPAQUE_NAVIGATION_BARS; 2584 } 2585 2586 @VisibleForTesting 2587 @Nullable 2588 static WindowState chooseNavigationBackgroundWindow(WindowState candidate, 2589 WindowState imeWindow, @NavigationBarPosition int navBarPosition) { 2590 if (imeWindow != null && imeWindow.isVisible() && navBarPosition == NAV_BAR_BOTTOM 2591 && drawsBarBackground(imeWindow)) { 2592 return imeWindow; 2593 } 2594 if (drawsBarBackground(candidate)) { 2595 return candidate; 2596 } 2597 return null; 2598 } 2599 2600 private boolean isImmersiveMode(WindowState win) { 2601 if (win == null) { 2602 return false; 2603 } 2604 if (win.mPolicy.getWindowLayerLw(win) > win.mPolicy.getWindowLayerFromTypeLw( 2605 WindowManager.LayoutParams.TYPE_STATUS_BAR) || win.isActivityTypeDream()) { 2606 return false; 2607 } 2608 return getInsetsPolicy().hasHiddenSources(Type.navigationBars()); 2609 } 2610 2611 private static boolean isNavBarEmpty(int systemUiFlags) { 2612 final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME 2613 | View.STATUS_BAR_DISABLE_BACK 2614 | View.STATUS_BAR_DISABLE_RECENT); 2615 2616 return (systemUiFlags & disableNavigationBar) == disableNavigationBar; 2617 } 2618 2619 private final Runnable mHiddenNavPanic = new Runnable() { 2620 @Override 2621 public void run() { 2622 synchronized (mLock) { 2623 if (!mService.mPolicy.isUserSetupComplete()) { 2624 // Swipe-up for navigation bar is disabled during setup 2625 return; 2626 } 2627 mPendingPanicGestureUptime = SystemClock.uptimeMillis(); 2628 updateSystemBarAttributes(); 2629 } 2630 } 2631 }; 2632 2633 void onPowerKeyDown(boolean isScreenOn) { 2634 // Detect user pressing the power button in panic when an application has 2635 // taken over the whole screen. 2636 boolean panic = false; 2637 if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) { 2638 panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn, 2639 SystemClock.elapsedRealtime(), isImmersiveMode(mSystemUiControllingWindow), 2640 isNavBarEmpty(mLastDisableFlags)); 2641 } else { 2642 panic = isPowerKeyDownPanic(isScreenOn, SystemClock.elapsedRealtime(), 2643 isImmersiveMode(mSystemUiControllingWindow), isNavBarEmpty(mLastDisableFlags)); 2644 } 2645 if (panic) { 2646 mHandler.post(mHiddenNavPanic); 2647 } 2648 } 2649 2650 private boolean isPowerKeyDownPanic(boolean isScreenOn, long time, boolean inImmersiveMode, 2651 boolean navBarEmpty) { 2652 if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) { 2653 // turning the screen back on within the panic threshold 2654 return !mImmersiveConfirmationWindowExists; 2655 } 2656 if (isScreenOn && inImmersiveMode && !navBarEmpty) { 2657 // turning the screen off, remember if we were in immersive mode 2658 mPanicTime = time; 2659 } else { 2660 mPanicTime = 0; 2661 } 2662 return false; 2663 } 2664 2665 void onVrStateChangedLw(boolean enabled) { 2666 if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) { 2667 mImmersiveModeConfirmation.onVrStateChangedLw(enabled); 2668 } 2669 } 2670 2671 /** 2672 * Called when the state of lock task mode changes. This should be used to disable immersive 2673 * mode confirmation. 2674 * 2675 * @param lockTaskState the new lock task mode state. One of 2676 * {@link ActivityManager#LOCK_TASK_MODE_NONE}, 2677 * {@link ActivityManager#LOCK_TASK_MODE_LOCKED}, 2678 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}. 2679 */ 2680 public void onLockTaskStateChangedLw(int lockTaskState) { 2681 if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) { 2682 mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState); 2683 } 2684 } 2685 2686 /** Called when a {@link android.os.PowerManager#USER_ACTIVITY_EVENT_TOUCH} is sent. */ 2687 public void onUserActivityEventTouch() { 2688 // If there is keyguard, it may use INPUT_FEATURE_DISABLE_USER_ACTIVITY (InputDispatcher 2689 // won't trigger user activity for touch). So while the device is not interactive, the user 2690 // event is only sent explicitly from SystemUI. 2691 if (mAwake) return; 2692 // If the event is triggered while the display is not awake, the screen may be showing 2693 // dozing UI such as AOD or overlay UI of under display fingerprint. Then set the animating 2694 // state temporarily to make the process more responsive. 2695 final WindowState w = mNotificationShade; 2696 mService.mAtmService.setProcessAnimatingWhileDozing(w != null ? w.getProcess() : null); 2697 } 2698 2699 boolean onSystemUiSettingsChanged() { 2700 if (CLIENT_TRANSIENT || CLIENT_IMMERSIVE_CONFIRMATION) { 2701 return false; 2702 } else { 2703 return mImmersiveModeConfirmation.onSettingChanged(mService.mCurrentUserId); 2704 } 2705 } 2706 2707 /** 2708 * Request a screenshot be taken. 2709 * 2710 * @param screenshotType The type of screenshot, for example either 2711 * {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or 2712 * {@link WindowManager#TAKE_SCREENSHOT_PROVIDED_IMAGE} 2713 * @param source Where the screenshot originated from (see WindowManager.ScreenshotSource) 2714 */ 2715 public void takeScreenshot(int screenshotType, int source) { 2716 if (mScreenshotHelper != null) { 2717 ScreenshotRequest request = 2718 new ScreenshotRequest.Builder(screenshotType, source).build(); 2719 mScreenshotHelper.takeScreenshot(request, mHandler, null /* completionConsumer */); 2720 } 2721 } 2722 2723 RefreshRatePolicy getRefreshRatePolicy() { 2724 return mRefreshRatePolicy; 2725 } 2726 2727 void dump(String prefix, PrintWriter pw) { 2728 pw.print(prefix); pw.println("DisplayPolicy"); 2729 prefix += " "; 2730 final String prefixInner = prefix + " "; 2731 pw.print(prefix); 2732 pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer); 2733 pw.print(" mDeskDockEnablesAccelerometer="); 2734 pw.println(mDeskDockEnablesAccelerometer); 2735 pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode)); 2736 pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState)); 2737 pw.print(prefix); pw.print("mAwake="); pw.print(mAwake); 2738 pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly); 2739 pw.print(" mScreenOnFully="); pw.println(mScreenOnFully); 2740 pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete); 2741 pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete); 2742 pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged); 2743 if (mLastDisableFlags != 0) { 2744 pw.print(prefix); pw.print("mLastDisableFlags=0x"); 2745 pw.println(Integer.toHexString(mLastDisableFlags)); 2746 } 2747 if (mLastAppearance != 0) { 2748 pw.print(prefix); pw.print("mLastAppearance="); 2749 pw.println(ViewDebug.flagsToString(InsetsFlags.class, "appearance", mLastAppearance)); 2750 } 2751 if (mLastBehavior != 0) { 2752 pw.print(prefix); pw.print("mLastBehavior="); 2753 pw.println(ViewDebug.flagsToString(InsetsFlags.class, "behavior", mLastBehavior)); 2754 } 2755 pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream); 2756 pw.print(" mDreamingLockscreen="); pw.println(mDreamingLockscreen); 2757 if (mStatusBar != null) { 2758 pw.print(prefix); pw.print("mStatusBar="); pw.println(mStatusBar); 2759 } 2760 if (mNotificationShade != null) { 2761 pw.print(prefix); pw.print("mExpandedPanel="); pw.println(mNotificationShade); 2762 } 2763 pw.print(prefix); pw.print("isKeyguardShowing="); pw.println(isKeyguardShowing()); 2764 if (mNavigationBar != null) { 2765 pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar); 2766 pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode); 2767 pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove); 2768 pw.print(prefix); pw.print("mNavigationBarPosition="); 2769 pw.println(mNavigationBarPosition); 2770 } 2771 if (mLeftGestureHost != null) { 2772 pw.print(prefix); pw.print("mLeftGestureHost="); pw.println(mLeftGestureHost); 2773 } 2774 if (mTopGestureHost != null) { 2775 pw.print(prefix); pw.print("mTopGestureHost="); pw.println(mTopGestureHost); 2776 } 2777 if (mRightGestureHost != null) { 2778 pw.print(prefix); pw.print("mRightGestureHost="); pw.println(mRightGestureHost); 2779 } 2780 if (mBottomGestureHost != null) { 2781 pw.print(prefix); pw.print("mBottomGestureHost="); pw.println(mBottomGestureHost); 2782 } 2783 if (mFocusedWindow != null) { 2784 pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow); 2785 } 2786 if (mTopFullscreenOpaqueWindowState != null) { 2787 pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState="); 2788 pw.println(mTopFullscreenOpaqueWindowState); 2789 } 2790 if (!mSystemBarColorApps.isEmpty()) { 2791 pw.print(prefix); pw.print("mSystemBarColorApps="); 2792 pw.println(mSystemBarColorApps); 2793 } 2794 if (!mRelaunchingSystemBarColorApps.isEmpty()) { 2795 pw.print(prefix); pw.print("mRelaunchingSystemBarColorApps="); 2796 pw.println(mRelaunchingSystemBarColorApps); 2797 } 2798 if (mNavBarColorWindowCandidate != null) { 2799 pw.print(prefix); pw.print("mNavBarColorWindowCandidate="); 2800 pw.println(mNavBarColorWindowCandidate); 2801 } 2802 if (mNavBarBackgroundWindowCandidate != null) { 2803 pw.print(prefix); pw.print("mNavBarBackgroundWindowCandidate="); 2804 pw.println(mNavBarBackgroundWindowCandidate); 2805 } 2806 if (mLastStatusBarAppearanceRegions != null) { 2807 pw.print(prefix); pw.println("mLastStatusBarAppearanceRegions="); 2808 for (int i = mLastStatusBarAppearanceRegions.length - 1; i >= 0; i--) { 2809 pw.print(prefixInner); pw.println(mLastStatusBarAppearanceRegions[i]); 2810 } 2811 } 2812 if (mLastLetterboxDetails != null) { 2813 pw.print(prefix); pw.println("mLastLetterboxDetails="); 2814 for (int i = mLastLetterboxDetails.length - 1; i >= 0; i--) { 2815 pw.print(prefixInner); pw.println(mLastLetterboxDetails[i]); 2816 } 2817 } 2818 if (!mStatusBarBackgroundWindows.isEmpty()) { 2819 pw.print(prefix); pw.println("mStatusBarBackgroundWindows="); 2820 for (int i = mStatusBarBackgroundWindows.size() - 1; i >= 0; i--) { 2821 final WindowState win = mStatusBarBackgroundWindows.get(i); 2822 pw.print(prefixInner); pw.println(win); 2823 } 2824 } 2825 pw.print(prefix); pw.print("mTopIsFullscreen="); pw.println(mTopIsFullscreen); 2826 pw.print(prefix); pw.print("mForceShowNavigationBarEnabled="); 2827 pw.print(mForceShowNavigationBarEnabled); 2828 pw.print(" mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn); 2829 pw.print(prefix); pw.print("mRemoteInsetsControllerControlsSystemBars="); 2830 pw.println(mRemoteInsetsControllerControlsSystemBars); 2831 pw.print(prefix); pw.println("mDecorInsetsInfo:"); 2832 mDecorInsets.dump(prefixInner, pw); 2833 if (mCachedDecorInsets != null) { 2834 pw.print(prefix); pw.println("mCachedDecorInsets:"); 2835 mCachedDecorInsets.mDecorInsets.dump(prefixInner, pw); 2836 } 2837 if (!CLIENT_TRANSIENT) { 2838 mSystemGestures.dump(pw, prefix); 2839 } 2840 2841 pw.print(prefix); pw.println("Looper state:"); 2842 mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " "); 2843 } 2844 2845 private boolean supportsPointerLocation() { 2846 return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate(); 2847 } 2848 2849 void setPointerLocationEnabled(boolean pointerLocationEnabled) { 2850 if (!supportsPointerLocation()) { 2851 return; 2852 } 2853 2854 mHandler.sendEmptyMessage(pointerLocationEnabled 2855 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION); 2856 } 2857 2858 private void enablePointerLocation() { 2859 if (mPointerLocationView != null) { 2860 return; 2861 } 2862 2863 mPointerLocationView = new PointerLocationView(mContext); 2864 mPointerLocationView.setPrintCoords(false); 2865 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(); 2866 lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; 2867 lp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 2868 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 2869 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 2870 lp.privateFlags |= LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; 2871 lp.setFitInsetsTypes(0); 2872 lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; 2873 if (ActivityManager.isHighEndGfx()) { 2874 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 2875 lp.privateFlags |= 2876 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED; 2877 } 2878 lp.format = PixelFormat.TRANSLUCENT; 2879 lp.setTitle("PointerLocation - display " + getDisplayId()); 2880 lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; 2881 final WindowManager wm = mContext.getSystemService(WindowManager.class); 2882 wm.addView(mPointerLocationView, lp); 2883 mDisplayContent.registerPointerEventListener(mPointerLocationView); 2884 } 2885 2886 private void disablePointerLocation() { 2887 if (mPointerLocationView == null) { 2888 return; 2889 } 2890 2891 if (!mDisplayContent.isRemoved()) { 2892 mDisplayContent.unregisterPointerEventListener(mPointerLocationView); 2893 } 2894 2895 final WindowManager wm = mContext.getSystemService(WindowManager.class); 2896 wm.removeView(mPointerLocationView); 2897 mPointerLocationView = null; 2898 } 2899 2900 /** 2901 * Check if the window could be excluded from checking if the display has content. 2902 * 2903 * @param w WindowState to check if should be excluded. 2904 * @return True if the window type is PointerLocation which is excluded. 2905 */ 2906 boolean isWindowExcludedFromContent(WindowState w) { 2907 if (w != null && mPointerLocationView != null) { 2908 return w.mClient == mPointerLocationView.getWindowToken(); 2909 } 2910 2911 return false; 2912 } 2913 2914 void release() { 2915 mDisplayContent.mTransitionController.unregisterLegacyListener(mAppTransitionListener); 2916 mHandler.post(mGestureNavigationSettingsObserver::unregister); 2917 mHandler.post(mForceShowNavBarSettingsObserver::unregister); 2918 if (!CLIENT_TRANSIENT && !CLIENT_IMMERSIVE_CONFIRMATION) { 2919 mImmersiveModeConfirmation.release(); 2920 } 2921 if (mService.mPointerLocationEnabled) { 2922 setPointerLocationEnabled(false); 2923 } 2924 } 2925 2926 @VisibleForTesting 2927 static boolean isOverlappingWithNavBar(@NonNull WindowState win) { 2928 if (!win.isVisible()) { 2929 return false; 2930 } 2931 2932 // When the window is dimming means it's requesting dim layer to its host container, so 2933 // checking whether it's overlapping with a navigation bar by its container's bounds. 2934 return intersectsAnyInsets(win.isDimming() ? win.getBounds() : win.getFrame(), 2935 win.getInsetsState(), Type.navigationBars()); 2936 } 2937 2938 /** 2939 * Returns whether the given {@param bounds} intersects with any insets of the 2940 * provided {@param insetsType}. 2941 */ 2942 private static boolean intersectsAnyInsets(Rect bounds, InsetsState insetsState, 2943 @InsetsType int insetsType) { 2944 for (int i = insetsState.sourceSize() - 1; i >= 0; i--) { 2945 final InsetsSource source = insetsState.sourceAt(i); 2946 if ((source.getType() & insetsType) == 0 || !source.isVisible()) { 2947 continue; 2948 } 2949 if (Rect.intersects(bounds, source.getFrame())) { 2950 return true; 2951 } 2952 } 2953 return false; 2954 } 2955 2956 /** 2957 * @return Whether we should attach navigation bar to the app during transition. 2958 */ 2959 boolean shouldAttachNavBarToAppDuringTransition() { 2960 return mShouldAttachNavBarToAppDuringTransition && mNavigationBar != null; 2961 } 2962 } 2963