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