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

Commit b30ccb3d authored by Silin Huang's avatar Silin Huang
Browse files

Wallet view UI tweaks.

1. Increase the card view bottom margin to avoid weird card shadow.
before: https://hsv.googleplex.com/6352365370212352
after: https://hsv.googleplex.com/5745851513176064
2. Center the card image in card view.
3. Add fade-in animation for the card carousel UI elements when card
carousel is shown; clean up the unnecessary animation for empty state
view -> non-empty state view.
see demo video:
https://drive.google.com/file/d/1Eih4p1uzw_To_SUQsWGYpkd4M85WX2C9/view?usp=sharing&resourcekey=0-oD7hpOg7uKW6xeCmVNvS0Q

Test: manual
Fix: 184905963
Change-Id: Ied2fffef1f2d9bd6bfcfed0985d39cbed3f52cb0
parent 208f294d
Loading
Loading
Loading
Loading
+2 −9
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginHorizontal="@dimen/card_margin"
        android:layout_marginBottom="@dimen/card_margin"
        android:foreground="?android:attr/selectableItemBackground"
        app:cardBackgroundColor="@android:color/transparent"
        app:cardElevation="12dp">
@@ -32,16 +33,8 @@
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:adjustViewBounds="true"
            android:contentDescription="@null"
            android:scaleType="fitXY"/>
        <ImageView
            android:id="@+id/add_card_logo"
            android:layout_width="28dp"
            android:layout_height="28dp"
            android:layout_gravity="center"
            android:drawable="@drawable/ic_qs_plus"
            android:contentDescription="@null"
            android:scaleType="fitCenter"
            android:visibility="gone"/>
            android:scaleType="fitXY"/>
    </com.android.systemui.wallet.ui.WalletCardView>
