1 /* 2 * Copyright (C) 2019 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.StatusBarManager.WINDOW_STATE_HIDDEN; 20 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING; 21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 23 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 24 import static android.view.InsetsSource.ID_IME; 25 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; 26 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 27 28 import android.annotation.NonNull; 29 import android.annotation.Nullable; 30 import android.app.ActivityTaskManager; 31 import android.app.StatusBarManager; 32 import android.app.WindowConfiguration; 33 import android.content.ComponentName; 34 import android.content.res.Resources; 35 import android.os.Handler; 36 import android.os.IBinder; 37 import android.util.SparseArray; 38 import android.view.InsetsController; 39 import android.view.InsetsFrameProvider; 40 import android.view.InsetsSource; 41 import android.view.InsetsState; 42 import android.view.SurfaceControl; 43 import android.view.SyncRtSurfaceTransactionApplier; 44 import android.view.WindowInsets; 45 import android.view.WindowInsets.Type; 46 import android.view.WindowInsets.Type.InsetsType; 47 import android.view.WindowInsetsAnimation; 48 import android.view.WindowInsetsAnimation.Bounds; 49 import android.view.WindowManager; 50 import android.view.inputmethod.Flags; 51 import android.view.inputmethod.ImeTracker; 52 import android.view.inputmethod.InputMethodManager; 53 54 import com.android.internal.R; 55 import com.android.internal.annotations.VisibleForTesting; 56 import com.android.server.statusbar.StatusBarManagerInternal; 57 58 import java.io.PrintWriter; 59 import java.util.List; 60 61 /** 62 * Policy that implements who gets control over the windows generating insets. 63 */ 64 class InsetsPolicy { 65 66 public static final int CONTROLLABLE_TYPES = WindowInsets.Type.statusBars() 67 | WindowInsets.Type.navigationBars() 68 | WindowInsets.Type.ime(); 69 70 private final InsetsStateController mStateController; 71 private final DisplayContent mDisplayContent; 72 private final DisplayPolicy mPolicy; 73 74 /** Used to show system bars transiently. This won't affect the layout. */ 75 private final InsetsControlTarget mTransientControlTarget; 76 77 /** Used to show system bars permanently. This will affect the layout. */ 78 private final InsetsControlTarget mPermanentControlTarget; 79 80 /** 81 * Used to override the visibility of {@link Type#statusBars()} when dispatching insets to 82 * clients. 83 */ 84 private InsetsControlTarget mFakeStatusControlTarget; 85 86 /** 87 * Used to override the visibility of {@link Type#navigationBars()} when dispatching insets to 88 * clients. 89 */ 90 private InsetsControlTarget mFakeNavControlTarget; 91 92 private WindowState mFocusedWin; 93 private final BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR); 94 private final BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR); 95 private @InsetsType int mShowingTransientTypes; 96 private @InsetsType int mForcedShowingTypes; 97 98 private final boolean mHideNavBarForKeyboard; 99 InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent)100 InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) { 101 mStateController = stateController; 102 mDisplayContent = displayContent; 103 mPolicy = displayContent.getDisplayPolicy(); 104 final Resources r = mPolicy.getContext().getResources(); 105 mHideNavBarForKeyboard = r.getBoolean(R.bool.config_hideNavBarForKeyboard); 106 mTransientControlTarget = new ControlTarget(displayContent, "TransientControlTarget"); 107 mPermanentControlTarget = new ControlTarget(displayContent, "PermanentControlTarget"); 108 } 109 110 /** Updates the target which can control system bars. */ updateBarControlTarget(@ullable WindowState focusedWin)111 void updateBarControlTarget(@Nullable WindowState focusedWin) { 112 if (mFocusedWin != focusedWin) { 113 abortTransient(); 114 } 115 mFocusedWin = focusedWin; 116 final @InsetsType int[] requestedVisibleTypes = 117 {focusedWin != null ? focusedWin.getRequestedVisibleTypes() : 0}; 118 final WindowState notificationShade = mPolicy.getNotificationShade(); 119 final WindowState topApp = mPolicy.getTopFullscreenOpaqueWindow(); 120 final InsetsControlTarget statusControlTarget = 121 getStatusControlTarget(focusedWin, false /* fake */, requestedVisibleTypes); 122 mFakeStatusControlTarget = statusControlTarget == mTransientControlTarget 123 ? getStatusControlTarget(focusedWin, true /* fake */, requestedVisibleTypes) 124 : statusControlTarget == notificationShade 125 ? getStatusControlTarget(topApp, true /* fake */, requestedVisibleTypes) 126 : null; 127 final InsetsControlTarget navControlTarget = 128 getNavControlTarget(focusedWin, false /* fake */, requestedVisibleTypes); 129 mFakeNavControlTarget = navControlTarget == mTransientControlTarget 130 ? getNavControlTarget(focusedWin, true /* fake */, requestedVisibleTypes) 131 : navControlTarget == notificationShade 132 ? getNavControlTarget(topApp, true /* fake */, requestedVisibleTypes) 133 : null; 134 mStateController.onBarControlTargetChanged( 135 statusControlTarget, mFakeStatusControlTarget, 136 navControlTarget, mFakeNavControlTarget); 137 138 if (statusControlTarget == mDisplayContent.mRemoteInsetsControlTarget 139 && navControlTarget == mDisplayContent.mRemoteInsetsControlTarget) { 140 notifyRemoteInsetsController(focusedWin, requestedVisibleTypes[0]); 141 } 142 143 mStatusBar.updateVisibility(statusControlTarget, Type.statusBars()); 144 mNavBar.updateVisibility(navControlTarget, Type.navigationBars()); 145 } 146 hasHiddenSources(@nsetsType int types)147 boolean hasHiddenSources(@InsetsType int types) { 148 final InsetsState state = mStateController.getRawInsetsState(); 149 for (int i = state.sourceSize() - 1; i >= 0; i--) { 150 final InsetsSource source = state.sourceAt(i); 151 if ((source.getType() & types) == 0) { 152 continue; 153 } 154 if (!source.getFrame().isEmpty() && !source.isVisible()) { 155 return true; 156 } 157 } 158 return false; 159 } 160 showTransient(@nsetsType int types, boolean isGestureOnSystemBar)161 void showTransient(@InsetsType int types, boolean isGestureOnSystemBar) { 162 @InsetsType int showingTransientTypes = mShowingTransientTypes; 163 final InsetsState rawState = mStateController.getRawInsetsState(); 164 for (int i = rawState.sourceSize() - 1; i >= 0; i--) { 165 final InsetsSource source = rawState.sourceAt(i); 166 if (source.isVisible()) { 167 continue; 168 } 169 final @InsetsType int type = source.getType(); 170 if ((source.getType() & types) == 0) { 171 continue; 172 } 173 showingTransientTypes |= type; 174 } 175 if (mShowingTransientTypes != showingTransientTypes) { 176 mShowingTransientTypes = showingTransientTypes; 177 StatusBarManagerInternal statusBarManagerInternal = 178 mPolicy.getStatusBarManagerInternal(); 179 if (statusBarManagerInternal != null) { 180 statusBarManagerInternal.showTransient(mDisplayContent.getDisplayId(), 181 showingTransientTypes, isGestureOnSystemBar); 182 } 183 updateBarControlTarget(mFocusedWin); 184 dispatchTransientSystemBarsVisibilityChanged( 185 mFocusedWin, 186 (showingTransientTypes & (Type.statusBars() | Type.navigationBars())) != 0, 187 isGestureOnSystemBar); 188 } 189 } 190 191 @VisibleForTesting getTransientControlTarget()192 InsetsControlTarget getTransientControlTarget() { 193 return mTransientControlTarget; 194 } 195 196 @VisibleForTesting getPermanentControlTarget()197 InsetsControlTarget getPermanentControlTarget() { 198 return mPermanentControlTarget; 199 } 200 hideTransient()201 void hideTransient() { 202 if (mShowingTransientTypes == 0) { 203 return; 204 } 205 206 dispatchTransientSystemBarsVisibilityChanged( 207 mFocusedWin, 208 /* areVisible= */ false, 209 /* wereRevealedFromSwipeOnSystemBar= */ false); 210 211 mShowingTransientTypes = 0; 212 updateBarControlTarget(mFocusedWin); 213 } 214 isTransient(@nsetsType int type)215 boolean isTransient(@InsetsType int type) { 216 return (mShowingTransientTypes & type) != 0; 217 } 218 219 /** 220 * Adjusts the sources in {@code originalState} to account for things like transient bars, IME 221 * & rounded corners. 222 */ adjustInsetsForWindow(WindowState target, InsetsState originalState, boolean includesTransient)223 InsetsState adjustInsetsForWindow(WindowState target, InsetsState originalState, 224 boolean includesTransient) { 225 InsetsState state; 226 if (!includesTransient) { 227 state = adjustVisibilityForFakeControllingSources(originalState); 228 } else { 229 state = originalState; 230 } 231 state = adjustVisibilityForIme(target, state, state == originalState); 232 state = mPolicy.replaceInsetsSourcesIfNeeded(state, state == originalState); 233 return adjustInsetsForRoundedCorners(target.mToken, state, state == originalState); 234 } 235 adjustInsetsForWindow(WindowState target, InsetsState originalState)236 InsetsState adjustInsetsForWindow(WindowState target, InsetsState originalState) { 237 return adjustInsetsForWindow(target, originalState, false); 238 } 239 240 /** 241 * @see WindowState#getInsetsState() 242 */ getInsetsForWindowMetrics(@ullable WindowToken token, @NonNull InsetsState outInsetsState)243 void getInsetsForWindowMetrics(@Nullable WindowToken token, 244 @NonNull InsetsState outInsetsState) { 245 final InsetsState srcState = token != null && token.isFixedRotationTransforming() 246 ? token.getFixedRotationTransformInsetsState() 247 : mStateController.getRawInsetsState(); 248 outInsetsState.set(srcState, true /* copySources */); 249 for (int i = outInsetsState.sourceSize() - 1; i >= 0; i--) { 250 final InsetsSource source = outInsetsState.sourceAt(i); 251 if (isTransient(source.getType())) { 252 source.setVisible(false); 253 } 254 } 255 adjustInsetsForRoundedCorners(token, outInsetsState, false /* copyState */); 256 if (token != null && token.hasSizeCompatBounds()) { 257 outInsetsState.scale(1f / token.getCompatScale()); 258 } 259 } 260 261 /** 262 * Modifies the given {@code state} according to insets provided by the target. When performing 263 * layout of the target or dispatching insets to the target, we need to exclude sources which 264 * should not be received by the target. e.g., the visible (non-gesture-wise) source provided by 265 * the target window itself. 266 * 267 * We also need to exclude certain types of insets source for client within specific windowing 268 * modes. 269 * 270 * @param target the target on which the policy is applied 271 * @param state the input inset state containing all the sources 272 * @return The state stripped of the necessary information. 273 */ enforceInsetsPolicyForTarget(WindowState target, InsetsState state)274 InsetsState enforceInsetsPolicyForTarget(WindowState target, InsetsState state) { 275 final InsetsState originalState = state; 276 final WindowManager.LayoutParams attrs = target.mAttrs; 277 278 // The caller should not receive the visible insets provided by itself. 279 if (attrs.type == TYPE_INPUT_METHOD) { 280 state = new InsetsState(state); 281 state.removeSource(ID_IME); 282 } else if (attrs.providedInsets != null) { 283 for (InsetsFrameProvider provider : attrs.providedInsets) { 284 if ((provider.getType() & WindowInsets.Type.systemBars()) == 0) { 285 continue; 286 } 287 if (state == originalState) { 288 state = new InsetsState(state); 289 } 290 state.removeSource(provider.getId()); 291 } 292 } 293 294 if (!attrs.isFullscreen() || attrs.getFitInsetsTypes() != 0) { 295 if (state == originalState) { 296 state = new InsetsState(originalState); 297 } 298 // Explicitly exclude floating windows from receiving caption insets. This is because we 299 // hard code caption insets for windows due to a synchronization issue that leads to 300 // flickering that bypasses insets frame calculation, which consequently needs us to 301 // remove caption insets from floating windows. 302 // TODO(b/254128050): Remove this workaround after we find a way to update window frames 303 // and caption insets frames simultaneously. 304 for (int i = state.sourceSize() - 1; i >= 0; i--) { 305 if (state.sourceAt(i).getType() == Type.captionBar()) { 306 state.removeSourceAt(i); 307 } 308 } 309 } 310 311 final SparseArray<InsetsSourceProvider> providers = mStateController.getSourceProviders(); 312 final int windowType = attrs.type; 313 for (int i = providers.size() - 1; i >= 0; i--) { 314 final InsetsSourceProvider otherProvider = providers.valueAt(i); 315 if (otherProvider.overridesFrame(windowType)) { 316 if (state == originalState) { 317 state = new InsetsState(state); 318 } 319 final InsetsSource override = new InsetsSource(otherProvider.getSource()); 320 override.setFrame(otherProvider.getOverriddenFrame(windowType)); 321 state.addSource(override); 322 } 323 } 324 325 final @WindowConfiguration.WindowingMode int windowingMode = target.getWindowingMode(); 326 if (WindowConfiguration.isFloating(windowingMode) 327 || (windowingMode == WINDOWING_MODE_MULTI_WINDOW && target.isAlwaysOnTop())) { 328 // Keep frames, caption, and IME. 329 int types = WindowInsets.Type.captionBar(); 330 if (windowingMode != WINDOWING_MODE_PINNED) { 331 if (!Flags.refactorInsetsController() || (mDisplayContent != null 332 && target == mDisplayContent.getImeInputTarget() 333 && (WindowInsets.Type.ime() & target.getRequestedVisibleTypes()) != 0)) { 334 types |= WindowInsets.Type.ime(); 335 } 336 } 337 final InsetsState newState = new InsetsState(); 338 newState.set(state, types); 339 state = newState; 340 } 341 342 return state; 343 } 344 adjustVisibilityForFakeControllingSources(InsetsState originalState)345 private InsetsState adjustVisibilityForFakeControllingSources(InsetsState originalState) { 346 if (mFakeStatusControlTarget == null && mFakeNavControlTarget == null) { 347 return originalState; 348 } 349 InsetsState state = originalState; 350 for (int i = state.sourceSize() - 1; i >= 0; i--) { 351 final InsetsSource source = state.sourceAt(i); 352 state = adjustVisibilityForFakeControllingSource(state, Type.statusBars(), source, 353 mFakeStatusControlTarget); 354 state = adjustVisibilityForFakeControllingSource(state, Type.navigationBars(), source, 355 mFakeNavControlTarget); 356 } 357 return state; 358 } 359 adjustVisibilityForFakeControllingSource(InsetsState originalState, @InsetsType int type, InsetsSource source, InsetsControlTarget target)360 private static InsetsState adjustVisibilityForFakeControllingSource(InsetsState originalState, 361 @InsetsType int type, InsetsSource source, InsetsControlTarget target) { 362 if (source.getType() != type || target == null) { 363 return originalState; 364 } 365 final boolean isRequestedVisible = target.isRequestedVisible(type); 366 if (source.isVisible() == isRequestedVisible) { 367 return originalState; 368 } 369 // The source will be modified, create a non-deep copy to store the new one. 370 final InsetsState state = new InsetsState(originalState); 371 372 // Replace the source with a copy with the overridden visibility. 373 final InsetsSource outSource = new InsetsSource(source); 374 outSource.setVisible(isRequestedVisible); 375 state.addSource(outSource); 376 return state; 377 } 378 adjustVisibilityForIme(WindowState w, InsetsState originalState, boolean copyState)379 private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState, 380 boolean copyState) { 381 if (w.mIsImWindow) { 382 InsetsState state = originalState; 383 // If navigation bar is not hidden by IME, IME should always receive visible 384 // navigation bar insets. 385 final boolean navVisible = !mHideNavBarForKeyboard; 386 for (int i = originalState.sourceSize() - 1; i >= 0; i--) { 387 final InsetsSource source = originalState.sourceAt(i); 388 if (source.getType() != Type.navigationBars() || source.isVisible() == navVisible) { 389 continue; 390 } 391 if (state == originalState && copyState) { 392 state = new InsetsState(originalState); 393 } 394 final InsetsSource navSource = new InsetsSource(source); 395 navSource.setVisible(navVisible); 396 state.addSource(navSource); 397 } 398 return state; 399 } else if (w.mImeInsetsConsumed) { 400 // Set the IME source (if there is one) to be invisible if it has been consumed. 401 final InsetsSource originalImeSource = originalState.peekSource(ID_IME); 402 if (originalImeSource != null && originalImeSource.isVisible()) { 403 final InsetsState state = copyState 404 ? new InsetsState(originalState) 405 : originalState; 406 final InsetsSource imeSource = new InsetsSource(originalImeSource); 407 imeSource.setVisible(false); 408 state.addSource(imeSource); 409 return state; 410 } 411 } else if (Flags.refactorInsetsController() 412 && (w.mMergedExcludeInsetsTypes & WindowInsets.Type.ime()) != 0) { 413 // In some cases (e.g. split screen from when the IME was requested and the animation 414 // actually starts) the insets should not be send, unless the flag is unset. 415 final InsetsSource originalImeSource = originalState.peekSource(ID_IME); 416 if (originalImeSource != null && originalImeSource.isVisible()) { 417 final InsetsState state = copyState 418 ? new InsetsState(originalState) 419 : originalState; 420 final InsetsSource imeSource = new InsetsSource(originalImeSource); 421 // Setting the height to zero, pretending we're in floating mode 422 imeSource.setFrame(0, 0, 0, 0); 423 imeSource.setVisibleFrame(imeSource.getFrame()); 424 state.addSource(imeSource); 425 return state; 426 } 427 } 428 return originalState; 429 } 430 adjustInsetsForRoundedCorners(WindowToken token, InsetsState originalState, boolean copyState)431 private InsetsState adjustInsetsForRoundedCorners(WindowToken token, InsetsState originalState, 432 boolean copyState) { 433 if (token != null) { 434 final ActivityRecord activityRecord = token.asActivityRecord(); 435 final Task task = activityRecord != null ? activityRecord.getTask() : null; 436 if (task != null && !task.getWindowConfiguration().tasksAreFloating()) { 437 // Use task bounds to calculating rounded corners if the task is not floating. 438 final InsetsState state = copyState ? new InsetsState(originalState) 439 : originalState; 440 state.setRoundedCornerFrame(token.isFixedRotationTransforming() 441 ? token.getFixedRotationTransformDisplayBounds() 442 : task.getBounds()); 443 return state; 444 } 445 } 446 return originalState; 447 } 448 onRequestedVisibleTypesChanged(InsetsTarget caller, @InsetsType int changedTypes, @Nullable ImeTracker.Token statsToken)449 void onRequestedVisibleTypesChanged(InsetsTarget caller, @InsetsType int changedTypes, 450 @Nullable ImeTracker.Token statsToken) { 451 mStateController.onRequestedVisibleTypesChanged(caller, changedTypes, statsToken); 452 checkAbortTransient(caller); 453 updateBarControlTarget(mFocusedWin); 454 } 455 456 /** 457 * Called when a control target modified the insets state. If the target set a insets source to 458 * visible while it is shown transiently, we need to abort the transient state. While IME is 459 * requested visible, we also need to abort the transient state of navigation bar if it is shown 460 * transiently. 461 * 462 * @param caller who changed the insets state. 463 */ checkAbortTransient(InsetsTarget caller)464 private void checkAbortTransient(InsetsTarget caller) { 465 if (mShowingTransientTypes == 0) { 466 return; 467 } 468 final boolean isImeVisible = mStateController.getImeSourceProvider().isClientVisible(); 469 final @InsetsType int fakeControllingTypes = 470 mStateController.getFakeControllingTypes(caller); 471 final @InsetsType int abortTypes = 472 (fakeControllingTypes & caller.getRequestedVisibleTypes()) 473 | (isImeVisible ? Type.navigationBars() : 0); 474 mShowingTransientTypes &= ~abortTypes; 475 if (abortTypes != 0) { 476 mDisplayContent.setLayoutNeeded(); 477 mDisplayContent.mWmService.requestTraversal(); 478 final StatusBarManagerInternal statusBarManager = mPolicy.getStatusBarManagerInternal(); 479 if (statusBarManager != null) { 480 statusBarManager.abortTransient(mDisplayContent.getDisplayId(), abortTypes); 481 } 482 } 483 } 484 485 /** 486 * If the caller is not {@link #updateBarControlTarget}, it should call 487 * updateBarControlTarget(mFocusedWin) after this invocation. 488 */ abortTransient()489 private void abortTransient() { 490 if (mShowingTransientTypes == 0) { 491 return; 492 } 493 final StatusBarManagerInternal statusBarManager = mPolicy.getStatusBarManagerInternal(); 494 if (statusBarManager != null) { 495 statusBarManager.abortTransient(mDisplayContent.getDisplayId(), mShowingTransientTypes); 496 } 497 mShowingTransientTypes = 0; 498 mDisplayContent.setLayoutNeeded(); 499 mDisplayContent.mWmService.requestTraversal(); 500 501 dispatchTransientSystemBarsVisibilityChanged( 502 mFocusedWin, 503 /* areVisible= */ false, 504 /* wereRevealedFromSwipeOnSystemBar= */ false); 505 } 506 getStatusControlTarget(@ullable WindowState focusedWin, boolean fake, @InsetsType int[] requestedVisibleTypes)507 private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin, 508 boolean fake, @InsetsType int[] requestedVisibleTypes) { 509 final InsetsControlTarget target = getStatusControlTargetInner(focusedWin, fake); 510 if (remoteInsetsControllerControlsSystemBars(target)) { 511 requestedVisibleTypes[0] = (requestedVisibleTypes[0] & ~Type.statusBars()) | ( 512 target.getRequestedVisibleTypes() & Type.statusBars()); 513 return mDisplayContent.mRemoteInsetsControlTarget; 514 } 515 return target; 516 } 517 getStatusControlTargetInner( @ullable WindowState focusedWin, boolean fake)518 private @Nullable InsetsControlTarget getStatusControlTargetInner( 519 @Nullable WindowState focusedWin, 520 boolean fake) { 521 if (!fake && isTransient(Type.statusBars())) { 522 return mTransientControlTarget; 523 } 524 final WindowState notificationShade = mPolicy.getNotificationShade(); 525 if (focusedWin == notificationShade) { 526 // Notification shade has control anyways, no reason to force anything. 527 return focusedWin; 528 } 529 if (areTypesForciblyShowing(Type.statusBars())) { 530 // Status bar is forcibly shown. We don't want the client to control the status bar, and 531 // we will dispatch the real visibility of status bar to the client. 532 return mPermanentControlTarget; 533 } 534 if (mPolicy.areTypesForciblyShownTransiently(Type.statusBars()) && !fake) { 535 // Status bar is forcibly shown transiently, and its new visibility won't be 536 // dispatched to the client so that we can keep the layout stable. We will dispatch the 537 // fake control to the client, so that it can re-show the bar during this scenario. 538 return mTransientControlTarget; 539 } 540 if (!canBeTopFullscreenOpaqueWindow(focusedWin) 541 && mPolicy.topAppHidesSystemBar(Type.statusBars()) 542 && (notificationShade == null || !notificationShade.canReceiveKeys())) { 543 // Non-fullscreen focused window should not break the state that the top-fullscreen-app 544 // window hides status bar, unless the notification shade can receive keys. 545 return mPolicy.getTopFullscreenOpaqueWindow(); 546 } 547 return focusedWin; 548 } 549 canBeTopFullscreenOpaqueWindow(@ullable WindowState win)550 private static boolean canBeTopFullscreenOpaqueWindow(@Nullable WindowState win) { 551 // The condition doesn't use WindowState#canAffectSystemUiFlags because the window may 552 // haven't drawn or committed the visibility. 553 final boolean nonAttachedAppWindow = win != null 554 && win.mAttrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW 555 && win.mAttrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 556 return nonAttachedAppWindow && win.mAttrs.isFullscreen() && !win.isFullyTransparent() 557 && !win.inMultiWindowMode(); 558 } 559 getNavControlTarget(@ullable WindowState focusedWin, boolean fake, @InsetsType int[] requestedVisibleTypes)560 private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin, 561 boolean fake, @InsetsType int[] requestedVisibleTypes) { 562 final InsetsControlTarget target = getNavControlTargetInner(focusedWin, fake); 563 if (remoteInsetsControllerControlsSystemBars(target)) { 564 requestedVisibleTypes[0] = (requestedVisibleTypes[0] & ~Type.navigationBars()) | ( 565 target.getRequestedVisibleTypes() & Type.navigationBars()); 566 return mDisplayContent.mRemoteInsetsControlTarget; 567 } 568 return target; 569 } 570 getNavControlTargetInner(@ullable WindowState focusedWin, boolean fake)571 private @Nullable InsetsControlTarget getNavControlTargetInner(@Nullable WindowState focusedWin, 572 boolean fake) { 573 final WindowState imeWin = mDisplayContent.mInputMethodWindow; 574 if (imeWin != null && imeWin.isVisible() && !mHideNavBarForKeyboard) { 575 // Force showing navigation bar while IME is visible and if navigation bar is not 576 // configured to be hidden by the IME. 577 return mPermanentControlTarget; 578 } 579 if (!fake && isTransient(Type.navigationBars())) { 580 return mTransientControlTarget; 581 } 582 if (focusedWin == mPolicy.getNotificationShade()) { 583 // Notification shade has control anyways, no reason to force anything. 584 return focusedWin; 585 } 586 if (focusedWin != null) { 587 final InsetsSourceProvider provider = focusedWin.getControllableInsetProvider(); 588 if (provider != null && provider.getSource().getType() == Type.navigationBars()) { 589 // Navigation bar has control if it is focused. 590 return focusedWin; 591 } 592 } 593 if (areTypesForciblyShowing(Type.navigationBars())) { 594 // Navigation bar is forcibly shown. We don't want the client to control the navigation 595 // bar, and we will dispatch the real visibility of navigation bar to the client. 596 return mPermanentControlTarget; 597 } 598 if (mPolicy.areTypesForciblyShownTransiently(Type.navigationBars()) && !fake) { 599 // Navigation bar is forcibly shown transiently, and its new visibility won't be 600 // dispatched to the client so that we can keep the layout stable. We will dispatch the 601 // fake control to the client, so that it can re-show the bar during this scenario. 602 return mTransientControlTarget; 603 } 604 final WindowState notificationShade = mPolicy.getNotificationShade(); 605 if (!canBeTopFullscreenOpaqueWindow(focusedWin) 606 && mPolicy.topAppHidesSystemBar(Type.navigationBars()) 607 && (notificationShade == null || !notificationShade.canReceiveKeys())) { 608 // Non-fullscreen focused window should not break the state that the top-fullscreen-app 609 // window hides navigation bar, unless the notification shade can receive keys. 610 return mPolicy.getTopFullscreenOpaqueWindow(); 611 } 612 return focusedWin; 613 } 614 notifyRemoteInsetsController(@ullable WindowState win, @InsetsType int requestVisibleTypes)615 private void notifyRemoteInsetsController(@Nullable WindowState win, 616 @InsetsType int requestVisibleTypes) { 617 if (win == null) { 618 return; 619 } 620 ComponentName component = win.mActivityRecord != null 621 ? win.mActivityRecord.mActivityComponent : null; 622 623 mDisplayContent.mRemoteInsetsControlTarget.topFocusedWindowChanged( 624 component, requestVisibleTypes); 625 } 626 areTypesForciblyShowing(@nsetsType int types)627 boolean areTypesForciblyShowing(@InsetsType int types) { 628 return (mForcedShowingTypes & types) == types; 629 } 630 updateSystemBars(WindowState win, boolean inSplitScreenMode, boolean inNonFullscreenFreeformMode)631 void updateSystemBars(WindowState win, boolean inSplitScreenMode, 632 boolean inNonFullscreenFreeformMode) { 633 mForcedShowingTypes = (inSplitScreenMode || inNonFullscreenFreeformMode) 634 ? (Type.statusBars() | Type.navigationBars()) 635 : forceShowingNavigationBars(win) 636 ? Type.navigationBars() 637 : 0; 638 639 // The client app won't be able to control these types of system bars. Here makes the client 640 // forcibly consume these types to prevent the app content from getting obscured. 641 mStateController.setForcedConsumingTypes( 642 mForcedShowingTypes | (remoteInsetsControllerControlsSystemBars(win) 643 ? (Type.statusBars() | Type.navigationBars()) 644 : 0)); 645 646 updateBarControlTarget(win); 647 } 648 forceShowingNavigationBars(WindowState win)649 private boolean forceShowingNavigationBars(WindowState win) { 650 // When "force show navigation bar" is enabled, it means both force visible is true, and 651 // we are in 3-button navigation. In this mode, the navigation bar is forcibly shown 652 // when activity type is ACTIVITY_TYPE_STANDARD which means Launcher or Recent could 653 // still control the navigation bar in this mode. 654 return mPolicy.isForceShowNavigationBarEnabled() && win != null 655 && win.getActivityType() == ACTIVITY_TYPE_STANDARD; 656 } 657 658 /** 659 * Determines whether the remote insets controller should take control of system bars for all 660 * windows. 661 */ remoteInsetsControllerControlsSystemBars(@ullable InsetsControlTarget target)662 boolean remoteInsetsControllerControlsSystemBars(@Nullable InsetsControlTarget target) { 663 if (!(target instanceof WindowState win)) { 664 return false; 665 } 666 667 if (!mPolicy.isRemoteInsetsControllerControllingSystemBars()) { 668 return false; 669 } 670 if (mDisplayContent == null || mDisplayContent.mRemoteInsetsControlTarget == null) { 671 // No remote insets control target to take control of insets. 672 return false; 673 } 674 // If necessary, auto can control application windows when 675 // config_remoteInsetsControllerControlsSystemBars is set to true. This is useful in cases 676 // where we want to dictate system bar inset state for applications. 677 return win.mAttrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW 678 && win.mAttrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 679 } 680 dispatchTransientSystemBarsVisibilityChanged( @ullable WindowState focusedWindow, boolean areVisible, boolean wereRevealedFromSwipeOnSystemBar)681 private void dispatchTransientSystemBarsVisibilityChanged( 682 @Nullable WindowState focusedWindow, 683 boolean areVisible, 684 boolean wereRevealedFromSwipeOnSystemBar) { 685 if (focusedWindow == null) { 686 return; 687 } 688 689 Task task = focusedWindow.getTask(); 690 if (task == null) { 691 return; 692 } 693 694 int taskId = task.mTaskId; 695 boolean isValidTaskId = taskId != ActivityTaskManager.INVALID_TASK_ID; 696 if (!isValidTaskId) { 697 return; 698 } 699 700 mDisplayContent.mWmService.mTaskSystemBarsListenerController 701 .dispatchTransientSystemBarVisibilityChanged( 702 taskId, 703 areVisible, 704 wereRevealedFromSwipeOnSystemBar); 705 } 706 dump(String prefix, PrintWriter pw)707 void dump(String prefix, PrintWriter pw) { 708 pw.println(prefix + "InsetsPolicy"); 709 prefix = prefix + " "; 710 pw.println(prefix + "status: " + StatusBarManager.windowStateToString(mStatusBar.mState)); 711 pw.println(prefix + "nav: " + StatusBarManager.windowStateToString(mNavBar.mState)); 712 if (mShowingTransientTypes != 0) { 713 pw.println(prefix + "mShowingTransientTypes=" 714 + WindowInsets.Type.toString(mShowingTransientTypes)); 715 } 716 if (mForcedShowingTypes != 0) { 717 pw.println(prefix + "mForcedShowingTypes=" 718 + WindowInsets.Type.toString(mForcedShowingTypes)); 719 } 720 } 721 722 private class BarWindow { 723 724 private final int mId; 725 private @StatusBarManager.WindowVisibleState int mState = 726 StatusBarManager.WINDOW_STATE_SHOWING; 727 BarWindow(int id)728 BarWindow(int id) { 729 mId = id; 730 } 731 updateVisibility(@ullable InsetsControlTarget controlTarget, @InsetsType int type)732 private void updateVisibility(@Nullable InsetsControlTarget controlTarget, 733 @InsetsType int type) { 734 setVisible(controlTarget == null || controlTarget.isRequestedVisible(type)); 735 } 736 setVisible(boolean visible)737 private void setVisible(boolean visible) { 738 final int state = visible ? WINDOW_STATE_SHOWING : WINDOW_STATE_HIDDEN; 739 if (mState != state) { 740 mState = state; 741 StatusBarManagerInternal statusBarManagerInternal = 742 mPolicy.getStatusBarManagerInternal(); 743 if (statusBarManagerInternal != null) { 744 statusBarManagerInternal.setWindowState( 745 mDisplayContent.getDisplayId(), mId, state); 746 } 747 } 748 } 749 } 750 751 private static class ControlTarget implements InsetsControlTarget, Runnable { 752 753 private final Handler mHandler; 754 private final Object mGlobalLock; 755 private final InsetsState mState = new InsetsState(); 756 private final InsetsStateController mStateController; 757 private final InsetsController mInsetsController; 758 private final String mName; 759 ControlTarget(DisplayContent displayContent, String name)760 ControlTarget(DisplayContent displayContent, String name) { 761 mHandler = displayContent.mWmService.mH; 762 mGlobalLock = displayContent.mWmService.mGlobalLock; 763 mStateController = displayContent.getInsetsStateController(); 764 mInsetsController = new InsetsController(new Host(mHandler, name)); 765 mName = name; 766 } 767 768 @Override notifyInsetsControlChanged(int displayId)769 public void notifyInsetsControlChanged(int displayId) { 770 mHandler.post(this); 771 } 772 773 @Override run()774 public void run() { 775 synchronized (mGlobalLock) { 776 mState.set(mStateController.getRawInsetsState(), true /* copySources */); 777 mInsetsController.onStateChanged(mState); 778 mInsetsController.onControlsChanged(mStateController.getControlsForDispatch(this)); 779 } 780 } 781 782 @Override toString()783 public String toString() { 784 return mName; 785 } 786 } 787 788 private static class Host implements InsetsController.Host { 789 790 private final float[] mTmpFloat9 = new float[9]; 791 private final Handler mHandler; 792 private final String mName; 793 Host(Handler handler, String name)794 Host(Handler handler, String name) { 795 mHandler = handler; 796 mName = name; 797 } 798 799 @Override getHandler()800 public Handler getHandler() { 801 return mHandler; 802 } 803 804 @Override notifyInsetsChanged()805 public void notifyInsetsChanged() { 806 } 807 808 @Override dispatchWindowInsetsAnimationPrepare( @onNull WindowInsetsAnimation animation)809 public void dispatchWindowInsetsAnimationPrepare( 810 @NonNull WindowInsetsAnimation animation) { 811 } 812 813 @Override dispatchWindowInsetsAnimationStart( @onNull WindowInsetsAnimation animation, @NonNull Bounds bounds)814 public Bounds dispatchWindowInsetsAnimationStart( 815 @NonNull WindowInsetsAnimation animation, 816 @NonNull Bounds bounds) { 817 return bounds; 818 } 819 820 @Override dispatchWindowInsetsAnimationProgress( @onNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations)821 public WindowInsets dispatchWindowInsetsAnimationProgress( 822 @NonNull WindowInsets insets, 823 @NonNull List<WindowInsetsAnimation> runningAnimations) { 824 return insets; 825 } 826 827 @Override dispatchWindowInsetsAnimationEnd( @onNull WindowInsetsAnimation animation)828 public void dispatchWindowInsetsAnimationEnd( 829 @NonNull WindowInsetsAnimation animation) { 830 } 831 832 @Override applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... p)833 public void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... p) { 834 final SurfaceControl.Transaction t = new SurfaceControl.Transaction(); 835 for (int i = p.length - 1; i >= 0; i--) { 836 SyncRtSurfaceTransactionApplier.applyParams(t, p[i], mTmpFloat9); 837 } 838 t.apply(); 839 t.close(); 840 } 841 842 @Override updateRequestedVisibleTypes(int types, @Nullable ImeTracker.Token statsToken)843 public void updateRequestedVisibleTypes(int types, @Nullable ImeTracker.Token statsToken) { 844 } 845 846 @Override hasAnimationCallbacks()847 public boolean hasAnimationCallbacks() { 848 return false; 849 } 850 851 @Override setSystemBarsAppearance(int appearance, int mask)852 public void setSystemBarsAppearance(int appearance, int mask) { 853 } 854 855 @Override getSystemBarsAppearance()856 public int getSystemBarsAppearance() { 857 return 0; 858 } 859 860 @Override setSystemBarsBehavior(int behavior)861 public void setSystemBarsBehavior(int behavior) { 862 } 863 864 @Override getSystemBarsBehavior()865 public int getSystemBarsBehavior() { 866 return BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; 867 } 868 869 @Override releaseSurfaceControlFromRt(SurfaceControl surfaceControl)870 public void releaseSurfaceControlFromRt(SurfaceControl surfaceControl) { 871 surfaceControl.release(); 872 } 873 874 @Override addOnPreDrawRunnable(Runnable r)875 public void addOnPreDrawRunnable(Runnable r) { 876 } 877 878 @Override postInsetsAnimationCallback(Runnable r)879 public void postInsetsAnimationCallback(Runnable r) { 880 } 881 882 @Override getInputMethodManager()883 public InputMethodManager getInputMethodManager() { 884 return null; 885 } 886 887 @Nullable 888 @Override getRootViewTitle()889 public String getRootViewTitle() { 890 return mName; 891 } 892 893 @Override dipToPx(int dips)894 public int dipToPx(int dips) { 895 return 0; 896 } 897 898 @Nullable 899 @Override getWindowToken()900 public IBinder getWindowToken() { 901 return null; 902 } 903 } 904 } 905