Merge "Wallet card carousel screen UI polish." into sc-dev

This commit is contained in:
Silin Huang
2021-04-12 20:20:47 +00:00
committed by Android (Google) Code Review
9 changed files with 141 additions and 46 deletions

View File

@@ -16,8 +16,8 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size
android:height="50dp"
android:width="50dp" />
android:height="56dp"
android:width="56dp" />
<solid android:color="@android:color/transparent" />
<stroke android:width="2dp" android:color="#AECBFA" />
</shape>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2019 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<size
android:height="56dp"
android:width="56dp" />
<solid android:color="@android:color/transparent" />
<stroke android:width="2dp" android:color="@color/GM2_grey_300" />
</shape>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="@color/GM2_grey_300"/>
<solid android:color="@android:color/transparent"/>
<corners android:radius="24dp"/>
</shape>
</item>
</selector>

View File

@@ -23,7 +23,7 @@
android:id="@+id/card_carousel_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="36dp"
android:layout_marginTop="48dp"
android:orientation="vertical">
<ImageView
android:id="@+id/icon"
@@ -31,7 +31,6 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginVertical="10dp"
android:background="@drawable/circle_wallet_primary_50dp"
android:scaleType="center"
android:contentDescription="@null"/>
<TextView
@@ -50,22 +49,36 @@
android:clipToPadding="false"
android:layout_marginVertical="24dp"/>
<Button
android:id="@+id/wallet_action_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginVertical="16dp"
android:paddingVertical="@dimen/wallet_button_vertical_padding"
android:paddingHorizontal="@dimen/wallet_button_horizontal_padding"
android:background="@drawable/wallet_action_button_bg"
android:textColor="@color/wallet_white"
android:textAlignment="center"
android:visibility="gone"/>
<View
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
android:id="@+id/wallet_button"
android:background="@drawable/wallet_button"
android:textColor="@color/wallet_white"
android:textAlignment="center"
android:id="@+id/wallet_app_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="24dp"
android:paddingVertical="8dp"
android:layout_marginVertical="24dp"
android:layout_gravity="center_horizontal"/>
android:layout_gravity="center_horizontal"
android:paddingVertical="@dimen/wallet_button_vertical_padding"
android:paddingHorizontal="@dimen/wallet_button_horizontal_padding"
android:background="@drawable/wallet_app_button_bg"
android:text="@string/wallet_app_button_label"
android:textColor="@color/GM2_blue_600"
android:textAlignment="center"
android:layout_marginVertical="24dp"/>
</LinearLayout>

View File

@@ -1452,6 +1452,8 @@
<dimen name="wallet_empty_state_corner_radius">24dp</dimen>
<dimen name="wallet_tile_card_view_height">32dp</dimen>
<dimen name="wallet_tile_card_view_width">50dp</dimen>
<dimen name="wallet_button_horizontal_padding">24dp</dimen>
<dimen name="wallet_button_vertical_padding">8dp</dimen>
<!-- Ongoing call chip -->
<dimen name="ongoing_call_chip_side_padding">12dp</dimen>

View File

@@ -1650,10 +1650,10 @@
<!-- Wallet strings -->
<!-- Wallet empty state, title [CHAR LIMIT=32] -->
<string name="wallet_title">Wallet</string>
<!-- Label of the button underneath the card carousel when device is unlocked. [CHAR LIMIT=NONE] -->
<string name="wallet_button_label_device_unlocked">Show all</string>
<!-- Label of the button underneath the card carousel when device is locked. [CHAR LIMIT=NONE] -->
<string name="wallet_button_label_device_locked">Unlock to pay</string>
<!-- Label of the button at the bottom prompting user enter wallet app. [CHAR LIMIT=NONE] -->
<string name="wallet_app_button_label">Show all</string>
<!-- Label of the button underneath the card carousel prompting user unlock device. [CHAR LIMIT=NONE] -->
<string name="wallet_action_button_label_unlock">Unlock to pay</string>
<!-- Secondary label of the quick access wallet tile if active. [CHAR LIMIT=32] -->
<string name="wallet_secondary_label_active">Ready</string>
<!-- Secondary label of the quick access wallet tile if no card. [CHAR LIMIT=NONE] -->

View File

@@ -94,17 +94,15 @@ public class WalletActivity extends LifecycleActivity {
mHandler,
mUserTracker,
mKeyguardStateController);
// Clicking the wallet button will open the wallet app if the device is unlocked; bring up
// the security bouncer otherwise.
walletView.getWalletButton().setOnClickListener(
v -> {
if (mKeyguardStateController.isUnlocked()) {
mActivityStarter.startActivity(
mQuickAccessWalletClient.createWalletIntent(), true);
} else {
mKeyguardDismissUtil.executeWhenUnlocked(() -> false, false);
}
});
walletView.getAppButton().setOnClickListener(
v -> mActivityStarter.startActivity(
mQuickAccessWalletClient.createWalletIntent(), true));
// Click the action button to re-render the screen when the device is unlocked.
if (!mKeyguardStateController.isUnlocked()) {
walletView.getActionButton().setOnClickListener(
v -> mKeyguardDismissUtil.executeWhenUnlocked(() -> false, false));
}
}
@Override

