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.WINDOWING_MODE_FREEFORM; 22 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 23 import static android.view.InsetsController.ANIMATION_TYPE_HIDE; 24 import static android.view.InsetsController.ANIMATION_TYPE_SHOW; 25 import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN; 26 import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN; 27 import static android.view.InsetsState.ITYPE_IME; 28 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; 29 import static android.view.InsetsState.ITYPE_STATUS_BAR; 30 import static android.view.SyncRtSurfaceTransactionApplier.applyParams; 31 import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; 32 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR; 33 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION; 34 35 import android.annotation.NonNull; 36 import android.annotation.Nullable; 37 import android.app.StatusBarManager; 38 import android.util.IntArray; 39 import android.util.SparseArray; 40 import android.view.InsetsAnimationControlCallbacks; 41 import android.view.InsetsAnimationControlImpl; 42 import android.view.InsetsAnimationControlRunner; 43 import android.view.InsetsController; 44 import android.view.InsetsSource; 45 import android.view.InsetsSourceControl; 46 import android.view.InsetsState; 47 import android.view.InsetsState.InternalInsetsType; 48 import android.view.SurfaceControl; 49 import android.view.SyncRtSurfaceTransactionApplier; 50 import android.view.WindowInsetsAnimation; 51 import android.view.WindowInsetsAnimation.Bounds; 52 import android.view.WindowInsetsAnimationControlListener; 53 import android.view.WindowManager; 54 55 import com.android.internal.R; 56 import com.android.internal.annotations.VisibleForTesting; 57 import com.android.server.DisplayThread; 58 59 /** 60 * Policy that implements who gets control over the windows generating insets. 61 */ 62 class InsetsPolicy { 63 64 private final InsetsStateController mStateController; 65 private final DisplayContent mDisplayContent; 66 private final DisplayPolicy mPolicy; 67 private final IntArray mShowingTransientTypes = new IntArray(); 68 69 /** For resetting visibilities of insets sources. */ 70 private final InsetsControlTarget mDummyControlTarget = new InsetsControlTarget() { 71 72 @Override 73 public void notifyInsetsControlChanged() { 74 boolean hasLeash = false; 75 final InsetsSourceControl[] controls = 76 mStateController.getControlsForDispatch(this); 77 if (controls == null) { 78 return; 79 } 80 for (InsetsSourceControl control : controls) { 81 final @InternalInsetsType int type = control.getType(); 82 if (mShowingTransientTypes.indexOf(type) != -1) { 83 // The visibilities of transient bars will be handled with animations. 84 continue; 85 } 86 final SurfaceControl leash = control.getLeash(); 87 if (leash != null) { 88 hasLeash = true; 89 90 // We use alpha to control the visibility here which aligns the logic at 91 // SurfaceAnimator.createAnimationLeash 92 mDisplayContent.getPendingTransaction().setAlpha( 93 leash, InsetsState.getDefaultVisibility(type) ? 1f : 0f); 94 } 95 } 96 if (hasLeash) { 97 mDisplayContent.scheduleAnimation(); 98 } 99 } 100 }; 101 102 private WindowState mFocusedWin; 103 private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR); 104 private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR); 105 private boolean mAnimatingShown; 106 /** 107 * Let remote insets controller control system bars regardless of other settings. 108 */ 109 private boolean mRemoteInsetsControllerControlsSystemBars; 110 private final float[] mTmpFloat9 = new float[9]; 111 InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent)112 InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) { 113 mStateController = stateController; 114 mDisplayContent = displayContent; 115 mPolicy = displayContent.getDisplayPolicy(); 116 mRemoteInsetsControllerControlsSystemBars = mPolicy.getContext().getResources().getBoolean( 117 R.bool.config_remoteInsetsControllerControlsSystemBars); 118 } 119 getRemoteInsetsControllerControlsSystemBars()120 boolean getRemoteInsetsControllerControlsSystemBars() { 121 return mRemoteInsetsControllerControlsSystemBars; 122 } 123 124 /** 125 * Used only for testing. 126 */ 127 @VisibleForTesting setRemoteInsetsControllerControlsSystemBars(boolean controlsSystemBars)128 void setRemoteInsetsControllerControlsSystemBars(boolean controlsSystemBars) { 129 mRemoteInsetsControllerControlsSystemBars = controlsSystemBars; 130 } 131 132 /** Updates the target which can control system bars. */ updateBarControlTarget(@ullable WindowState focusedWin)133 void updateBarControlTarget(@Nullable WindowState focusedWin) { 134 if (mFocusedWin != focusedWin){ 135 abortTransient(); 136 } 137 mFocusedWin = focusedWin; 138 boolean forceShowsSystemBarsForWindowingMode = forceShowsSystemBarsForWindowingMode(); 139 InsetsControlTarget statusControlTarget = getStatusControlTarget(focusedWin, 140 forceShowsSystemBarsForWindowingMode); 141 InsetsControlTarget navControlTarget = getNavControlTarget(focusedWin, 142 forceShowsSystemBarsForWindowingMode); 143 mStateController.onBarControlTargetChanged(statusControlTarget, 144 getFakeControlTarget(focusedWin, statusControlTarget), 145 navControlTarget, 146 getFakeControlTarget(focusedWin, navControlTarget)); 147 mStatusBar.updateVisibility(statusControlTarget, ITYPE_STATUS_BAR); 148 mNavBar.updateVisibility(navControlTarget, ITYPE_NAVIGATION_BAR); 149 } 150 isHidden(@nternalInsetsType int type)151 boolean isHidden(@InternalInsetsType int type) { 152 final InsetsSourceProvider provider = mStateController.peekSourceProvider(type); 153 return provider != null && provider.hasWindow() && !provider.getSource().isVisible(); 154 } 155 showTransient(@nternalInsetsType int[] types)156 void showTransient(@InternalInsetsType int[] types) { 157 boolean changed = false; 158 for (int i = types.length - 1; i >= 0; i--) { 159 final @InternalInsetsType int type = types[i]; 160 if (!isHidden(type)) { 161 continue; 162 } 163 if (mShowingTransientTypes.indexOf(type) != -1) { 164 continue; 165 } 166 mShowingTransientTypes.add(type); 167 changed = true; 168 } 169 if (changed) { 170 mPolicy.getStatusBarManagerInternal().showTransient(mDisplayContent.getDisplayId(), 171 mShowingTransientTypes.toArray()); 172 updateBarControlTarget(mFocusedWin); 173 174 // The leashes can be created while updating bar control target. The surface transaction 175 // of the new leashes might not be applied yet. The callback posted here ensures we can 176 // get the valid leashes because the surface transaction will be applied in the next 177 // animation frame which will be triggered if a new leash is created. 178 mDisplayContent.mWmService.mAnimator.getChoreographer().postFrameCallback(time -> { 179 synchronized (mDisplayContent.mWmService.mGlobalLock) { 180 startAnimation(true /* show */, null /* callback */); 181 } 182 }); 183 } 184 } 185 hideTransient()186 void hideTransient() { 187 if (mShowingTransientTypes.size() == 0) { 188 return; 189 } 190 startAnimation(false /* show */, () -> { 191 synchronized (mDisplayContent.mWmService.mGlobalLock) { 192 for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) { 193 // We are about to clear mShowingTransientTypes, we don't want the transient bar 194 // can cause insets on the client. Restore the client visibility. 195 final @InternalInsetsType int type = mShowingTransientTypes.get(i); 196 mStateController.getSourceProvider(type).setClientVisible(false); 197 } 198 mShowingTransientTypes.clear(); 199 updateBarControlTarget(mFocusedWin); 200 } 201 }); 202 } 203 isTransient(@nternalInsetsType int type)204 boolean isTransient(@InternalInsetsType int type) { 205 return mShowingTransientTypes.indexOf(type) != -1; 206 } 207 208 /** 209 * @see InsetsStateController#getInsetsForWindow 210 */ getInsetsForWindow(WindowState target)211 InsetsState getInsetsForWindow(WindowState target) { 212 final InsetsState originalState = mStateController.getInsetsForWindow(target); 213 final InsetsState state = adjustVisibilityForTransientTypes(originalState); 214 return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state; 215 } 216 217 /** 218 * @see InsetsStateController#getInsetsForWindowMetrics 219 */ getInsetsForWindowMetrics(@onNull WindowManager.LayoutParams attrs)220 InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) { 221 final InsetsState originalState = mStateController.getInsetsForWindowMetrics(attrs); 222 return adjustVisibilityForTransientTypes(originalState); 223 } 224 adjustVisibilityForTransientTypes(InsetsState originalState)225 private InsetsState adjustVisibilityForTransientTypes(InsetsState originalState) { 226 InsetsState state = originalState; 227 for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) { 228 final @InternalInsetsType int type = mShowingTransientTypes.get(i); 229 final InsetsSource originalSource = state.peekSource(type); 230 if (originalSource != null && originalSource.isVisible()) { 231 if (state == originalState) { 232 // The source will be modified, create a non-deep copy to store the new one. 233 state = new InsetsState(originalState); 234 } 235 // Replace the source with a copy in invisible state. 236 final InsetsSource source = new InsetsSource(originalSource); 237 source.setVisible(false); 238 state.addSource(source); 239 } 240 } 241 return state; 242 } 243 244 // Navigation bar insets is always visible to IME. adjustVisibilityForIme(InsetsState originalState, boolean copyState)245 private static InsetsState adjustVisibilityForIme(InsetsState originalState, 246 boolean copyState) { 247 final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR); 248 if (originalNavSource != null && !originalNavSource.isVisible()) { 249 final InsetsState state = copyState ? new InsetsState(originalState) : originalState; 250 final InsetsSource navSource = new InsetsSource(originalNavSource); 251 navSource.setVisible(true); 252 state.addSource(navSource); 253 return state; 254 } 255 return originalState; 256 } 257 onInsetsModified(InsetsControlTarget caller)258 void onInsetsModified(InsetsControlTarget caller) { 259 mStateController.onInsetsModified(caller); 260 checkAbortTransient(caller); 261 updateBarControlTarget(mFocusedWin); 262 } 263 264 /** 265 * Called when a control target modified the insets state. If the target set a insets source to 266 * visible while it is shown transiently, we need to abort the transient state. While IME is 267 * requested visible, we also need to abort the transient state of navigation bar if it is shown 268 * transiently. 269 * 270 * @param caller who changed the insets state. 271 */ checkAbortTransient(InsetsControlTarget caller)272 private void checkAbortTransient(InsetsControlTarget caller) { 273 if (mShowingTransientTypes.size() != 0) { 274 final IntArray abortTypes = new IntArray(); 275 final boolean imeRequestedVisible = caller.getRequestedVisibility(ITYPE_IME); 276 for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) { 277 final @InternalInsetsType int type = mShowingTransientTypes.get(i); 278 if ((mStateController.isFakeTarget(type, caller) 279 && caller.getRequestedVisibility(type)) 280 || (type == ITYPE_NAVIGATION_BAR && imeRequestedVisible)) { 281 mShowingTransientTypes.remove(i); 282 abortTypes.add(type); 283 } 284 } 285 if (abortTypes.size() > 0) { 286 mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(), 287 abortTypes.toArray()); 288 } 289 } 290 } 291 292 /** 293 * If the caller is not {@link #updateBarControlTarget}, it should call 294 * updateBarControlTarget(mFocusedWin) after this invocation. 295 */ abortTransient()296 private void abortTransient() { 297 mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(), 298 mShowingTransientTypes.toArray()); 299 mShowingTransientTypes.clear(); 300 } 301 getFakeControlTarget(@ullable WindowState focused, InsetsControlTarget realControlTarget)302 private @Nullable InsetsControlTarget getFakeControlTarget(@Nullable WindowState focused, 303 InsetsControlTarget realControlTarget) { 304 return realControlTarget == mDummyControlTarget ? focused : null; 305 } 306 getStatusControlTarget(@ullable WindowState focusedWin, boolean forceShowsSystemBarsForWindowingMode)307 private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin, 308 boolean forceShowsSystemBarsForWindowingMode) { 309 if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1) { 310 return mDummyControlTarget; 311 } 312 final WindowState notificationShade = mPolicy.getNotificationShade(); 313 if (focusedWin == notificationShade) { 314 // Notification shade has control anyways, no reason to force anything. 315 return focusedWin; 316 } 317 if (remoteInsetsControllerControlsSystemBars(focusedWin)) { 318 mDisplayContent.mRemoteInsetsControlTarget.topFocusedWindowChanged( 319 focusedWin.mAttrs.packageName); 320 return mDisplayContent.mRemoteInsetsControlTarget; 321 } 322 if (forceShowsSystemBarsForWindowingMode) { 323 // Status bar is forcibly shown for the windowing mode which is a steady state. 324 // We don't want the client to control the status bar, and we will dispatch the real 325 // visibility of status bar to the client. 326 return null; 327 } 328 if (forceShowsStatusBarTransiently()) { 329 // Status bar is forcibly shown transiently, and its new visibility won't be 330 // dispatched to the client so that we can keep the layout stable. We will dispatch the 331 // fake control to the client, so that it can re-show the bar during this scenario. 332 return mDummyControlTarget; 333 } 334 if (!canBeTopFullscreenOpaqueWindow(focusedWin) && mPolicy.topAppHidesStatusBar() 335 && (notificationShade == null || !notificationShade.canReceiveKeys())) { 336 // Non-fullscreen focused window should not break the state that the top-fullscreen-app 337 // window hides status bar, unless the notification shade can receive keys. 338 return mPolicy.getTopFullscreenOpaqueWindow(); 339 } 340 return focusedWin; 341 } 342 canBeTopFullscreenOpaqueWindow(@ullable WindowState win)343 private static boolean canBeTopFullscreenOpaqueWindow(@Nullable WindowState win) { 344 // The condition doesn't use WindowState#canAffectSystemUiFlags because the window may 345 // haven't drawn or committed the visibility. 346 final boolean nonAttachedAppWindow = win != null 347 && win.mAttrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW 348 && win.mAttrs.type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 349 return nonAttachedAppWindow && win.mAttrs.isFullscreen() && !win.isFullyTransparent() 350 && !win.inMultiWindowMode(); 351 } 352 getNavControlTarget(@ullable WindowState focusedWin, boolean forceShowsSystemBarsForWindowingMode)353 private @Nullable InsetsControlTarget getNavControlTarget(@Nullable WindowState focusedWin, 354 boolean forceShowsSystemBarsForWindowingMode) { 355 final WindowState imeWin = mDisplayContent.mInputMethodWindow; 356 if (imeWin != null && imeWin.isVisible()) { 357 // Force showing navigation bar while IME is visible. 358 return null; 359 } 360 if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1) { 361 return mDummyControlTarget; 362 } 363 if (focusedWin == mPolicy.getNotificationShade()) { 364 // Notification shade has control anyways, no reason to force anything. 365 return focusedWin; 366 } 367 if (remoteInsetsControllerControlsSystemBars(focusedWin)) { 368 mDisplayContent.mRemoteInsetsControlTarget.topFocusedWindowChanged( 369 focusedWin.mAttrs.packageName); 370 return mDisplayContent.mRemoteInsetsControlTarget; 371 } 372 if (forceShowsSystemBarsForWindowingMode) { 373 // Navigation bar is forcibly shown for the windowing mode which is a steady state. 374 // We don't want the client to control the navigation bar, and we will dispatch the real 375 // visibility of navigation bar to the client. 376 return null; 377 } 378 if (forceShowsNavigationBarTransiently()) { 379 // Navigation bar is forcibly shown transiently, and its new visibility won't be 380 // dispatched to the client so that we can keep the layout stable. We will dispatch the 381 // fake control to the client, so that it can re-show the bar during this scenario. 382 return mDummyControlTarget; 383 } 384 return focusedWin; 385 } 386 387 /** 388 * Determines whether the remote insets controller should take control of system bars for all 389 * windows. 390 */ remoteInsetsControllerControlsSystemBars(@ullable WindowState focusedWin)391 boolean remoteInsetsControllerControlsSystemBars(@Nullable WindowState focusedWin) { 392 if (focusedWin == null) { 393 return false; 394 } 395 if (!mRemoteInsetsControllerControlsSystemBars) { 396 return false; 397 } 398 if (mDisplayContent == null || mDisplayContent.mRemoteInsetsControlTarget == null) { 399 // No remote insets control target to take control of insets. 400 return false; 401 } 402 // If necessary, auto can control application windows when 403 // config_remoteInsetsControllerControlsSystemBars is set to true. This is useful in cases 404 // where we want to dictate system bar inset state for applications. 405 return focusedWin.getAttrs().type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW 406 && focusedWin.getAttrs().type <= WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 407 } 408 forceShowsStatusBarTransiently()409 private boolean forceShowsStatusBarTransiently() { 410 final WindowState win = mPolicy.getStatusBar(); 411 return win != null && (win.mAttrs.privateFlags & PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR) != 0; 412 } 413 forceShowsNavigationBarTransiently()414 private boolean forceShowsNavigationBarTransiently() { 415 final WindowState win = mPolicy.getNotificationShade(); 416 return win != null 417 && (win.mAttrs.privateFlags & PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION) != 0; 418 } 419 forceShowsSystemBarsForWindowingMode()420 private boolean forceShowsSystemBarsForWindowingMode() { 421 final boolean isDockedRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea() 422 .isRootTaskVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); 423 final boolean isFreeformRootTaskVisible = mDisplayContent.getDefaultTaskDisplayArea() 424 .isRootTaskVisible(WINDOWING_MODE_FREEFORM); 425 final boolean isResizing = mDisplayContent.getDockedDividerController().isResizing(); 426 427 // We need to force system bars when the docked root task is visible, when the freeform 428 // root task is visible but also when we are resizing for the transitions when docked 429 // root task visibility changes. 430 return isDockedRootTaskVisible || isFreeformRootTaskVisible || isResizing; 431 } 432 433 @VisibleForTesting startAnimation(boolean show, Runnable callback)434 void startAnimation(boolean show, Runnable callback) { 435 int typesReady = 0; 436 final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); 437 final IntArray showingTransientTypes = mShowingTransientTypes; 438 for (int i = showingTransientTypes.size() - 1; i >= 0; i--) { 439 final @InternalInsetsType int type = showingTransientTypes.get(i); 440 InsetsSourceProvider provider = mStateController.getSourceProvider(type); 441 InsetsSourceControl control = provider.getControl(mDummyControlTarget); 442 if (control == null || control.getLeash() == null) { 443 continue; 444 } 445 typesReady |= InsetsState.toPublicType(type); 446 controls.put(control.getType(), new InsetsSourceControl(control)); 447 } 448 controlAnimationUnchecked(typesReady, controls, show, callback); 449 } 450 controlAnimationUnchecked(int typesReady, SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback)451 private void controlAnimationUnchecked(int typesReady, 452 SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback) { 453 InsetsPolicyAnimationControlListener listener = 454 new InsetsPolicyAnimationControlListener(show, callback, typesReady); 455 listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show); 456 } 457 458 private class BarWindow { 459 460 private final int mId; 461 private @StatusBarManager.WindowVisibleState int mState = 462 StatusBarManager.WINDOW_STATE_SHOWING; 463 BarWindow(int id)464 BarWindow(int id) { 465 mId = id; 466 } 467 updateVisibility(@ullable InsetsControlTarget controlTarget, @InternalInsetsType int type)468 private void updateVisibility(@Nullable InsetsControlTarget controlTarget, 469 @InternalInsetsType int type) { 470 setVisible(controlTarget == null || controlTarget.getRequestedVisibility(type)); 471 } 472 setVisible(boolean visible)473 private void setVisible(boolean visible) { 474 final int state = visible ? WINDOW_STATE_SHOWING : WINDOW_STATE_HIDDEN; 475 if (mState != state) { 476 mState = state; 477 mPolicy.getStatusBarManagerInternal().setWindowState( 478 mDisplayContent.getDisplayId(), mId, state); 479 } 480 } 481 } 482 483 private class InsetsPolicyAnimationControlListener extends 484 InsetsController.InternalAnimationControlListener { 485 Runnable mFinishCallback; 486 InsetsPolicyAnimationControlCallbacks mControlCallbacks; 487 InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types)488 InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) { 489 super(show, false /* hasCallbacks */, types, BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE, 490 false /* disable */, 0 /* floatingImeBottomInsets */); 491 mFinishCallback = finishCallback; 492 mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this); 493 } 494 495 @Override onAnimationFinish()496 protected void onAnimationFinish() { 497 super.onAnimationFinish(); 498 if (mFinishCallback != null) { 499 DisplayThread.getHandler().post(mFinishCallback); 500 } 501 } 502 503 private class InsetsPolicyAnimationControlCallbacks implements 504 InsetsAnimationControlCallbacks { 505 private InsetsAnimationControlImpl mAnimationControl = null; 506 private InsetsPolicyAnimationControlListener mListener; 507 InsetsPolicyAnimationControlCallbacks(InsetsPolicyAnimationControlListener listener)508 InsetsPolicyAnimationControlCallbacks(InsetsPolicyAnimationControlListener listener) { 509 mListener = listener; 510 } 511 controlAnimationUnchecked(int typesReady, SparseArray<InsetsSourceControl> controls, boolean show)512 private void controlAnimationUnchecked(int typesReady, 513 SparseArray<InsetsSourceControl> controls, boolean show) { 514 if (typesReady == 0) { 515 // nothing to animate. 516 return; 517 } 518 mAnimatingShown = show; 519 520 final InsetsState state = getInsetsForWindow(mFocusedWin); 521 522 // We are about to playing the default animation. Passing a null frame indicates 523 // the controlled types should be animated regardless of the frame. 524 mAnimationControl = new InsetsAnimationControlImpl(controls, 525 null /* frame */, state, mListener, typesReady, this, 526 mListener.getDurationMs(), getInsetsInterpolator(), 527 show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE, show 528 ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN 529 : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN, 530 null /* translator */); 531 SurfaceAnimationThread.getHandler().post( 532 () -> mListener.onReady(mAnimationControl, typesReady)); 533 } 534 535 /** Called on SurfaceAnimationThread without global WM lock held. */ 536 @Override scheduleApplyChangeInsets(InsetsAnimationControlRunner runner)537 public void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner) { 538 if (mAnimationControl.applyChangeInsets(null /* outState */)) { 539 mAnimationControl.finish(mAnimatingShown); 540 } 541 } 542 543 @Override notifyFinished(InsetsAnimationControlRunner runner, boolean shown)544 public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) { 545 // Nothing's needed here. Finish steps is handled in the listener 546 // onAnimationFinished callback. 547 } 548 549 /** Called on SurfaceAnimationThread without global WM lock held. */ 550 @Override applySurfaceParams( final SyncRtSurfaceTransactionApplier.SurfaceParams... params)551 public void applySurfaceParams( 552 final SyncRtSurfaceTransactionApplier.SurfaceParams... params) { 553 SurfaceControl.Transaction t = new SurfaceControl.Transaction(); 554 for (int i = params.length - 1; i >= 0; i--) { 555 SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i]; 556 applyParams(t, surfaceParams, mTmpFloat9); 557 } 558 t.apply(); 559 t.close(); 560 } 561 562 // Since we don't push applySurfaceParams to a Handler-queue we don't need 563 // to push release in this case. 564 @Override releaseSurfaceControlFromRt(SurfaceControl sc)565 public void releaseSurfaceControlFromRt(SurfaceControl sc) { 566 sc.release(); 567 } 568 569 @Override startAnimation(InsetsAnimationControlImpl controller, WindowInsetsAnimationControlListener listener, int types, WindowInsetsAnimation animation, Bounds bounds)570 public void startAnimation(InsetsAnimationControlImpl controller, 571 WindowInsetsAnimationControlListener listener, int types, 572 WindowInsetsAnimation animation, 573 Bounds bounds) { 574 } 575 576 @Override reportPerceptible(int types, boolean perceptible)577 public void reportPerceptible(int types, boolean perceptible) { 578 // No-op for now - only client windows report perceptibility for now, with policy 579 // controllers assumed to always be perceptible. 580 } 581 } 582 } 583 } 584