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