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

Commit 20209637 authored by Johannes Gallmann's avatar Johannes Gallmann
Browse files

Fix inline reply defocus animation issues

Instead of adding the RemoteInputView to an Overlay, it is kept normally in the view tree and is thus still receiving windowInsetsAnimation callbacks during the animation.

In order to free up the space occupied by the RemoteInputView during the animation, a negative topMargin is set during the animation.

Bug: 281847513
Flag: NOTIFICATION_INLINE_REPLY_ANIMATION
Test: atest RemoteInputViewTest, Manual (i.e. analysing screenrecordings of inline reply defocus animation and verifying that "clear all" button is functioning normally afterwards)
Change-Id: I8a9e1ab227d204ca18554a447f9f2ccc404be73e
parent 3816d9b9
Loading
Loading
Loading
Loading
+23 −21
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_STANDARD;

import android.app.ActivityManager;
import android.app.Notification;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
@@ -47,7 +46,6 @@ import android.view.OnReceiveContentListener;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
import android.view.ViewGroupOverlay;
import android.view.ViewRootImpl;
import android.view.WindowInsets;
import android.view.WindowInsetsAnimation;
@@ -58,6 +56,7 @@ import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -436,25 +435,23 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
            if (animate && parent != null && mIsFocusAnimationFlagActive) {

                ViewGroup grandParent = (ViewGroup) parent.getParent();
                ViewGroupOverlay overlay = parent.getOverlay();
                View actionsContainer = getActionsContainerLayout();
                int actionsContainerHeight =
                        actionsContainer != null ? actionsContainer.getHeight() : 0;

                // After adding this RemoteInputView to the overlay of the parent (and thus removing
                // it from the parent itself), the parent will shrink in height. This causes the
                // overlay to be moved. To correct the position of the overlay we need to offset it.
                int overlayOffsetY = actionsContainerHeight - getHeight();
                overlay.add(this);
                // When defocusing, the notification needs to shrink. Therefore, we need to free
                // up the space that was needed for the RemoteInputView. This is done by setting
                // a negative top margin of the height difference of the RemoteInputView and its
                // sibling (the actions_container_layout containing the Reply button etc.)
                final int heightToShrink = actionsContainerHeight - getHeight();
                setTopMargin(heightToShrink);
                if (grandParent != null) grandParent.setClipChildren(false);

                Animator animator = getDefocusAnimator(actionsContainer, overlayOffsetY);
                View self = this;
                final Animator animator = getDefocusAnimator(actionsContainer);
                animator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        overlay.remove(self);
                        parent.addView(self);
                        setTopMargin(0);
                        if (grandParent != null) grandParent.setClipChildren(true);
                        setVisibility(GONE);
                        if (mWrapper != null) {
@@ -499,6 +496,13 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
        }
    }

    private void setTopMargin(int topMargin) {
        if (!(getLayoutParams() instanceof FrameLayout.LayoutParams)) return;
        final FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) getLayoutParams();
        layoutParams.topMargin = topMargin;
        setLayoutParams(layoutParams);
    }

    @VisibleForTesting
    protected void setViewRootImpl(ViewRootImpl viewRoot) {
        mTestableViewRootImpl = viewRoot;
@@ -674,12 +678,12 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
            mProgressBar.setVisibility(INVISIBLE);
            mResetting = true;
            mSending = false;
            mController.removeSpinning(mEntry.getKey(), mToken);
            onDefocus(true /* animate */, false /* logClose */, () -> {
                mEntry.remoteInputTextWhenReset = SpannedString.valueOf(mEditText.getText());
                mEditText.getText().clear();
                mEditText.setEnabled(isAggregatedVisible());
                mSendButton.setVisibility(VISIBLE);
                mController.removeSpinning(mEntry.getKey(), mToken);
                updateSendButton();
                setAttachment(null);
                mResetting = false;
@@ -874,7 +878,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene

        ValueAnimator scaleAnimator = ValueAnimator.ofFloat(FOCUS_ANIMATION_MIN_SCALE, 1f);
        scaleAnimator.addUpdateListener(valueAnimator -> {
            setFocusAnimationScaleY((float) scaleAnimator.getAnimatedValue(), 0);
            setFocusAnimationScaleY((float) scaleAnimator.getAnimatedValue());
        });
        scaleAnimator.setDuration(FOCUS_ANIMATION_TOTAL_DURATION);
        scaleAnimator.setInterpolator(InterpolatorsAndroidX.FAST_OUT_SLOW_IN);
@@ -901,9 +905,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
     * Creates an animator for the defocus animation.
     *
     * @param fadeInView View that will be faded in during the defocus animation.
     * @param offsetY    The RemoteInputView will be offset by offsetY during the animation
     */
    private Animator getDefocusAnimator(@Nullable View fadeInView, int offsetY) {
    private Animator getDefocusAnimator(@Nullable View fadeInView) {
        final AnimatorSet animatorSet = new AnimatorSet();

        final Animator alphaAnimator = ObjectAnimator.ofFloat(this, View.ALPHA, 1f, 0f);
@@ -913,14 +916,14 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene

        ValueAnimator scaleAnimator = ValueAnimator.ofFloat(1f, FOCUS_ANIMATION_MIN_SCALE);
        scaleAnimator.addUpdateListener(valueAnimator -> {
            setFocusAnimationScaleY((float) scaleAnimator.getAnimatedValue(), offsetY);
            setFocusAnimationScaleY((float) scaleAnimator.getAnimatedValue());
        });
        scaleAnimator.setDuration(FOCUS_ANIMATION_TOTAL_DURATION);
        scaleAnimator.setInterpolator(InterpolatorsAndroidX.FAST_OUT_SLOW_IN);
        scaleAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation, boolean isReverse) {
                setFocusAnimationScaleY(1f /* scaleY */, 0 /* verticalOffset */);
                setFocusAnimationScaleY(1f /* scaleY */);
            }
        });

@@ -942,9 +945,8 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
     * Sets affected view properties for a vertical scale animation
     *
     * @param scaleY         desired vertical view scale
     * @param verticalOffset vertical offset to apply to the RemoteInputView during the animation
     */
    private void setFocusAnimationScaleY(float scaleY, int verticalOffset) {
    private void setFocusAnimationScaleY(float scaleY) {
        int verticalBoundOffset = (int) ((1f - scaleY) * 0.5f * mContentView.getHeight());
        Rect contentBackgroundBounds = new Rect(0, verticalBoundOffset, mContentView.getWidth(),
                mContentView.getHeight() - verticalBoundOffset);
@@ -955,7 +957,7 @@ public class RemoteInputView extends LinearLayout implements View.OnClickListene
        } else {
            mContentBackgroundBounds = contentBackgroundBounds;
        }
        setTranslationY(verticalBoundOffset + verticalOffset);
        setTranslationY(verticalBoundOffset);
    }

    /** Handler for button click on send action in IME. */