Merge "Fine tune animation parameters for IME animations" into rvc-dev am: 08a45d2445 am: 2a392ab3a8

Change-Id: Ic79b78235446e227af9ac6d8e62af96edccf2594
This commit is contained in:
Jorim Jaggi
2020-03-20 11:38:14 +00:00
committed by Automerger Merge Worker
5 changed files with 118 additions and 77 deletions

View File

@@ -68,7 +68,6 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
private final @InsetsType int mTypes;
private final InsetsAnimationControlCallbacks mController;
private final WindowInsetsAnimation mAnimation;
private final boolean mFade;
private Insets mCurrentInsets;
private Insets mPendingInsets;
private float mPendingFraction;
@@ -83,11 +82,10 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
InsetsState state, WindowInsetsAnimationControlListener listener,
@InsetsType int types,
InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
boolean fade, @AnimationType int animationType) {
@AnimationType int animationType) {
mControls = controls;
mListener = listener;
mTypes = types;
mFade = fade;
mController = controller;
mInitialInsetsState = new InsetsState(state, true /* copySources */);
mCurrentInsets = getInsetsFromState(mInitialInsetsState, frame, null /* typeSideMap */);
@@ -299,8 +297,6 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
// If the system is controlling the insets source, the leash can be null.
if (leash != null) {
// TODO: use a better interpolation for fade.
alpha = mFade ? ((float) inset / maxInset * 0.3f + 0.7f) : alpha;
SurfaceParams params = new SurfaceParams.Builder(leash)
.withAlpha(side == ISIDE_FLOATING ? 1 : alpha)
.withMatrix(mTmpMatrix)

View File

@@ -88,11 +88,11 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro
InsetsState state, WindowInsetsAnimationControlListener listener,
@InsetsType int types,
InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
boolean fade, @AnimationType int animationType, Handler mainThreadHandler) {
@AnimationType int animationType, Handler mainThreadHandler) {
mMainThreadHandler = mainThreadHandler;
mOuterCallbacks = controller;
mControl = new InsetsAnimationControlImpl(copyControls(controls), frame, state, listener,
types, mCallbacks, durationMs, interpolator, fade, animationType);
types, mCallbacks, durationMs, interpolator, animationType);
InsetsAnimationThread.getHandler().post(() -> listener.onReady(mControl, types));
}

View File

