1 /*
2  * Copyright (C) 2024 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.nfc.cardemulation;
18 
19 import static org.mockito.ArgumentMatchers.any;
20 import static org.mockito.ArgumentMatchers.anyInt;
21 import static org.mockito.ArgumentMatchers.eq;
22 import static org.mockito.Mockito.verify;
23 import static org.mockito.Mockito.verifyNoMoreInteractions;
24 import static org.mockito.Mockito.when;
25 
26 import android.app.ActivityManager;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.nfc.cardemulation.ApduServiceInfo;
30 import android.nfc.cardemulation.CardEmulation;
31 import android.os.UserHandle;
32 import android.os.UserManager;
33 import android.util.Pair;
34 
35 import androidx.test.ext.junit.runners.AndroidJUnit4;
36 
37 import com.android.dx.mockito.inline.extended.ExtendedMockito;
38 import com.android.nfc.NfcService;
39 
40 import org.junit.After;
41 import org.junit.Assert;
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.junit.runner.RunWith;
45 import org.mockito.ArgumentCaptor;
46 import org.mockito.Captor;
47 import org.mockito.Mock;
48 import org.mockito.Mockito;
49 import org.mockito.MockitoAnnotations;
50 import org.mockito.MockitoSession;
51 import org.mockito.quality.Strictness;
52 
53 import java.util.ArrayList;
54 import java.util.HashMap;
55 import java.util.List;
56 
57 @RunWith(AndroidJUnit4.class)
58 public class RegisteredAidCacheTest {
59 
60     private static final String PREFIX_AID = "ASDASD*";
61     private static final String SUBSET_AID = "ASDASD#";
62     private static final String EXACT_AID = "TASDASD";
63     private static final String PAYMENT_AID_1 = "A000000004101012";
64     private static final String PAYMENT_AID_2 = "A000000004101018";
65     private static final String NON_PAYMENT_AID_1 = "F053414950454D";
66     private static final String PREFIX_PAYMENT_AID = "A000000004*";
67     private static final String NFC_FOREGROUND_PACKAGE_NAME = "com.android.test.foregroundnfc";
68     private static final String NON_PAYMENT_NFC_PACKAGE_NAME = "com.android.test.nonpaymentnfc";
69     private static final String WALLET_HOLDER_PACKAGE_NAME = "com.android.test.walletroleholder";
70     private static final String WALLET_HOLDER_2_PACKAGE_NAME = "com.android.test.walletroleholder2";
71 
72     private static final ComponentName WALLET_PAYMENT_SERVICE
73             = new ComponentName(WALLET_HOLDER_PACKAGE_NAME,
74             "com.android.test.walletroleholder.WalletRoleHolderApduService");
75 
76     private static final ComponentName WALLET_PAYMENT_SERVICE_2
77             = new ComponentName(WALLET_HOLDER_PACKAGE_NAME,
78             "com.android.test.walletroleholder.XWalletRoleHolderApduService");
79     private static final ComponentName FOREGROUND_SERVICE
80             = new ComponentName(NFC_FOREGROUND_PACKAGE_NAME,
81             "com.android.test.foregroundnfc.ForegroundApduService");
82     private static final ComponentName NON_PAYMENT_SERVICE =
83             new ComponentName(NON_PAYMENT_NFC_PACKAGE_NAME,
84                     "com.android.test.nonpaymentnfc.NonPaymentApduService");
85 
86     private static final ComponentName PAYMENT_SERVICE =
87             new ComponentName(WALLET_HOLDER_2_PACKAGE_NAME,
88                     "com.android.test.walletroleholder.WalletRoleHolderXApduService");
89 
90     private static final int USER_ID = 0;
91     private static final UserHandle USER_HANDLE = UserHandle.of(USER_ID);
92 
93     @Mock
94     private Context mContext;
95     @Mock
96     private WalletRoleObserver mWalletRoleObserver;
97     @Mock
98     private AidRoutingManager mAidRoutingManager;
99     @Mock
100     private UserManager mUserManager;
101     @Mock
102     private NfcService mNfcService;
103     @Captor
104     private ArgumentCaptor<HashMap<String, AidRoutingManager.AidEntry>> mRoutingEntryMapCaptor;
105 
106     private MockitoSession mStaticMockSession;
107 
108     RegisteredAidCache mRegisteredAidCache;
109 
110     @Before
setUp()111     public void setUp() {
112         mStaticMockSession = ExtendedMockito.mockitoSession()
113                 .mockStatic(ActivityManager.class)
114                 .mockStatic(NfcService.class)
115                 .strictness(Strictness.LENIENT)
116                 .initMocks(this)
117                 .startMocking();
118         when(ActivityManager.getCurrentUser()).thenReturn(USER_ID);
119         when(NfcService.getInstance()).thenReturn(mNfcService);
120         when(mNfcService.getNciVersion()).thenReturn(NfcService.NCI_VERSION_1_0);
121         when(mUserManager.getProfileParent(eq(USER_HANDLE))).thenReturn(USER_HANDLE);
122         when(mContext.createContextAsUser(
123                 any(), anyInt())).thenReturn(mContext);
124         when(mContext.getSystemService(eq(UserManager.class))).thenReturn(mUserManager);
125     }
126 
127     @After
tearDown()128     public void tearDown() {
129         mStaticMockSession.finishMocking();
130     }
131 
132     @Test
testConstructor_supportsPrefixAndSubset()133     public void testConstructor_supportsPrefixAndSubset() {
134         supportPrefixAndSubset(true);
135         mRegisteredAidCache = new RegisteredAidCache(mContext, mWalletRoleObserver,
136                 mAidRoutingManager);
137 
138         verify(mAidRoutingManager).supportsAidPrefixRouting();
139         verify(mAidRoutingManager).supportsAidSubsetRouting();
140         Assert.assertTrue(mRegisteredAidCache.supportsAidPrefixRegistration());
141         Assert.assertTrue(mRegisteredAidCache.supportsAidSubsetRegistration());
142     }
143 
144     @Test
testConstructor_doesNotSupportsPrefixAndSubset()145     public void testConstructor_doesNotSupportsPrefixAndSubset() {
146         supportPrefixAndSubset(false);
147         mRegisteredAidCache = new RegisteredAidCache(mContext, mWalletRoleObserver,
148                 mAidRoutingManager);
149 
150         verify(mAidRoutingManager).supportsAidPrefixRouting();
151         verify(mAidRoutingManager).supportsAidSubsetRouting();
152         Assert.assertFalse(mRegisteredAidCache.supportsAidPrefixRegistration());
153         Assert.assertFalse(mRegisteredAidCache.supportsAidSubsetRegistration());
154     }
155 
156     @Test
testAidStaticMethods()157     public void testAidStaticMethods() {
158         Assert.assertTrue(RegisteredAidCache.isPrefix(PREFIX_AID));
159         Assert.assertTrue(RegisteredAidCache.isSubset(SUBSET_AID));
160         Assert.assertTrue(RegisteredAidCache.isExact(EXACT_AID));
161 
162         Assert.assertFalse(RegisteredAidCache.isPrefix(EXACT_AID));
163         Assert.assertFalse(RegisteredAidCache.isSubset(EXACT_AID));
164         Assert.assertFalse(RegisteredAidCache.isExact(PREFIX_AID));
165         Assert.assertFalse(RegisteredAidCache.isExact(SUBSET_AID));
166     }
167 
168     @Test
testAidConflictResolution_walletRoleEnabledNfcDisabled_foregroundWins()169     public void testAidConflictResolution_walletRoleEnabledNfcDisabled_foregroundWins() {
170         setWalletRoleFlag(true);
171         supportPrefixAndSubset(false);
172         mRegisteredAidCache = new RegisteredAidCache(mContext, mWalletRoleObserver,
173                 mAidRoutingManager);
174         mRegisteredAidCache.mNfcEnabled = false;
175 
176         List<ApduServiceInfo> apduServiceInfos = new ArrayList<>();
177         apduServiceInfos.add(createServiceInfoForAidRouting(
178                 WALLET_PAYMENT_SERVICE,
179                 true,
180                 List.of(PAYMENT_AID_1, NON_PAYMENT_AID_1),
181                 List.of(CardEmulation.CATEGORY_PAYMENT, CardEmulation.CATEGORY_OTHER),
182                 false,
183                 false,
184                 USER_ID,
185                 true));
186         apduServiceInfos.add(createServiceInfoForAidRouting(
187                 FOREGROUND_SERVICE,
188                 true,
189                 List.of(PAYMENT_AID_1, NON_PAYMENT_AID_1),
190                 List.of(CardEmulation.CATEGORY_PAYMENT, CardEmulation.CATEGORY_OTHER),
191                 false,
192                 false,
193                 USER_ID,
194                 true));
195         apduServiceInfos.add(createServiceInfoForAidRouting(
196                 NON_PAYMENT_SERVICE,
197                 true,
198                 List.of(NON_PAYMENT_AID_1),
199                 List.of(CardEmulation.CATEGORY_OTHER),
200                 false,
201                 false,
202                 USER_ID,
203                 true));
204 
205         mRegisteredAidCache.generateUserApduServiceInfoLocked(USER_ID, apduServiceInfos);
206         mRegisteredAidCache.generateServiceMapLocked(apduServiceInfos);
207         mRegisteredAidCache.onPreferredForegroundServiceChanged(USER_ID, FOREGROUND_SERVICE);
208         RegisteredAidCache.AidResolveInfo resolveInfo
209                 = mRegisteredAidCache.resolveAid(PAYMENT_AID_1);
210 
211         verify(mAidRoutingManager).supportsAidPrefixRouting();
212         verify(mAidRoutingManager).supportsAidSubsetRouting();
213         Assert.assertEquals(resolveInfo.defaultService.getComponent(), FOREGROUND_SERVICE);
214         Assert.assertEquals(mRegisteredAidCache.getPreferredService(),
215                 new Pair<>(USER_ID, FOREGROUND_SERVICE));
216         Assert.assertEquals(resolveInfo.services.size(), 1);
217         Assert.assertEquals(resolveInfo.category, CardEmulation.CATEGORY_PAYMENT);
218         verifyNoMoreInteractions(mAidRoutingManager);
219     }
220 
221     @Test
testAidConflictResolution_walletRoleEnabledNfcEnabled_walletWins()222     public void testAidConflictResolution_walletRoleEnabledNfcEnabled_walletWins() {
223         setWalletRoleFlag(true);
224         supportPrefixAndSubset(false);
225         mRegisteredAidCache = new RegisteredAidCache(mContext, mWalletRoleObserver,
226                 mAidRoutingManager);
227         mRegisteredAidCache.mNfcEnabled = true;
228 
229         List<ApduServiceInfo> apduServiceInfos = new ArrayList<>();
230         apduServiceInfos.add(createServiceInfoForAidRouting(
231                 WALLET_PAYMENT_SERVICE,
232                 true,
233                 List.of(PAYMENT_AID_1),
234                 List.of(CardEmulation.CATEGORY_PAYMENT),
235                 false,
236                 true,
237                 USER_ID,
238                 true));
239         apduServiceInfos.add(createServiceInfoForAidRouting(
240                 PAYMENT_SERVICE,
241                 true,
242                 List.of(PAYMENT_AID_1),
243                 List.of(CardEmulation.CATEGORY_PAYMENT),
244                 false,
245                 true,
246                 USER_ID,
247                 true));
248         apduServiceInfos.add(createServiceInfoForAidRouting(
249                 NON_PAYMENT_SERVICE,
250                 true,
251                 List.of(NON_PAYMENT_AID_1),
252                 List.of(CardEmulation.CATEGORY_OTHER),
253                 false,
254                 false,
255                 USER_ID,
256                 true));
257 
258         mRegisteredAidCache.generateUserApduServiceInfoLocked(USER_ID, apduServiceInfos);
259         mRegisteredAidCache.generateServiceMapLocked(apduServiceInfos);
260         mRegisteredAidCache.onWalletRoleHolderChanged(WALLET_HOLDER_PACKAGE_NAME, USER_ID);
261         RegisteredAidCache.AidResolveInfo paymentResolveInfo
262                 = mRegisteredAidCache.resolveAid(PAYMENT_AID_1);
263         RegisteredAidCache.AidResolveInfo nonPaymentResolveInfo
264                 = mRegisteredAidCache.resolveAid(NON_PAYMENT_AID_1);
265 
266         Assert.assertEquals(paymentResolveInfo.defaultService.getComponent(),
267                 WALLET_PAYMENT_SERVICE);
268         Assert.assertEquals(paymentResolveInfo.services.size(), 1);
269         Assert.assertEquals(paymentResolveInfo.category, CardEmulation.CATEGORY_PAYMENT);
270         Assert.assertEquals(nonPaymentResolveInfo.defaultService.getComponent(),
271                 NON_PAYMENT_SERVICE);
272         Assert.assertEquals(nonPaymentResolveInfo.services.size(), 1);
273         Assert.assertEquals(nonPaymentResolveInfo.category, CardEmulation.CATEGORY_OTHER);
274         verify(mAidRoutingManager).configureRouting(mRoutingEntryMapCaptor.capture(),
275                 eq(false));
276         HashMap<String, AidRoutingManager.AidEntry> routingEntries =
277                 mRoutingEntryMapCaptor.getValue();
278         Assert.assertTrue(routingEntries.containsKey(PAYMENT_AID_1));
279         Assert.assertTrue(routingEntries.containsKey(NON_PAYMENT_AID_1));
280         Assert.assertTrue(routingEntries.get(PAYMENT_AID_1).isOnHost);
281         Assert.assertTrue(routingEntries.get(NON_PAYMENT_AID_1).isOnHost);
282         Assert.assertNull(routingEntries.get(PAYMENT_AID_1).offHostSE);
283         Assert.assertNull(routingEntries.get(NON_PAYMENT_AID_1).offHostSE);
284         Assert.assertTrue(mRegisteredAidCache.isRequiresScreenOnServiceExist());
285     }
286 
287     @Test
testAidConflictResolution_walletRoleEnabledNfcEnabledPreFixAid_walletWins()288     public void testAidConflictResolution_walletRoleEnabledNfcEnabledPreFixAid_walletWins() {
289         setWalletRoleFlag(true);
290         supportPrefixAndSubset(true);
291         mRegisteredAidCache = new RegisteredAidCache(mContext, mWalletRoleObserver,
292                 mAidRoutingManager);
293         mRegisteredAidCache.mNfcEnabled = true;
294 
295         List<ApduServiceInfo> apduServiceInfos = new ArrayList<>();
296         apduServiceInfos.add(createServiceInfoForAidRouting(
297                 WALLET_PAYMENT_SERVICE,
298                 true,
299                 List.of(PREFIX_PAYMENT_AID),
300                 List.of(CardEmulation.CATEGORY_PAYMENT),
301                 false,
302                 true,
303                 USER_ID,
304                 true));
305         apduServiceInfos.add(createServiceInfoForAidRouting(
306                 PAYMENT_SERVICE,
307                 true,
308                 List.of(PAYMENT_AID_1),
309                 List.of(CardEmulation.CATEGORY_PAYMENT),
310                 false,
311                 true,
312                 USER_ID,
313                 true));
314         apduServiceInfos.add(createServiceInfoForAidRouting(
315                 NON_PAYMENT_SERVICE,
316                 true,
317                 List.of(NON_PAYMENT_AID_1),
318                 List.of(CardEmulation.CATEGORY_OTHER),
319                 false,
320                 false,
321                 USER_ID,
322                 true));
323 
324         mRegisteredAidCache.generateUserApduServiceInfoLocked(USER_ID, apduServiceInfos);
325         mRegisteredAidCache.generateServiceMapLocked(apduServiceInfos);
326         mRegisteredAidCache.onWalletRoleHolderChanged(WALLET_HOLDER_PACKAGE_NAME, USER_ID);
327         RegisteredAidCache.AidResolveInfo paymentResolveInfo
328                 = mRegisteredAidCache.resolveAid(PAYMENT_AID_1);
329         RegisteredAidCache.AidResolveInfo nonPaymentResolveInfo
330                 = mRegisteredAidCache.resolveAid(NON_PAYMENT_AID_1);
331 
332         Assert.assertEquals(paymentResolveInfo.defaultService.getComponent(),
333                 WALLET_PAYMENT_SERVICE);
334         Assert.assertEquals(paymentResolveInfo.services.size(), 1);
335         Assert.assertEquals(paymentResolveInfo.category, CardEmulation.CATEGORY_PAYMENT);
336         Assert.assertEquals(nonPaymentResolveInfo.defaultService.getComponent(),
337                 NON_PAYMENT_SERVICE);
338         Assert.assertEquals(nonPaymentResolveInfo.services.size(), 1);
339         Assert.assertEquals(nonPaymentResolveInfo.category, CardEmulation.CATEGORY_OTHER);
340     }
341 
342     @Test
testAidConflictResolution_walletRoleEnabled_twoServicesOnWallet_firstServiceWins()343     public void testAidConflictResolution_walletRoleEnabled_twoServicesOnWallet_firstServiceWins() {
344         setWalletRoleFlag(true);
345         supportPrefixAndSubset(false);
346         mRegisteredAidCache = new RegisteredAidCache(mContext, mWalletRoleObserver,
347                 mAidRoutingManager);
348 
349         List<ApduServiceInfo> apduServiceInfos = new ArrayList<>();
350         apduServiceInfos.add(createServiceInfoForAidRouting(
351                 WALLET_PAYMENT_SERVICE,
352                 true,
353                 List.of(PAYMENT_AID_1, NON_PAYMENT_AID_1),
354                 List.of(CardEmulation.CATEGORY_PAYMENT, CardEmulation.CATEGORY_OTHER),
355                 false,
356                 false,
357                 USER_ID,
358                 true));
359         apduServiceInfos.add(createServiceInfoForAidRouting(
360                 WALLET_PAYMENT_SERVICE_2,
361                 true,
362                 List.of(PAYMENT_AID_1),
363                 List.of(CardEmulation.CATEGORY_PAYMENT),
364                 false,
365                 false,
366                 USER_ID,
367                 true));
368         apduServiceInfos.add(createServiceInfoForAidRouting(
369                 PAYMENT_SERVICE,
370                 true,
371                 List.of(PAYMENT_AID_1),
372                 List.of(CardEmulation.CATEGORY_PAYMENT),
373                 false,
374                 false,
375                 USER_ID,
376                 true));
377 
378         mRegisteredAidCache.generateUserApduServiceInfoLocked(USER_ID, apduServiceInfos);
379         mRegisteredAidCache.generateServiceMapLocked(apduServiceInfos);
380         mRegisteredAidCache.onWalletRoleHolderChanged(WALLET_HOLDER_PACKAGE_NAME, USER_ID);
381         RegisteredAidCache.AidResolveInfo resolveInfo
382                 = mRegisteredAidCache.resolveAid(PAYMENT_AID_1);
383         Assert.assertEquals(resolveInfo.defaultService.getComponent(), WALLET_PAYMENT_SERVICE);
384         Assert.assertEquals(resolveInfo.services.size(), 2);
385         Assert.assertEquals(resolveInfo.category, CardEmulation.CATEGORY_PAYMENT);
386     }
387 
388     @Test
testOnServicesUpdated_walletRoleEnabled()389     public void testOnServicesUpdated_walletRoleEnabled() {
390         setWalletRoleFlag(true);
391         supportPrefixAndSubset(false);
392         mRegisteredAidCache = new RegisteredAidCache(mContext, mWalletRoleObserver,
393                 mAidRoutingManager);
394         mRegisteredAidCache.mNfcEnabled = true;
395 
396         List<ApduServiceInfo> apduServiceInfos = new ArrayList<>();
397         apduServiceInfos.add(createServiceInfoForAidRouting(
398                 WALLET_PAYMENT_SERVICE,
399                 true,
400                 List.of(PAYMENT_AID_1),
401                 List.of(CardEmulation.CATEGORY_PAYMENT),
402                 false,
403                 true,
404                 USER_ID,
405                 true));
406         apduServiceInfos.add(createServiceInfoForAidRouting(
407                 PAYMENT_SERVICE,
408                 true,
409                 List.of(PAYMENT_AID_1),
410                 List.of(CardEmulation.CATEGORY_PAYMENT),
411                 false,
412                 true,
413                 USER_ID,
414                 true));
415         apduServiceInfos.add(createServiceInfoForAidRouting(
416                 NON_PAYMENT_SERVICE,
417                 true,
418                 List.of(NON_PAYMENT_AID_1),
419                 List.of(CardEmulation.CATEGORY_OTHER),
420                 false,
421                 true,
422                 USER_ID,
423                 true));
424 
425         mRegisteredAidCache.onServicesUpdated(USER_ID, apduServiceInfos);
426 
427         verify(mAidRoutingManager).supportsAidPrefixRouting();
428         verify(mAidRoutingManager).supportsAidSubsetRouting();
429         Assert.assertTrue(mRegisteredAidCache.mAidServices.containsKey(PAYMENT_AID_1));
430         Assert.assertTrue(mRegisteredAidCache.mAidServices.containsKey(NON_PAYMENT_AID_1));
431         Assert.assertEquals(mRegisteredAidCache.mAidServices.get(PAYMENT_AID_1).size(), 2);
432         Assert.assertEquals(mRegisteredAidCache.mAidServices.get(NON_PAYMENT_AID_1).size(), 1);
433         Assert.assertEquals(mRegisteredAidCache.mAidServices.get(PAYMENT_AID_1).get(0)
434                 .service.getComponent(), WALLET_PAYMENT_SERVICE);
435         Assert.assertEquals(mRegisteredAidCache.mAidServices.get(PAYMENT_AID_1).get(1)
436                         .service.getComponent(), PAYMENT_SERVICE);
437         verify(mAidRoutingManager).configureRouting(mRoutingEntryMapCaptor.capture(),
438                 eq(false));
439         HashMap<String, AidRoutingManager.AidEntry> routingEntries =
440                 mRoutingEntryMapCaptor.getValue();
441         Assert.assertTrue(routingEntries.containsKey(NON_PAYMENT_AID_1));
442         Assert.assertTrue(routingEntries.get(NON_PAYMENT_AID_1).isOnHost);
443         Assert.assertNull(routingEntries.get(NON_PAYMENT_AID_1).offHostSE);
444         Assert.assertTrue(mRegisteredAidCache.isRequiresScreenOnServiceExist());
445     }
446 
447     @Test
testOnNfcEnabled()448     public void testOnNfcEnabled() {
449         setWalletRoleFlag(true);
450         supportPrefixAndSubset(false);
451         mRegisteredAidCache = new RegisteredAidCache(mContext, mWalletRoleObserver,
452                 mAidRoutingManager);
453 
454         List<ApduServiceInfo> apduServiceInfos = new ArrayList<>();
455         apduServiceInfos.add(createServiceInfoForAidRouting(
456                 WALLET_PAYMENT_SERVICE,
457                 true,
458                 List.of(PAYMENT_AID_1),
459                 List.of(CardEmulation.CATEGORY_PAYMENT),
460                 false,
461                 false,
462                 USER_ID,
463                 true));
464         apduServiceInfos.add(createServiceInfoForAidRouting(
465                 PAYMENT_SERVICE,
466                 true,
467                 List.of(PAYMENT_AID_1),
468                 List.of(CardEmulation.CATEGORY_PAYMENT),
469                 false,
470                 false,
471                 USER_ID,
472                 true));
473         apduServiceInfos.add(createServiceInfoForAidRouting(
474                 NON_PAYMENT_SERVICE,
475                 true,
476                 List.of(NON_PAYMENT_AID_1),
477                 List.of(CardEmulation.CATEGORY_OTHER),
478                 false,
479                 false,
480                 USER_ID,
481                 true));
482 
483         mRegisteredAidCache.generateUserApduServiceInfoLocked(USER_ID, apduServiceInfos);
484         mRegisteredAidCache.generateServiceMapLocked(apduServiceInfos);
485         mRegisteredAidCache.onNfcEnabled();
486 
487         verify(mAidRoutingManager).supportsAidPrefixRouting();
488         verify(mAidRoutingManager).supportsAidSubsetRouting();
489         verify(mAidRoutingManager).configureRouting(mRoutingEntryMapCaptor.capture(),
490                 eq(false));
491         Assert.assertFalse(mRegisteredAidCache.isRequiresScreenOnServiceExist());
492     }
493 
494     @Test
testOnNfcDisabled()495     public void testOnNfcDisabled() {
496         setWalletRoleFlag(true);
497         supportPrefixAndSubset(false);
498         mRegisteredAidCache = new RegisteredAidCache(mContext, mWalletRoleObserver,
499                 mAidRoutingManager);
500         mRegisteredAidCache.onNfcDisabled();
501 
502         verify(mAidRoutingManager).supportsAidPrefixRouting();
503         verify(mAidRoutingManager).supportsAidSubsetRouting();
504         verify(mAidRoutingManager).onNfccRoutingTableCleared();
505     }
506 
507     @Test
testPollingLoopFilterToForeground_walletRoleEnabled_walletSet()508     public void testPollingLoopFilterToForeground_walletRoleEnabled_walletSet() {
509         setWalletRoleFlag(true);
510         supportPrefixAndSubset(false);
511         mRegisteredAidCache = new RegisteredAidCache(mContext, mWalletRoleObserver,
512                 mAidRoutingManager);
513         mRegisteredAidCache.mNfcEnabled = true;
514 
515         List<ApduServiceInfo> apduServiceInfos = new ArrayList<>();
516         apduServiceInfos.add(createServiceInfoForAidRouting(
517                 WALLET_PAYMENT_SERVICE,
518                 true,
519                 List.of(PAYMENT_AID_1, NON_PAYMENT_AID_1),
520                 List.of(CardEmulation.CATEGORY_PAYMENT, CardEmulation.CATEGORY_OTHER),
521                 false,
522                 false,
523                 USER_ID,
524                 true));
525         apduServiceInfos.add(createServiceInfoForAidRouting(
526                 FOREGROUND_SERVICE,
527                 true,
528                 List.of(PAYMENT_AID_1, NON_PAYMENT_AID_1),
529                 List.of(CardEmulation.CATEGORY_PAYMENT, CardEmulation.CATEGORY_OTHER),
530                 false,
531                 false,
532                 USER_ID,
533                 true));
534         apduServiceInfos.add(createServiceInfoForAidRouting(
535                 NON_PAYMENT_SERVICE,
536                 true,
537                 List.of(NON_PAYMENT_AID_1),
538                 List.of(CardEmulation.CATEGORY_OTHER),
539                 false,
540                 false,
541                 USER_ID,
542                 true));
543 
544         mRegisteredAidCache.onWalletRoleHolderChanged(WALLET_HOLDER_PACKAGE_NAME, USER_ID);
545         mRegisteredAidCache.onPreferredForegroundServiceChanged(USER_ID, FOREGROUND_SERVICE);
546 
547         ApduServiceInfo resolvedApdu =
548                 mRegisteredAidCache.resolvePollingLoopFilterConflict(apduServiceInfos);
549 
550         Assert.assertEquals(resolvedApdu, apduServiceInfos.get(1));
551     }
552 
553     @Test
testPollingLoopFilterToWallet_walletRoleEnabled_walletSet()554     public void testPollingLoopFilterToWallet_walletRoleEnabled_walletSet() {
555         setWalletRoleFlag(true);
556         supportPrefixAndSubset(false);
557         mRegisteredAidCache = new RegisteredAidCache(mContext, mWalletRoleObserver,
558                 mAidRoutingManager);
559         mRegisteredAidCache.mNfcEnabled = true;
560 
561         List<ApduServiceInfo> apduServiceInfos = new ArrayList<>();
562         apduServiceInfos.add(createServiceInfoForAidRouting(
563                 WALLET_PAYMENT_SERVICE,
564                 true,
565                 List.of(PAYMENT_AID_1, NON_PAYMENT_AID_1),
566                 List.of(CardEmulation.CATEGORY_PAYMENT, CardEmulation.CATEGORY_OTHER),
567                 false,
568                 false,
569                 USER_ID,
570                 true));
571         apduServiceInfos.add(createServiceInfoForAidRouting(
572                 FOREGROUND_SERVICE,
573                 true,
574                 List.of(PAYMENT_AID_1, NON_PAYMENT_AID_1),
575                 List.of(CardEmulation.CATEGORY_PAYMENT, CardEmulation.CATEGORY_OTHER),
576                 false,
577                 false,
578                 USER_ID,
579                 true));
580         apduServiceInfos.add(createServiceInfoForAidRouting(
581                 NON_PAYMENT_SERVICE,
582                 true,
583                 List.of(NON_PAYMENT_AID_1),
584                 List.of(CardEmulation.CATEGORY_OTHER),
585                 false,
586                 false,
587                 USER_ID,
588                 true));
589 
590         mRegisteredAidCache.mDefaultWalletHolderPackageName = WALLET_HOLDER_PACKAGE_NAME;
591 
592         ApduServiceInfo resolvedApdu =
593                 mRegisteredAidCache.resolvePollingLoopFilterConflict(apduServiceInfos);
594 
595         Assert.assertEquals(resolvedApdu, apduServiceInfos.get(0));
596     }
597 
setWalletRoleFlag(boolean flag)598     private void setWalletRoleFlag(boolean flag) {
599         when(mWalletRoleObserver.isWalletRoleFeatureEnabled()).thenReturn(flag);
600     }
601 
supportPrefixAndSubset(boolean support)602     private void supportPrefixAndSubset(boolean support) {
603         when(mAidRoutingManager.supportsAidPrefixRouting()).thenReturn(support);
604         when(mAidRoutingManager.supportsAidSubsetRouting()).thenReturn(support);
605     }
606 
createServiceInfoForAidRouting(ComponentName componentName, boolean onHost, List<String> aids,List<String> categories, boolean requiresUnlock, boolean requiresScreenOn, int uid, boolean isCategoryOtherServiceEnabled)607     private static ApduServiceInfo createServiceInfoForAidRouting(ComponentName componentName,
608             boolean onHost,
609             List<String> aids,List<String> categories, boolean requiresUnlock, boolean requiresScreenOn,
610             int uid, boolean isCategoryOtherServiceEnabled) {
611         ApduServiceInfo apduServiceInfo = Mockito.mock(ApduServiceInfo.class);
612         when(apduServiceInfo.isOnHost()).thenReturn(onHost);
613         when(apduServiceInfo.getAids()).thenReturn(aids);
614         when(apduServiceInfo.getUid()).thenReturn(uid);
615         when(apduServiceInfo.requiresUnlock()).thenReturn(requiresUnlock);
616         when(apduServiceInfo.requiresScreenOn()).thenReturn(requiresScreenOn);
617         when(apduServiceInfo.isCategoryOtherServiceEnabled())
618                 .thenReturn(isCategoryOtherServiceEnabled);
619         when(apduServiceInfo.getComponent()).thenReturn(componentName);
620         for (int i = 0; i < aids.size(); i++) {
621             String aid = aids.get(i);
622             String category = categories.get(i);
623             when(apduServiceInfo.getCategoryForAid(eq(aid))).thenReturn(category);
624         }
625         return apduServiceInfo;
626     }
627 
628 }
629