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