1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.wallet.controller; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotSame; 22 import static org.junit.Assert.assertSame; 23 import static org.junit.Assert.assertTrue; 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.ArgumentMatchers.eq; 26 import static org.mockito.Mockito.doAnswer; 27 import static org.mockito.Mockito.never; 28 import static org.mockito.Mockito.verify; 29 import static org.mockito.Mockito.when; 30 31 import android.app.PendingIntent; 32 import android.app.role.RoleManager; 33 import android.content.Intent; 34 import android.service.quickaccesswallet.GetWalletCardsRequest; 35 import android.service.quickaccesswallet.QuickAccessWalletClient; 36 import android.testing.TestableLooper; 37 38 import androidx.test.ext.junit.runners.AndroidJUnit4; 39 import androidx.test.filters.SmallTest; 40 41 import com.android.systemui.SysuiTestCase; 42 import com.android.systemui.animation.ActivityTransitionAnimator; 43 import com.android.systemui.plugins.ActivityStarter; 44 import com.android.systemui.res.R; 45 import com.android.systemui.util.settings.SecureSettings; 46 import com.android.systemui.util.time.FakeSystemClock; 47 48 import com.google.common.util.concurrent.MoreExecutors; 49 50 import org.junit.Before; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 import org.mockito.ArgumentCaptor; 54 import org.mockito.Captor; 55 import org.mockito.Mock; 56 import org.mockito.MockitoAnnotations; 57 58 import java.util.List; 59 60 @RunWith(AndroidJUnit4.class) 61 @TestableLooper.RunWithLooper 62 @SmallTest 63 public class QuickAccessWalletControllerTest extends SysuiTestCase { 64 65 private static final String WALLET_ROLE_HOLDER = "wallet.role.holder"; 66 @Mock 67 private QuickAccessWalletClient mQuickAccessWalletClient; 68 @Mock 69 private SecureSettings mSecureSettings; 70 @Mock 71 private QuickAccessWalletClient.OnWalletCardsRetrievedCallback mCardsRetriever; 72 @Mock 73 private ActivityStarter mActivityStarter; 74 @Mock 75 private ActivityTransitionAnimator.Controller mAnimationController; 76 @Mock 77 private RoleManager mRoleManager; 78 @Captor 79 private ArgumentCaptor<GetWalletCardsRequest> mRequestCaptor; 80 @Captor 81 private ArgumentCaptor<Intent> mIntentCaptor; 82 @Captor 83 private ArgumentCaptor<PendingIntent> mPendingIntentCaptor; 84 85 private FakeSystemClock mClock = new FakeSystemClock(); 86 private QuickAccessWalletController mController; 87 88 @Before setUp()89 public void setUp() { 90 MockitoAnnotations.initMocks(this); 91 92 when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(true); 93 when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true); 94 when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(true); 95 mClock.setElapsedRealtime(100L); 96 97 doAnswer(invocation -> { 98 QuickAccessWalletClient.WalletPendingIntentCallback callback = 99 (QuickAccessWalletClient.WalletPendingIntentCallback) invocation 100 .getArguments()[1]; 101 callback.onWalletPendingIntentRetrieved(null); 102 return null; 103 }).when(mQuickAccessWalletClient).getWalletPendingIntent(any(), any()); 104 105 mController = new QuickAccessWalletController( 106 mContext, 107 MoreExecutors.directExecutor(), 108 MoreExecutors.directExecutor(), 109 mSecureSettings, 110 mQuickAccessWalletClient, 111 mClock, 112 mRoleManager); 113 } 114 115 @Test walletEnabled()116 public void walletEnabled() { 117 mController.updateWalletPreference(); 118 119 assertTrue(mController.isWalletEnabled()); 120 } 121 122 @Test walletRoleAvailable_isAvailable()123 public void walletRoleAvailable_isAvailable() { 124 when(mRoleManager.isRoleAvailable(eq(RoleManager.ROLE_WALLET))).thenReturn(true); 125 when(mRoleManager.getRoleHolders(eq(RoleManager.ROLE_WALLET))) 126 .thenReturn(List.of(WALLET_ROLE_HOLDER)); 127 128 assertTrue(mController.isWalletRoleAvailable()); 129 } 130 131 @Test walletRoleAvailable_isNotAvailable()132 public void walletRoleAvailable_isNotAvailable() { 133 when(mRoleManager.isRoleAvailable(eq(RoleManager.ROLE_WALLET))).thenReturn(false); 134 when(mRoleManager.getRoleHolders(eq(RoleManager.ROLE_WALLET))) 135 .thenReturn(List.of(WALLET_ROLE_HOLDER)); 136 137 assertFalse(mController.isWalletRoleAvailable()); 138 } 139 140 @Test walletServiceUnavailable_walletNotEnabled()141 public void walletServiceUnavailable_walletNotEnabled() { 142 when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false); 143 144 mController.updateWalletPreference(); 145 146 assertFalse(mController.isWalletEnabled()); 147 } 148 149 @Test walletFeatureUnavailable_walletNotEnabled()150 public void walletFeatureUnavailable_walletNotEnabled() { 151 when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(false); 152 153 mController.updateWalletPreference(); 154 155 assertFalse(mController.isWalletEnabled()); 156 } 157 158 @Test walletFeatureWhenLockedUnavailable_walletNotEnabled()159 public void walletFeatureWhenLockedUnavailable_walletNotEnabled() { 160 when(mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).thenReturn(false); 161 162 mController.updateWalletPreference(); 163 164 assertFalse(mController.isWalletEnabled()); 165 } 166 167 @Test getWalletClient_NoRecreation_sameClient()168 public void getWalletClient_NoRecreation_sameClient() { 169 assertSame(mQuickAccessWalletClient, mController.getWalletClient()); 170 } 171 172 @Test getWalletClient_reCreateClient_notSameClient()173 public void getWalletClient_reCreateClient_notSameClient() { 174 mController.reCreateWalletClient(); 175 176 assertNotSame(mQuickAccessWalletClient, mController.getWalletClient()); 177 } 178 179 @Test queryWalletCards_avoidStale_recreateClient()180 public void queryWalletCards_avoidStale_recreateClient() { 181 // advance current time by 100 seconds, should not recreate the client. 182 mClock.setElapsedRealtime(100100L); 183 184 mController.queryWalletCards(mCardsRetriever); 185 186 assertSame(mQuickAccessWalletClient, mController.getWalletClient()); 187 188 // advance current time by another 501 seconds, should recreate the client. 189 mClock.setElapsedRealtime(601100L); 190 191 mController.queryWalletCards(mCardsRetriever); 192 193 assertNotSame(mQuickAccessWalletClient, mController.getWalletClient()); 194 } 195 196 @Test queryWalletCards_walletEnabled_queryCards()197 public void queryWalletCards_walletEnabled_queryCards() { 198 mController.queryWalletCards(mCardsRetriever); 199 200 verify(mQuickAccessWalletClient) 201 .getWalletCards( 202 eq(MoreExecutors.directExecutor()), mRequestCaptor.capture(), 203 eq(mCardsRetriever)); 204 205 GetWalletCardsRequest request = mRequestCaptor.getValue(); 206 assertEquals(1, mRequestCaptor.getValue().getMaxCards()); 207 assertEquals( 208 mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width), 209 request.getCardWidthPx()); 210 assertEquals( 211 mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height), 212 request.getCardHeightPx()); 213 } 214 215 @Test queryWalletCards_walletEnabled_queryMultipleCards()216 public void queryWalletCards_walletEnabled_queryMultipleCards() { 217 mController.queryWalletCards(mCardsRetriever, 5); 218 219 verify(mQuickAccessWalletClient) 220 .getWalletCards( 221 eq(MoreExecutors.directExecutor()), mRequestCaptor.capture(), 222 eq(mCardsRetriever)); 223 224 GetWalletCardsRequest request = mRequestCaptor.getValue(); 225 assertEquals(5, mRequestCaptor.getValue().getMaxCards()); 226 assertEquals( 227 mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width), 228 request.getCardWidthPx()); 229 assertEquals( 230 mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height), 231 request.getCardHeightPx()); 232 } 233 234 @Test queryWalletCards_walletFeatureNotAvailable_noQuery()235 public void queryWalletCards_walletFeatureNotAvailable_noQuery() { 236 when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(false); 237 238 mController.queryWalletCards(mCardsRetriever); 239 240 verify(mQuickAccessWalletClient, never()).getWalletCards(any(), any(), any()); 241 } 242 243 @Test getQuickAccessUiIntent_hasCards_noPendingIntent_startsWalletActivity()244 public void getQuickAccessUiIntent_hasCards_noPendingIntent_startsWalletActivity() { 245 mController.startQuickAccessUiIntent(mActivityStarter, mAnimationController, true); 246 verify(mActivityStarter).startActivity(mIntentCaptor.capture(), eq(true), 247 any(ActivityTransitionAnimator.Controller.class), eq(true)); 248 Intent intent = mIntentCaptor.getValue(); 249 assertEquals(intent.getAction(), Intent.ACTION_VIEW); 250 assertEquals( 251 intent.getComponent().getClassName(), 252 "com.android.systemui.wallet.ui.WalletActivity"); 253 } 254 255 @Test getQuickAccessUiIntent_noCards_noPendingIntent_startsWalletActivity()256 public void getQuickAccessUiIntent_noCards_noPendingIntent_startsWalletActivity() { 257 mController.startQuickAccessUiIntent(mActivityStarter, mAnimationController, false); 258 verify(mActivityStarter).postStartActivityDismissingKeyguard(mIntentCaptor.capture(), eq(0), 259 any(ActivityTransitionAnimator.Controller.class)); 260 Intent intent = mIntentCaptor.getValue(); 261 assertEquals(intent.getAction(), Intent.ACTION_VIEW); 262 assertEquals( 263 intent.getComponent().getClassName(), 264 "com.android.systemui.wallet.ui.WalletActivity"); 265 } 266 267 @Test getQuickAccessUiIntent_targetActivityViaPendingIntent_intentComponentIsCorrect()268 public void getQuickAccessUiIntent_targetActivityViaPendingIntent_intentComponentIsCorrect() { 269 doAnswer(invocation -> { 270 QuickAccessWalletClient.WalletPendingIntentCallback callback = 271 (QuickAccessWalletClient.WalletPendingIntentCallback) invocation 272 .getArguments()[1]; 273 Intent intent = new Intent(Intent.ACTION_VIEW).setClassName( 274 "com.google.android.apps.testapp", 275 "com.google.android.apps.testapp.TestActivity"); 276 callback.onWalletPendingIntentRetrieved( 277 PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE)); 278 return null; 279 }).when(mQuickAccessWalletClient).getWalletPendingIntent(any(), any()); 280 mController.startQuickAccessUiIntent(mActivityStarter, mAnimationController, true); 281 verify(mActivityStarter).postStartActivityDismissingKeyguard(mPendingIntentCaptor.capture(), 282 any(ActivityTransitionAnimator.Controller.class)); 283 PendingIntent pendingIntent = mPendingIntentCaptor.getValue(); 284 Intent intent = pendingIntent.getIntent(); 285 assertEquals(intent.getAction(), Intent.ACTION_VIEW); 286 assertEquals( 287 intent.getComponent().getClassName(), 288 "com.google.android.apps.testapp.TestActivity"); 289 } 290 } 291