1 package com.android.cts.verifier.nfc.hce;
2 
3 import android.annotation.TargetApi;
4 import android.content.ComponentName;
5 import android.content.Intent;
6 import android.nfc.cardemulation.HostApduService;
7 import android.os.Bundle;
8 import android.util.Log;
9 
10 import java.util.Arrays;
11 
12 @TargetApi(19)
13 public abstract class HceService extends HostApduService {
14     final static String TAG = "HceService";
15 
16     final static int STATE_IDLE = 0;
17     final static int STATE_IN_PROGRESS = 1;
18     final static int STATE_FAILED = 2;
19 
20     // Variables below only used on main thread
21     CommandApdu[] mCommandApdus = null;
22     String[] mResponseApdus = null;
23     int mApduIndex = 0;
24     int mState = STATE_IDLE;
25     long mStartTime;
26 
initialize(CommandApdu[] commandApdus, String[] responseApdus)27     public void initialize(CommandApdu[] commandApdus, String[] responseApdus) {
28        mCommandApdus = commandApdus;
29        mResponseApdus = responseApdus;
30     }
31 
32     @Override
onDeactivated(int arg0)33     public void onDeactivated(int arg0) {
34         mApduIndex = 0;
35         mState = STATE_IDLE;
36     }
37 
getComponent()38     public abstract ComponentName getComponent();
39 
onApduSequenceComplete()40     public void onApduSequenceComplete() {
41         Intent completionIntent = new Intent(HceUtils.ACTION_APDU_SEQUENCE_COMPLETE);
42         completionIntent.putExtra(HceUtils.EXTRA_COMPONENT, getComponent());
43         completionIntent.putExtra(HceUtils.EXTRA_DURATION,
44                 System.currentTimeMillis() - mStartTime);
45         sendBroadcast(completionIntent);
46     }
47 
onApduSequenceError()48     public void onApduSequenceError() {
49         Intent errorIntent = new Intent(HceUtils.ACTION_APDU_SEQUENCE_ERROR);
50         sendBroadcast(errorIntent);
51     }
52 
53     @Override
processCommandApdu(byte[] arg0, Bundle arg1)54     public byte[] processCommandApdu(byte[] arg0, Bundle arg1) {
55         if (mState == STATE_FAILED) {
56             // Don't accept any more APDUs until deactivated
57             return null;
58         }
59 
60         if (mState == STATE_IDLE) {
61             mState = STATE_IN_PROGRESS;
62             mStartTime = System.currentTimeMillis();
63         }
64 
65 
66         if (mApduIndex >= mCommandApdus.length) {
67 	        // Skip all APDUs which aren't supposed to reach us
68             return null;
69         }
70 
71         do {
72             if (!mCommandApdus[mApduIndex].isReachable()) {
73                 mApduIndex++;
74             } else {
75                 break;
76             }
77         } while (mApduIndex < mCommandApdus.length);
78 
79         if (mApduIndex >= mCommandApdus.length) {
80             Log.d(TAG, "Ignoring command APDU; protocol complete.");
81             // Ignore new APDUs after completion
82             return null;
83         } else {
84 
85             if (!Arrays.equals(HceUtils.hexStringToBytes(mCommandApdus[mApduIndex].getApdu()), arg0)) {
86                 Log.d(TAG, "Unexpected command APDU: " + HceUtils.getHexBytes("", arg0));
87                 onApduSequenceError();
88                 return null;
89             } else {
90                 // Send corresponding response APDU
91                 byte[] responseApdu = HceUtils.hexStringToBytes(mResponseApdus[mApduIndex]);
92                 mApduIndex++;
93                 if (mApduIndex == mCommandApdus.length) {
94                     // Test passed
95                     onApduSequenceComplete();
96                 }
97                 return responseApdu;
98             }
99         }
100     }
101 }
102