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