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      * @throws SecurityException if the tag object is reused after the tag has left the field
92      */
setTimeout(int timeout)93     public void setTimeout(int timeout) {
94         try {
95             int err = mTag.getTagService().setTimeout(TagTechnology.ISO_DEP, timeout);
96             if (err != ErrorCodes.SUCCESS) {
97                 throw new IllegalArgumentException("The supplied timeout is not valid");
98             }
99         } catch (RemoteException e) {
100             Log.e(TAG, "NFC service dead", e);
101         }
102     }
103 
104     /**
105      * Get the current timeout for {@link #transceive} in milliseconds.
106      *
107      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
108      *
109      * @return timeout value in milliseconds
110      * @throws SecurityException if the tag object is reused after the tag has left the field
111      */
getTimeout()112     public int getTimeout() {
113         try {
114             return mTag.getTagService().getTimeout(TagTechnology.ISO_DEP);
115         } catch (RemoteException e) {
116             Log.e(TAG, "NFC service dead", e);
117             return 0;
118         }
119     }
120 
121     /**
122      * Return the ISO-DEP historical bytes for {@link NfcA} tags.
123      * <p>Does not cause any RF activity and does not block.
124      * <p>The historical bytes can be used to help identify a tag. They are present
125      * only on {@link IsoDep} tags that are based on {@link NfcA} RF technology.
126      * If this tag is not {@link NfcA} then null is returned.
127      * <p>In ISO 14443-4 terminology, the historical bytes are a subset of the RATS
128      * response.
129      *
130      * @return ISO-DEP historical bytes, or null if this is not a {@link NfcA} tag
131      */
getHistoricalBytes()132     public byte[] getHistoricalBytes() {
133         return mHistBytes;
134     }
135 
136     /**
137      * Return the higher layer response bytes for {@link NfcB} tags.
138      * <p>Does not cause any RF activity and does not block.
139      * <p>The higher layer response bytes can be used to help identify a tag.
140      * They are present only on {@link IsoDep} tags that are based on {@link NfcB}
141      * RF technology. If this tag is not {@link NfcB} then null is returned.
142      * <p>In ISO 14443-4 terminology, the higher layer bytes are a subset of the
143      * ATTRIB response.
144      *
145      * @return ISO-DEP historical bytes, or null if this is not a {@link NfcB} tag
146      */
getHiLayerResponse()147     public byte[] getHiLayerResponse() {
148         return mHiLayerResponse;
149     }
150 
151     /**
152      * Send raw ISO-DEP data to the tag and receive the response.
153      *
154      * <p>Applications must only send the INF payload, and not the start of frame and
155      * end of frame indicators. Applications do not need to fragment the payload, it
156      * will be automatically fragmented and defragmented by {@link #transceive} if
157      * it exceeds FSD/FSC limits.
158      *
159      * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum number of bytes
160      * that can be sent with {@link #transceive}.
161      *
162      * <p>This is an I/O operation and will block until complete. It must
163      * not be called from the main application thread. A blocked call will be canceled with
164      * {@link IOException} if {@link #close} is called from another thread.
165      *
166      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
167      *
168      * @param data command bytes to send, must not be null
169      * @return response bytes received, will not be null
170      * @throws TagLostException if the tag leaves the field
171      * @throws IOException if there is an I/O failure, or this operation is canceled
172      * @throws SecurityException if the tag object is reused after the tag has left the field
173      */
transceive(byte[] data)174     public byte[] transceive(byte[] data) throws IOException {
175         return transceive(data, true);
176     }
177 
178     /**
179      * Return the maximum number of bytes that can be sent with {@link #transceive}.
180      * @return the maximum number of bytes that can be sent with {@link #transceive}.
181      */
getMaxTransceiveLength()182     public int getMaxTransceiveLength() {
183         return getMaxTransceiveLengthInternal();
184     }
185 
186     /**
187      * <p>Standard APDUs have a 1-byte length field, allowing a maximum of
188      * 255 payload bytes, which results in a maximum APDU length of 261 bytes.
189      *
190      * <p>Extended length APDUs have a 3-byte length field, allowing 65535
191      * payload bytes.
192      *
193      * <p>Some NFC adapters, like the one used in the Nexus S and the Galaxy Nexus
194      * do not support extended length APDUs. They are expected to be well-supported
195      * in the future though. Use this method to check for extended length APDU
196      * support.
197      *
198      * @return whether the NFC adapter on this device supports extended length APDUs.
199      * @throws SecurityException if the tag object is reused after the tag has left the field
200      */
isExtendedLengthApduSupported()201     public boolean isExtendedLengthApduSupported() {
202         try {
203             return mTag.getTagService().getExtendedLengthApdusSupported();
204         } catch (RemoteException e) {
205             Log.e(TAG, "NFC service dead", e);
206             return false;
207         }
208     }
209 }
210