Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +3 −1 Original line number Original line Diff line number Diff line Loading @@ -127,8 +127,10 @@ public abstract class PipTransitionController implements Transitions.TransitionH /** /** * Called when the Shell wants to start resizing Pip transition/animation. * Called when the Shell wants to start resizing Pip transition/animation. * * @param duration the suggested duration for resize animation. */ */ public void startResizeTransition(WindowContainerTransaction wct) { public void startResizeTransition(WindowContainerTransaction wct, int duration) { // Default implementation does nothing. // Default implementation does nothing. } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java +8 −1 Original line number Original line Diff line number Diff line Loading @@ -47,9 +47,17 @@ public class PipResizeAnimator extends ValueAnimator @Nullable @Nullable private Runnable mAnimationEndCallback; private Runnable mAnimationEndCallback; private RectEvaluator mRectEvaluator; private RectEvaluator mRectEvaluator; // Bounds relative to which scaling/cropping must be done. private final Rect mBaseBounds = new Rect(); private final Rect mBaseBounds = new Rect(); // Bounds to animate from. private final Rect mStartBounds = new Rect(); private final Rect mStartBounds = new Rect(); // Target bounds. private final Rect mEndBounds = new Rect(); private final Rect mEndBounds = new Rect(); // Bounds updated by the evaluator as animator is running. private final Rect mAnimatedRect = new Rect(); private final Rect mAnimatedRect = new Rect(); private final float mDelta; private final float mDelta; Loading Loading @@ -84,7 +92,6 @@ public class PipResizeAnimator extends ValueAnimator addListener(this); addListener(this); addUpdateListener(this); addUpdateListener(this); setEvaluator(mRectEvaluator); setEvaluator(mRectEvaluator); // TODO: change this setDuration(duration); setDuration(duration); } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -352,6 +352,7 @@ public class PipController implements ConfigurationChangeListener, mPipBoundsAlgorithm.dump(pw, innerPrefix); mPipBoundsAlgorithm.dump(pw, innerPrefix); mPipBoundsState.dump(pw, innerPrefix); mPipBoundsState.dump(pw, innerPrefix); mPipDisplayLayoutState.dump(pw, innerPrefix); mPipDisplayLayoutState.dump(pw, innerPrefix); mPipTransitionState.dump(pw, innerPrefix); } } /** /** Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java +87 −25 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.pip2.phone; package com.android.wm.shell.pip2.phone; import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY; import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_NO_BOUNCY; import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_NO_BOUNCY; import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW; import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW; import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_MEDIUM; import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_MEDIUM; Loading @@ -25,6 +26,7 @@ import static com.android.wm.shell.common.pip.PipBoundsState.STASH_TYPE_NONE; import static com.android.wm.shell.common.pip.PipBoundsState.STASH_TYPE_RIGHT; import static com.android.wm.shell.common.pip.PipBoundsState.STASH_TYPE_RIGHT; import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_DISMISS; import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_DISMISS; import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_NONE; import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_NONE; import static com.android.wm.shell.pip2.phone.PipTransition.ANIMATING_BOUNDS_CHANGE_DURATION; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; Loading @@ -36,6 +38,7 @@ import android.os.Debug; import android.view.SurfaceControl; import android.view.SurfaceControl; import com.android.internal.protolog.ProtoLog; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.Preconditions; import com.android.wm.shell.R; import com.android.wm.shell.R; import com.android.wm.shell.animation.FloatProperties; import com.android.wm.shell.animation.FloatProperties; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.FloatingContentCoordinator; Loading @@ -45,6 +48,7 @@ import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipPerfHintController; import com.android.wm.shell.common.pip.PipPerfHintController; import com.android.wm.shell.common.pip.PipSnapAlgorithm; import com.android.wm.shell.common.pip.PipSnapAlgorithm; import com.android.wm.shell.pip2.animation.PipResizeAnimator; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.shared.animation.PhysicsAnimator; import com.android.wm.shell.shared.animation.PhysicsAnimator; Loading @@ -62,6 +66,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, PipTransitionState.PipTransitionStateChangedListener { PipTransitionState.PipTransitionStateChangedListener { private static final String TAG = "PipMotionHelper"; private static final String TAG = "PipMotionHelper"; private static final String FLING_BOUNDS_CHANGE = "fling_bounds_change"; private static final String FLING_BOUNDS_CHANGE = "fling_bounds_change"; private static final String ANIMATING_BOUNDS_CHANGE = "animating_bounds_change"; private static final boolean DEBUG = false; private static final boolean DEBUG = false; private static final int SHRINK_STACK_FROM_MENU_DURATION = 250; private static final int SHRINK_STACK_FROM_MENU_DURATION = 250; Loading Loading @@ -113,7 +118,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, /** SpringConfig to use for fling-then-spring animations. */ /** SpringConfig to use for fling-then-spring animations. */ private final PhysicsAnimator.SpringConfig mSpringConfig = private final PhysicsAnimator.SpringConfig mSpringConfig = new PhysicsAnimator.SpringConfig(700f, DAMPING_RATIO_NO_BOUNCY); new PhysicsAnimator.SpringConfig(300f, DAMPING_RATIO_LOW_BOUNCY); /** SpringConfig used for animating into the dismiss region, matches the one in /** SpringConfig used for animating into the dismiss region, matches the one in * {@link MagnetizedObject}. */ * {@link MagnetizedObject}. */ Loading Loading @@ -152,9 +157,16 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private boolean mDismissalPending = false; private boolean mDismissalPending = false; /** /** * Set to true if bounds change transition has been scheduled from PipMotionHelper. * Set to true if bounds change transition has been scheduled from PipMotionHelper * after animating is over. */ */ private boolean mWaitingForBoundsChangeTransition = false; private boolean mWaitingForFlingTransition = false; /** * Set to true if bounds change transition has been scheduled from PipMotionHelper, * and if the animation is supposed to run while transition is playing. */ private boolean mWaitingToPlayBoundsChangeTransition = false; /** /** * Gets set in {@link #animateToExpandedState(Rect, Rect, Rect, Runnable)}, this callback is * Gets set in {@link #animateToExpandedState(Rect, Rect, Rect, Runnable)}, this callback is Loading Loading @@ -634,6 +646,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, // The physics animation ended, though we may not necessarily be done animating, such as // 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. // when we're still dragging after moving out of the magnetic target. if (!mDismissalPending && !mSpringingToTouch && !mMagnetizedPip.getObjectStuckToTarget()) { if (!mDismissalPending && !mSpringingToTouch && !mMagnetizedPip.getObjectStuckToTarget()) { // Update the earlier estimate on bounds we are animating towards, since physics // animator is non-deterministic. setAnimatingToBounds(mPipBoundsState.getMotionBoundsState().getBoundsInMotion()); // do not schedule resize if PiP is dismissing, which may cause app re-open to // do not schedule resize if PiP is dismissing, which may cause app re-open to // mBounds instead of its normal bounds. // mBounds instead of its normal bounds. Bundle extra = new Bundle(); Bundle extra = new Bundle(); Loading Loading @@ -673,6 +688,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, * Directly resizes the PiP to the given {@param bounds}. * Directly resizes the PiP to the given {@param bounds}. */ */ private void resizeAndAnimatePipUnchecked(Rect toBounds, int duration) { private void resizeAndAnimatePipUnchecked(Rect toBounds, int duration) { if (mPipBoundsState.getMotionBoundsState().isInMotion()) { // Do not carry out any resizing if we are dragging or physics animator is running. return; } if (DEBUG) { if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: resizeAndAnimatePipUnchecked: toBounds=%s" "%s: resizeAndAnimatePipUnchecked: toBounds=%s" Loading @@ -682,10 +702,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, // Intentionally resize here even if the current bounds match the destination bounds. // Intentionally resize here even if the current bounds match the destination bounds. // This is so all the proper callbacks are performed. // This is so all the proper callbacks are performed. setAnimatingToBounds(toBounds); // mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, Bundle extra = new Bundle(); // TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND, null /* updateBoundsCallback */); extra.putBoolean(ANIMATING_BOUNDS_CHANGE, true); // setAnimatingToBounds(toBounds); extra.putInt(ANIMATING_BOUNDS_CHANGE_DURATION, duration); mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra); } } @Override @Override Loading @@ -694,7 +715,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, @Nullable Bundle extra) { @Nullable Bundle extra) { switch (newState) { switch (newState) { case PipTransitionState.SCHEDULED_BOUNDS_CHANGE: case PipTransitionState.SCHEDULED_BOUNDS_CHANGE: if (!extra.getBoolean(FLING_BOUNDS_CHANGE)) break; mWaitingForFlingTransition = extra.getBoolean(FLING_BOUNDS_CHANGE); mWaitingToPlayBoundsChangeTransition = extra.getBoolean(ANIMATING_BOUNDS_CHANGE); if (!mWaitingForFlingTransition && !mWaitingToPlayBoundsChangeTransition) { break; } if (mPipBoundsState.getBounds().equals( if (mPipBoundsState.getBounds().equals( mPipBoundsState.getMotionBoundsState().getBoundsInMotion())) { mPipBoundsState.getMotionBoundsState().getBoundsInMotion())) { Loading @@ -709,20 +734,43 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, break; break; } } // If touch is turned off and we are in a fling animation, schedule a transition. // Delay config until the end, if we are animating after scheduling the transition. mWaitingForBoundsChangeTransition = true; mPipScheduler.scheduleAnimateResizePip( mPipScheduler.scheduleAnimateResizePip( mPipBoundsState.getMotionBoundsState().getBoundsInMotion()); mPipBoundsState.getMotionBoundsState().getAnimatingToBounds(), mWaitingToPlayBoundsChangeTransition, extra.getInt(ANIMATING_BOUNDS_CHANGE_DURATION, PipTransition.BOUNDS_CHANGE_JUMPCUT_DURATION)); break; break; case PipTransitionState.CHANGING_PIP_BOUNDS: case PipTransitionState.CHANGING_PIP_BOUNDS: if (!mWaitingForBoundsChangeTransition) break; // If bounds change transition was scheduled from this class, handle leash updates. mWaitingForBoundsChangeTransition = false; SurfaceControl.Transaction startTx = extra.getParcelable( SurfaceControl.Transaction startTx = extra.getParcelable( PipTransition.PIP_START_TX, SurfaceControl.Transaction.class); PipTransition.PIP_START_TX, SurfaceControl.Transaction.class); SurfaceControl.Transaction finishTx = extra.getParcelable( PipTransition.PIP_FINISH_TX, SurfaceControl.Transaction.class); Rect destinationBounds = extra.getParcelable( Rect destinationBounds = extra.getParcelable( PipTransition.PIP_DESTINATION_BOUNDS, Rect.class); PipTransition.PIP_DESTINATION_BOUNDS, Rect.class); final int duration = extra.getInt(ANIMATING_BOUNDS_CHANGE_DURATION, PipTransition.BOUNDS_CHANGE_JUMPCUT_DURATION); if (mWaitingForFlingTransition) { mWaitingForFlingTransition = false; handleFlingTransition(startTx, finishTx, destinationBounds); } else if (mWaitingToPlayBoundsChangeTransition) { mWaitingToPlayBoundsChangeTransition = false; startResizeAnimation(startTx, finishTx, destinationBounds, duration); } break; case PipTransitionState.EXITING_PIP: // We need to force finish any local animators if about to leave PiP, to avoid // breaking the state (e.g. leashes are cleaned up upon exit). if (!mPipBoundsState.getMotionBoundsState().isInMotion()) break; cancelPhysicsAnimation(); settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */); break; } } private void handleFlingTransition(SurfaceControl.Transaction startTx, SurfaceControl.Transaction finishTx, Rect destinationBounds) { startTx.setPosition(mPipTransitionState.mPinnedTaskLeash, startTx.setPosition(mPipTransitionState.mPinnedTaskLeash, destinationBounds.left, destinationBounds.top); destinationBounds.left, destinationBounds.top); startTx.apply(); startTx.apply(); Loading @@ -733,14 +781,28 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, // Signal that the transition is done - should update transition state by default. // Signal that the transition is done - should update transition state by default. mPipScheduler.scheduleFinishResizePip(false /* configAtEnd */); mPipScheduler.scheduleFinishResizePip(false /* configAtEnd */); break; case PipTransitionState.EXITING_PIP: // We need to force finish any local animators if about to leave PiP, to avoid // breaking the state (e.g. leashes are cleaned up upon exit). if (!mPipBoundsState.getMotionBoundsState().isInMotion()) break; cancelPhysicsAnimation(); settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */); } } private void startResizeAnimation(SurfaceControl.Transaction startTx, SurfaceControl.Transaction finishTx, Rect destinationBounds, int duration) { SurfaceControl pipLeash = mPipTransitionState.mPinnedTaskLeash; Preconditions.checkState(pipLeash != null, "No leash cached by mPipTransitionState=" + mPipTransitionState); startTx.setWindowCrop(pipLeash, mPipBoundsState.getBounds().width(), mPipBoundsState.getBounds().height()); PipResizeAnimator animator = new PipResizeAnimator(mContext, pipLeash, 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. cleanUpHighPerfSessionMaybe(); // Signal that we are done with resize transition mPipScheduler.scheduleFinishResizePip(true /* configAtEnd */); }); animator.start(); } } private void settlePipBoundsAfterPhysicsAnimation(boolean animatingAfter) { private void settlePipBoundsAfterPhysicsAnimation(boolean animatingAfter) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java +7 −2 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.pip2.phone; package com.android.wm.shell.pip2.phone; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE; import static com.android.wm.shell.pip2.phone.PipTransition.ANIMATING_BOUNDS_CHANGE_DURATION; import android.annotation.Nullable; import android.annotation.Nullable; import android.content.Context; import android.content.Context; Loading Loading @@ -535,7 +536,8 @@ public class PipResizeGestureHandler implements mWaitingForBoundsChangeTransition = true; mWaitingForBoundsChangeTransition = true; // Schedule PiP resize transition, but delay any config updates until very end. // Schedule PiP resize transition, but delay any config updates until very end. mPipScheduler.scheduleAnimateResizePip(mLastResizeBounds, true /* configAtEnd */); mPipScheduler.scheduleAnimateResizePip(mLastResizeBounds, true /* configAtEnd */, PINCH_RESIZE_SNAP_DURATION); break; break; case PipTransitionState.CHANGING_PIP_BOUNDS: case PipTransitionState.CHANGING_PIP_BOUNDS: if (!mWaitingForBoundsChangeTransition) break; if (!mWaitingForBoundsChangeTransition) break; Loading @@ -550,12 +552,15 @@ public class PipResizeGestureHandler implements PipTransition.PIP_START_TX, SurfaceControl.Transaction.class); PipTransition.PIP_START_TX, SurfaceControl.Transaction.class); SurfaceControl.Transaction finishTx = extra.getParcelable( SurfaceControl.Transaction finishTx = extra.getParcelable( PipTransition.PIP_FINISH_TX, SurfaceControl.Transaction.class); PipTransition.PIP_FINISH_TX, SurfaceControl.Transaction.class); final int duration = extra.getInt(ANIMATING_BOUNDS_CHANGE_DURATION, PipTransition.BOUNDS_CHANGE_JUMPCUT_DURATION); startTx.setWindowCrop(pipLeash, mPipBoundsState.getBounds().width(), startTx.setWindowCrop(pipLeash, mPipBoundsState.getBounds().width(), mPipBoundsState.getBounds().height()); mPipBoundsState.getBounds().height()); PipResizeAnimator animator = new PipResizeAnimator(mContext, pipLeash, PipResizeAnimator animator = new PipResizeAnimator(mContext, pipLeash, startTx, finishTx, mPipBoundsState.getBounds(), mStartBoundsAfterRelease, startTx, finishTx, mPipBoundsState.getBounds(), mStartBoundsAfterRelease, mLastResizeBounds, PINCH_RESIZE_SNAP_DURATION, mAngle); mLastResizeBounds, duration, mAngle); animator.setAnimationEndCallback(() -> { animator.setAnimationEndCallback(() -> { // All motion operations have actually finished, so make bounds cache updates. // All motion operations have actually finished, so make bounds cache updates. mUpdateResizeBoundsCallback.accept(mLastResizeBounds); mUpdateResizeBoundsCallback.accept(mLastResizeBounds); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTransitionController.java +3 −1 Original line number Original line Diff line number Diff line Loading @@ -127,8 +127,10 @@ public abstract class PipTransitionController implements Transitions.TransitionH /** /** * Called when the Shell wants to start resizing Pip transition/animation. * Called when the Shell wants to start resizing Pip transition/animation. * * @param duration the suggested duration for resize animation. */ */ public void startResizeTransition(WindowContainerTransaction wct) { public void startResizeTransition(WindowContainerTransaction wct, int duration) { // Default implementation does nothing. // Default implementation does nothing. } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipResizeAnimator.java +8 −1 Original line number Original line Diff line number Diff line Loading @@ -47,9 +47,17 @@ public class PipResizeAnimator extends ValueAnimator @Nullable @Nullable private Runnable mAnimationEndCallback; private Runnable mAnimationEndCallback; private RectEvaluator mRectEvaluator; private RectEvaluator mRectEvaluator; // Bounds relative to which scaling/cropping must be done. private final Rect mBaseBounds = new Rect(); private final Rect mBaseBounds = new Rect(); // Bounds to animate from. private final Rect mStartBounds = new Rect(); private final Rect mStartBounds = new Rect(); // Target bounds. private final Rect mEndBounds = new Rect(); private final Rect mEndBounds = new Rect(); // Bounds updated by the evaluator as animator is running. private final Rect mAnimatedRect = new Rect(); private final Rect mAnimatedRect = new Rect(); private final float mDelta; private final float mDelta; Loading Loading @@ -84,7 +92,6 @@ public class PipResizeAnimator extends ValueAnimator addListener(this); addListener(this); addUpdateListener(this); addUpdateListener(this); setEvaluator(mRectEvaluator); setEvaluator(mRectEvaluator); // TODO: change this setDuration(duration); setDuration(duration); } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java +1 −0 Original line number Original line Diff line number Diff line Loading @@ -352,6 +352,7 @@ public class PipController implements ConfigurationChangeListener, mPipBoundsAlgorithm.dump(pw, innerPrefix); mPipBoundsAlgorithm.dump(pw, innerPrefix); mPipBoundsState.dump(pw, innerPrefix); mPipBoundsState.dump(pw, innerPrefix); mPipDisplayLayoutState.dump(pw, innerPrefix); mPipDisplayLayoutState.dump(pw, innerPrefix); mPipTransitionState.dump(pw, innerPrefix); } } /** /** Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java +87 −25 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.pip2.phone; package com.android.wm.shell.pip2.phone; import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_LOW_BOUNCY; import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_NO_BOUNCY; import static androidx.dynamicanimation.animation.SpringForce.DAMPING_RATIO_NO_BOUNCY; import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW; import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_LOW; import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_MEDIUM; import static androidx.dynamicanimation.animation.SpringForce.STIFFNESS_MEDIUM; Loading @@ -25,6 +26,7 @@ import static com.android.wm.shell.common.pip.PipBoundsState.STASH_TYPE_NONE; import static com.android.wm.shell.common.pip.PipBoundsState.STASH_TYPE_RIGHT; import static com.android.wm.shell.common.pip.PipBoundsState.STASH_TYPE_RIGHT; import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_DISMISS; import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_DISMISS; import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_NONE; import static com.android.wm.shell.pip2.phone.PipMenuView.ANIM_TYPE_NONE; import static com.android.wm.shell.pip2.phone.PipTransition.ANIMATING_BOUNDS_CHANGE_DURATION; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; Loading @@ -36,6 +38,7 @@ import android.os.Debug; import android.view.SurfaceControl; import android.view.SurfaceControl; import com.android.internal.protolog.ProtoLog; import com.android.internal.protolog.ProtoLog; import com.android.internal.util.Preconditions; import com.android.wm.shell.R; import com.android.wm.shell.R; import com.android.wm.shell.animation.FloatProperties; import com.android.wm.shell.animation.FloatProperties; import com.android.wm.shell.common.FloatingContentCoordinator; import com.android.wm.shell.common.FloatingContentCoordinator; Loading @@ -45,6 +48,7 @@ import com.android.wm.shell.common.pip.PipBoundsAlgorithm; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipBoundsState; import com.android.wm.shell.common.pip.PipPerfHintController; import com.android.wm.shell.common.pip.PipPerfHintController; import com.android.wm.shell.common.pip.PipSnapAlgorithm; import com.android.wm.shell.common.pip.PipSnapAlgorithm; import com.android.wm.shell.pip2.animation.PipResizeAnimator; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.shared.animation.PhysicsAnimator; import com.android.wm.shell.shared.animation.PhysicsAnimator; Loading @@ -62,6 +66,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, PipTransitionState.PipTransitionStateChangedListener { PipTransitionState.PipTransitionStateChangedListener { private static final String TAG = "PipMotionHelper"; private static final String TAG = "PipMotionHelper"; private static final String FLING_BOUNDS_CHANGE = "fling_bounds_change"; private static final String FLING_BOUNDS_CHANGE = "fling_bounds_change"; private static final String ANIMATING_BOUNDS_CHANGE = "animating_bounds_change"; private static final boolean DEBUG = false; private static final boolean DEBUG = false; private static final int SHRINK_STACK_FROM_MENU_DURATION = 250; private static final int SHRINK_STACK_FROM_MENU_DURATION = 250; Loading Loading @@ -113,7 +118,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, /** SpringConfig to use for fling-then-spring animations. */ /** SpringConfig to use for fling-then-spring animations. */ private final PhysicsAnimator.SpringConfig mSpringConfig = private final PhysicsAnimator.SpringConfig mSpringConfig = new PhysicsAnimator.SpringConfig(700f, DAMPING_RATIO_NO_BOUNCY); new PhysicsAnimator.SpringConfig(300f, DAMPING_RATIO_LOW_BOUNCY); /** SpringConfig used for animating into the dismiss region, matches the one in /** SpringConfig used for animating into the dismiss region, matches the one in * {@link MagnetizedObject}. */ * {@link MagnetizedObject}. */ Loading Loading @@ -152,9 +157,16 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, private boolean mDismissalPending = false; private boolean mDismissalPending = false; /** /** * Set to true if bounds change transition has been scheduled from PipMotionHelper. * Set to true if bounds change transition has been scheduled from PipMotionHelper * after animating is over. */ */ private boolean mWaitingForBoundsChangeTransition = false; private boolean mWaitingForFlingTransition = false; /** * Set to true if bounds change transition has been scheduled from PipMotionHelper, * and if the animation is supposed to run while transition is playing. */ private boolean mWaitingToPlayBoundsChangeTransition = false; /** /** * Gets set in {@link #animateToExpandedState(Rect, Rect, Rect, Runnable)}, this callback is * Gets set in {@link #animateToExpandedState(Rect, Rect, Rect, Runnable)}, this callback is Loading Loading @@ -634,6 +646,9 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, // The physics animation ended, though we may not necessarily be done animating, such as // 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. // when we're still dragging after moving out of the magnetic target. if (!mDismissalPending && !mSpringingToTouch && !mMagnetizedPip.getObjectStuckToTarget()) { if (!mDismissalPending && !mSpringingToTouch && !mMagnetizedPip.getObjectStuckToTarget()) { // Update the earlier estimate on bounds we are animating towards, since physics // animator is non-deterministic. setAnimatingToBounds(mPipBoundsState.getMotionBoundsState().getBoundsInMotion()); // do not schedule resize if PiP is dismissing, which may cause app re-open to // do not schedule resize if PiP is dismissing, which may cause app re-open to // mBounds instead of its normal bounds. // mBounds instead of its normal bounds. Bundle extra = new Bundle(); Bundle extra = new Bundle(); Loading Loading @@ -673,6 +688,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, * Directly resizes the PiP to the given {@param bounds}. * Directly resizes the PiP to the given {@param bounds}. */ */ private void resizeAndAnimatePipUnchecked(Rect toBounds, int duration) { private void resizeAndAnimatePipUnchecked(Rect toBounds, int duration) { if (mPipBoundsState.getMotionBoundsState().isInMotion()) { // Do not carry out any resizing if we are dragging or physics animator is running. return; } if (DEBUG) { if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: resizeAndAnimatePipUnchecked: toBounds=%s" "%s: resizeAndAnimatePipUnchecked: toBounds=%s" Loading @@ -682,10 +702,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, // Intentionally resize here even if the current bounds match the destination bounds. // Intentionally resize here even if the current bounds match the destination bounds. // This is so all the proper callbacks are performed. // This is so all the proper callbacks are performed. setAnimatingToBounds(toBounds); // mPipTaskOrganizer.scheduleAnimateResizePip(toBounds, duration, Bundle extra = new Bundle(); // TRANSITION_DIRECTION_EXPAND_OR_UNEXPAND, null /* updateBoundsCallback */); extra.putBoolean(ANIMATING_BOUNDS_CHANGE, true); // setAnimatingToBounds(toBounds); extra.putInt(ANIMATING_BOUNDS_CHANGE_DURATION, duration); mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra); } } @Override @Override Loading @@ -694,7 +715,11 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, @Nullable Bundle extra) { @Nullable Bundle extra) { switch (newState) { switch (newState) { case PipTransitionState.SCHEDULED_BOUNDS_CHANGE: case PipTransitionState.SCHEDULED_BOUNDS_CHANGE: if (!extra.getBoolean(FLING_BOUNDS_CHANGE)) break; mWaitingForFlingTransition = extra.getBoolean(FLING_BOUNDS_CHANGE); mWaitingToPlayBoundsChangeTransition = extra.getBoolean(ANIMATING_BOUNDS_CHANGE); if (!mWaitingForFlingTransition && !mWaitingToPlayBoundsChangeTransition) { break; } if (mPipBoundsState.getBounds().equals( if (mPipBoundsState.getBounds().equals( mPipBoundsState.getMotionBoundsState().getBoundsInMotion())) { mPipBoundsState.getMotionBoundsState().getBoundsInMotion())) { Loading @@ -709,20 +734,43 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, break; break; } } // If touch is turned off and we are in a fling animation, schedule a transition. // Delay config until the end, if we are animating after scheduling the transition. mWaitingForBoundsChangeTransition = true; mPipScheduler.scheduleAnimateResizePip( mPipScheduler.scheduleAnimateResizePip( mPipBoundsState.getMotionBoundsState().getBoundsInMotion()); mPipBoundsState.getMotionBoundsState().getAnimatingToBounds(), mWaitingToPlayBoundsChangeTransition, extra.getInt(ANIMATING_BOUNDS_CHANGE_DURATION, PipTransition.BOUNDS_CHANGE_JUMPCUT_DURATION)); break; break; case PipTransitionState.CHANGING_PIP_BOUNDS: case PipTransitionState.CHANGING_PIP_BOUNDS: if (!mWaitingForBoundsChangeTransition) break; // If bounds change transition was scheduled from this class, handle leash updates. mWaitingForBoundsChangeTransition = false; SurfaceControl.Transaction startTx = extra.getParcelable( SurfaceControl.Transaction startTx = extra.getParcelable( PipTransition.PIP_START_TX, SurfaceControl.Transaction.class); PipTransition.PIP_START_TX, SurfaceControl.Transaction.class); SurfaceControl.Transaction finishTx = extra.getParcelable( PipTransition.PIP_FINISH_TX, SurfaceControl.Transaction.class); Rect destinationBounds = extra.getParcelable( Rect destinationBounds = extra.getParcelable( PipTransition.PIP_DESTINATION_BOUNDS, Rect.class); PipTransition.PIP_DESTINATION_BOUNDS, Rect.class); final int duration = extra.getInt(ANIMATING_BOUNDS_CHANGE_DURATION, PipTransition.BOUNDS_CHANGE_JUMPCUT_DURATION); if (mWaitingForFlingTransition) { mWaitingForFlingTransition = false; handleFlingTransition(startTx, finishTx, destinationBounds); } else if (mWaitingToPlayBoundsChangeTransition) { mWaitingToPlayBoundsChangeTransition = false; startResizeAnimation(startTx, finishTx, destinationBounds, duration); } break; case PipTransitionState.EXITING_PIP: // We need to force finish any local animators if about to leave PiP, to avoid // breaking the state (e.g. leashes are cleaned up upon exit). if (!mPipBoundsState.getMotionBoundsState().isInMotion()) break; cancelPhysicsAnimation(); settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */); break; } } private void handleFlingTransition(SurfaceControl.Transaction startTx, SurfaceControl.Transaction finishTx, Rect destinationBounds) { startTx.setPosition(mPipTransitionState.mPinnedTaskLeash, startTx.setPosition(mPipTransitionState.mPinnedTaskLeash, destinationBounds.left, destinationBounds.top); destinationBounds.left, destinationBounds.top); startTx.apply(); startTx.apply(); Loading @@ -733,14 +781,28 @@ public class PipMotionHelper implements PipAppOpsListener.Callback, // Signal that the transition is done - should update transition state by default. // Signal that the transition is done - should update transition state by default. mPipScheduler.scheduleFinishResizePip(false /* configAtEnd */); mPipScheduler.scheduleFinishResizePip(false /* configAtEnd */); break; case PipTransitionState.EXITING_PIP: // We need to force finish any local animators if about to leave PiP, to avoid // breaking the state (e.g. leashes are cleaned up upon exit). if (!mPipBoundsState.getMotionBoundsState().isInMotion()) break; cancelPhysicsAnimation(); settlePipBoundsAfterPhysicsAnimation(false /* animatingAfter */); } } private void startResizeAnimation(SurfaceControl.Transaction startTx, SurfaceControl.Transaction finishTx, Rect destinationBounds, int duration) { SurfaceControl pipLeash = mPipTransitionState.mPinnedTaskLeash; Preconditions.checkState(pipLeash != null, "No leash cached by mPipTransitionState=" + mPipTransitionState); startTx.setWindowCrop(pipLeash, mPipBoundsState.getBounds().width(), mPipBoundsState.getBounds().height()); PipResizeAnimator animator = new PipResizeAnimator(mContext, pipLeash, 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. cleanUpHighPerfSessionMaybe(); // Signal that we are done with resize transition mPipScheduler.scheduleFinishResizePip(true /* configAtEnd */); }); animator.start(); } } private void settlePipBoundsAfterPhysicsAnimation(boolean animatingAfter) { private void settlePipBoundsAfterPhysicsAnimation(boolean animatingAfter) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipResizeGestureHandler.java +7 −2 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.wm.shell.pip2.phone; package com.android.wm.shell.pip2.phone; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE; import static com.android.internal.policy.TaskResizingAlgorithm.CTRL_NONE; import static com.android.wm.shell.pip2.phone.PipTransition.ANIMATING_BOUNDS_CHANGE_DURATION; import android.annotation.Nullable; import android.annotation.Nullable; import android.content.Context; import android.content.Context; Loading Loading @@ -535,7 +536,8 @@ public class PipResizeGestureHandler implements mWaitingForBoundsChangeTransition = true; mWaitingForBoundsChangeTransition = true; // Schedule PiP resize transition, but delay any config updates until very end. // Schedule PiP resize transition, but delay any config updates until very end. mPipScheduler.scheduleAnimateResizePip(mLastResizeBounds, true /* configAtEnd */); mPipScheduler.scheduleAnimateResizePip(mLastResizeBounds, true /* configAtEnd */, PINCH_RESIZE_SNAP_DURATION); break; break; case PipTransitionState.CHANGING_PIP_BOUNDS: case PipTransitionState.CHANGING_PIP_BOUNDS: if (!mWaitingForBoundsChangeTransition) break; if (!mWaitingForBoundsChangeTransition) break; Loading @@ -550,12 +552,15 @@ public class PipResizeGestureHandler implements PipTransition.PIP_START_TX, SurfaceControl.Transaction.class); PipTransition.PIP_START_TX, SurfaceControl.Transaction.class); SurfaceControl.Transaction finishTx = extra.getParcelable( SurfaceControl.Transaction finishTx = extra.getParcelable( PipTransition.PIP_FINISH_TX, SurfaceControl.Transaction.class); PipTransition.PIP_FINISH_TX, SurfaceControl.Transaction.class); final int duration = extra.getInt(ANIMATING_BOUNDS_CHANGE_DURATION, PipTransition.BOUNDS_CHANGE_JUMPCUT_DURATION); startTx.setWindowCrop(pipLeash, mPipBoundsState.getBounds().width(), startTx.setWindowCrop(pipLeash, mPipBoundsState.getBounds().width(), mPipBoundsState.getBounds().height()); mPipBoundsState.getBounds().height()); PipResizeAnimator animator = new PipResizeAnimator(mContext, pipLeash, PipResizeAnimator animator = new PipResizeAnimator(mContext, pipLeash, startTx, finishTx, mPipBoundsState.getBounds(), mStartBoundsAfterRelease, startTx, finishTx, mPipBoundsState.getBounds(), mStartBoundsAfterRelease, mLastResizeBounds, PINCH_RESIZE_SNAP_DURATION, mAngle); mLastResizeBounds, duration, mAngle); animator.setAnimationEndCallback(() -> { animator.setAnimationEndCallback(() -> { // All motion operations have actually finished, so make bounds cache updates. // All motion operations have actually finished, so make bounds cache updates. mUpdateResizeBoundsCallback.accept(mLastResizeBounds); mUpdateResizeBoundsCallback.accept(mLastResizeBounds); Loading