• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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