diff options
8 files changed, 212 insertions, 22 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt index 5d7a3d432dcb..23f50eaba7e7 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfig.kt @@ -34,6 +34,7 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.plugins.ActivityStarter import com.android.systemui.wallet.controller.QuickAccessWalletController +import com.android.systemui.wallet.util.getPaymentCards import javax.inject.Inject import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow @@ -60,7 +61,7 @@ constructor( val callback = object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback { override fun onWalletCardsRetrieved(response: GetWalletCardsResponse) { - val hasCards = response?.walletCards?.isNotEmpty() == true + val hasCards = getPaymentCards(response.walletCards)?.isNotEmpty() == true trySendWithFailureLogging( state( isFeatureEnabled = isWalletAvailable(), @@ -135,7 +136,7 @@ constructor( object : QuickAccessWalletClient.OnWalletCardsRetrievedCallback { override fun onWalletCardsRetrieved(response: GetWalletCardsResponse) { continuation.resumeWith( - Result.success(response?.walletCards ?: emptyList()) + Result.success(getPaymentCards(response.walletCards) ?: emptyList()) ) } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java index 544e6ad295ff..e382eca17369 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QuickAccessWalletTile.java @@ -20,6 +20,7 @@ import static android.graphics.drawable.Icon.TYPE_URI; import static android.provider.Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT; import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE; +import static com.android.systemui.wallet.util.WalletCardUtilsKt.getPaymentCards; import android.content.Intent; import android.content.pm.PackageManager; @@ -210,7 +211,7 @@ public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> { public void onWalletCardsRetrieved(@NonNull GetWalletCardsResponse response) { Log.i(TAG, "Successfully retrieved wallet cards."); mIsWalletUpdating = false; - List<WalletCard> cards = response.getWalletCards(); + List<WalletCard> cards = getPaymentCards(response.getWalletCards()); if (cards.isEmpty()) { Log.d(TAG, "No wallet cards exist."); mCardViewDrawable = null; diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java index 81d04d4458c0..6fd0a4db5a14 100644 --- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java +++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java @@ -16,6 +16,8 @@ package com.android.systemui.wallet.ui; +import static com.android.systemui.wallet.util.WalletCardUtilsKt.getPaymentCards; + import android.app.PendingIntent; import android.content.Context; import android.content.Intent; @@ -47,10 +49,10 @@ import com.android.systemui.plugins.FalsingManager; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.policy.KeyguardStateController; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** Controller for the wallet card carousel screen. */ public class WalletScreenController implements @@ -126,22 +128,11 @@ public class WalletScreenController implements return; } Log.i(TAG, "Successfully retrieved wallet cards."); - List<WalletCard> walletCards = response.getWalletCards(); - - boolean allUnknown = true; - for (WalletCard card : walletCards) { - if (card.getCardType() != WalletCard.CARD_TYPE_UNKNOWN) { - allUnknown = false; - break; - } - } + List<WalletCard> walletCards = getPaymentCards(response.getWalletCards()); - List<WalletCardViewInfo> paymentCardData = new ArrayList<>(); - for (WalletCard card : walletCards) { - if (allUnknown || card.getCardType() == WalletCard.CARD_TYPE_PAYMENT) { - paymentCardData.add(new QAWalletCardViewInfo(mContext, card)); - } - } + List<WalletCardViewInfo> paymentCardData = walletCards.stream().map( + card -> new QAWalletCardViewInfo(mContext, card) + ).collect(Collectors.toList()); // Get on main thread for UI updates. mHandler.post(() -> { diff --git a/packages/SystemUI/src/com/android/systemui/wallet/util/WalletCardUtils.kt b/packages/SystemUI/src/com/android/systemui/wallet/util/WalletCardUtils.kt new file mode 100644 index 000000000000..077b80bde953 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/wallet/util/WalletCardUtils.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2023 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. + */ + +package com.android.systemui.wallet.util + +import android.service.quickaccesswallet.WalletCard + +/** + * Filters wallet cards to only those of [WalletCard.CARD_TYPE_PAYMENT], or returns all cards if + * they are all of [WalletCard.CARD_TYPE_UNKNOWN] (maintaining pre-U behavior). Used by the wallet + * card carousel, quick settings tile, and lock screen. + */ +fun getPaymentCards(walletCards: List<WalletCard>): List<WalletCard> { + val atLeastOneKnownCardType = walletCards.any { it.cardType != WalletCard.CARD_TYPE_UNKNOWN } + + return if (atLeastOneKnownCardType) { + walletCards.filter { it.cardType == WalletCard.CARD_TYPE_PAYMENT } + } else { + walletCards + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt index d36e77889810..b9c0b7fe35d7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/QuickAccessWalletKeyguardQuickAffordanceConfigTest.kt @@ -20,6 +20,7 @@ package com.android.systemui.keyguard.data.quickaffordance import android.graphics.drawable.Drawable import android.service.quickaccesswallet.GetWalletCardsResponse import android.service.quickaccesswallet.QuickAccessWalletClient +import android.service.quickaccesswallet.WalletCard import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.R @@ -38,6 +39,7 @@ import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.runBlockingTest import kotlinx.coroutines.test.runTest import org.junit.Before @@ -92,6 +94,40 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { } @Test + fun affordance_keyguardShowing_hasNonPaymentCard_modelIsNone() = + runTest(UnconfinedTestDispatcher()) { + setUpState(cardType = WalletCard.CARD_TYPE_NON_PAYMENT) + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null + + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) + + assertThat(latest).isEqualTo(KeyguardQuickAffordanceConfig.LockScreenState.Hidden) + job.cancel() + } + + @Test + fun affordance_keyguardShowing_hasPaymentCard_visibleModel() = + runTest(UnconfinedTestDispatcher()) { + setUpState(cardType = WalletCard.CARD_TYPE_PAYMENT) + var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null + + val job = underTest.lockScreenState.onEach { latest = it }.launchIn(this) + + val visibleModel = latest as KeyguardQuickAffordanceConfig.LockScreenState.Visible + assertThat(visibleModel.icon) + .isEqualTo( + Icon.Loaded( + drawable = ICON, + contentDescription = + ContentDescription.Resource( + res = R.string.accessibility_wallet_button, + ), + ) + ) + job.cancel() + } + + @Test fun affordance_walletFeatureNotEnabled_modelIsNone() = runBlockingTest { setUpState(isWalletFeatureAvailable = false) var latest: KeyguardQuickAffordanceConfig.LockScreenState? = null @@ -187,6 +223,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { isWalletServiceAvailable: Boolean = true, isWalletQuerySuccessful: Boolean = true, hasSelectedCard: Boolean = true, + cardType: Int = WalletCard.CARD_TYPE_UNKNOWN ) { val walletClient: QuickAccessWalletClient = mock() whenever(walletClient.tileIcon).thenReturn(ICON) @@ -202,7 +239,19 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { if (isWalletQuerySuccessful) { onWalletCardsRetrieved( if (hasSelectedCard) { - GetWalletCardsResponse(listOf(mock()), 0) + GetWalletCardsResponse( + listOf( + WalletCard.Builder( + /*cardId= */ CARD_ID, + /*cardType= */ cardType, + /*cardImage= */ mock(), + /*contentDescription= */ CARD_DESCRIPTION, + /*pendingIntent= */ mock() + ) + .build() + ), + 0 + ) } else { GetWalletCardsResponse(emptyList(), 0) } @@ -216,5 +265,7 @@ class QuickAccessWalletKeyguardQuickAffordanceConfigTest : SysuiTestCase() { companion object { private val ICON: Drawable = mock() + private const val CARD_ID: String = "Id" + private const val CARD_DESCRIPTION: String = "Description" } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java index b00ae399af21..dd55baddc2d9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/QuickAccessWalletTileTest.java @@ -395,7 +395,7 @@ public class QuickAccessWalletTileTest extends SysuiTestCase { PendingIntent.getActivity(mContext, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE); WalletCard walletCard = new WalletCard.Builder( - CARD_ID, mCardImage, CARD_DESCRIPTION, pendingIntent).build(); + CARD_ID, mCardImage, CARD_DESCRIPTION, pendingIntent).build(); GetWalletCardsResponse response = new GetWalletCardsResponse(Collections.singletonList(walletCard), 0); @@ -410,6 +410,22 @@ public class QuickAccessWalletTileTest extends SysuiTestCase { } @Test + public void testQueryCards_cardDataPayment_updateSideViewDrawable() { + when(mKeyguardStateController.isUnlocked()).thenReturn(true); + setUpWalletCardWithType(/* hasCard =*/ true, WalletCard.CARD_TYPE_PAYMENT); + + assertNotNull(mTile.getState().sideViewCustomDrawable); + } + + @Test + public void testQueryCards_cardDataNonPayment_updateSideViewDrawable() { + when(mKeyguardStateController.isUnlocked()).thenReturn(true); + setUpWalletCardWithType(/* hasCard =*/ true, WalletCard.CARD_TYPE_NON_PAYMENT); + + assertNull(mTile.getState().sideViewCustomDrawable); + } + + @Test public void testQueryCards_noCards_notUpdateSideViewDrawable() { setUpWalletCard(/* hasCard= */ false); @@ -438,6 +454,29 @@ public class QuickAccessWalletTileTest extends SysuiTestCase { verifyZeroInteractions(mQuickAccessWalletClient); } + private WalletCard createWalletCardWithType(Context context, int cardType) { + PendingIntent pendingIntent = + PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE); + return new WalletCard.Builder(CARD_ID, cardType, CARD_IMAGE, CARD_DESCRIPTION, + pendingIntent).build(); + } + + private void setUpWalletCardWithType(boolean hasCard, int cardType) { + GetWalletCardsResponse response = + new GetWalletCardsResponse( + hasCard + ? Collections.singletonList( + createWalletCardWithType(mContext, cardType)) + : Collections.EMPTY_LIST, 0); + + mTile.handleSetListening(true); + + verify(mController).queryWalletCards(mCallbackCaptor.capture()); + + mCallbackCaptor.getValue().onWalletCardsRetrieved(response); + mTestableLooper.processAllMessages(); + } + private void setUpWalletCard(boolean hasCard) { GetWalletCardsResponse response = new GetWalletCardsResponse( diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java index 692af6a9a37b..c1d11aa1eb89 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java @@ -459,7 +459,7 @@ public class WalletScreenControllerTest extends SysuiTestCase { WalletCard.CARD_TYPE_UNKNOWN), createWalletCardWithType(mContext, WalletCard.CARD_TYPE_PAYMENT), createWalletCardWithType(mContext, WalletCard.CARD_TYPE_NON_PAYMENT) - ); + ); GetWalletCardsResponse response = new GetWalletCardsResponse(walletCardList, 0); mController.onWalletCardsRetrieved(response); mTestableLooper.processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/util/WalletCardUtilsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/wallet/util/WalletCardUtilsTest.kt new file mode 100644 index 000000000000..e46c1f554dd6 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/util/WalletCardUtilsTest.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 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. + */ + +package com.android.systemui.wallet.util + +import android.service.quickaccesswallet.WalletCard +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.util.mockito.mock +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith + +/** Test class for WalletCardUtils */ +@RunWith(AndroidTestingRunner::class) +@RunWithLooper +@SmallTest +class WalletCardUtilsTest : SysuiTestCase() { + + private val paymentCard = createWalletCardWithType(WalletCard.CARD_TYPE_PAYMENT) + private val nonPaymentCard = createWalletCardWithType(WalletCard.CARD_TYPE_NON_PAYMENT) + private val unknownCard = createWalletCardWithType(WalletCard.CARD_TYPE_UNKNOWN) + + @Test + fun paymentCards_cardTypesAllUnknown_getsAllCards() { + val walletCardList = + mutableListOf( + createWalletCardWithType(WalletCard.CARD_TYPE_UNKNOWN), + createWalletCardWithType(WalletCard.CARD_TYPE_UNKNOWN), + createWalletCardWithType(WalletCard.CARD_TYPE_UNKNOWN) + ) + + assertThat(walletCardList).isEqualTo(getPaymentCards(walletCardList)) + } + + @Test + fun paymentCards_cardTypesDifferent_onlyGetsPayment() { + val walletCardList = mutableListOf(paymentCard, nonPaymentCard, unknownCard) + + assertThat(getPaymentCards(walletCardList)).isEqualTo(mutableListOf(paymentCard)) + } + + private fun createWalletCardWithType(cardType: Int): WalletCard { + return WalletCard.Builder( + /*cardId= */ CARD_ID, + /*cardType= */ cardType, + /*cardImage= */ mock(), + /*contentDescription= */ CARD_DESCRIPTION, + /*pendingIntent= */ mock() + ) + .build() + } + + companion object { + private const val CARD_ID: String = "ID" + private const val CARD_DESCRIPTION: String = "Description" + } +} |