@@ -27,7 +27,9 @@ import android.animation.AnimationHandler;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -36,6 +38,7 @@ import android.graphics.Rect;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.RemoteException;
import android.renderscript.Sampler.Value;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
@@ -50,6 +53,7 @@ import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation.Bounds;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.PathInterpolator;
import com.android.internal.annotations.VisibleForTesting;
@@ -72,9 +76,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private static final int ANIMATION_DURATION_SHOW_MS = 275;
private static final int ANIMATION_DURATION_HIDE_MS = 340;
private static final int ANIMATION_DURATION_SYNC_IME_MS = 285;
private static final int ANIMATION_DURATION_UNSYNC_IME_MS = 200;
private static final int PENDING_CONTROL_TIMEOUT_MS = 2000;
public static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
public static final Interpolator SYSTEM_BARS_INTERPOLATOR =
new PathInterpolator(0.4f, 0f, 0.2f, 1f);
private static final Interpolator SYNC_IME_INTERPOLATOR =
new PathInterpolator(0.2f, 0f, 0f, 1f);
private static final Interpolator LINEAR_OUT_SLOW_IN_INTERPOLATOR =
new PathInterpolator(0, 0, 0.2f, 1f);
private static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR =
new PathInterpolator(0.4f, 0f, 1f, 1f);
/**
* Layout mode during insets animation: The views should be laid out as if the changing inset
@@ -138,27 +153,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
(int) (startValue.right + fraction * (endValue.right - startValue.right)),
(int) (startValue.bottom + fraction * (endValue.bottom - startValue.bottom)));
/**
* Linear animation property
*/
private static class InsetsProperty extends Property<WindowInsetsAnimationController, Insets> {
InsetsProperty() {
super(Insets.class, "Insets");
}
@Override
public Insets get(WindowInsetsAnimationController object) {
return object.getCurrentInsets();
}
@Override
public void set(WindowInsetsAnimationController controller, Insets value) {
controller.setInsetsAndAlpha(
value, 1f /* alpha */, (((InternalAnimationControlListener)
((InsetsAnimationControlImpl) controller).getListener())
.getRawFraction()));
}
}
/**
* The default implementation of listener, to be used by InsetsController and InsetsPolicy to
* animate insets.
@@ -167,9 +161,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
implements WindowInsetsAnimationControlListener {
private WindowInsetsAnimationController mController;
private ObjectAnimator mAnimator;
private ValueAnimator mAnimator;
private final boolean mShow;
private final boolean mUseSfVsync;
private final boolean mHasAnimationCallbacks;
private final @InsetsType int mRequestedTypes;
private final long mDurationMs;
private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
new ThreadLocal<AnimationHandler>() {
@@ -181,24 +177,40 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
};
public InternalAnimationControlListener(boolean show, boolean useSfVsync) {
public InternalAnimationControlListener(boolean show, boolean hasAnimationCallbacks,
int requestedTypes) {
mShow = show;
mUseSfVsync = useSfVsync;
mHasAnimationCallbacks = hasAnimationCallbacks;
mRequestedTypes = requestedTypes;
mDurationMs = calculateDurationMs();
}
@Override
public void onReady(WindowInsetsAnimationController controller, int types) {
mController = controller;
mAnimator = ObjectAnimator.ofObject(
controller,
new InsetsProperty(),
sEvaluator,
mShow ? controller.getHiddenStateInsets() : controller.getShownStateInsets(),
mShow ? controller.getShownStateInsets() : controller.getHiddenStateInsets()
);
mAnimator.setDuration(getDurationMs());
mAnimator.setInterpolator(INTERPOLATOR);
mAnimator = ValueAnimator.ofFloat(0f, 1f);
mAnimator.setDuration(mDurationMs);
mAnimator.setInterpolator(new LinearInterpolator());
Insets start = mShow
? controller.getHiddenStateInsets()
: controller.getShownStateInsets();
Insets end = mShow
? controller.getShownStateInsets()
: controller.getHiddenStateInsets();
Interpolator insetsInterpolator = getInterpolator();
Interpolator alphaInterpolator = getAlphaInterpolator();
mAnimator.addUpdateListener(animation -> {
float rawFraction = animation.getAnimatedFraction();
float alphaFraction = mShow
? rawFraction
: 1 - rawFraction;
float insetsFraction = insetsInterpolator.getInterpolation(rawFraction);
controller.setInsetsAndAlpha(
sEvaluator.evaluate(insetsFraction, start, end),
alphaInterpolator.getInterpolation(alphaFraction),
rawFraction);
});
mAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -206,7 +218,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
onAnimationFinish();
}
});
if (mUseSfVsync) {
if (!mHasAnimationCallbacks) {
mAnimator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get());
}
mAnimator.start();
@@ -224,22 +236,57 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
}
protected void onAnimationFinish() {
mController.finish(mShow);
Interpolator getInterpolator() {
if ((mRequestedTypes & ime()) != 0) {
if (mHasAnimationCallbacks) {
return SYNC_IME_INTERPOLATOR;
} else if (mShow) {
return LINEAR_OUT_SLOW_IN_INTERPOLATOR;
} else {
return FAST_OUT_LINEAR_IN_INTERPOLATOR;
}
} else {
return SYSTEM_BARS_INTERPOLATOR;
}
}
protected float getRawFraction() {
return (float) mAnimator.getCurrentPlayTime() / mAnimator.getDuration();
Interpolator getAlphaInterpolator() {
if ((mRequestedTypes & ime()) != 0) {
if (mHasAnimationCallbacks) {
return input -> 1f;
} else if (mShow) {
// Alpha animation takes half the time with linear interpolation;
return input -> Math.min(1f, 2 * input);
} else {
return FAST_OUT_LINEAR_IN_INTERPOLATOR;
}
} else {
return input -> 1f;
}
}
protected void onAnimationFinish() {
mController.finish(mShow);
}
/**
* To get the animation duration in MS.
*/
public long getDurationMs() {
if (mAnimator != null) {
return mAnimator.getDuration();
return mDurationMs;
}
private long calculateDurationMs() {
if ((mRequestedTypes & ime()) != 0) {
if (mHasAnimationCallbacks) {
return ANIMATION_DURATION_SYNC_IME_MS;
} else {
return ANIMATION_DURATION_UNSYNC_IME_MS;
}
} else {
return mShow ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS;
}
return mShow ? ANIMATION_DURATION_SHOW_MS : ANIMATION_DURATION_HIDE_MS;
}
}
@@ -525,7 +572,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
pendingRequest.types, pendingRequest.cancellationSignal,
pendingRequest.listener, mFrame,
true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator,
false /* fade */, pendingRequest.animationType,
pendingRequest.animationType,
pendingRequest.layoutInsetsDuringAnimation,
pendingRequest.useInsetsAnimationThread);
return;
@@ -590,9 +637,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
listener.onCancelled(null);
return;
}
controlAnimationUnchecked(types, cancellationSignal, listener, mFrame, fromIme, durationMs,
interpolator, false /* fade */, animationType,
getLayoutInsetsDuringAnimationMode(types),
interpolator, animationType, getLayoutInsetsDuringAnimationMode(types),
false /* useInsetsAnimationThread */);
}
@@ -606,7 +653,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private void controlAnimationUnchecked(@InsetsType int types,
@Nullable CancellationSignal cancellationSignal,
WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
long durationMs, Interpolator interpolator, boolean fade,
long durationMs, Interpolator interpolator,
@AnimationType int animationType,
@LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
boolean useInsetsAnimationThread) {
@@ -652,10 +699,10 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
final InsetsAnimationControlRunner runner = useInsetsAnimationThread
? new InsetsAnimationThreadControlRunner(controls,
frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
frame, mState, listener, typesReady, this, durationMs, interpolator,
animationType, mViewRoot.mHandler)
: new InsetsAnimationControlImpl(controls,
frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
frame, mState, listener, typesReady, this, durationMs, interpolator,
animationType);
mRunningAnimations.add(new RunningAnimation(runner, animationType));
if (cancellationSignal != null) {
@@ -921,25 +968,26 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
return;
}
boolean useInsetsAnimationThread = canUseInsetsAnimationThread();
boolean hasAnimationCallbacks = hasAnimationCallbacks();
final InternalAnimationControlListener listener =
new InternalAnimationControlListener(show, useInsetsAnimationThread);
new InternalAnimationControlListener(show, hasAnimationCallbacks, types);
// Show/hide animations always need to be relative to the display frame, in order that shown
// and hidden state insets are correct.
controlAnimationUnchecked(
types, null /* cancellationSignal */, listener, mState.getDisplayFrame(), fromIme,
listener.getDurationMs(),
INTERPOLATOR, true /* fade */, show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
: LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
useInsetsAnimationThread);
listener.getDurationMs(), listener.getInterpolator(),
show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
!hasAnimationCallbacks /* useInsetsAnimationThread */);
}
private boolean canUseInsetsAnimationThread() {
private boolean hasAnimationCallbacks() {
if (mViewRoot.mView == null) {
return true;
return false;
}
return !mViewRoot.mView.hasWindowInsetsAnimationCallback();
return mViewRoot.mView.hasWindowInsetsAnimationCallback();
}
private void hideDirectly(
@@ -1118,7 +1166,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
// Make sure a frame gets scheduled.
mViewRoot.mView.invalidate();
} else {
sc.release();
sc.release();
}
}
}

