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