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