View File

@@ -54,7 +54,10 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
private final WalletCardCarousel mCardCarousel;
private final ImageView mIcon;
private final TextView mCardLabel;
private final Button mWalletButton;
// Displays at the bottom of the screen, allow user to enter the default wallet app.
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;
@@ -75,7 +78,8 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
mCardCarousel.setCardScrollListener(this);
mIcon = requireViewById(R.id.icon);
mCardLabel = requireViewById(R.id.label);
mWalletButton = requireViewById(R.id.wallet_button);
mAppButton = requireViewById(R.id.wallet_app_button);
mActionButton = requireViewById(R.id.wallet_action_button);
mErrorView = requireViewById(R.id.error_view);
mEmptyStateView = requireViewById(R.id.wallet_empty_state);
mInInterpolator =
@@ -101,15 +105,6 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
public void onCardScroll(WalletCardViewInfo centerCard, WalletCardViewInfo nextCard,
float percentDistanceFromCenter) {
CharSequence centerCardText = centerCard.getLabel();
Drawable icon = centerCard.getIcon();
if (icon != null) {
Drawable drawable = resizeDrawable(getResources(), icon);
drawable.setTint(mContext.getColor(R.color.GM2_blue_600));
mIcon.setImageDrawable(drawable);
mIcon.setVisibility(VISIBLE);
} else {
mIcon.setVisibility(INVISIBLE);
}
if (!TextUtils.equals(mCenterCardText, centerCardText)) {
mCenterCardText = centerCardText;
mCardLabel.setText(centerCardText);
@@ -122,16 +117,21 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
}
}
/**
* Render and show card carousel view.
*
* <p>This is called only when {@param data} is not empty.</p>
*
* @param data a list of wallet cards information.
* @param selectedIndex index of the current selected card
* @param isDeviceLocked indicates whether the device is locked.
*/
void showCardCarousel(
List<WalletCardViewInfo> data, int selectedIndex, boolean isDeviceLocked) {
boolean shouldAnimate = mCardCarousel.setData(data, selectedIndex);
mCardCarouselContainer.setVisibility(VISIBLE);
mErrorView.setVisibility(GONE);
if (isDeviceLocked) {
mWalletButton.setText(R.string.wallet_button_label_device_locked);
} else {
mWalletButton.setText(R.string.wallet_button_label_device_unlocked);
}
renderHeaderIconAndActionButton(data.get(0), isDeviceLocked);
if (shouldAnimate) {
// If the empty state is visible, animate it away and delay the card carousel animation
int emptyStateAnimDelay = 0;
@@ -216,8 +216,12 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
return mCardCarousel;
}
Button getWalletButton() {
return mWalletButton;
Button getAppButton() {
return mAppButton;
}
Button getActionButton() {
return mActionButton;
}
@VisibleForTesting
@@ -235,7 +239,37 @@ public class WalletView extends FrameLayout implements WalletCardCarousel.OnCard
return mCardCarouselContainer;
}
private static Drawable resizeDrawable(Resources resources, Drawable drawable) {
private void renderHeaderIconAndActionButton(WalletCardViewInfo walletCard, boolean isLocked) {
Drawable icon = resizeDrawable(getResources(), walletCard.getIcon());
renderHeaderIcon(icon, isLocked);
if (isLocked) {
mActionButton.setVisibility(VISIBLE);
mActionButton.setText(R.string.wallet_action_button_label_unlock);
} else {
mActionButton.setVisibility(GONE);
}
}
private void renderHeaderIcon(@Nullable Drawable icon, boolean isLocked) {
if (icon == null) {
mIcon.setVisibility(INVISIBLE);
return;
}
icon.setTint(mContext.getColor(isLocked ? R.color.GM2_grey_800 : R.color.GM2_blue_600));
mIcon.setImageDrawable(icon);
mIcon.setVisibility(VISIBLE);
mIcon.setBackground(
mContext.getDrawable(
isLocked
? R.drawable.circle_wallet_secondary_56dp
: R.drawable.circle_wallet_primary_56dp));
}
@Nullable
private static Drawable resizeDrawable(Resources resources, @Nullable Drawable drawable) {
if (drawable == null) {
return null;
}
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
return new BitmapDrawable(resources, Bitmap.createScaledBitmap(
bitmap, CONTACTLESS_ICON_SIZE, CONTACTLESS_ICON_SIZE, true));