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