</FrameLayout>
+27 −35
Original line number Diff line number Diff line
@@ -61,7 +61,7 @@ public class WalletCardCarousel extends RecyclerView {
    static final int CARD_ANIM_ALPHA_DELAY = 50;

    private final Rect mSystemGestureExclusionZone = new Rect();
    private WalletCardCarouselAdapter mWalletCardCarouselAdapter;
    private final WalletCardCarouselAdapter mWalletCardCarouselAdapter;
    private int mExpectedViewWidth;
    private int mCardMarginPx;
    private int mCardWidthPx;
@@ -79,12 +79,6 @@ public class WalletCardCarousel extends RecyclerView {
    // also be used in DotIndicatorDecoration.
    float mEdgeToCenterDistance = Float.MAX_VALUE;
    private float mCardCenterToScreenCenterDistancePx = Float.MAX_VALUE;
    // When card data is loaded, this many cards should be animated as data is bound to them.
    private int mNumCardsToAnimate;
    // When card data is loaded, this is the position of the leftmost card to be animated.
    private int mCardAnimationStartPosition;
    // When card data is loaded, the animations may be delayed so that other animations can complete
    private int mExtraAnimationDelay;

    interface OnSelectionListener {
        /**
@@ -179,10 +173,6 @@ public class WalletCardCarousel extends RecyclerView {
        }
    }

    void setExtraAnimationDelay(int extraAnimationDelay) {
        mExtraAnimationDelay = extraAnimationDelay;
    }

    void setSelectionListener(OnSelectionListener selectionListener) {
        mSelectionListener = selectionListener;
    }
@@ -200,19 +190,14 @@ public class WalletCardCarousel extends RecyclerView {
    }

    /**
     * Set card data. Returns true if carousel was empty, indicating that views will be animated
     * Returns true if the data set is changed.
     */
    boolean setData(List<WalletCardViewInfo> data, int selectedIndex) {
        boolean wasEmpty = mWalletCardCarouselAdapter.getItemCount() == 0;
        mWalletCardCarouselAdapter.setData(data);
    boolean setData(List<WalletCardViewInfo> data, int selectedIndex, boolean hasLockStateChanged) {
        boolean hasDataChanged = mWalletCardCarouselAdapter.setData(data, hasLockStateChanged);
        scrollToPosition(selectedIndex);
        if (wasEmpty) {
            mNumCardsToAnimate = numCardsOnScreen(data.size(), selectedIndex);
            mCardAnimationStartPosition = Math.max(selectedIndex - 1, 0);
        }
        WalletCardViewInfo selectedCard = data.get(selectedIndex);
        mCardScrollListener.onCardScroll(selectedCard, selectedCard, 0);
        return wasEmpty;
        return hasDataChanged;
    }

    @Override
@@ -221,19 +206,6 @@ public class WalletCardCarousel extends RecyclerView {
        mSelectionListener.onCardSelected(mWalletCardCarouselAdapter.mData.get(position));
    }

    /**
     * The number of cards shown on screen when one of the cards is position in the center. This is
     * also the num
     */
    private static int numCardsOnScreen(int numCards, int selectedIndex) {
        if (numCards <= 2) {
            return numCards;
        }
        // When there are 3 or more cards, 3 cards will be shown unless the first or last card is
        // centered on screen.
        return selectedIndex > 0 && selectedIndex < (numCards - 1) ? 3 : 2;
    }

    /**
     * The padding pushes the first and last cards in the list to the center when they are
     * selected.
@@ -439,9 +411,29 @@ public class WalletCardCarousel extends RecyclerView {
            return mData.get(position).getCardId().hashCode();
        }

        void setData(List<WalletCardViewInfo> data) {
        private boolean setData(List<WalletCardViewInfo> data, boolean hasLockedStateChanged) {
            List<WalletCardViewInfo> oldData = mData;
            mData = data;
            if (hasLockedStateChanged || !isUiEquivalent(oldData, data)) {
                notifyDataSetChanged();
                return true;
            }
            return false;
        }

        private boolean isUiEquivalent(
                List<WalletCardViewInfo> oldData, List<WalletCardViewInfo> newData) {
            if (oldData.size() != newData.size()) {
                return false;
            }
            for (int i = 0; i < newData.size(); i++) {
                WalletCardViewInfo oldItem = oldData.get(i);
                WalletCardViewInfo newItem = newData.get(i);
                if (!oldItem.isUiEquivalent(newItem)) {
                    return false;
                }
            }
            return true;
        }
    }

+7 −0
Original line number Diff line number Diff line
@@ -54,4 +54,11 @@ interface WalletCardViewInfo {
     */
    @NonNull
    PendingIntent getPendingIntent();

    default boolean isUiEquivalent(WalletCardViewInfo other) {
        if (other == null) {
            return false;
        }
        return getCardId().equals(other.getCardId());
    }
}
+15 −37
Original line number Diff line number Diff line
@@ -19,8 +19,6 @@ package com.android.systemui.wallet.ui;
import static com.android.systemui.wallet.ui.WalletCardCarousel.CARD_ANIM_ALPHA_DELAY;
import static com.android.systemui.wallet.ui.WalletCardCarousel.CARD_ANIM_ALPHA_DURATION;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.Context;
@@ -29,6 +27,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
@@ -46,9 +45,8 @@ import java.util.List;
public class WalletView extends FrameLayout implements WalletCardCarousel.OnCardScrollListener {

    private static final String TAG = "WalletView";
    private static final int CAROUSEL_IN_ANIMATION_DURATION = 300;
    private static final int CAROUSEL_IN_ANIMATION_DURATION = 100;
    private static final int CAROUSEL_OUT_ANIMATION_DURATION = 200;
    private static final int CARD_LABEL_ANIM_DELAY = 133;

    private final WalletCardCarousel mCardCarousel;
    private final ImageView mIcon;
@@ -57,14 +55,12 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
    private final Button mAppButton;
    // Displays underneath the carousel, allow user to unlock device, verify card, etc.
    private final Button mActionButton;
    private final Interpolator mInInterpolator;
    private final Interpolator mOutInterpolator;
    private final float mAnimationTranslationX;
    private final ViewGroup mCardCarouselContainer;
    private final TextView mErrorView;
    private final ViewGroup mEmptyStateView;
    private CharSequence mCenterCardText;
    private Drawable mCenterCardIcon;
    private boolean mIsDeviceLocked = false;

    public WalletView(Context context) {
@@ -83,8 +79,6 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
        mActionButton = requireViewById(R.id.wallet_action_button);
        mErrorView = requireViewById(R.id.error_view);
        mEmptyStateView = requireViewById(R.id.wallet_empty_state);
        mInInterpolator =
                AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
        mOutInterpolator =
                AnimationUtils.loadInterpolator(context, android.R.interpolator.accelerate_cubic);
        mAnimationTranslationX = mCardCarousel.getCardWidthPx() / 4f;
@@ -109,7 +103,6 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
        Drawable centerCardIcon = centerCard.getIcon();
        if (!TextUtils.equals(mCenterCardText, centerCardText)) {
            mCenterCardText = centerCardText;
            mCenterCardIcon = centerCardIcon;
            mCardLabel.setText(centerCardText);
            mIcon.setImageDrawable(centerCardIcon);
        }
@@ -134,39 +127,15 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
     */
    void showCardCarousel(
            List<WalletCardViewInfo> data, int selectedIndex, boolean isDeviceLocked) {
        boolean shouldAnimate =
                mCardCarousel.setData(data, selectedIndex, mIsDeviceLocked != isDeviceLocked);
        mIsDeviceLocked = isDeviceLocked;
        boolean shouldAnimate = mCardCarousel.setData(data, selectedIndex);
        mCardCarouselContainer.setVisibility(VISIBLE);
        mErrorView.setVisibility(GONE);
        mEmptyStateView.setVisibility(GONE);
        renderHeaderIconAndActionButton(data.get(selectedIndex), isDeviceLocked);
        if (shouldAnimate) {
            // If the empty state is visible, animate it away and delay the card carousel animation
            int emptyStateAnimDelay = 0;
            if (mEmptyStateView.getVisibility() == VISIBLE) {
                emptyStateAnimDelay = CARD_ANIM_ALPHA_DURATION;
                mEmptyStateView.animate()
                        .alpha(0)
                        .setDuration(emptyStateAnimDelay)
                        .setListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                mEmptyStateView.setVisibility(GONE);
                            }
                        })
                        .start();
            }
            mCardLabel.setAlpha(0f);
            mCardLabel.animate().alpha(1f)
                    .setStartDelay(CARD_LABEL_ANIM_DELAY + emptyStateAnimDelay)
                    .setDuration(CARD_ANIM_ALPHA_DURATION)
                    .start();
            mCardCarousel.setExtraAnimationDelay(emptyStateAnimDelay);
            mCardCarousel.setTranslationX(mAnimationTranslationX);
            mCardCarousel.animate().translationX(0)
                    .setInterpolator(mInInterpolator)
                    .setDuration(CAROUSEL_IN_ANIMATION_DURATION)
                    .setStartDelay(emptyStateAnimDelay)
                    .start();
            animateViewsShown(mIcon, mCardLabel, mActionButton);
        }
    }

@@ -277,6 +246,15 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
        }
    }

    private static void animateViewsShown(View... uiElements) {
        for (View view : uiElements) {
            if (view.getVisibility() == VISIBLE) {
                view.setAlpha(0f);
                view.animate().alpha(1f).setDuration(CAROUSEL_IN_ANIMATION_DURATION).start();
            }
        }
    }

    private static CharSequence getLabelText(WalletCardViewInfo card) {
        String[] rawLabel = card.getLabel().toString().split("\\n");
        return rawLabel.length == 2 ? rawLabel[0] : card.getLabel();