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