| Index: components/autofill/android/java/src/org/chromium/components/autofill/AutofillKeyboardAccessory.java
|
| diff --git a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillKeyboardAccessory.java b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillKeyboardAccessory.java
|
| index b36b9f5b698fc6175a25ac93502e82980b4e591a..ab59f5646216e9f25972ba5da5c912021f03b3c8 100644
|
| --- a/components/autofill/android/java/src/org/chromium/components/autofill/AutofillKeyboardAccessory.java
|
| +++ b/components/autofill/android/java/src/org/chromium/components/autofill/AutofillKeyboardAccessory.java
|
| @@ -6,6 +6,7 @@ package org.chromium.components.autofill;
|
|
|
| import android.animation.Animator;
|
| import android.animation.AnimatorListenerAdapter;
|
| +import android.animation.AnimatorSet;
|
| import android.animation.ObjectAnimator;
|
| import android.annotation.SuppressLint;
|
| import android.graphics.PorterDuff;
|
| @@ -27,6 +28,8 @@ import org.chromium.base.ApiCompatibilityUtils;
|
| import org.chromium.ui.UiUtils;
|
| import org.chromium.ui.base.WindowAndroid;
|
|
|
| +import java.util.ArrayList;
|
| +
|
| /**
|
| * The Autofill suggestion view that lists relevant suggestions. It sits above the keyboard and
|
| * below the content area.
|
| @@ -36,6 +39,8 @@ public class AutofillKeyboardAccessory extends LinearLayout
|
| View.OnLongClickListener {
|
| // Time to pause before reversing animation when the first suggestion is a hint.
|
| private static final long PAUSE_ANIMATION_BEFORE_REVERSE_MILLIS = 1000;
|
| + // Time to fade in views that we temporarily hide when we change container layout.
|
| + private static final long ALPHA_ANIMATION_DURATION_MILLIS = 250;
|
|
|
| private final WindowAndroid mWindowAndroid;
|
| private final AutofillDelegate mAutofillDelegate;
|
| @@ -47,7 +52,8 @@ public class AutofillKeyboardAccessory extends LinearLayout
|
| // We start animating by scrolling the suggestions from beyond the viewport.
|
| private final int mStartAnimationTranslationPx;
|
|
|
| - private ObjectAnimator mAnimator;
|
| + private int mSeparatorPosition;
|
| + private Animator mAnimator;
|
| private Runnable mReverseAnimationRunnable;
|
|
|
| /**
|
| @@ -97,7 +103,7 @@ public class AutofillKeyboardAccessory extends LinearLayout
|
| }
|
|
|
| removeAllViews();
|
| - int separatorPosition = -1;
|
| + mSeparatorPosition = -1;
|
| for (int i = 0; i < suggestions.length; i++) {
|
| AutofillSuggestion suggestion = suggestions[i];
|
| boolean isKeyboardAccessoryHint = i == 0 && isFirstSuggestionAHint;
|
| @@ -110,7 +116,7 @@ public class AutofillKeyboardAccessory extends LinearLayout
|
| touchTarget = LayoutInflater.from(getContext()).inflate(
|
| R.layout.autofill_keyboard_accessory_icon, this, false);
|
|
|
| - if (separatorPosition == -1 && !isKeyboardAccessoryHint) separatorPosition = i;
|
| + if (mSeparatorPosition == -1 && !isKeyboardAccessoryHint) mSeparatorPosition = i;
|
|
|
| ImageView icon = (ImageView) touchTarget;
|
| Drawable drawable =
|
| @@ -166,8 +172,8 @@ public class AutofillKeyboardAccessory extends LinearLayout
|
| addView(touchTarget);
|
| }
|
|
|
| - if (separatorPosition != -1) {
|
| - addView(createSeparatorView(), separatorPosition);
|
| + if (mSeparatorPosition != -1) {
|
| + addView(createSeparatorView(), mSeparatorPosition);
|
| }
|
|
|
| // TODO(crbug/722897): Following does not reverse layout order for RTL.
|
| @@ -194,6 +200,15 @@ public class AutofillKeyboardAccessory extends LinearLayout
|
| mAnimator.addListener(new AnimatorListenerAdapter() {
|
| @Override
|
| public void onAnimationStart(Animator animator) {
|
| + if (isFirstSuggestionAHint) {
|
| + // We will make suggestions beyond the separator visible after we have
|
| + // finished the reverse animation and removed the first suggestion. This
|
| + // prevents a sudden movement of these suggestions when the container view
|
| + // is redrawn. See |scheduleReverseAnimation|.
|
| + for (int i = mSeparatorPosition + 1; i < getChildCount(); ++i) {
|
| + getChildAt(i).setAlpha(0);
|
| + }
|
| + }
|
| container.setVisibility(View.VISIBLE);
|
| }
|
| @Override
|
| @@ -277,20 +292,47 @@ public class AutofillKeyboardAccessory extends LinearLayout
|
| return;
|
| }
|
|
|
| - int hintWidth = firstSuggestion.getWidth() - firstSuggestion.getPaddingRight();
|
| - mAnimator = ObjectAnimator.ofFloat(this, View.TRANSLATION_X, 0, -hintWidth);
|
| - mAnimator.setDuration(mAnimationDurationMillis);
|
| - mAnimator.addListener(new AnimatorListenerAdapter() {
|
| + // Play 2 animations sequentially.
|
| + // 1. Move the icon hint out of the viewport by reversing the forward animation.
|
| + // At the end of this animation, we remove the icon hint, mark views beyond
|
| + // |mSeparatorPosition| as |View.VISIBLE| but 100% transparent.
|
| + // 2. Fade-in the views beyond |mSeparatorPosition|.
|
| + // We use 2 animations to smoothen the relayout of the |HorizonatlScrollView| when we
|
| + // remove the icon hint.
|
| + assert getChildAt(0) instanceof ImageView;
|
| + for (int i = mSeparatorPosition + 1; i < getChildCount(); ++i) {
|
| + assert getChildAt(i) instanceof ImageView;
|
| + }
|
| +
|
| + // |reverseAnimator| moves icon hint out of viewport, removes the icon hint and hides views
|
| + // beyond |mSeparatorPosition|.
|
| + int hintWidth = firstSuggestion.getWidth();
|
| + final ObjectAnimator reverseAnimator =
|
| + ObjectAnimator.ofFloat(this, View.TRANSLATION_X, -hintWidth);
|
| + reverseAnimator.setDuration(mAnimationDurationMillis);
|
| + reverseAnimator.addListener(new AnimatorListenerAdapter() {
|
| @Override
|
| public void onAnimationEnd(Animator animator) {
|
| - mAnimator.removeListener(this);
|
| - if (view.getVisibility() == View.VISIBLE) {
|
| - // Remove the keyboard accessory hint, reset 'X' and redraw the layout.
|
| - removeView(firstSuggestion);
|
| - setTranslationX(0);
|
| - }
|
| + reverseAnimator.removeListener(this);
|
| + if (view.getVisibility() != View.VISIBLE) return;
|
| + removeView(firstSuggestion);
|
| + mSeparatorPosition--;
|
| + // Reset 'X' and redraw the layout.
|
| + setTranslationX(0);
|
| }
|
| });
|
| +
|
| + // |alphaAnimation| fades in views beyond |mSeparatorPosition|.
|
| + final AnimatorSet alphaAnimation = new AnimatorSet();
|
| + ArrayList<Animator> alphaAnimators = new ArrayList<Animator>();
|
| + for (int i = mSeparatorPosition + 1; i < getChildCount(); ++i) {
|
| + alphaAnimators.add(ObjectAnimator.ofFloat(getChildAt(i), View.ALPHA, 1f));
|
| + }
|
| + alphaAnimation.setDuration(ALPHA_ANIMATION_DURATION_MILLIS);
|
| + alphaAnimation.playTogether(alphaAnimators);
|
| +
|
| + mAnimator = new AnimatorSet();
|
| + ((AnimatorSet) mAnimator).playSequentially(reverseAnimator, alphaAnimation);
|
| mReverseAnimationRunnable = new Runnable() {
|
| @Override
|
| public void run() {
|
|
|