View File

@@ -20,7 +20,6 @@ import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
import static android.view.WindowInsets.Type.systemBars;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -44,8 +43,6 @@ import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.animation.LinearInterpolator;
import android.view.test.InsetsModeSession;
import androidx.test.runner.AndroidJUnit4;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -57,6 +54,8 @@ import org.mockito.MockitoAnnotations;
import java.util.List;
import androidx.test.runner.AndroidJUnit4;
/**
* Tests for {@link InsetsAnimationControlImpl}.
*
@@ -124,7 +123,7 @@ public class InsetsAnimationControlImplTest {
mController = new InsetsAnimationControlImpl(controls,
new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
mMockController, 10 /* durationMs */, new LinearInterpolator(),
false /* fade */, 0 /* animationType */);
0 /* animationType */);
}
@Test

View File

@@ -22,8 +22,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
@@ -299,7 +297,7 @@ class InsetsPolicy {
private void controlAnimationUnchecked(int typesReady,
SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback) {
InsetsPolicyAnimationControlListener listener =
new InsetsPolicyAnimationControlListener(show, callback);
new InsetsPolicyAnimationControlListener(show, callback, typesReady);
listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show);
}
@@ -328,8 +326,8 @@ class InsetsPolicy {
Runnable mFinishCallback;
InsetsPolicyAnimationControlCallbacks mControlCallbacks;
InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback) {
super(show, true /* useSfVsync */);
InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) {
super(show, false /* hasCallbacks */, types);
mFinishCallback = finishCallback;
mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
}
@@ -361,7 +359,7 @@ class InsetsPolicy {
mAnimationControl = new InsetsAnimationControlImpl(controls,
mFocusedWin.getDisplayContent().getBounds(), getState(),
mListener, typesReady, this, mListener.getDurationMs(),
InsetsController.INTERPOLATOR, true,
InsetsController.SYSTEM_BARS_INTERPOLATOR,
show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE);
SurfaceAnimationThread.getHandler().post(
() -> mListener.onReady(mAnimationControl, typesReady));