Home | History | Annotate | Download | only in hce
      1 package com.android.cts.verifier.nfc.hce;
      2 
      3 import android.annotation.TargetApi;
      4 import android.nfc.NfcAdapter;
      5 import android.nfc.NfcAdapter.ReaderCallback;
      6 import android.nfc.tech.IsoDep;
      7 import android.nfc.tech.NfcA;
      8 import android.nfc.Tag;
      9 import android.os.Bundle;
     10 import android.widget.TextView;
     11 
     12 import com.android.cts.verifier.PassFailButtons;
     13 import com.android.cts.verifier.R;
     14 
     15 import java.io.IOException;
     16 
     17 @TargetApi(19)
     18 public class ProtocolParamsReaderActivity extends PassFailButtons.Activity implements ReaderCallback {
     19     public static final String TAG = "ProtocolParamsReaderActivity";
     20 
     21     NfcAdapter mAdapter;
     22 
     23     TextView mTextView;
     24 
     25     @Override
     26     protected void onCreate(Bundle savedInstanceState) {
     27         super.onCreate(savedInstanceState);
     28         setContentView(R.layout.pass_fail_text);
     29         setPassFailButtonClickListeners();
     30 
     31         setTitle(R.string.nfc_hce_protocol_params_reader);
     32 
     33         mAdapter = NfcAdapter.getDefaultAdapter(this);
     34         mTextView = (TextView) findViewById(R.id.text);
     35         mTextView.setTextSize(12.0f);
     36     }
     37 
     38     @Override
     39     protected void onResume() {
     40         super.onResume();
     41         mAdapter.enableReaderMode(this, this, NfcAdapter.FLAG_READER_NFC_A |
     42                 NfcAdapter.FLAG_READER_NFC_BARCODE | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null);
     43     }
     44 
     45     public boolean parseProtocolParameters(StringBuilder sb, byte[] uid,
     46             short sak, byte[] atqa, byte[] ats) {
     47 
     48         boolean success = true;
     49 
     50         sb.append("UID: " + HceUtils.getHexBytes(null, uid) + "\n\n");
     51         sb.append("SAK: 0x" + Integer.toHexString(sak & 0xFF) + "\n");
     52 
     53         if ((sak & 0x20) != 0) {
     54             sb.append("    (OK) ISO-DEP bit (0x20) is set.\n");
     55         } else {
     56             success = false;
     57             sb.append("    (FAIL) ISO-DEP bit (0x20) is NOT set.\n");
     58         }
     59 
     60         if ((sak & 0x40) != 0) {
     61             sb.append("    (OK) P2P bit (0x40) is set.\n");
     62         } else {
     63             sb.append("    (WARN) P2P bit (0x40) is NOT set.\n");
     64         }
     65 
     66         sb.append("\n");
     67         sb.append("ATQA: " + HceUtils.getHexBytes(null, atqa) + "\n");
     68         sb.append("\n");
     69 
     70         sb.append("ATS: " + HceUtils.getHexBytes(null, ats) + "\n");
     71         sb.append("    TL: 0x" + Integer.toHexString(ats[0] & 0xFF) + "\n");
     72         sb.append("    T0: 0x" + Integer.toHexString(ats[1] & 0xFF) + "\n");
     73 
     74         boolean ta_present = false;
     75         boolean tb_present = false;
     76         boolean tc_present = false;
     77         int atsIndex = 1;
     78         if ((ats[atsIndex] & 0x40) != 0) {
     79             sb.append("        (OK) T(C) is present (bit 7 is set).\n");
     80             tc_present = true;
     81         } else {
     82             success = false;
     83             sb.append("        (FAIL) T(C) is not present (bit 7 is NOT set).\n");
     84         }
     85         if ((ats[atsIndex] & 0x20) != 0) {
     86             sb.append("        (OK) T(B) is present (bit 6 is set).\n");
     87             tb_present = true;
     88         } else {
     89             success = false;
     90             sb.append("        (FAIL) T(B) is not present (bit 6 is NOT set).\n");
     91         }
     92         if ((ats[atsIndex] & 0x10) != 0) {
     93             sb.append("        (OK) T(A) is present (bit 5 is set).\n");
     94             ta_present = true;
     95         } else {
     96             success = false;
     97             sb.append("        (FAIL) T(A) is not present (bit 5 is NOT set).\n");
     98         }
     99         int fsc = ats[atsIndex] & 0x0F;
    100         if (fsc > 8) {
    101             success = false;
    102             sb.append("        (FAIL) FSC " + Integer.toString(fsc) + " is > 8\n");
    103         } else if (fsc < 2) {
    104             sb.append("        (FAIL EMVCO) FSC " + Integer.toString(fsc) + " is < 2\n");
    105         } else {
    106             sb.append("        (OK) FSC = " + Integer.toString(fsc) + "\n");
    107         }
    108 
    109         atsIndex++;
    110         if (ta_present) {
    111             sb.append("    TA: 0x" + Integer.toHexString(ats[atsIndex] & 0xff) + "\n");
    112             if ((ats[atsIndex] & 0x80) != 0) {
    113                 sb.append("        (OK) bit 8 set, indicating only same bit rate divisor.\n");
    114             } else {
    115                 sb.append("        (FAIL EMVCO) bit 8 NOT set, indicating support for assymetric " +
    116                         "bit rate divisors. EMVCo requires bit 8 set.\n");
    117             }
    118             if ((ats[atsIndex] & 0x70) != 0) {
    119                 sb.append("        (FAIL EMVCO) EMVCo requires bits 7 to 5 set to 0.\n");
    120             } else {
    121                 sb.append("        (OK) bits 7 to 5 indicating only 106 kbit/s L->P supported.\n");
    122             }
    123             if ((ats[atsIndex] & 0x7) != 0) {
    124                 sb.append("        (FAIL EMVCO) EMVCo requires bits 3 to 1 set to 0.\n");
    125             } else {
    126                 sb.append("        (OK) bits 3 to 1 indicating only 106 kbit/s P->L supported.\n");
    127             }
    128             atsIndex++;
    129         }
    130 
    131         if (tb_present) {
    132             sb.append("    TB: 0x" + Integer.toHexString(ats[3] & 0xFF) + "\n");
    133             int fwi = (ats[atsIndex] & 0xF0) >> 4;
    134             if (fwi > 8) {
    135                 success = false;
    136                 sb.append("        (FAIL) FWI=" + Integer.toString(fwi) + ", should be <= 8\n");
    137             } else if (fwi == 8) {
    138                 sb.append("        (FAIL EMVCO) FWI=" + Integer.toString(fwi) +
    139                         ", EMVCo requires <= 7\n");
    140             } else {
    141                 sb.append("        (OK) FWI=" + Integer.toString(fwi) + "\n");
    142             }
    143             int sfgi = ats[atsIndex] & 0x0F;
    144             if (sfgi > 8) {
    145                 success = false;
    146                 sb.append("        (FAIL) SFGI=" + Integer.toString(sfgi) + ", should be <= 8\n");
    147             } else {
    148                 sb.append("        (OK) SFGI=" + Integer.toString(sfgi) + "\n");
    149             }
    150             atsIndex++;
    151         }
    152 
    153         if (tc_present) {
    154             sb.append("    TC: 0x" + Integer.toHexString(ats[atsIndex] & 0xFF) + "\n");
    155             boolean apSupported = (ats[atsIndex] & 0x10) != 0;
    156             boolean didSupported = (ats[atsIndex] & 0x02) != 0;
    157             boolean nadSupported = (ats[atsIndex] & 0x01) != 0;
    158             if (nadSupported) {
    159                 success = false;
    160                 sb.append("        (FAIL) NAD bit is not allowed to be set.\n");
    161             } else {
    162                 sb.append("        (OK) NAD bit is not set.\n");
    163             }
    164             atsIndex++;
    165             // See if there's any bytes left for general bytes
    166             if (atsIndex + 1 < ats.length) {
    167                 int bytesToCopy = ats.length - atsIndex;
    168                 byte[] historical_bytes = new byte[bytesToCopy];
    169                 System.arraycopy(ats, atsIndex, historical_bytes, 0, bytesToCopy);
    170                 sb.append("\n(OK) Historical bytes: " +
    171                         HceUtils.getHexBytes(null, historical_bytes));
    172             }
    173         }
    174         return success;
    175     }
    176 
    177     @Override
    178     public void onTagDiscovered(Tag tag) {
    179         final StringBuilder sb = new StringBuilder();
    180         IsoDep isoDep = IsoDep.get(tag);
    181         NfcA nfcA = NfcA.get(tag);
    182         boolean success = false;
    183         if (nfcA == null || isoDep == null) {
    184             return;
    185         }
    186         try {
    187             nfcA.connect();
    188             byte[] ats = nfcA.transceive(new byte[] { (byte) 0xE0, (byte)0xF0});
    189             success = parseProtocolParameters(sb, tag.getId(), nfcA.getSak(), nfcA.getAtqa(), ats);
    190         } catch (IOException e) {
    191             sb.insert(0, "Test failed. IOException (did you keep the devices in range?)\n\n.");
    192         } finally {
    193             if (success) {
    194                 runOnUiThread(new Runnable() {
    195                     @Override
    196                     public void run() {
    197                         mTextView.setText(sb.toString());
    198                         getPassButton().setEnabled(true);
    199                     }
    200                 });
    201             } else {
    202                 runOnUiThread(new Runnable() {
    203                     @Override
    204                     public void run() {
    205                         mTextView.setText(sb.toString());
    206                         getPassButton().setEnabled(false);
    207                     }
    208                 });
    209             }
    210             try {
    211                 nfcA.transceive(new byte[] {(byte) 0xC2});
    212                 nfcA.close();
    213                 isoDep.connect();
    214             } catch (IOException e) {
    215             }
    216         }
    217     }
    218 }
    219