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