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

Commit 7c5b0fc9 authored by Aaron Liu's avatar Aaron Liu
Browse files

Fix view jumping up in the password disappear...

animation. The problem is that the edittext is not statically anchored
to the bottom, so when we start the disappear animation, the height of
the view increases to basically the full vertical size of the screen,
causing the jump.

The solution here is to prevent the bottom padding to be set in
onApplyWindowInsets. This means the viewfliper view will remain the same
size for the duration of the disapper animation and we use a y
translation animation and apply it to the security container for a
smooth transition.

Fixes: 268221346
Test: start disappear animation in password. Switch security method to
see that those work as well.
Test: Test animation with bouncer user switcher as well.

Change-Id: Id036bb10df79e4d357c00265507b43632d763a6b
parent 43e1ee6b
Loading
Loading
Loading
Loading
+24 −3
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {

    private Interpolator mLinearOutSlowInInterpolator;
    private Interpolator mFastOutLinearInInterpolator;
    private DisappearAnimationListener mDisappearAnimationListener;

    public KeyguardPasswordView(Context context) {
        this(context, null);
@@ -186,9 +187,13 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
                                return;
                            }
                            Insets shownInsets = controller.getShownStateInsets();
                            Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0,
                                    (int) (-shownInsets.bottom / 4
                                            * anim.getAnimatedFraction())));
                            int dist = (int) (-shownInsets.bottom / 4
                                    * anim.getAnimatedFraction());
                            Insets insets = Insets.add(shownInsets, Insets.of(0, 0, 0, dist));
                            if (mDisappearAnimationListener != null) {
                                mDisappearAnimationListener.setTranslationY(-dist);
                            }

                            controller.setInsetsAndAlpha(insets,
                                    (float) animation.getAnimatedValue(),
                                    anim.getAnimatedFraction());
@@ -209,6 +214,7 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
                                    controller.finish(false);
                                    runOnFinishImeAnimationRunnable();
                                    finishRunnable.run();
                                    mDisappearAnimationListener = null;
                                    Trace.endSection();
                                });
                            }
@@ -286,4 +292,19 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView {
            }
        });
    }

    /**
     * Listens to the progress of the disappear animation and handles it.
     */
    interface DisappearAnimationListener {
        void setTranslationY(int transY);
    }

    /**
     * Set an instance of the disappear animation listener to this class. This will be
     * removed when the animation completes.
     */
    public void setDisappearAnimationListener(DisappearAnimationListener listener) {
        mDisappearAnimationListener = listener;
    }
}
+27 −3
Original line number Diff line number Diff line
@@ -173,6 +173,17 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
    private @Mode int mCurrentMode = MODE_UNINITIALIZED;
    private int mWidth = -1;

    /**
     * This callback is used to animate KeyguardSecurityContainer and its child views based on
     * the interaction with the ime. After
     * {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)},
     * {@link #onApplyWindowInsets} is called where we
     * set the bottom padding to be the height of the keyboard. We use this padding to determine
     * the delta of vertical distance for y-translation animations.
     * Note that bottom padding is not set when the disappear animation is started because
     * we are deferring the y translation logic to the animator in
     * {@link KeyguardPasswordView#startDisappearAnimation(Runnable)}
     */
    private final WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback =
            new WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {

@@ -213,7 +224,6 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
                            continue;
                        }
                        interpolatedFraction = animation.getInterpolatedFraction();

                        final int paddingBottom = (int) MathUtils.lerp(
                                start, end,
                                interpolatedFraction);
