Loading packages/SystemUI/res/layout/wallet_card_view.xml +2 −9 Original line number Diff line number Diff line Loading @@ -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"> Loading @@ -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> packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java +27 −35 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 { /** Loading Loading @@ -179,10 +173,6 @@ public class WalletCardCarousel extends RecyclerView { } } void setExtraAnimationDelay(int extraAnimationDelay) { mExtraAnimationDelay = extraAnimationDelay; } void setSelectionListener(OnSelectionListener selectionListener) { mSelectionListener = selectionListener; } Loading @@ -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 Loading @@ -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. Loading Loading @@ -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; } } Loading packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardViewInfo.java +7 −0 Original line number Diff line number Diff line Loading @@ -54,4 +54,11 @@ interface WalletCardViewInfo { */ @NonNull PendingIntent getPendingIntent(); default boolean isUiEquivalent(WalletCardViewInfo other) { if (other == null) { return false; } return getCardId().equals(other.getCardId()); } } packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java +15 −37 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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) { Loading @@ -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; Loading @@ -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); } Loading @@ -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); } } Loading Loading @@ -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(); Loading Loading
packages/SystemUI/res/layout/wallet_card_view.xml +2 −9 Original line number Diff line number Diff line Loading @@ -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"> Loading @@ -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>
packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardCarousel.java +27 −35 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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 { /** Loading Loading @@ -179,10 +173,6 @@ public class WalletCardCarousel extends RecyclerView { } } void setExtraAnimationDelay(int extraAnimationDelay) { mExtraAnimationDelay = extraAnimationDelay; } void setSelectionListener(OnSelectionListener selectionListener) { mSelectionListener = selectionListener; } Loading @@ -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 Loading @@ -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. Loading Loading @@ -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; } } Loading
packages/SystemUI/src/com/android/systemui/wallet/ui/WalletCardViewInfo.java +7 −0 Original line number Diff line number Diff line Loading @@ -54,4 +54,11 @@ interface WalletCardViewInfo { */ @NonNull PendingIntent getPendingIntent(); default boolean isUiEquivalent(WalletCardViewInfo other) { if (other == null) { return false; } return getCardId().equals(other.getCardId()); } }
packages/SystemUI/src/com/android/systemui/wallet/ui/WalletView.java +15 −37 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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) { Loading @@ -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; Loading @@ -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); } Loading @@ -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); } } Loading Loading @@ -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(); Loading