1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_INSETS; 20 import static com.android.server.wm.InsetsSourceProviderProto.CAPTURED_LEASH; 21 import static com.android.server.wm.InsetsSourceProviderProto.CLIENT_VISIBLE; 22 import static com.android.server.wm.InsetsSourceProviderProto.CONTROL; 23 import static com.android.server.wm.InsetsSourceProviderProto.CONTROLLABLE; 24 import static com.android.server.wm.InsetsSourceProviderProto.CONTROL_TARGET; 25 import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL; 26 import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL_TARGET; 27 import static com.android.server.wm.InsetsSourceProviderProto.FRAME; 28 import static com.android.server.wm.InsetsSourceProviderProto.IS_LEASH_READY_FOR_DISPATCHING; 29 import static com.android.server.wm.InsetsSourceProviderProto.PENDING_CONTROL_TARGET; 30 import static com.android.server.wm.InsetsSourceProviderProto.SEAMLESS_ROTATING; 31 import static com.android.server.wm.InsetsSourceProviderProto.SERVER_VISIBLE; 32 import static com.android.server.wm.InsetsSourceProviderProto.SOURCE; 33 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_INSETS_CONTROL; 34 35 import android.annotation.NonNull; 36 import android.annotation.Nullable; 37 import android.graphics.Insets; 38 import android.graphics.Point; 39 import android.graphics.Rect; 40 import android.util.SparseArray; 41 import android.util.proto.ProtoOutputStream; 42 import android.view.InsetsSource; 43 import android.view.InsetsSource.Flags; 44 import android.view.InsetsSourceControl; 45 import android.view.SurfaceControl; 46 import android.view.SurfaceControl.Transaction; 47 import android.view.WindowInsets; 48 49 import com.android.internal.annotations.VisibleForTesting; 50 import com.android.internal.protolog.common.ProtoLog; 51 import com.android.internal.util.function.TriFunction; 52 import com.android.server.wm.SurfaceAnimator.AnimationType; 53 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; 54 55 import java.io.PrintWriter; 56 import java.util.function.Consumer; 57 58 /** 59 * Controller for a specific inset source on the server. It's called provider as it provides the 60 * {@link InsetsSource} to the client that uses it in {@link android.view.InsetsSourceConsumer}. 61 */ 62 class InsetsSourceProvider { 63 64 protected final DisplayContent mDisplayContent; 65 protected final @NonNull InsetsSource mSource; 66 protected WindowContainer mWindowContainer; 67 68 private final Rect mTmpRect = new Rect(); 69 private final InsetsStateController mStateController; 70 private final InsetsSourceControl mFakeControl; 71 private @Nullable InsetsSourceControl mControl; 72 private @Nullable InsetsControlTarget mControlTarget; 73 private @Nullable InsetsControlTarget mPendingControlTarget; 74 private @Nullable InsetsControlTarget mFakeControlTarget; 75 76 private @Nullable ControlAdapter mAdapter; 77 private TriFunction<DisplayFrames, WindowContainer, Rect, Integer> mFrameProvider; 78 private SparseArray<TriFunction<DisplayFrames, WindowContainer, Rect, Integer>> 79 mOverrideFrameProviders; 80 private final SparseArray<Rect> mOverrideFrames = new SparseArray<Rect>(); 81 private boolean mIsLeashReadyForDispatching; 82 private final Rect mSourceFrame = new Rect(); 83 private final Rect mLastSourceFrame = new Rect(); 84 private @NonNull Insets mInsetsHint = Insets.NONE; 85 private boolean mInsetsHintStale = true; 86 private @Flags int mFlagsFromFrameProvider; 87 private @Flags int mFlagsFromServer; 88 89 private final Consumer<Transaction> mSetLeashPositionConsumer = t -> { 90 if (mControl != null) { 91 final SurfaceControl leash = mControl.getLeash(); 92 if (leash != null) { 93 final Point position = mControl.getSurfacePosition(); 94 t.setPosition(leash, position.x, position.y); 95 } 96 } 97 }; 98 99 /** The visibility override from the current controlling window. */ 100 private boolean mClientVisible; 101 102 /** 103 * Whether the window container is available and considered visible as in 104 * {@link WindowContainer#isVisible}. 105 */ 106 private boolean mServerVisible; 107 108 private boolean mSeamlessRotating; 109 110 private final boolean mControllable; 111 112 /** 113 * Whether to forced the dimensions of the source window container to the inset frame and crop 114 * out any overflow. 115 * Used to crop the taskbar inset source when a task animation is occurring to hide the taskbar 116 * rounded corners overlays. 117 * 118 * TODO: Remove when we enable shell transitions (b/202383002) 119 */ 120 private boolean mCropToProvidingInsets = false; 121 InsetsSourceProvider(InsetsSource source, InsetsStateController stateController, DisplayContent displayContent)122 InsetsSourceProvider(InsetsSource source, InsetsStateController stateController, 123 DisplayContent displayContent) { 124 mClientVisible = (WindowInsets.Type.defaultVisible() & source.getType()) != 0; 125 mSource = source; 126 mDisplayContent = displayContent; 127 mStateController = stateController; 128 mFakeControl = new InsetsSourceControl( 129 source.getId(), source.getType(), null /* leash */, false /* initialVisible */, 130 new Point(), Insets.NONE); 131 mControllable = (InsetsPolicy.CONTROLLABLE_TYPES & source.getType()) != 0; 132 } 133 getSource()134 InsetsSource getSource() { 135 return mSource; 136 } 137 138 /** 139 * @return Whether the current flag configuration allows to control this source. 140 */ isControllable()141 boolean isControllable() { 142 return mControllable; 143 } 144 145 /** 146 * Updates the window container that currently backs this source. 147 * 148 * @param windowContainer The window container that links to this source. 149 * @param frameProvider Based on display frame state and the window, calculates the resulting 150 * frame that should be reported to clients. 151 * This will only be used when the window container providing the insets is 152 * not a WindowState. 153 * @param overrideFrameProviders Based on display frame state and the window, calculates the 154 * resulting frame that should be reported to given window type. 155 */ setWindowContainer(@ullable WindowContainer windowContainer, @Nullable TriFunction<DisplayFrames, WindowContainer, Rect, Integer> frameProvider, @Nullable SparseArray<TriFunction<DisplayFrames, WindowContainer, Rect, Integer>> overrideFrameProviders)156 void setWindowContainer(@Nullable WindowContainer windowContainer, 157 @Nullable TriFunction<DisplayFrames, WindowContainer, Rect, Integer> frameProvider, 158 @Nullable SparseArray<TriFunction<DisplayFrames, WindowContainer, Rect, Integer>> 159 overrideFrameProviders) { 160 if (mWindowContainer != null) { 161 if (mControllable) { 162 mWindowContainer.setControllableInsetProvider(null); 163 } 164 // The window container may be animating such that we can hand out the leash to the 165 // control target. Revoke the leash by cancelling the animation to correct the state. 166 // TODO: Ideally, we should wait for the animation to finish so previous window can 167 // animate-out as new one animates-in. 168 mWindowContainer.cancelAnimation(); 169 mWindowContainer.getInsetsSourceProviders().remove(mSource.getId()); 170 mSeamlessRotating = false; 171 } 172 ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "InsetsSource setWin %s for type %s", 173 windowContainer, WindowInsets.Type.toString(mSource.getType())); 174 mWindowContainer = windowContainer; 175 // TODO: remove the frame provider for non-WindowState container. 176 mFrameProvider = frameProvider; 177 mOverrideFrames.clear(); 178 mOverrideFrameProviders = overrideFrameProviders; 179 if (windowContainer == null) { 180 setServerVisible(false); 181 mSource.setVisibleFrame(null); 182 mSource.setFlags(0, 0xffffffff); 183 mSourceFrame.setEmpty(); 184 } else { 185 mWindowContainer.getInsetsSourceProviders().put(mSource.getId(), this); 186 if (mControllable) { 187 mWindowContainer.setControllableInsetProvider(this); 188 if (mPendingControlTarget != null) { 189 updateControlForTarget(mPendingControlTarget, true /* force */); 190 mPendingControlTarget = null; 191 } 192 } 193 } 194 } 195 setFlags(@lags int flags, @Flags int mask)196 boolean setFlags(@Flags int flags, @Flags int mask) { 197 mFlagsFromServer = (mFlagsFromServer & ~mask) | (flags & mask); 198 final @Flags int mergedFlags = mFlagsFromFrameProvider | mFlagsFromServer; 199 if (mSource.getFlags() != mergedFlags) { 200 mSource.setFlags(mergedFlags); 201 return true; 202 } 203 return false; 204 } 205 206 /** 207 * The source frame can affect the layout of other windows, so this should be called once the 208 * window container gets laid out. 209 */ updateSourceFrame(Rect frame)210 void updateSourceFrame(Rect frame) { 211 if (mWindowContainer == null) { 212 return; 213 } 214 WindowState win = mWindowContainer.asWindowState(); 215 216 if (win == null) { 217 // For all the non window WindowContainers. 218 if (mServerVisible) { 219 mTmpRect.set(mWindowContainer.getBounds()); 220 if (mFrameProvider != null) { 221 mFrameProvider.apply(mWindowContainer.getDisplayContent().mDisplayFrames, 222 mWindowContainer, mTmpRect); 223 } 224 } else { 225 mTmpRect.setEmpty(); 226 } 227 mSource.setFrame(mTmpRect); 228 mSource.setVisibleFrame(null); 229 return; 230 } 231 232 mSourceFrame.set(frame); 233 if (mFrameProvider != null) { 234 mFlagsFromFrameProvider = mFrameProvider.apply( 235 mWindowContainer.getDisplayContent().mDisplayFrames, 236 mWindowContainer, 237 mSourceFrame); 238 mSource.setFlags(mFlagsFromFrameProvider | mFlagsFromServer); 239 } 240 updateSourceFrameForServerVisibility(); 241 if (!mLastSourceFrame.equals(mSourceFrame)) { 242 mLastSourceFrame.set(mSourceFrame); 243 mInsetsHintStale = true; 244 } 245 246 if (mOverrideFrameProviders != null) { 247 // Not necessary to clear the mOverrideFrames here. It will be cleared every time the 248 // override frame provider updates. 249 for (int i = mOverrideFrameProviders.size() - 1; i >= 0; i--) { 250 final int windowType = mOverrideFrameProviders.keyAt(i); 251 final Rect overrideFrame; 252 if (mOverrideFrames.contains(windowType)) { 253 overrideFrame = mOverrideFrames.get(windowType); 254 overrideFrame.set(frame); 255 } else { 256 overrideFrame = new Rect(frame); 257 } 258 final TriFunction<DisplayFrames, WindowContainer, Rect, Integer> provider = 259 mOverrideFrameProviders.get(windowType); 260 if (provider != null) { 261 mOverrideFrameProviders.get(windowType).apply( 262 mWindowContainer.getDisplayContent().mDisplayFrames, mWindowContainer, 263 overrideFrame); 264 } 265 mOverrideFrames.put(windowType, overrideFrame); 266 } 267 } 268 269 if (win.mGivenVisibleInsets.left != 0 || win.mGivenVisibleInsets.top != 0 270 || win.mGivenVisibleInsets.right != 0 271 || win.mGivenVisibleInsets.bottom != 0) { 272 mTmpRect.set(frame); 273 mTmpRect.inset(win.mGivenVisibleInsets); 274 mSource.setVisibleFrame(mTmpRect); 275 } else { 276 mSource.setVisibleFrame(null); 277 } 278 } 279 updateSourceFrameForServerVisibility()280 private void updateSourceFrameForServerVisibility() { 281 // Make sure we set the valid source frame only when server visible is true, because the 282 // frame may not yet determined that server side doesn't think the window is ready to 283 // visible. (i.e. No surface, pending insets that were given during layout, etc..) 284 if (mServerVisible) { 285 mSource.setFrame(mSourceFrame); 286 } else { 287 mSource.setFrame(0, 0, 0, 0); 288 } 289 } 290 onWindowContainerBoundsChanged()291 void onWindowContainerBoundsChanged() { 292 mInsetsHintStale = true; 293 } 294 295 @VisibleForTesting getInsetsHint()296 Insets getInsetsHint() { 297 if (!mServerVisible) { 298 return mInsetsHint; 299 } 300 final WindowState win = mWindowContainer.asWindowState(); 301 if (win != null && win.mGivenInsetsPending) { 302 return mInsetsHint; 303 } 304 if (mInsetsHintStale) { 305 final Rect bounds = mWindowContainer.getBounds(); 306 mInsetsHint = mSource.calculateInsets(bounds, true /* ignoreVisibility */); 307 mInsetsHintStale = false; 308 } 309 return mInsetsHint; 310 } 311 312 /** @return A new source computed by the specified window frame in the given display frames. */ createSimulatedSource(DisplayFrames displayFrames, Rect frame)313 InsetsSource createSimulatedSource(DisplayFrames displayFrames, Rect frame) { 314 final InsetsSource source = new InsetsSource(mSource); 315 mTmpRect.set(frame); 316 if (mFrameProvider != null) { 317 mFrameProvider.apply(displayFrames, mWindowContainer, mTmpRect); 318 } 319 source.setFrame(mTmpRect); 320 321 // Don't copy visible frame because it might not be calculated in the provided display 322 // frames and it is not significant for this usage. 323 source.setVisibleFrame(null); 324 325 return source; 326 } 327 328 /** 329 * Called when a layout pass has occurred. 330 */ onPostLayout()331 void onPostLayout() { 332 if (mWindowContainer == null) { 333 return; 334 } 335 WindowState windowState = mWindowContainer.asWindowState(); 336 boolean isServerVisible = windowState != null 337 ? windowState.wouldBeVisibleIfPolicyIgnored() && windowState.isVisibleByPolicy() 338 : mWindowContainer.isVisibleRequested(); 339 setServerVisible(isServerVisible); 340 if (mControl != null) { 341 boolean changed = false; 342 final Point position = getWindowFrameSurfacePosition(); 343 if (mControl.setSurfacePosition(position.x, position.y) && mControlTarget != null) { 344 changed = true; 345 if (windowState != null && windowState.getWindowFrames().didFrameSizeChange() 346 && windowState.mWinAnimator.getShown() && mWindowContainer.okToDisplay()) { 347 windowState.applyWithNextDraw(mSetLeashPositionConsumer); 348 } else { 349 Transaction t = mWindowContainer.getSyncTransaction(); 350 if (windowState != null) { 351 // Make the buffer, token transformation, and leash position to be updated 352 // together when the window is drawn for new rotation. Otherwise the window 353 // may be outside the screen by the inconsistent orientations. 354 final AsyncRotationController rotationController = 355 mDisplayContent.getAsyncRotationController(); 356 if (rotationController != null) { 357 final Transaction drawT = 358 rotationController.getDrawTransaction(windowState.mToken); 359 if (drawT != null) { 360 t = drawT; 361 } 362 } 363 } 364 mSetLeashPositionConsumer.accept(t); 365 } 366 } 367 final Insets insetsHint = getInsetsHint(); 368 if (!mControl.getInsetsHint().equals(insetsHint)) { 369 mControl.setInsetsHint(insetsHint); 370 changed = true; 371 } 372 if (changed) { 373 mStateController.notifyControlChanged(mControlTarget); 374 } 375 } 376 } 377 getWindowFrameSurfacePosition()378 private Point getWindowFrameSurfacePosition() { 379 final WindowState win = mWindowContainer.asWindowState(); 380 if (win != null && mControl != null) { 381 final AsyncRotationController controller = mDisplayContent.getAsyncRotationController(); 382 if (controller != null && controller.shouldFreezeInsetsPosition(win)) { 383 // Use previous position because the window still shows with old rotation. 384 return mControl.getSurfacePosition(); 385 } 386 } 387 final Rect frame = win != null ? win.getFrame() : mWindowContainer.getBounds(); 388 final Point position = new Point(); 389 mWindowContainer.transformFrameToSurfacePosition(frame.left, frame.top, position); 390 return position; 391 } 392 393 /** 394 * @see InsetsStateController#onControlTargetChanged 395 */ updateFakeControlTarget(@ullable InsetsControlTarget fakeTarget)396 void updateFakeControlTarget(@Nullable InsetsControlTarget fakeTarget) { 397 if (fakeTarget == mFakeControlTarget) { 398 return; 399 } 400 mFakeControlTarget = fakeTarget; 401 } 402 403 /** 404 * Ensures that the inset source window container is cropped so that anything that doesn't fit 405 * within the inset frame is cropped out until removeCropToProvidingInsetsBounds is called. 406 * 407 * The inset source surface will get cropped to the be of the size of the insets it's providing. 408 * 409 * For example, for the taskbar window which serves as the ITYPE_EXTRA_NAVIGATION_BAR inset 410 * source, the window is larger than the insets because of the rounded corners overlay, but 411 * during task animations we want to make sure that the overlay is cropped out of the window so 412 * that they don't hide the window animations. 413 * 414 * @param t The transaction to use to apply immediate overflow cropping operations. 415 * 416 * NOTE: The relies on the inset source window to have a leash (usually this would be a leash 417 * for the ANIMATION_TYPE_INSETS_CONTROL animation if the inset is controlled by the client) 418 * 419 * TODO: Remove when we migrate over to shell transitions (b/202383002) 420 */ setCropToProvidingInsetsBounds(Transaction t)421 void setCropToProvidingInsetsBounds(Transaction t) { 422 mCropToProvidingInsets = true; 423 424 if (mWindowContainer != null && mWindowContainer.mSurfaceAnimator.hasLeash()) { 425 // apply to existing leash 426 t.setWindowCrop(mWindowContainer.mSurfaceAnimator.mLeash, 427 getProvidingInsetsBoundsCropRect()); 428 } 429 } 430 431 /** 432 * Removes any overflow cropping and future cropping to the inset source window's leash that may 433 * have been set with a call to setCropToProvidingInsetsBounds(). 434 * @param t The transaction to use to apply immediate removal of overflow cropping. 435 * 436 * TODO: Remove when we migrate over to shell transitions (b/202383002) 437 */ removeCropToProvidingInsetsBounds(Transaction t)438 void removeCropToProvidingInsetsBounds(Transaction t) { 439 mCropToProvidingInsets = false; 440 441 // apply to existing leash 442 if (mWindowContainer != null && mWindowContainer.mSurfaceAnimator.hasLeash()) { 443 t.setWindowCrop(mWindowContainer.mSurfaceAnimator.mLeash, null); 444 } 445 } 446 getProvidingInsetsBoundsCropRect()447 private Rect getProvidingInsetsBoundsCropRect() { 448 Rect sourceWindowFrame = mWindowContainer.asWindowState() != null 449 ? mWindowContainer.asWindowState().getFrame() 450 : mWindowContainer.getBounds(); 451 Rect insetFrame = getSource().getFrame(); 452 453 // The rectangle in buffer space we want to crop to 454 return new Rect( 455 insetFrame.left - sourceWindowFrame.left, 456 insetFrame.top - sourceWindowFrame.top, 457 insetFrame.right - sourceWindowFrame.left, 458 insetFrame.bottom - sourceWindowFrame.top 459 ); 460 } 461 updateControlForTarget(@ullable InsetsControlTarget target, boolean force)462 void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) { 463 if (mSeamlessRotating) { 464 // We are un-rotating the window against the display rotation. We don't want the target 465 // to control the window for now. 466 return; 467 } 468 469 if (mWindowContainer != null && mWindowContainer.getSurfaceControl() == null) { 470 // if window doesn't have a surface, set it null and return. 471 setWindowContainer(null, null, null); 472 } 473 if (mWindowContainer == null) { 474 mPendingControlTarget = target; 475 return; 476 } 477 if (target == mControlTarget && !force) { 478 return; 479 } 480 if (target == null) { 481 // Cancelling the animation will invoke onAnimationCancelled, resetting all the fields. 482 mWindowContainer.cancelAnimation(); 483 setClientVisible((WindowInsets.Type.defaultVisible() & mSource.getType()) != 0); 484 return; 485 } 486 final Point surfacePosition = getWindowFrameSurfacePosition(); 487 mAdapter = new ControlAdapter(surfacePosition); 488 if (mSource.getType() == WindowInsets.Type.ime()) { 489 setClientVisible(target.isRequestedVisible(WindowInsets.Type.ime())); 490 } 491 final Transaction t = mWindowContainer.getSyncTransaction(); 492 mWindowContainer.startAnimation(t, mAdapter, !mClientVisible /* hidden */, 493 ANIMATION_TYPE_INSETS_CONTROL); 494 495 // The leash was just created. We cannot dispatch it until its surface transaction is 496 // applied. Otherwise, the client's operation to the leash might be overwritten by us. 497 mIsLeashReadyForDispatching = false; 498 499 final SurfaceControl leash = mAdapter.mCapturedLeash; 500 mControlTarget = target; 501 updateVisibility(); 502 mControl = new InsetsSourceControl(mSource.getId(), mSource.getType(), leash, 503 mClientVisible, surfacePosition, getInsetsHint()); 504 505 ProtoLog.d(WM_DEBUG_WINDOW_INSETS, 506 "InsetsSource Control %s for target %s", mControl, mControlTarget); 507 } 508 startSeamlessRotation()509 void startSeamlessRotation() { 510 if (!mSeamlessRotating) { 511 mSeamlessRotating = true; 512 mWindowContainer.cancelAnimation(); 513 } 514 } 515 finishSeamlessRotation()516 void finishSeamlessRotation() { 517 mSeamlessRotating = false; 518 } 519 updateClientVisibility(InsetsControlTarget caller)520 boolean updateClientVisibility(InsetsControlTarget caller) { 521 final boolean requestedVisible = caller.isRequestedVisible(mSource.getType()); 522 if (caller != mControlTarget || requestedVisible == mClientVisible) { 523 return false; 524 } 525 setClientVisible(requestedVisible); 526 return true; 527 } 528 onSurfaceTransactionApplied()529 void onSurfaceTransactionApplied() { 530 mIsLeashReadyForDispatching = true; 531 } 532 setClientVisible(boolean clientVisible)533 void setClientVisible(boolean clientVisible) { 534 if (mClientVisible == clientVisible) { 535 return; 536 } 537 mClientVisible = clientVisible; 538 updateVisibility(); 539 // The visibility change needs a traversal to apply. 540 mDisplayContent.setLayoutNeeded(); 541 mDisplayContent.mWmService.mWindowPlacerLocked.requestTraversal(); 542 } 543 544 @VisibleForTesting setServerVisible(boolean serverVisible)545 void setServerVisible(boolean serverVisible) { 546 mServerVisible = serverVisible; 547 updateSourceFrameForServerVisibility(); 548 updateVisibility(); 549 } 550 updateVisibility()551 protected void updateVisibility() { 552 mSource.setVisible(mServerVisible && mClientVisible); 553 ProtoLog.d(WM_DEBUG_WINDOW_INSETS, 554 "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s", 555 WindowInsets.Type.toString(mSource.getType()), 556 mServerVisible, mClientVisible); 557 } 558 getControl(InsetsControlTarget target)559 InsetsSourceControl getControl(InsetsControlTarget target) { 560 if (target == mControlTarget) { 561 if (!mIsLeashReadyForDispatching && mControl != null) { 562 // The surface transaction of preparing leash is not applied yet. We don't send it 563 // to the client in case that the client applies its transaction sooner than ours 564 // that we could unexpectedly overwrite the surface state. 565 return new InsetsSourceControl(mControl.getId(), mControl.getType(), 566 null /* leash */, mControl.isInitiallyVisible(), 567 mControl.getSurfacePosition(), mControl.getInsetsHint()); 568 } 569 return mControl; 570 } 571 if (target == mFakeControlTarget) { 572 return mFakeControl; 573 } 574 return null; 575 } 576 getControlTarget()577 InsetsControlTarget getControlTarget() { 578 return mControlTarget; 579 } 580 getFakeControlTarget()581 InsetsControlTarget getFakeControlTarget() { 582 return mFakeControlTarget; 583 } 584 isClientVisible()585 boolean isClientVisible() { 586 return mClientVisible; 587 } 588 overridesFrame(int windowType)589 boolean overridesFrame(int windowType) { 590 return mOverrideFrames.contains(windowType); 591 } 592 getOverriddenFrame(int windowType)593 Rect getOverriddenFrame(int windowType) { 594 return mOverrideFrames.get(windowType); 595 } 596 dump(PrintWriter pw, String prefix)597 public void dump(PrintWriter pw, String prefix) { 598 pw.println(prefix + getClass().getSimpleName()); 599 prefix = prefix + " "; 600 pw.print(prefix + "mSource="); mSource.dump("", pw); 601 pw.print(prefix + "mSourceFrame="); 602 pw.println(mSourceFrame); 603 if (mOverrideFrames.size() > 0) { 604 pw.print(prefix + "mOverrideFrames="); 605 pw.println(mOverrideFrames); 606 } 607 if (mControl != null) { 608 pw.print(prefix + "mControl="); 609 mControl.dump("", pw); 610 } 611 if (mControllable) { 612 pw.print(prefix + "mInsetsHint="); 613 pw.print(mInsetsHint); 614 if (mInsetsHintStale) { 615 pw.print(" stale"); 616 } 617 pw.println(); 618 } 619 pw.print(prefix); 620 pw.print("mIsLeashReadyForDispatching="); pw.print(mIsLeashReadyForDispatching); 621 pw.println(); 622 if (mWindowContainer != null) { 623 pw.print(prefix + "mWindowContainer="); 624 pw.println(mWindowContainer); 625 } 626 if (mAdapter != null) { 627 pw.print(prefix + "mAdapter="); 628 mAdapter.dump(pw, ""); 629 } 630 if (mControlTarget != null) { 631 pw.print(prefix + "mControlTarget="); 632 pw.println(mControlTarget); 633 } 634 if (mPendingControlTarget != null) { 635 pw.print(prefix + "mPendingControlTarget="); 636 pw.println(mPendingControlTarget); 637 } 638 if (mFakeControlTarget != null) { 639 pw.print(prefix + "mFakeControlTarget="); 640 pw.println(mFakeControlTarget); 641 } 642 } 643 dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)644 void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { 645 final long token = proto.start(fieldId); 646 mSource.dumpDebug(proto, SOURCE); 647 mTmpRect.dumpDebug(proto, FRAME); 648 mFakeControl.dumpDebug(proto, FAKE_CONTROL); 649 if (mControl != null) { 650 mControl.dumpDebug(proto, CONTROL); 651 } 652 if (mControlTarget != null && mControlTarget.getWindow() != null) { 653 mControlTarget.getWindow().dumpDebug(proto, CONTROL_TARGET, logLevel); 654 } 655 if (mPendingControlTarget != null && mPendingControlTarget.getWindow() != null) { 656 mPendingControlTarget.getWindow().dumpDebug(proto, PENDING_CONTROL_TARGET, logLevel); 657 } 658 if (mFakeControlTarget != null && mFakeControlTarget.getWindow() != null) { 659 mFakeControlTarget.getWindow().dumpDebug(proto, FAKE_CONTROL_TARGET, logLevel); 660 } 661 if (mAdapter != null && mAdapter.mCapturedLeash != null) { 662 mAdapter.mCapturedLeash.dumpDebug(proto, CAPTURED_LEASH); 663 } 664 proto.write(IS_LEASH_READY_FOR_DISPATCHING, mIsLeashReadyForDispatching); 665 proto.write(CLIENT_VISIBLE, mClientVisible); 666 proto.write(SERVER_VISIBLE, mServerVisible); 667 proto.write(SEAMLESS_ROTATING, mSeamlessRotating); 668 proto.write(CONTROLLABLE, mControllable); 669 proto.end(token); 670 } 671 672 private class ControlAdapter implements AnimationAdapter { 673 674 private final Point mSurfacePosition; 675 private SurfaceControl mCapturedLeash; 676 ControlAdapter(Point surfacePosition)677 ControlAdapter(Point surfacePosition) { 678 mSurfacePosition = surfacePosition; 679 } 680 681 @Override getShowWallpaper()682 public boolean getShowWallpaper() { 683 return false; 684 } 685 686 @Override startAnimation(SurfaceControl animationLeash, Transaction t, @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback)687 public void startAnimation(SurfaceControl animationLeash, Transaction t, 688 @AnimationType int type, @NonNull OnAnimationFinishedCallback finishCallback) { 689 // TODO(b/166736352): Check if we still need to control the IME visibility here. 690 if (mSource.getType() == WindowInsets.Type.ime()) { 691 // TODO: use 0 alpha and remove t.hide() once b/138459974 is fixed. 692 t.setAlpha(animationLeash, 1 /* alpha */); 693 t.hide(animationLeash); 694 } 695 ProtoLog.i(WM_DEBUG_WINDOW_INSETS, 696 "ControlAdapter startAnimation mSource: %s controlTarget: %s", mSource, 697 mControlTarget); 698 699 mCapturedLeash = animationLeash; 700 t.setPosition(mCapturedLeash, mSurfacePosition.x, mSurfacePosition.y); 701 702 if (mCropToProvidingInsets) { 703 // Apply crop to hide overflow 704 t.setWindowCrop(mCapturedLeash, getProvidingInsetsBoundsCropRect()); 705 } 706 } 707 708 @Override onAnimationCancelled(SurfaceControl animationLeash)709 public void onAnimationCancelled(SurfaceControl animationLeash) { 710 if (mAdapter == this) { 711 mStateController.notifyControlRevoked(mControlTarget, InsetsSourceProvider.this); 712 mControl = null; 713 mControlTarget = null; 714 mAdapter = null; 715 setClientVisible((WindowInsets.Type.defaultVisible() & mSource.getType()) != 0); 716 ProtoLog.i(WM_DEBUG_WINDOW_INSETS, 717 "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s", 718 mSource, mControlTarget); 719 } 720 } 721 722 @Override getDurationHint()723 public long getDurationHint() { 724 return 0; 725 } 726 727 @Override getStatusBarTransitionsStartTime()728 public long getStatusBarTransitionsStartTime() { 729 return 0; 730 } 731 732 @Override dump(PrintWriter pw, String prefix)733 public void dump(PrintWriter pw, String prefix) { 734 pw.print(prefix + "ControlAdapter mCapturedLeash="); 735 pw.print(mCapturedLeash); 736 pw.println(); 737 } 738 739 @Override dumpDebug(ProtoOutputStream proto)740 public void dumpDebug(ProtoOutputStream proto) { 741 } 742 } 743 } 744