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.ACTIVITY_TYPE_HOME; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 24 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 25 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 26 import static android.content.res.Configuration.UI_MODE_TYPE_CAR; 27 import static android.content.res.Configuration.UI_MODE_TYPE_MASK; 28 import static android.view.Display.TYPE_BUILT_IN; 29 import static android.view.InsetsState.TYPE_TOP_BAR; 30 import static android.view.InsetsState.TYPE_TOP_GESTURES; 31 import static android.view.InsetsState.TYPE_TOP_TAPPABLE_ELEMENT; 32 import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 33 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 34 import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; 35 import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION; 36 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 37 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW; 38 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON; 39 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; 40 import static android.view.WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN; 41 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; 42 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR; 43 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; 44 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN; 45 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 46 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; 47 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 48 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; 49 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; 50 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 51 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; 52 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT; 53 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 54 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS; 55 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT; 56 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR; 57 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR; 58 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; 59 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION; 60 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_CROSSFADE; 61 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_JUMPCUT; 62 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; 63 import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS; 64 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; 65 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 66 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST; 67 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 68 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS; 69 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; 70 import static android.view.WindowManager.LayoutParams.TYPE_DREAM; 71 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_CONSUMER; 72 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 73 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG; 74 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; 75 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL; 76 import static android.view.WindowManager.LayoutParams.TYPE_SCREENSHOT; 77 import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; 78 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; 79 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL; 80 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL; 81 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; 82 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; 83 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY; 84 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 85 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION; 86 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION_STARTING; 87 import static android.view.WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY; 88 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 89 import static android.view.WindowManagerGlobal.ADD_OKAY; 90 import static android.view.WindowManagerPolicyConstants.ACTION_HDMI_PLUGGED; 91 import static android.view.WindowManagerPolicyConstants.EXTRA_HDMI_PLUGGED_STATE; 92 import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM; 93 import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT; 94 import static android.view.WindowManagerPolicyConstants.NAV_BAR_RIGHT; 95 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.ActivityTaskManagerInternal.SleepToken; 105 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; 106 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT; 107 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON; 108 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 109 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 110 import static com.android.server.wm.WindowManagerService.localLOGV; 111 112 import android.Manifest.permission; 113 import android.annotation.NonNull; 114 import android.annotation.Nullable; 115 import android.annotation.Px; 116 import android.app.ActivityManager; 117 import android.app.ActivityThread; 118 import android.app.LoadedApk; 119 import android.app.ResourcesManager; 120 import android.app.StatusBarManager; 121 import android.content.Context; 122 import android.content.Intent; 123 import android.content.pm.PackageManager; 124 import android.content.res.Resources; 125 import android.graphics.Insets; 126 import android.graphics.PixelFormat; 127 import android.graphics.Rect; 128 import android.graphics.Region; 129 import android.hardware.input.InputManager; 130 import android.hardware.power.V1_0.PowerHint; 131 import android.os.Handler; 132 import android.os.Looper; 133 import android.os.Message; 134 import android.os.SystemClock; 135 import android.os.SystemProperties; 136 import android.os.UserHandle; 137 import android.util.ArraySet; 138 import android.util.Pair; 139 import android.util.PrintWriterPrinter; 140 import android.util.Slog; 141 import android.view.DisplayCutout; 142 import android.view.Gravity; 143 import android.view.IApplicationToken; 144 import android.view.InputChannel; 145 import android.view.InputDevice; 146 import android.view.InputEvent; 147 import android.view.InputEventReceiver; 148 import android.view.InsetsState; 149 import android.view.MotionEvent; 150 import android.view.PointerIcon; 151 import android.view.Surface; 152 import android.view.View; 153 import android.view.ViewRootImpl; 154 import android.view.WindowManager; 155 import android.view.WindowManager.LayoutParams; 156 import android.view.WindowManagerGlobal; 157 import android.view.WindowManagerPolicyConstants; 158 import android.view.accessibility.AccessibilityManager; 159 160 import com.android.internal.R; 161 import com.android.internal.annotations.GuardedBy; 162 import com.android.internal.annotations.VisibleForTesting; 163 import com.android.internal.policy.ScreenDecorationsUtils; 164 import com.android.internal.util.ScreenShapeHelper; 165 import com.android.internal.util.ScreenshotHelper; 166 import com.android.internal.util.function.TriConsumer; 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.InputConsumer; 172 import com.android.server.policy.WindowManagerPolicy.NavigationBarPosition; 173 import com.android.server.policy.WindowManagerPolicy.ScreenOnListener; 174 import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs; 175 import com.android.server.policy.WindowOrientationListener; 176 import com.android.server.statusbar.StatusBarManagerInternal; 177 import com.android.server.wallpaper.WallpaperManagerInternal; 178 import com.android.server.wm.utils.InsetUtils; 179 180 import java.io.PrintWriter; 181 182 /** 183 * The policy that provides the basic behaviors and states of a display to show UI. 184 */ 185 public class DisplayPolicy { 186 private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayPolicy" : TAG_WM; 187 private static final boolean DEBUG = false; 188 189 private static final boolean ALTERNATE_CAR_MODE_NAV_SIZE = false; 190 191 // The panic gesture may become active only after the keyguard is dismissed and the immersive 192 // app shows again. If that doesn't happen for 30s we drop the gesture. 193 private static final long PANIC_GESTURE_EXPIRATION = 30000; 194 195 // Controls navigation bar opacity depending on which workspace stacks are currently 196 // visible. 197 // Nav bar is always opaque when either the freeform stack or docked stack is visible. 198 private static final int NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED = 0; 199 // Nav bar is always translucent when the freeform stack is visible, otherwise always opaque. 200 private static final int NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE = 1; 201 // Nav bar is never forced opaque. 202 private static final int NAV_BAR_FORCE_TRANSPARENT = 2; 203 204 /** 205 * These are the system UI flags that, when changing, can cause the layout 206 * of the screen to change. 207 */ 208 private static final int SYSTEM_UI_CHANGING_LAYOUT = 209 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 210 | View.SYSTEM_UI_FLAG_FULLSCREEN 211 | View.STATUS_BAR_TRANSLUCENT 212 | View.NAVIGATION_BAR_TRANSLUCENT 213 | View.STATUS_BAR_TRANSPARENT 214 | View.NAVIGATION_BAR_TRANSPARENT; 215 216 private final WindowManagerService mService; 217 private final Context mContext; 218 private final DisplayContent mDisplayContent; 219 private final Object mLock; 220 private final Handler mHandler; 221 222 private Resources mCurrentUserResources; 223 224 private final boolean mCarDockEnablesAccelerometer; 225 private final boolean mDeskDockEnablesAccelerometer; 226 private final AccessibilityManager mAccessibilityManager; 227 private final ImmersiveModeConfirmation mImmersiveModeConfirmation; 228 private final ScreenshotHelper mScreenshotHelper; 229 230 private final Object mServiceAcquireLock = new Object(); 231 private StatusBarManagerInternal mStatusBarManagerInternal; 232 233 @Px 234 private int mBottomGestureAdditionalInset; 235 @Px 236 private int mSideGestureInset; 237 getStatusBarManagerInternal()238 private StatusBarManagerInternal getStatusBarManagerInternal() { 239 synchronized (mServiceAcquireLock) { 240 if (mStatusBarManagerInternal == null) { 241 mStatusBarManagerInternal = 242 LocalServices.getService(StatusBarManagerInternal.class); 243 } 244 return mStatusBarManagerInternal; 245 } 246 } 247 248 private final SystemGesturesPointerEventListener mSystemGestures; 249 250 private volatile int mLidState = LID_ABSENT; 251 private volatile int mDockMode = Intent.EXTRA_DOCK_STATE_UNDOCKED; 252 private volatile boolean mHdmiPlugged; 253 254 private volatile boolean mHasStatusBar; 255 private volatile boolean mHasNavigationBar; 256 // Can the navigation bar ever move to the side? 257 private volatile boolean mNavigationBarCanMove; 258 private volatile boolean mNavigationBarLetsThroughTaps; 259 private volatile boolean mNavigationBarAlwaysShowOnSideGesture; 260 private volatile boolean mAllowSeamlessRotationDespiteNavBarMoving; 261 262 // Written by vr manager thread, only read in this class. 263 private volatile boolean mPersistentVrModeEnabled; 264 265 private volatile boolean mAwake; 266 private volatile boolean mScreenOnEarly; 267 private volatile boolean mScreenOnFully; 268 private volatile ScreenOnListener mScreenOnListener; 269 270 private volatile boolean mKeyguardDrawComplete; 271 private volatile boolean mWindowManagerDrawComplete; 272 273 private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>(); 274 private WindowState mStatusBar = null; 275 private final int[] mStatusBarHeightForRotation = new int[4]; 276 private WindowState mNavigationBar = null; 277 @NavigationBarPosition 278 private int mNavigationBarPosition = NAV_BAR_BOTTOM; 279 private int[] mNavigationBarHeightForRotationDefault = new int[4]; 280 private int[] mNavigationBarWidthForRotationDefault = new int[4]; 281 private int[] mNavigationBarHeightForRotationInCarMode = new int[4]; 282 private int[] mNavigationBarWidthForRotationInCarMode = new int[4]; 283 284 /** See {@link #getNavigationBarFrameHeight} */ 285 private int[] mNavigationBarFrameHeightForRotationDefault = new int[4]; 286 287 /** Cached value of {@link ScreenShapeHelper#getWindowOutsetBottomPx} */ 288 @Px private int mWindowOutsetBottom; 289 290 private final StatusBarController mStatusBarController; 291 292 private final BarController mNavigationBarController; 293 294 private final BarController.OnBarVisibilityChangedListener mNavBarVisibilityListener = 295 new BarController.OnBarVisibilityChangedListener() { 296 @Override 297 public void onBarVisibilityChanged(boolean visible) { 298 if (mAccessibilityManager == null) { 299 return; 300 } 301 mAccessibilityManager.notifyAccessibilityButtonVisibilityChanged(visible); 302 } 303 }; 304 305 @GuardedBy("mHandler") 306 private SleepToken mDreamingSleepToken; 307 308 @GuardedBy("mHandler") 309 private SleepToken mWindowSleepToken; 310 311 private final Runnable mAcquireSleepTokenRunnable; 312 private final Runnable mReleaseSleepTokenRunnable; 313 314 // The windows we were told about in focusChanged. 315 private WindowState mFocusedWindow; 316 private WindowState mLastFocusedWindow; 317 318 IApplicationToken mFocusedApp; 319 320 int mLastSystemUiFlags; 321 // Bits that we are in the process of clearing, so we want to prevent 322 // them from being set by applications until everything has been updated 323 // to have them clear. 324 private int mResettingSystemUiFlags = 0; 325 // Bits that we are currently always keeping cleared. 326 private int mForceClearedSystemUiFlags = 0; 327 private int mLastFullscreenStackSysUiFlags; 328 private int mLastDockedStackSysUiFlags; 329 private final Rect mNonDockedStackBounds = new Rect(); 330 private final Rect mDockedStackBounds = new Rect(); 331 private final Rect mLastNonDockedStackBounds = new Rect(); 332 private final Rect mLastDockedStackBounds = new Rect(); 333 334 // What we last reported to system UI about whether the compatibility 335 // menu needs to be displayed. 336 private boolean mLastFocusNeedsMenu = false; 337 // If nonzero, a panic gesture was performed at that time in uptime millis and is still pending. 338 private long mPendingPanicGestureUptime; 339 340 private static final Rect sTmpDisplayCutoutSafeExceptMaybeBarsRect = new Rect(); 341 private static final Rect sTmpRect = new Rect(); 342 private static final Rect sTmpDockedFrame = new Rect(); 343 private static final Rect sTmpNavFrame = new Rect(); 344 private static final Rect sTmpLastParentFrame = new Rect(); 345 346 private WindowState mTopFullscreenOpaqueWindowState; 347 private WindowState mTopFullscreenOpaqueOrDimmingWindowState; 348 private WindowState mTopDockedOpaqueWindowState; 349 private WindowState mTopDockedOpaqueOrDimmingWindowState; 350 private boolean mTopIsFullscreen; 351 private boolean mForceStatusBar; 352 private boolean mForceStatusBarFromKeyguard; 353 private boolean mForceStatusBarTransparent; 354 private int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED; 355 private boolean mForcingShowNavBar; 356 private int mForcingShowNavBarLayer; 357 private boolean mForceShowSystemBars; 358 359 /** 360 * Force the display of system bars regardless of other settings. 361 */ 362 private boolean mForceShowSystemBarsFromExternal; 363 364 private boolean mShowingDream; 365 private boolean mLastShowingDream; 366 private boolean mDreamingLockscreen; 367 private boolean mDreamingSleepTokenNeeded; 368 private boolean mWindowSleepTokenNeeded; 369 private boolean mLastWindowSleepTokenNeeded; 370 private boolean mAllowLockscreenWhenOn; 371 372 private InputConsumer mInputConsumer = null; 373 374 private PointerLocationView mPointerLocationView; 375 376 /** 377 * The area covered by system windows which belong to another display. Forwarded insets is set 378 * in case this is a virtual display, this is displayed on another display that has insets, and 379 * the bounds of this display is overlapping with the insets of the host display (e.g. IME is 380 * displayed on the host display, and it covers a part of this virtual display.) 381 * The forwarded insets is used to compute display frames of this virtual display, which will 382 * be then used to layout windows in the virtual display. 383 */ 384 @NonNull private Insets mForwardedInsets = Insets.NONE; 385 386 private RefreshRatePolicy mRefreshRatePolicy; 387 388 // -------- PolicyHandler -------- 389 private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1; 390 private static final int MSG_REQUEST_TRANSIENT_BARS = 2; 391 private static final int MSG_DISPOSE_INPUT_CONSUMER = 3; 392 private static final int MSG_ENABLE_POINTER_LOCATION = 4; 393 private static final int MSG_DISABLE_POINTER_LOCATION = 5; 394 395 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0; 396 private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1; 397 398 private class PolicyHandler extends Handler { 399 PolicyHandler(Looper looper)400 PolicyHandler(Looper looper) { 401 super(looper); 402 } 403 404 @Override handleMessage(Message msg)405 public void handleMessage(Message msg) { 406 switch (msg.what) { 407 case MSG_UPDATE_DREAMING_SLEEP_TOKEN: 408 updateDreamingSleepToken(msg.arg1 != 0); 409 break; 410 case MSG_REQUEST_TRANSIENT_BARS: 411 WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS) 412 ? mStatusBar : mNavigationBar; 413 if (targetBar != null) { 414 requestTransientBars(targetBar); 415 } 416 break; 417 case MSG_DISPOSE_INPUT_CONSUMER: 418 disposeInputConsumer((InputConsumer) msg.obj); 419 break; 420 case MSG_ENABLE_POINTER_LOCATION: 421 enablePointerLocation(); 422 break; 423 case MSG_DISABLE_POINTER_LOCATION: 424 disablePointerLocation(); 425 break; 426 } 427 } 428 } 429 DisplayPolicy(WindowManagerService service, DisplayContent displayContent)430 DisplayPolicy(WindowManagerService service, DisplayContent displayContent) { 431 mService = service; 432 mContext = displayContent.isDefaultDisplay ? service.mContext 433 : service.mContext.createDisplayContext(displayContent.getDisplay()); 434 mDisplayContent = displayContent; 435 mLock = service.getWindowManagerLock(); 436 437 final int displayId = displayContent.getDisplayId(); 438 mStatusBarController = new StatusBarController(displayId); 439 mNavigationBarController = new BarController("NavigationBar", 440 displayId, 441 View.NAVIGATION_BAR_TRANSIENT, 442 View.NAVIGATION_BAR_UNHIDE, 443 View.NAVIGATION_BAR_TRANSLUCENT, 444 StatusBarManager.WINDOW_NAVIGATION_BAR, 445 FLAG_TRANSLUCENT_NAVIGATION, 446 View.NAVIGATION_BAR_TRANSPARENT); 447 448 final Resources r = mContext.getResources(); 449 mCarDockEnablesAccelerometer = r.getBoolean(R.bool.config_carDockEnablesAccelerometer); 450 mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer); 451 mForceShowSystemBarsFromExternal = r.getBoolean(R.bool.config_forceShowSystemBars); 452 453 mAccessibilityManager = (AccessibilityManager) mContext.getSystemService( 454 Context.ACCESSIBILITY_SERVICE); 455 if (!displayContent.isDefaultDisplay) { 456 mAwake = true; 457 mScreenOnEarly = true; 458 mScreenOnFully = true; 459 } 460 461 final Looper looper = UiThread.getHandler().getLooper(); 462 mHandler = new PolicyHandler(looper); 463 mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler, 464 new SystemGesturesPointerEventListener.Callbacks() { 465 @Override 466 public void onSwipeFromTop() { 467 if (mStatusBar != null) { 468 requestTransientBars(mStatusBar); 469 } 470 } 471 472 @Override 473 public void onSwipeFromBottom() { 474 if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) { 475 requestTransientBars(mNavigationBar); 476 } 477 } 478 479 @Override 480 public void onSwipeFromRight() { 481 final Region excludedRegion = Region.obtain(); 482 synchronized (mLock) { 483 mDisplayContent.calculateSystemGestureExclusion( 484 excludedRegion, null /* outUnrestricted */); 485 } 486 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture 487 || mNavigationBarPosition == NAV_BAR_RIGHT; 488 if (mNavigationBar != null && sideAllowed 489 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) { 490 requestTransientBars(mNavigationBar); 491 } 492 excludedRegion.recycle(); 493 } 494 495 @Override 496 public void onSwipeFromLeft() { 497 final Region excludedRegion = Region.obtain(); 498 synchronized (mLock) { 499 mDisplayContent.calculateSystemGestureExclusion( 500 excludedRegion, null /* outUnrestricted */); 501 } 502 final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture 503 || mNavigationBarPosition == NAV_BAR_LEFT; 504 if (mNavigationBar != null && sideAllowed 505 && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) { 506 requestTransientBars(mNavigationBar); 507 } 508 excludedRegion.recycle(); 509 } 510 511 @Override 512 public void onFling(int duration) { 513 if (mService.mPowerManagerInternal != null) { 514 mService.mPowerManagerInternal.powerHint( 515 PowerHint.INTERACTION, duration); 516 } 517 } 518 519 @Override 520 public void onDebug() { 521 // no-op 522 } 523 524 private WindowOrientationListener getOrientationListener() { 525 final DisplayRotation rotation = mDisplayContent.getDisplayRotation(); 526 return rotation != null ? rotation.getOrientationListener() : null; 527 } 528 529 @Override 530 public void onDown() { 531 final WindowOrientationListener listener = getOrientationListener(); 532 if (listener != null) { 533 listener.onTouchStart(); 534 } 535 } 536 537 @Override 538 public void onUpOrCancel() { 539 final WindowOrientationListener listener = getOrientationListener(); 540 if (listener != null) { 541 listener.onTouchEnd(); 542 } 543 } 544 545 @Override 546 public void onMouseHoverAtTop() { 547 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); 548 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS); 549 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS; 550 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */); 551 } 552 553 @Override 554 public void onMouseHoverAtBottom() { 555 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); 556 Message msg = mHandler.obtainMessage(MSG_REQUEST_TRANSIENT_BARS); 557 msg.arg1 = MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION; 558 mHandler.sendMessageDelayed(msg, 500 /* delayMillis */); 559 } 560 561 @Override 562 public void onMouseLeaveFromEdge() { 563 mHandler.removeMessages(MSG_REQUEST_TRANSIENT_BARS); 564 } 565 }); 566 displayContent.registerPointerEventListener(mSystemGestures); 567 displayContent.mAppTransition.registerListenerLocked( 568 mStatusBarController.getAppTransitionListener()); 569 mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext, looper, 570 mService.mVrModeEnabled); 571 mAcquireSleepTokenRunnable = () -> { 572 if (mWindowSleepToken != null) { 573 return; 574 } 575 mWindowSleepToken = service.mAtmInternal.acquireSleepToken( 576 "WindowSleepTokenOnDisplay" + displayId, displayId); 577 }; 578 mReleaseSleepTokenRunnable = () -> { 579 if (mWindowSleepToken == null) { 580 return; 581 } 582 mWindowSleepToken.release(); 583 mWindowSleepToken = null; 584 }; 585 586 // TODO: Make it can take screenshot on external display 587 mScreenshotHelper = displayContent.isDefaultDisplay 588 ? new ScreenshotHelper(mContext) : null; 589 590 if (mDisplayContent.isDefaultDisplay) { 591 mHasStatusBar = true; 592 mHasNavigationBar = mContext.getResources().getBoolean(R.bool.config_showNavigationBar); 593 594 // Allow a system property to override this. Used by the emulator. 595 // See also hasNavigationBar(). 596 String navBarOverride = SystemProperties.get("qemu.hw.mainkeys"); 597 if ("1".equals(navBarOverride)) { 598 mHasNavigationBar = false; 599 } else if ("0".equals(navBarOverride)) { 600 mHasNavigationBar = true; 601 } 602 } else { 603 mHasStatusBar = false; 604 mHasNavigationBar = mDisplayContent.supportsSystemDecorations(); 605 } 606 607 mRefreshRatePolicy = new RefreshRatePolicy(mService, 608 mDisplayContent.getDisplayInfo(), 609 mService.mHighRefreshRateBlacklist); 610 } 611 systemReady()612 void systemReady() { 613 mSystemGestures.systemReady(); 614 if (mService.mPointerLocationEnabled) { 615 setPointerLocationEnabled(true); 616 } 617 } 618 getDisplayId()619 private int getDisplayId() { 620 return mDisplayContent.getDisplayId(); 621 } 622 setHdmiPlugged(boolean plugged)623 public void setHdmiPlugged(boolean plugged) { 624 setHdmiPlugged(plugged, false /* force */); 625 } 626 setHdmiPlugged(boolean plugged, boolean force)627 public void setHdmiPlugged(boolean plugged, boolean force) { 628 if (force || mHdmiPlugged != plugged) { 629 mHdmiPlugged = plugged; 630 mService.updateRotation(true /* alwaysSendConfiguration */, true /* forceRelayout */); 631 final Intent intent = new Intent(ACTION_HDMI_PLUGGED); 632 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 633 intent.putExtra(EXTRA_HDMI_PLUGGED_STATE, plugged); 634 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); 635 } 636 } 637 isHdmiPlugged()638 boolean isHdmiPlugged() { 639 return mHdmiPlugged; 640 } 641 isCarDockEnablesAccelerometer()642 boolean isCarDockEnablesAccelerometer() { 643 return mCarDockEnablesAccelerometer; 644 } 645 isDeskDockEnablesAccelerometer()646 boolean isDeskDockEnablesAccelerometer() { 647 return mDeskDockEnablesAccelerometer; 648 } 649 setPersistentVrModeEnabled(boolean persistentVrModeEnabled)650 public void setPersistentVrModeEnabled(boolean persistentVrModeEnabled) { 651 mPersistentVrModeEnabled = persistentVrModeEnabled; 652 } 653 isPersistentVrModeEnabled()654 public boolean isPersistentVrModeEnabled() { 655 return mPersistentVrModeEnabled; 656 } 657 setDockMode(int dockMode)658 public void setDockMode(int dockMode) { 659 mDockMode = dockMode; 660 } 661 getDockMode()662 public int getDockMode() { 663 return mDockMode; 664 } 665 666 /** 667 * @see WindowManagerService.setForceShowSystemBars 668 */ setForceShowSystemBars(boolean forceShowSystemBars)669 void setForceShowSystemBars(boolean forceShowSystemBars) { 670 mForceShowSystemBarsFromExternal = forceShowSystemBars; 671 } 672 hasNavigationBar()673 public boolean hasNavigationBar() { 674 return mHasNavigationBar; 675 } 676 hasStatusBar()677 public boolean hasStatusBar() { 678 return mHasStatusBar; 679 } 680 hasSideGestures()681 boolean hasSideGestures() { 682 return mHasNavigationBar && mSideGestureInset > 0; 683 } 684 navigationBarCanMove()685 public boolean navigationBarCanMove() { 686 return mNavigationBarCanMove; 687 } 688 setLidState(int lidState)689 public void setLidState(int lidState) { 690 mLidState = lidState; 691 } 692 getLidState()693 public int getLidState() { 694 return mLidState; 695 } 696 setAwake(boolean awake)697 public void setAwake(boolean awake) { 698 mAwake = awake; 699 } 700 isAwake()701 public boolean isAwake() { 702 return mAwake; 703 } 704 isScreenOnEarly()705 public boolean isScreenOnEarly() { 706 return mScreenOnEarly; 707 } 708 isScreenOnFully()709 public boolean isScreenOnFully() { 710 return mScreenOnFully; 711 } 712 isKeyguardDrawComplete()713 public boolean isKeyguardDrawComplete() { 714 return mKeyguardDrawComplete; 715 } 716 isWindowManagerDrawComplete()717 public boolean isWindowManagerDrawComplete() { 718 return mWindowManagerDrawComplete; 719 } 720 getScreenOnListener()721 public ScreenOnListener getScreenOnListener() { 722 return mScreenOnListener; 723 } 724 screenTurnedOn(ScreenOnListener screenOnListener)725 public void screenTurnedOn(ScreenOnListener screenOnListener) { 726 synchronized (mLock) { 727 mScreenOnEarly = true; 728 mScreenOnFully = false; 729 mKeyguardDrawComplete = false; 730 mWindowManagerDrawComplete = false; 731 mScreenOnListener = screenOnListener; 732 } 733 } 734 screenTurnedOff()735 public void screenTurnedOff() { 736 synchronized (mLock) { 737 mScreenOnEarly = false; 738 mScreenOnFully = false; 739 mKeyguardDrawComplete = false; 740 mWindowManagerDrawComplete = false; 741 mScreenOnListener = null; 742 } 743 } 744 745 /** Return false if we are not awake yet or we have already informed of this event. */ finishKeyguardDrawn()746 public boolean finishKeyguardDrawn() { 747 synchronized (mLock) { 748 if (!mScreenOnEarly || mKeyguardDrawComplete) { 749 return false; 750 } 751 752 mKeyguardDrawComplete = true; 753 mWindowManagerDrawComplete = false; 754 } 755 return true; 756 } 757 758 /** Return false if screen is not turned on or we did already handle this case earlier. */ finishWindowsDrawn()759 public boolean finishWindowsDrawn() { 760 synchronized (mLock) { 761 if (!mScreenOnEarly || mWindowManagerDrawComplete) { 762 return false; 763 } 764 765 mWindowManagerDrawComplete = true; 766 } 767 return true; 768 } 769 770 /** Return false if it is not ready to turn on. */ finishScreenTurningOn()771 public boolean finishScreenTurningOn() { 772 synchronized (mLock) { 773 if (DEBUG_SCREEN_ON) Slog.d(TAG, 774 "finishScreenTurningOn: mAwake=" + mAwake 775 + ", mScreenOnEarly=" + mScreenOnEarly 776 + ", mScreenOnFully=" + mScreenOnFully 777 + ", mKeyguardDrawComplete=" + mKeyguardDrawComplete 778 + ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete); 779 780 if (mScreenOnFully || !mScreenOnEarly || !mWindowManagerDrawComplete 781 || (mAwake && !mKeyguardDrawComplete)) { 782 return false; 783 } 784 785 if (DEBUG_SCREEN_ON) Slog.i(TAG, "Finished screen turning on..."); 786 mScreenOnListener = null; 787 mScreenOnFully = true; 788 } 789 return true; 790 } 791 hasStatusBarServicePermission(int pid, int uid)792 private boolean hasStatusBarServicePermission(int pid, int uid) { 793 return mContext.checkPermission(permission.STATUS_BAR_SERVICE, pid, uid) 794 == PackageManager.PERMISSION_GRANTED; 795 } 796 797 /** 798 * Sanitize the layout parameters coming from a client. Allows the policy 799 * to do things like ensure that windows of a specific type can't take 800 * input focus. 801 * 802 * @param attrs The window layout parameters to be modified. These values 803 * are modified in-place. 804 */ adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs, int callingPid, int callingUid)805 public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs, 806 int callingPid, int callingUid) { 807 808 final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0; 809 if (mScreenDecorWindows.contains(win)) { 810 if (!isScreenDecor) { 811 // No longer has the flag set, so remove from the set. 812 mScreenDecorWindows.remove(win); 813 } 814 } else if (isScreenDecor && hasStatusBarServicePermission(callingPid, callingUid)) { 815 mScreenDecorWindows.add(win); 816 } 817 818 switch (attrs.type) { 819 case TYPE_SYSTEM_OVERLAY: 820 case TYPE_SECURE_SYSTEM_OVERLAY: 821 // These types of windows can't receive input events. 822 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 823 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 824 attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; 825 break; 826 case TYPE_DREAM: 827 case TYPE_WALLPAPER: 828 // Dreams and wallpapers don't have an app window token and can thus not be 829 // letterboxed. Hence always let them extend under the cutout. 830 attrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 831 break; 832 case TYPE_STATUS_BAR: 833 834 // If the Keyguard is in a hidden state (occluded by another window), we force to 835 // remove the wallpaper and keyguard flag so that any change in-flight after setting 836 // the keyguard as occluded wouldn't set these flags again. 837 // See {@link #processKeyguardSetHiddenResultLw}. 838 if (mService.mPolicy.isKeyguardOccluded()) { 839 attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 840 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; 841 } 842 break; 843 844 case TYPE_SCREENSHOT: 845 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 846 break; 847 848 case TYPE_TOAST: 849 // While apps should use the dedicated toast APIs to add such windows 850 // it possible legacy apps to add the window directly. Therefore, we 851 // make windows added directly by the app behave as a toast as much 852 // as possible in terms of timeout and animation. 853 if (attrs.hideTimeoutMilliseconds < 0 854 || attrs.hideTimeoutMilliseconds > TOAST_WINDOW_TIMEOUT) { 855 attrs.hideTimeoutMilliseconds = TOAST_WINDOW_TIMEOUT; 856 } 857 // Accessibility users may need longer timeout duration. This api compares 858 // original timeout with user's preference and return longer one. It returns 859 // original timeout if there's no preference. 860 attrs.hideTimeoutMilliseconds = mAccessibilityManager.getRecommendedTimeoutMillis( 861 (int) attrs.hideTimeoutMilliseconds, 862 AccessibilityManager.FLAG_CONTENT_TEXT); 863 attrs.windowAnimations = com.android.internal.R.style.Animation_Toast; 864 // Toast can show with below conditions when the screen is locked. 865 if (canToastShowWhenLocked(callingPid)) { 866 attrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; 867 } 868 // Toasts can't be clickable 869 attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; 870 break; 871 } 872 873 if (attrs.type != TYPE_STATUS_BAR) { 874 // The status bar is the only window allowed to exhibit keyguard behavior. 875 attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD; 876 } 877 } 878 879 /** 880 * @return {@code true} if the calling activity initiate toast and is visible with 881 * {@link WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} flag. 882 */ canToastShowWhenLocked(int callingPid)883 boolean canToastShowWhenLocked(int callingPid) { 884 return mDisplayContent.forAllWindows(w -> { 885 return callingPid == w.mSession.mPid && w.isVisible() && w.canShowWhenLocked(); 886 }, true /* traverseTopToBottom */); 887 } 888 889 /** 890 * Preflight adding a window to the system. 891 * 892 * Currently enforces that three window types are singletons per display: 893 * <ul> 894 * <li>{@link WindowManager.LayoutParams#TYPE_STATUS_BAR}</li> 895 * <li>{@link WindowManager.LayoutParams#TYPE_NAVIGATION_BAR}</li> 896 * </ul> 897 * 898 * @param win The window to be added 899 * @param attrs Information about the window to be added 900 * 901 * @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons, 902 * WindowManagerImpl.ADD_MULTIPLE_SINGLETON 903 */ prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs)904 public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) { 905 906 if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) { 907 mContext.enforceCallingOrSelfPermission( 908 android.Manifest.permission.STATUS_BAR_SERVICE, 909 "DisplayPolicy"); 910 mScreenDecorWindows.add(win); 911 } 912 913 switch (attrs.type) { 914 case TYPE_STATUS_BAR: 915 mContext.enforceCallingOrSelfPermission( 916 android.Manifest.permission.STATUS_BAR_SERVICE, 917 "DisplayPolicy"); 918 if (mStatusBar != null) { 919 if (mStatusBar.isAlive()) { 920 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; 921 } 922 } 923 mStatusBar = win; 924 mStatusBarController.setWindow(win); 925 if (mDisplayContent.isDefaultDisplay) { 926 mService.mPolicy.setKeyguardCandidateLw(win); 927 } 928 final TriConsumer<DisplayFrames, WindowState, Rect> frameProvider = 929 (displayFrames, windowState, rect) -> { 930 rect.top = 0; 931 rect.bottom = getStatusBarHeight(displayFrames); 932 }; 933 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, win, frameProvider); 934 mDisplayContent.setInsetProvider(TYPE_TOP_GESTURES, win, frameProvider); 935 mDisplayContent.setInsetProvider(TYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider); 936 break; 937 case TYPE_NAVIGATION_BAR: 938 mContext.enforceCallingOrSelfPermission( 939 android.Manifest.permission.STATUS_BAR_SERVICE, 940 "DisplayPolicy"); 941 if (mNavigationBar != null) { 942 if (mNavigationBar.isAlive()) { 943 return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON; 944 } 945 } 946 mNavigationBar = win; 947 mNavigationBarController.setWindow(win); 948 mNavigationBarController.setOnBarVisibilityChangedListener( 949 mNavBarVisibilityListener, true); 950 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR, 951 win, null /* frameProvider */); 952 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_GESTURES, win, 953 (displayFrames, windowState, inOutFrame) -> { 954 inOutFrame.top -= mBottomGestureAdditionalInset; 955 }); 956 mDisplayContent.setInsetProvider(InsetsState.TYPE_LEFT_GESTURES, win, 957 (displayFrames, windowState, inOutFrame) -> { 958 inOutFrame.left = 0; 959 inOutFrame.top = 0; 960 inOutFrame.bottom = displayFrames.mDisplayHeight; 961 inOutFrame.right = displayFrames.mUnrestricted.left + mSideGestureInset; 962 }); 963 mDisplayContent.setInsetProvider(InsetsState.TYPE_RIGHT_GESTURES, win, 964 (displayFrames, windowState, inOutFrame) -> { 965 inOutFrame.left = displayFrames.mUnrestricted.right - mSideGestureInset; 966 inOutFrame.top = 0; 967 inOutFrame.bottom = displayFrames.mDisplayHeight; 968 inOutFrame.right = displayFrames.mDisplayWidth; 969 }); 970 mDisplayContent.setInsetProvider(InsetsState.TYPE_BOTTOM_TAPPABLE_ELEMENT, win, 971 (displayFrames, windowState, inOutFrame) -> { 972 if ((windowState.getAttrs().flags & FLAG_NOT_TOUCHABLE) != 0 973 || mNavigationBarLetsThroughTaps) { 974 inOutFrame.setEmpty(); 975 } 976 }); 977 if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar); 978 break; 979 case TYPE_NAVIGATION_BAR_PANEL: 980 case TYPE_STATUS_BAR_PANEL: 981 case TYPE_STATUS_BAR_SUB_PANEL: 982 case TYPE_VOICE_INTERACTION_STARTING: 983 mContext.enforceCallingOrSelfPermission( 984 android.Manifest.permission.STATUS_BAR_SERVICE, 985 "DisplayPolicy"); 986 break; 987 } 988 return ADD_OKAY; 989 } 990 991 /** 992 * Called when a window is being removed from a window manager. Must not 993 * throw an exception -- clean up as much as possible. 994 * 995 * @param win The window being removed. 996 */ removeWindowLw(WindowState win)997 public void removeWindowLw(WindowState win) { 998 if (mStatusBar == win) { 999 mStatusBar = null; 1000 mStatusBarController.setWindow(null); 1001 if (mDisplayContent.isDefaultDisplay) { 1002 mService.mPolicy.setKeyguardCandidateLw(null); 1003 } 1004 mDisplayContent.setInsetProvider(TYPE_TOP_BAR, null, null); 1005 } else if (mNavigationBar == win) { 1006 mNavigationBar = null; 1007 mNavigationBarController.setWindow(null); 1008 mDisplayContent.setInsetProvider(InsetsState.TYPE_NAVIGATION_BAR, null, null); 1009 } 1010 if (mLastFocusedWindow == win) { 1011 mLastFocusedWindow = null; 1012 } 1013 mScreenDecorWindows.remove(win); 1014 } 1015 getStatusBarHeight(DisplayFrames displayFrames)1016 private int getStatusBarHeight(DisplayFrames displayFrames) { 1017 return Math.max(mStatusBarHeightForRotation[displayFrames.mRotation], 1018 displayFrames.mDisplayCutoutSafe.top); 1019 } 1020 1021 /** 1022 * Control the animation to run when a window's state changes. Return a 1023 * non-0 number to force the animation to a specific resource ID, or 0 1024 * to use the default animation. 1025 * 1026 * @param win The window that is changing. 1027 * @param transit What is happening to the window: 1028 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_ENTER}, 1029 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_EXIT}, 1030 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_SHOW}, or 1031 * {@link com.android.server.policy.WindowManagerPolicy#TRANSIT_HIDE}. 1032 * 1033 * @return Resource ID of the actual animation to use, or 0 for none. 1034 */ selectAnimationLw(WindowState win, int transit)1035 public int selectAnimationLw(WindowState win, int transit) { 1036 if (DEBUG_ANIM) Slog.i(TAG, "selectAnimation in " + win 1037 + ": transit=" + transit); 1038 if (win == mStatusBar) { 1039 final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0; 1040 final boolean expanded = win.getAttrs().height == MATCH_PARENT 1041 && win.getAttrs().width == MATCH_PARENT; 1042 if (isKeyguard || expanded) { 1043 return -1; 1044 } 1045 if (transit == TRANSIT_EXIT 1046 || transit == TRANSIT_HIDE) { 1047 return R.anim.dock_top_exit; 1048 } else if (transit == TRANSIT_ENTER 1049 || transit == TRANSIT_SHOW) { 1050 return R.anim.dock_top_enter; 1051 } 1052 } else if (win == mNavigationBar) { 1053 if (win.getAttrs().windowAnimations != 0) { 1054 return 0; 1055 } 1056 // This can be on either the bottom or the right or the left. 1057 if (mNavigationBarPosition == NAV_BAR_BOTTOM) { 1058 if (transit == TRANSIT_EXIT 1059 || transit == TRANSIT_HIDE) { 1060 if (mService.mPolicy.isKeyguardShowingAndNotOccluded()) { 1061 return R.anim.dock_bottom_exit_keyguard; 1062 } else { 1063 return R.anim.dock_bottom_exit; 1064 } 1065 } else if (transit == TRANSIT_ENTER 1066 || transit == TRANSIT_SHOW) { 1067 return R.anim.dock_bottom_enter; 1068 } 1069 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) { 1070 if (transit == TRANSIT_EXIT 1071 || transit == TRANSIT_HIDE) { 1072 return R.anim.dock_right_exit; 1073 } else if (transit == TRANSIT_ENTER 1074 || transit == TRANSIT_SHOW) { 1075 return R.anim.dock_right_enter; 1076 } 1077 } else if (mNavigationBarPosition == NAV_BAR_LEFT) { 1078 if (transit == TRANSIT_EXIT 1079 || transit == TRANSIT_HIDE) { 1080 return R.anim.dock_left_exit; 1081 } else if (transit == TRANSIT_ENTER 1082 || transit == TRANSIT_SHOW) { 1083 return R.anim.dock_left_enter; 1084 } 1085 } 1086 } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) { 1087 return selectDockedDividerAnimationLw(win, transit); 1088 } 1089 1090 if (transit == TRANSIT_PREVIEW_DONE) { 1091 if (win.hasAppShownWindows()) { 1092 if (DEBUG_ANIM) Slog.i(TAG, "**** STARTING EXIT"); 1093 return R.anim.app_starting_exit; 1094 } 1095 } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen 1096 && transit == TRANSIT_ENTER) { 1097 // Special case: we are animating in a dream, while the keyguard 1098 // is shown. We don't want an animation on the dream, because 1099 // we need it shown immediately with the keyguard animating away 1100 // to reveal it. 1101 return -1; 1102 } 1103 1104 return 0; 1105 } 1106 selectDockedDividerAnimationLw(WindowState win, int transit)1107 private int selectDockedDividerAnimationLw(WindowState win, int transit) { 1108 int insets = mDisplayContent.getDockedDividerController().getContentInsets(); 1109 1110 // If the divider is behind the navigation bar, don't animate. 1111 final Rect frame = win.getFrameLw(); 1112 final boolean behindNavBar = mNavigationBar != null 1113 && ((mNavigationBarPosition == NAV_BAR_BOTTOM 1114 && frame.top + insets >= mNavigationBar.getFrameLw().top) 1115 || (mNavigationBarPosition == NAV_BAR_RIGHT 1116 && frame.left + insets >= mNavigationBar.getFrameLw().left) 1117 || (mNavigationBarPosition == NAV_BAR_LEFT 1118 && frame.right - insets <= mNavigationBar.getFrameLw().right)); 1119 final boolean landscape = frame.height() > frame.width(); 1120 final boolean offscreenLandscape = landscape && (frame.right - insets <= 0 1121 || frame.left + insets >= win.getDisplayFrameLw().right); 1122 final boolean offscreenPortrait = !landscape && (frame.top - insets <= 0 1123 || frame.bottom + insets >= win.getDisplayFrameLw().bottom); 1124 final boolean offscreen = offscreenLandscape || offscreenPortrait; 1125 if (behindNavBar || offscreen) { 1126 return 0; 1127 } 1128 if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) { 1129 return R.anim.fade_in; 1130 } else if (transit == TRANSIT_EXIT) { 1131 return R.anim.fade_out; 1132 } else { 1133 return 0; 1134 } 1135 } 1136 1137 /** 1138 * Determine the animation to run for a rotation transition based on the 1139 * top fullscreen windows {@link WindowManager.LayoutParams#rotationAnimation} 1140 * and whether it is currently fullscreen and frontmost. 1141 * 1142 * @param anim The exiting animation resource id is stored in anim[0], the 1143 * entering animation resource id is stored in anim[1]. 1144 */ selectRotationAnimationLw(int anim[])1145 public void selectRotationAnimationLw(int anim[]) { 1146 // If the screen is off or non-interactive, force a jumpcut. 1147 final boolean forceJumpcut = !mScreenOnFully || !mService.mPolicy.okToAnimate(); 1148 if (DEBUG_ANIM) Slog.i(TAG, "selectRotationAnimation mTopFullscreen=" 1149 + mTopFullscreenOpaqueWindowState + " rotationAnimation=" 1150 + (mTopFullscreenOpaqueWindowState == null 1151 ? "0" : mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation) 1152 + " forceJumpcut=" + forceJumpcut); 1153 if (forceJumpcut) { 1154 anim[0] = R.anim.rotation_animation_jump_exit; 1155 anim[1] = R.anim.rotation_animation_enter; 1156 return; 1157 } 1158 if (mTopFullscreenOpaqueWindowState != null) { 1159 int animationHint = mTopFullscreenOpaqueWindowState.getRotationAnimationHint(); 1160 if (animationHint < 0 && mTopIsFullscreen) { 1161 animationHint = mTopFullscreenOpaqueWindowState.getAttrs().rotationAnimation; 1162 } 1163 switch (animationHint) { 1164 case ROTATION_ANIMATION_CROSSFADE: 1165 case ROTATION_ANIMATION_SEAMLESS: // Crossfade is fallback for seamless. 1166 anim[0] = R.anim.rotation_animation_xfade_exit; 1167 anim[1] = R.anim.rotation_animation_enter; 1168 break; 1169 case ROTATION_ANIMATION_JUMPCUT: 1170 anim[0] = R.anim.rotation_animation_jump_exit; 1171 anim[1] = R.anim.rotation_animation_enter; 1172 break; 1173 case ROTATION_ANIMATION_ROTATE: 1174 default: 1175 anim[0] = anim[1] = 0; 1176 break; 1177 } 1178 } else { 1179 anim[0] = anim[1] = 0; 1180 } 1181 } 1182 1183 /** 1184 * Validate whether the current top fullscreen has specified the same 1185 * {@link WindowManager.LayoutParams#rotationAnimation} value as that 1186 * being passed in from the previous top fullscreen window. 1187 * 1188 * @param exitAnimId exiting resource id from the previous window. 1189 * @param enterAnimId entering resource id from the previous window. 1190 * @param forceDefault For rotation animations only, if true ignore the 1191 * animation values and just return false. 1192 * @return true if the previous values are still valid, false if they 1193 * should be replaced with the default. 1194 */ validateRotationAnimationLw(int exitAnimId, int enterAnimId, boolean forceDefault)1195 public boolean validateRotationAnimationLw(int exitAnimId, int enterAnimId, 1196 boolean forceDefault) { 1197 switch (exitAnimId) { 1198 case R.anim.rotation_animation_xfade_exit: 1199 case R.anim.rotation_animation_jump_exit: 1200 // These are the only cases that matter. 1201 if (forceDefault) { 1202 return false; 1203 } 1204 int anim[] = new int[2]; 1205 selectRotationAnimationLw(anim); 1206 return (exitAnimId == anim[0] && enterAnimId == anim[1]); 1207 default: 1208 return true; 1209 } 1210 } 1211 1212 /** 1213 * Called when a new system UI visibility is being reported, allowing 1214 * the policy to adjust what is actually reported. 1215 * @param visibility The raw visibility reported by the status bar. 1216 * @return The new desired visibility. 1217 */ adjustSystemUiVisibilityLw(int visibility)1218 public int adjustSystemUiVisibilityLw(int visibility) { 1219 mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility); 1220 mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility); 1221 1222 // Reset any bits in mForceClearingStatusBarVisibility that 1223 // are now clear. 1224 mResettingSystemUiFlags &= visibility; 1225 // Clear any bits in the new visibility that are currently being 1226 // force cleared, before reporting it. 1227 return visibility & ~mResettingSystemUiFlags 1228 & ~mForceClearedSystemUiFlags; 1229 } 1230 1231 /** 1232 * @return true if the system bars are forced to stay visible 1233 */ areSystemBarsForcedShownLw(WindowState windowState)1234 public boolean areSystemBarsForcedShownLw(WindowState windowState) { 1235 return mForceShowSystemBars; 1236 } 1237 1238 // TODO: Should probably be moved into DisplayFrames. 1239 /** 1240 * Return the layout hints for a newly added window. These values are computed on the 1241 * most recent layout, so they are not guaranteed to be correct. 1242 * 1243 * @param attrs The LayoutParams of the window. 1244 * @param taskBounds The bounds of the task this window is on or {@code null} if no task is 1245 * associated with the window. 1246 * @param displayFrames display frames. 1247 * @param floatingStack Whether the window's stack is floating. 1248 * @param outFrame The frame of the window. 1249 * @param outContentInsets The areas covered by system windows, expressed as positive insets. 1250 * @param outStableInsets The areas covered by stable system windows irrespective of their 1251 * current visibility. Expressed as positive insets. 1252 * @param outOutsets The areas that are not real display, but we would like to treat as such. 1253 * @param outDisplayCutout The area that has been cut away from the display. 1254 * @return Whether to always consume the system bars. 1255 * See {@link #areSystemBarsForcedShownLw(WindowState)}. 1256 */ getLayoutHintLw(LayoutParams attrs, Rect taskBounds, DisplayFrames displayFrames, boolean floatingStack, Rect outFrame, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout)1257 public boolean getLayoutHintLw(LayoutParams attrs, Rect taskBounds, 1258 DisplayFrames displayFrames, boolean floatingStack, Rect outFrame, 1259 Rect outContentInsets, Rect outStableInsets, 1260 Rect outOutsets, DisplayCutout.ParcelableWrapper outDisplayCutout) { 1261 final int fl = PolicyControl.getWindowFlags(null, attrs); 1262 final int pfl = attrs.privateFlags; 1263 final int requestedSysUiVis = PolicyControl.getSystemUiVisibility(null, attrs); 1264 final int sysUiVis = requestedSysUiVis | getImpliedSysUiFlagsForLayout(attrs); 1265 final int displayRotation = displayFrames.mRotation; 1266 1267 final boolean useOutsets = outOutsets != null && shouldUseOutsets(attrs, fl); 1268 if (useOutsets) { 1269 int outset = mWindowOutsetBottom; 1270 if (outset > 0) { 1271 if (displayRotation == Surface.ROTATION_0) { 1272 outOutsets.bottom += outset; 1273 } else if (displayRotation == Surface.ROTATION_90) { 1274 outOutsets.right += outset; 1275 } else if (displayRotation == Surface.ROTATION_180) { 1276 outOutsets.top += outset; 1277 } else if (displayRotation == Surface.ROTATION_270) { 1278 outOutsets.left += outset; 1279 } 1280 } 1281 } 1282 1283 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) != 0; 1284 final boolean layoutInScreenAndInsetDecor = layoutInScreen 1285 && (fl & FLAG_LAYOUT_INSET_DECOR) != 0; 1286 final boolean screenDecor = (pfl & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0; 1287 1288 if (layoutInScreenAndInsetDecor && !screenDecor) { 1289 if ((sysUiVis & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0) { 1290 outFrame.set(displayFrames.mUnrestricted); 1291 } else { 1292 outFrame.set(displayFrames.mRestricted); 1293 } 1294 1295 final Rect sf; 1296 if (floatingStack) { 1297 sf = null; 1298 } else { 1299 sf = displayFrames.mStable; 1300 } 1301 1302 final Rect cf; 1303 if (floatingStack) { 1304 cf = null; 1305 } else if ((sysUiVis & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0) { 1306 if ((fl & FLAG_FULLSCREEN) != 0) { 1307 cf = displayFrames.mStableFullscreen; 1308 } else { 1309 cf = displayFrames.mStable; 1310 } 1311 } else if ((fl & FLAG_FULLSCREEN) != 0 || (fl & FLAG_LAYOUT_IN_OVERSCAN) != 0) { 1312 cf = displayFrames.mOverscan; 1313 } else { 1314 cf = displayFrames.mCurrent; 1315 } 1316 1317 if (taskBounds != null) { 1318 outFrame.intersect(taskBounds); 1319 } 1320 InsetUtils.insetsBetweenFrames(outFrame, cf, outContentInsets); 1321 InsetUtils.insetsBetweenFrames(outFrame, sf, outStableInsets); 1322 outDisplayCutout.set(displayFrames.mDisplayCutout.calculateRelativeTo(outFrame) 1323 .getDisplayCutout()); 1324 return mForceShowSystemBars; 1325 } else { 1326 if (layoutInScreen) { 1327 outFrame.set(displayFrames.mUnrestricted); 1328 } else { 1329 outFrame.set(displayFrames.mStable); 1330 } 1331 if (taskBounds != null) { 1332 outFrame.intersect(taskBounds); 1333 } 1334 1335 outContentInsets.setEmpty(); 1336 outStableInsets.setEmpty(); 1337 outDisplayCutout.set(DisplayCutout.NO_CUTOUT); 1338 return mForceShowSystemBars; 1339 } 1340 } 1341 getImpliedSysUiFlagsForLayout(LayoutParams attrs)1342 private static int getImpliedSysUiFlagsForLayout(LayoutParams attrs) { 1343 int impliedFlags = 0; 1344 final boolean forceWindowDrawsBarBackgrounds = 1345 (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0 1346 && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT; 1347 if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0 1348 || forceWindowDrawsBarBackgrounds) { 1349 impliedFlags |= SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION; 1350 impliedFlags |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 1351 } 1352 return impliedFlags; 1353 } 1354 shouldUseOutsets(WindowManager.LayoutParams attrs, int fl)1355 private static boolean shouldUseOutsets(WindowManager.LayoutParams attrs, int fl) { 1356 return attrs.type == TYPE_WALLPAPER || (fl & (WindowManager.LayoutParams.FLAG_FULLSCREEN 1357 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN)) != 0; 1358 } 1359 1360 private final Runnable mClearHideNavigationFlag = new Runnable() { 1361 @Override 1362 public void run() { 1363 synchronized (mLock) { 1364 mForceClearedSystemUiFlags &= ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 1365 mDisplayContent.reevaluateStatusBarVisibility(); 1366 } 1367 } 1368 }; 1369 1370 /** 1371 * Input handler used while nav bar is hidden. Captures any touch on the screen, 1372 * to determine when the nav bar should be shown and prevent applications from 1373 * receiving those touches. 1374 */ 1375 private final class HideNavInputEventReceiver extends InputEventReceiver { HideNavInputEventReceiver(InputChannel inputChannel, Looper looper)1376 HideNavInputEventReceiver(InputChannel inputChannel, Looper looper) { 1377 super(inputChannel, looper); 1378 } 1379 1380 @Override onInputEvent(InputEvent event)1381 public void onInputEvent(InputEvent event) { 1382 try { 1383 if (event instanceof MotionEvent 1384 && (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { 1385 final MotionEvent motionEvent = (MotionEvent) event; 1386 if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { 1387 // When the user taps down, we re-show the nav bar. 1388 boolean changed = false; 1389 synchronized (mLock) { 1390 if (mInputConsumer == null) { 1391 return; 1392 } 1393 // Any user activity always causes us to show the 1394 // navigation controls, if they had been hidden. 1395 // We also clear the low profile and only content 1396 // flags so that tapping on the screen will atomically 1397 // restore all currently hidden screen decorations. 1398 int newVal = mResettingSystemUiFlags 1399 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 1400 | View.SYSTEM_UI_FLAG_LOW_PROFILE 1401 | View.SYSTEM_UI_FLAG_FULLSCREEN; 1402 if (mResettingSystemUiFlags != newVal) { 1403 mResettingSystemUiFlags = newVal; 1404 changed = true; 1405 } 1406 // We don't allow the system's nav bar to be hidden 1407 // again for 1 second, to prevent applications from 1408 // spamming us and keeping it from being shown. 1409 newVal = mForceClearedSystemUiFlags 1410 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION; 1411 if (mForceClearedSystemUiFlags != newVal) { 1412 mForceClearedSystemUiFlags = newVal; 1413 changed = true; 1414 mHandler.postDelayed(mClearHideNavigationFlag, 1000); 1415 } 1416 if (changed) { 1417 mDisplayContent.reevaluateStatusBarVisibility(); 1418 } 1419 } 1420 } 1421 } 1422 } finally { 1423 finishInputEvent(event, false /* handled */); 1424 } 1425 } 1426 } 1427 1428 /** 1429 * Called when layout of the windows is about to start. 1430 * 1431 * @param displayFrames frames of the display we are doing layout on. 1432 * @param uiMode The current uiMode in configuration. 1433 */ beginLayoutLw(DisplayFrames displayFrames, int uiMode)1434 public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) { 1435 displayFrames.onBeginLayout(); 1436 mSystemGestures.screenWidth = displayFrames.mUnrestricted.width(); 1437 mSystemGestures.screenHeight = displayFrames.mUnrestricted.height(); 1438 1439 // For purposes of putting out fake window up to steal focus, we will 1440 // drive nav being hidden only by whether it is requested. 1441 final int sysui = mLastSystemUiFlags; 1442 boolean navVisible = (sysui & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0; 1443 boolean navTranslucent = (sysui 1444 & (View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT)) != 0; 1445 boolean immersive = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0; 1446 boolean immersiveSticky = (sysui & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0; 1447 boolean navAllowedHidden = immersive || immersiveSticky; 1448 navTranslucent &= !immersiveSticky; // transient trumps translucent 1449 boolean isKeyguardShowing = isStatusBarKeyguard() 1450 && !mService.mPolicy.isKeyguardOccluded(); 1451 boolean statusBarForcesShowingNavigation = !isKeyguardShowing && mStatusBar != null 1452 && (mStatusBar.getAttrs().privateFlags 1453 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0; 1454 1455 // When the navigation bar isn't visible, we put up a fake input window to catch all 1456 // touch events. This way we can detect when the user presses anywhere to bring back the 1457 // nav bar and ensure the application doesn't see the event. 1458 if (navVisible || navAllowedHidden) { 1459 if (mInputConsumer != null) { 1460 mHandler.sendMessage( 1461 mHandler.obtainMessage(MSG_DISPOSE_INPUT_CONSUMER, mInputConsumer)); 1462 mInputConsumer = null; 1463 } 1464 } else if (mInputConsumer == null && mStatusBar != null && canHideNavigationBar()) { 1465 mInputConsumer = mService.createInputConsumer(mHandler.getLooper(), 1466 INPUT_CONSUMER_NAVIGATION, 1467 HideNavInputEventReceiver::new, 1468 displayFrames.mDisplayId); 1469 // As long as mInputConsumer is active, hover events are not dispatched to the app 1470 // and the pointer icon is likely to become stale. Hide it to avoid confusion. 1471 InputManager.getInstance().setPointerIconType(PointerIcon.TYPE_NULL); 1472 } 1473 1474 // For purposes of positioning and showing the nav bar, if we have decided that it can't 1475 // be hidden (because of the screen aspect ratio), then take that into account. 1476 navVisible |= !canHideNavigationBar(); 1477 1478 boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible, 1479 navTranslucent, navAllowedHidden, statusBarForcesShowingNavigation); 1480 if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock); 1481 updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing); 1482 if (updateSysUiVisibility) { 1483 updateSystemUiVisibilityLw(); 1484 } 1485 layoutScreenDecorWindows(displayFrames); 1486 1487 if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) { 1488 // Make sure that the zone we're avoiding for the cutout is at least as tall as the 1489 // status bar; otherwise fullscreen apps will end up cutting halfway into the status 1490 // bar. 1491 displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top, 1492 displayFrames.mStable.top); 1493 } 1494 1495 // In case this is a virtual display, and the host display has insets that overlap this 1496 // virtual display, apply the insets of the overlapped area onto the current and content 1497 // frame of this virtual display. This let us layout windows in the virtual display as 1498 // expected when the window needs to avoid overlap with the system windows. 1499 // TODO: Generalize the forwarded insets, so that we can handle system windows other than 1500 // IME. 1501 displayFrames.mCurrent.inset(mForwardedInsets); 1502 displayFrames.mContent.inset(mForwardedInsets); 1503 } 1504 layoutScreenDecorWindows(DisplayFrames displayFrames)1505 private void layoutScreenDecorWindows(DisplayFrames displayFrames) { 1506 if (mScreenDecorWindows.isEmpty()) { 1507 return; 1508 } 1509 1510 sTmpRect.setEmpty(); 1511 final int displayId = displayFrames.mDisplayId; 1512 final Rect dockFrame = displayFrames.mDock; 1513 final int displayHeight = displayFrames.mDisplayHeight; 1514 final int displayWidth = displayFrames.mDisplayWidth; 1515 1516 for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) { 1517 final WindowState w = mScreenDecorWindows.valueAt(i); 1518 if (w.getDisplayId() != displayId || !w.isVisibleLw()) { 1519 // Skip if not on the same display or not visible. 1520 continue; 1521 } 1522 1523 w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */, 1524 displayFrames.mUnrestricted /* displayFrame */, 1525 displayFrames.mUnrestricted /* overscanFrame */, 1526 displayFrames.mUnrestricted /* contentFrame */, 1527 displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */, 1528 displayFrames.mUnrestricted /* stableFrame */, 1529 displayFrames.mUnrestricted /* outsetFrame */); 1530 w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout); 1531 w.computeFrameLw(); 1532 final Rect frame = w.getFrameLw(); 1533 1534 if (frame.left <= 0 && frame.top <= 0) { 1535 // Docked at left or top. 1536 if (frame.bottom >= displayHeight) { 1537 // Docked left. 1538 dockFrame.left = Math.max(frame.right, dockFrame.left); 1539 } else if (frame.right >= displayWidth) { 1540 // Docked top. 1541 dockFrame.top = Math.max(frame.bottom, dockFrame.top); 1542 } else { 1543 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w 1544 + " not docked on left or top of display. frame=" + frame 1545 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight); 1546 } 1547 } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) { 1548 // Docked at right or bottom. 1549 if (frame.top <= 0) { 1550 // Docked right. 1551 dockFrame.right = Math.min(frame.left, dockFrame.right); 1552 } else if (frame.left <= 0) { 1553 // Docked bottom. 1554 dockFrame.bottom = Math.min(frame.top, dockFrame.bottom); 1555 } else { 1556 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w 1557 + " not docked on right or bottom" + " of display. frame=" + frame 1558 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight); 1559 } 1560 } else { 1561 // Screen decor windows are required to be docked on one of the sides of the screen. 1562 Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w 1563 + " not docked on one of the sides of the display. frame=" + frame 1564 + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight); 1565 } 1566 } 1567 1568 displayFrames.mRestricted.set(dockFrame); 1569 displayFrames.mCurrent.set(dockFrame); 1570 displayFrames.mVoiceContent.set(dockFrame); 1571 displayFrames.mSystem.set(dockFrame); 1572 displayFrames.mContent.set(dockFrame); 1573 displayFrames.mRestrictedOverscan.set(dockFrame); 1574 } 1575 layoutStatusBar(DisplayFrames displayFrames, int sysui, boolean isKeyguardShowing)1576 private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui, 1577 boolean isKeyguardShowing) { 1578 // decide where the status bar goes ahead of time 1579 if (mStatusBar == null) { 1580 return false; 1581 } 1582 // apply any navigation bar insets 1583 sTmpRect.setEmpty(); 1584 final WindowFrames windowFrames = mStatusBar.getWindowFrames(); 1585 windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */, 1586 displayFrames.mUnrestricted /* displayFrame */, 1587 displayFrames.mStable /* overscanFrame */, displayFrames.mStable /* contentFrame */, 1588 displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */, 1589 displayFrames.mStable /* stableFrame */, displayFrames.mStable /* outsetFrame */); 1590 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout); 1591 1592 // Let the status bar determine its size. 1593 mStatusBar.computeFrameLw(); 1594 1595 // For layout, the status bar is always at the top with our fixed height. 1596 displayFrames.mStable.top = displayFrames.mUnrestricted.top 1597 + mStatusBarHeightForRotation[displayFrames.mRotation]; 1598 // Make sure the status bar covers the entire cutout height 1599 displayFrames.mStable.top = Math.max(displayFrames.mStable.top, 1600 displayFrames.mDisplayCutoutSafe.top); 1601 1602 // Tell the bar controller where the collapsed status bar content is 1603 sTmpRect.set(mStatusBar.getContentFrameLw()); 1604 sTmpRect.intersect(displayFrames.mDisplayCutoutSafe); 1605 sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset 1606 sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size 1607 mStatusBarController.setContentFrame(sTmpRect); 1608 1609 boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0; 1610 boolean statusBarTranslucent = (sysui 1611 & (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0; 1612 1613 // If the status bar is hidden, we don't want to cause windows behind it to scroll. 1614 if (mStatusBar.isVisibleLw() && !statusBarTransient) { 1615 // Status bar may go away, so the screen area it occupies is available to apps but just 1616 // covering them when the status bar is visible. 1617 final Rect dockFrame = displayFrames.mDock; 1618 dockFrame.top = displayFrames.mStable.top; 1619 displayFrames.mContent.set(dockFrame); 1620 displayFrames.mVoiceContent.set(dockFrame); 1621 displayFrames.mCurrent.set(dockFrame); 1622 1623 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " + String.format( 1624 "dock=%s content=%s cur=%s", dockFrame.toString(), 1625 displayFrames.mContent.toString(), displayFrames.mCurrent.toString())); 1626 1627 if (!statusBarTranslucent && !mStatusBarController.wasRecentlyTranslucent() 1628 && !mStatusBar.isAnimatingLw()) { 1629 1630 // If the opaque status bar is currently requested to be visible, and not in the 1631 // process of animating on or off, then we can tell the app that it is covered by 1632 // it. 1633 displayFrames.mSystem.top = displayFrames.mStable.top; 1634 } 1635 } 1636 return mStatusBarController.checkHiddenLw(); 1637 } 1638 layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible, boolean navTranslucent, boolean navAllowedHidden, boolean statusBarForcesShowingNavigation)1639 private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible, 1640 boolean navTranslucent, boolean navAllowedHidden, 1641 boolean statusBarForcesShowingNavigation) { 1642 if (mNavigationBar == null) { 1643 return false; 1644 } 1645 1646 final Rect navigationFrame = sTmpNavFrame; 1647 boolean transientNavBarShowing = mNavigationBarController.isTransientShowing(); 1648 // Force the navigation bar to its appropriate place and size. We need to do this directly, 1649 // instead of relying on it to bubble up from the nav bar, because this needs to change 1650 // atomically with screen rotations. 1651 final int rotation = displayFrames.mRotation; 1652 final int displayHeight = displayFrames.mDisplayHeight; 1653 final int displayWidth = displayFrames.mDisplayWidth; 1654 final Rect dockFrame = displayFrames.mDock; 1655 mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation); 1656 1657 final Rect cutoutSafeUnrestricted = sTmpRect; 1658 cutoutSafeUnrestricted.set(displayFrames.mUnrestricted); 1659 cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe); 1660 1661 if (mNavigationBarPosition == NAV_BAR_BOTTOM) { 1662 // It's a system nav bar or a portrait screen; nav bar goes on bottom. 1663 final int top = cutoutSafeUnrestricted.bottom 1664 - getNavigationBarHeight(rotation, uiMode); 1665 final int topNavBar = cutoutSafeUnrestricted.bottom 1666 - getNavigationBarFrameHeight(rotation, uiMode); 1667 navigationFrame.set(0, topNavBar, displayWidth, displayFrames.mUnrestricted.bottom); 1668 displayFrames.mStable.bottom = displayFrames.mStableFullscreen.bottom = top; 1669 if (transientNavBarShowing) { 1670 mNavigationBarController.setBarShowingLw(true); 1671 } else if (navVisible) { 1672 mNavigationBarController.setBarShowingLw(true); 1673 dockFrame.bottom = displayFrames.mRestricted.bottom = 1674 displayFrames.mRestrictedOverscan.bottom = top; 1675 } else { 1676 // We currently want to hide the navigation UI - unless we expanded the status bar. 1677 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation); 1678 } 1679 if (navVisible && !navTranslucent && !navAllowedHidden 1680 && !mNavigationBar.isAnimatingLw() 1681 && !mNavigationBarController.wasRecentlyTranslucent()) { 1682 // If the opaque nav bar is currently requested to be visible and not in the process 1683 // of animating on or off, then we can tell the app that it is covered by it. 1684 displayFrames.mSystem.bottom = top; 1685 } 1686 } else if (mNavigationBarPosition == NAV_BAR_RIGHT) { 1687 // Landscape screen; nav bar goes to the right. 1688 final int left = cutoutSafeUnrestricted.right 1689 - getNavigationBarWidth(rotation, uiMode); 1690 navigationFrame.set(left, 0, displayFrames.mUnrestricted.right, displayHeight); 1691 displayFrames.mStable.right = displayFrames.mStableFullscreen.right = left; 1692 if (transientNavBarShowing) { 1693 mNavigationBarController.setBarShowingLw(true); 1694 } else if (navVisible) { 1695 mNavigationBarController.setBarShowingLw(true); 1696 dockFrame.right = displayFrames.mRestricted.right = 1697 displayFrames.mRestrictedOverscan.right = left; 1698 } else { 1699 // We currently want to hide the navigation UI - unless we expanded the status bar. 1700 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation); 1701 } 1702 if (navVisible && !navTranslucent && !navAllowedHidden 1703 && !mNavigationBar.isAnimatingLw() 1704 && !mNavigationBarController.wasRecentlyTranslucent()) { 1705 // If the nav bar is currently requested to be visible, and not in the process of 1706 // animating on or off, then we can tell the app that it is covered by it. 1707 displayFrames.mSystem.right = left; 1708 } 1709 } else if (mNavigationBarPosition == NAV_BAR_LEFT) { 1710 // Seascape screen; nav bar goes to the left. 1711 final int right = cutoutSafeUnrestricted.left 1712 + getNavigationBarWidth(rotation, uiMode); 1713 navigationFrame.set(displayFrames.mUnrestricted.left, 0, right, displayHeight); 1714 displayFrames.mStable.left = displayFrames.mStableFullscreen.left = right; 1715 if (transientNavBarShowing) { 1716 mNavigationBarController.setBarShowingLw(true); 1717 } else if (navVisible) { 1718 mNavigationBarController.setBarShowingLw(true); 1719 dockFrame.left = displayFrames.mRestricted.left = 1720 displayFrames.mRestrictedOverscan.left = right; 1721 } else { 1722 // We currently want to hide the navigation UI - unless we expanded the status bar. 1723 mNavigationBarController.setBarShowingLw(statusBarForcesShowingNavigation); 1724 } 1725 if (navVisible && !navTranslucent && !navAllowedHidden 1726 && !mNavigationBar.isAnimatingLw() 1727 && !mNavigationBarController.wasRecentlyTranslucent()) { 1728 // If the nav bar is currently requested to be visible, and not in the process of 1729 // animating on or off, then we can tell the app that it is covered by it. 1730 displayFrames.mSystem.left = right; 1731 } 1732 } 1733 1734 // Make sure the content and current rectangles are updated to account for the restrictions 1735 // from the navigation bar. 1736 displayFrames.mCurrent.set(dockFrame); 1737 displayFrames.mVoiceContent.set(dockFrame); 1738 displayFrames.mContent.set(dockFrame); 1739 // And compute the final frame. 1740 sTmpRect.setEmpty(); 1741 mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */, 1742 navigationFrame /* displayFrame */, navigationFrame /* overscanFrame */, 1743 displayFrames.mDisplayCutoutSafe /* contentFrame */, 1744 navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */, 1745 navigationFrame /* stableFrame */, 1746 displayFrames.mDisplayCutoutSafe /* outsetFrame */); 1747 mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout); 1748 mNavigationBar.computeFrameLw(); 1749 mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw()); 1750 1751 if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame); 1752 return mNavigationBarController.checkHiddenLw(); 1753 } 1754 setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf, DisplayFrames displayFrames)1755 private void setAttachedWindowFrames(WindowState win, int fl, int adjust, WindowState attached, 1756 boolean insetDecors, Rect pf, Rect df, Rect of, Rect cf, Rect vf, 1757 DisplayFrames displayFrames) { 1758 if (!win.isInputMethodTarget() && attached.isInputMethodTarget()) { 1759 // Here's a special case: if the child window is not the 'dock window' 1760 // or input method target, and the window it is attached to is below 1761 // the dock window, then the frames we computed for the window it is 1762 // attached to can not be used because the dock is effectively part 1763 // of the underlying window and the attached window is floating on top 1764 // of the whole thing. So, we ignore the attached window and explicitly 1765 // compute the frames that would be appropriate without the dock. 1766 vf.set(displayFrames.mDock); 1767 cf.set(displayFrames.mDock); 1768 of.set(displayFrames.mDock); 1769 df.set(displayFrames.mDock); 1770 } else { 1771 1772 // In case we forced the window to draw behind the navigation bar, restrict df/of to 1773 // DF.RestrictedOverscan to simulate old compat behavior. 1774 Rect parentDisplayFrame = attached.getDisplayFrameLw(); 1775 Rect parentOverscan = attached.getOverscanFrameLw(); 1776 final WindowManager.LayoutParams attachedAttrs = attached.mAttrs; 1777 if ((attachedAttrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0 1778 && (attachedAttrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0 1779 && (attachedAttrs.systemUiVisibility 1780 & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) == 0) { 1781 parentOverscan = new Rect(parentOverscan); 1782 parentOverscan.intersect(displayFrames.mRestrictedOverscan); 1783 parentDisplayFrame = new Rect(parentDisplayFrame); 1784 parentDisplayFrame.intersect(displayFrames.mRestrictedOverscan); 1785 } 1786 1787 // The effective display frame of the attached window depends on whether it is taking 1788 // care of insetting its content. If not, we need to use the parent's content frame so 1789 // that the entire window is positioned within that content. Otherwise we can use the 1790 // overscan frame and let the attached window take care of positioning its content 1791 // appropriately. 1792 if (adjust != SOFT_INPUT_ADJUST_RESIZE) { 1793 // Set the content frame of the attached window to the parent's decor frame 1794 // (same as content frame when IME isn't present) if specifically requested by 1795 // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag. 1796 // Otherwise, use the overscan frame. 1797 cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0 1798 ? attached.getContentFrameLw() : parentOverscan); 1799 } else { 1800 // If the window is resizing, then we want to base the content frame on our attached 1801 // content frame to resize...however, things can be tricky if the attached window is 1802 // NOT in resize mode, in which case its content frame will be larger. 1803 // Ungh. So to deal with that, make sure the content frame we end up using is not 1804 // covering the IM dock. 1805 cf.set(attached.getContentFrameLw()); 1806 if (attached.isVoiceInteraction()) { 1807 cf.intersectUnchecked(displayFrames.mVoiceContent); 1808 } else if (win.isInputMethodTarget() || attached.isInputMethodTarget()) { 1809 cf.intersectUnchecked(displayFrames.mContent); 1810 } 1811 } 1812 df.set(insetDecors ? parentDisplayFrame : cf); 1813 of.set(insetDecors ? parentOverscan : cf); 1814 vf.set(attached.getVisibleFrameLw()); 1815 } 1816 // The LAYOUT_IN_SCREEN flag is used to determine whether the attached window should be 1817 // positioned relative to its parent or the entire screen. 1818 pf.set((fl & FLAG_LAYOUT_IN_SCREEN) == 0 ? attached.getFrameLw() : df); 1819 } 1820 applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames)1821 private void applyStableConstraints(int sysui, int fl, Rect r, DisplayFrames displayFrames) { 1822 if ((sysui & View.SYSTEM_UI_FLAG_LAYOUT_STABLE) == 0) { 1823 return; 1824 } 1825 // If app is requesting a stable layout, don't let the content insets go below the stable 1826 // values. 1827 if ((fl & FLAG_FULLSCREEN) != 0) { 1828 r.intersectUnchecked(displayFrames.mStableFullscreen); 1829 } else { 1830 r.intersectUnchecked(displayFrames.mStable); 1831 } 1832 } 1833 canReceiveInput(WindowState win)1834 private boolean canReceiveInput(WindowState win) { 1835 boolean notFocusable = 1836 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) != 0; 1837 boolean altFocusableIm = 1838 (win.getAttrs().flags & WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) != 0; 1839 boolean notFocusableForIm = notFocusable ^ altFocusableIm; 1840 return !notFocusableForIm; 1841 } 1842 1843 /** 1844 * Called for each window attached to the window manager as layout is proceeding. The 1845 * implementation of this function must take care of setting the window's frame, either here or 1846 * in finishLayout(). 1847 * 1848 * @param win The window being positioned. 1849 * @param attached For sub-windows, the window it is attached to; this 1850 * window will already have had layoutWindow() called on it 1851 * so you can use its Rect. Otherwise null. 1852 * @param displayFrames The display frames. 1853 */ layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames)1854 public void layoutWindowLw(WindowState win, WindowState attached, DisplayFrames displayFrames) { 1855 // We've already done the navigation bar, status bar, and all screen decor windows. If the 1856 // status bar can receive input, we need to layout it again to accommodate for the IME 1857 // window. 1858 if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar 1859 || mScreenDecorWindows.contains(win)) { 1860 return; 1861 } 1862 final WindowManager.LayoutParams attrs = win.getAttrs(); 1863 final boolean isDefaultDisplay = win.isDefaultDisplay(); 1864 1865 final int type = attrs.type; 1866 final int fl = PolicyControl.getWindowFlags(win, attrs); 1867 final int pfl = attrs.privateFlags; 1868 final int sim = attrs.softInputMode; 1869 final int requestedSysUiFl = PolicyControl.getSystemUiVisibility(null, attrs); 1870 final int sysUiFl = requestedSysUiFl | getImpliedSysUiFlagsForLayout(attrs); 1871 1872 final WindowFrames windowFrames = win.getWindowFrames(); 1873 1874 windowFrames.setHasOutsets(false); 1875 sTmpLastParentFrame.set(windowFrames.mParentFrame); 1876 final Rect pf = windowFrames.mParentFrame; 1877 final Rect df = windowFrames.mDisplayFrame; 1878 final Rect of = windowFrames.mOverscanFrame; 1879 final Rect cf = windowFrames.mContentFrame; 1880 final Rect vf = windowFrames.mVisibleFrame; 1881 final Rect dcf = windowFrames.mDecorFrame; 1882 final Rect sf = windowFrames.mStableFrame; 1883 dcf.setEmpty(); 1884 windowFrames.setParentFrameWasClippedByDisplayCutout(false); 1885 windowFrames.setDisplayCutout(displayFrames.mDisplayCutout); 1886 1887 final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null 1888 && mNavigationBar.isVisibleLw(); 1889 1890 final int adjust = sim & SOFT_INPUT_MASK_ADJUST; 1891 1892 final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0 1893 || (requestedSysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0; 1894 1895 final boolean layoutInScreen = (fl & FLAG_LAYOUT_IN_SCREEN) == FLAG_LAYOUT_IN_SCREEN; 1896 final boolean layoutInsetDecor = (fl & FLAG_LAYOUT_INSET_DECOR) == FLAG_LAYOUT_INSET_DECOR; 1897 1898 sf.set(displayFrames.mStable); 1899 1900 if (type == TYPE_INPUT_METHOD) { 1901 vf.set(displayFrames.mDock); 1902 cf.set(displayFrames.mDock); 1903 of.set(displayFrames.mDock); 1904 df.set(displayFrames.mDock); 1905 windowFrames.mParentFrame.set(displayFrames.mDock); 1906 // IM dock windows layout below the nav bar... 1907 pf.bottom = df.bottom = of.bottom = displayFrames.mUnrestricted.bottom; 1908 // ...with content insets above the nav bar 1909 cf.bottom = vf.bottom = displayFrames.mStable.bottom; 1910 if (mStatusBar != null && mFocusedWindow == mStatusBar && canReceiveInput(mStatusBar)) { 1911 // The status bar forces the navigation bar while it's visible. Make sure the IME 1912 // avoids the navigation bar in that case. 1913 if (mNavigationBarPosition == NAV_BAR_RIGHT) { 1914 pf.right = df.right = of.right = cf.right = vf.right = 1915 displayFrames.mStable.right; 1916 } else if (mNavigationBarPosition == NAV_BAR_LEFT) { 1917 pf.left = df.left = of.left = cf.left = vf.left = displayFrames.mStable.left; 1918 } 1919 } 1920 1921 // In case the navigation bar is on the bottom, we use the frame height instead of the 1922 // regular height for the insets we send to the IME as we need some space to show 1923 // additional buttons in SystemUI when the IME is up. 1924 if (mNavigationBarPosition == NAV_BAR_BOTTOM) { 1925 final int rotation = displayFrames.mRotation; 1926 final int uimode = mService.mPolicy.getUiMode(); 1927 final int navHeightOffset = getNavigationBarFrameHeight(rotation, uimode) 1928 - getNavigationBarHeight(rotation, uimode); 1929 if (navHeightOffset > 0) { 1930 cf.bottom -= navHeightOffset; 1931 sf.bottom -= navHeightOffset; 1932 vf.bottom -= navHeightOffset; 1933 dcf.bottom -= navHeightOffset; 1934 } 1935 } 1936 1937 // IM dock windows always go to the bottom of the screen. 1938 attrs.gravity = Gravity.BOTTOM; 1939 } else if (type == TYPE_VOICE_INTERACTION) { 1940 of.set(displayFrames.mUnrestricted); 1941 df.set(displayFrames.mUnrestricted); 1942 pf.set(displayFrames.mUnrestricted); 1943 if (adjust != SOFT_INPUT_ADJUST_RESIZE) { 1944 cf.set(displayFrames.mDock); 1945 } else { 1946 cf.set(displayFrames.mContent); 1947 } 1948 if (adjust != SOFT_INPUT_ADJUST_NOTHING) { 1949 vf.set(displayFrames.mCurrent); 1950 } else { 1951 vf.set(cf); 1952 } 1953 } else if (type == TYPE_WALLPAPER) { 1954 layoutWallpaper(displayFrames, pf, df, of, cf); 1955 } else if (win == mStatusBar) { 1956 of.set(displayFrames.mUnrestricted); 1957 df.set(displayFrames.mUnrestricted); 1958 pf.set(displayFrames.mUnrestricted); 1959 cf.set(displayFrames.mStable); 1960 vf.set(displayFrames.mStable); 1961 1962 if (adjust == SOFT_INPUT_ADJUST_RESIZE) { 1963 cf.bottom = displayFrames.mContent.bottom; 1964 } else { 1965 cf.bottom = displayFrames.mDock.bottom; 1966 vf.bottom = displayFrames.mContent.bottom; 1967 } 1968 } else { 1969 dcf.set(displayFrames.mSystem); 1970 final boolean inheritTranslucentDecor = 1971 (attrs.privateFlags & PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR) != 0; 1972 final boolean isAppWindow = 1973 type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW; 1974 final boolean topAtRest = 1975 win == mTopFullscreenOpaqueWindowState && !win.isAnimatingLw(); 1976 if (isAppWindow && !inheritTranslucentDecor && !topAtRest) { 1977 if ((sysUiFl & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0 1978 && (fl & FLAG_FULLSCREEN) == 0 1979 && (fl & FLAG_TRANSLUCENT_STATUS) == 0 1980 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0 1981 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) { 1982 // Ensure policy decor includes status bar 1983 dcf.top = displayFrames.mStable.top; 1984 } 1985 if ((fl & FLAG_TRANSLUCENT_NAVIGATION) == 0 1986 && (sysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0 1987 && (fl & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0 1988 && (pfl & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) == 0) { 1989 // Ensure policy decor includes navigation bar 1990 dcf.bottom = displayFrames.mStable.bottom; 1991 dcf.right = displayFrames.mStable.right; 1992 } 1993 } 1994 1995 if (layoutInScreen && layoutInsetDecor) { 1996 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() 1997 + "): IN_SCREEN, INSET_DECOR"); 1998 // This is the case for a normal activity window: we want it to cover all of the 1999 // screen space, and it can take care of moving its contents to account for screen 2000 // decorations that intrude into that space. 2001 if (attached != null) { 2002 // If this window is attached to another, our display 2003 // frame is the same as the one we are attached to. 2004 setAttachedWindowFrames(win, fl, adjust, attached, true, pf, df, of, cf, vf, 2005 displayFrames); 2006 } else { 2007 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) { 2008 // Status bar panels are the only windows who can go on top of the status 2009 // bar. They are protected by the STATUS_BAR_SERVICE permission, so they 2010 // have the same privileges as the status bar itself. 2011 // 2012 // However, they should still dodge the navigation bar if it exists. 2013 2014 pf.left = df.left = of.left = hasNavBar 2015 ? displayFrames.mDock.left : displayFrames.mUnrestricted.left; 2016 pf.top = df.top = of.top = displayFrames.mUnrestricted.top; 2017 pf.right = df.right = of.right = hasNavBar 2018 ? displayFrames.mRestricted.right 2019 : displayFrames.mUnrestricted.right; 2020 pf.bottom = df.bottom = of.bottom = hasNavBar 2021 ? displayFrames.mRestricted.bottom 2022 : displayFrames.mUnrestricted.bottom; 2023 2024 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out status bar window: " + pf); 2025 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0 2026 && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) { 2027 // Asking to layout into the overscan region, so give it that pure 2028 // unrestricted area. 2029 of.set(displayFrames.mOverscan); 2030 df.set(displayFrames.mOverscan); 2031 pf.set(displayFrames.mOverscan); 2032 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 2033 && (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW 2034 || type == TYPE_VOLUME_OVERLAY 2035 || type == TYPE_KEYGUARD_DIALOG)) { 2036 // Asking for layout as if the nav bar is hidden, lets the application 2037 // extend into the unrestricted overscan screen area. We only do this for 2038 // application windows and certain system windows to ensure no window that 2039 // can be above the nav bar can do this. 2040 df.set(displayFrames.mOverscan); 2041 pf.set(displayFrames.mOverscan); 2042 // We need to tell the app about where the frame inside the overscan is, so 2043 // it can inset its content by that amount -- it didn't ask to actually 2044 // extend itself into the overscan region. 2045 of.set(displayFrames.mUnrestricted); 2046 } else { 2047 df.set(displayFrames.mRestrictedOverscan); 2048 pf.set(displayFrames.mRestrictedOverscan); 2049 // We need to tell the app about where the frame inside the overscan 2050 // is, so it can inset its content by that amount -- it didn't ask 2051 // to actually extend itself into the overscan region. 2052 of.set(displayFrames.mUnrestricted); 2053 } 2054 2055 if ((fl & FLAG_FULLSCREEN) == 0) { 2056 if (win.isVoiceInteraction()) { 2057 cf.set(displayFrames.mVoiceContent); 2058 } else { 2059 // IME Insets are handled on the client for ADJUST_RESIZE in the new 2060 // insets world 2061 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE 2062 || adjust != SOFT_INPUT_ADJUST_RESIZE) { 2063 cf.set(displayFrames.mDock); 2064 } else { 2065 cf.set(displayFrames.mContent); 2066 } 2067 } 2068 } else { 2069 // Full screen windows are always given a layout that is as if the status 2070 // bar and other transient decors are gone. This is to avoid bad states when 2071 // moving from a window that is not hiding the status bar to one that is. 2072 cf.set(displayFrames.mRestricted); 2073 } 2074 applyStableConstraints(sysUiFl, fl, cf, displayFrames); 2075 if (adjust != SOFT_INPUT_ADJUST_NOTHING) { 2076 vf.set(displayFrames.mCurrent); 2077 } else { 2078 vf.set(cf); 2079 } 2080 } 2081 } else if (layoutInScreen || (sysUiFl 2082 & (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 2083 | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)) != 0) { 2084 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() 2085 + "): IN_SCREEN"); 2086 // A window that has requested to fill the entire screen just 2087 // gets everything, period. 2088 if (type == TYPE_STATUS_BAR_PANEL || type == TYPE_STATUS_BAR_SUB_PANEL) { 2089 cf.set(displayFrames.mUnrestricted); 2090 of.set(displayFrames.mUnrestricted); 2091 df.set(displayFrames.mUnrestricted); 2092 pf.set(displayFrames.mUnrestricted); 2093 if (hasNavBar) { 2094 pf.left = df.left = of.left = cf.left = displayFrames.mDock.left; 2095 pf.right = df.right = of.right = cf.right = displayFrames.mRestricted.right; 2096 pf.bottom = df.bottom = of.bottom = cf.bottom = 2097 displayFrames.mRestricted.bottom; 2098 } 2099 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out IN_SCREEN status bar window: " + pf); 2100 } else if (type == TYPE_NAVIGATION_BAR || type == TYPE_NAVIGATION_BAR_PANEL) { 2101 // The navigation bar has Real Ultimate Power. 2102 of.set(displayFrames.mUnrestricted); 2103 df.set(displayFrames.mUnrestricted); 2104 pf.set(displayFrames.mUnrestricted); 2105 if (DEBUG_LAYOUT) Slog.v(TAG, "Laying out navigation bar window: " + pf); 2106 } else if ((type == TYPE_SECURE_SYSTEM_OVERLAY || type == TYPE_SCREENSHOT) 2107 && ((fl & FLAG_FULLSCREEN) != 0)) { 2108 // Fullscreen secure system overlays get what they ask for. Screenshot region 2109 // selection overlay should also expand to full screen. 2110 cf.set(displayFrames.mOverscan); 2111 of.set(displayFrames.mOverscan); 2112 df.set(displayFrames.mOverscan); 2113 pf.set(displayFrames.mOverscan); 2114 } else if (type == TYPE_BOOT_PROGRESS) { 2115 // Boot progress screen always covers entire display. 2116 cf.set(displayFrames.mOverscan); 2117 of.set(displayFrames.mOverscan); 2118 df.set(displayFrames.mOverscan); 2119 pf.set(displayFrames.mOverscan); 2120 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0 2121 && type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW) { 2122 // Asking to layout into the overscan region, so give it that pure unrestricted 2123 // area. 2124 cf.set(displayFrames.mOverscan); 2125 of.set(displayFrames.mOverscan); 2126 df.set(displayFrames.mOverscan); 2127 pf.set(displayFrames.mOverscan); 2128 } else if ((sysUiFl & SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0 2129 && (type == TYPE_STATUS_BAR 2130 || type == TYPE_TOAST 2131 || type == TYPE_DOCK_DIVIDER 2132 || type == TYPE_VOICE_INTERACTION_STARTING 2133 || (type >= FIRST_APPLICATION_WINDOW && type <= LAST_SUB_WINDOW))) { 2134 // Asking for layout as if the nav bar is hidden, lets the 2135 // application extend into the unrestricted screen area. We 2136 // only do this for application windows (or toasts) to ensure no window that 2137 // can be above the nav bar can do this. 2138 // XXX This assumes that an app asking for this will also 2139 // ask for layout in only content. We can't currently figure out 2140 // what the screen would be if only laying out to hide the nav bar. 2141 cf.set(displayFrames.mUnrestricted); 2142 of.set(displayFrames.mUnrestricted); 2143 df.set(displayFrames.mUnrestricted); 2144 pf.set(displayFrames.mUnrestricted); 2145 } else if ((sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) != 0) { 2146 of.set(displayFrames.mRestricted); 2147 df.set(displayFrames.mRestricted); 2148 pf.set(displayFrames.mRestricted); 2149 2150 // IME Insets are handled on the client for ADJUST_RESIZE in the new insets 2151 // world 2152 if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE 2153 || adjust != SOFT_INPUT_ADJUST_RESIZE) { 2154 cf.set(displayFrames.mDock); 2155 } else { 2156 cf.set(displayFrames.mContent); 2157 } 2158 } else { 2159 cf.set(displayFrames.mRestricted); 2160 of.set(displayFrames.mRestricted); 2161 df.set(displayFrames.mRestricted); 2162 pf.set(displayFrames.mRestricted); 2163 } 2164 2165 applyStableConstraints(sysUiFl, fl, cf, displayFrames); 2166 2167 if (adjust != SOFT_INPUT_ADJUST_NOTHING) { 2168 vf.set(displayFrames.mCurrent); 2169 } else { 2170 vf.set(cf); 2171 } 2172 } else if (attached != null) { 2173 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() 2174 + "): attached to " + attached); 2175 // A child window should be placed inside of the same visible 2176 // frame that its parent had. 2177 setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, of, cf, vf, 2178 displayFrames); 2179 } else { 2180 if (DEBUG_LAYOUT) Slog.v(TAG, "layoutWindowLw(" + attrs.getTitle() 2181 + "): normal window"); 2182 // Otherwise, a normal window must be placed inside the content 2183 // of all screen decorations. 2184 if (type == TYPE_STATUS_BAR_PANEL) { 2185 // Status bar panels can go on 2186 // top of the status bar. They are protected by the STATUS_BAR_SERVICE 2187 // permission, so they have the same privileges as the status bar itself. 2188 cf.set(displayFrames.mRestricted); 2189 of.set(displayFrames.mRestricted); 2190 df.set(displayFrames.mRestricted); 2191 pf.set(displayFrames.mRestricted); 2192 } else if (type == TYPE_TOAST || type == TYPE_SYSTEM_ALERT) { 2193 // These dialogs are stable to interim decor changes. 2194 cf.set(displayFrames.mStable); 2195 of.set(displayFrames.mStable); 2196 df.set(displayFrames.mStable); 2197 pf.set(displayFrames.mStable); 2198 } else { 2199 pf.set(displayFrames.mContent); 2200 if (win.isVoiceInteraction()) { 2201 cf.set(displayFrames.mVoiceContent); 2202 of.set(displayFrames.mVoiceContent); 2203 df.set(displayFrames.mVoiceContent); 2204 } else if (adjust != SOFT_INPUT_ADJUST_RESIZE) { 2205 cf.set(displayFrames.mDock); 2206 of.set(displayFrames.mDock); 2207 df.set(displayFrames.mDock); 2208 } else { 2209 cf.set(displayFrames.mContent); 2210 of.set(displayFrames.mContent); 2211 df.set(displayFrames.mContent); 2212 } 2213 if (adjust != SOFT_INPUT_ADJUST_NOTHING) { 2214 vf.set(displayFrames.mCurrent); 2215 } else { 2216 vf.set(cf); 2217 } 2218 } 2219 } 2220 } 2221 2222 final int cutoutMode = attrs.layoutInDisplayCutoutMode; 2223 final boolean attachedInParent = attached != null && !layoutInScreen; 2224 final boolean requestedHideNavigation = 2225 (requestedSysUiFl & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0; 2226 2227 // TYPE_BASE_APPLICATION windows are never considered floating here because they don't get 2228 // cropped / shifted to the displayFrame in WindowState. 2229 final boolean floatingInScreenWindow = !attrs.isFullscreen() && layoutInScreen 2230 && type != TYPE_BASE_APPLICATION; 2231 2232 // Ensure that windows with a DEFAULT or NEVER display cutout mode are laid out in 2233 // the cutout safe zone. 2234 if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES) { 2235 final Rect displayCutoutSafeExceptMaybeBars = sTmpDisplayCutoutSafeExceptMaybeBarsRect; 2236 displayCutoutSafeExceptMaybeBars.set(displayFrames.mDisplayCutoutSafe); 2237 if (layoutInScreen && layoutInsetDecor && !requestedFullscreen 2238 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) { 2239 // At the top we have the status bar, so apps that are 2240 // LAYOUT_IN_SCREEN | LAYOUT_INSET_DECOR but not FULLSCREEN 2241 // already expect that there's an inset there and we don't need to exclude 2242 // the window from that area. 2243 displayCutoutSafeExceptMaybeBars.top = Integer.MIN_VALUE; 2244 } 2245 if (layoutInScreen && layoutInsetDecor && !requestedHideNavigation 2246 && cutoutMode == LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT) { 2247 // Same for the navigation bar. 2248 switch (mNavigationBarPosition) { 2249 case NAV_BAR_BOTTOM: 2250 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE; 2251 break; 2252 case NAV_BAR_RIGHT: 2253 displayCutoutSafeExceptMaybeBars.right = Integer.MAX_VALUE; 2254 break; 2255 case NAV_BAR_LEFT: 2256 displayCutoutSafeExceptMaybeBars.left = Integer.MIN_VALUE; 2257 break; 2258 } 2259 } 2260 if (type == TYPE_INPUT_METHOD && mNavigationBarPosition == NAV_BAR_BOTTOM) { 2261 // The IME can always extend under the bottom cutout if the navbar is there. 2262 displayCutoutSafeExceptMaybeBars.bottom = Integer.MAX_VALUE; 2263 } 2264 // Windows that are attached to a parent and laid out in said parent already avoid 2265 // the cutout according to that parent and don't need to be further constrained. 2266 // Floating IN_SCREEN windows get what they ask for and lay out in the full screen. 2267 // They will later be cropped or shifted using the displayFrame in WindowState, 2268 // which prevents overlap with the DisplayCutout. 2269 if (!attachedInParent && !floatingInScreenWindow) { 2270 sTmpRect.set(pf); 2271 pf.intersectUnchecked(displayCutoutSafeExceptMaybeBars); 2272 windowFrames.setParentFrameWasClippedByDisplayCutout(!sTmpRect.equals(pf)); 2273 } 2274 // Make sure that NO_LIMITS windows clipped to the display don't extend under the 2275 // cutout. 2276 df.intersectUnchecked(displayCutoutSafeExceptMaybeBars); 2277 } 2278 2279 // Content should never appear in the cutout. 2280 cf.intersectUnchecked(displayFrames.mDisplayCutoutSafe); 2281 2282 // TYPE_SYSTEM_ERROR is above the NavigationBar so it can't be allowed to extend over it. 2283 // Also, we don't allow windows in multi-window mode to extend out of the screen. 2284 if ((fl & FLAG_LAYOUT_NO_LIMITS) != 0 && type != TYPE_SYSTEM_ERROR 2285 && !win.inMultiWindowMode()) { 2286 df.left = df.top = -10000; 2287 df.right = df.bottom = 10000; 2288 if (type != TYPE_WALLPAPER) { 2289 of.left = of.top = cf.left = cf.top = vf.left = vf.top = -10000; 2290 of.right = of.bottom = cf.right = cf.bottom = vf.right = vf.bottom = 10000; 2291 } 2292 } 2293 2294 // If the device has a chin (e.g. some watches), a dead area at the bottom of the screen we 2295 // need to provide information to the clients that want to pretend that you can draw there. 2296 // We only want to apply outsets to certain types of windows. For example, we never want to 2297 // apply the outsets to floating dialogs, because they wouldn't make sense there. 2298 final boolean useOutsets = shouldUseOutsets(attrs, fl); 2299 if (isDefaultDisplay && useOutsets) { 2300 final Rect osf = windowFrames.mOutsetFrame; 2301 osf.set(cf.left, cf.top, cf.right, cf.bottom); 2302 windowFrames.setHasOutsets(true); 2303 int outset = mWindowOutsetBottom; 2304 if (outset > 0) { 2305 int rotation = displayFrames.mRotation; 2306 if (rotation == Surface.ROTATION_0) { 2307 osf.bottom += outset; 2308 } else if (rotation == Surface.ROTATION_90) { 2309 osf.right += outset; 2310 } else if (rotation == Surface.ROTATION_180) { 2311 osf.top -= outset; 2312 } else if (rotation == Surface.ROTATION_270) { 2313 osf.left -= outset; 2314 } 2315 if (DEBUG_LAYOUT) Slog.v(TAG, "applying bottom outset of " + outset 2316 + " with rotation " + rotation + ", result: " + osf); 2317 } 2318 } 2319 2320 if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle() 2321 + ": sim=#" + Integer.toHexString(sim) 2322 + " attach=" + attached + " type=" + type 2323 + String.format(" flags=0x%08x", fl) 2324 + " pf=" + pf.toShortString() + " df=" + df.toShortString() 2325 + " of=" + of.toShortString() 2326 + " cf=" + cf.toShortString() + " vf=" + vf.toShortString() 2327 + " dcf=" + dcf.toShortString() 2328 + " sf=" + sf.toShortString() 2329 + " osf=" + windowFrames.mOutsetFrame.toShortString() + " " + win); 2330 2331 if (!sTmpLastParentFrame.equals(pf)) { 2332 windowFrames.setContentChanged(true); 2333 } 2334 2335 win.computeFrameLw(); 2336 // Dock windows carve out the bottom of the screen, so normal windows 2337 // can't appear underneath them. 2338 if (type == TYPE_INPUT_METHOD && win.isVisibleLw() 2339 && !win.getGivenInsetsPendingLw()) { 2340 offsetInputMethodWindowLw(win, displayFrames); 2341 } 2342 if (type == TYPE_VOICE_INTERACTION && win.isVisibleLw() 2343 && !win.getGivenInsetsPendingLw()) { 2344 offsetVoiceInputWindowLw(win, displayFrames); 2345 } 2346 } 2347 layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf)2348 private void layoutWallpaper(DisplayFrames displayFrames, Rect pf, Rect df, Rect of, Rect cf) { 2349 // The wallpaper has Real Ultimate Power, but we want to tell it about the overscan area. 2350 df.set(displayFrames.mOverscan); 2351 pf.set(displayFrames.mOverscan); 2352 cf.set(displayFrames.mUnrestricted); 2353 of.set(displayFrames.mUnrestricted); 2354 } 2355 offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames)2356 private void offsetInputMethodWindowLw(WindowState win, DisplayFrames displayFrames) { 2357 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top); 2358 top += win.getGivenContentInsetsLw().top; 2359 displayFrames.mContent.bottom = Math.min(displayFrames.mContent.bottom, top); 2360 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top); 2361 top = win.getVisibleFrameLw().top; 2362 top += win.getGivenVisibleInsetsLw().top; 2363 displayFrames.mCurrent.bottom = Math.min(displayFrames.mCurrent.bottom, top); 2364 if (DEBUG_LAYOUT) Slog.v(TAG, "Input method: mDockBottom=" 2365 + displayFrames.mDock.bottom + " mContentBottom=" 2366 + displayFrames.mContent.bottom + " mCurBottom=" + displayFrames.mCurrent.bottom); 2367 } 2368 offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames)2369 private void offsetVoiceInputWindowLw(WindowState win, DisplayFrames displayFrames) { 2370 int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top); 2371 top += win.getGivenContentInsetsLw().top; 2372 displayFrames.mVoiceContent.bottom = Math.min(displayFrames.mVoiceContent.bottom, top); 2373 } 2374 2375 /** 2376 * Called following layout of all windows before each window has policy applied. 2377 */ beginPostLayoutPolicyLw()2378 public void beginPostLayoutPolicyLw() { 2379 mTopFullscreenOpaqueWindowState = null; 2380 mTopFullscreenOpaqueOrDimmingWindowState = null; 2381 mTopDockedOpaqueWindowState = null; 2382 mTopDockedOpaqueOrDimmingWindowState = null; 2383 mForceStatusBar = false; 2384 mForceStatusBarFromKeyguard = false; 2385 mForceStatusBarTransparent = false; 2386 mForcingShowNavBar = false; 2387 mForcingShowNavBarLayer = -1; 2388 2389 mAllowLockscreenWhenOn = false; 2390 mShowingDream = false; 2391 mWindowSleepTokenNeeded = false; 2392 } 2393 2394 /** 2395 * Called following layout of all window to apply policy to each window. 2396 * 2397 * @param win The window being positioned. 2398 * @param attrs The LayoutParams of the window. 2399 * @param attached For sub-windows, the window it is attached to. Otherwise null. 2400 */ applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs, WindowState attached, WindowState imeTarget)2401 public void applyPostLayoutPolicyLw(WindowState win, WindowManager.LayoutParams attrs, 2402 WindowState attached, WindowState imeTarget) { 2403 final boolean affectsSystemUi = win.canAffectSystemUiFlags(); 2404 if (DEBUG_LAYOUT) Slog.i(TAG, "Win " + win + ": affectsSystemUi=" + affectsSystemUi); 2405 mService.mPolicy.applyKeyguardPolicyLw(win, imeTarget); 2406 final int fl = PolicyControl.getWindowFlags(win, attrs); 2407 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi 2408 && attrs.type == TYPE_INPUT_METHOD) { 2409 mForcingShowNavBar = true; 2410 mForcingShowNavBarLayer = win.getSurfaceLayer(); 2411 } 2412 if (attrs.type == TYPE_STATUS_BAR) { 2413 if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) { 2414 mForceStatusBarFromKeyguard = true; 2415 } 2416 if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) { 2417 mForceStatusBarTransparent = true; 2418 } 2419 } 2420 2421 boolean appWindow = attrs.type >= FIRST_APPLICATION_WINDOW 2422 && attrs.type < FIRST_SYSTEM_WINDOW; 2423 final int windowingMode = win.getWindowingMode(); 2424 final boolean inFullScreenOrSplitScreenSecondaryWindowingMode = 2425 windowingMode == WINDOWING_MODE_FULLSCREEN 2426 || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY; 2427 if (mTopFullscreenOpaqueWindowState == null && affectsSystemUi) { 2428 if ((fl & FLAG_FORCE_NOT_FULLSCREEN) != 0) { 2429 mForceStatusBar = true; 2430 } 2431 if (attrs.type == TYPE_DREAM) { 2432 // If the lockscreen was showing when the dream started then wait 2433 // for the dream to draw before hiding the lockscreen. 2434 if (!mDreamingLockscreen 2435 || (win.isVisibleLw() && win.hasDrawnLw())) { 2436 mShowingDream = true; 2437 appWindow = true; 2438 } 2439 } 2440 2441 // For app windows that are not attached, we decide if all windows in the app they 2442 // represent should be hidden or if we should hide the lockscreen. For attached app 2443 // windows we defer the decision to the window it is attached to. 2444 if (appWindow && attached == null) { 2445 if (attrs.isFullscreen() && inFullScreenOrSplitScreenSecondaryWindowingMode) { 2446 if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win); 2447 mTopFullscreenOpaqueWindowState = win; 2448 if (mTopFullscreenOpaqueOrDimmingWindowState == null) { 2449 mTopFullscreenOpaqueOrDimmingWindowState = win; 2450 } 2451 if ((fl & FLAG_ALLOW_LOCK_WHILE_SCREEN_ON) != 0) { 2452 mAllowLockscreenWhenOn = true; 2453 } 2454 } 2455 } 2456 } 2457 2458 // Voice interaction overrides both top fullscreen and top docked. 2459 if (affectsSystemUi && attrs.type == TYPE_VOICE_INTERACTION) { 2460 if (mTopFullscreenOpaqueWindowState == null) { 2461 mTopFullscreenOpaqueWindowState = win; 2462 if (mTopFullscreenOpaqueOrDimmingWindowState == null) { 2463 mTopFullscreenOpaqueOrDimmingWindowState = win; 2464 } 2465 } 2466 if (mTopDockedOpaqueWindowState == null) { 2467 mTopDockedOpaqueWindowState = win; 2468 if (mTopDockedOpaqueOrDimmingWindowState == null) { 2469 mTopDockedOpaqueOrDimmingWindowState = win; 2470 } 2471 } 2472 } 2473 2474 // Keep track of the window if it's dimming but not necessarily fullscreen. 2475 if (mTopFullscreenOpaqueOrDimmingWindowState == null && affectsSystemUi 2476 && win.isDimming() && inFullScreenOrSplitScreenSecondaryWindowingMode) { 2477 mTopFullscreenOpaqueOrDimmingWindowState = win; 2478 } 2479 2480 // We need to keep track of the top "fullscreen" opaque window for the docked stack 2481 // separately, because both the "real fullscreen" opaque window and the one for the docked 2482 // stack can control View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR. 2483 if (mTopDockedOpaqueWindowState == null && affectsSystemUi && appWindow && attached == null 2484 && attrs.isFullscreen() && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { 2485 mTopDockedOpaqueWindowState = win; 2486 if (mTopDockedOpaqueOrDimmingWindowState == null) { 2487 mTopDockedOpaqueOrDimmingWindowState = win; 2488 } 2489 } 2490 2491 // Also keep track of any windows that are dimming but not necessarily fullscreen in the 2492 // docked stack. 2493 if (mTopDockedOpaqueOrDimmingWindowState == null && affectsSystemUi && win.isDimming() 2494 && windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) { 2495 mTopDockedOpaqueOrDimmingWindowState = win; 2496 } 2497 } 2498 2499 /** 2500 * Called following layout of all windows and after policy has been applied 2501 * to each window. If in this function you do 2502 * something that may have modified the animation state of another window, 2503 * be sure to return non-zero in order to perform another pass through layout. 2504 * 2505 * @return Return any bit set of 2506 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_LAYOUT}, 2507 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_CONFIG}, 2508 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_WALLPAPER}, or 2509 * {@link WindowManagerPolicy#FINISH_LAYOUT_REDO_ANIM}. 2510 */ 2511 public int finishPostLayoutPolicyLw() { 2512 int changes = 0; 2513 boolean topIsFullscreen = false; 2514 2515 // If we are not currently showing a dream then remember the current 2516 // lockscreen state. We will use this to determine whether the dream 2517 // started while the lockscreen was showing and remember this state 2518 // while the dream is showing. 2519 if (!mShowingDream) { 2520 mDreamingLockscreen = mService.mPolicy.isKeyguardShowingAndNotOccluded(); 2521 if (mDreamingSleepTokenNeeded) { 2522 mDreamingSleepTokenNeeded = false; 2523 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 0, 1).sendToTarget(); 2524 } 2525 } else { 2526 if (!mDreamingSleepTokenNeeded) { 2527 mDreamingSleepTokenNeeded = true; 2528 mHandler.obtainMessage(MSG_UPDATE_DREAMING_SLEEP_TOKEN, 1, 1).sendToTarget(); 2529 } 2530 } 2531 2532 if (mStatusBar != null) { 2533 if (DEBUG_LAYOUT) Slog.i(TAG, "force=" + mForceStatusBar 2534 + " forcefkg=" + mForceStatusBarFromKeyguard 2535 + " top=" + mTopFullscreenOpaqueWindowState); 2536 boolean shouldBeTransparent = mForceStatusBarTransparent 2537 && !mForceStatusBar 2538 && !mForceStatusBarFromKeyguard; 2539 if (!shouldBeTransparent) { 2540 mStatusBarController.setShowTransparent(false /* transparent */); 2541 } else if (!mStatusBar.isVisibleLw()) { 2542 mStatusBarController.setShowTransparent(true /* transparent */); 2543 } 2544 2545 boolean statusBarForcesShowingNavigation = 2546 (mStatusBar.getAttrs().privateFlags 2547 & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0; 2548 boolean topAppHidesStatusBar = topAppHidesStatusBar(); 2549 if (mForceStatusBar || mForceStatusBarFromKeyguard || mForceStatusBarTransparent 2550 || statusBarForcesShowingNavigation) { 2551 if (DEBUG_LAYOUT) Slog.v(TAG, "Showing status bar: forced"); 2552 if (mStatusBarController.setBarShowingLw(true)) { 2553 changes |= FINISH_LAYOUT_REDO_LAYOUT; 2554 } 2555 // Maintain fullscreen layout until incoming animation is complete. 2556 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw(); 2557 // Transient status bar is not allowed if status bar is on lockscreen or status bar 2558 // is expecting the navigation keys from the user. 2559 if ((mForceStatusBarFromKeyguard || statusBarForcesShowingNavigation) 2560 && mStatusBarController.isTransientShowing()) { 2561 mStatusBarController.updateVisibilityLw(false /*transientAllowed*/, 2562 mLastSystemUiFlags, mLastSystemUiFlags); 2563 } 2564 } else if (mTopFullscreenOpaqueWindowState != null) { 2565 topIsFullscreen = topAppHidesStatusBar; 2566 // The subtle difference between the window for mTopFullscreenOpaqueWindowState 2567 // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window 2568 // has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the 2569 // case though. 2570 if (mStatusBarController.isTransientShowing()) { 2571 if (mStatusBarController.setBarShowingLw(true)) { 2572 changes |= FINISH_LAYOUT_REDO_LAYOUT; 2573 } 2574 } else if (topIsFullscreen 2575 && !mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM) 2576 && !mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY)) { 2577 if (DEBUG_LAYOUT) Slog.v(TAG, "** HIDING status bar"); 2578 if (mStatusBarController.setBarShowingLw(false)) { 2579 changes |= FINISH_LAYOUT_REDO_LAYOUT; 2580 } else { 2581 if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar already hiding"); 2582 } 2583 } else { 2584 if (DEBUG_LAYOUT) Slog.v(TAG, "** SHOWING status bar: top is not fullscreen"); 2585 if (mStatusBarController.setBarShowingLw(true)) { 2586 changes |= FINISH_LAYOUT_REDO_LAYOUT; 2587 } 2588 topAppHidesStatusBar = false; 2589 } 2590 } 2591 mStatusBarController.setTopAppHidesStatusBar(topAppHidesStatusBar); 2592 } 2593 2594 if (mTopIsFullscreen != topIsFullscreen) { 2595 if (!topIsFullscreen) { 2596 // Force another layout when status bar becomes fully shown. 2597 changes |= FINISH_LAYOUT_REDO_LAYOUT; 2598 } 2599 mTopIsFullscreen = topIsFullscreen; 2600 } 2601 2602 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) { 2603 // If the navigation bar has been hidden or shown, we need to do another 2604 // layout pass to update that window. 2605 changes |= FINISH_LAYOUT_REDO_LAYOUT; 2606 } 2607 2608 if (mShowingDream != mLastShowingDream) { 2609 mLastShowingDream = mShowingDream; 2610 mService.notifyShowingDreamChanged(); 2611 } 2612 2613 updateWindowSleepToken(); 2614 2615 mService.mPolicy.setAllowLockscreenWhenOn(getDisplayId(), mAllowLockscreenWhenOn); 2616 return changes; 2617 } 2618 2619 private void updateWindowSleepToken() { 2620 if (mWindowSleepTokenNeeded && !mLastWindowSleepTokenNeeded) { 2621 mHandler.removeCallbacks(mReleaseSleepTokenRunnable); 2622 mHandler.post(mAcquireSleepTokenRunnable); 2623 } else if (!mWindowSleepTokenNeeded && mLastWindowSleepTokenNeeded) { 2624 mHandler.removeCallbacks(mAcquireSleepTokenRunnable); 2625 mHandler.post(mReleaseSleepTokenRunnable); 2626 } 2627 mLastWindowSleepTokenNeeded = mWindowSleepTokenNeeded; 2628 } 2629 2630 /** 2631 * @return Whether the top app should hide the statusbar based on the top fullscreen opaque 2632 * window. 2633 */ 2634 private boolean topAppHidesStatusBar() { 2635 if (mTopFullscreenOpaqueWindowState == null) { 2636 return false; 2637 } 2638 final int fl = PolicyControl.getWindowFlags(null, 2639 mTopFullscreenOpaqueWindowState.getAttrs()); 2640 if (localLOGV) { 2641 Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()); 2642 Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs() 2643 + " lp.flags=0x" + Integer.toHexString(fl)); 2644 } 2645 return (fl & LayoutParams.FLAG_FULLSCREEN) != 0 2646 || (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0; 2647 } 2648 2649 /** 2650 * Called when the user is switched. 2651 */ 2652 public void switchUser() { 2653 updateCurrentUserResources(); 2654 } 2655 2656 /** 2657 * Called when the resource overlays change. 2658 */ 2659 public void onOverlayChangedLw() { 2660 updateCurrentUserResources(); 2661 onConfigurationChanged(); 2662 mSystemGestures.onConfigurationChanged(); 2663 } 2664 2665 /** 2666 * Called when the configuration has changed, and it's safe to load new values from resources. 2667 */ 2668 public void onConfigurationChanged() { 2669 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation(); 2670 2671 final Resources res = getCurrentUserResources(); 2672 final int portraitRotation = displayRotation.getPortraitRotation(); 2673 final int upsideDownRotation = displayRotation.getUpsideDownRotation(); 2674 final int landscapeRotation = displayRotation.getLandscapeRotation(); 2675 final int seascapeRotation = displayRotation.getSeascapeRotation(); 2676 final int uiMode = mService.mPolicy.getUiMode(); 2677 2678 if (hasStatusBar()) { 2679 mStatusBarHeightForRotation[portraitRotation] = 2680 mStatusBarHeightForRotation[upsideDownRotation] = 2681 res.getDimensionPixelSize(R.dimen.status_bar_height_portrait); 2682 mStatusBarHeightForRotation[landscapeRotation] = 2683 mStatusBarHeightForRotation[seascapeRotation] = 2684 res.getDimensionPixelSize(R.dimen.status_bar_height_landscape); 2685 } else { 2686 mStatusBarHeightForRotation[portraitRotation] = 2687 mStatusBarHeightForRotation[upsideDownRotation] = 2688 mStatusBarHeightForRotation[landscapeRotation] = 2689 mStatusBarHeightForRotation[seascapeRotation] = 0; 2690 } 2691 2692 // Height of the navigation bar when presented horizontally at bottom 2693 mNavigationBarHeightForRotationDefault[portraitRotation] = 2694 mNavigationBarHeightForRotationDefault[upsideDownRotation] = 2695 res.getDimensionPixelSize(R.dimen.navigation_bar_height); 2696 mNavigationBarHeightForRotationDefault[landscapeRotation] = 2697 mNavigationBarHeightForRotationDefault[seascapeRotation] = 2698 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape); 2699 2700 // Height of the navigation bar frame when presented horizontally at bottom 2701 mNavigationBarFrameHeightForRotationDefault[portraitRotation] = 2702 mNavigationBarFrameHeightForRotationDefault[upsideDownRotation] = 2703 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height); 2704 mNavigationBarFrameHeightForRotationDefault[landscapeRotation] = 2705 mNavigationBarFrameHeightForRotationDefault[seascapeRotation] = 2706 res.getDimensionPixelSize(R.dimen.navigation_bar_frame_height_landscape); 2707 2708 // Width of the navigation bar when presented vertically along one side 2709 mNavigationBarWidthForRotationDefault[portraitRotation] = 2710 mNavigationBarWidthForRotationDefault[upsideDownRotation] = 2711 mNavigationBarWidthForRotationDefault[landscapeRotation] = 2712 mNavigationBarWidthForRotationDefault[seascapeRotation] = 2713 res.getDimensionPixelSize(R.dimen.navigation_bar_width); 2714 2715 if (ALTERNATE_CAR_MODE_NAV_SIZE) { 2716 // Height of the navigation bar when presented horizontally at bottom 2717 mNavigationBarHeightForRotationInCarMode[portraitRotation] = 2718 mNavigationBarHeightForRotationInCarMode[upsideDownRotation] = 2719 res.getDimensionPixelSize(R.dimen.navigation_bar_height_car_mode); 2720 mNavigationBarHeightForRotationInCarMode[landscapeRotation] = 2721 mNavigationBarHeightForRotationInCarMode[seascapeRotation] = 2722 res.getDimensionPixelSize(R.dimen.navigation_bar_height_landscape_car_mode); 2723 2724 // Width of the navigation bar when presented vertically along one side 2725 mNavigationBarWidthForRotationInCarMode[portraitRotation] = 2726 mNavigationBarWidthForRotationInCarMode[upsideDownRotation] = 2727 mNavigationBarWidthForRotationInCarMode[landscapeRotation] = 2728 mNavigationBarWidthForRotationInCarMode[seascapeRotation] = 2729 res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode); 2730 } 2731 2732 mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode); 2733 mSideGestureInset = res.getDimensionPixelSize(R.dimen.config_backGestureInset); 2734 mNavigationBarLetsThroughTaps = res.getBoolean(R.bool.config_navBarTapThrough); 2735 mNavigationBarAlwaysShowOnSideGesture = 2736 res.getBoolean(R.bool.config_navBarAlwaysShowOnSideEdgeGesture); 2737 2738 // This should calculate how much above the frame we accept gestures. 2739 mBottomGestureAdditionalInset = 2740 res.getDimensionPixelSize(R.dimen.navigation_bar_gesture_height) 2741 - getNavigationBarFrameHeight(portraitRotation, uiMode); 2742 2743 updateConfigurationAndScreenSizeDependentBehaviors(); 2744 mWindowOutsetBottom = ScreenShapeHelper.getWindowOutsetBottomPx(mContext.getResources()); 2745 } 2746 2747 void updateConfigurationAndScreenSizeDependentBehaviors() { 2748 final Resources res = getCurrentUserResources(); 2749 mNavigationBarCanMove = 2750 mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight 2751 && res.getBoolean(R.bool.config_navBarCanMove); 2752 mAllowSeamlessRotationDespiteNavBarMoving = 2753 res.getBoolean(R.bool.config_allowSeamlessRotationDespiteNavBarMoving); 2754 } 2755 2756 /** 2757 * Updates the current user's resources to pick up any changes for the current user (including 2758 * overlay paths) 2759 */ 2760 private void updateCurrentUserResources() { 2761 final int userId = mService.mAmInternal.getCurrentUserId(); 2762 final Context uiContext = getSystemUiContext(); 2763 2764 if (userId == UserHandle.USER_SYSTEM) { 2765 // Skip the (expensive) recreation of resources for the system user below and just 2766 // use the resources from the system ui context 2767 mCurrentUserResources = uiContext.getResources(); 2768 return; 2769 } 2770 2771 // For non-system users, ensure that the resources are loaded from the current 2772 // user's package info (see ContextImpl.createDisplayContext) 2773 final LoadedApk pi = ActivityThread.currentActivityThread().getPackageInfo( 2774 uiContext.getPackageName(), null, 0, userId); 2775 mCurrentUserResources = ResourcesManager.getInstance().getResources(null, 2776 pi.getResDir(), 2777 null /* splitResDirs */, 2778 pi.getOverlayDirs(), 2779 pi.getApplicationInfo().sharedLibraryFiles, 2780 mDisplayContent.getDisplayId(), 2781 null /* overrideConfig */, 2782 uiContext.getResources().getCompatibilityInfo(), 2783 null /* classLoader */); 2784 } 2785 2786 @VisibleForTesting 2787 Resources getCurrentUserResources() { 2788 if (mCurrentUserResources == null) { 2789 updateCurrentUserResources(); 2790 } 2791 return mCurrentUserResources; 2792 } 2793 2794 @VisibleForTesting 2795 Context getContext() { 2796 return mContext; 2797 } 2798 2799 private Context getSystemUiContext() { 2800 final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext(); 2801 return mDisplayContent.isDefaultDisplay 2802 ? uiContext : uiContext.createDisplayContext(mDisplayContent.getDisplay()); 2803 } 2804 2805 private int getNavigationBarWidth(int rotation, int uiMode) { 2806 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) { 2807 return mNavigationBarWidthForRotationInCarMode[rotation]; 2808 } else { 2809 return mNavigationBarWidthForRotationDefault[rotation]; 2810 } 2811 } 2812 2813 void notifyDisplayReady() { 2814 mHandler.post(() -> { 2815 final int displayId = getDisplayId(); 2816 getStatusBarManagerInternal().onDisplayReady(displayId); 2817 final WallpaperManagerInternal wpMgr = LocalServices 2818 .getService(WallpaperManagerInternal.class); 2819 if (wpMgr != null) { 2820 wpMgr.onDisplayReady(displayId); 2821 } 2822 }); 2823 } 2824 2825 /** 2826 * Return the display width available after excluding any screen 2827 * decorations that could never be removed in Honeycomb. That is, system bar or 2828 * button bar. 2829 */ getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, DisplayCutout displayCutout)2830 public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, 2831 DisplayCutout displayCutout) { 2832 int width = fullWidth; 2833 if (hasNavigationBar()) { 2834 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation); 2835 if (navBarPosition == NAV_BAR_LEFT || navBarPosition == NAV_BAR_RIGHT) { 2836 width -= getNavigationBarWidth(rotation, uiMode); 2837 } 2838 } 2839 if (displayCutout != null) { 2840 width -= displayCutout.getSafeInsetLeft() + displayCutout.getSafeInsetRight(); 2841 } 2842 return width; 2843 } 2844 getNavigationBarHeight(int rotation, int uiMode)2845 private int getNavigationBarHeight(int rotation, int uiMode) { 2846 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) { 2847 return mNavigationBarHeightForRotationInCarMode[rotation]; 2848 } else { 2849 return mNavigationBarHeightForRotationDefault[rotation]; 2850 } 2851 } 2852 2853 /** 2854 * Get the Navigation Bar Frame height. This dimension is the height of the navigation bar that 2855 * is used for spacing to show additional buttons on the navigation bar (such as the ime 2856 * switcher when ime is visible) while {@link #getNavigationBarHeight} is used for the visible 2857 * height that we send to the app as content insets that can be smaller. 2858 * <p> 2859 * In car mode it will return the same height as {@link #getNavigationBarHeight} 2860 * 2861 * @param rotation specifies rotation to return dimension from 2862 * @param uiMode to determine if in car mode 2863 * @return navigation bar frame height 2864 */ getNavigationBarFrameHeight(int rotation, int uiMode)2865 private int getNavigationBarFrameHeight(int rotation, int uiMode) { 2866 if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) { 2867 return mNavigationBarHeightForRotationInCarMode[rotation]; 2868 } else { 2869 return mNavigationBarFrameHeightForRotationDefault[rotation]; 2870 } 2871 } 2872 2873 /** 2874 * Return the display height available after excluding any screen 2875 * decorations that could never be removed in Honeycomb. That is, system bar or 2876 * button bar. 2877 */ getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, DisplayCutout displayCutout)2878 public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, 2879 DisplayCutout displayCutout) { 2880 int height = fullHeight; 2881 if (hasNavigationBar()) { 2882 final int navBarPosition = navigationBarPosition(fullWidth, fullHeight, rotation); 2883 if (navBarPosition == NAV_BAR_BOTTOM) { 2884 height -= getNavigationBarHeight(rotation, uiMode); 2885 } 2886 } 2887 if (displayCutout != null) { 2888 height -= displayCutout.getSafeInsetTop() + displayCutout.getSafeInsetBottom(); 2889 } 2890 return height; 2891 } 2892 2893 /** 2894 * Return the available screen width that we should report for the 2895 * configuration. This must be no larger than 2896 * {@link #getNonDecorDisplayWidth(int, int, int, int, DisplayCutout)}; it may be smaller 2897 * than that to account for more transient decoration like a status bar. 2898 */ getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, DisplayCutout displayCutout)2899 public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode, 2900 DisplayCutout displayCutout) { 2901 return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode, displayCutout); 2902 } 2903 2904 /** 2905 * Return the available screen height that we should report for the 2906 * configuration. This must be no larger than 2907 * {@link #getNonDecorDisplayHeight(int, int, int, int, DisplayCutout)}; it may be smaller 2908 * than that to account for more transient decoration like a status bar. 2909 */ getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, DisplayCutout displayCutout)2910 public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode, 2911 DisplayCutout displayCutout) { 2912 // There is a separate status bar at the top of the display. We don't count that as part 2913 // of the fixed decor, since it can hide; however, for purposes of configurations, 2914 // we do want to exclude it since applications can't generally use that part 2915 // of the screen. 2916 int statusBarHeight = mStatusBarHeightForRotation[rotation]; 2917 if (displayCutout != null) { 2918 // If there is a cutout, it may already have accounted for some part of the status 2919 // bar height. 2920 statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop()); 2921 } 2922 return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayCutout) 2923 - statusBarHeight; 2924 } 2925 2926 /** 2927 * Return corner radius in pixels that should be used on windows in order to cover the display. 2928 * The radius is only valid for built-in displays since the one who configures window corner 2929 * radius cannot know the corner radius of non-built-in display. 2930 */ getWindowCornerRadius()2931 float getWindowCornerRadius() { 2932 return mDisplayContent.getDisplay().getType() == TYPE_BUILT_IN 2933 ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f; 2934 } 2935 isShowingDreamLw()2936 boolean isShowingDreamLw() { 2937 return mShowingDream; 2938 } 2939 2940 /** 2941 * Calculates the stable insets if we already have the non-decor insets. 2942 * 2943 * @param inOutInsets The known non-decor insets. It will be modified to stable insets. 2944 * @param rotation The current display rotation. 2945 */ convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation)2946 void convertNonDecorInsetsToStableInsets(Rect inOutInsets, int rotation) { 2947 inOutInsets.top = Math.max(inOutInsets.top, mStatusBarHeightForRotation[rotation]); 2948 } 2949 2950 /** 2951 * Calculates the stable insets without running a layout. 2952 * 2953 * @param displayRotation the current display rotation 2954 * @param displayWidth the current display width 2955 * @param displayHeight the current display height 2956 * @param displayCutout the current display cutout 2957 * @param outInsets the insets to return 2958 */ getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight, DisplayCutout displayCutout, Rect outInsets)2959 public void getStableInsetsLw(int displayRotation, int displayWidth, int displayHeight, 2960 DisplayCutout displayCutout, Rect outInsets) { 2961 outInsets.setEmpty(); 2962 2963 // Navigation bar and status bar. 2964 getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets); 2965 convertNonDecorInsetsToStableInsets(outInsets, displayRotation); 2966 } 2967 2968 /** 2969 * Calculates the insets for the areas that could never be removed in Honeycomb, i.e. system 2970 * bar or button bar. See {@link #getNonDecorDisplayWidth}. 2971 * 2972 * @param displayRotation the current display rotation 2973 * @param displayWidth the current display width 2974 * @param displayHeight the current display height 2975 * @param displayCutout the current display cutout 2976 * @param outInsets the insets to return 2977 */ getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight, DisplayCutout displayCutout, Rect outInsets)2978 public void getNonDecorInsetsLw(int displayRotation, int displayWidth, int displayHeight, 2979 DisplayCutout displayCutout, Rect outInsets) { 2980 outInsets.setEmpty(); 2981 2982 // Only navigation bar 2983 if (hasNavigationBar()) { 2984 final int uiMode = mService.mPolicy.getUiMode(); 2985 int position = navigationBarPosition(displayWidth, displayHeight, displayRotation); 2986 if (position == NAV_BAR_BOTTOM) { 2987 outInsets.bottom = getNavigationBarHeight(displayRotation, uiMode); 2988 } else if (position == NAV_BAR_RIGHT) { 2989 outInsets.right = getNavigationBarWidth(displayRotation, uiMode); 2990 } else if (position == NAV_BAR_LEFT) { 2991 outInsets.left = getNavigationBarWidth(displayRotation, uiMode); 2992 } 2993 } 2994 2995 if (displayCutout != null) { 2996 outInsets.left += displayCutout.getSafeInsetLeft(); 2997 outInsets.top += displayCutout.getSafeInsetTop(); 2998 outInsets.right += displayCutout.getSafeInsetRight(); 2999 outInsets.bottom += displayCutout.getSafeInsetBottom(); 3000 } 3001 } 3002 3003 /** 3004 * @see IWindowManager#setForwardedInsets 3005 */ setForwardedInsets(@onNull Insets forwardedInsets)3006 public void setForwardedInsets(@NonNull Insets forwardedInsets) { 3007 mForwardedInsets = forwardedInsets; 3008 } 3009 3010 @NonNull getForwardedInsets()3011 public Insets getForwardedInsets() { 3012 return mForwardedInsets; 3013 } 3014 3015 @NavigationBarPosition navigationBarPosition(int displayWidth, int displayHeight, int displayRotation)3016 int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) { 3017 if (navigationBarCanMove() && displayWidth > displayHeight) { 3018 if (displayRotation == Surface.ROTATION_270) { 3019 return NAV_BAR_LEFT; 3020 } else if (displayRotation == Surface.ROTATION_90) { 3021 return NAV_BAR_RIGHT; 3022 } 3023 } 3024 return NAV_BAR_BOTTOM; 3025 } 3026 3027 /** 3028 * @return The side of the screen where navigation bar is positioned. 3029 * @see WindowManagerPolicyConstants#NAV_BAR_LEFT 3030 * @see WindowManagerPolicyConstants#NAV_BAR_RIGHT 3031 * @see WindowManagerPolicyConstants#NAV_BAR_BOTTOM 3032 */ 3033 @NavigationBarPosition getNavBarPosition()3034 public int getNavBarPosition() { 3035 return mNavigationBarPosition; 3036 } 3037 3038 /** 3039 * A new window has been focused. 3040 */ focusChangedLw(WindowState lastFocus, WindowState newFocus)3041 public int focusChangedLw(WindowState lastFocus, WindowState newFocus) { 3042 mFocusedWindow = newFocus; 3043 mLastFocusedWindow = lastFocus; 3044 if (mDisplayContent.isDefaultDisplay) { 3045 mService.mPolicy.onDefaultDisplayFocusChangedLw(newFocus); 3046 } 3047 if ((updateSystemUiVisibilityLw() & SYSTEM_UI_CHANGING_LAYOUT) != 0) { 3048 // If the navigation bar has been hidden or shown, we need to do another 3049 // layout pass to update that window. 3050 return FINISH_LAYOUT_REDO_LAYOUT; 3051 } 3052 return 0; 3053 } 3054 3055 /** 3056 * Return true if it is okay to perform animations for an app transition 3057 * that is about to occur. You may return false for this if, for example, 3058 * the dream window is currently displayed so the switch should happen 3059 * immediately. 3060 */ allowAppAnimationsLw()3061 public boolean allowAppAnimationsLw() { 3062 return !mShowingDream; 3063 } 3064 updateDreamingSleepToken(boolean acquire)3065 private void updateDreamingSleepToken(boolean acquire) { 3066 if (acquire) { 3067 final int displayId = getDisplayId(); 3068 if (mDreamingSleepToken == null) { 3069 mDreamingSleepToken = mService.mAtmInternal.acquireSleepToken( 3070 "DreamOnDisplay" + displayId, displayId); 3071 } 3072 } else { 3073 if (mDreamingSleepToken != null) { 3074 mDreamingSleepToken.release(); 3075 mDreamingSleepToken = null; 3076 } 3077 } 3078 } 3079 requestTransientBars(WindowState swipeTarget)3080 private void requestTransientBars(WindowState swipeTarget) { 3081 synchronized (mLock) { 3082 if (!mService.mPolicy.isUserSetupComplete()) { 3083 // Swipe-up for navigation bar is disabled during setup 3084 return; 3085 } 3086 boolean sb = mStatusBarController.checkShowTransientBarLw(); 3087 boolean nb = mNavigationBarController.checkShowTransientBarLw() 3088 && !isNavBarEmpty(mLastSystemUiFlags); 3089 if (sb || nb) { 3090 // Don't show status bar when swiping on already visible navigation bar 3091 if (!nb && swipeTarget == mNavigationBar) { 3092 if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target"); 3093 return; 3094 } 3095 if (sb) mStatusBarController.showTransient(); 3096 if (nb) mNavigationBarController.showTransient(); 3097 mImmersiveModeConfirmation.confirmCurrentPrompt(); 3098 updateSystemUiVisibilityLw(); 3099 } 3100 } 3101 } 3102 disposeInputConsumer(InputConsumer inputConsumer)3103 private void disposeInputConsumer(InputConsumer inputConsumer) { 3104 if (inputConsumer != null) { 3105 inputConsumer.dismiss(); 3106 } 3107 } 3108 isStatusBarKeyguard()3109 private boolean isStatusBarKeyguard() { 3110 return mStatusBar != null 3111 && (mStatusBar.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0; 3112 } 3113 isKeyguardOccluded()3114 private boolean isKeyguardOccluded() { 3115 // TODO (b/113840485): Handle per display keyguard. 3116 return mService.mPolicy.isKeyguardOccluded(); 3117 } 3118 resetSystemUiVisibilityLw()3119 void resetSystemUiVisibilityLw() { 3120 mLastSystemUiFlags = 0; 3121 updateSystemUiVisibilityLw(); 3122 } 3123 updateSystemUiVisibilityLw()3124 private int updateSystemUiVisibilityLw() { 3125 // If there is no window focused, there will be nobody to handle the events 3126 // anyway, so just hang on in whatever state we're in until things settle down. 3127 WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow 3128 : mTopFullscreenOpaqueWindowState; 3129 if (winCandidate == null) { 3130 return 0; 3131 } 3132 3133 // The immersive mode confirmation should never affect the system bar visibility, otherwise 3134 // it will unhide the navigation bar and hide itself. 3135 if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) { 3136 3137 // The immersive mode confirmation took the focus from mLastFocusedWindow which was 3138 // controlling the system ui visibility. So if mLastFocusedWindow can still receive 3139 // keys, we let it keep controlling the visibility. 3140 final boolean lastFocusCanReceiveKeys = 3141 (mLastFocusedWindow != null && mLastFocusedWindow.canReceiveKeys()); 3142 winCandidate = isStatusBarKeyguard() ? mStatusBar 3143 : lastFocusCanReceiveKeys ? mLastFocusedWindow 3144 : mTopFullscreenOpaqueWindowState; 3145 if (winCandidate == null) { 3146 return 0; 3147 } 3148 } 3149 final WindowState win = winCandidate; 3150 if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && isKeyguardOccluded()) { 3151 // We are updating at a point where the keyguard has gotten 3152 // focus, but we were last in a state where the top window is 3153 // hiding it. This is probably because the keyguard as been 3154 // shown while the top window was displayed, so we want to ignore 3155 // it here because this is just a very transient change and it 3156 // will quickly lose focus once it correctly gets hidden. 3157 return 0; 3158 } 3159 3160 mDisplayContent.getInsetsStateController().onBarControllingWindowChanged( 3161 mTopFullscreenOpaqueWindowState); 3162 3163 int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null) 3164 & ~mResettingSystemUiFlags 3165 & ~mForceClearedSystemUiFlags; 3166 if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) { 3167 tmpVisibility 3168 &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS); 3169 } 3170 3171 final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */, 3172 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState); 3173 final int dockedVisibility = updateLightStatusBarLw(0 /* vis */, 3174 mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState); 3175 mService.getStackBounds( 3176 WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mNonDockedStackBounds); 3177 mService.getStackBounds( 3178 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, mDockedStackBounds); 3179 final Pair<Integer, Boolean> result = 3180 updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility); 3181 final int visibility = result.first; 3182 final int diff = visibility ^ mLastSystemUiFlags; 3183 final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags; 3184 final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags; 3185 final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState); 3186 if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu 3187 && mFocusedApp == win.getAppToken() 3188 && mLastNonDockedStackBounds.equals(mNonDockedStackBounds) 3189 && mLastDockedStackBounds.equals(mDockedStackBounds)) { 3190 return 0; 3191 } 3192 mLastSystemUiFlags = visibility; 3193 mLastFullscreenStackSysUiFlags = fullscreenVisibility; 3194 mLastDockedStackSysUiFlags = dockedVisibility; 3195 mLastFocusNeedsMenu = needsMenu; 3196 mFocusedApp = win.getAppToken(); 3197 mLastNonDockedStackBounds.set(mNonDockedStackBounds); 3198 mLastDockedStackBounds.set(mDockedStackBounds); 3199 final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds); 3200 final Rect dockedStackBounds = new Rect(mDockedStackBounds); 3201 final boolean isNavbarColorManagedByIme = result.second; 3202 mHandler.post(() -> { 3203 StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); 3204 if (statusBar != null) { 3205 final int displayId = getDisplayId(); 3206 statusBar.setSystemUiVisibility(displayId, visibility, fullscreenVisibility, 3207 dockedVisibility, 0xffffffff, fullscreenStackBounds, 3208 dockedStackBounds, isNavbarColorManagedByIme, win.toString()); 3209 statusBar.topAppWindowChanged(displayId, needsMenu); 3210 } 3211 }); 3212 return diff; 3213 } 3214 updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming)3215 private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) { 3216 final boolean onKeyguard = isStatusBarKeyguard() && !isKeyguardOccluded(); 3217 final WindowState statusColorWin = onKeyguard ? mStatusBar : opaqueOrDimming; 3218 if (statusColorWin != null && (statusColorWin == opaque || onKeyguard)) { 3219 // If the top fullscreen-or-dimming window is also the top fullscreen, respect 3220 // its light flag. 3221 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 3222 vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null) 3223 & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 3224 } else if (statusColorWin != null && statusColorWin.isDimming()) { 3225 // Otherwise if it's dimming, clear the light flag. 3226 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 3227 } 3228 return vis; 3229 } 3230 3231 @VisibleForTesting 3232 @Nullable chooseNavigationColorWindowLw(WindowState opaque, WindowState opaqueOrDimming, WindowState imeWindow, @NavigationBarPosition int navBarPosition)3233 static WindowState chooseNavigationColorWindowLw(WindowState opaque, 3234 WindowState opaqueOrDimming, WindowState imeWindow, 3235 @NavigationBarPosition int navBarPosition) { 3236 // If the IME window is visible and FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS is set, then IME 3237 // window can be navigation color window. 3238 final boolean imeWindowCanNavColorWindow = imeWindow != null 3239 && imeWindow.isVisibleLw() 3240 && navBarPosition == NAV_BAR_BOTTOM 3241 && (PolicyControl.getWindowFlags(imeWindow, null) 3242 & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; 3243 3244 if (opaque != null && opaqueOrDimming == opaque) { 3245 // If the top fullscreen-or-dimming window is also the top fullscreen, respect it 3246 // unless IME window is also eligible, since currently the IME window is always show 3247 // above the opaque fullscreen app window, regardless of the IME target window. 3248 // TODO(b/31559891): Maybe we need to revisit this condition once b/31559891 is fixed. 3249 return imeWindowCanNavColorWindow ? imeWindow : opaque; 3250 } 3251 3252 if (opaqueOrDimming == null || !opaqueOrDimming.isDimming()) { 3253 // No dimming window is involved. Determine the result only with the IME window. 3254 return imeWindowCanNavColorWindow ? imeWindow : null; 3255 } 3256 3257 if (!imeWindowCanNavColorWindow) { 3258 // No IME window is involved. Determine the result only with opaqueOrDimming. 3259 return opaqueOrDimming; 3260 } 3261 3262 // The IME window and the dimming window are competing. Check if the dimming window can be 3263 // IME target or not. 3264 if (LayoutParams.mayUseInputMethod(PolicyControl.getWindowFlags(opaqueOrDimming, null))) { 3265 // The IME window is above the dimming window. 3266 return imeWindow; 3267 } else { 3268 // The dimming window is above the IME window. 3269 return opaqueOrDimming; 3270 } 3271 } 3272 3273 @VisibleForTesting updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming, WindowState imeWindow, WindowState navColorWin)3274 static int updateLightNavigationBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming, 3275 WindowState imeWindow, WindowState navColorWin) { 3276 3277 if (navColorWin != null) { 3278 if (navColorWin == imeWindow || navColorWin == opaque) { 3279 // Respect the light flag. 3280 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; 3281 vis |= PolicyControl.getSystemUiVisibility(navColorWin, null) 3282 & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; 3283 } else if (navColorWin == opaqueOrDimming && navColorWin.isDimming()) { 3284 // Clear the light flag for dimming window. 3285 vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; 3286 } 3287 } 3288 return vis; 3289 } 3290 updateSystemBarsLw(WindowState win, int oldVis, int vis)3291 private Pair<Integer, Boolean> updateSystemBarsLw(WindowState win, int oldVis, int vis) { 3292 final boolean dockedStackVisible = 3293 mDisplayContent.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); 3294 final boolean freeformStackVisible = 3295 mDisplayContent.isStackVisible(WINDOWING_MODE_FREEFORM); 3296 final boolean resizing = mDisplayContent.getDockedDividerController().isResizing(); 3297 3298 // We need to force system bars when the docked stack is visible, when the freeform stack 3299 // is visible but also when we are resizing for the transitions when docked stack 3300 // visibility changes. 3301 mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing 3302 || mForceShowSystemBarsFromExternal; 3303 final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard; 3304 3305 // apply translucent bar vis flags 3306 WindowState fullscreenTransWin = isStatusBarKeyguard() && !isKeyguardOccluded() 3307 ? mStatusBar 3308 : mTopFullscreenOpaqueWindowState; 3309 vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis); 3310 vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis); 3311 int dockedVis = mStatusBarController.applyTranslucentFlagLw( 3312 mTopDockedOpaqueWindowState, 0, 0); 3313 dockedVis = mNavigationBarController.applyTranslucentFlagLw( 3314 mTopDockedOpaqueWindowState, dockedVis, 0); 3315 3316 final boolean fullscreenDrawsStatusBarBackground = 3317 drawsStatusBarBackground(vis, mTopFullscreenOpaqueWindowState); 3318 final boolean dockedDrawsStatusBarBackground = 3319 drawsStatusBarBackground(dockedVis, mTopDockedOpaqueWindowState); 3320 final boolean fullscreenDrawsNavBarBackground = 3321 drawsNavigationBarBackground(vis, mTopFullscreenOpaqueWindowState); 3322 final boolean dockedDrawsNavigationBarBackground = 3323 drawsNavigationBarBackground(dockedVis, mTopDockedOpaqueWindowState); 3324 3325 // prevent status bar interaction from clearing certain flags 3326 int type = win.getAttrs().type; 3327 boolean statusBarHasFocus = type == TYPE_STATUS_BAR; 3328 if (statusBarHasFocus && !isStatusBarKeyguard()) { 3329 int flags = View.SYSTEM_UI_FLAG_FULLSCREEN 3330 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 3331 | View.SYSTEM_UI_FLAG_IMMERSIVE 3332 | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 3333 | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; 3334 if (isKeyguardOccluded()) { 3335 flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT; 3336 } 3337 vis = (vis & ~flags) | (oldVis & flags); 3338 } 3339 3340 if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) { 3341 vis |= View.STATUS_BAR_TRANSPARENT; 3342 vis &= ~View.STATUS_BAR_TRANSLUCENT; 3343 } else if (forceOpaqueStatusBar) { 3344 vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT); 3345 } 3346 3347 vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing, 3348 fullscreenDrawsNavBarBackground, dockedDrawsNavigationBarBackground); 3349 3350 // update status bar 3351 boolean immersiveSticky = 3352 (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0; 3353 final boolean hideStatusBarWM = 3354 mTopFullscreenOpaqueWindowState != null 3355 && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null) 3356 & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; 3357 final boolean hideStatusBarSysui = 3358 (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0; 3359 final boolean hideNavBarSysui = 3360 (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0; 3361 3362 final boolean transientStatusBarAllowed = mStatusBar != null 3363 && (statusBarHasFocus || (!mForceShowSystemBars 3364 && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky)))); 3365 3366 final boolean transientNavBarAllowed = mNavigationBar != null 3367 && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky; 3368 3369 final long now = SystemClock.uptimeMillis(); 3370 final boolean pendingPanic = mPendingPanicGestureUptime != 0 3371 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION; 3372 final DisplayPolicy defaultDisplayPolicy = 3373 mService.getDefaultDisplayContentLocked().getDisplayPolicy(); 3374 if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard() 3375 // TODO (b/111955725): Show keyguard presentation on all external displays 3376 && defaultDisplayPolicy.isKeyguardDrawComplete()) { 3377 // The user performed the panic gesture recently, we're about to hide the bars, 3378 // we're no longer on the Keyguard and the screen is ready. We can now request the bars. 3379 mPendingPanicGestureUptime = 0; 3380 mStatusBarController.showTransient(); 3381 if (!isNavBarEmpty(vis)) { 3382 mNavigationBarController.showTransient(); 3383 } 3384 } 3385 3386 final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested() 3387 && !transientStatusBarAllowed && hideStatusBarSysui; 3388 final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested() 3389 && !transientNavBarAllowed; 3390 if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) { 3391 // clear the clearable flags instead 3392 clearClearableFlagsLw(); 3393 vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS; 3394 } 3395 3396 final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0; 3397 immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0; 3398 final boolean navAllowedHidden = immersive || immersiveSticky; 3399 3400 if (hideNavBarSysui && !navAllowedHidden 3401 && mService.mPolicy.getWindowLayerLw(win) 3402 > mService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_CONSUMER)) { 3403 // We can't hide the navbar from this window otherwise the input consumer would not get 3404 // the input events. 3405 vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); 3406 } 3407 3408 vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis); 3409 3410 // update navigation bar 3411 boolean oldImmersiveMode = isImmersiveMode(oldVis); 3412 boolean newImmersiveMode = isImmersiveMode(vis); 3413 if (oldImmersiveMode != newImmersiveMode) { 3414 final String pkg = win.getOwningPackage(); 3415 mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode, 3416 mService.mPolicy.isUserSetupComplete(), 3417 isNavBarEmpty(win.getSystemUiVisibility())); 3418 } 3419 3420 vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis); 3421 3422 final WindowState navColorWin = chooseNavigationColorWindowLw( 3423 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState, 3424 mDisplayContent.mInputMethodWindow, mNavigationBarPosition); 3425 vis = updateLightNavigationBarLw(vis, mTopFullscreenOpaqueWindowState, 3426 mTopFullscreenOpaqueOrDimmingWindowState, 3427 mDisplayContent.mInputMethodWindow, navColorWin); 3428 // Navbar color is controlled by the IME. 3429 final boolean isManagedByIme = 3430 navColorWin != null && navColorWin == mDisplayContent.mInputMethodWindow; 3431 3432 return Pair.create(vis, isManagedByIme); 3433 } 3434 drawsBarBackground(int vis, WindowState win, BarController controller, int translucentFlag)3435 private boolean drawsBarBackground(int vis, WindowState win, BarController controller, 3436 int translucentFlag) { 3437 if (!controller.isTransparentAllowed(win)) { 3438 return false; 3439 } 3440 if (win == null) { 3441 return true; 3442 } 3443 3444 final boolean drawsSystemBars = 3445 (win.getAttrs().flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0; 3446 final boolean forceDrawsSystemBars = 3447 (win.getAttrs().privateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0; 3448 3449 return forceDrawsSystemBars || drawsSystemBars && (vis & translucentFlag) == 0; 3450 } 3451 drawsStatusBarBackground(int vis, WindowState win)3452 private boolean drawsStatusBarBackground(int vis, WindowState win) { 3453 return drawsBarBackground(vis, win, mStatusBarController, FLAG_TRANSLUCENT_STATUS); 3454 } 3455 drawsNavigationBarBackground(int vis, WindowState win)3456 private boolean drawsNavigationBarBackground(int vis, WindowState win) { 3457 return drawsBarBackground(vis, win, mNavigationBarController, FLAG_TRANSLUCENT_NAVIGATION); 3458 } 3459 3460 /** 3461 * @return the current visibility flags with the nav-bar opacity related flags toggled based 3462 * on the nav bar opacity rules chosen by {@link #mNavBarOpacityMode}. 3463 */ configureNavBarOpacity(int visibility, boolean dockedStackVisible, boolean freeformStackVisible, boolean isDockedDividerResizing, boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground)3464 private int configureNavBarOpacity(int visibility, boolean dockedStackVisible, 3465 boolean freeformStackVisible, boolean isDockedDividerResizing, 3466 boolean fullscreenDrawsBackground, boolean dockedDrawsNavigationBarBackground) { 3467 if (mNavBarOpacityMode == NAV_BAR_FORCE_TRANSPARENT) { 3468 if (fullscreenDrawsBackground && dockedDrawsNavigationBarBackground) { 3469 visibility = setNavBarTransparentFlag(visibility); 3470 } else if (dockedStackVisible) { 3471 visibility = setNavBarOpaqueFlag(visibility); 3472 } 3473 } else if (mNavBarOpacityMode == NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED) { 3474 if (dockedStackVisible || freeformStackVisible || isDockedDividerResizing) { 3475 visibility = setNavBarOpaqueFlag(visibility); 3476 } else if (fullscreenDrawsBackground) { 3477 visibility = setNavBarTransparentFlag(visibility); 3478 } 3479 } else if (mNavBarOpacityMode == NAV_BAR_TRANSLUCENT_WHEN_FREEFORM_OPAQUE_OTHERWISE) { 3480 if (isDockedDividerResizing) { 3481 visibility = setNavBarOpaqueFlag(visibility); 3482 } else if (freeformStackVisible) { 3483 visibility = setNavBarTranslucentFlag(visibility); 3484 } else { 3485 visibility = setNavBarOpaqueFlag(visibility); 3486 } 3487 } 3488 3489 return visibility; 3490 } 3491 setNavBarOpaqueFlag(int visibility)3492 private int setNavBarOpaqueFlag(int visibility) { 3493 return visibility & ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT); 3494 } 3495 setNavBarTranslucentFlag(int visibility)3496 private int setNavBarTranslucentFlag(int visibility) { 3497 visibility &= ~View.NAVIGATION_BAR_TRANSPARENT; 3498 return visibility | View.NAVIGATION_BAR_TRANSLUCENT; 3499 } 3500 setNavBarTransparentFlag(int visibility)3501 private int setNavBarTransparentFlag(int visibility) { 3502 visibility &= ~View.NAVIGATION_BAR_TRANSLUCENT; 3503 return visibility | View.NAVIGATION_BAR_TRANSPARENT; 3504 } 3505 clearClearableFlagsLw()3506 private void clearClearableFlagsLw() { 3507 int newVal = mResettingSystemUiFlags | View.SYSTEM_UI_CLEARABLE_FLAGS; 3508 if (newVal != mResettingSystemUiFlags) { 3509 mResettingSystemUiFlags = newVal; 3510 mDisplayContent.reevaluateStatusBarVisibility(); 3511 } 3512 } 3513 isImmersiveMode(int vis)3514 private boolean isImmersiveMode(int vis) { 3515 final int flags = View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; 3516 return mNavigationBar != null 3517 && (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0 3518 && (vis & flags) != 0 3519 && canHideNavigationBar(); 3520 } 3521 3522 /** 3523 * @return whether the navigation bar can be hidden, e.g. the device has a navigation bar 3524 */ canHideNavigationBar()3525 private boolean canHideNavigationBar() { 3526 return hasNavigationBar(); 3527 } 3528 isNavBarEmpty(int systemUiFlags)3529 private static boolean isNavBarEmpty(int systemUiFlags) { 3530 final int disableNavigationBar = (View.STATUS_BAR_DISABLE_HOME 3531 | View.STATUS_BAR_DISABLE_BACK 3532 | View.STATUS_BAR_DISABLE_RECENT); 3533 3534 return (systemUiFlags & disableNavigationBar) == disableNavigationBar; 3535 } 3536 shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation, int newRotation)3537 boolean shouldRotateSeamlessly(DisplayRotation displayRotation, int oldRotation, 3538 int newRotation) { 3539 // For the upside down rotation we don't rotate seamlessly as the navigation 3540 // bar moves position. 3541 // Note most apps (using orientation:sensor or user as opposed to fullSensor) 3542 // will not enter the reverse portrait orientation, so actually the 3543 // orientation won't change at all. 3544 if (oldRotation == displayRotation.getUpsideDownRotation() 3545 || newRotation == displayRotation.getUpsideDownRotation()) { 3546 return false; 3547 } 3548 // If the navigation bar can't change sides, then it will 3549 // jump when we change orientations and we don't rotate 3550 // seamlessly - unless that is allowed, eg. with gesture 3551 // navigation where the navbar is low-profile enough that this isn't very noticeable. 3552 if (!navigationBarCanMove() && !mAllowSeamlessRotationDespiteNavBarMoving) { 3553 return false; 3554 } 3555 3556 final WindowState w = mTopFullscreenOpaqueWindowState; 3557 if (w == null || w != mFocusedWindow) { 3558 return false; 3559 } 3560 // If the bounds of activity window is different from its parent, then reject to be seamless 3561 // because the window position may change after rotation that will look like a sudden jump. 3562 if (w.mAppToken != null && !w.mAppToken.matchParentBounds()) { 3563 return false; 3564 } 3565 3566 // We only enable seamless rotation if the top window has requested 3567 // it and is in the fullscreen opaque state. Seamless rotation 3568 // requires freezing various Surface states and won't work well 3569 // with animations, so we disable it in the animation case for now. 3570 if (!w.isAnimatingLw() && w.getAttrs().rotationAnimation == ROTATION_ANIMATION_SEAMLESS) { 3571 return true; 3572 } 3573 return false; 3574 } 3575 3576 private final Runnable mHiddenNavPanic = new Runnable() { 3577 @Override 3578 public void run() { 3579 synchronized (mLock) { 3580 if (!mService.mPolicy.isUserSetupComplete()) { 3581 // Swipe-up for navigation bar is disabled during setup 3582 return; 3583 } 3584 mPendingPanicGestureUptime = SystemClock.uptimeMillis(); 3585 if (!isNavBarEmpty(mLastSystemUiFlags)) { 3586 mNavigationBarController.showTransient(); 3587 } 3588 } 3589 } 3590 }; 3591 onPowerKeyDown(boolean isScreenOn)3592 void onPowerKeyDown(boolean isScreenOn) { 3593 // Detect user pressing the power button in panic when an application has 3594 // taken over the whole screen. 3595 boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(isScreenOn, 3596 SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags), 3597 isNavBarEmpty(mLastSystemUiFlags)); 3598 if (panic) { 3599 mHandler.post(mHiddenNavPanic); 3600 } 3601 } 3602 onVrStateChangedLw(boolean enabled)3603 void onVrStateChangedLw(boolean enabled) { 3604 mImmersiveModeConfirmation.onVrStateChangedLw(enabled); 3605 } 3606 3607 /** 3608 * Called when the state of lock task mode changes. This should be used to disable immersive 3609 * mode confirmation. 3610 * 3611 * @param lockTaskState the new lock task mode state. One of 3612 * {@link ActivityManager#LOCK_TASK_MODE_NONE}, 3613 * {@link ActivityManager#LOCK_TASK_MODE_LOCKED}, 3614 * {@link ActivityManager#LOCK_TASK_MODE_PINNED}. 3615 */ onLockTaskStateChangedLw(int lockTaskState)3616 public void onLockTaskStateChangedLw(int lockTaskState) { 3617 mImmersiveModeConfirmation.onLockTaskModeChangedLw(lockTaskState); 3618 } 3619 3620 /** 3621 * Request a screenshot be taken. 3622 * 3623 * @param screenshotType The type of screenshot, for example either 3624 * {@link WindowManager#TAKE_SCREENSHOT_FULLSCREEN} or 3625 * {@link WindowManager#TAKE_SCREENSHOT_SELECTED_REGION} 3626 */ takeScreenshot(int screenshotType)3627 public void takeScreenshot(int screenshotType) { 3628 if (mScreenshotHelper != null) { 3629 mScreenshotHelper.takeScreenshot(screenshotType, 3630 mStatusBar != null && mStatusBar.isVisibleLw(), 3631 mNavigationBar != null && mNavigationBar.isVisibleLw(), 3632 mHandler, null /* completionConsumer */); 3633 } 3634 } 3635 getRefreshRatePolicy()3636 RefreshRatePolicy getRefreshRatePolicy() { 3637 return mRefreshRatePolicy; 3638 } 3639 dump(String prefix, PrintWriter pw)3640 void dump(String prefix, PrintWriter pw) { 3641 pw.print(prefix); pw.print("DisplayPolicy"); 3642 prefix += " "; 3643 pw.print(prefix); 3644 pw.print("mCarDockEnablesAccelerometer="); pw.print(mCarDockEnablesAccelerometer); 3645 pw.print(" mDeskDockEnablesAccelerometer="); 3646 pw.println(mDeskDockEnablesAccelerometer); 3647 pw.print(prefix); pw.print("mDockMode="); pw.print(Intent.dockStateToString(mDockMode)); 3648 pw.print(" mLidState="); pw.println(WindowManagerFuncs.lidStateToString(mLidState)); 3649 pw.print(prefix); pw.print("mAwake="); pw.print(mAwake); 3650 pw.print(" mScreenOnEarly="); pw.print(mScreenOnEarly); 3651 pw.print(" mScreenOnFully="); pw.println(mScreenOnFully); 3652 pw.print(prefix); pw.print("mKeyguardDrawComplete="); pw.print(mKeyguardDrawComplete); 3653 pw.print(" mWindowManagerDrawComplete="); pw.println(mWindowManagerDrawComplete); 3654 pw.print(prefix); pw.print("mHdmiPlugged="); pw.println(mHdmiPlugged); 3655 if (mLastSystemUiFlags != 0 || mResettingSystemUiFlags != 0 3656 || mForceClearedSystemUiFlags != 0) { 3657 pw.print(prefix); pw.print("mLastSystemUiFlags=0x"); 3658 pw.print(Integer.toHexString(mLastSystemUiFlags)); 3659 pw.print(" mResettingSystemUiFlags=0x"); 3660 pw.print(Integer.toHexString(mResettingSystemUiFlags)); 3661 pw.print(" mForceClearedSystemUiFlags=0x"); 3662 pw.println(Integer.toHexString(mForceClearedSystemUiFlags)); 3663 } 3664 if (mLastFocusNeedsMenu) { 3665 pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu); 3666 } 3667 pw.print(prefix); pw.print("mShowingDream="); pw.print(mShowingDream); 3668 pw.print(" mDreamingLockscreen="); pw.print(mDreamingLockscreen); 3669 pw.print(" mDreamingSleepToken="); pw.println(mDreamingSleepToken); 3670 if (mStatusBar != null) { 3671 pw.print(prefix); pw.print("mStatusBar="); pw.print(mStatusBar); 3672 pw.print(" isStatusBarKeyguard="); pw.println(isStatusBarKeyguard()); 3673 } 3674 if (mNavigationBar != null) { 3675 pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar); 3676 pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode); 3677 pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove); 3678 pw.print(prefix); pw.print("mNavigationBarPosition="); 3679 pw.println(mNavigationBarPosition); 3680 } 3681 if (mFocusedWindow != null) { 3682 pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow); 3683 } 3684 if (mFocusedApp != null) { 3685 pw.print(prefix); pw.print("mFocusedApp="); pw.println(mFocusedApp); 3686 } 3687 if (mTopFullscreenOpaqueWindowState != null) { 3688 pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState="); 3689 pw.println(mTopFullscreenOpaqueWindowState); 3690 } 3691 if (mTopFullscreenOpaqueOrDimmingWindowState != null) { 3692 pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState="); 3693 pw.println(mTopFullscreenOpaqueOrDimmingWindowState); 3694 } 3695 if (mForcingShowNavBar) { 3696 pw.print(prefix); pw.print("mForcingShowNavBar="); pw.println(mForcingShowNavBar); 3697 pw.print(prefix); pw.print("mForcingShowNavBarLayer="); 3698 pw.println(mForcingShowNavBarLayer); 3699 } 3700 pw.print(prefix); pw.print("mTopIsFullscreen="); pw.print(mTopIsFullscreen); 3701 pw.print(prefix); pw.print("mForceStatusBar="); pw.print(mForceStatusBar); 3702 pw.print(" mForceStatusBarFromKeyguard="); pw.println(mForceStatusBarFromKeyguard); 3703 pw.print(" mForceShowSystemBarsFromExternal="); 3704 pw.println(mForceShowSystemBarsFromExternal); 3705 pw.print(prefix); pw.print("mAllowLockscreenWhenOn="); pw.println(mAllowLockscreenWhenOn); 3706 mStatusBarController.dump(pw, prefix); 3707 mNavigationBarController.dump(pw, prefix); 3708 3709 pw.print(prefix); pw.println("Looper state:"); 3710 mHandler.getLooper().dump(new PrintWriterPrinter(pw), prefix + " "); 3711 } 3712 supportsPointerLocation()3713 private boolean supportsPointerLocation() { 3714 return mDisplayContent.isDefaultDisplay || !mDisplayContent.isPrivate(); 3715 } 3716 setPointerLocationEnabled(boolean pointerLocationEnabled)3717 void setPointerLocationEnabled(boolean pointerLocationEnabled) { 3718 if (!supportsPointerLocation()) { 3719 return; 3720 } 3721 3722 mHandler.sendEmptyMessage(pointerLocationEnabled 3723 ? MSG_ENABLE_POINTER_LOCATION : MSG_DISABLE_POINTER_LOCATION); 3724 } 3725 enablePointerLocation()3726 private void enablePointerLocation() { 3727 if (mPointerLocationView != null) { 3728 return; 3729 } 3730 3731 mPointerLocationView = new PointerLocationView(mContext); 3732 mPointerLocationView.setPrintCoords(false); 3733 final WindowManager.LayoutParams lp = new WindowManager.LayoutParams( 3734 WindowManager.LayoutParams.MATCH_PARENT, 3735 WindowManager.LayoutParams.MATCH_PARENT); 3736 lp.type = WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; 3737 lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN 3738 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 3739 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE 3740 | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; 3741 lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; 3742 if (ActivityManager.isHighEndGfx()) { 3743 lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; 3744 lp.privateFlags |= 3745 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED; 3746 } 3747 lp.format = PixelFormat.TRANSLUCENT; 3748 lp.setTitle("PointerLocation - display " + getDisplayId()); 3749 lp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; 3750 final WindowManager wm = mContext.getSystemService(WindowManager.class); 3751 wm.addView(mPointerLocationView, lp); 3752 mDisplayContent.registerPointerEventListener(mPointerLocationView); 3753 } 3754 disablePointerLocation()3755 private void disablePointerLocation() { 3756 if (mPointerLocationView == null) { 3757 return; 3758 } 3759 3760 mDisplayContent.unregisterPointerEventListener(mPointerLocationView); 3761 final WindowManager wm = mContext.getSystemService(WindowManager.class); 3762 wm.removeView(mPointerLocationView); 3763 mPointerLocationView = null; 3764 } 3765 } 3766