Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 42914101 authored by Taran Singh's avatar Taran Singh
Browse files

Animate IME with zero insets

When IME has zero insets, it doesn't map to any side and doesn't have
can't be animated.
IME can have zero insets in following cases:
1. Floating IME
2. Fullscreen IME (in landscape)
3. IME doesn't overlap with IME target window.

In order to animate a type, it must have insets. We can animate IME
from negative insets to zero and vice-versa. This makes zero insets IME a
special case of ISIDE_BOTTOM.
Deprecate SIDE_FLOATING because it shouldn't logically map to a side.

Fix: 153909316
Test: atest WindowInsetsAnimationImeTests#testZeroInsetsImeAnimates
Change-Id: I6d1d3430888db4632cb2f93e9042f692b35ebaeb
parent 3987866c
Loading
Loading
Loading
Loading
+25 −8
Original line number Diff line number Diff line
@@ -16,13 +16,14 @@

package android.view;

import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
import static android.view.InsetsController.AnimationType;
import static android.view.InsetsController.DEBUG;
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_RIGHT;
import static android.view.InsetsState.ISIDE_TOP;
import static android.view.InsetsState.ITYPE_IME;

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 InsetsAnimationControlCallbacks mController;
    private final WindowInsetsAnimation mAnimation;
    /** @see WindowInsetsAnimationController#hasZeroInsetsIme */
    private final boolean mHasZeroInsetsIme;
    private Insets mCurrentInsets;
    private Insets mPendingInsets;
    private float mPendingFraction;
@@ -102,6 +105,12 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
                null /* typeSideMap */);
        mShownInsets = calculateInsets(mInitialInsetsState, frame, controls, true /* shown */,
                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);

        mAnimation = new WindowInsetsAnimation(mTypes, interpolator,
@@ -112,6 +121,11 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
                new Bounds(mHiddenInsets, mShownInsets));
    }

    @Override
    public boolean hasZeroInsetsIme() {
        return mHasZeroInsetsIme;
    }

    @Override
    public Insets getHiddenStateInsets() {
        return mHiddenInsets;
@@ -182,8 +196,6 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
                params, state, mPendingAlpha);
        updateLeashesForSide(ISIDE_BOTTOM, offset.bottom, mShownInsets.bottom,
                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()]));
        mCurrentInsets = mPendingInsets;
@@ -290,6 +302,9 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
        if (insets == null) {
            insets = getCurrentInsets();
        }
        if (hasZeroInsetsIme()) {
            return insets;
        }
        return Insets.max(Insets.min(insets, mShownInsets), mHiddenInsets);
    }

@@ -313,17 +328,19 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll
            mTmpFrame.set(source.getFrame());
            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);

            // If the system is controlling the insets source, the leash can be null.
            if (leash != null) {
                SurfaceParams params = new SurfaceParams.Builder(leash)
                        .withAlpha(side == ISIDE_FLOATING ? 1 : alpha)
                        .withAlpha(alpha)
                        .withMatrix(mTmpMatrix)
                        .withVisibility(side == ISIDE_FLOATING
                                ? mShownOnFinish
                                : inset != 0 /* visible */)
                        .withVisibility(visible)
                        .build();
                surfaceParams.add(params);
            }
+20 −4
Original line number Diff line number Diff line
@@ -162,6 +162,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
         */
        @Nullable
        String getRootViewTitle();

        /** @see ViewRootImpl#dipToPx */
        int dipToPx(int dips);
    }

    private static final String TAG = "InsetsController";
@@ -254,6 +257,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
    public static class InternalAnimationControlListener
            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 ValueAnimator mAnimator;
        private final boolean mShow;
@@ -261,6 +267,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        private final @InsetsType int mRequestedTypes;
        private final long mDurationMs;
        private final boolean mDisable;
        private final int mFloatingImeBottomInset;

        private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
                new ThreadLocal<AnimationHandler>() {
@@ -273,12 +280,13 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        };

        public InternalAnimationControlListener(boolean show, boolean hasAnimationCallbacks,
                int requestedTypes, boolean disable) {
                int requestedTypes, boolean disable, int floatingImeBottomInset) {
            mShow = show;
            mHasAnimationCallbacks = hasAnimationCallbacks;
            mRequestedTypes = requestedTypes;
            mDurationMs = calculateDurationMs();
            mDisable = disable;
            mFloatingImeBottomInset = floatingImeBottomInset;
        }

        @Override
@@ -293,12 +301,19 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
            mAnimator = ValueAnimator.ofFloat(0f, 1f);
            mAnimator.setDuration(mDurationMs);
            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
                    ? controller.getHiddenStateInsets()
                    ? hiddenInsets
                    : controller.getShownStateInsets();
            Insets end = mShow
                    ? controller.getShownStateInsets()
                    : controller.getHiddenStateInsets();
                    : hiddenInsets;
            Interpolator insetsInterpolator = getInterpolator();
            Interpolator alphaInterpolator = getAlphaInterpolator();
            mAnimator.addUpdateListener(animation -> {
@@ -1173,7 +1188,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

        boolean hasAnimationCallbacks = mHost.hasAnimationCallbacks();
        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
        // and hidden state insets are correct.
+1 −1
Original line number Diff line number Diff line
@@ -2315,7 +2315,7 @@ public final class ViewRootImpl implements ViewParent,
                || lp.type == TYPE_VOLUME_OVERLAY;
    }

    private int dipToPx(int dip) {
    int dipToPx(int dip) {
        final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
        return (int) (displayMetrics.density * dip + 0.5f);
    }
+8 −0
Original line number Diff line number Diff line
@@ -228,4 +228,12 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host {
        }
        return mViewRoot.getTitle().toString();
    }

    @Override
    public int dipToPx(int dips) {
        if (mViewRoot != null) {
            return mViewRoot.dipToPx(dips);
        }
        return 0;
    }
}
+7 −0
Original line number Diff line number Diff line
@@ -181,4 +181,11 @@ public interface WindowInsetsAnimationController {
     * @return {@code true} if the instance is cancelled, {@code false} otherwise.
     */
    boolean isCancelled();

    /**
     * @hide
     * @return {@code true} when controller controls IME and IME has no insets (floating,
     *  fullscreen or non-overlapping).
     */
    boolean hasZeroInsetsIme();
}
Loading