@@ -568,13 +578,21 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
     */
    public void startDisappearAnimation(SecurityMode securitySelection) {
        mDisappearAnimRunning = true;
        if (securitySelection == SecurityMode.Password
                && mSecurityViewFlipper.getSecurityView() instanceof KeyguardPasswordView) {
            ((KeyguardPasswordView) mSecurityViewFlipper.getSecurityView())
                    .setDisappearAnimationListener(this::setTranslationY);
        } else {
            mViewMode.startDisappearAnimation(securitySelection);
        }
    }

    /**
     * This will run when the bouncer shows in all cases except when the user drags the bouncer up.
     */
    public void startAppearAnimation(SecurityMode securityMode) {
        setTranslationY(0f);
        setAlpha(1f);
        updateChildren(0 /* translationY */, 1f /* alpha */);
        mViewMode.startAppearAnimation(securityMode);
    }
@@ -623,7 +641,13 @@ public class KeyguardSecurityContainer extends ConstraintLayout {
        int inset = max(bottomInset, imeInset);
        int paddingBottom = max(inset, getContext().getResources()
                .getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin));
        // If security mode is password, we rely on the animation value of defined in
        // KeyguardPasswordView to determine the y translation animation.
        // This means that we will prevent the WindowInsetsAnimationCallback from setting any y
        // translation values by preventing the setting of the padding here.
        if (!mDisappearAnimRunning) {
            setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
        }
        return insets.inset(0, 0, 0, inset);
    }

+43 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@@ -159,6 +160,29 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
        assertThat(mKeyguardSecurityContainer.getPaddingBottom()).isEqualTo(systemBarInsetAmount);
    }

    @Test
    public void testOnApplyWindowInsets_disappearAnimation_paddingNotSet() {
        int paddingBottom = getContext().getResources()
                .getDimensionPixelSize(R.dimen.keyguard_security_view_bottom_margin);
        int imeInsetAmount = paddingBottom + 1;
        int systemBarInsetAmount = 0;
        initMode(MODE_DEFAULT);

        Insets imeInset = Insets.of(0, 0, 0, imeInsetAmount);
        Insets systemBarInset = Insets.of(0, 0, 0, systemBarInsetAmount);

        WindowInsets insets = new WindowInsets.Builder()
                .setInsets(ime(), imeInset)
                .setInsetsIgnoringVisibility(systemBars(), systemBarInset)
                .build();

        ensureViewFlipperIsMocked();
        mKeyguardSecurityContainer.startDisappearAnimation(
                KeyguardSecurityModel.SecurityMode.Password);
        mKeyguardSecurityContainer.onApplyWindowInsets(insets);
        assertThat(mKeyguardSecurityContainer.getPaddingBottom()).isNotEqualTo(imeInsetAmount);
    }

    @Test
    public void testDefaultViewMode() {
        initMode(MODE_ONE_HANDED);
@@ -376,6 +400,17 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
        assertThat(mKeyguardSecurityContainer.getScaleY()).isEqualTo(1);
    }

    @Test
    public void testDisappearAnimationPassword() {
        ensureViewFlipperIsMocked();
        KeyguardPasswordView keyguardPasswordView = mock(KeyguardPasswordView.class);
        when(mSecurityViewFlipper.getSecurityView()).thenReturn(keyguardPasswordView);

        mKeyguardSecurityContainer
                .startDisappearAnimation(KeyguardSecurityModel.SecurityMode.Password);
        verify(keyguardPasswordView).setDisappearAnimationListener(any());
    }

    private BackEvent createBackEvent(float touchX, float progress) {
        return new BackEvent(0, 0, progress, BackEvent.EDGE_LEFT);
    }
@@ -446,4 +481,12 @@ public class KeyguardSecurityContainerTest extends SysuiTestCase {
                mUserSwitcherController, () -> {
                }, mFalsingA11yDelegate);
    }

    private void ensureViewFlipperIsMocked() {
        mSecurityViewFlipper = mock(KeyguardSecurityViewFlipper.class);
        KeyguardPasswordView keyguardPasswordView = mock(KeyguardPasswordView.class);
        when(mSecurityViewFlipper.getSecurityView()).thenReturn(keyguardPasswordView);
        mKeyguardSecurityContainer.mSecurityViewFlipper = mSecurityViewFlipper;
    }

}