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

Commit ce249254 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Merge cherrypicks of ['googleplex-android-review.googlesource.com/30595743',...

Merge cherrypicks of ['googleplex-android-review.googlesource.com/30595743', 'googleplex-android-review.googlesource.com/29689248', 'googleplex-android-review.googlesource.com/29688663', 'googleplex-android-review.googlesource.com/29688664', 'googleplex-android-review.googlesource.com/30965242', 'googleplex-android-review.googlesource.com/31157007', 'googleplex-android-review.googlesource.com/31106431', 'googleplex-android-review.googlesource.com/31092845', 'googleplex-android-review.googlesource.com/30800590'] into security-aosp-24Q3-release.

Change-Id: I152139156ffec25bc87272cf5b73769548a63e6e
parents 505938d9 f1a15b5e
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -19,10 +19,10 @@ package android.app;
import android.os.IRemoteCallback;

/** {@hide} */
oneway interface IUserSwitchObserver {
interface IUserSwitchObserver {
    void onBeforeUserSwitching(int newUserId);
    void onUserSwitching(int newUserId, IRemoteCallback reply);
    void onUserSwitchComplete(int newUserId);
    void onForegroundProfileSwitch(int newProfileId);
    void onLockedBootComplete(int newUserId);
    oneway void onUserSwitching(int newUserId, IRemoteCallback reply);
    oneway void onUserSwitchComplete(int newUserId);
    oneway void onForegroundProfileSwitch(int newProfileId);
    oneway void onLockedBootComplete(int newUserId);
}
+3 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.packageinstaller;
import static android.Manifest.permission;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ARCHIVED_PACKAGES;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;

import android.app.Activity;
import android.app.DialogFragment;
@@ -53,6 +54,8 @@ public class UnarchiveActivity extends Activity {

    @Override
    public void onCreate(Bundle icicle) {
        getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);

        super.onCreate(null);

        int callingUid = getLaunchedFromUid();
+30 −1
Original line number Diff line number Diff line
@@ -21,10 +21,14 @@ import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.widget.Button;

public class UnarchiveFragment extends DialogFragment implements
        DialogInterface.OnClickListener {

    private Dialog mDialog;
    private Button mRestoreButton;

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        String appTitle = getArguments().getString(UnarchiveActivity.APP_TITLE);
@@ -40,7 +44,32 @@ public class UnarchiveFragment extends DialogFragment implements
        dialogBuilder.setPositiveButton(R.string.restore, this);
        dialogBuilder.setNegativeButton(android.R.string.cancel, this);

        return dialogBuilder.create();
        mDialog = dialogBuilder.create();
        return mDialog;
    }

    @Override
    public void onStart() {
        super.onStart();
        if (mDialog != null) {
            mRestoreButton = ((AlertDialog) mDialog).getButton(DialogInterface.BUTTON_POSITIVE);
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        if (mRestoreButton != null) {
            mRestoreButton.setEnabled(false);
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (mRestoreButton != null) {
            mRestoreButton.setEnabled(true);
        }
    }

    @Override
+13 −10
Original line number Diff line number Diff line
@@ -47,19 +47,19 @@ import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.StringRes;

import com.android.packageinstaller.common.EventResultPersister;
import com.android.packageinstaller.common.UninstallEventReceiver;
import com.android.packageinstaller.handheld.ErrorDialogFragment;
import com.android.packageinstaller.handheld.UninstallAlertDialogFragment;
import com.android.packageinstaller.television.ErrorFragment;
import com.android.packageinstaller.television.UninstallAlertFragment;
import com.android.packageinstaller.television.UninstallAppProgress;
import com.android.packageinstaller.common.EventResultPersister;
import com.android.packageinstaller.common.UninstallEventReceiver;
import com.android.packageinstaller.v2.ui.UninstallLaunch;

import java.util.List;

/*
 * This activity presents UI to uninstall an application. Usually launched with intent
 * Intent.ACTION_UNINSTALL_PKG_COMMAND and attribute
@@ -182,14 +182,17 @@ public class UninstallerActivity extends Activity {
        if (mDialogInfo.user == null) {
            mDialogInfo.user = Process.myUserHandle();
        } else {
            List<UserHandle> profiles = userManager.getUserProfiles();
            if (!profiles.contains(mDialogInfo.user)) {
            if (!mDialogInfo.user.equals(Process.myUserHandle())) {
                final boolean isCurrentUserProfileOwner = Process.myUserHandle().equals(
                        userManager.getProfileParent(mDialogInfo.user));
                if (!isCurrentUserProfileOwner) {
                    Log.e(TAG, "User " + Process.myUserHandle() + " can't request uninstall "
                            + "for user " + mDialogInfo.user);
                    showUserIsNotAllowed();
                    return;
                }
            }
        }

        mDialogInfo.callback = intent.getParcelableExtra(PackageInstaller.EXTRA_CALLBACK,
                                            PackageManager.UninstallCompleteCallback.class);
+545 −0
Original line number Diff line number Diff line
/*
 * 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.qs.tiles;

import static android.content.pm.PackageManager.FEATURE_NFC_HOST_CARD_EMULATION;
import static android.provider.Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT;

import static com.google.common.truth.Truth.assertThat;

import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertNull;
import static junit.framework.TestCase.assertTrue;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.os.Handler;
import android.os.UserHandle;
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.service.quicksettings.Tile;
import android.testing.TestableLooper;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.android.internal.logging.MetricsLogger;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.classifier.FalsingManagerFake;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.QsEventLogger;
import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.qs.tileimpl.QSTileImpl;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.wallet.controller.QuickAccessWalletController;

import org.junit.After;
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(AndroidJUnit4.class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@SmallTest
public class QuickAccessWalletTileTest extends SysuiTestCase {

    private static final String CARD_ID = "card_id";
    private static final String LABEL = "QAW";
    private static final String CARD_DESCRIPTION = "•••• 1234";
    private static final Icon CARD_IMAGE =
            Icon.createWithBitmap(Bitmap.createBitmap(70, 50, Bitmap.Config.ARGB_8888));
    private static final Icon INVALID_CARD_IMAGE =
            Icon.createWithContentUri("content://media/external/images/media");
    private static final int PRIMARY_USER_ID = 0;
    private static final int SECONDARY_USER_ID = 10;

    private final Drawable mTileIcon = mContext.getDrawable(R.drawable.ic_qs_wallet);
    private final Intent mWalletIntent = new Intent(QuickAccessWalletService.ACTION_VIEW_WALLET)
            .setComponent(new ComponentName(mContext.getPackageName(), "WalletActivity"));

    @Mock
    private QSHost mHost;
    @Mock
    private MetricsLogger mMetricsLogger;
    @Mock
    private StatusBarStateController mStatusBarStateController;
    @Mock
    private ActivityStarter mActivityStarter;
    @Mock
    private QSLogger mQSLogger;
    @Mock
    private QsEventLogger mUiEventLogger;
    @Mock
    private QuickAccessWalletClient mQuickAccessWalletClient;
    @Mock
    private KeyguardStateController mKeyguardStateController;
    @Mock
    private PackageManager mPackageManager;
    @Mock
    private SecureSettings mSecureSettings;
    @Mock
    private QuickAccessWalletController mController;
    @Mock
    private Icon mCardImage;
    @Captor
    ArgumentCaptor<QuickAccessWalletClient.OnWalletCardsRetrievedCallback> mCallbackCaptor;

    private Context mSpiedContext;
    private TestableLooper mTestableLooper;
    private QuickAccessWalletTile mTile;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        mTestableLooper = TestableLooper.get(this);
        mSpiedContext = spy(mContext);

        doNothing().when(mSpiedContext).startActivity(any(Intent.class));
        when(mHost.getContext()).thenReturn(mSpiedContext);
        when(mQuickAccessWalletClient.getServiceLabel()).thenReturn(LABEL);
        when(mQuickAccessWalletClient.getTileIcon()).thenReturn(mTileIcon);
        when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
        when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(true);
        when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(true);
        when(mController.getWalletClient()).thenReturn(mQuickAccessWalletClient);
        when(mCardImage.getType()).thenReturn(Icon.TYPE_URI);
        when(mCardImage.loadDrawableAsUser(any(), eq(SECONDARY_USER_ID))).thenReturn(null);

        mTile = new QuickAccessWalletTile(
                mHost,
                mUiEventLogger,
                mTestableLooper.getLooper(),
                new Handler(mTestableLooper.getLooper()),
                new FalsingManagerFake(),
                mMetricsLogger,
                mStatusBarStateController,
                mActivityStarter,
                mQSLogger,
                mKeyguardStateController,
                mPackageManager,
                mSecureSettings,
                mController);

        mTile.initialize();
        mTestableLooper.processAllMessages();
    }

    @After
    public void tearDown() {
        mTile.destroy();
        mTestableLooper.processAllMessages();
    }

    @Test
    public void testNewTile() {
        assertFalse(mTile.newTileState().handlesLongClick);
    }

    @Test
    public void testWalletServiceUnavailable_recreateWalletClient() {
        when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);

        mTile.handleSetListening(true);

        verify(mController, times(1)).reCreateWalletClient();
    }

    @Test
    public void testWalletFeatureUnavailable_recreateWalletClient() {
        when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(false);

        mTile.handleSetListening(true);

        verify(mController, times(1)).reCreateWalletClient();
    }

    @Test
    public void testIsAvailable_qawFeatureAvailableWalletUnavailable() {
        when(mController.isWalletRoleAvailable()).thenReturn(false);
        when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(true);
        when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
        when(mSecureSettings.getStringForUser(NFC_PAYMENT_DEFAULT_COMPONENT,
                UserHandle.USER_CURRENT)).thenReturn("Component");

        assertTrue(mTile.isAvailable());
    }

    @Test
    public void testIsAvailable_nfcUnavailableWalletAvailable() {
        when(mController.isWalletRoleAvailable()).thenReturn(true);
        when(mHost.getUserId()).thenReturn(PRIMARY_USER_ID);
        when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(false);
        when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);

        assertTrue(mTile.isAvailable());
    }

    @Test
    public void testHandleClick_startQuickAccessUiIntent_noCard() {
        setUpWalletCard(/* hasCard= */ false);

        mTile.handleClick(/* view= */ null);
        mTestableLooper.processAllMessages();

        verify(mController).startQuickAccessUiIntent(
                eq(mActivityStarter),
                eq(null),
                /* hasCard= */ eq(false));
    }

    @Test
    public void testHandleClick_startQuickAccessUiIntent_hasCard() {
        setUpWalletCard(/* hasCard= */ true);

        mTile.handleClick(null /* view */);
        mTestableLooper.processAllMessages();

        verify(mController).startQuickAccessUiIntent(
                eq(mActivityStarter),
                eq(null),
                /* hasCard= */ eq(true));
    }

    @Test
    public void testHandleUpdateState_updateLabelAndIcon() {
        QSTile.State state = new QSTile.State();

        mTile.handleUpdateState(state, null);

        assertEquals(LABEL, state.label.toString());
        assertTrue(state.label.toString().contentEquals(state.contentDescription));
        assertEquals(mTileIcon, state.icon.getDrawable(mContext));
    }

    @Test
    public void testHandleUpdateState_updateLabelAndIcon_noIconFromApi() {
        when(mQuickAccessWalletClient.getTileIcon()).thenReturn(null);
        QSTile.State state = new QSTile.State();
        QSTile.Icon icon = QSTileImpl.ResourceIcon.get(R.drawable.ic_wallet_lockscreen);

        mTile.handleUpdateState(state, null);

        assertEquals(LABEL, state.label.toString());
        assertTrue(state.label.toString().contentEquals(state.contentDescription));
        assertEquals(icon, state.icon);
    }

    @Test
    public void testGetTileLabel_serviceLabelExists() {
        assertEquals(LABEL, mTile.getTileLabel().toString());
    }

    @Test
    public void testGetTileLabel_serviceLabelDoesNotExist() {
        when(mQuickAccessWalletClient.getServiceLabel()).thenReturn(null);
        assertEquals(mContext.getString(R.string.wallet_title), mTile.getTileLabel().toString());
    }

    @Test
    public void testHandleUpdateState_walletIsUpdating() {
        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
        QSTile.State state = new QSTile.State();
        GetWalletCardsResponse response =
                new GetWalletCardsResponse(
                        Collections.singletonList(createWalletCard(mContext)), 0);

        mTile.handleSetListening(true);

        verify(mController).queryWalletCards(mCallbackCaptor.capture());

        // Wallet cards fetching on its way; wallet updating.
        mTile.handleUpdateState(state, null);

        assertEquals(Tile.STATE_INACTIVE, state.state);
        assertEquals(
                mContext.getString(R.string.wallet_secondary_label_updating), state.secondaryLabel);
        assertNotNull(state.stateDescription);
        assertNull(state.sideViewCustomDrawable);

        // Wallet cards fetching completed.
        mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
        mTestableLooper.processAllMessages();

        mTile.handleUpdateState(state, null);

        assertEquals(Tile.STATE_ACTIVE, state.state);
        assertEquals(CARD_DESCRIPTION, state.secondaryLabel);
        assertNotNull(state.stateDescription);
        assertNotNull(state.sideViewCustomDrawable);
    }

    @Test
    public void testHandleUpdateState_hasCard_deviceLocked_tileInactive() {
        when(mKeyguardStateController.isUnlocked()).thenReturn(false);
        QSTile.State state = new QSTile.State();
        setUpWalletCard(/* hasCard= */ true);

        mTile.handleUpdateState(state, null);

        assertEquals(Tile.STATE_INACTIVE, state.state);
        assertEquals(CARD_DESCRIPTION, state.secondaryLabel);
        assertNotNull(state.stateDescription);
        assertNotNull(state.sideViewCustomDrawable);
    }

    @Test
    public void testHandleUpdateState_hasCard_deviceUnlocked_tileActive() {
        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
        QSTile.State state = new QSTile.State();
        setUpWalletCard(/* hasCard= */ true);

        mTile.handleUpdateState(state, null);

        assertEquals(Tile.STATE_ACTIVE, state.state);
        assertEquals(CARD_DESCRIPTION, state.secondaryLabel);
        assertNotNull(state.stateDescription);
        assertNotNull(state.sideViewCustomDrawable);
    }


    @Test
    public void testHandleUpdateState_noCard_tileInactive() {
        QSTile.State state = new QSTile.State();
        setUpWalletCard(/* hasCard= */ false);

        mTile.handleUpdateState(state, null);

        assertEquals(Tile.STATE_INACTIVE, state.state);
        assertEquals(
                mContext.getString(R.string.wallet_secondary_label_no_card),
                state.secondaryLabel);
        assertNotNull(state.stateDescription);
        assertNull(state.sideViewCustomDrawable);
    }

    @Test
    public void testHandleUpdateState_qawServiceUnavailable_tileUnavailable() {
        when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
        QSTile.State state = new QSTile.State();

        mTile.handleUpdateState(state, null);

        assertEquals(Tile.STATE_UNAVAILABLE, state.state);
        assertNull(state.stateDescription);
        assertNull(state.sideViewCustomDrawable);
    }

    @Test
    public void testHandleUpdateState_qawFeatureUnavailable_tileUnavailable() {
        when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(false);
        QSTile.State state = new QSTile.State();

        mTile.handleUpdateState(state, null);

        assertEquals(Tile.STATE_UNAVAILABLE, state.state);
        assertNull(state.stateDescription);
        assertNull(state.sideViewCustomDrawable);
    }

    @Test
    public void testHandleSetListening_queryCards() {
        mTile.handleSetListening(true);

        verify(mController).queryWalletCards(mCallbackCaptor.capture());

        assertThat(mCallbackCaptor.getValue()).isInstanceOf(
                QuickAccessWalletClient.OnWalletCardsRetrievedCallback.class);
    }

    @Test
    public void testQueryCards_hasCards_updateSideViewDrawable() {
        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
        setUpWalletCard(/* hasCard= */ true);

        assertNotNull(mTile.getState().sideViewCustomDrawable);
    }

    @Test
    public void testQueryCards_notCurrentUser_hasCards_noSideViewDrawable() {
        when(mKeyguardStateController.isUnlocked()).thenReturn(true);

        PendingIntent pendingIntent =
                PendingIntent.getActivity(mContext, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
        WalletCard walletCard =
                new WalletCard.Builder(
                        CARD_ID, mCardImage, CARD_DESCRIPTION, pendingIntent).build();
        GetWalletCardsResponse response =
                new GetWalletCardsResponse(Collections.singletonList(walletCard), 0);

        mTile.handleSetListening(true);

        verify(mController).queryWalletCards(mCallbackCaptor.capture());

        mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
        mTestableLooper.processAllMessages();

        assertNull(mTile.getState().sideViewCustomDrawable);
    }

    @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);

        assertNull(mTile.getState().sideViewCustomDrawable);
    }

    @Test
    public void testQueryCards_invalidDrawable_noSideViewDrawable() {
        when(mKeyguardStateController.isUnlocked()).thenReturn(true);
        setUpInvalidWalletCard(/* hasCard= */ true);

        assertNull(mTile.getState().sideViewCustomDrawable);
    }

    @Test
    public void testQueryCards_error_notUpdateSideViewDrawable() {
        String errorMessage = "getWalletCardsError";
        GetWalletCardsError error = new GetWalletCardsError(CARD_IMAGE, errorMessage);

        mTile.handleSetListening(true);

        verify(mController).queryWalletCards(mCallbackCaptor.capture());

        mCallbackCaptor.getValue().onWalletCardRetrievalError(error);
        mTestableLooper.processAllMessages();

        assertNull(mTile.getState().sideViewCustomDrawable);
    }

    @Test
    public void testHandleSetListening_notListening_notQueryCards() {
        mTile.handleSetListening(false);

        verifyNoMoreInteractions(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(
                        hasCard
                                ? Collections.singletonList(createWalletCard(mContext))
                                : Collections.EMPTY_LIST, 0);

        mTile.handleSetListening(true);

        verify(mController).queryWalletCards(mCallbackCaptor.capture());

        mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
        mTestableLooper.processAllMessages();
    }

    private void setUpInvalidWalletCard(boolean hasCard) {
        GetWalletCardsResponse response =
                new GetWalletCardsResponse(
                        hasCard
                                ? Collections.singletonList(createInvalidWalletCard(mContext))
                                : Collections.EMPTY_LIST, 0);

        mTile.handleSetListening(true);

        verify(mController).queryWalletCards(mCallbackCaptor.capture());

        mCallbackCaptor.getValue().onWalletCardsRetrieved(response);
        mTestableLooper.processAllMessages();
    }

    private WalletCard createWalletCard(Context context) {
        PendingIntent pendingIntent =
                PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
        return new WalletCard.Builder(CARD_ID, CARD_IMAGE, CARD_DESCRIPTION, pendingIntent).build();
    }

    private WalletCard createInvalidWalletCard(Context context) {
        PendingIntent pendingIntent =
                PendingIntent.getActivity(context, 0, mWalletIntent, PendingIntent.FLAG_IMMUTABLE);
        return new WalletCard.Builder(
                CARD_ID, INVALID_CARD_IMAGE, CARD_DESCRIPTION, pendingIntent).build();
    }


}
Loading