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.reader; 18 19 import android.content.Intent; 20 import android.nfc.NfcAdapter; 21 import android.nfc.NfcAdapter.ReaderCallback; 22 import android.nfc.Tag; 23 import android.nfc.tech.IsoDep; 24 import android.os.Parcelable; 25 import android.util.Log; 26 27 import com.android.nfc.utils.CommandApdu; 28 import com.android.nfc.utils.HceUtils; 29 30 import java.io.IOException; 31 import java.util.Arrays; 32 33 /** Basic reader activity that sends and receives APDUs to tag when discovered. */ 34 public class SimpleReaderActivity extends BaseReaderActivity implements ReaderCallback { 35 public static final String EXTRA_APDUS = "apdus"; 36 public static final String EXTRA_RESPONSES = "responses"; 37 38 private static final String TAG = "SimpleReaderActivity"; 39 private static final String EXTRA_NFC_TECH = "nfc_tech"; 40 public static final int NFC_TECH_A_POLLING_ON = 41 NfcAdapter.FLAG_READER_NFC_A 42 | NfcAdapter.FLAG_READER_NFC_BARCODE 43 | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK; 44 45 46 private CommandApdu[] mApdus; 47 private String[] mResponses; 48 49 @Override onResume()50 protected void onResume() { 51 super.onResume(); 52 Intent intent = getIntent(); 53 setIntent(intent); 54 int nfcTech = intent.getIntExtra(EXTRA_NFC_TECH, NFC_TECH_A_POLLING_ON); 55 mAdapter.enableReaderMode(this, this, nfcTech, null); 56 Parcelable[] apdus = intent.getParcelableArrayExtra(EXTRA_APDUS); 57 if (apdus != null) { 58 mApdus = new CommandApdu[apdus.length]; 59 for (int i = 0; i < apdus.length; i++) { 60 mApdus[i] = (CommandApdu) apdus[i]; 61 } 62 } else { 63 mApdus = null; 64 } 65 66 mResponses = intent.getStringArrayExtra(EXTRA_RESPONSES); 67 } 68 69 // Override the default setPollTech for this case since we have a specific reader activity. 70 @Override setPollTech(int pollTech)71 public void setPollTech(int pollTech) { 72 Log.d(TAG, "setting polltech to " + pollTech); 73 mAdapter.enableReaderMode(this, this, pollTech, null); 74 } 75 76 @Override onPause()77 protected void onPause() { 78 super.onPause(); 79 Log.d(TAG, "onPause"); 80 } 81 82 @Override onTagDiscovered(Tag tag)83 public void onTagDiscovered(Tag tag) { 84 Log.d(TAG, "onTagDiscovered"); 85 final StringBuilder sb = new StringBuilder(); 86 IsoDep isoDep = IsoDep.get(tag); 87 if (isoDep == null) { 88 return; 89 } 90 91 boolean success = true; 92 long startTime = System.currentTimeMillis(); 93 try { 94 isoDep.connect(); 95 isoDep.setTimeout(5000); 96 int count = 0; 97 98 for (CommandApdu apdu : mApdus) { 99 sb.append("Request APDU:\n"); 100 sb.append(apdu.getApdu()).append("\n\n"); 101 long apduStartTime = System.currentTimeMillis(); 102 byte[] response = isoDep.transceive(HceUtils.hexStringToBytes(apdu.getApdu())); 103 long apduEndTime = System.currentTimeMillis(); 104 sb.append("Response APDU (in ") 105 .append(apduEndTime - apduStartTime) 106 .append(" ms):\n"); 107 sb.append(HceUtils.getHexBytes(null, response)); 108 109 sb.append("\n\n\n"); 110 boolean wildCard = "*".equals(mResponses[count]); 111 byte[] expectedResponse = HceUtils.hexStringToBytes(mResponses[count]); 112 Log.d(TAG, HceUtils.getHexBytes("APDU response: ", response)); 113 if (!wildCard && !Arrays.equals(response, expectedResponse)) { 114 Log.d(TAG, "Unexpected APDU response: " + HceUtils.getHexBytes("", response) 115 + " expected: " + mResponses[count]); 116 success = false; 117 break; 118 } 119 count++; 120 } 121 } catch (IOException e) { 122 sb.insert( 123 0, 124 "Error while reading: (did you keep the devices in range?)\nPlease try " 125 + "again\n."); 126 Log.e(TAG, sb.toString()); 127 } 128 if (success) { 129 sb.insert( 130 0, 131 "Total APDU exchange time: " 132 + (System.currentTimeMillis() - startTime) 133 + " ms.\n\n"); 134 Log.d(TAG, sb.toString()); 135 setTestPassed(); 136 } else { 137 sb.insert( 138 0, 139 "FAIL. Total APDU exchange time: " 140 + (System.currentTimeMillis() - startTime) 141 + " ms.\n\n"); 142 Log.w(TAG, sb.toString()); 143 } 144 } 145 } 146