Home | History | Annotate | Download | only in tech
      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      */
     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 */
     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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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