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.junit.Assert.assertNotNull; 20 import static org.junit.Assert.assertNull; 21 import static org.mockito.ArgumentMatchers.any; 22 import static org.mockito.ArgumentMatchers.anyBoolean; 23 import static org.mockito.ArgumentMatchers.anyInt; 24 import static org.mockito.ArgumentMatchers.argThat; 25 import static org.mockito.ArgumentMatchers.eq; 26 import static org.mockito.Mockito.times; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.verifyNoMoreInteractions; 29 import static org.mockito.Mockito.when; 30 31 import android.app.ActivityManager; 32 import android.content.BroadcastReceiver; 33 import android.content.ComponentName; 34 import android.content.Context; 35 import android.content.Intent; 36 import android.content.IntentFilter; 37 import android.content.pm.PackageManager; 38 import android.content.pm.ResolveInfo; 39 import android.content.pm.ServiceInfo; 40 import android.nfc.NfcAdapter; 41 import android.nfc.cardemulation.AidGroup; 42 import android.nfc.cardemulation.ApduServiceInfo; 43 import android.nfc.cardemulation.CardEmulation; 44 import android.nfc.cardemulation.HostApduService; 45 import android.nfc.cardemulation.OffHostApduService; 46 import android.os.UserHandle; 47 import android.os.UserManager; 48 import android.util.Pair; 49 50 import androidx.test.ext.junit.runners.AndroidJUnit4; 51 import androidx.test.platform.app.InstrumentationRegistry; 52 53 import com.android.dx.mockito.inline.extended.ExtendedMockito; 54 import com.android.nfc.NfcService; 55 import com.android.nfc.NfcStatsLog; 56 57 import org.junit.After; 58 import org.junit.Assert; 59 import org.junit.Before; 60 import org.junit.Test; 61 import org.junit.runner.RunWith; 62 import org.mockito.ArgumentCaptor; 63 import org.mockito.Captor; 64 import org.mockito.Mock; 65 import org.mockito.Mockito; 66 import org.mockito.MockitoAnnotations; 67 import org.mockito.MockitoSession; 68 import org.mockito.quality.Strictness; 69 import org.xmlpull.v1.XmlPullParserException; 70 71 import java.io.ByteArrayInputStream; 72 import java.io.ByteArrayOutputStream; 73 import java.io.File; 74 import java.io.FileNotFoundException; 75 import java.io.FileOutputStream; 76 import java.io.IOException; 77 import java.io.InputStream; 78 import java.util.ArrayList; 79 import java.util.HashMap; 80 import java.util.List; 81 import java.util.Map; 82 83 @RunWith(AndroidJUnit4.class) 84 public class RegisteredServicesCacheTest { 85 86 private static final int USER_ID = 1; 87 private static final int SERVICE_UID = 1; 88 private static final int SYSTEM_ID = 0; 89 private static final UserHandle USER_HANDLE = UserHandle.of(USER_ID); 90 private static final UserHandle SYSTEM_USER_HANDLE = UserHandle.of(SYSTEM_ID); 91 private static final UserHandle USER_HANDLE_QUITE_MODE = UserHandle.of(2); 92 private static final File DIR = new File("/"); 93 private static final String MOCK_FILE_PATH = "mockfile"; 94 private static final String MOCK_FILE_EXT = ".xml"; 95 private static final String ANOTHER_PACKAGE_NAME = "com.android.test.another"; 96 private static final String NON_PAYMENT_NFC_PACKAGE_NAME = "com.android.test.nonpaymentnfc"; 97 private static final String WALLET_HOLDER_PACKAGE_NAME = "com.android.test.walletroleholder"; 98 private static final String ON_HOST_SERVICE_NAME 99 = "com.android.test.walletroleholder.OnHostApduService"; 100 private static final String OFF_HOST_SERVICE_NAME 101 = "com.android.test.another.OffHostApduService"; 102 private static final String NON_PAYMENT_SERVICE_NAME 103 = "com.android.test.nonpaymentnfc.NonPaymentApduService"; 104 private static final ComponentName WALLET_HOLDER_SERVICE_COMPONENT = 105 new ComponentName(WALLET_HOLDER_PACKAGE_NAME, ON_HOST_SERVICE_NAME); 106 private static final ComponentName NON_PAYMENT_SERVICE_COMPONENT = 107 new ComponentName(NON_PAYMENT_NFC_PACKAGE_NAME, NON_PAYMENT_SERVICE_NAME); 108 private static final ComponentName ANOTHER_SERVICE_COMPONENT = 109 new ComponentName(ANOTHER_PACKAGE_NAME, OFF_HOST_SERVICE_NAME); 110 private static final String OFFHOST_SE_STRING = "offhostse"; 111 private static final String TRUE_STRING = "true"; 112 private static final String FALSE_STRING = "false"; 113 private static final String ANDROID_STRING = "android"; 114 private static final List<String> PAYMENT_AIDS = List.of("A000000004101011", 115 "A000000004101012", "A000000004101013"); 116 private static final List<String> NON_PAYMENT_AID = List.of("F053414950454D"); 117 118 @Mock 119 private Context mContext; 120 @Mock 121 private RegisteredServicesCache.Callback mCallback; 122 @Mock 123 private UserManager mUserManager; 124 @Mock 125 private PackageManager mPackageManager; 126 @Mock 127 private RegisteredServicesCache.SettingsFile mDynamicSettingsFile; 128 @Mock 129 private RegisteredServicesCache.SettingsFile mOtherSettingsFile; 130 @Mock 131 private RegisteredServicesCache.ServiceParser mServiceParser; 132 @Mock 133 private RoutingOptionManager mRoutingOptionManager; 134 @Captor 135 private ArgumentCaptor<BroadcastReceiver> mReceiverArgumentCaptor; 136 @Captor 137 private ArgumentCaptor<IntentFilter> mIntentFilterArgumentCaptor; 138 @Captor 139 private ArgumentCaptor<PackageManager.ResolveInfoFlags> mFlagArgumentCaptor; 140 @Captor 141 private ArgumentCaptor<Intent> mIntentArgumentCaptor; 142 @Captor 143 private ArgumentCaptor<List<ApduServiceInfo>> mApduServiceListCaptor; 144 @Captor 145 private ArgumentCaptor<FileOutputStream> fileOutputStreamArgumentCaptor; 146 147 private MockitoSession mStaticMockSession; 148 private RegisteredServicesCache mRegisteredServicesCache; 149 private Map<String, ApduServiceInfo> mMappedServices; 150 private File mMockFile = new File(MOCK_FILE_PATH + MOCK_FILE_EXT); 151 152 @Before setUp()153 public void setUp() throws PackageManager.NameNotFoundException, XmlPullParserException, 154 IOException { 155 mStaticMockSession = ExtendedMockito.mockitoSession() 156 .mockStatic(com.android.nfc.flags.Flags.class) 157 .mockStatic(ActivityManager.class) 158 .mockStatic(NfcStatsLog.class) 159 .mockStatic(UserHandle.class) 160 .mockStatic(NfcAdapter.class) 161 .mockStatic(NfcService.class) 162 .strictness(Strictness.LENIENT) 163 .startMocking(); 164 MockitoAnnotations.initMocks(this); 165 if (!mMockFile.exists()) { 166 mMockFile = File.createTempFile(MOCK_FILE_PATH, MOCK_FILE_EXT); 167 } 168 mMappedServices = new HashMap<>(); 169 when(UserHandle.getUserHandleForUid(eq(USER_ID))).thenReturn(USER_HANDLE); 170 when(UserHandle.getUserHandleForUid(eq(SYSTEM_ID))).thenReturn(SYSTEM_USER_HANDLE); 171 when(UserHandle.of(eq(SYSTEM_ID))).thenReturn(SYSTEM_USER_HANDLE); 172 when(UserHandle.of(eq(USER_ID))).thenReturn(USER_HANDLE); 173 when(ActivityManager.getCurrentUser()).thenReturn(USER_ID); 174 when(mContext.getSystemService(eq(UserManager.class))).thenReturn(mUserManager); 175 when(mContext.getFilesDir()).thenReturn(DIR); 176 when(mContext.createContextAsUser( 177 any(), anyInt())).thenReturn(mContext); 178 when(mContext.createPackageContextAsUser( 179 any(), anyInt(), any())).thenReturn(mContext); 180 when(mContext.getPackageManager()).thenReturn(mPackageManager); 181 List<UserHandle> enabledProfiles = new ArrayList<>(); 182 enabledProfiles.add(USER_HANDLE); 183 enabledProfiles.add(USER_HANDLE_QUITE_MODE); 184 when(mUserManager.getEnabledProfiles()).thenReturn(enabledProfiles); 185 when(mUserManager.isQuietModeEnabled(eq(USER_HANDLE))).thenReturn(false); 186 when(mUserManager.isQuietModeEnabled(eq(USER_HANDLE_QUITE_MODE))).thenReturn(true); 187 when(mUserManager.getProfileParent(eq(USER_HANDLE))).thenReturn(USER_HANDLE); 188 List<ResolveInfo> onHostServicesList = new ArrayList<>(); 189 onHostServicesList.add(createServiceResolveInfo(true, 190 WALLET_HOLDER_PACKAGE_NAME, ON_HOST_SERVICE_NAME, 191 List.of(CardEmulation.CATEGORY_PAYMENT))); 192 onHostServicesList.add(createServiceResolveInfo(false, 193 NON_PAYMENT_NFC_PACKAGE_NAME, NON_PAYMENT_SERVICE_NAME, 194 List.of(CardEmulation.CATEGORY_OTHER))); 195 List<ResolveInfo> offHostServicesList = new ArrayList<>(); 196 offHostServicesList.add(createServiceResolveInfo(true, ANOTHER_PACKAGE_NAME, 197 OFF_HOST_SERVICE_NAME, List.of(CardEmulation.CATEGORY_OTHER))); 198 when(mPackageManager.queryIntentServicesAsUser( 199 any(), any(), any())).thenAnswer(invocation -> { 200 Intent intent = invocation.getArgument(0); 201 if(intent.getAction().equals(OffHostApduService.SERVICE_INTERFACE)) { 202 return offHostServicesList; 203 } 204 if(intent.getAction().equals(HostApduService.SERVICE_INTERFACE)) { 205 return onHostServicesList; 206 } 207 return List.of(); 208 }); 209 when(mServiceParser.parseApduService(any(), any(), anyBoolean())) 210 .thenAnswer(invocation -> { 211 ResolveInfo resolveInfo = invocation.getArgument(1); 212 if(mMappedServices.containsKey(resolveInfo.serviceInfo.name)) { 213 return mMappedServices.get(resolveInfo.serviceInfo.name); 214 } 215 return null; 216 }); 217 } 218 219 @After tearDown()220 public void tearDown() { 221 mStaticMockSession.finishMocking(); 222 if (mMockFile.exists()) { 223 mMockFile.delete(); 224 } 225 } 226 227 // Intent filter registration is actually not happening. It's just a mock verification. 228 @SuppressWarnings({"UnspecifiedRegisterReceiverFlag", "GuardedBy"}) 229 @Test testConstructor()230 public void testConstructor() { 231 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 232 mRoutingOptionManager); 233 234 // Verify that the users handles are populated correctly 235 Assert.assertEquals(1, mRegisteredServicesCache.mUserHandles.size()); 236 Assert.assertEquals(mRegisteredServicesCache.mUserHandles.get(0), USER_HANDLE); 237 // Verify that broadcast receivers for apk changes are created and registered properly 238 assertNotNull(mRegisteredServicesCache.mReceiver.get()); 239 verify(mContext).createContextAsUser(eq(USER_HANDLE), eq(0)); 240 verify(mContext, times(2)).registerReceiverForAllUsers( 241 mReceiverArgumentCaptor.capture(), mIntentFilterArgumentCaptor.capture(), 242 eq(null), eq(null)); 243 IntentFilter packageInstallTrackerIntent = mIntentFilterArgumentCaptor 244 .getAllValues().get(0); 245 Assert.assertTrue(packageInstallTrackerIntent.hasAction(Intent.ACTION_PACKAGE_ADDED)); 246 Assert.assertTrue(packageInstallTrackerIntent.hasAction(Intent.ACTION_PACKAGE_CHANGED)); 247 Assert.assertTrue(packageInstallTrackerIntent.hasAction(Intent.ACTION_PACKAGE_REMOVED)); 248 Assert.assertTrue(packageInstallTrackerIntent.hasAction(Intent.ACTION_PACKAGE_REPLACED)); 249 Assert.assertTrue(packageInstallTrackerIntent 250 .hasAction(Intent.ACTION_PACKAGE_FIRST_LAUNCH)); 251 Assert.assertTrue(packageInstallTrackerIntent.hasAction(Intent.ACTION_PACKAGE_RESTARTED)); 252 Assert.assertTrue(packageInstallTrackerIntent 253 .hasDataScheme(RegisteredServicesCache.PACKAGE_DATA)); 254 IntentFilter sdCardIntentFilter = mIntentFilterArgumentCaptor.getAllValues().get(1); 255 Assert.assertTrue(sdCardIntentFilter 256 .hasAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE)); 257 Assert.assertTrue(sdCardIntentFilter 258 .hasAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)); 259 Assert.assertEquals(mRegisteredServicesCache.mReceiver.get(), 260 mReceiverArgumentCaptor.getAllValues().get(0)); 261 Assert.assertEquals(mRegisteredServicesCache.mReceiver.get(), 262 mReceiverArgumentCaptor.getAllValues().get(1)); 263 verify(mContext, times(2)).getFilesDir(); 264 // Verify that correct file setting directories are set 265 Assert.assertEquals(mRegisteredServicesCache.mDynamicSettingsFile.getBaseFile() 266 .getParentFile(), DIR); 267 Assert.assertEquals(mRegisteredServicesCache.mDynamicSettingsFile.getBaseFile() 268 .getAbsolutePath(), DIR + RegisteredServicesCache.AID_XML_PATH); 269 Assert.assertEquals(mRegisteredServicesCache.mOthersFile.getBaseFile().getParentFile(), 270 DIR); 271 Assert.assertEquals(mRegisteredServicesCache.mOthersFile.getBaseFile() 272 .getAbsolutePath(), DIR + RegisteredServicesCache.OTHER_STATUS_PATH); 273 } 274 275 @Test testInitialize_filesExist()276 public void testInitialize_filesExist() throws IOException, 277 PackageManager.NameNotFoundException { 278 InputStream dynamicSettingsIs = InstrumentationRegistry.getInstrumentation() 279 .getContext().getResources().getAssets() 280 .open(RegisteredServicesCache.AID_XML_PATH); 281 InputStream otherSettingsIs = InstrumentationRegistry.getInstrumentation() 282 .getContext().getResources().getAssets() 283 .open(RegisteredServicesCache.OTHER_STATUS_PATH); 284 when(mDynamicSettingsFile.openRead()).thenReturn(dynamicSettingsIs); 285 when(mOtherSettingsFile.openRead()).thenReturn(otherSettingsIs); 286 when(mDynamicSettingsFile.exists()).thenReturn(true); 287 when(mOtherSettingsFile.exists()).thenReturn(true); 288 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 289 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 290 291 mRegisteredServicesCache.initialize(); 292 293 // Verify that file operations are called 294 verify(mDynamicSettingsFile).exists(); 295 verify(mOtherSettingsFile).exists(); 296 verify(mDynamicSettingsFile).openRead(); 297 verify(mOtherSettingsFile).openRead(); 298 verifyNoMoreInteractions(mDynamicSettingsFile); 299 verifyNoMoreInteractions(mOtherSettingsFile); 300 // Verify that user services are read properly 301 Assert.assertEquals(1, mRegisteredServicesCache.mUserServices.size()); 302 RegisteredServicesCache.UserServices userServices 303 = mRegisteredServicesCache.mUserServices.get(USER_ID); 304 Assert.assertEquals(2, userServices.services.size()); 305 Assert.assertTrue(userServices.services.containsKey(WALLET_HOLDER_SERVICE_COMPONENT)); 306 Assert.assertTrue(userServices.services.containsKey(ANOTHER_SERVICE_COMPONENT)); 307 Assert.assertEquals(3, userServices.dynamicSettings.size()); 308 // Verify that dynamic settings are read properly 309 Assert.assertTrue(userServices.dynamicSettings 310 .containsKey(WALLET_HOLDER_SERVICE_COMPONENT)); 311 Assert.assertTrue(userServices.dynamicSettings.containsKey(NON_PAYMENT_SERVICE_COMPONENT)); 312 // Verify that dynamic settings are properly populated for each service in the xml 313 // Verify the details of service 1 314 RegisteredServicesCache.DynamicSettings walletHolderSettings = 315 userServices.dynamicSettings.get(WALLET_HOLDER_SERVICE_COMPONENT); 316 Assert.assertEquals(OFFHOST_SE_STRING+"1", walletHolderSettings.offHostSE); 317 Assert.assertEquals(1, walletHolderSettings.uid); 318 Assert.assertEquals(TRUE_STRING, walletHolderSettings.shouldDefaultToObserveModeStr); 319 Assert.assertTrue(walletHolderSettings.aidGroups 320 .containsKey(CardEmulation.CATEGORY_PAYMENT)); 321 Assert.assertTrue(walletHolderSettings.aidGroups.get(CardEmulation.CATEGORY_PAYMENT) 322 .getAids().containsAll(PAYMENT_AIDS)); 323 Assert.assertFalse(walletHolderSettings.aidGroups 324 .containsKey(CardEmulation.CATEGORY_OTHER)); 325 // Verify the details of service 2 326 RegisteredServicesCache.DynamicSettings nonPaymentSettings = 327 userServices.dynamicSettings.get(NON_PAYMENT_SERVICE_COMPONENT); 328 Assert.assertEquals(OFFHOST_SE_STRING+"2", nonPaymentSettings.offHostSE); 329 Assert.assertEquals(1, nonPaymentSettings.uid); 330 Assert.assertEquals(FALSE_STRING, nonPaymentSettings.shouldDefaultToObserveModeStr); 331 Assert.assertTrue(nonPaymentSettings.aidGroups 332 .containsKey(CardEmulation.CATEGORY_OTHER)); 333 Assert.assertTrue(nonPaymentSettings.aidGroups.get(CardEmulation.CATEGORY_OTHER) 334 .getAids().containsAll(NON_PAYMENT_AID)); 335 // Verify that other settings are read properly 336 Assert.assertEquals(1, userServices.others.size()); 337 Assert.assertTrue(userServices.others.containsKey(ANOTHER_SERVICE_COMPONENT)); 338 RegisteredServicesCache.OtherServiceStatus otherServiceStatus 339 = userServices.others.get(ANOTHER_SERVICE_COMPONENT); 340 Assert.assertTrue(otherServiceStatus.checked); 341 Assert.assertEquals(1, otherServiceStatus.uid); 342 // Verify that the installed services are populated properly 343 verify(mContext) 344 .createPackageContextAsUser(eq(ANDROID_STRING), eq(0), eq(USER_HANDLE)); 345 verify(mContext).getPackageManager(); 346 verify(mPackageManager, times(2)) 347 .queryIntentServicesAsUser(mIntentArgumentCaptor.capture(), 348 mFlagArgumentCaptor.capture(), eq(USER_HANDLE)); 349 Intent onHostIntent = mIntentArgumentCaptor.getAllValues().get(0); 350 Assert.assertEquals(HostApduService.SERVICE_INTERFACE, onHostIntent.getAction()); 351 Intent offHostIntent = mIntentArgumentCaptor.getAllValues().get(1); 352 Assert.assertEquals(OffHostApduService.SERVICE_INTERFACE, offHostIntent.getAction()); 353 PackageManager.ResolveInfoFlags onHostFlag = mFlagArgumentCaptor.getAllValues().get(0); 354 Assert.assertEquals(PackageManager.GET_META_DATA, onHostFlag.getValue()); 355 PackageManager.ResolveInfoFlags offHostFlag = mFlagArgumentCaptor.getAllValues().get(1); 356 Assert.assertEquals(PackageManager.GET_META_DATA, offHostFlag.getValue()); 357 // Verify that the installed services are filtered properly 358 verify(mPackageManager).checkPermission(eq(android.Manifest.permission.NFC), 359 eq(WALLET_HOLDER_PACKAGE_NAME)); 360 verify(mPackageManager).checkPermission(eq(android.Manifest.permission.NFC), 361 eq(NON_PAYMENT_NFC_PACKAGE_NAME)); 362 verify(mPackageManager).checkPermission(eq(android.Manifest.permission.NFC), 363 eq(ANOTHER_PACKAGE_NAME)); 364 // Verify that the callback is called with properly installed and filtered services. 365 verify(mCallback).onServicesUpdated(eq(USER_ID), mApduServiceListCaptor.capture(), 366 eq(false)); 367 List<ApduServiceInfo> apduServiceInfos = mApduServiceListCaptor.getValue(); 368 Assert.assertEquals(2, apduServiceInfos.size()); 369 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, apduServiceInfos.get(0) 370 .getComponent()); 371 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, apduServiceInfos.get(1).getComponent()); 372 } 373 374 @Test testInitialize_filesDontExist()375 public void testInitialize_filesDontExist() throws IOException { 376 MockFileOutputStream mockFileOutputStream = new MockFileOutputStream(); 377 when(mDynamicSettingsFile.exists()).thenReturn(false); 378 when(mOtherSettingsFile.exists()).thenReturn(false); 379 when(mOtherSettingsFile.startWrite()).thenReturn(mockFileOutputStream); 380 381 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 382 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 383 mRegisteredServicesCache.initialize(); 384 385 // Verify that files are NOT read 386 verify(mDynamicSettingsFile).exists(); 387 verifyNoMoreInteractions(mDynamicSettingsFile); 388 verify(mOtherSettingsFile).exists(); 389 verify(mOtherSettingsFile).startWrite(); 390 verify(mOtherSettingsFile).finishWrite(fileOutputStreamArgumentCaptor.capture()); 391 verifyNoMoreInteractions(mOtherSettingsFile); 392 // Validate that no dynamic settings are read 393 Assert.assertEquals(1, mRegisteredServicesCache.mUserServices.size()); 394 RegisteredServicesCache.UserServices userServices 395 = mRegisteredServicesCache.mUserServices.get(USER_ID); 396 Assert.assertTrue(userServices.dynamicSettings.isEmpty()); 397 // Verify that other settings are only read from system services 398 Assert.assertEquals(1, userServices.others.size()); 399 Assert.assertTrue(userServices.others.containsKey(ANOTHER_SERVICE_COMPONENT)); 400 RegisteredServicesCache.OtherServiceStatus otherServiceStatus 401 = userServices.others.get(ANOTHER_SERVICE_COMPONENT); 402 Assert.assertTrue(otherServiceStatus.checked); 403 Assert.assertEquals(USER_ID, otherServiceStatus.uid); 404 // Verify that the callback is called with properly installed and filtered services. 405 verify(mCallback).onServicesUpdated(eq(USER_ID), mApduServiceListCaptor.capture(), 406 eq(false)); 407 List<ApduServiceInfo> apduServiceInfos = mApduServiceListCaptor.getValue(); 408 Assert.assertEquals(2, apduServiceInfos.size()); 409 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, apduServiceInfos.get(0) 410 .getComponent()); 411 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, apduServiceInfos.get(1).getComponent()); 412 // Validate that other setting file is written properly with a setting 413 // that previously did not exists. 414 InputStream otherSettingsIs = mockFileOutputStream.toInputStream(); 415 RegisteredServicesCache.SettingsFile otherSettingsFile 416 = Mockito.mock(RegisteredServicesCache.SettingsFile.class); 417 when(otherSettingsFile.openRead()).thenReturn(otherSettingsIs); 418 when(otherSettingsFile.exists()).thenReturn(true); 419 Map<Integer, List<Pair<ComponentName, RegisteredServicesCache.OtherServiceStatus>>> 420 readOtherSettingsFromFile = RegisteredServicesCache 421 .readOtherFromFile(otherSettingsFile); 422 Assert.assertEquals(mockFileOutputStream, fileOutputStreamArgumentCaptor.getValue()); 423 Assert.assertTrue(readOtherSettingsFromFile.containsKey(USER_ID)); 424 Assert.assertFalse(readOtherSettingsFromFile.get(USER_ID).isEmpty()); 425 Assert.assertEquals(readOtherSettingsFromFile.get(USER_ID).get(0).first, 426 ANOTHER_SERVICE_COMPONENT); 427 Assert.assertTrue(readOtherSettingsFromFile.get(USER_ID).get(0).second.checked); 428 } 429 430 @SuppressWarnings("GuardedBy") 431 @Test testOnUserSwitched()432 public void testOnUserSwitched() { 433 List<UserHandle> enabledProfiles = new ArrayList<>(); 434 // Do not trigger user switch in constructor. Send empty list. 435 when(mUserManager.getEnabledProfiles()).thenReturn(enabledProfiles); 436 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 437 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 438 enabledProfiles.add(USER_HANDLE); 439 enabledProfiles.add(USER_HANDLE_QUITE_MODE); 440 when(mUserManager.getEnabledProfiles()).thenReturn(enabledProfiles); 441 442 mRegisteredServicesCache.onUserSwitched(); 443 444 // Validate that quite mode profiles get filtered out. 445 Assert.assertEquals(1, mRegisteredServicesCache.mUserHandles.size()); 446 Assert.assertEquals(mRegisteredServicesCache.mUserHandles.get(0), USER_HANDLE); 447 } 448 449 @SuppressWarnings("GuardedBy") 450 @Test testOnManagedProfileChanged()451 public void testOnManagedProfileChanged() { 452 List<UserHandle> enabledProfiles = new ArrayList<>(); 453 // Do not trigger user switch in constructor. Send empty list. 454 when(mUserManager.getEnabledProfiles()).thenReturn(enabledProfiles); 455 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 456 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 457 enabledProfiles.add(USER_HANDLE); 458 enabledProfiles.add(USER_HANDLE_QUITE_MODE); 459 when(mUserManager.getEnabledProfiles()).thenReturn(enabledProfiles); 460 461 mRegisteredServicesCache.onManagedProfileChanged(); 462 463 // Validate that quite mode profiles get filtered out. 464 Assert.assertEquals(1, mRegisteredServicesCache.mUserHandles.size()); 465 Assert.assertEquals(mRegisteredServicesCache.mUserHandles.get(0), USER_HANDLE); 466 } 467 468 @Test testHasService()469 public void testHasService() { 470 when(mDynamicSettingsFile.exists()).thenReturn(false); 471 when(mOtherSettingsFile.exists()).thenReturn(false); 472 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 473 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 474 mRegisteredServicesCache.initialize(); 475 476 Assert.assertTrue(mRegisteredServicesCache.hasService(USER_ID, ANOTHER_SERVICE_COMPONENT)); 477 Assert.assertTrue(mRegisteredServicesCache.hasService(USER_ID, 478 WALLET_HOLDER_SERVICE_COMPONENT)); 479 } 480 481 @Test testGetService()482 public void testGetService() { 483 when(mDynamicSettingsFile.exists()).thenReturn(false); 484 when(mOtherSettingsFile.exists()).thenReturn(false); 485 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 486 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 487 mRegisteredServicesCache.initialize(); 488 489 ApduServiceInfo serviceInfo = mRegisteredServicesCache.getService(USER_ID, 490 WALLET_HOLDER_SERVICE_COMPONENT); 491 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, serviceInfo.getComponent()); 492 Assert.assertEquals(SERVICE_UID, serviceInfo.getUid()); 493 } 494 495 @Test testGetServices()496 public void testGetServices() { 497 when(mDynamicSettingsFile.exists()).thenReturn(false); 498 when(mOtherSettingsFile.exists()).thenReturn(false); 499 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 500 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 501 mRegisteredServicesCache.initialize(); 502 503 List<ApduServiceInfo> serviceInfos = mRegisteredServicesCache.getServices(USER_ID); 504 Assert.assertFalse(serviceInfos.isEmpty()); 505 Assert.assertEquals(2, serviceInfos.size()); 506 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, serviceInfos.get(0).getComponent()); 507 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, serviceInfos.get(1).getComponent()); 508 } 509 510 @Test testGetServicesForCategory_paymentCategory()511 public void testGetServicesForCategory_paymentCategory() { 512 when(mDynamicSettingsFile.exists()).thenReturn(false); 513 when(mOtherSettingsFile.exists()).thenReturn(false); 514 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 515 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 516 mRegisteredServicesCache.initialize(); 517 518 List<ApduServiceInfo> serviceInfos = mRegisteredServicesCache 519 .getServicesForCategory(USER_ID, CardEmulation.CATEGORY_PAYMENT); 520 Assert.assertFalse(serviceInfos.isEmpty()); 521 Assert.assertEquals(1, serviceInfos.size()); 522 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, serviceInfos.get(0).getComponent()); 523 } 524 525 @Test testGetServicesForCategory_otherCategory()526 public void testGetServicesForCategory_otherCategory() { 527 when(mDynamicSettingsFile.exists()).thenReturn(false); 528 when(mOtherSettingsFile.exists()).thenReturn(false); 529 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 530 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 531 mRegisteredServicesCache.initialize(); 532 533 List<ApduServiceInfo> serviceInfos = mRegisteredServicesCache 534 .getServicesForCategory(USER_ID, CardEmulation.CATEGORY_OTHER); 535 Assert.assertFalse(serviceInfos.isEmpty()); 536 Assert.assertEquals(1, serviceInfos.size()); 537 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, serviceInfos.get(0).getComponent()); 538 } 539 540 @Test testSetOffhostSecureElement_nonExistingService()541 public void testSetOffhostSecureElement_nonExistingService() { 542 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 543 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 544 mRegisteredServicesCache.initialize(); 545 ComponentName wrongComponentName = new ComponentName("test","com.wrong.class"); 546 547 Assert.assertFalse(mRegisteredServicesCache.setOffHostSecureElement(USER_ID, 548 SERVICE_UID, wrongComponentName, "offhostse1")); 549 } 550 551 @Test testSetOffhostSecureElement_wrongServiceUid()552 public void testSetOffhostSecureElement_wrongServiceUid() { 553 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 554 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 555 mRegisteredServicesCache.initialize(); 556 557 Assert.assertFalse(mRegisteredServicesCache.setOffHostSecureElement(USER_ID, 558 3, WALLET_HOLDER_SERVICE_COMPONENT, "offhostse1")); 559 } 560 561 @Test testSetOffhostSecureElement_nullOffHostSet()562 public void testSetOffhostSecureElement_nullOffHostSet() { 563 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 564 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 565 mRegisteredServicesCache.initialize(); 566 567 Assert.assertFalse(mRegisteredServicesCache.setOffHostSecureElement(USER_ID, 568 SERVICE_UID, WALLET_HOLDER_SERVICE_COMPONENT, null)); 569 } 570 571 @Test testSetOffhostSecureElement_existingService_correctUid_nonNullSE()572 public void testSetOffhostSecureElement_existingService_correctUid_nonNullSE() 573 throws IOException { 574 InputStream dynamicSettingsIs = InstrumentationRegistry.getInstrumentation() 575 .getContext().getResources().getAssets() 576 .open(RegisteredServicesCache.AID_XML_PATH); 577 MockFileOutputStream mockFileOutputStream = new MockFileOutputStream(); 578 when(mDynamicSettingsFile.exists()).thenReturn(true); 579 when(mDynamicSettingsFile.openRead()).thenReturn(dynamicSettingsIs); 580 when(mOtherSettingsFile.exists()).thenReturn(false); 581 when(mDynamicSettingsFile.startWrite()).thenReturn(mockFileOutputStream); 582 when(mOtherSettingsFile.startWrite()).thenReturn(new MockFileOutputStream()); 583 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 584 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 585 mRegisteredServicesCache.initialize(); 586 String newOffHostValue = "newOffhostValue"; 587 588 Assert.assertTrue(mRegisteredServicesCache.setOffHostSecureElement(USER_ID, 589 SERVICE_UID, WALLET_HOLDER_SERVICE_COMPONENT, newOffHostValue)); 590 verify(mDynamicSettingsFile).exists(); 591 verify(mDynamicSettingsFile).openRead(); 592 verify(mDynamicSettingsFile).startWrite(); 593 verify(mDynamicSettingsFile).finishWrite(fileOutputStreamArgumentCaptor.capture()); 594 verifyNoMoreInteractions(mDynamicSettingsFile); 595 Assert.assertEquals(mockFileOutputStream, fileOutputStreamArgumentCaptor.getValue()); 596 // Verify that the callback is called with properly installed and filtered services. 597 verify(mCallback).onServicesUpdated(eq(USER_ID), mApduServiceListCaptor.capture(), 598 eq(true)); 599 List<ApduServiceInfo> apduServiceInfos = mApduServiceListCaptor.getValue(); 600 Assert.assertEquals(2, apduServiceInfos.size()); 601 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, apduServiceInfos.get(0) 602 .getComponent()); 603 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, apduServiceInfos.get(1) 604 .getComponent()); 605 verify(apduServiceInfos.get(1)).setOffHostSecureElement(eq(newOffHostValue)); 606 // Verify that dynamic settings file is updated 607 InputStream dynamicSettingsMockIs = mockFileOutputStream.toInputStream(); 608 RegisteredServicesCache.SettingsFile dynamicSettingsFile 609 = Mockito.mock(RegisteredServicesCache.SettingsFile.class); 610 when(dynamicSettingsFile.openRead()).thenReturn(dynamicSettingsMockIs); 611 when(dynamicSettingsFile.exists()).thenReturn(true); 612 Map<Integer, List<Pair<ComponentName, RegisteredServicesCache.DynamicSettings>>> 613 readDynamicSettingsFromFile = RegisteredServicesCache 614 .readDynamicSettingsFromFile(dynamicSettingsFile); 615 Assert.assertFalse(readDynamicSettingsFromFile.isEmpty()); 616 Assert.assertTrue(readDynamicSettingsFromFile.containsKey(USER_ID)); 617 RegisteredServicesCache.DynamicSettings dynamicSettings 618 = readDynamicSettingsFromFile.get(USER_ID).get(1).second; 619 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, 620 readDynamicSettingsFromFile.get(USER_ID).get(1).first); 621 Assert.assertEquals(newOffHostValue, dynamicSettings.offHostSE); 622 } 623 624 @Test testResetOffhostSecureElement_nonExistingService()625 public void testResetOffhostSecureElement_nonExistingService() { 626 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 627 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 628 mRegisteredServicesCache.initialize(); 629 ComponentName wrongComponentName = new ComponentName("test","com.wrong.class"); 630 631 Assert.assertFalse(mRegisteredServicesCache.resetOffHostSecureElement(USER_ID, 632 SERVICE_UID, wrongComponentName)); 633 } 634 635 @Test testResetOffhostSecureElement_wrongServiceUid()636 public void testResetOffhostSecureElement_wrongServiceUid() { 637 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 638 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 639 mRegisteredServicesCache.initialize(); 640 641 Assert.assertFalse(mRegisteredServicesCache.resetOffHostSecureElement(USER_ID, 642 3, WALLET_HOLDER_SERVICE_COMPONENT)); 643 } 644 645 @Test testResetOffhostSecureElement_nullOffHostSet()646 public void testResetOffhostSecureElement_nullOffHostSet() { 647 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 648 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 649 mRegisteredServicesCache.initialize(); 650 651 Assert.assertFalse(mRegisteredServicesCache.resetOffHostSecureElement(USER_ID, 652 SERVICE_UID, WALLET_HOLDER_SERVICE_COMPONENT)); 653 } 654 655 @Test testResetOffhostSecureElement_existingService_correctUid()656 public void testResetOffhostSecureElement_existingService_correctUid() 657 throws IOException { 658 InputStream dynamicSettingsIs = InstrumentationRegistry.getInstrumentation() 659 .getContext().getResources().getAssets() 660 .open(RegisteredServicesCache.AID_XML_PATH); 661 MockFileOutputStream mockFileOutputStream = new MockFileOutputStream(); 662 when(mDynamicSettingsFile.exists()).thenReturn(true); 663 when(mDynamicSettingsFile.openRead()).thenReturn(dynamicSettingsIs); 664 when(mOtherSettingsFile.exists()).thenReturn(false); 665 when(mDynamicSettingsFile.startWrite()).thenReturn(mockFileOutputStream); 666 when(mOtherSettingsFile.startWrite()).thenReturn(new MockFileOutputStream()); 667 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 668 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 669 mRegisteredServicesCache.initialize(); 670 when(mRegisteredServicesCache.getService(USER_ID, ANOTHER_SERVICE_COMPONENT) 671 .getOffHostSecureElement()).thenReturn("offhost"); 672 673 Assert.assertTrue(mRegisteredServicesCache.resetOffHostSecureElement(USER_ID, 674 SERVICE_UID, ANOTHER_SERVICE_COMPONENT)); 675 verify(mDynamicSettingsFile).exists(); 676 verify(mDynamicSettingsFile).openRead(); 677 verify(mDynamicSettingsFile).startWrite(); 678 verify(mDynamicSettingsFile).finishWrite(fileOutputStreamArgumentCaptor.capture()); 679 verifyNoMoreInteractions(mDynamicSettingsFile); 680 Assert.assertEquals(mockFileOutputStream, fileOutputStreamArgumentCaptor.getValue()); 681 // Verify that the callback is called with properly installed and filtered services. 682 verify(mCallback).onServicesUpdated(eq(USER_ID), mApduServiceListCaptor.capture(), 683 eq(true)); 684 List<ApduServiceInfo> apduServiceInfos = mApduServiceListCaptor.getValue(); 685 Assert.assertEquals(2, apduServiceInfos.size()); 686 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, apduServiceInfos.get(0) 687 .getComponent()); 688 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, apduServiceInfos.get(1) 689 .getComponent()); 690 verify(apduServiceInfos.get(0)).resetOffHostSecureElement(); 691 // Verify that dynamic settings file is updated 692 InputStream dynamicSettingsMockIs = mockFileOutputStream.toInputStream(); 693 RegisteredServicesCache.SettingsFile dynamicSettingsFile 694 = Mockito.mock(RegisteredServicesCache.SettingsFile.class); 695 when(dynamicSettingsFile.openRead()).thenReturn(dynamicSettingsMockIs); 696 when(dynamicSettingsFile.exists()).thenReturn(true); 697 Map<Integer, List<Pair<ComponentName, RegisteredServicesCache.DynamicSettings>>> 698 readDynamicSettingsFromFile = RegisteredServicesCache 699 .readDynamicSettingsFromFile(dynamicSettingsFile); 700 Assert.assertFalse(readDynamicSettingsFromFile.isEmpty()); 701 Assert.assertTrue(readDynamicSettingsFromFile.containsKey(USER_ID)); 702 RegisteredServicesCache.DynamicSettings dynamicSettings 703 = readDynamicSettingsFromFile.get(USER_ID).get(0).second; 704 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, 705 readDynamicSettingsFromFile.get(USER_ID).get(0).first); 706 assertNull(dynamicSettings.offHostSE); 707 } 708 709 @Test testSetShouldDefaultToObserveModeForService_nonExistingService()710 public void testSetShouldDefaultToObserveModeForService_nonExistingService() { 711 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 712 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 713 mRegisteredServicesCache.initialize(); 714 ComponentName wrongComponentName = new ComponentName("test","com.wrong.class"); 715 716 Assert.assertFalse(mRegisteredServicesCache.setShouldDefaultToObserveModeForService(USER_ID, 717 SERVICE_UID, wrongComponentName, true)); 718 } 719 720 @Test testSetShouldDefaultToObserveModeForService_wrongServiceUid()721 public void testSetShouldDefaultToObserveModeForService_wrongServiceUid() { 722 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 723 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 724 mRegisteredServicesCache.initialize(); 725 726 Assert.assertFalse(mRegisteredServicesCache.setShouldDefaultToObserveModeForService(USER_ID, 727 3, WALLET_HOLDER_SERVICE_COMPONENT, true)); 728 } 729 730 @Test testSetShouldDefaultToObserveModeForService_existingService_correctUid()731 public void testSetShouldDefaultToObserveModeForService_existingService_correctUid() 732 throws IOException { 733 InputStream dynamicSettingsIs = InstrumentationRegistry.getInstrumentation() 734 .getContext().getResources().getAssets() 735 .open(RegisteredServicesCache.AID_XML_PATH); 736 when(mDynamicSettingsFile.exists()).thenReturn(true); 737 when(mDynamicSettingsFile.openRead()).thenReturn(dynamicSettingsIs); 738 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 739 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 740 mRegisteredServicesCache.initialize(); 741 742 Assert.assertTrue(mRegisteredServicesCache.setShouldDefaultToObserveModeForService(USER_ID, 743 SERVICE_UID, WALLET_HOLDER_SERVICE_COMPONENT, true)); 744 Assert.assertEquals("true", mRegisteredServicesCache.mUserServices.get(USER_ID) 745 .dynamicSettings.get(WALLET_HOLDER_SERVICE_COMPONENT) 746 .shouldDefaultToObserveModeStr); 747 verify(mRegisteredServicesCache.getService(USER_ID, WALLET_HOLDER_SERVICE_COMPONENT), 748 times(2)).setShouldDefaultToObserveMode(eq(true)); 749 } 750 751 @Test testRegisterPollingLoopFilterForService_nonExistingService()752 public void testRegisterPollingLoopFilterForService_nonExistingService() { 753 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 754 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 755 mRegisteredServicesCache.initialize(); 756 ComponentName wrongComponentName = new ComponentName("test","com.wrong.class"); 757 758 Assert.assertFalse(mRegisteredServicesCache.registerPollingLoopFilterForService(USER_ID, 759 SERVICE_UID, wrongComponentName, "empty", true)); 760 } 761 762 @Test testRegisterPollingLoopFilterForService_wrongUid()763 public void testRegisterPollingLoopFilterForService_wrongUid() { 764 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 765 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 766 mRegisteredServicesCache.initialize(); 767 768 Assert.assertFalse(mRegisteredServicesCache.registerPollingLoopFilterForService(USER_ID, 769 3, WALLET_HOLDER_SERVICE_COMPONENT, "empty", true)); 770 } 771 772 @Test testRegisterPollingLoopFilterForService_existingService_correctUid()773 public void testRegisterPollingLoopFilterForService_existingService_correctUid() { 774 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 775 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 776 mRegisteredServicesCache.initialize(); 777 String plFilter = "afilter"; 778 779 Assert.assertTrue(mRegisteredServicesCache.registerPollingLoopFilterForService(USER_ID, 780 SERVICE_UID, WALLET_HOLDER_SERVICE_COMPONENT, plFilter, true)); 781 // Verify that the callback is called with properly installed and filtered services. 782 verify(mCallback).onServicesUpdated(eq(USER_ID), mApduServiceListCaptor.capture(), 783 eq(true)); 784 List<ApduServiceInfo> apduServiceInfos = mApduServiceListCaptor.getValue(); 785 Assert.assertEquals(2, apduServiceInfos.size()); 786 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, apduServiceInfos.get(0) 787 .getComponent()); 788 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, apduServiceInfos.get(1) 789 .getComponent()); 790 verify(apduServiceInfos.get(1)).addPollingLoopFilter(eq(plFilter), eq(true)); 791 } 792 793 @Test testRemovePollingLoopFilterForService_nonExistingService()794 public void testRemovePollingLoopFilterForService_nonExistingService() { 795 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 796 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 797 mRegisteredServicesCache.initialize(); 798 ComponentName wrongComponentName = new ComponentName("test","com.wrong.class"); 799 800 Assert.assertFalse(mRegisteredServicesCache.removePollingLoopFilterForService(USER_ID, 801 SERVICE_UID, wrongComponentName, "empty")); 802 } 803 804 @Test testRemovePollingLoopFilterForService_wrongUid()805 public void testRemovePollingLoopFilterForService_wrongUid() { 806 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 807 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 808 mRegisteredServicesCache.initialize(); 809 810 Assert.assertFalse(mRegisteredServicesCache.removePollingLoopFilterForService(USER_ID, 811 3, WALLET_HOLDER_SERVICE_COMPONENT, "empty")); 812 } 813 814 @Test testRemovePollingLoopFilterForService_existingService_correctUid()815 public void testRemovePollingLoopFilterForService_existingService_correctUid() { 816 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 817 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 818 mRegisteredServicesCache.initialize(); 819 String plFilter = "afilter"; 820 821 Assert.assertTrue(mRegisteredServicesCache.removePollingLoopFilterForService(USER_ID, 822 SERVICE_UID, WALLET_HOLDER_SERVICE_COMPONENT, plFilter)); 823 // Verify that the callback is called with properly installed and filtered services. 824 verify(mCallback).onServicesUpdated(eq(USER_ID), mApduServiceListCaptor.capture(), 825 eq(true)); 826 List<ApduServiceInfo> apduServiceInfos = mApduServiceListCaptor.getValue(); 827 Assert.assertEquals(2, apduServiceInfos.size()); 828 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, apduServiceInfos.get(0) 829 .getComponent()); 830 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, apduServiceInfos.get(1) 831 .getComponent()); 832 verify(apduServiceInfos.get(1)).removePollingLoopFilter(eq(plFilter)); 833 } 834 835 @Test testRegisterPollingLoopPatternFilterForService_nonExistingService()836 public void testRegisterPollingLoopPatternFilterForService_nonExistingService() { 837 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 838 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 839 mRegisteredServicesCache.initialize(); 840 ComponentName wrongComponentName = new ComponentName("test","com.wrong.class"); 841 842 Assert.assertFalse(mRegisteredServicesCache.registerPollingLoopPatternFilterForService( 843 USER_ID, SERVICE_UID, wrongComponentName, "empty", 844 true)); 845 } 846 847 @Test testRegisterPollingLoopPatterFilterForService_wrongUid()848 public void testRegisterPollingLoopPatterFilterForService_wrongUid() { 849 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 850 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 851 mRegisteredServicesCache.initialize(); 852 853 Assert.assertFalse(mRegisteredServicesCache 854 .registerPollingLoopPatternFilterForService(USER_ID, 3, 855 WALLET_HOLDER_SERVICE_COMPONENT, "empty", true)); 856 } 857 858 @Test testRegisterPollingLoopPatternFilterForService_existingService_correctUid()859 public void testRegisterPollingLoopPatternFilterForService_existingService_correctUid() { 860 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 861 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 862 mRegisteredServicesCache.initialize(); 863 String plFilter = "afilter"; 864 865 Assert.assertTrue(mRegisteredServicesCache.registerPollingLoopPatternFilterForService( 866 USER_ID, SERVICE_UID, WALLET_HOLDER_SERVICE_COMPONENT, plFilter, true)); 867 // Verify that the callback is called with properly installed and filtered services. 868 verify(mCallback).onServicesUpdated(eq(USER_ID), mApduServiceListCaptor.capture(), 869 eq(true)); 870 List<ApduServiceInfo> apduServiceInfos = mApduServiceListCaptor.getValue(); 871 Assert.assertEquals(2, apduServiceInfos.size()); 872 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, apduServiceInfos.get(0) 873 .getComponent()); 874 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, apduServiceInfos.get(1) 875 .getComponent()); 876 verify(apduServiceInfos.get(1)).addPollingLoopPatternFilter(eq(plFilter), eq(true)); 877 } 878 879 @Test testRemovePollingLoopPatternFilterForService_nonExistingService()880 public void testRemovePollingLoopPatternFilterForService_nonExistingService() { 881 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 882 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 883 mRegisteredServicesCache.initialize(); 884 ComponentName wrongComponentName = new ComponentName("test","com.wrong.class"); 885 886 Assert.assertFalse(mRegisteredServicesCache.removePollingLoopPatternFilterForService( 887 USER_ID, SERVICE_UID, wrongComponentName, "empty")); 888 } 889 890 @Test testRemovePollingLoopPatternFilterForService_wrongUid()891 public void testRemovePollingLoopPatternFilterForService_wrongUid() { 892 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 893 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 894 mRegisteredServicesCache.initialize(); 895 896 Assert.assertFalse(mRegisteredServicesCache.removePollingLoopFilterForService(USER_ID, 897 3, WALLET_HOLDER_SERVICE_COMPONENT, "empty")); 898 } 899 900 @Test testRemovePollingLoopPatternFilterForService_existingService_correctUid()901 public void testRemovePollingLoopPatternFilterForService_existingService_correctUid() { 902 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 903 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 904 mRegisteredServicesCache.initialize(); 905 String plFilter = "afilter"; 906 907 Assert.assertTrue(mRegisteredServicesCache.removePollingLoopPatternFilterForService(USER_ID, 908 SERVICE_UID, WALLET_HOLDER_SERVICE_COMPONENT, plFilter)); 909 // Verify that the callback is called with properly installed and filtered services. 910 verify(mCallback).onServicesUpdated(eq(USER_ID), mApduServiceListCaptor.capture(), 911 eq(true)); 912 List<ApduServiceInfo> apduServiceInfos = mApduServiceListCaptor.getValue(); 913 Assert.assertEquals(2, apduServiceInfos.size()); 914 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, apduServiceInfos.get(0) 915 .getComponent()); 916 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, apduServiceInfos.get(1) 917 .getComponent()); 918 verify(apduServiceInfos.get(1)).removePollingLoopPatternFilter(eq(plFilter)); 919 } 920 921 @Test testRegisterAidGroupForService_nonExistingService()922 public void testRegisterAidGroupForService_nonExistingService() { 923 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 924 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 925 mRegisteredServicesCache.initialize(); 926 ComponentName wrongComponentName = new ComponentName("test","com.wrong.class"); 927 AidGroup aidGroup = createAidGroup(CardEmulation.CATEGORY_PAYMENT); 928 929 Assert.assertFalse(mRegisteredServicesCache.registerAidGroupForService( 930 USER_ID, SERVICE_UID, wrongComponentName, aidGroup)); 931 } 932 933 @Test testRegisterAidGroupForService_wrongUid()934 public void testRegisterAidGroupForService_wrongUid() { 935 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 936 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 937 mRegisteredServicesCache.initialize(); 938 AidGroup aidGroup = createAidGroup(CardEmulation.CATEGORY_PAYMENT); 939 940 Assert.assertFalse(mRegisteredServicesCache.registerAidGroupForService(USER_ID, 941 3, WALLET_HOLDER_SERVICE_COMPONENT, aidGroup)); 942 } 943 944 @Test testRegisterAidGroupForService_existingService_correctUid()945 public void testRegisterAidGroupForService_existingService_correctUid() throws IOException { 946 InputStream dynamicSettingsIs = InstrumentationRegistry.getInstrumentation() 947 .getContext().getResources().getAssets() 948 .open(RegisteredServicesCache.AID_XML_PATH); 949 MockFileOutputStream mockFileOutputStream = new MockFileOutputStream(); 950 when(mDynamicSettingsFile.exists()).thenReturn(true); 951 when(mDynamicSettingsFile.openRead()).thenReturn(dynamicSettingsIs); 952 when(mOtherSettingsFile.exists()).thenReturn(false); 953 when(mDynamicSettingsFile.startWrite()).thenReturn(mockFileOutputStream); 954 when(mOtherSettingsFile.startWrite()).thenReturn(new MockFileOutputStream()); 955 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 956 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 957 mRegisteredServicesCache.initialize(); 958 AidGroup aidGroup = createAidGroup(CardEmulation.CATEGORY_OTHER); 959 960 Assert.assertTrue(mRegisteredServicesCache.registerAidGroupForService(USER_ID, 961 SERVICE_UID, WALLET_HOLDER_SERVICE_COMPONENT, aidGroup)); 962 963 ApduServiceInfo serviceInfo = mRegisteredServicesCache.getService(USER_ID, 964 WALLET_HOLDER_SERVICE_COMPONENT); 965 verify(serviceInfo).setDynamicAidGroup(eq(aidGroup)); 966 Assert.assertEquals(aidGroup, mRegisteredServicesCache.mUserServices.get(USER_ID) 967 .dynamicSettings.get(WALLET_HOLDER_SERVICE_COMPONENT) 968 .aidGroups.get(CardEmulation.CATEGORY_OTHER)); 969 // Verify that the callback is called with properly installed and filtered services. 970 verify(mCallback).onServicesUpdated(eq(USER_ID), mApduServiceListCaptor.capture(), 971 eq(true)); 972 List<ApduServiceInfo> apduServiceInfos = mApduServiceListCaptor.getValue(); 973 Assert.assertEquals(2, apduServiceInfos.size()); 974 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, apduServiceInfos.get(0) 975 .getComponent()); 976 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, apduServiceInfos.get(1) 977 .getComponent()); 978 // Verify that dynamic settings file is updated 979 InputStream dynamicSettingsMockIs = mockFileOutputStream.toInputStream(); 980 RegisteredServicesCache.SettingsFile dynamicSettingsFile 981 = Mockito.mock(RegisteredServicesCache.SettingsFile.class); 982 when(dynamicSettingsFile.openRead()).thenReturn(dynamicSettingsMockIs); 983 when(dynamicSettingsFile.exists()).thenReturn(true); 984 Map<Integer, List<Pair<ComponentName, RegisteredServicesCache.DynamicSettings>>> 985 readDynamicSettingsFromFile = RegisteredServicesCache 986 .readDynamicSettingsFromFile(dynamicSettingsFile); 987 Assert.assertFalse(readDynamicSettingsFromFile.isEmpty()); 988 Assert.assertTrue(readDynamicSettingsFromFile.containsKey(USER_ID)); 989 RegisteredServicesCache.DynamicSettings dynamicSettings 990 = readDynamicSettingsFromFile.get(USER_ID).get(0).second; 991 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, 992 readDynamicSettingsFromFile.get(USER_ID).get(0).first); 993 Assert.assertTrue(dynamicSettings.aidGroups.containsKey(CardEmulation.CATEGORY_OTHER)); 994 Assert.assertEquals(aidGroup.getAids(), 995 dynamicSettings.aidGroups.get(CardEmulation.CATEGORY_OTHER).getAids()); 996 } 997 998 @Test testGetAidGroupForService_nonExistingService()999 public void testGetAidGroupForService_nonExistingService() { 1000 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 1001 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 1002 mRegisteredServicesCache.initialize(); 1003 ComponentName wrongComponentName = new ComponentName("test","com.wrong.class"); 1004 1005 assertNull(mRegisteredServicesCache.getAidGroupForService( 1006 USER_ID, SERVICE_UID, wrongComponentName, CardEmulation.CATEGORY_PAYMENT)); 1007 } 1008 1009 @Test testGetAidGroupForService_wrongUid()1010 public void testGetAidGroupForService_wrongUid() { 1011 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 1012 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 1013 mRegisteredServicesCache.initialize(); 1014 1015 assertNull(mRegisteredServicesCache.getAidGroupForService(USER_ID, 1016 3, WALLET_HOLDER_SERVICE_COMPONENT, CardEmulation.CATEGORY_PAYMENT)); 1017 } 1018 1019 @Test testGetAidGroupForService_existingService_correctUid()1020 public void testGetAidGroupForService_existingService_correctUid() { 1021 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 1022 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 1023 mRegisteredServicesCache.initialize(); 1024 ApduServiceInfo serviceInfo = mRegisteredServicesCache.getService(USER_ID, 1025 WALLET_HOLDER_SERVICE_COMPONENT); 1026 AidGroup aidGroup = createAidGroup(CardEmulation.CATEGORY_OTHER); 1027 when(serviceInfo.getDynamicAidGroupForCategory(eq(CardEmulation.CATEGORY_OTHER))) 1028 .thenReturn(aidGroup); 1029 1030 AidGroup aidGroupReceived = mRegisteredServicesCache.getAidGroupForService(USER_ID, 1031 SERVICE_UID, WALLET_HOLDER_SERVICE_COMPONENT, CardEmulation.CATEGORY_OTHER); 1032 Assert.assertEquals(aidGroup, aidGroupReceived); 1033 } 1034 1035 @Test testRemoveAidGroupForService_nonExistingService()1036 public void testRemoveAidGroupForService_nonExistingService() { 1037 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 1038 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 1039 mRegisteredServicesCache.initialize(); 1040 ComponentName wrongComponentName = new ComponentName("test","com.wrong.class"); 1041 1042 Assert.assertFalse(mRegisteredServicesCache.removeAidGroupForService( 1043 USER_ID, SERVICE_UID, wrongComponentName, CardEmulation.CATEGORY_PAYMENT)); 1044 } 1045 1046 @Test testRemoveAidGroupForService_wrongUid()1047 public void testRemoveAidGroupForService_wrongUid() { 1048 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 1049 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 1050 mRegisteredServicesCache.initialize(); 1051 1052 Assert.assertFalse(mRegisteredServicesCache.removeAidGroupForService(USER_ID, 1053 3, WALLET_HOLDER_SERVICE_COMPONENT, CardEmulation.CATEGORY_PAYMENT)); 1054 } 1055 1056 @Test testRemoveAidGroupForService_existingService_correctUid()1057 public void testRemoveAidGroupForService_existingService_correctUid() throws IOException { 1058 InputStream dynamicSettingsIs = InstrumentationRegistry.getInstrumentation() 1059 .getContext().getResources().getAssets() 1060 .open(RegisteredServicesCache.AID_XML_PATH); 1061 MockFileOutputStream mockFileOutputStream = new MockFileOutputStream(); 1062 when(mDynamicSettingsFile.exists()).thenReturn(true); 1063 when(mDynamicSettingsFile.openRead()).thenReturn(dynamicSettingsIs); 1064 when(mOtherSettingsFile.exists()).thenReturn(false); 1065 when(mDynamicSettingsFile.startWrite()).thenReturn(mockFileOutputStream); 1066 when(mOtherSettingsFile.startWrite()).thenReturn(new MockFileOutputStream()); 1067 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 1068 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 1069 mRegisteredServicesCache.initialize(); 1070 ApduServiceInfo serviceInfo = mRegisteredServicesCache.getService(USER_ID, 1071 WALLET_HOLDER_SERVICE_COMPONENT); 1072 when(serviceInfo.removeDynamicAidGroupForCategory(eq(CardEmulation.CATEGORY_PAYMENT))) 1073 .thenReturn(true); 1074 1075 Assert.assertTrue(mRegisteredServicesCache.removeAidGroupForService(USER_ID, 1076 SERVICE_UID, WALLET_HOLDER_SERVICE_COMPONENT, CardEmulation.CATEGORY_PAYMENT)); 1077 1078 verify(serviceInfo).removeDynamicAidGroupForCategory(eq(CardEmulation.CATEGORY_PAYMENT)); 1079 Assert.assertFalse(mRegisteredServicesCache.mUserServices.get(USER_ID) 1080 .dynamicSettings.get(WALLET_HOLDER_SERVICE_COMPONENT) 1081 .aidGroups.containsKey(CardEmulation.CATEGORY_PAYMENT)); 1082 // Verify that the callback is called with properly installed and filtered services. 1083 verify(mCallback).onServicesUpdated(eq(USER_ID), mApduServiceListCaptor.capture(), 1084 eq(true)); 1085 List<ApduServiceInfo> apduServiceInfos = mApduServiceListCaptor.getValue(); 1086 Assert.assertEquals(2, apduServiceInfos.size()); 1087 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, apduServiceInfos.get(0) 1088 .getComponent()); 1089 Assert.assertEquals(WALLET_HOLDER_SERVICE_COMPONENT, apduServiceInfos.get(1) 1090 .getComponent()); 1091 // Verify that dynamic settings file is updated 1092 InputStream dynamicSettingsMockIs = mockFileOutputStream.toInputStream(); 1093 RegisteredServicesCache.SettingsFile dynamicSettingsFile 1094 = Mockito.mock(RegisteredServicesCache.SettingsFile.class); 1095 when(dynamicSettingsFile.openRead()).thenReturn(dynamicSettingsMockIs); 1096 when(dynamicSettingsFile.exists()).thenReturn(true); 1097 Map<Integer, List<Pair<ComponentName, RegisteredServicesCache.DynamicSettings>>> 1098 readDynamicSettingsFromFile = RegisteredServicesCache 1099 .readDynamicSettingsFromFile(dynamicSettingsFile); 1100 Assert.assertFalse(readDynamicSettingsFromFile.isEmpty()); 1101 Assert.assertTrue(readDynamicSettingsFromFile.containsKey(USER_ID)); 1102 RegisteredServicesCache.DynamicSettings dynamicSettings 1103 = readDynamicSettingsFromFile.get(USER_ID).get(0).second; 1104 Assert.assertEquals(ANOTHER_SERVICE_COMPONENT, 1105 readDynamicSettingsFromFile.get(USER_ID).get(0).first); 1106 Assert.assertFalse(dynamicSettings.aidGroups.containsKey(CardEmulation.CATEGORY_PAYMENT)); 1107 } 1108 @Test testHandlePackageRemoved()1109 public void testHandlePackageRemoved() { 1110 mRegisteredServicesCache = new RegisteredServicesCache(mContext, mCallback, 1111 mDynamicSettingsFile, mOtherSettingsFile, mServiceParser, mRoutingOptionManager); 1112 verify(mContext).registerReceiverForAllUsers( 1113 mReceiverArgumentCaptor.capture(), 1114 argThat(intent -> intent.hasAction(Intent.ACTION_PACKAGE_ADDED)), 1115 eq(null), eq(null)); 1116 mRegisteredServicesCache.initialize(); 1117 assertNotNull(mRegisteredServicesCache.getService(USER_ID, WALLET_HOLDER_SERVICE_COMPONENT)); 1118 1119 Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED); 1120 intent.putExtra(Intent.EXTRA_UID, USER_ID); 1121 // return empty list 1122 Mockito.reset(mPackageManager); 1123 when(mPackageManager.queryIntentServicesAsUser(any(), any(), any())).thenReturn(List.of()); 1124 mReceiverArgumentCaptor.getValue().onReceive(mContext, intent); 1125 assertNull(mRegisteredServicesCache.getService(USER_ID, WALLET_HOLDER_SERVICE_COMPONENT)); 1126 } 1127 1128 private class MockFileOutputStream extends FileOutputStream { 1129 1130 ByteArrayOutputStream mByteOutputStream; 1131 MockFileOutputStream()1132 public MockFileOutputStream() throws FileNotFoundException { 1133 // Does not actually matter what the path is since we won't be writing to it. 1134 super(mMockFile); 1135 mByteOutputStream = new ByteArrayOutputStream(); 1136 } 1137 1138 @Override write(byte[] b, int off, int len)1139 public void write(byte[] b, int off, int len) throws IOException { 1140 mByteOutputStream.write(b, off, len); 1141 } 1142 1143 @Override write(byte[] b)1144 public void write(byte[] b) throws IOException { 1145 mByteOutputStream.write(b); 1146 } 1147 1148 @Override write(int b)1149 public void write(int b) throws IOException { 1150 mByteOutputStream.write(b); 1151 } 1152 1153 @Override close()1154 public void close() throws IOException { 1155 mByteOutputStream.close(); 1156 } 1157 1158 @Override flush()1159 public void flush() throws IOException { 1160 mByteOutputStream.flush(); 1161 } 1162 toInputStream()1163 InputStream toInputStream() { 1164 return new ByteArrayInputStream(mByteOutputStream.toByteArray()); 1165 } 1166 } 1167 createServiceResolveInfo(boolean hasPermission, String packageName, String className, List<String> categories)1168 private ResolveInfo createServiceResolveInfo(boolean hasPermission, 1169 String packageName, String className, 1170 List<String> categories) { 1171 when(mPackageManager.checkPermission(any(), eq(packageName))) 1172 .thenReturn(hasPermission ? PackageManager.PERMISSION_GRANTED 1173 : PackageManager.PERMISSION_DENIED); 1174 ApduServiceInfo apduServiceInfo = Mockito.mock(ApduServiceInfo.class); 1175 when(apduServiceInfo.getComponent()).thenReturn(new ComponentName(packageName, className)); 1176 when(apduServiceInfo.getUid()).thenReturn(SERVICE_UID); 1177 if (!categories.isEmpty()) { 1178 for(String category : categories) { 1179 when(apduServiceInfo.hasCategory(category)).thenReturn(true); 1180 when(apduServiceInfo.getDynamicAidGroupForCategory(eq(category))) 1181 .thenReturn(createAidGroup(category)); 1182 } 1183 } 1184 mMappedServices.put(className, apduServiceInfo); 1185 1186 ResolveInfo resolveInfo = new ResolveInfo(); 1187 resolveInfo.serviceInfo = new ServiceInfo(); 1188 resolveInfo.serviceInfo.permission = android.Manifest.permission.BIND_NFC_SERVICE; 1189 resolveInfo.serviceInfo.exported = true; 1190 resolveInfo.serviceInfo.packageName = packageName; 1191 resolveInfo.serviceInfo.name = className; 1192 return resolveInfo; 1193 } 1194 createAidGroup(String category)1195 private static AidGroup createAidGroup(String category) { 1196 return new AidGroup(category.equals( 1197 CardEmulation.CATEGORY_PAYMENT) ? PAYMENT_AIDS : NON_PAYMENT_AID, category); 1198 } 1199 } 1200