Merge "Animate IME with zero insets" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
cc498f3e69
@@ -16,13 +16,14 @@
|
|||||||
|
|
||||||
package android.view;
|
package android.view;
|
||||||
|
|
||||||
|
import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
|
||||||
import static android.view.InsetsController.AnimationType;
|
import static android.view.InsetsController.AnimationType;
|
||||||
import static android.view.InsetsController.DEBUG;
|
import static android.view.InsetsController.DEBUG;
|
||||||
import static android.view.InsetsState.ISIDE_BOTTOM;
|
import static android.view.InsetsState.ISIDE_BOTTOM;
|
||||||
import static android.view.InsetsState.ISIDE_FLOATING;
|
|
||||||
import static android.view.InsetsState.ISIDE_LEFT;
|
import static android.view.InsetsState.ISIDE_LEFT;
|
||||||
import static android.view.InsetsState.ISIDE_RIGHT;
|
import static android.view.InsetsState.ISIDE_RIGHT;
|
||||||
import static android.view.InsetsState.ISIDE_TOP;
|
import static android.view.InsetsState.ISIDE_TOP;
|
||||||
|
import static android.view.InsetsState.ITYPE_IME;
|
||||||
|
|
||||||
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
|
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
|
||||||
|
|
||||||
@@ -74,6 +75,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
|||||||
private final @InsetsType int mTypes;
|
private final @InsetsType int mTypes;
|
||||||
private final InsetsAnimationControlCallbacks mController;
|
private final InsetsAnimationControlCallbacks mController;
|
||||||
private final WindowInsetsAnimation mAnimation;
|
private final WindowInsetsAnimation mAnimation;
|
||||||
|
/** @see WindowInsetsAnimationController#hasZeroInsetsIme */
|
||||||
|
private final boolean mHasZeroInsetsIme;
|
||||||
private Insets mCurrentInsets;
|
private Insets mCurrentInsets;
|
||||||
private Insets mPendingInsets;
|
private Insets mPendingInsets;
|
||||||
private float mPendingFraction;
|
private float mPendingFraction;
|
||||||
@@ -102,6 +105,12 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
|||||||
null /* typeSideMap */);
|
null /* typeSideMap */);
|
||||||
mShownInsets = calculateInsets(mInitialInsetsState, frame, controls, true /* shown */,
|
mShownInsets = calculateInsets(mInitialInsetsState, frame, controls, true /* shown */,
|
||||||
mTypeSideMap);
|
mTypeSideMap);
|
||||||
|
mHasZeroInsetsIme = mShownInsets.bottom == 0 && controlsInternalType(ITYPE_IME);
|
||||||
|
if (mHasZeroInsetsIme) {
|
||||||
|
// IME has shownInsets of ZERO, and can't map to a side by default.
|
||||||
|
// Map zero insets IME to bottom, making it a special case of bottom insets.
|
||||||
|
mTypeSideMap.put(ITYPE_IME, ISIDE_BOTTOM);
|
||||||
|
}
|
||||||
buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mControls);
|
buildTypeSourcesMap(mTypeSideMap, mSideSourceMap, mControls);
|
||||||
|
|
||||||
mAnimation = new WindowInsetsAnimation(mTypes, interpolator,
|
mAnimation = new WindowInsetsAnimation(mTypes, interpolator,
|
||||||
@@ -112,6 +121,11 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
|||||||
new Bounds(mHiddenInsets, mShownInsets));
|
new Bounds(mHiddenInsets, mShownInsets));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasZeroInsetsIme() {
|
||||||
|
return mHasZeroInsetsIme;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Insets getHiddenStateInsets() {
|
public Insets getHiddenStateInsets() {
|
||||||
return mHiddenInsets;
|
return mHiddenInsets;
|
||||||
@@ -182,8 +196,6 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
|||||||
params, state, mPendingAlpha);
|
params, state, mPendingAlpha);
|
||||||
updateLeashesForSide(ISIDE_BOTTOM, offset.bottom, mShownInsets.bottom,
|
updateLeashesForSide(ISIDE_BOTTOM, offset.bottom, mShownInsets.bottom,
|
||||||
mPendingInsets.bottom, params, state, mPendingAlpha);
|
mPendingInsets.bottom, params, state, mPendingAlpha);
|
||||||
updateLeashesForSide(ISIDE_FLOATING, 0 /* offset */, 0 /* inset */, 0 /* maxInset */,
|
|
||||||
params, state, mPendingAlpha);
|
|
||||||
|
|
||||||
mController.applySurfaceParams(params.toArray(new SurfaceParams[params.size()]));
|
mController.applySurfaceParams(params.toArray(new SurfaceParams[params.size()]));
|
||||||
mCurrentInsets = mPendingInsets;
|
mCurrentInsets = mPendingInsets;
|
||||||
@@ -290,6 +302,9 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
|||||||
if (insets == null) {
|
if (insets == null) {
|
||||||
insets = getCurrentInsets();
|
insets = getCurrentInsets();
|
||||||
}
|
}
|
||||||
|
if (hasZeroInsetsIme()) {
|
||||||
|
return insets;
|
||||||
|
}
|
||||||
return Insets.max(Insets.min(insets, mShownInsets), mHiddenInsets);
|
return Insets.max(Insets.min(insets, mShownInsets), mHiddenInsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,17 +328,19 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
|
|||||||
mTmpFrame.set(source.getFrame());
|
mTmpFrame.set(source.getFrame());
|
||||||
addTranslationToMatrix(side, offset, mTmpMatrix, mTmpFrame);
|
addTranslationToMatrix(side, offset, mTmpMatrix, mTmpFrame);
|
||||||
|
|
||||||
state.getSource(source.getType()).setVisible(side == ISIDE_FLOATING || inset != 0);
|
final boolean visible = mHasZeroInsetsIme && side == ISIDE_BOTTOM
|
||||||
|
? (mAnimationType == ANIMATION_TYPE_SHOW ? true : !mFinished)
|
||||||
|
: inset != 0;
|
||||||
|
|
||||||
|
state.getSource(source.getType()).setVisible(visible);
|
||||||
state.getSource(source.getType()).setFrame(mTmpFrame);
|
state.getSource(source.getType()).setFrame(mTmpFrame);
|
||||||
|
|
||||||
// If the system is controlling the insets source, the leash can be null.
|
// If the system is controlling the insets source, the leash can be null.
|
||||||
if (leash != null) {
|
if (leash != null) {
|
||||||
SurfaceParams params = new SurfaceParams.Builder(leash)
|
SurfaceParams params = new SurfaceParams.Builder(leash)
|
||||||
.withAlpha(side == ISIDE_FLOATING ? 1 : alpha)
|
.withAlpha(alpha)
|
||||||
.withMatrix(mTmpMatrix)
|
.withMatrix(mTmpMatrix)
|
||||||
.withVisibility(side == ISIDE_FLOATING
|
.withVisibility(visible)
|
||||||
? mShownOnFinish
|
|
||||||
: inset != 0 /* visible */)
|
|
||||||
.build();
|
.build();
|
||||||
surfaceParams.add(params);
|
surfaceParams.add(params);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -162,6 +162,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
String getRootViewTitle();
|
String getRootViewTitle();
|
||||||
|
|
||||||
|
/** @see ViewRootImpl#dipToPx */
|
||||||
|
int dipToPx(int dips);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String TAG = "InsetsController";
|
private static final String TAG = "InsetsController";
|
||||||
@@ -254,6 +257,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
public static class InternalAnimationControlListener
|
public static class InternalAnimationControlListener
|
||||||
implements WindowInsetsAnimationControlListener {
|
implements WindowInsetsAnimationControlListener {
|
||||||
|
|
||||||
|
/** The amount IME will move up/down when animating in floating mode. */
|
||||||
|
protected static final int FLOATING_IME_BOTTOM_INSET = -80;
|
||||||
|
|
||||||
private WindowInsetsAnimationController mController;
|
private WindowInsetsAnimationController mController;
|
||||||
private ValueAnimator mAnimator;
|
private ValueAnimator mAnimator;
|
||||||
private final boolean mShow;
|
private final boolean mShow;
|
||||||
@@ -261,6 +267,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
private final @InsetsType int mRequestedTypes;
|
private final @InsetsType int mRequestedTypes;
|
||||||
private final long mDurationMs;
|
private final long mDurationMs;
|
||||||
private final boolean mDisable;
|
private final boolean mDisable;
|
||||||
|
private final int mFloatingImeBottomInset;
|
||||||
|
|
||||||
private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
|
private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
|
||||||
new ThreadLocal<AnimationHandler>() {
|
new ThreadLocal<AnimationHandler>() {
|
||||||
@@ -273,12 +280,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
};
|
};
|
||||||
|
|
||||||
public InternalAnimationControlListener(boolean show, boolean hasAnimationCallbacks,
|
public InternalAnimationControlListener(boolean show, boolean hasAnimationCallbacks,
|
||||||
int requestedTypes, boolean disable) {
|
int requestedTypes, boolean disable, int floatingImeBottomInset) {
|
||||||
mShow = show;
|
mShow = show;
|
||||||
mHasAnimationCallbacks = hasAnimationCallbacks;
|
mHasAnimationCallbacks = hasAnimationCallbacks;
|
||||||
mRequestedTypes = requestedTypes;
|
mRequestedTypes = requestedTypes;
|
||||||
mDurationMs = calculateDurationMs();
|
mDurationMs = calculateDurationMs();
|
||||||
mDisable = disable;
|
mDisable = disable;
|
||||||
|
mFloatingImeBottomInset = floatingImeBottomInset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -293,12 +301,19 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
mAnimator = ValueAnimator.ofFloat(0f, 1f);
|
mAnimator = ValueAnimator.ofFloat(0f, 1f);
|
||||||
mAnimator.setDuration(mDurationMs);
|
mAnimator.setDuration(mDurationMs);
|
||||||
mAnimator.setInterpolator(new LinearInterpolator());
|
mAnimator.setInterpolator(new LinearInterpolator());
|
||||||
|
Insets hiddenInsets = controller.getHiddenStateInsets();
|
||||||
|
// IME with zero insets is a special case: it will animate-in from offscreen and end
|
||||||
|
// with final insets of zero and vice-versa.
|
||||||
|
hiddenInsets = controller.hasZeroInsetsIme()
|
||||||
|
? Insets.of(hiddenInsets.left, hiddenInsets.top, hiddenInsets.right,
|
||||||
|
mFloatingImeBottomInset)
|
||||||
|
: hiddenInsets;
|
||||||
Insets start = mShow
|
Insets start = mShow
|
||||||
? controller.getHiddenStateInsets()
|
? hiddenInsets
|
||||||
: controller.getShownStateInsets();
|
: controller.getShownStateInsets();
|
||||||
Insets end = mShow
|
Insets end = mShow
|
||||||
? controller.getShownStateInsets()
|
? controller.getShownStateInsets()
|
||||||
: controller.getHiddenStateInsets();
|
: hiddenInsets;
|
||||||
Interpolator insetsInterpolator = getInterpolator();
|
Interpolator insetsInterpolator = getInterpolator();
|
||||||
Interpolator alphaInterpolator = getAlphaInterpolator();
|
Interpolator alphaInterpolator = getAlphaInterpolator();
|
||||||
mAnimator.addUpdateListener(animation -> {
|
mAnimator.addUpdateListener(animation -> {
|
||||||
@@ -1173,7 +1188,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
|
|||||||
|
|
||||||
boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks();
|
boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks();
|
||||||
final InternalAnimationControlListener listener = new InternalAnimationControlListener(
|
final InternalAnimationControlListener listener = new InternalAnimationControlListener(
|
||||||
show, hasAnimationCallbacks, types, mAnimationsDisabled);
|
show, hasAnimationCallbacks, types, mAnimationsDisabled,
|
||||||
|
mHost.dipToPx(InternalAnimationControlListener.FLOATING_IME_BOTTOM_INSET));
|
||||||
|
|
||||||
// Show/hide animations always need to be relative to the display frame, in order that shown
|
// Show/hide animations always need to be relative to the display frame, in order that shown
|
||||||
// and hidden state insets are correct.
|
// and hidden state insets are correct.
|
||||||
|
|||||||
@@ -2315,7 +2315,7 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
|| lp.type == TYPE_VOLUME_OVERLAY;
|
|| lp.type == TYPE_VOLUME_OVERLAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int dipToPx(int dip) {
|
int dipToPx(int dip) {
|
||||||
final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
|
final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
|
||||||
return (int) (displayMetrics.density * dip + 0.5f);
|
return (int) (displayMetrics.density * dip + 0.5f);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,4 +228,12 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host {
|
|||||||
}
|
}
|
||||||
return mViewRoot.getTitle().toString();
|
return mViewRoot.getTitle().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int dipToPx(int dips) {
|
||||||
|
if (mViewRoot != null) {
|
||||||
|
return mViewRoot.dipToPx(dips);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,4 +181,11 @@ public interface WindowInsetsAnimationController {
|
|||||||
* @return {@code true} if the instance is cancelled, {@code false} otherwise.
|
* @return {@code true} if the instance is cancelled, {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
boolean isCancelled();
|
boolean isCancelled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
* @return {@code true} when controller controls IME and IME has no insets (floating,
|
||||||
|
* fullscreen or non-overlapping).
|
||||||
|
*/
|
||||||
|
boolean hasZeroInsetsIme();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -387,7 +387,10 @@ class InsetsPolicy {
|
|||||||
InsetsPolicyAnimationControlCallbacks mControlCallbacks;
|
InsetsPolicyAnimationControlCallbacks mControlCallbacks;
|
||||||
|
|
||||||
InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) {
|
InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) {
|
||||||
super(show, false /* hasCallbacks */, types, false /* disable */);
|
|
||||||
|
super(show, false /* hasCallbacks */, types, false /* disable */,
|
||||||
|
(int) (mDisplayContent.getDisplayMetrics().density * FLOATING_IME_BOTTOM_INSET
|
||||||
|
+ 0.5f));
|
||||||
mFinishCallback = finishCallback;
|
mFinishCallback = finishCallback;
|
||||||
mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
|
mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user