1 package com.android.cts.verifier.nfc.hce;
2 
3 import android.annotation.TargetApi;
4 import android.app.AlertDialog;
5 import android.content.Intent;
6 import android.content.SharedPreferences;
7 import android.nfc.NfcAdapter;
8 import android.nfc.NfcAdapter.ReaderCallback;
9 import android.nfc.tech.IsoDep;
10 import android.nfc.Tag;
11 import android.os.Bundle;
12 import android.os.Parcelable;
13 import android.util.Log;
14 import android.view.View;
15 import android.widget.AdapterView;
16 import android.widget.AdapterView.OnItemSelectedListener;
17 import android.widget.ArrayAdapter;
18 import android.widget.Spinner;
19 import android.widget.TextView;
20 
21 import com.android.cts.verifier.PassFailButtons;
22 import com.android.cts.verifier.R;
23 
24 import java.io.IOException;
25 import java.util.Arrays;
26 
27 @TargetApi(19)
28 public class SimpleReaderActivity extends PassFailButtons.Activity implements ReaderCallback,
29         OnItemSelectedListener {
30     public static final String PREFS_NAME = "HceTypePrefs";
31 
32     public static final String TAG = "SimpleReaderActivity";
33     public static final String EXTRA_APDUS = "apdus";
34     public static final String EXTRA_RESPONSES = "responses";
35     public static final String EXTRA_LABEL = "label";
36 
37     NfcAdapter mAdapter;
38     CommandApdu[] mApdus;
39     String[] mResponses;
40     String mLabel;
41 
42     TextView mTextView;
43     Spinner mSpinner;
44     SharedPreferences mPrefs;
45 
46     @Override
onCreate(Bundle savedInstanceState)47     protected void onCreate(Bundle savedInstanceState) {
48         super.onCreate(savedInstanceState);
49         setContentView(R.layout.nfc_hce_reader);
50         setPassFailButtonClickListeners();
51         getPassButton().setEnabled(false);
52 
53         mLabel = getIntent().getStringExtra(EXTRA_LABEL);
54         setTitle(mLabel);
55 
56         mAdapter = NfcAdapter.getDefaultAdapter(this);
57         mTextView = (TextView) findViewById(R.id.text);
58         mTextView.setTextSize(12.0f);
59         mTextView.setText(R.string.nfc_hce_type_selection);
60 
61         Spinner spinner = (Spinner) findViewById(R.id.type_ab_selection);
62         ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,
63                 R.array.nfc_types_array, android.R.layout.simple_spinner_item);
64         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
65         spinner.setAdapter(adapter);
66         spinner.setOnItemSelectedListener(this);
67 
68         mPrefs = getSharedPreferences(PREFS_NAME, 0);
69         boolean isTypeB = mPrefs.getBoolean("typeB", false);
70         if (isTypeB) {
71             spinner.setSelection(1);
72         }
73     }
74 
75     @Override
onResume()76     protected void onResume() {
77         super.onResume();
78         mAdapter.enableReaderMode(this, this, NfcAdapter.FLAG_READER_NFC_A |
79                 NfcAdapter.FLAG_READER_NFC_BARCODE | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null);
80         Intent intent = getIntent();
81         Parcelable[] apdus = intent.getParcelableArrayExtra(EXTRA_APDUS);
82         if (apdus != null) {
83 	        mApdus = new CommandApdu[apdus.length];
84 	        for (int i = 0; i < apdus.length; i++) {
85 	            mApdus[i] = (CommandApdu) apdus[i];
86 	        }
87         } else {
88             mApdus = null;
89         }
90         mResponses = intent.getStringArrayExtra(EXTRA_RESPONSES);
91     }
92 
93     @Override
onTagDiscovered(Tag tag)94     public void onTagDiscovered(Tag tag) {
95         final StringBuilder sb = new StringBuilder();
96         IsoDep isoDep = IsoDep.get(tag);
97         if (isoDep == null) {
98             // TODO dialog box
99             return;
100         }
101 
102         try {
103             isoDep.connect();
104             isoDep.setTimeout(5000);
105             int count = 0;
106             boolean success = true;
107             long startTime = System.currentTimeMillis();
108             for (CommandApdu apdu: mApdus) {
109                 sb.append("Request APDU:\n");
110                 sb.append(apdu.getApdu() + "\n\n");
111                 long apduStartTime = System.currentTimeMillis();
112                 byte[] response = isoDep.transceive(HceUtils.hexStringToBytes(apdu.getApdu()));
113                 long apduEndTime = System.currentTimeMillis();
114                 sb.append("Response APDU (in " + Long.toString(apduEndTime - apduStartTime) +
115                         " ms):\n");
116                 sb.append(HceUtils.getHexBytes(null, response));
117 
118                 sb.append("\n\n\n");
119                 boolean wildCard = "*".equals(mResponses[count]);
120                 byte[] expectedResponse = HceUtils.hexStringToBytes(mResponses[count]);
121                 Log.d(TAG, HceUtils.getHexBytes("APDU response: ", response));
122                 if (!wildCard && !Arrays.equals(response, expectedResponse)) {
123                     Log.d(TAG, "Unexpected APDU response: " + HceUtils.getHexBytes("", response));
124                     success = false;
125                     break;
126                 }
127                 count++;
128             }
129             if (success) {
130                 sb.insert(0, "Total APDU exchange time: " +
131                         Long.toString(System.currentTimeMillis() - startTime) + " ms.\n\n");
132                 runOnUiThread(new Runnable() {
133                     @Override
134                     public void run() {
135                         mTextView.setText(sb.toString());
136                         getPassButton().setEnabled(true);
137                     }
138                 });
139             } else {
140                 sb.insert(0, "FAIL. Total APDU exchange time: " +
141                         Long.toString(System.currentTimeMillis() - startTime) + " ms.\n\n");
142                 runOnUiThread(new Runnable() {
143                     @Override
144                     public void run() {
145                         mTextView.setText(sb.toString());
146                         AlertDialog.Builder builder = new AlertDialog.Builder(SimpleReaderActivity.this);
147                         builder.setTitle("Test failed");
148                         builder.setMessage("An unexpected response APDU was received, or no APDUs were received at all.");
149                         builder.setPositiveButton("OK", null);
150                         builder.show();
151                     }
152                 });
153             }
154         } catch (IOException e) {
155             sb.insert(0, "Test failed. IOException (did you keep the devices in range?)\n\n.");
156             runOnUiThread(new Runnable() {
157                 @Override
158                 public void run() {
159                     mTextView.setText(sb.toString());
160                 }
161             });
162         } finally {
163         }
164     }
165 
166     @Override
onItemSelected(AdapterView<?> parent, View view, int position, long id)167     public void onItemSelected(AdapterView<?> parent, View view, int position,
168             long id) {
169         if (position == 0) {
170             // Type-A
171             mAdapter.disableReaderMode(this);
172             mAdapter.enableReaderMode(this, this, NfcAdapter.FLAG_READER_NFC_A |
173                 NfcAdapter.FLAG_READER_NFC_BARCODE | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null);
174             SharedPreferences.Editor editor = mPrefs.edit();
175             editor.putBoolean("typeB", false);
176             editor.commit();
177         } else {
178             // Type-B
179             mAdapter.disableReaderMode(this);
180             mAdapter.enableReaderMode(this, this, NfcAdapter.FLAG_READER_NFC_B |
181                     NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, null);
182             SharedPreferences.Editor editor = mPrefs.edit();
183             editor.putBoolean("typeB", true);
184             editor.commit();
185         }
186     }
187 
188     @Override
onNothingSelected(AdapterView<?> parent)189     public void onNothingSelected(AdapterView<?> parent) {
190     }
191 
192     @Override
getTestId()193     public String getTestId() {
194         return mLabel;
195     }
196 }
197