Use sf animation handler in PIP PhysicsAnimator

To reduce jank caused by vsync app, replace whole animation handler
in PhysicsAnimator used by PIP to sf animation handler.

Bug: 159313747
Test: Launch PIP app and drag it around
Change-Id: Iebee75d071fecc2d98d4871d47d83a4b4143b94e
This commit is contained in:
Tony Huang
2020-07-01 16:22:24 +08:00
parent 9ef5558e1d
commit 7016e97d6e
2 changed files with 54 additions and 16 deletions

View File

@@ -26,9 +26,10 @@ import android.os.Debug;
import android.util.Log;
import android.view.Choreographer;
import androidx.dynamicanimation.animation.AnimationHandler;
import androidx.dynamicanimation.animation.AnimationHandler.FrameCallbackScheduler;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.systemui.pip.PipSnapAlgorithm;
import com.android.systemui.pip.PipTaskOrganizer;
import com.android.systemui.util.FloatingContentCoordinator;
@@ -74,9 +75,6 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
/** The region that all of PIP must stay within. */
private final Rect mFloatingAllowedArea = new Rect();
private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider =
new SfVsyncFrameCallbackProvider();
/**
* Temporary bounds used when PIP is being dragged or animated. These bounds are applied to PIP
* using {@link PipTaskOrganizer#scheduleUserResizePip}, so that we can animate shrinking into
@@ -94,8 +92,13 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
/** Coordinator instance for resolving conflicts with other floating content. */
private FloatingContentCoordinator mFloatingContentCoordinator;
/** Callback that re-sizes PIP to the animated bounds. */
private final Choreographer.FrameCallback mResizePipVsyncCallback;
private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
ThreadLocal.withInitial(() -> {
FrameCallbackScheduler scheduler = runnable ->
Choreographer.getSfInstance().postFrameCallback(t -> runnable.run());
AnimationHandler handler = new AnimationHandler(scheduler);
return handler;
});
/**
* PhysicsAnimator instance for animating {@link #mTemporaryBounds} using physics animations.
@@ -171,16 +174,15 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
mSnapAlgorithm = snapAlgorithm;
mFloatingContentCoordinator = floatingContentCoordinator;
mPipTaskOrganizer.registerPipTransitionCallback(mPipTransitionCallback);
mTemporaryBoundsPhysicsAnimator.setCustomAnimationHandler(
mSfAnimationHandlerThreadLocal.get());
mResizePipVsyncCallback = l -> {
mResizePipUpdateListener = (target, values) -> {
if (!mTemporaryBounds.isEmpty()) {
mPipTaskOrganizer.scheduleUserResizePip(
mBounds, mTemporaryBounds, null);
}
};
mResizePipUpdateListener = (target, values) ->
mSfVsyncFrameProvider.postFrameCallback(mResizePipVsyncCallback);
}
@NonNull

View File

@@ -20,6 +20,7 @@ import android.os.Looper
import android.util.ArrayMap
import android.util.Log
import android.view.View
import androidx.dynamicanimation.animation.AnimationHandler
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FlingAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
@@ -123,6 +124,12 @@ class PhysicsAnimator<T> private constructor (target: T) {
/** FlingConfig to use by default for properties whose fling configs were not provided. */
private var defaultFling: FlingConfig = globalDefaultFling
/**
* AnimationHandler to use if it need custom AnimationHandler, if this is null, it will use
* the default AnimationHandler in the DynamicAnimation.
*/
private var customAnimationHandler: AnimationHandler? = null
/**
* Internal listeners that respond to DynamicAnimations updating and ending, and dispatch to
* the listeners provided via [addUpdateListener] and [addEndListener]. This allows us to add
@@ -447,6 +454,14 @@ class PhysicsAnimator<T> private constructor (target: T) {
this.defaultFling = defaultFling
}
/**
* Set the custom AnimationHandler for all aniatmion in this animator. Set this with null for
* restoring to default AnimationHandler.
*/
fun setCustomAnimationHandler(handler: AnimationHandler) {
this.customAnimationHandler = handler
}
/** Starts the animations! */
fun start() {
startAction()
@@ -501,10 +516,13 @@ class PhysicsAnimator<T> private constructor (target: T) {
// springs) on this property before flinging.
cancel(animatedProperty)
// Apply the custom animation handler if it not null
val flingAnim = getFlingAnimation(animatedProperty, target)
flingAnim.animationHandler =
customAnimationHandler ?: flingAnim.animationHandler
// Apply the configuration and start the animation.
getFlingAnimation(animatedProperty, target)
.also { flingConfig.applyToAnimation(it) }
.start()
flingAnim.also { flingConfig.applyToAnimation(it) }.start()
}
}
@@ -516,6 +534,21 @@ class PhysicsAnimator<T> private constructor (target: T) {
if (flingConfig == null) {
// Apply the configuration and start the animation.
val springAnim = getSpringAnimation(animatedProperty, target)
// If customAnimationHander is exist and has not been set to the animation,
// it should set here.
if (customAnimationHandler != null &&
springAnim.animationHandler != customAnimationHandler) {
// Cancel the animation before set animation handler
if (springAnim.isRunning) {
cancel(animatedProperty)
}
// Apply the custom animation handler if it not null
springAnim.animationHandler =
customAnimationHandler ?: springAnim.animationHandler
}
// Apply the configuration and start the animation.
springConfig.applyToAnimation(springAnim)
animationStartActions.add(springAnim::start)
} else {
@@ -570,10 +603,13 @@ class PhysicsAnimator<T> private constructor (target: T) {
}
}
// Apply the custom animation handler if it not null
val springAnim = getSpringAnimation(animatedProperty, target)
springAnim.animationHandler =
customAnimationHandler ?: springAnim.animationHandler
// Apply the configuration and start the spring animation.
getSpringAnimation(animatedProperty, target)
.also { springConfig.applyToAnimation(it) }
.start()
springAnim.also { springConfig.applyToAnimation(it) }.start()
}
}
})