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 package com.android.nfc.reader; 17 18 19 import android.app.Instrumentation; 20 import android.content.Intent; 21 import android.os.RemoteException; 22 import android.util.Log; 23 24 import androidx.test.platform.app.InstrumentationRegistry; 25 import androidx.test.uiautomator.UiDevice; 26 27 import com.android.nfc.utils.CommandApdu; 28 import com.android.nfc.utils.HceUtils; 29 import com.android.nfc.utils.NfcSnippet; 30 import com.android.nfc.service.AccessService; 31 import com.android.nfc.service.LargeNumAidsService; 32 import com.android.nfc.service.OffHostService; 33 import com.android.nfc.service.PaymentService1; 34 import com.android.nfc.service.PaymentService2; 35 import com.android.nfc.service.PaymentServiceDynamicAids; 36 import com.android.nfc.service.PrefixAccessService; 37 import com.android.nfc.service.PrefixPaymentService1; 38 import com.android.nfc.service.PrefixTransportService1; 39 import com.android.nfc.service.PrefixTransportService2; 40 import com.android.nfc.service.ScreenOffPaymentService; 41 import com.android.nfc.service.ScreenOnOnlyOffHostService; 42 import com.android.nfc.service.ThroughputService; 43 import com.android.nfc.service.TransportService1; 44 import com.android.nfc.service.TransportService2; 45 46 import com.google.android.mobly.snippet.rpc.AsyncRpc; 47 import com.google.android.mobly.snippet.rpc.Rpc; 48 49 public class NfcReaderDeviceSnippet extends NfcSnippet { 50 protected static final String TAG = "NfcSnippet"; 51 52 private BaseReaderActivity mActivity; 53 54 /** Opens NFC reader for single non-payment test */ 55 @Rpc(description = "Open simple reader activity for single non-payment test") startSingleNonPaymentReaderActivity()56 public void startSingleNonPaymentReaderActivity() { 57 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 58 Intent intent = 59 buildReaderIntentWithApduSequence( 60 instrumentation, 61 HceUtils.COMMAND_APDUS_BY_SERVICE.get(TransportService1.class.getName()), 62 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(TransportService1.class.getName())); 63 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 64 } 65 66 /** Open simple reader activity for single non-payment test */ 67 @Rpc(description = "Open simple reader activity for single non-payment test") startSinglePaymentReaderActivity()68 public void startSinglePaymentReaderActivity() { 69 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 70 Intent intent = 71 buildReaderIntentWithApduSequence( 72 instrumentation, 73 HceUtils.COMMAND_APDUS_BY_SERVICE.get(PaymentService1.class.getName()), 74 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(PaymentService1.class.getName())); 75 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 76 } 77 78 /** Opens simple reader activity for dual payment services test */ 79 @Rpc(description = "Opens simple reader activity for dual payment services test") startDualPaymentReaderActivity()80 public void startDualPaymentReaderActivity() { 81 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 82 Intent intent = 83 buildReaderIntentWithApduSequence( 84 instrumentation, 85 HceUtils.COMMAND_APDUS_BY_SERVICE.get(PaymentService1.class.getName()), 86 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(PaymentService1.class.getName())); 87 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 88 } 89 90 /** Opens simple reader activity for foreground payment test */ 91 @Rpc(description = "Opens simple reader activity for foreground payment test") startForegroundPaymentReaderActivity()92 public void startForegroundPaymentReaderActivity() { 93 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 94 Intent intent = 95 buildReaderIntentWithApduSequence( 96 instrumentation, 97 HceUtils.COMMAND_APDUS_BY_SERVICE.get(PaymentService2.class.getName()), 98 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(PaymentService2.class.getName())); 99 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 100 } 101 102 /** Opens simple reader activity for dynamic AID test */ 103 @Rpc(description = "Opens simple reader activity for dynamic AID test") startDynamicAidReaderActivity()104 public void startDynamicAidReaderActivity() { 105 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 106 Intent intent = 107 buildReaderIntentWithApduSequence( 108 instrumentation, 109 HceUtils.COMMAND_APDUS_BY_SERVICE.get( 110 PaymentServiceDynamicAids.class.getName()), 111 HceUtils.RESPONSE_APDUS_BY_SERVICE.get( 112 PaymentServiceDynamicAids.class.getName())); 113 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 114 } 115 116 /** Opens simple reader activity for prefix payment test */ 117 @Rpc(description = "Opens simple reader activity for prefix payment test") startPrefixPaymentReaderActivity()118 public void startPrefixPaymentReaderActivity() { 119 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 120 Intent intent = 121 buildReaderIntentWithApduSequence( 122 instrumentation, 123 HceUtils.COMMAND_APDUS_BY_SERVICE.get( 124 PrefixPaymentService1.class.getName()), 125 HceUtils.RESPONSE_APDUS_BY_SERVICE.get( 126 PrefixPaymentService1.class.getName())); 127 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 128 } 129 130 /** Opens simple reader activity for prefix payment 2 test */ 131 @Rpc(description = "Opens simple reader activity for prefix payment 2 test") startPrefixPaymentReader2Activity()132 public void startPrefixPaymentReader2Activity() { 133 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 134 Intent intent = 135 buildReaderIntentWithApduSequence( 136 instrumentation, 137 HceUtils.COMMAND_APDUS_BY_SERVICE.get( 138 PrefixPaymentService1.class.getName()), 139 HceUtils.RESPONSE_APDUS_BY_SERVICE.get( 140 PrefixPaymentService1.class.getName())); 141 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 142 } 143 144 /** Opens simple reader activity for non-payment prefix test */ 145 @Rpc(description = "Opens simple reader activity for non-payment prefix test.") startDualNonPaymentPrefixReaderActivity()146 public void startDualNonPaymentPrefixReaderActivity() { 147 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 148 CommandApdu[] prefixTransportService1Commands = 149 HceUtils.COMMAND_APDUS_BY_SERVICE.get(PrefixTransportService1.class.getName()); 150 CommandApdu[] prefixAccessServiceCommands = 151 HceUtils.COMMAND_APDUS_BY_SERVICE.get(PrefixAccessService.class.getName()); 152 153 // Combine command/response APDU arrays 154 CommandApdu[] combinedCommands = 155 new CommandApdu 156 [prefixTransportService1Commands.length 157 + prefixAccessServiceCommands.length]; 158 System.arraycopy( 159 prefixTransportService1Commands, 160 0, 161 combinedCommands, 162 0, 163 prefixTransportService1Commands.length); 164 System.arraycopy( 165 prefixAccessServiceCommands, 166 0, 167 combinedCommands, 168 prefixTransportService1Commands.length, 169 prefixAccessServiceCommands.length); 170 171 String[] prefixTransportService1Responses = 172 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(PrefixTransportService1.class.getName()); 173 String[] prefixAccessServiceResponses = 174 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(PrefixAccessService.class.getName()); 175 176 String[] combinedResponses = 177 new String 178 [prefixTransportService1Responses.length 179 + prefixAccessServiceResponses.length]; 180 System.arraycopy( 181 prefixTransportService1Responses, 182 0, 183 combinedResponses, 184 0, 185 prefixTransportService1Responses.length); 186 System.arraycopy( 187 prefixAccessServiceResponses, 188 0, 189 combinedResponses, 190 prefixTransportService1Responses.length, 191 prefixAccessServiceResponses.length); 192 Intent intent = 193 buildReaderIntentWithApduSequence( 194 instrumentation, combinedCommands, combinedResponses); 195 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 196 } 197 198 /** Open simple reader activity for off host test. */ 199 @Rpc(description = "Open simple reader activity for off host test") startOffHostReaderActivity()200 public void startOffHostReaderActivity() { 201 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 202 Intent intent = 203 buildReaderIntentWithApduSequence( 204 instrumentation, 205 HceUtils.COMMAND_APDUS_BY_SERVICE.get(OffHostService.class.getName()), 206 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(OffHostService.class.getName())); 207 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 208 } 209 210 /** Open simple reader activity for on and off host test. */ 211 @Rpc(description = "Open simple reader activity for off host test") startOnAndOffHostReaderActivity()212 public void startOnAndOffHostReaderActivity() { 213 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 214 // Merge command/response APDU sequences. 215 CommandApdu[] offHostCommands = HceUtils.COMMAND_APDUS_BY_SERVICE.get( 216 OffHostService.class.getName()); 217 CommandApdu[] onHostCommands = HceUtils.COMMAND_APDUS_BY_SERVICE.get( 218 TransportService1.class.getName()); 219 CommandApdu[] combinedCommands = 220 new CommandApdu[offHostCommands.length + onHostCommands.length]; 221 System.arraycopy(offHostCommands, 0, combinedCommands, 0, offHostCommands.length); 222 System.arraycopy(onHostCommands, 0, combinedCommands, offHostCommands.length, 223 onHostCommands.length); 224 225 String[] offHostResponses = HceUtils.RESPONSE_APDUS_BY_SERVICE.get( 226 OffHostService.class.getName()); 227 String[] onHostResponses = HceUtils.RESPONSE_APDUS_BY_SERVICE.get( 228 TransportService1.class.getName()); 229 String[] combinedResponses = new String[offHostResponses.length + onHostResponses.length]; 230 231 System.arraycopy(offHostResponses, 0, combinedResponses, 0, offHostResponses.length); 232 System.arraycopy(onHostResponses, 0, combinedResponses, offHostResponses.length, 233 onHostResponses.length); 234 235 Intent intent = 236 buildReaderIntentWithApduSequence( 237 instrumentation, 238 combinedCommands, 239 combinedResponses); 240 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 241 } 242 243 /** Open simple reader activity for dual non-payment test */ 244 @Rpc(description = "Open simple reader activity for dual non-payment test") startDualNonPaymentReaderActivity()245 public void startDualNonPaymentReaderActivity() { 246 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 247 CommandApdu[] transportService2CommandApdus = 248 HceUtils.COMMAND_APDUS_BY_SERVICE.get(TransportService2.class.getName()); 249 String[] transportService2ResponseApdus = 250 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(TransportService2.class.getName()); 251 252 CommandApdu[] accessServiceCommandApdus = 253 HceUtils.COMMAND_APDUS_BY_SERVICE.get(AccessService.class.getName()); 254 String[] accessServiceResponseApdus = 255 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(AccessService.class.getName()); 256 // Combine command/response APDU arrays 257 CommandApdu[] commandSequences = 258 new CommandApdu 259 [transportService2CommandApdus.length + accessServiceCommandApdus.length]; 260 System.arraycopy( 261 transportService2CommandApdus, 262 0, 263 commandSequences, 264 0, 265 transportService2CommandApdus.length); 266 System.arraycopy( 267 accessServiceCommandApdus, 268 0, 269 commandSequences, 270 transportService2CommandApdus.length, 271 accessServiceCommandApdus.length); 272 String[] responseSequences = 273 new String 274 [transportService2ResponseApdus.length + accessServiceResponseApdus.length]; 275 System.arraycopy( 276 transportService2ResponseApdus, 277 0, 278 responseSequences, 279 0, 280 transportService2ResponseApdus.length); 281 System.arraycopy( 282 accessServiceResponseApdus, 283 0, 284 responseSequences, 285 transportService2ResponseApdus.length, 286 accessServiceResponseApdus.length); 287 288 Intent intent = 289 buildReaderIntentWithApduSequence( 290 instrumentation, commandSequences, responseSequences); 291 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 292 } 293 294 /** Open simple reader activity for foreground non-payment test */ 295 @Rpc(description = "Open simple reader activity for foreground non-payment test") startForegroundNonPaymentReaderActivity()296 public void startForegroundNonPaymentReaderActivity() { 297 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 298 Intent intent = 299 buildReaderIntentWithApduSequence( 300 instrumentation, 301 HceUtils.COMMAND_APDUS_BY_SERVICE.get(TransportService2.class.getName()), 302 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(TransportService2.class.getName())); 303 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 304 } 305 306 /** Open simple reader activity for throughput test */ 307 @Rpc(description = "Open simple reader activity for throughput test") startThroughputReaderActivity()308 public void startThroughputReaderActivity() { 309 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 310 Intent intent = 311 buildReaderIntentWithApduSequence( 312 instrumentation, 313 HceUtils.COMMAND_APDUS_BY_SERVICE.get(ThroughputService.class.getName()), 314 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(ThroughputService.class.getName())); 315 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 316 } 317 318 /** Open simple reader activity for tap test */ 319 @Rpc(description = "Open simple reader activity for tap test") startTapTestReaderActivity()320 public void startTapTestReaderActivity() { 321 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 322 Intent intent = 323 buildReaderIntentWithApduSequence( 324 instrumentation, 325 HceUtils.COMMAND_APDUS_BY_SERVICE.get(TransportService1.class.getName()), 326 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(TransportService1.class.getName())); 327 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 328 } 329 330 /** Open simple reader activity for large num AIDs test */ 331 @Rpc(description = "Open simple reader activity for large num AIDs Test") startLargeNumAidsReaderActivity()332 public void startLargeNumAidsReaderActivity() { 333 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 334 Intent intent = 335 buildReaderIntentWithApduSequence( 336 instrumentation, 337 HceUtils.COMMAND_APDUS_BY_SERVICE.get(LargeNumAidsService.class.getName()), 338 HceUtils.RESPONSE_APDUS_BY_SERVICE.get( 339 LargeNumAidsService.class.getName())); 340 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 341 } 342 343 /** Open simple reader activity for screen off payment test */ 344 @Rpc(description = "Open simple reader activity for screen off payment Test") startScreenOffPaymentReaderActivity()345 public void startScreenOffPaymentReaderActivity() { 346 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 347 Intent intent = 348 buildReaderIntentWithApduSequence( 349 instrumentation, 350 HceUtils.COMMAND_APDUS_BY_SERVICE.get( 351 ScreenOffPaymentService.class.getName()), 352 HceUtils.RESPONSE_APDUS_BY_SERVICE.get( 353 ScreenOffPaymentService.class.getName())); 354 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 355 } 356 357 /** Open protocol params reader activity */ 358 @Rpc(description = "Open protocol params reader activity") startProtocolParamsReaderActivity()359 public void startProtocolParamsReaderActivity() { 360 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 361 Intent intent = new Intent(Intent.ACTION_MAIN); 362 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 363 intent.setClassName( 364 instrumentation.getTargetContext(), ProtocolParamsReaderActivity.class.getName()); 365 mActivity = (ProtocolParamsReaderActivity) instrumentation.startActivitySync(intent); 366 } 367 368 /** Open simple reader activity for conflicting non-payment test */ 369 @Rpc(description = "Open simple reader activity for conflicting non-payment Test") startConflictingNonPaymentReaderActivity()370 public void startConflictingNonPaymentReaderActivity() { 371 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 372 Intent intent = 373 buildReaderIntentWithApduSequence( 374 instrumentation, 375 HceUtils.COMMAND_APDUS_BY_SERVICE.get(TransportService2.class.getName()), 376 HceUtils.RESPONSE_APDUS_BY_SERVICE.get(TransportService2.class.getName())); 377 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 378 } 379 380 /** Open simple reader activity for conflicting non-payment prefix test */ 381 @Rpc(description = "Open simple reader activity for conflicting non-payment prefix Test") startConflictingNonPaymentPrefixReaderActivity()382 public void startConflictingNonPaymentPrefixReaderActivity() { 383 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 384 Intent intent = 385 buildReaderIntentWithApduSequence( 386 instrumentation, 387 HceUtils.COMMAND_APDUS_BY_SERVICE.get( 388 PrefixTransportService2.class.getName()), 389 HceUtils.RESPONSE_APDUS_BY_SERVICE.get( 390 PrefixTransportService2.class.getName())); 391 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 392 } 393 394 /** Open simple reader activity for screen on only off-host service test */ 395 @Rpc(description = "Open simple reader activity for screen on only off-host service Test") startScreenOnOnlyOffHostReaderActivity()396 public void startScreenOnOnlyOffHostReaderActivity() { 397 Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); 398 Intent intent = 399 buildReaderIntentWithApduSequence( 400 instrumentation, 401 HceUtils.COMMAND_APDUS_BY_SERVICE.get( 402 ScreenOnOnlyOffHostService.class.getName()), 403 HceUtils.RESPONSE_APDUS_BY_SERVICE.get( 404 ScreenOnOnlyOffHostService.class.getName() 405 )); 406 mActivity = (SimpleReaderActivity) instrumentation.startActivitySync(intent); 407 } 408 409 /** Registers receiver for Test Pass event */ 410 @AsyncRpc(description = "Waits for Test Pass event") asyncWaitForTestPass(String callbackId, String eventName)411 public void asyncWaitForTestPass(String callbackId, String eventName) { 412 registerSnippetBroadcastReceiver( 413 callbackId, eventName, BaseReaderActivity.ACTION_TEST_PASSED); 414 } 415 416 /** Sets the poll tech for the active reader activity */ 417 @Rpc(description = "Set the listen tech for the emulator") setPollTech(Integer pollTech)418 public void setPollTech(Integer pollTech) { 419 if (mActivity == null) { 420 Log.e(TAG, "Activity is null."); 421 return; 422 } 423 mActivity.setPollTech(pollTech); 424 } 425 426 /** Resets the poll tech for the active reader activity */ 427 @Rpc(description = "Reset the listen tech for the emulator") resetPollTech()428 public void resetPollTech() { 429 if (mActivity == null) { 430 Log.e(TAG, "Activity is null."); 431 return; 432 } 433 mActivity.resetPollTech(); 434 } 435 436 /** Closes reader activity between tests */ 437 @Rpc(description = "Close activity if one was opened.") closeActivity()438 public void closeActivity() { 439 if (mActivity != null) { 440 mActivity.finish(); 441 } 442 } 443 buildReaderIntentWithApduSequence( Instrumentation instrumentation, CommandApdu[] commandApdus, String[] responseApdus)444 private Intent buildReaderIntentWithApduSequence( 445 Instrumentation instrumentation, CommandApdu[] commandApdus, String[] responseApdus) { 446 Intent intent = new Intent(Intent.ACTION_MAIN); 447 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 448 intent.setClassName( 449 instrumentation.getTargetContext(), SimpleReaderActivity.class.getName()); 450 intent.putExtra(SimpleReaderActivity.EXTRA_APDUS, commandApdus); 451 intent.putExtra(SimpleReaderActivity.EXTRA_RESPONSES, responseApdus); 452 return intent; 453 } 454 } 455