diff options
6 files changed, 106 insertions, 15 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java index ea7e9685dd92..06c1e68753e1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java @@ -104,6 +104,7 @@ public abstract class Pip2Module { TaskStackListenerImpl taskStackListener, ShellTaskOrganizer shellTaskOrganizer, PipTransitionState pipTransitionState, + PipTouchHandler pipTouchHandler, @ShellMainThread ShellExecutor mainExecutor) { if (!PipUtils.isPip2ExperimentEnabled()) { return Optional.empty(); @@ -112,7 +113,7 @@ public abstract class Pip2Module { context, shellInit, shellCommandHandler, shellController, displayController, displayInsetsController, pipBoundsState, pipBoundsAlgorithm, pipDisplayLayoutState, pipScheduler, taskStackListener, shellTaskOrganizer, - pipTransitionState, mainExecutor)); + pipTransitionState, pipTouchHandler, mainExecutor)); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java index 8aa093379ee7..94fe286de869 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java @@ -88,6 +88,7 @@ public class PipController implements ConfigurationChangeListener, private final TaskStackListenerImpl mTaskStackListener; private final ShellTaskOrganizer mShellTaskOrganizer; private final PipTransitionState mPipTransitionState; + private final PipTouchHandler mPipTouchHandler; private final ShellExecutor mMainExecutor; private final PipImpl mImpl; private Consumer<Boolean> mOnIsInPipStateChangedListener; @@ -130,6 +131,7 @@ public class PipController implements ConfigurationChangeListener, TaskStackListenerImpl taskStackListener, ShellTaskOrganizer shellTaskOrganizer, PipTransitionState pipTransitionState, + PipTouchHandler pipTouchHandler, ShellExecutor mainExecutor) { mContext = context; mShellCommandHandler = shellCommandHandler; @@ -144,6 +146,7 @@ public class PipController implements ConfigurationChangeListener, mShellTaskOrganizer = shellTaskOrganizer; mPipTransitionState = pipTransitionState; mPipTransitionState.addPipTransitionStateChangedListener(this); + mPipTouchHandler = pipTouchHandler; mMainExecutor = mainExecutor; mImpl = new PipImpl(); @@ -168,6 +171,7 @@ public class PipController implements ConfigurationChangeListener, TaskStackListenerImpl taskStackListener, ShellTaskOrganizer shellTaskOrganizer, PipTransitionState pipTransitionState, + PipTouchHandler pipTouchHandler, ShellExecutor mainExecutor) { if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) { ProtoLog.w(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, @@ -177,7 +181,7 @@ public class PipController implements ConfigurationChangeListener, return new PipController(context, shellInit, shellCommandHandler, shellController, displayController, displayInsetsController, pipBoundsState, pipBoundsAlgorithm, pipDisplayLayoutState, pipScheduler, taskStackListener, shellTaskOrganizer, - pipTransitionState, mainExecutor); + pipTransitionState, pipTouchHandler, mainExecutor); } public PipImpl getPipImpl() { @@ -204,7 +208,9 @@ public class PipController implements ConfigurationChangeListener, mDisplayInsetsController.addInsetsChangedListener(mPipDisplayLayoutState.getDisplayId(), new ImeListener(mDisplayController, mPipDisplayLayoutState.getDisplayId()) { @Override - public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {} + public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { + mPipTouchHandler.onImeVisibilityChanged(imeVisible, imeHeight); + } }); // Allow other outside processes to bind to PiP controller using the key below. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java index ea02de9d9704..2905a1582b24 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java @@ -134,6 +134,8 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private final PhysicsAnimator.SpringConfig mConflictResolutionSpringConfig = new PhysicsAnimator.SpringConfig(STIFFNESS_LOW, DAMPING_RATIO_NO_BOUNCY); + @Nullable private Runnable mUpdateMovementBoundsRunnable; + private final Consumer<Rect> mUpdateBoundsCallback = (Rect newBounds) -> { if (mPipBoundsState.getBounds().equals(newBounds)) { return; @@ -141,6 +143,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, mMenuController.updateMenuLayout(newBounds); mPipBoundsState.setBounds(newBounds); + maybeUpdateMovementBounds(); }; /** @@ -555,11 +558,20 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, + " callers=\n%s", TAG, originalBounds, offset, Debug.getCallers(5, " ")); } + if (offset == 0) { + return; + } + cancelPhysicsAnimation(); - /* - mPipTaskOrganizer.scheduleOffsetPip(originalBounds, offset, SHIFT_DURATION, - mUpdateBoundsCallback); - */ + + Rect adjustedBounds = new Rect(originalBounds); + adjustedBounds.offset(0, offset); + + setAnimatingToBounds(adjustedBounds); + Bundle extra = new Bundle(); + extra.putBoolean(ANIMATING_BOUNDS_CHANGE, true); + extra.putInt(ANIMATING_BOUNDS_CHANGE_DURATION, SHIFT_DURATION); + mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra); } /** @@ -574,11 +586,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, /** Set new fling configs whose min/max values respect the given movement bounds. */ private void rebuildFlingConfigs() { mFlingConfigX = new PhysicsAnimator.FlingConfig(DEFAULT_FRICTION, - mPipBoundsAlgorithm.getMovementBounds(getBounds()).left, - mPipBoundsAlgorithm.getMovementBounds(getBounds()).right); + mPipBoundsState.getMovementBounds().left, + mPipBoundsState.getMovementBounds().right); mFlingConfigY = new PhysicsAnimator.FlingConfig(DEFAULT_FRICTION, - mPipBoundsAlgorithm.getMovementBounds(getBounds()).top, - mPipBoundsAlgorithm.getMovementBounds(getBounds()).bottom); + mPipBoundsState.getMovementBounds().top, + mPipBoundsState.getMovementBounds().bottom); final Rect insetBounds = mPipBoundsState.getDisplayLayout().stableInsets(); mStashConfigX = new PhysicsAnimator.FlingConfig( DEFAULT_FRICTION, @@ -660,6 +672,16 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, cleanUpHighPerfSessionMaybe(); } + void setUpdateMovementBoundsRunnable(Runnable updateMovementBoundsRunnable) { + mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable; + } + + private void maybeUpdateMovementBounds() { + if (mUpdateMovementBoundsRunnable != null) { + mUpdateMovementBoundsRunnable.run(); + } + } + /** * Notifies the floating coordinator that we're moving, and sets the animating to bounds so * we return these bounds from @@ -796,8 +818,14 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, startTx, finishTx, mPipBoundsState.getBounds(), mPipBoundsState.getBounds(), destinationBounds, duration, 0f /* angle */); animator.setAnimationEndCallback(() -> { - mPipBoundsState.setBounds(destinationBounds); - // All motion operations have actually finished, so make bounds cache updates. + mUpdateBoundsCallback.accept(destinationBounds); + + // In case an ongoing drag/fling was present before a deterministic resize transition + // kicked in, we need to update the update bounds properly before cleaning in-motion + // state. + mPipBoundsState.getMotionBoundsState().setBoundsInMotion(destinationBounds); + settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */); + cleanUpHighPerfSessionMaybe(); // Signal that we are done with resize transition mPipScheduler.scheduleFinishResizePip(true /* configAtEnd */); @@ -806,7 +834,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, } private void settlePipBoundsAfterPhysicsAnimation(boolean animatingAfter) { - if (!animatingAfter) { + if (!animatingAfter && mPipBoundsState.getMotionBoundsState().isInMotion()) { // The physics animation ended, though we may not necessarily be done animating, such as // when we're still dragging after moving out of the magnetic target. Only set the final // bounds state and clear motion bounds completely if the whole animation is over. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java index 5b0ca1837a1c..d28204add0ac 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java @@ -146,8 +146,8 @@ public class PipResizeGestureHandler implements mUpdateResizeBoundsCallback = (rect) -> { mUserResizeBounds.set(rect); // mMotionHelper.synchronizePinnedStackBounds(); - mUpdateMovementBoundsRunnable.run(); mPipBoundsState.setBounds(rect); + mUpdateMovementBoundsRunnable.run(); resetState(); }; } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java index 53b80e8b7542..f387e72b3da6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTouchHandler.java @@ -199,6 +199,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha mMenuController.addListener(new PipMenuListener()); mGesture = new DefaultPipTouchGesture(); mMotionHelper = pipMotionHelper; + mMotionHelper.setUpdateMovementBoundsRunnable(this::updateMovementBounds); mPipDismissTargetHandler = new PipDismissTargetHandler(context, pipUiEventLogger, mMotionHelper, mainExecutor); mTouchState = new PipTouchState(ViewConfiguration.get(context), @@ -317,6 +318,8 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha mFloatingContentCoordinator.onContentRemoved(mMotionHelper); mPipResizeGestureHandler.onActivityUnpinned(); mPipInputConsumer.unregisterInputConsumer(); + mPipBoundsState.setHasUserMovedPip(false); + mPipBoundsState.setHasUserResizedPip(false); } void onPinnedStackAnimationEnded( @@ -346,6 +349,22 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha void onImeVisibilityChanged(boolean imeVisible, int imeHeight) { mIsImeShowing = imeVisible; mImeHeight = imeHeight; + + // Cache new movement bounds using the new potential IME height. + updateMovementBounds(); + + mPipTransitionState.setOnIdlePipTransitionStateRunnable(() -> { + int delta = mPipBoundsState.getMovementBounds().bottom + - mPipBoundsState.getBounds().top; + + boolean hasUserInteracted = (mPipBoundsState.hasUserMovedPip() + || mPipBoundsState.hasUserResizedPip()); + if ((imeVisible && delta < 0) || (!imeVisible && !hasUserInteracted)) { + // The policy is to ignore an IME disappearing if user has interacted with PiP. + // Otherwise, only offset due to an appearing IME if PiP occludes it. + mMotionHelper.animateToOffset(mPipBoundsState.getBounds(), delta); + } + }); } void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) { @@ -1077,6 +1096,7 @@ public class PipTouchHandler implements PipTransitionState.PipTransitionStateCha switch (newState) { case PipTransitionState.ENTERED_PIP: onActivityPinned(); + updateMovementBounds(); mTouchState.setAllowInputEvents(true); mTouchState.reset(); break; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java index 29272be6e9bd..a132796f4a84 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java @@ -149,6 +149,12 @@ public class PipTransitionState { @Nullable private SurfaceControl mSwipePipToHomeOverlay; + // + // Scheduling-related state + // + @Nullable + private Runnable mOnIdlePipTransitionStateRunnable; + /** * An interface to track state updates as we progress through PiP transitions. */ @@ -197,6 +203,8 @@ public class PipTransitionState { mState = state; dispatchPipTransitionStateChanged(prevState, mState, extra); } + + maybeRunOnIdlePipTransitionStateCallback(); } /** @@ -231,6 +239,29 @@ public class PipTransitionState { } /** + * Schedule a callback to run when in a valid idle PiP state. + * + * <p>We only allow for one callback to be scheduled to avoid cases with multiple transitions + * being scheduled. For instance, if user double taps and IME shows, this would + * schedule a bounds change transition for IME appearing. But if some other transition would + * want to animate PiP before the scheduled callback executes, we would rather want to replace + * the existing callback with a new one, to avoid multiple animations + * as soon as we are idle.</p> + */ + public void setOnIdlePipTransitionStateRunnable( + @Nullable Runnable onIdlePipTransitionStateRunnable) { + mOnIdlePipTransitionStateRunnable = onIdlePipTransitionStateRunnable; + maybeRunOnIdlePipTransitionStateCallback(); + } + + private void maybeRunOnIdlePipTransitionStateCallback() { + if (mOnIdlePipTransitionStateRunnable != null && isPipStateIdle()) { + mOnIdlePipTransitionStateRunnable.run(); + mOnIdlePipTransitionStateRunnable = null; + } + } + + /** * Adds a {@link PipTransitionStateChangedListener} for future PiP transition state updates. */ public void addPipTransitionStateChangedListener(PipTransitionStateChangedListener listener) { @@ -318,6 +349,11 @@ public class PipTransitionState { throw new IllegalStateException("Unknown state: " + state); } + public boolean isPipStateIdle() { + // This needs to be a valid in-PiP state that isn't a transient state. + return mState == ENTERED_PIP || mState == CHANGED_PIP_BOUNDS; + } + @Override public String toString() { return String.format("PipTransitionState(mState=%s, mInSwipePipToHomeTransition=%b)", |