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