1 /*
2  * Copyright (C) 2010 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 android.nfc.tech;
18 
19 import android.nfc.ErrorCodes;
20 import android.nfc.Tag;
21 import android.os.Bundle;
22 import android.os.RemoteException;
23 import android.util.Log;
24 
25 import java.io.IOException;
26 
27 /**
28  * Provides access to ISO-DEP (ISO 14443-4) properties and I/O operations on a {@link Tag}.
29  *
30  * <p>Acquire an {@link IsoDep} object using {@link #get}.
31  * <p>The primary ISO-DEP I/O operation is {@link #transceive}. Applications must
32  * implement their own protocol stack on top of {@link #transceive}.
33  * <p>Tags that enumerate the {@link IsoDep} technology in {@link Tag#getTechList}
34  * will also enumerate
35  * {@link NfcA} or {@link NfcB} (since IsoDep builds on top of either of these).
36  *
37  * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
38  * require the {@link android.Manifest.permission#NFC} permission.
39  */
40 public final class IsoDep extends BasicTagTechnology {
41     private static final String TAG = "NFC";
42 
43     /** @hide */
44     public static final String EXTRA_HI_LAYER_RESP = "hiresp";
45     /** @hide */
46     public static final String EXTRA_HIST_BYTES = "histbytes";
47 
48     private byte[] mHiLayerResponse = null;
49     private byte[] mHistBytes = null;
50 
51     /**
52      * Get an instance of {@link IsoDep} for the given tag.
53      * <p>Does not cause any RF activity and does not block.
54      * <p>Returns null if {@link IsoDep} was not enumerated in {@link Tag#getTechList}.
55      * This indicates the tag does not support ISO-DEP.
56      *
57      * @param tag an ISO-DEP compatible tag
58      * @return ISO-DEP object
59      */
get(Tag tag)60     public static IsoDep get(Tag tag) {
61         if (!tag.hasTech(TagTechnology.ISO_DEP)) return null;
62         try {
63             return new IsoDep(tag);
64         } catch (RemoteException e) {
65             return null;
66         }
67     }
68 
69     /** @hide */
IsoDep(Tag tag)70     public IsoDep(Tag tag)
71             throws RemoteException {
72         super(tag, TagTechnology.ISO_DEP);
73         Bundle extras = tag.getTechExtras(TagTechnology.ISO_DEP);
74         if (extras != null) {
75             mHiLayerResponse = extras.getByteArray(EXTRA_HI_LAYER_RESP);
76             mHistBytes = extras.getByteArray(EXTRA_HIST_BYTES);
77         }
78     }
79 
80     /**
81      * Set the timeout of {@link #transceive} in milliseconds.
82      * <p>The timeout only applies to ISO-DEP {@link #transceive}, and is
83      * reset to a default value when {@link #close} is called.
84      * <p>Setting a longer timeout may be useful when performing
85      * transactions that require a long processing time on the tag
86      * such as key generation.
87      *
88      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
89      *
90      * @param timeout timeout value in milliseconds
91      */
setTimeout(int timeout)92     public void setTimeout(int timeout) {
93         try {
94             int err = mTag.getTagService().setTimeout(TagTechnology.ISO_DEP, timeout);
95             if (err != ErrorCodes.SUCCESS) {
96                 throw new IllegalArgumentException("The supplied timeout is not valid");
97             }
98         } catch (RemoteException e) {
99             Log.e(TAG, "NFC service dead", e);
100         }
101     }
102 
103     /**
104      * Get the current timeout for {@link #transceive} in milliseconds.
105      *
106      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
107      *
108      * @return timeout value in milliseconds
109      */
getTimeout()110     public int getTimeout() {
111         try {
112             return mTag.getTagService().getTimeout(TagTechnology.ISO_DEP);
113         } catch (RemoteException e) {
114             Log.e(TAG, "NFC service dead", e);
115             return 0;
116         }
117     }
118 
119     /**
120      * Return the ISO-DEP historical bytes for {@link NfcA} tags.
121      * <p>Does not cause any RF activity and does not block.
122      * <p>The historical bytes can be used to help identify a tag. They are present
123      * only on {@link IsoDep} tags that are based on {@link NfcA} RF technology.
124      * If this tag is not {@link NfcA} then null is returned.
125      * <p>In ISO 14443-4 terminology, the historical bytes are a subset of the RATS
126      * response.
127      *
128      * @return ISO-DEP historical bytes, or null if this is not a {@link NfcA} tag
129      */
getHistoricalBytes()130     public byte[] getHistoricalBytes() {
131         return mHistBytes;
132     }
133 
134     /**
135      * Return the higher layer response bytes for {@link NfcB} tags.
136      * <p>Does not cause any RF activity and does not block.
137      * <p>The higher layer response bytes can be used to help identify a tag.
138      * They are present only on {@link IsoDep} tags that are based on {@link NfcB}
139      * RF technology. If this tag is not {@link NfcB} then null is returned.
140      * <p>In ISO 14443-4 terminology, the higher layer bytes are a subset of the
141      * ATTRIB response.
142      *
143      * @return ISO-DEP historical bytes, or null if this is not a {@link NfcB} tag
144      */
getHiLayerResponse()145     public byte[] getHiLayerResponse() {
146         return mHiLayerResponse;
147     }
148 
149     /**
150      * Send raw ISO-DEP data to the tag and receive the response.
151      *
152      * <p>Applications must only send the INF payload, and not the start of frame and
153      * end of frame indicators. Applications do not need to fragment the payload, it
154      * will be automatically fragmented and defragmented by {@link #transceive} if
155      * it exceeds FSD/FSC limits.
156      *
157      * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum number of bytes
158      * that can be sent with {@link #transceive}.
159      *
160      * <p>This is an I/O operation and will block until complete. It must
161      * not be called from the main application thread. A blocked call will be canceled with
162      * {@link IOException} if {@link #close} is called from another thread.
163      *
164      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
165      *
166      * @param data command bytes to send, must not be null
167      * @return response bytes received, will not be null
168      * @throws TagLostException if the tag leaves the field
169      * @throws IOException if there is an I/O failure, or this operation is canceled
170      */
transceive(byte[] data)171     public byte[] transceive(byte[] data) throws IOException {
172         return transceive(data, true);
173     }
174 
175     /**
176      * Return the maximum number of bytes that can be sent with {@link #transceive}.
177      * @return the maximum number of bytes that can be sent with {@link #transceive}.
178      */
getMaxTransceiveLength()179     public int getMaxTransceiveLength() {
180         return getMaxTransceiveLengthInternal();
181     }
182 
183     /**
184      * <p>Standard APDUs have a 1-byte length field, allowing a maximum of
185      * 255 payload bytes, which results in a maximum APDU length of 261 bytes.
186      *
187      * <p>Extended length APDUs have a 3-byte length field, allowing 65535
188      * payload bytes.
189      *
190      * <p>Some NFC adapters, like the one used in the Nexus S and the Galaxy Nexus
191      * do not support extended length APDUs. They are expected to be well-supported
192      * in the future though. Use this method to check for extended length APDU
193      * support.
194      *
195      * @return whether the NFC adapter on this device supports extended length APDUs.
196      */
isExtendedLengthApduSupported()197     public boolean isExtendedLengthApduSupported() {
198         try {
199             return mTag.getTagService().getExtendedLengthApdusSupported();
200         } catch (RemoteException e) {
201             Log.e(TAG, "NFC service dead", e);
202             return false;
203         }
204     }
205 }
206