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 NFC-A (ISO 14443-3A) properties and I/O operations on a {@link Tag}.
29  *
30  * <p>Acquire a {@link NfcA} object using {@link #get}.
31  * <p>The primary NFC-A I/O operation is {@link #transceive}. Applications must
32  * implement their own protocol stack on top of {@link #transceive}.
33  *
34  * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
35  * require the {@link android.Manifest.permission#NFC} permission.
36  */
37 public final class NfcA extends BasicTagTechnology {
38     private static final String TAG = "NFC";
39 
40     /** @hide */
41     public static final String EXTRA_SAK = "sak";
42     /** @hide */
43     public static final String EXTRA_ATQA = "atqa";
44 
45     private short mSak;
46     private byte[] mAtqa;
47 
48     /**
49      * Get an instance of {@link NfcA} for the given tag.
50      * <p>Returns null if {@link NfcA} was not enumerated in {@link Tag#getTechList}.
51      * This indicates the tag does not support NFC-A.
52      * <p>Does not cause any RF activity and does not block.
53      *
54      * @param tag an NFC-A compatible tag
55      * @return NFC-A object
56      */
get(Tag tag)57     public static NfcA get(Tag tag) {
58         if (!tag.hasTech(TagTechnology.NFC_A)) return null;
59         try {
60             return new NfcA(tag);
61         } catch (RemoteException e) {
62             return null;
63         }
64     }
65 
66     /** @hide */
NfcA(Tag tag)67     public NfcA(Tag tag) throws RemoteException {
68         super(tag, TagTechnology.NFC_A);
69         Bundle extras = tag.getTechExtras(TagTechnology.NFC_A);
70         mSak = extras.getShort(EXTRA_SAK);
71         mAtqa = extras.getByteArray(EXTRA_ATQA);
72     }
73 
74     /**
75      * Return the ATQA/SENS_RES bytes from tag discovery.
76      *
77      * <p>Does not cause any RF activity and does not block.
78      *
79      * @return ATQA/SENS_RES bytes
80      */
getAtqa()81     public byte[] getAtqa() {
82         return mAtqa;
83     }
84 
85     /**
86      * Return the SAK/SEL_RES bytes from tag discovery.
87      *
88      * <p>Does not cause any RF activity and does not block.
89      *
90      * @return SAK bytes
91      */
getSak()92     public short getSak() {
93         return mSak;
94     }
95 
96     /**
97      * Send raw NFC-A commands to the tag and receive the response.
98      *
99      * <p>Applications must not append the EoD (CRC) to the payload,
100      * it will be automatically calculated.
101      * <p>Applications must only send commands that are complete bytes,
102      * for example a SENS_REQ is not possible (these are used to
103      * manage tag polling and initialization).
104      *
105      * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum number of bytes
106      * that can be sent with {@link #transceive}.
107      *
108      * <p>This is an I/O operation and will block until complete. It must
109      * not be called from the main application thread. A blocked call will be canceled with
110      * {@link IOException} if {@link #close} is called from another thread.
111      *
112      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
113      *
114      * @param data bytes to send
115      * @return bytes received in response
116      * @throws TagLostException if the tag leaves the field
117      * @throws IOException if there is an I/O failure, or this operation is canceled
118      */
transceive(byte[] data)119     public byte[] transceive(byte[] data) throws IOException {
120         return transceive(data, true);
121     }
122 
123     /**
124      * Return the maximum number of bytes that can be sent with {@link #transceive}.
125      * @return the maximum number of bytes that can be sent with {@link #transceive}.
126      */
getMaxTransceiveLength()127     public int getMaxTransceiveLength() {
128         return getMaxTransceiveLengthInternal();
129     }
130 
131     /**
132      * Set the {@link #transceive} timeout in milliseconds.
133      *
134      * <p>The timeout only applies to {@link #transceive} on this object,
135      * and is reset to a default value when {@link #close} is called.
136      *
137      * <p>Setting a longer timeout may be useful when performing
138      * transactions that require a long processing time on the tag
139      * such as key generation.
140      *
141      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
142      *
143      * @param timeout timeout value in milliseconds
144      */
setTimeout(int timeout)145     public void setTimeout(int timeout) {
146         try {
147             int err = mTag.getTagService().setTimeout(TagTechnology.NFC_A, timeout);
148             if (err != ErrorCodes.SUCCESS) {
149                 throw new IllegalArgumentException("The supplied timeout is not valid");
150             }
151         } catch (RemoteException e) {
152             Log.e(TAG, "NFC service dead", e);
153         }
154     }
155 
156     /**
157      * Get the current {@link #transceive} timeout in milliseconds.
158      *
159      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
160      *
161      * @return timeout value in milliseconds
162      */
getTimeout()163     public int getTimeout() {
164         try {
165             return mTag.getTagService().getTimeout(TagTechnology.NFC_A);
166         } catch (RemoteException e) {
167             Log.e(TAG, "NFC service dead", e);
168             return 0;
169         }
170     }
171 }
172