blob: 01769e52c8d39838b88cde36c0bdedd0edad1da1 [file] [log] [blame]
/*
* Copyright (C) 2021 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.ui;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Handler;
import android.service.quickaccesswallet.GetWalletCardsError;
import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.service.quickaccesswallet.QuickAccessWalletService;
import android.service.quickaccesswallet.WalletCard;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import androidx.test.filters.SmallTest;
import com.android.internal.logging.UiEventLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.google.common.util.concurrent.MoreExecutors;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Collections;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
public class WalletScreenControllerTest extends SysuiTestCase {
private static final int CARD_CAROUSEL_WIDTH = 10;
private static final String CARD_ID_1 = "card_id_1";
private static final String CARD_ID_2 = "card_id_2";
private static final CharSequence SHORTCUT_SHORT_LABEL = "View all";
private static final CharSequence SHORTCUT_LONG_LABEL = "Add a payment method";
private static final CharSequence SERVICE_LABEL = "Wallet app";
private final Drawable mWalletLogo = mContext.getDrawable(android.R.drawable.ic_lock_lock);
private final Intent mWalletIntent = new Intent(QuickAccessWalletService.ACTION_VIEW_WALLET)
.setComponent(new ComponentName(mContext.getPackageName(), "WalletActivity"));
private WalletView mWalletView;
@Mock
QuickAccessWalletClient mWalletClient;
@Mock
ActivityStarter mActivityStarter;
@Mock
UserTracker mUserTracker;
@Mock
FalsingManager mFalsingManager;
@Mock
KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
KeyguardStateController mKeyguardStateController;
@Mock
UiEventLogger mUiEventLogger;
@Captor
ArgumentCaptor<PendingIntent> mIntentCaptor;
@Captor
ArgumentCaptor<QuickAccessWalletClient.OnWalletCardsRetrievedCallback> mCallbackCaptor;
private WalletScreenController mController;
private TestableLooper mTestableLooper;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this);
when(mUserTracker.getUserContext()).thenReturn(mContext);
mWalletView = new WalletView(mContext);
mWalletView.getCardCarousel().setExpectedViewWidth(CARD_CAROUSEL_WIDTH);
when(mWalletClient.getLogo()).thenReturn(mWalletLogo);
when(mWalletClient.getShortcutLongLabel()).thenReturn(SHORTCUT_LONG_LABEL);
when(mWalletClient.getShortcutShortLabel()).thenReturn(SHORTCUT_SHORT_LABEL);
when(mWalletClient.getServiceLabel()).thenReturn(SERVICE_LABEL);
when(mWalletClient.createWalletIntent()).thenReturn(mWalletIntent);
when(mKeyguardStateController.isUnlocked()).thenReturn(true);
when(mKeyguardUpdateMonitor.isUdfpsEnrolled()).thenReturn(false);
when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(false);
mController = new WalletScreenController(
mContext,
mWalletView,
mWalletClient,
mActivityStarter,
MoreExecutors.directExecutor(),
new Handler(mTestableLooper.getLooper()),
mUserTracker,
mFalsingManager,
mKeyguardUpdateMonitor,
mKeyguardStateController,
mUiEventLogger);
}
@Test
public void queryCards_deviceLocked_udfpsEnabled_hideUnlockButton() {
when(mKeyguardUpdateMonitor.isFingerprintDetectionRunning()).thenReturn(true);
when(mKeyguardUpdateMonitor.isUdfpsEnrolled()).thenReturn(true);
when(mKeyguardStateController.isUnlocked()).thenReturn(false);
GetWalletCardsResponse response =
new GetWalletCardsResponse(
Collections.singletonList(createWalletCard(mContext)), 0);
mController.queryWalletCards();
mTestableLooper.processAllMessages();
verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
QuickAccessWalletClient.OnWalletCardsRetrievedCallback callback =
mCallbackCaptor.getValue();
assertEquals(mController, callback);
callback.onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
assertEquals(VISIBLE, mWalletView.getCardCarouselContainer().getVisibility());
assertEquals(GONE, mWalletView.getActionButton().getVisibility());
}
@Test
public void queryCards_deviceLocked_udfpsNotEnabled_showUnlockButton() {
when(mKeyguardStateController.isUnlocked()).thenReturn(false);
GetWalletCardsResponse response =
new GetWalletCardsResponse(
Collections.singletonList(createLockedWalletCard(mContext)), 0);
mController.queryWalletCards();
mTestableLooper.processAllMessages();
verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
QuickAccessWalletClient.OnWalletCardsRetrievedCallback callback =
mCallbackCaptor.getValue();
assertEquals(mController, callback);
callback.onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
verify(mUiEventLogger).log(WalletUiEvent.QAW_IMPRESSION);
assertEquals(VISIBLE, mWalletView.getCardCarouselContainer().getVisibility());
assertEquals(VISIBLE, mWalletView.getActionButton().getVisibility());
}
@Test
public void queryCards_hasCards_showCarousel_activeCard() {
GetWalletCardsResponse response =
new GetWalletCardsResponse(
Collections.singletonList(createWalletCard(mContext)), 0);
mController.queryWalletCards();
mTestableLooper.processAllMessages();
verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
QuickAccessWalletClient.OnWalletCardsRetrievedCallback callback =
mCallbackCaptor.getValue();
assertEquals(mController, callback);
callback.onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
assertEquals(VISIBLE, mWalletView.getCardCarouselContainer().getVisibility());
assertEquals("Hold to reader", mWalletView.getCardLabel().getText().toString());
assertEquals(GONE, mWalletView.getErrorView().getVisibility());
verify(mUiEventLogger, times(1)).log(WalletUiEvent.QAW_IMPRESSION);
}
@Test
public void queryCards_hasCards_showCarousel_pendingActivationCard_parseLabel() {
GetWalletCardsResponse response =
new GetWalletCardsResponse(
Collections.singletonList(createNonActiveWalletCard(mContext)), 0);
mController.queryWalletCards();
mTestableLooper.processAllMessages();
verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
QuickAccessWalletClient.OnWalletCardsRetrievedCallback callback =
mCallbackCaptor.getValue();
assertEquals(mController, callback);
callback.onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
assertEquals(VISIBLE, mWalletView.getCardCarouselContainer().getVisibility());
assertEquals("Not set up", mWalletView.getCardLabel().getText().toString());
assertEquals("Verify now", mWalletView.getActionButton().getText().toString());
assertEquals(VISIBLE, mWalletView.getActionButton().getVisibility());
assertEquals(GONE, mWalletView.getErrorView().getVisibility());
}
@Test
public void queryCards_hasCards_showCarousel_badCard_parseLabel_notCrash() {
GetWalletCardsResponse response =
new GetWalletCardsResponse(
Collections.singletonList(createCrazyWalletCard(mContext, true)), 0);
mController.queryWalletCards();
mTestableLooper.processAllMessages();
verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
QuickAccessWalletClient.OnWalletCardsRetrievedCallback callback =
mCallbackCaptor.getValue();
assertEquals(mController, callback);
callback.onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
assertEquals(VISIBLE, mWalletView.getCardCarouselContainer().getVisibility());
assertEquals("This\nis\ncrazy!!", mWalletView.getCardLabel().getText().toString());
assertEquals(GONE, mWalletView.getActionButton().getVisibility());
assertEquals(GONE, mWalletView.getErrorView().getVisibility());
}
@Test
public void queryCards_hasCards_showCarousel_badCard_noLabel_notCrash() {
GetWalletCardsResponse response =
new GetWalletCardsResponse(
Collections.singletonList(createCrazyWalletCard(mContext, false)), 0);
mController.queryWalletCards();
mTestableLooper.processAllMessages();
verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
QuickAccessWalletClient.OnWalletCardsRetrievedCallback callback =
mCallbackCaptor.getValue();
assertEquals(mController, callback);
callback.onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
assertEquals(VISIBLE, mWalletView.getCardCarouselContainer().getVisibility());
assertEquals("", mWalletView.getCardLabel().getText().toString());
assertEquals(GONE, mWalletView.getActionButton().getVisibility());
assertEquals(GONE, mWalletView.getErrorView().getVisibility());
}
@Test
public void queryCards_hasCards_showCarousel_invalidSelectedIndex_notCrash() {
GetWalletCardsResponse response =
new GetWalletCardsResponse(
Collections.singletonList(createCrazyWalletCard(mContext, true)), 8);
mController.queryWalletCards();
mTestableLooper.processAllMessages();
verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
QuickAccessWalletClient.OnWalletCardsRetrievedCallback callback =
mCallbackCaptor.getValue();
assertEquals(mController, callback);
callback.onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
assertEquals(GONE, mWalletView.getCardCarousel().getVisibility());
assertEquals(VISIBLE, mWalletView.getEmptyStateView().getVisibility());
assertEquals(GONE, mWalletView.getErrorView().getVisibility());
}
@Test
public void queryCards_noCards_showEmptyState() {
GetWalletCardsResponse response = new GetWalletCardsResponse(Collections.EMPTY_LIST, 0);
mController.queryWalletCards();
mTestableLooper.processAllMessages();
verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
assertEquals(GONE, mWalletView.getCardCarousel().getVisibility());
assertEquals(VISIBLE, mWalletView.getEmptyStateView().getVisibility());
assertEquals(GONE, mWalletView.getErrorView().getVisibility());
}
@Test
public void queryCards_error_showErrorView() {
String errorMessage = "getWalletCardsError";
GetWalletCardsError error = new GetWalletCardsError(createIcon(), errorMessage);
mController.queryWalletCards();
mTestableLooper.processAllMessages();
verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
mCallbackCaptor.getValue().onWalletCardRetrievalError(error);
mTestableLooper.processAllMessages();
assertEquals(GONE, mWalletView.getCardCarouselContainer().getVisibility());
assertEquals(GONE, mWalletView.getEmptyStateView().getVisibility());
assertEquals(VISIBLE, mWalletView.getErrorView().getVisibility());
assertEquals(errorMessage, mWalletView.getErrorView().getText().toString());
}
@Test
public void onKeyguardFadingAwayChanged_queryCards() {
mController.onKeyguardFadingAwayChanged();
verify(mWalletClient).getWalletCards(any(), any(), mCallbackCaptor.capture());
assertEquals(mController, mCallbackCaptor.getValue());
}
@Test
public void onCardSelected() {
mController.onCardSelected(createCardViewInfo(createWalletCard(mContext)));
assertEquals(CARD_ID_1, mController.mSelectedCardId);
}
@Test
public void logOnCardChanged() {
mController.onCardSelected(createCardViewInfo(createWalletCard(mContext)));
mController.onCardSelected(createCardViewInfo(createNonActiveWalletCard(mContext)));
verify(mUiEventLogger, times(1)).log(WalletUiEvent.QAW_CHANGE_CARD);
}
@Test
public void onCardClicked_startIntent() {
WalletCardViewInfo walletCardViewInfo = createCardViewInfo(createWalletCard(mContext));
mController.onCardClicked(walletCardViewInfo);
verify(mActivityStarter).startPendingIntentDismissingKeyguard(mIntentCaptor.capture());
Intent actualIntent = mIntentCaptor.getValue().getIntent();
assertEquals(mWalletIntent.getAction(), actualIntent.getAction());
assertEquals(mWalletIntent.getComponent(), actualIntent.getComponent());
verify(mUiEventLogger, times(1)).log(WalletUiEvent.QAW_CLICK_CARD);
}
@Test
public void onCardClicked_deviceLocked_logUnlockEvent() {
when(mKeyguardStateController.isUnlocked()).thenReturn(false);
WalletCardViewInfo walletCardViewInfo = createCardViewInfo(createWalletCard(mContext));
mController.onCardClicked(walletCardViewInfo);
verify(mUiEventLogger, times(1))
.log(WalletUiEvent.QAW_UNLOCK_FROM_CARD_CLICK);
verify(mUiEventLogger, times(1)).log(WalletUiEvent.QAW_CLICK_CARD);
}
@Test
public void onWalletCardsRetrieved_cardDataEmpty_intentIsNull_hidesWallet() {
when(mWalletClient.createWalletIntent()).thenReturn(null);
GetWalletCardsResponse response = new GetWalletCardsResponse(Collections.emptyList(), 0);
mController.onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
assertEquals(GONE, mWalletView.getVisibility());
}
@Test
public void onWalletCardsRetrieved_cardDataEmpty_logoIsNull_hidesWallet() {
when(mWalletClient.getLogo()).thenReturn(null);
GetWalletCardsResponse response = new GetWalletCardsResponse(Collections.emptyList(), 0);
mController.onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
assertEquals(GONE, mWalletView.getVisibility());
}
@Test
public void onWalletCardsRetrieved_cardDataEmpty_labelIsEmpty_hidesWallet() {
when(mWalletClient.getShortcutLongLabel()).thenReturn("");
GetWalletCardsResponse response = new GetWalletCardsResponse(Collections.emptyList(), 0);
mController.onWalletCardsRetrieved(response);
mTestableLooper.processAllMessages();
assertEquals(GONE, mWalletView.getVisibility());
}
private WalletCard createNonActiveWalletCard(Context context) {
PendingIntent pendingIntent =
PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
return new WalletCard.Builder(CARD_ID_2, createIcon(), "•••• 5678", pendingIntent)
.setCardIcon(createIcon())
.setCardLabel("Not set up\nVerify now")
.build();
}
private WalletCard createLockedWalletCard(Context context) {
PendingIntent pendingIntent =
PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
return new WalletCard.Builder(CARD_ID_2, createIcon(), "•••• 5679", pendingIntent)
.setCardIcon(createIcon())
.setCardLabel("Locked\nUnlock to pay")
.build();
}
private WalletCard createWalletCard(Context context) {
PendingIntent pendingIntent =
PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
return new WalletCard.Builder(CARD_ID_1, createIcon(), "•••• 1234", pendingIntent)
.setCardIcon(createIcon())
.setCardLabel("Hold to reader")
.build();
}
private WalletCard createCrazyWalletCard(Context context, boolean hasLabel) {
PendingIntent pendingIntent =
PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
return new WalletCard.Builder("BadCard", createIcon(), "•••• 1234", pendingIntent)
.setCardIcon(null)
.setCardLabel(hasLabel ? "This\nis\ncrazy!!" : null)
.build();
}
private static Icon createIcon() {
return Icon.createWithBitmap(Bitmap.createBitmap(70, 44, Bitmap.Config.ARGB_8888));
}
private WalletCardViewInfo createCardViewInfo(WalletCard walletCard) {
return new WalletScreenController.QAWalletCardViewInfo(
mContext, walletCard);
}
}