diff options
author | Nick Pelly <npelly@google.com> | 2011-02-02 22:37:40 -0800 |
---|---|---|
committer | Nick Pelly <npelly@google.com> | 2011-02-03 15:11:09 -0800 |
commit | 74fe6c6b245ebe7d3b3d96962c32980d88dca4f5 (patch) | |
tree | 20c998f629cd43db2b8f4b4a5b4849447e36b434 /core/java/android/nfc/tech | |
parent | 155b0ee0498cf863091f3f83a752eaaedf1257f8 (diff) | |
download | frameworks_base-74fe6c6b245ebe7d3b3d96962c32980d88dca4f5.zip frameworks_base-74fe6c6b245ebe7d3b3d96962c32980d88dca4f5.tar.gz frameworks_base-74fe6c6b245ebe7d3b3d96962c32980d88dca4f5.tar.bz2 |
NFC documentation overhaul.
Change-Id: I45dca95a24b2d0327e080436fbcc7b1dad79de02
Diffstat (limited to 'core/java/android/nfc/tech')
-rw-r--r-- | core/java/android/nfc/tech/IsoDep.java | 85 | ||||
-rw-r--r-- | core/java/android/nfc/tech/MifareClassic.java | 266 | ||||
-rw-r--r-- | core/java/android/nfc/tech/MifareUltralight.java | 112 | ||||
-rw-r--r-- | core/java/android/nfc/tech/Ndef.java | 154 | ||||
-rw-r--r-- | core/java/android/nfc/tech/NdefFormatable.java | 66 | ||||
-rw-r--r-- | core/java/android/nfc/tech/NfcA.java | 55 | ||||
-rw-r--r-- | core/java/android/nfc/tech/NfcB.java | 56 | ||||
-rw-r--r-- | core/java/android/nfc/tech/NfcF.java | 54 | ||||
-rw-r--r-- | core/java/android/nfc/tech/NfcV.java | 55 | ||||
-rw-r--r-- | core/java/android/nfc/tech/TagTechnology.java | 109 |
10 files changed, 711 insertions, 301 deletions
diff --git a/core/java/android/nfc/tech/IsoDep.java b/core/java/android/nfc/tech/IsoDep.java index 774982e..2a132f9 100644 --- a/core/java/android/nfc/tech/IsoDep.java +++ b/core/java/android/nfc/tech/IsoDep.java @@ -24,18 +24,14 @@ import android.util.Log; import java.io.IOException; /** - * A low-level connection to a {@link Tag} using the ISO-DEP technology, also known as - * ISO1443-4. + * Provides access to ISO-DEP (ISO 14443-4) properties and I/O operations on a {@link Tag}. * - * <p>You can acquire this kind of connection with {@link #get}. - * Use this class to send and receive data with {@link #transceive transceive()}. - * - * <p>Applications must implement their own protocol stack on top of - * {@link #transceive transceive()}. - * - * <p class="note"><strong>Note:</strong> - * Use of this class requires the {@link android.Manifest.permission#NFC} - * permission. + * <p>Acquire a {@link IsoDep} object using {@link #get}. + * <p>The primary ISO-DEP I/O operation is {@link #transceive}. Applications must + * implement their own protocol stack on top of {@link #transceive}. + * <p>Tags that enumerate the {@link IsoDep} technology in {@link Tag#getTechList} + * will also enumerate + * {@link NfcA} or {@link NfcB} (since IsoDep builds on top of either of these). */ public final class IsoDep extends BasicTagTechnology { private static final String TAG = "NFC"; @@ -49,10 +45,13 @@ public final class IsoDep extends BasicTagTechnology { private byte[] mHistBytes = null; /** - * Returns an instance of this tech for the given tag. If the tag doesn't support - * this tech type null is returned. + * Get an instance of {@link IsoDep} for the given tag. + * <p>Does not cause any RF activity and does not block. + * <p>Returns null if {@link IsoDep} was not enumerated in {@link Tag#getTechList}. + * This indicates the tag does not support ISO-DEP. * - * @param tag The tag to get the tech from + * @param tag an ISO-DEP compatible tag + * @return ISO-DEP object */ public static IsoDep get(Tag tag) { if (!tag.hasTech(TagTechnology.ISO_DEP)) return null; @@ -62,7 +61,7 @@ public final class IsoDep extends BasicTagTechnology { return null; } } - + /** @hide */ public IsoDep(Tag tag) throws RemoteException { @@ -75,13 +74,13 @@ public final class IsoDep extends BasicTagTechnology { } /** - * Sets the timeout of an IsoDep transceive transaction in milliseconds. - * If the transaction has not completed before the timeout, - * any ongoing {@link #transceive} operation will be - * aborted and the connection to the tag is lost. This setting is applied - * only to the {@link Tag} object linked to this technology and will be - * reset when {@link IsoDep#close} is called. - * The default transaction timeout is 300 milliseconds. + * Set the timeout of {@link #transceive} in milliseconds. + * <p>The timeout only applies to ISO-DEP {@link #transceive}, and is + * reset to a default value when {@link #close} is called. + * <p>Setting a longer timeout may be useful when performing + * transactions that require a long processing time on the tag + * such as key generation. + * @param timeout timeout value in milliseconds */ public void setTimeout(int timeout) { try { @@ -102,29 +101,51 @@ public final class IsoDep extends BasicTagTechnology { } /** - * Return the historical bytes if the tag is using {@link NfcA}, null otherwise. + * Return the ISO-DEP historical bytes for {@link NfcA} tags. + * <p>Does not cause any RF activity and does not block. + * <p>The historical bytes can be used to help identify a tag. They are present + * only on {@link IsoDep} tags that are based on {@link NfcA} RF technology. + * If this tag is not {@link NfcA} then null is returned. + * <p>In ISO 14443-4 terminology, the historical bytes are a subset of the RATS + * response. + * + * @return ISO-DEP historical bytes, or null if this is not a {@link NfcA} tag */ public byte[] getHistoricalBytes() { return mHistBytes; } /** - * Return the hi layer response bytes if the tag is using {@link NfcB}, null otherwise. + * Return the higher layer response bytes for {@link NfcB} tags. + * <p>Does not cause any RF activity and does not block. + * <p>The higher layer response bytes can be used to help identify a tag. + * They are present only on {@link IsoDep} tags that are based on {@link NfcB} + * RF technology. If this tag is not {@link NfcB} then null is returned. + * <p>In ISO 14443-4 terminology, the higher layer bytes are a subset of the + * ATTRIB response. + * + * @return ISO-DEP historical bytes, or null if this is not a {@link NfcB} tag */ public byte[] getHiLayerResponse() { return mHiLayerResponse; } /** - * Send data to a tag and receive the response. - * <p> - * This method will block until the response is received. It can be canceled - * with {@link #close}. - * <p>Requires {@link android.Manifest.permission#NFC} permission. + * Send raw ISO-DEP data to the tag and receive the response. + * + * <p>Applications must only send the INF payload, and not the start of frame and + * end of frame indicators. Applications do not need to fragment the payload, it + * will be automatically fragmented and defragmented by {@link #transceive} if + * it exceeds FSD/FSC limits. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. * - * @param data bytes to send - * @return bytes received in response - * @throws IOException if the target is lost or connection closed + * @param data command bytes to send, must not be null + * @return response bytes received, will not be null + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or this operation is canceled */ public byte[] transceive(byte[] data) throws IOException { return transceive(data, true); diff --git a/core/java/android/nfc/tech/MifareClassic.java b/core/java/android/nfc/tech/MifareClassic.java index d337ead..268fe95 100644 --- a/core/java/android/nfc/tech/MifareClassic.java +++ b/core/java/android/nfc/tech/MifareClassic.java @@ -25,32 +25,61 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; /** - * Technology class representing MIFARE Classic tags (also known as MIFARE Standard). + * Provides access to MIFARE Classic properties and I/O operations on a {@link Tag}. * - * <p>Support for this technology type is optional. If the NFC stack doesn't support this technology - * MIFARE Classic tags will still be scanned, but will only show the NfcA technology. + * <p>Acquire a {@link MifareClassic} object using {@link #get}. * - * <p>MIFARE Classic tags have sectors that each contain blocks. The block size is constant at - * 16 bytes, but the number of sectors and the sector size varies by product. MIFARE has encryption - * built in and each sector has two keys associated with it, as well as ACLs to determine what - * level acess each key grants. Before operating on a sector you must call either - * {@link #authenticateSectorWithKeyA(int, byte[])} or - * {@link #authenticateSectorWithKeyB(int, byte[])} to gain authorization for your request. + * <p>MIFARE Classic is also known as MIFARE Standard. + * <p>MIFARE Classic tags are divided into sectors, and each sector is sub-divided into + * blocks. Block size is always 16 bytes ({@link #BLOCK_SIZE}. Sector size varies. + * <ul> + * <li>MIFARE Classic Mini are 320 bytes ({@link #SIZE_MINI}), with 5 sectors each of 4 blocks. + * <li>MIFARE Classic 1k are 1024 bytes ({@link #SIZE_1K}), with 16 sectors each of 4 blocks. + * <li>MIFARE Classic 2k are 2048 bytes ({@link #SIZE_2K}), with 32 sectors each of 4 blocks. + * <li>MIFARE Classic 4k} are 4096 bytes ({@link #SIZE_4K}). The first 32 sectors contain 4 blocks + * and the last 8 sectors contain 16 blocks. + * </ul> + * + * <p>MIFARE Classic tags require authentication on a per-sector basis before any + * other I/O operations on that sector can be performed. There are two keys per sector, + * and ACL bits determine what I/O operations are allowed on that sector after + * authenticating with a key. {@see #authenticateSectorWithKeyA} and + * {@see #authenticateSectorWithKeyB}. + * + * <p>Three well-known authentication keys are defined in this class: + * {@link #KEY_DEFAULT}, {@link #KEY_MIFARE_APPLICATION_DIRECTORY}, + * {@link #KEY_NFC_FORUM}. + * <ul> + * <li>{@link #KEY_DEFAULT} is the default factory key for MIFARE Classic. + * <li>{@link #KEY_MIFARE_APPLICATION_DIRECTORY} is the well-known key for + * MIFARE Classic cards that have been formatted according to the + * MIFARE Application Directory (MAD) specification. + * <li>{@link #KEY_NFC_FORUM} is the well-known key for MIFARE Classic cards that + * have been formatted according to the NFC + * + * <p>Implementation of this class on a Android NFC device is optional. + * If it is not implemented, then + * {@link MifareClassic} will never be enumerated in {@link Tag#getTechList}. + * If it is enumerated, then all {@link MifareClassic} I/O operations will be supported, + * and {@link Ndef#MIFARE_CLASSIC} NDEF tags will also be supported. In either case, + * {@link NfcA} will also be enumerated on the tag, because all MIFARE Classic tags are also + * {@link NfcA}. */ public final class MifareClassic extends BasicTagTechnology { /** - * The well-known default MIFARE read key. All keys are set to this at the factory. - * Using this key will effectively make the payload in the sector public. + * The default factory key. */ public static final byte[] KEY_DEFAULT = {(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF}; /** - * The well-known, default MIFARE Application Directory read key. + * The well-known key for tags formatted according to the + * MIFARE Application Directory (MAD) specification. */ public static final byte[] KEY_MIFARE_APPLICATION_DIRECTORY = {(byte)0xA0,(byte)0xA1,(byte)0xA2,(byte)0xA3,(byte)0xA4,(byte)0xA5}; /** - * The well-known, default read key for NDEF data on a MIFARE Classic + * The well-known key for tags formatted according to the + * NDEF on Mifare Classic specification. */ public static final byte[] KEY_NFC_FORUM = {(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7}; @@ -64,19 +93,19 @@ public final class MifareClassic extends BasicTagTechnology { /** A MIFARE Pro tag */ public static final int TYPE_PRO = 2; - /** The tag contains 16 sectors, each holding 4 blocks. */ + /** Tag contains 16 sectors, each with 4 blocks. */ public static final int SIZE_1K = 1024; - /** The tag contains 32 sectors, each holding 4 blocks. */ + /** Tag contains 32 sectors, each with 4 blocks. */ public static final int SIZE_2K = 2048; /** - * The tag contains 40 sectors. The first 32 sectors contain 4 blocks and the last 8 sectors + * Tag contains 40 sectors. The first 32 sectors contain 4 blocks and the last 8 sectors * contain 16 blocks. */ public static final int SIZE_4K = 4096; - /** The tag contains 5 sectors, each holding 4 blocks. */ + /** Tag contains 5 sectors, each with 4 blocks. */ public static final int SIZE_MINI = 320; - /** Size of a Mifare Classic block (in bytes) */ + /** Size of a MIFARE Classic block (in bytes) */ public static final int BLOCK_SIZE = 16; private static final int MAX_BLOCK_COUNT = 256; @@ -87,10 +116,14 @@ public final class MifareClassic extends BasicTagTechnology { private int mSize; /** - * Returns an instance of this tech for the given tag. If the tag doesn't support - * this tech type null is returned. + * Get an instance of {@link MifareClassic} for the given tag. + * <p>Does not cause any RF activity and does not block. + * <p>Returns null if {@link MifareClassic} was not enumerated in {@link Tag#getTechList}. + * This indicates the tag is not MIFARE Classic compatible, or this Android + * device does not support MIFARE Classic. * - * @param tag The tag to get the tech from + * @param tag an MIFARE Classic compatible tag + * @return MIFARE Classic object */ public static MifareClassic get(Tag tag) { if (!tag.hasTech(TagTechnology.MIFARE_CLASSIC)) return null; @@ -160,17 +193,31 @@ public final class MifareClassic extends BasicTagTechnology { } } - /** Returns the type of the tag, determined at discovery time */ + /** + * Return the type of this MIFARE Classic compatible tag. + * <p>One of {@link #TYPE_UNKNOWN}, {@link #TYPE_CLASSIC}, {@link #TYPE_PLUS} or + * {@link #TYPE_PRO}. + * <p>Does not cause any RF activity and does not block. + * + * @return type + */ public int getType() { return mType; } - /** Returns the size of the tag in bytes, determined at discovery time */ + /** + * Return the size of the tag in bytes + * <p>One of {@link #SIZE_MINI}, {@link #SIZE_1K}, {@link #SIZE_2K}, {@link #SIZE_4K}. + * These constants are equal to their respective size in bytes. + * <p>Does not cause any RF activity and does not block. + * @return size in bytes + */ public int getSize() { return mSize; } - /** Returns true if the tag is emulated, determined at discovery time. + /** + * Return true if the tag is emulated, determined at discovery time. * These are actually smart-cards that emulate a Mifare Classic interface. * They can be treated identically to a Mifare Classic tag. * @hide @@ -179,7 +226,11 @@ public final class MifareClassic extends BasicTagTechnology { return mIsEmulated; } - /** Returns the number of sectors on this tag, determined at discovery time */ + /** + * Return the number of MIFARE Classic sectors. + * <p>Does not cause any RF activity and does not block. + * @return number of sectors + */ public int getSectorCount() { switch (mSize) { case SIZE_1K: @@ -195,12 +246,21 @@ public final class MifareClassic extends BasicTagTechnology { } } - /** Returns the total block count, determined at discovery time */ + /** + * Return the total number of MIFARE Classic blocks. + * <p>Does not cause any RF activity and does not block. + * @return total number of blocks public int getBlockCount() { return mSize / BLOCK_SIZE; } - /** Returns the block count for the given sector, determined at discovery time */ + /** + * Return the number of blocks in the given sector. + * <p>Does not cause any RF activity and does not block. + * + * @param sectorIndex index of sector, starting from 0 + * @return number of blocks in the sector + */ public int getBlockCountInSector(int sectorIndex) { validateSector(sectorIndex); @@ -211,7 +271,13 @@ public final class MifareClassic extends BasicTagTechnology { } } - /** Return the sector index of a given block */ + /** + * Return the sector that contains a given block. + * <p>Does not cause any RF activity and does not block. + * + * @param blockIndex index of block to lookup, starting from 0 + * @return sector index that contains the block + */ public int blockToSector(int blockIndex) { validateBlock(blockIndex); @@ -222,7 +288,13 @@ public final class MifareClassic extends BasicTagTechnology { } } - /** Return the first block of a given sector */ + /** + * Return the first block of a given sector. + * <p>Does not cause any RF activity and does not block. + * + * @param sectorIndex index of sector to lookup, starting from 0 + * @return block index of first block in sector + */ public int sectorToBlock(int sectorIndex) { if (sectorIndex < 32) { return sectorIndex * 4; @@ -231,22 +303,51 @@ public final class MifareClassic extends BasicTagTechnology { } } - // Methods that require connect() /** - * Authenticate a sector. - * <p>Every sector has an A and B key with different access privileges, - * this method attempts to authenticate against the A key. - * <p>This requires a that the tag be connected. + * Authenticate a sector with key A. + * + * <p>Successful authentication of a sector with key A enables other + * I/O operations on that sector. The set of operations granted by key A + * key depends on the ACL bits set in that sector. For more information + * see the MIFARE Classic specification on {@see http://www.nxp.com}. + * + * <p>A failed authentication attempt causes an implicit reconnection to the + * tag, so authentication to other sectors will be lost. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param sectorIndex index of sector to authenticate, starting from 0 + * @param key 6-byte authentication key + * @return true on success, false on authentication failure + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled */ public boolean authenticateSectorWithKeyA(int sectorIndex, byte[] key) throws IOException { return authenticate(sectorIndex, key, true); } /** - * Authenticate a sector. - * <p>Every sector has an A and B key with different access privileges, - * this method attempts to authenticate against the B key. - * <p>This requires a that the tag be connected. + * Authenticate a sector with key B. + * + * <p>Successful authentication of a sector with key B enables other + * I/O operations on that sector. The set of operations granted by key B + * depends on the ACL bits set in that sector. For more information + * see the MIFARE Classic specification on {@see http://www.nxp.com}. + * + * <p>A failed authentication attempt causes an implicit reconnection to the + * tag, so authentication to other sectors will be lost. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param sectorIndex index of sector to authenticate, starting from 0 + * @param key 6-byte authentication key + * @return true on success, false on authentication failure + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled */ public boolean authenticateSectorWithKeyB(int sectorIndex, byte[] key) throws IOException { return authenticate(sectorIndex, key, false); @@ -291,8 +392,15 @@ public final class MifareClassic extends BasicTagTechnology { /** * Read 16-byte block. - * <p>This requires a that the tag be connected. - * @throws IOException + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param blockIndex index of block to read, starting from 0 + * @return 16 byte block + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled */ public byte[] readBlock(int blockIndex) throws IOException { validateBlock(blockIndex); @@ -304,8 +412,15 @@ public final class MifareClassic extends BasicTagTechnology { /** * Write 16-byte block. - * <p>This requires a that the tag be connected. - * @throws IOException + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param blockIndex index of block to write, starting from 0 + * @param data 16 bytes of data to write + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled */ public void writeBlock(int blockIndex, byte[] data) throws IOException { validateBlock(blockIndex); @@ -323,9 +438,16 @@ public final class MifareClassic extends BasicTagTechnology { } /** - * Increment a value block, and store the result in temporary memory. - * @param blockIndex - * @throws IOException + * Increment a value block, storing the result in the temporary block on the tag. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param blockIndex index of block to increment, starting from 0 + * @param value non-negative to increment by + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled */ public void increment(int blockIndex, int value) throws IOException { validateBlock(blockIndex); @@ -342,9 +464,16 @@ public final class MifareClassic extends BasicTagTechnology { } /** - * Decrement a value block, and store the result in temporary memory. - * @param blockIndex - * @throws IOException + * Decrement a value block, storing the result in the temporary block on the tag. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param blockIndex index of block to decrement, starting from 0 + * @param value non-negative to decrement by + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled */ public void decrement(int blockIndex, int value) throws IOException { validateBlock(blockIndex); @@ -361,9 +490,15 @@ public final class MifareClassic extends BasicTagTechnology { } /** - * Copy from temporary memory to value block. - * @param blockIndex - * @throws IOException + * Copy from the temporary block to a value block. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param blockIndex index of block to copy to + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled */ public void transfer(int blockIndex) throws IOException { validateBlock(blockIndex); @@ -375,9 +510,15 @@ public final class MifareClassic extends BasicTagTechnology { } /** - * Copy from value block to temporary memory. - * @param blockIndex - * @throws IOException + * Copy from a value block to the temporary block. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param blockIndex index of block to copy from + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled */ public void restore(int blockIndex) throws IOException { validateBlock(blockIndex); @@ -390,15 +531,16 @@ public final class MifareClassic extends BasicTagTechnology { /** * Send raw NfcA data to a tag and receive the response. - * <p> - * This method will block until the response is received. It can be canceled - * with {@link #close}. - * <p>Requires {@link android.Manifest.permission#NFC} permission. - * <p>This requires a that the tag be connected. * - * @param data bytes to send - * @return bytes received in response - * @throws IOException if the target is lost or connection closed + * <p>This is equivalent to connecting to this tag via {@link NfcA} + * and calling {@link NfcA#transceive}. Note that all MIFARE Classic + * tags are based on {@link NfcA} technology. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @see NfcA#transceive */ public byte[] transceive(byte[] data) throws IOException { return transceive(data, true); diff --git a/core/java/android/nfc/tech/MifareUltralight.java b/core/java/android/nfc/tech/MifareUltralight.java index b514f1c..5971708 100644 --- a/core/java/android/nfc/tech/MifareUltralight.java +++ b/core/java/android/nfc/tech/MifareUltralight.java @@ -17,6 +17,7 @@ package android.nfc.tech; import android.nfc.Tag; +import android.nfc.TagLostException; import android.os.RemoteException; import java.io.IOException; @@ -24,14 +25,13 @@ import java.io.IOException; //TOOD: Ultralight C 3-DES authentication, one-way counter /** - * Technology class representing MIFARE Ultralight and MIFARE Ultralight C tags. + * Provides access to MIFARE Ultralight properties and I/O operations on a {@link Tag}. * - * <p>Support for this technology type is optional. If the NFC stack doesn't support this technology - * MIFARE Ultralight class tags will still be scanned, but will only show the NfcA technology. + * <p>Acquire a {@link MifareUltralight} object using {@link #get}. * - * <p>MIFARE Ultralight compatible tags have 4 byte pages. The read command - * returns 4 pages (16 bytes) at a time, for speed. The write command operates - * on a single page (4 bytes) to minimize EEPROM write cycles. + * <p>MIFARE Ultralight compatible tags have 4 byte pages {@link #PAGE_SIZE}. + * The primary operations on an Ultralight tag are {@link #readPages} and + * {@link #writePage}. * * <p>The original MIFARE Ultralight consists of a 64 byte EEPROM. The first * 4 pages are for the OTP area, manufacturer data, and locking bits. They are @@ -44,6 +44,13 @@ import java.io.IOException; * and authentication configuration and are readable. The final 4 pages are for * the authentication key and are not readable. For more information see the * NXP data sheet MF0ICU2. + * + * <p>Implementation of this class on a Android NFC device is optional. + * If it is not implemented, then + * {@link MifareUltralight} will never be enumerated in {@link Tag#getTechList}. + * If it is enumerated, then all {@link MifareUltralight} I/O operations will be supported. + * In either case, {@link NfcA} will also be enumerated on the tag, + * because all MIFARE Ultralight tags are also {@link NfcA} tags. */ public final class MifareUltralight extends BasicTagTechnology { /** A MIFARE Ultralight compatible tag of unknown type */ @@ -62,10 +69,15 @@ public final class MifareUltralight extends BasicTagTechnology { private int mType; /** - * Returns an instance of this tech for the given tag. If the tag doesn't support - * this tech type null is returned. + * Get an instance of {@link MifareUltralight} for the given tag. + * <p>Returns null if {@link MifareUltralight} was not enumerated in + * {@link Tag#getTechList} - this indicates the tag is not MIFARE + * Ultralight compatible, or that this Android + * device does not implement MIFARE Ultralight. + * <p>Does not cause any RF activity and does not block. * - * @param tag The tag to get the tech from + * @param tag an MIFARE Ultralight compatible tag + * @return MIFARE Ultralight object */ public static MifareUltralight get(Tag tag) { if (!tag.hasTech(TagTechnology.MIFARE_ULTRALIGHT)) return null; @@ -93,53 +105,72 @@ public final class MifareUltralight extends BasicTagTechnology { } } - /** Returns the type of the tag. - * <p>It is very hard to always accurately classify a MIFARE Ultralight - * compatible tag as Ultralight original or Ultralight C. So consider - * {@link #getType} a hint. */ + /** + * Return the MIFARE Ultralight type of the tag. + * <p>One of {@link #TYPE_ULTRALIGHT} or {@link #TYPE_ULTRALIGHT_C} or + * {@link #TYPE_UNKNOWN}. + * <p>Depending on how the tag has been formatted, it can be impossible + * to accurately classify between original MIFARE Ultralight and + * Ultralight C. So treat this method as a hint. + * <p>Does not cause any RF activity and does not block. + * + * @return the type + */ public int getType() { return mType; } - // Methods that require connect() /** * Read 4 pages (16 bytes). - * <p>The MIFARE Ultralight protocol always reads 4 pages at a time. - * <p>If the read spans past the last readable block, then the tag will + * + * <p>The MIFARE Ultralight protocol always reads 4 pages at a time, to + * reduce the number of commands required to read an entire tag. + * <p>If a read spans past the last readable block, then the tag will * return pages that have been wrapped back to the first blocks. MIFARE * Ultralight tags have readable blocks 0x00 through 0x0F. So a read to * block offset 0x0E would return blocks 0x0E, 0x0F, 0x00, 0x01. MIFARE * Ultralight C tags have readable blocks 0x00 through 0x2B. So a read to * block 0x2A would return blocks 0x2A, 0x2B, 0x00, 0x01. - * <p>This requires that the tag be connected. * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param pageIndex index of first page to read, starting from 0 * @return 4 pages (16 bytes) - * @throws IOException + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled */ - public byte[] readPages(int pageOffset) throws IOException { - validatePageOffset(pageOffset); + public byte[] readPages(int pageIndex) throws IOException { + validatePageIndex(pageIndex); checkConnected(); - byte[] cmd = { 0x30, (byte) pageOffset}; + byte[] cmd = { 0x30, (byte) pageIndex}; return transceive(cmd, false); } /** * Write 1 page (4 bytes). - * <p>The MIFARE Ultralight protocol always writes 1 page at a time. - * <p>This requires that the tag be connected. * - * @param pageOffset The offset of the page to write - * @param data The data to write - * @throws IOException + * <p>The MIFARE Ultralight protocol always writes 1 page at a time, to + * minimize EEPROM write cycles. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param pageIndex index of page to write, starting from 0 + * @param data 4 bytes to write + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled */ - public void writePage(int pageOffset, byte[] data) throws IOException { - validatePageOffset(pageOffset); + public void writePage(int pageIndex, byte[] data) throws IOException { + validatePageIndex(pageIndex); checkConnected(); byte[] cmd = new byte[data.length + 2]; cmd[0] = (byte) 0xA2; - cmd[1] = (byte) pageOffset; + cmd[1] = (byte) pageIndex; System.arraycopy(data, 0, cmd, 2, data.length); transceive(cmd, false); @@ -147,28 +178,29 @@ public final class MifareUltralight extends BasicTagTechnology { /** * Send raw NfcA data to a tag and receive the response. - * <p> - * This method will block until the response is received. It can be canceled - * with {@link #close}. - * <p>Requires {@link android.Manifest.permission#NFC} permission. - * <p>This requires a that the tag be connected. * - * @param data bytes to send - * @return bytes received in response - * @throws IOException if the target is lost or connection closed + * <p>This is equivalent to connecting to this tag via {@link NfcA} + * and calling {@link NfcA#transceive}. Note that all MIFARE Classic + * tags are based on {@link NfcA} technology. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @see NfcA#transceive */ public byte[] transceive(byte[] data) throws IOException { return transceive(data, true); } - private static void validatePageOffset(int pageOffset) { + private static void validatePageIndex(int pageIndex) { // Do not be too strict on upper bounds checking, since some cards // may have more addressable memory than they report. // Note that issuing a command to an out-of-bounds block is safe - the // tag will wrap the read to an addressable area. This validation is a // helper to guard against obvious programming mistakes. - if (pageOffset < 0 || pageOffset >= MAX_PAGE_COUNT) { - throw new IndexOutOfBoundsException("page out of bounds: " + pageOffset); + if (pageIndex < 0 || pageIndex >= MAX_PAGE_COUNT) { + throw new IndexOutOfBoundsException("page out of bounds: " + pageIndex); } } } diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java index 39ff282..0467473 100644 --- a/core/java/android/nfc/tech/Ndef.java +++ b/core/java/android/nfc/tech/Ndef.java @@ -22,6 +22,7 @@ import android.nfc.INfcTag; import android.nfc.NdefMessage; import android.nfc.NfcAdapter; import android.nfc.Tag; +import android.nfc.TagLostException; import android.os.Bundle; import android.os.RemoteException; import android.util.Log; @@ -29,11 +30,41 @@ import android.util.Log; import java.io.IOException; /** - * A high-level connection to a {@link Tag} using one of the NFC type 1, 2, 3, or 4 technologies - * to interact with NDEF data. MiFare Classic cards that present NDEF data may also be used - * via this class. To determine the exact technology being used call {@link #getType()} + * Provides access to NDEF content and operations on a {@link Tag}. * - * <p>You can acquire this kind of connection with {@link #get}. + * <p>Acquire a {@link Ndef} object using {@link #get}. + * + * <p>NDEF is an NFC Forum data format. The data formats are implemented in + * {@link android.nfc.NdefMessage} and + * {@link android.nfc.NdefRecord}. This class provides methods to + * retrieve and modify the {@link android.nfc.NdefMessage} + * on a tag. + * + * <p>There are currently four NFC Forum standardized tag types that can be + * formatted to contain NDEF data. + * <ul> + * <li>NFC Forum Type 1 Tag ({@link #NFC_FORUM_TYPE_1}), such as the Innovision Topaz + * <li>NFC Forum Type 2 Tag ({@link #NFC_FORUM_TYPE_2}), such as the NXP Mifare Ultralight + * <li>NFC Forum Type 3 Tag ({@link #NFC_FORUM_TYPE_3}), such as Sony Felica + * <li>NFC Forum Type 4 Tag ({@link #NFC_FORUM_TYPE_4}), such as NXP MIFARE Desfire + * </ul> + * It is mandatory for all Android devices with NFC to correctly enumerate + * {@link Ndef} on NFC Forum Tag Types 1-4, and implement all NDEF operations + * as defined in this class. + * + * <p>Some vendors have there own well defined specifications for storing NDEF data + * on tags that do not fall into the above categories. Android devices with NFC + * should enumerate and implement {@link Ndef} under these vendor specifications + * where possible, but it is not mandatory. {@link #getType} returns a String + * describing this specification, for example {@link #MIFARE_CLASSIC} is + * <code>com.nxp.ndef.mifareclassic</code>. + * + * <p>Android devices that support MIFARE Classic must also correctly + * implement {@link Ndef} on MIFARE Classic tags formatted to NDEF. + * + * <p>For guaranteed compatibility across all Android devices with NFC, it is + * recommended to use NFC Forum Types 1-4 in new deployments of NFC tags + * with NDEF payload. Vendor NDEF formats will not work on all Android devices. * * <p class="note"><strong>Note:</strong> * Use of this class requires the {@link android.Manifest.permission#NFC} @@ -77,14 +108,15 @@ public final class Ndef extends BasicTagTechnology { /** @hide */ public static final String UNKNOWN = "android.ndef.unknown"; + /** NFC Forum Tag Type 1 */ public static final String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1"; - + /** NFC Forum Tag Type 2 */ public static final String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2"; - + /** NFC Forum Tag Type 4 */ public static final String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3"; - + /** NFC Forum Tag Type 4 */ public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4"; - + /** NDEF on MIFARE Classic */ public static final String MIFARE_CLASSIC = "com.nxp.ndef.mifareclassic"; private final int mMaxNdefSize; @@ -93,11 +125,19 @@ public final class Ndef extends BasicTagTechnology { private final int mNdefType; /** - * Returns an instance of this tech for the given tag. If the tag doesn't support - * this tech type null is returned. + * Get an instance of {@link Ndef} for the given tag. + * + * <p>Returns null if {@link Ndef} was not enumerated in {@link Tag#getTechList}. + * This indicates the tag is not NDEF formatted, or that this tag + * is NDEF formatted but under a vendor specification that this Android + * device does not implement. * - * @param tag The tag to get the tech from + * <p>Does not cause any RF activity and does not block. + * + * @param tag an MIFARE Classic compatible tag + * @return MIFARE Classic object */ + public static Ndef get(Tag tag) { if (!tag.hasTech(TagTechnology.NDEF)) return null; try { @@ -126,22 +166,29 @@ public final class Ndef extends BasicTagTechnology { } /** - * Get the primary NDEF message on this tag. This data is read at discovery time - * and does not require a connection. + * Get the {@link NdefMessage} that was read from the tag at discovery time. + * + * <p>If the NDEF Message is modified by an I/O operation then it + * will not be updated here, this function only returns what was discovered + * when the tag entered the field. + * <p>Does not cause any RF activity and does not block. + * @return NDEF Message read from the tag at discovery time */ public NdefMessage getCachedNdefMessage() { return mNdefMsg; } /** - * Get NDEF tag type. + * Get the NDEF tag type. + * * <p>Returns one of {@link #NFC_FORUM_TYPE_1}, {@link #NFC_FORUM_TYPE_2}, * {@link #NFC_FORUM_TYPE_3}, {@link #NFC_FORUM_TYPE_4}, - * {@link #MIFARE_CLASSIC} or another NDEF tag type that is not yet in the - * Android API. - * <p>Android devices with NFC support must always correctly enumerate - * NFC Forum tag types, and may optionally enumerate - * {@link #MIFARE_CLASSIC} since it requires proprietary technology. + * {@link #MIFARE_CLASSIC} or another NDEF tag type that has not yet been + * formalized in this Android API. + * + * <p>Does not cause any RF activity and does not block. + * + * @return a string representing the NDEF tag type */ public String getType() { switch (mNdefType) { @@ -161,25 +208,44 @@ public final class Ndef extends BasicTagTechnology { } /** - * Get maximum NDEF message size in bytes + * Get the maximum NDEF message size in bytes. + * + * <p>Does not cause any RF activity and does not block. + * + * @return size in bytes */ public int getMaxSize() { return mMaxNdefSize; } /** - * Provides a hint on whether writes are likely to succeed. + * Determine if the tag is writable. + * + * <p>NFC Forum tags can be in read-only or read-write states. + * + * <p>Does not cause any RF activity and does not block. + * * <p>Requires {@link android.Manifest.permission#NFC} permission. - * @return true if write is likely to succeed + * + * @return true if the tag is writable */ public boolean isWritable() { return (mCardState == NDEF_MODE_READ_WRITE); } - // Methods that require connect() /** - * Get the primary NDEF message on this tag. This data is read actively - * and requires a connection. + * Read the current {@link android.nfc.NdefMessage} on this tag. + * + * <p>This always reads the current NDEF Message stored on the tag. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @return the NDEF Message, never null + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled + * @throws FormatException if the NDEF Message on the tag is malformed */ public NdefMessage getNdefMessage() throws IOException, FormatException { checkConnected(); @@ -212,8 +278,16 @@ public final class Ndef extends BasicTagTechnology { } /** - * Overwrite the primary NDEF message - * @throws IOException + * Overwrite the {@link NdefMessage} on this tag. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param msg the NDEF Message to write, must not be null + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled + * @throws FormatException if the NDEF Message to write is malformed */ public void writeNdefMessage(NdefMessage msg) throws IOException, FormatException { checkConnected(); @@ -244,8 +318,11 @@ public final class Ndef extends BasicTagTechnology { } /** - * Indicates whether a tag can be made read-only with - * {@link #makeReadOnly()} + * Indicates whether a tag can be made read-only with {@link #makeReadOnly()}. + * + * <p>Does not cause any RF activity and does not block. + * + * @return true if it is possible to make this tag read-only */ public boolean canMakeReadOnly() { if (mNdefType == TYPE_1 || mNdefType == TYPE_2) { @@ -256,11 +333,20 @@ public final class Ndef extends BasicTagTechnology { } /** - * Sets the CC field to indicate this tag is read-only - * and permanently sets the lock bits to prevent any further NDEF - * modifications. - * This is a one-way process and can not be reverted! - * @throws IOException + * Make a tag read-only. + * + * <p>This sets the CC field to indicate the tag is read-only, + * and where possible permanently sets the lock bits to prevent + * any further modification of the memory. + * <p>This is a one-way process and cannot be reverted! + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @return true on success, false if it is not possible to make this tag read-only + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled */ public boolean makeReadOnly() throws IOException { checkConnected(); diff --git a/core/java/android/nfc/tech/NdefFormatable.java b/core/java/android/nfc/tech/NdefFormatable.java index e2828b5..84bda87 100644 --- a/core/java/android/nfc/tech/NdefFormatable.java +++ b/core/java/android/nfc/tech/NdefFormatable.java @@ -22,15 +22,24 @@ import android.nfc.INfcTag; import android.nfc.NdefMessage; import android.nfc.NfcAdapter; import android.nfc.Tag; +import android.nfc.TagLostException; import android.os.RemoteException; import android.util.Log; import java.io.IOException; /** - * An interface to a {@link Tag} allowing to format the tag as NDEF. + * Provide access to NDEF format operations on a {@link Tag}. * - * <p>You can acquire this kind of connection with {@link #get}. + * <p>Acquire a {@link NdefFormatable} object using {@link #get}. + * + * <p>Android devices with NFC must only enumerate and implement this + * class for tags for which it can format to NDEF. + * + * <p>Unfortunately the procedures to convert unformated tags to NDEF formatted + * tags are not specified by NFC Forum, and are not generally well-known. So + * there is no mandatory set of tags for which all Android devices with NFC + * must support {@link NdefFormatable}. * * <p class="note"><strong>Note:</strong> * Use of this class requires the {@link android.Manifest.permission#NFC} @@ -40,10 +49,13 @@ public final class NdefFormatable extends BasicTagTechnology { private static final String TAG = "NFC"; /** - * Returns an instance of this tech for the given tag. If the tag doesn't support - * this tech type null is returned. + * Get an instance of {@link NdefFormatable} for the given tag. + * <p>Does not cause any RF activity and does not block. + * <p>Returns null if {@link NdefFormatable} was not enumerated in {@link Tag#getTechList}. + * This indicates the tag is not NDEF formatable by this Android device. * - * @param tag The tag to get the tech from + * @param tag an NDEF formatable tag + * @return NDEF formatable object */ public static NdefFormatable get(Tag tag) { if (!tag.hasTech(TagTechnology.NDEF_FORMATABLE)) return null; @@ -63,23 +75,43 @@ public final class NdefFormatable extends BasicTagTechnology { } /** - * Formats a tag as NDEF, if possible. You may supply a first - * NdefMessage to be written on the tag. - * <p>Either all steps succeed, or an IOException is thrown if any one step - * fails. + * Format a tag as NDEF, and write a {@link NdefMessage}. + * + * <p>This is a multi-step process, an IOException is thrown + * if any one step fails. + * <p>The card is left in a read-write state after this operation. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param msg the NDEF message to write after formatting + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled + * @throws FormatException if the NDEF Message to write is malformed */ - public void format(NdefMessage firstMessage) throws IOException, FormatException { - format(firstMessage, false); + public void format(NdefMessage msg) throws IOException, FormatException { + format(msg, false); } /** - * Formats a tag as NDEF, if possible. You may supply a first - * NdefMessage to be written on the tag. - * <p>Either all steps succeed, or an IOException is thrown if any one step - * fails. + * Formats a tag as NDEF, write a {@link NdefMessage}, and make read-only. + * + * <p>This is a multi-step process, an IOException is thrown + * if any one step fails. + * <p>The card is left in a read-only state if this method returns successfully. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. + * + * @param msg the NDEF message to write after formatting + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or the operation is canceled + * @throws FormatException if the NDEF Message to write is malformed */ - public void formatReadOnly(NdefMessage firstMessage) throws IOException, FormatException { - format(firstMessage, true); + public void formatReadOnly(NdefMessage msg) throws IOException, FormatException { + format(msg, true); } /*package*/ void format(NdefMessage firstMessage, boolean makeReadOnly) throws IOException, diff --git a/core/java/android/nfc/tech/NfcA.java b/core/java/android/nfc/tech/NfcA.java index 24badc4..93d8510 100644 --- a/core/java/android/nfc/tech/NfcA.java +++ b/core/java/android/nfc/tech/NfcA.java @@ -23,18 +23,11 @@ import android.os.RemoteException; import java.io.IOException; /** - * A low-level connection to a {@link Tag} using the NFC-A technology, also known as - * ISO1443-3A. + * Provides access to NFC-A (ISO 14443-3A) properties and I/O operations on a {@link Tag}. * - * <p>You can acquire this kind of connection with {@link #get}. - * Use this class to send and receive data with {@link #transceive transceive()}. - * - * <p>Applications must implement their own protocol stack on top of - * {@link #transceive transceive()}. - * - * <p class="note"><strong>Note:</strong> - * Use of this class requires the {@link android.Manifest.permission#NFC} - * permission. + * <p>Acquire a {@link NfcA} object using {@link #get}. + * <p>The primary NFC-A I/O operation is {@link #transceive}. Applications must + * implement their own protocol stack on top of {@link #transceive}. */ public final class NfcA extends BasicTagTechnology { /** @hide */ @@ -46,10 +39,13 @@ public final class NfcA extends BasicTagTechnology { private byte[] mAtqa; /** - * Returns an instance of this tech for the given tag. If the tag doesn't support - * this tech type null is returned. + * Get an instance of {@link NfcA} for the given tag. + * <p>Returns null if {@link NfcA} was not enumerated in {@link Tag#getTechList}. + * This indicates the tag does not support NFC-A. + * <p>Does not cause any RF activity and does not block. * - * @param tag The tag to get the tech from + * @param tag an NFC-A compatible tag + * @return NFC-A object */ public static NfcA get(Tag tag) { if (!tag.hasTech(TagTechnology.NFC_A)) return null; @@ -69,29 +65,44 @@ public final class NfcA extends BasicTagTechnology { } /** - * Returns the ATQA/SENS_RES bytes discovered at tag discovery. + * Return the ATQA/SENS_RES bytes from tag discovery. + * + * <p>Does not cause any RF activity and does not block. + * + * @return ATQA/SENS_RES bytes */ public byte[] getAtqa() { return mAtqa; } /** - * Returns the SAK/SEL_RES discovered at tag discovery. + * Return the SAK/SEL_RES bytes from tag discovery. + * + * <p>Does not cause any RF activity and does not block. + * + * @return SAK bytes */ public short getSak() { return mSak; } /** - * Send data to a tag and receive the response. - * <p> - * This method will block until the response is received. It can be canceled - * with {@link #close}. - * <p>Requires {@link android.Manifest.permission#NFC} permission. + * Send raw NFC-A commands to the tag and receive the response. + * + * <p>Applications must not append the EoD (CRC) to the payload, + * it will be automatically calculated. + * <p>Applications must only send commands that are complete bytes, + * for example a SENS_REQ is not possible (these are used to + * manage tag polling and initialization). + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. * * @param data bytes to send * @return bytes received in response - * @throws IOException if the target is lost or connection closed + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or this operation is canceled */ public byte[] transceive(byte[] data) throws IOException { return transceive(data, true); diff --git a/core/java/android/nfc/tech/NfcB.java b/core/java/android/nfc/tech/NfcB.java index abeef32..29246ee 100644 --- a/core/java/android/nfc/tech/NfcB.java +++ b/core/java/android/nfc/tech/NfcB.java @@ -23,18 +23,11 @@ import android.os.RemoteException; import java.io.IOException; /** - * A low-level connection to a {@link Tag} using the NFC-B technology, also known as - * ISO1443-3B. + * Provides access to NFC-B (ISO 14443-3B) properties and I/O operations on a {@link Tag}. * - * <p>You can acquire this kind of connection with {@link #get}. - * Use this class to send and receive data with {@link #transceive transceive()}. - * - * <p>Applications must implement their own protocol stack on top of - * {@link #transceive transceive()}. - * - * <p class="note"><strong>Note:</strong> - * Use of this class requires the {@link android.Manifest.permission#NFC} - * permission. + * <p>Acquire a {@link NfcB} object using {@link #get}. + * <p>The primary NFC-B I/O operation is {@link #transceive}. Applications must + * implement their own protocol stack on top of {@link #transceive}. */ public final class NfcB extends BasicTagTechnology { /** @hide */ @@ -46,10 +39,13 @@ public final class NfcB extends BasicTagTechnology { private byte[] mProtInfo; /** - * Returns an instance of this tech for the given tag. If the tag doesn't support - * this tech type null is returned. + * Get an instance of {@link NfcB} for the given tag. + * <p>Returns null if {@link NfcB} was not enumerated in {@link Tag#getTechList}. + * This indicates the tag does not support NFC-B. + * <p>Does not cause any RF activity and does not block. * - * @param tag The tag to get the tech from + * @param tag an NFC-B compatible tag + * @return NFC-B object */ public static NfcB get(Tag tag) { if (!tag.hasTech(TagTechnology.NFC_B)) return null; @@ -69,31 +65,43 @@ public final class NfcB extends BasicTagTechnology { } /** - * Returns the Application Data bytes from the ATQB/SENSB_RES - * bytes discovered at tag discovery. + * Return the Application Data bytes from ATQB/SENSB_RES at tag discovery. + * + * <p>Does not cause any RF activity and does not block. + * + * @return Application Data bytes from ATQB/SENSB_RES bytes */ public byte[] getApplicationData() { return mAppData; } /** - * Returns the Protocol Info bytes from the ATQB/SENSB_RES - * bytes discovered at tag discovery. + * Return the Protocol Info bytes from ATQB/SENSB_RES at tag discovery. + * + * <p>Does not cause any RF activity and does not block. + * + * @return Protocol Info bytes from ATQB/SENSB_RES bytes */ public byte[] getProtocolInfo() { return mProtInfo; } /** - * Send data to a tag and receive the response. - * <p> - * This method will block until the response is received. It can be canceled - * with {@link #close}. - * <p>Requires {@link android.Manifest.permission#NFC} permission. + * Send raw NFC-B commands to the tag and receive the response. + * + * <p>Applications must not append the EoD (CRC) to the payload, + * it will be automatically calculated. + * <p>Applications must not send commands that manage the polling + * loop and initialization (SENSB_REQ, SLOT_MARKER etc). + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. * * @param data bytes to send * @return bytes received in response - * @throws IOException if the target is lost or connection closed + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or this operation is canceled */ public byte[] transceive(byte[] data) throws IOException { return transceive(data, true); diff --git a/core/java/android/nfc/tech/NfcF.java b/core/java/android/nfc/tech/NfcF.java index f617739..27d1b57 100644 --- a/core/java/android/nfc/tech/NfcF.java +++ b/core/java/android/nfc/tech/NfcF.java @@ -23,18 +23,11 @@ import android.os.RemoteException; import java.io.IOException; /** - * A low-level connection to a {@link Tag} using the NFC-F technology, also known as - * JIS6319-4. + * Provides access to NFC-F (JIS 6319-4) properties and I/O operations on a {@link Tag}. * - * <p>You can acquire this kind of connection with {@link #get}. - * Use this class to send and receive data with {@link #transceive transceive()}. - * - * <p>Applications must implement their own protocol stack on top of - * {@link #transceive transceive()}. - * - * <p class="note"><strong>Note:</strong> - * Use of this class requires the {@link android.Manifest.permission#NFC} - * permission. + * <p>Acquire a {@link NfcF} object using {@link #get}. + * <p>The primary NFC-F I/O operation is {@link #transceive}. Applications must + * implement their own protocol stack on top of {@link #transceive}. */ public final class NfcF extends BasicTagTechnology { /** @hide */ @@ -46,10 +39,13 @@ public final class NfcF extends BasicTagTechnology { private byte[] mManufacturer = null; /** - * Returns an instance of this tech for the given tag. If the tag doesn't support - * this tech type null is returned. + * Get an instance of {@link NfcF} for the given tag. + * <p>Returns null if {@link NfcF} was not enumerated in {@link Tag#getTechList}. + * This indicates the tag does not support NFC-F. + * <p>Does not cause any RF activity and does not block. * - * @param tag The tag to get the tech from + * @param tag an NFC-F compatible tag + * @return NFC-F object */ public static NfcF get(Tag tag) { if (!tag.hasTech(TagTechnology.NFC_F)) return null; @@ -70,24 +66,42 @@ public final class NfcF extends BasicTagTechnology { } } + /** + * Return the System Code bytes from tag discovery. + * + * <p>Does not cause any RF activity and does not block. + * + * @return System Code bytes + */ public byte[] getSystemCode() { return mSystemCode; } + /** + * Return the Manufacturer bytes from tag discovery. + * + * <p>Does not cause any RF activity and does not block. + * + * @return Manufacturer bytes + */ public byte[] getManufacturer() { return mManufacturer; } /** - * Send data to a tag and receive the response. - * <p> - * This method will block until the response is received. It can be canceled - * with {@link #close}. - * <p>Requires {@link android.Manifest.permission#NFC} permission. + * Send raw NFC-F commands to the tag and receive the response. + * + * <p>Applications must not append the SoD (length) or EoD (CRC) to the payload, + * it will be automatically calculated. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. * * @param data bytes to send * @return bytes received in response - * @throws IOException if the target is lost or connection closed + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or this operation is canceled */ public byte[] transceive(byte[] data) throws IOException { return transceive(data, true); diff --git a/core/java/android/nfc/tech/NfcV.java b/core/java/android/nfc/tech/NfcV.java index 8e1f066..99dc318 100644 --- a/core/java/android/nfc/tech/NfcV.java +++ b/core/java/android/nfc/tech/NfcV.java @@ -23,18 +23,11 @@ import android.os.RemoteException; import java.io.IOException; /** - * A low-level connection to a {@link Tag} using NFC vicinity technology, also known as - * ISO15693. + * Provides access to NFC-V (ISO 15693) properties and I/O operations on a {@link Tag}. * - * <p>You can acquire this kind of connection with {@link #get}. - * Use this class to send and receive data with {@link #transceive transceive()}. - * - * <p>Applications must implement their own protocol stack on top of - * {@link #transceive transceive()}. - * - * <p class="note"><strong>Note:</strong> - * Use of this class requires the {@link android.Manifest.permission#NFC} - * permission. + * <p>Acquire a {@link NfcV} object using {@link #get}. + * <p>The primary NFC-V I/O operation is {@link #transceive}. Applications must + * implement their own protocol stack on top of {@link #transceive}. */ public final class NfcV extends BasicTagTechnology { /** @hide */ @@ -47,10 +40,13 @@ public final class NfcV extends BasicTagTechnology { private byte mDsfId; /** - * Returns an instance of this tech for the given tag. If the tag doesn't support - * this tech type null is returned. + * Get an instance of {@link NfcV} for the given tag. + * <p>Returns null if {@link NfcV} was not enumerated in {@link Tag#getTechList}. + * This indicates the tag does not support NFC-V. + * <p>Does not cause any RF activity and does not block. * - * @param tag The tag to get the tech from + * @param tag an NFC-V compatible tag + * @return NFC-V object */ public static NfcV get(Tag tag) { if (!tag.hasTech(TagTechnology.NFC_V)) return null; @@ -69,24 +65,43 @@ public final class NfcV extends BasicTagTechnology { mDsfId = extras.getByte(EXTRA_DSFID); } + /** + * Return the Response Flag bytes from tag discovery. + * + * <p>Does not cause any RF activity and does not block. + * + * @return Response Flag bytes + */ public byte getResponseFlags() { return mRespFlags; } + /** + * Return the DSF ID bytes from tag discovery. + * + * <p>Does not cause any RF activity and does not block. + * + * @return DSF ID bytes + */ public byte getDsfId() { return mDsfId; } /** - * Send data to a tag and receive the response. - * <p> - * This method will block until the response is received. It can be canceled - * with {@link #close}. - * <p>Requires {@link android.Manifest.permission#NFC} permission. + * Send raw NFC-V commands to the tag and receive the response. + * + * <p>Applications must not append the CRC to the payload, + * it will be automatically calculated. The application does + * provide FLAGS, CMD and PARAMETER bytes. + * + * <p>This is an I/O operation and will block until complete. It must + * not be called from the main application thread. A blocked call will be canceled with + * {@link IOException} if {@link #close} is called from another thread. * * @param data bytes to send * @return bytes received in response - * @throws IOException if the target is lost or connection closed + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or this operation is canceled */ public byte[] transceive(byte[] data) throws IOException { return transceive(data, true); diff --git a/core/java/android/nfc/tech/TagTechnology.java b/core/java/android/nfc/tech/TagTechnology.java index 50df865..be6ccd0 100644 --- a/core/java/android/nfc/tech/TagTechnology.java +++ b/core/java/android/nfc/tech/TagTechnology.java @@ -21,6 +21,61 @@ import android.nfc.Tag; import java.io.Closeable; import java.io.IOException; +/** + * {@link TagTechnology} is an interface to a technology in a {@link Tag}. + * <p> + * Obtain a {@link TagTechnology} implementation by calling the static method <code>get()</code> + * on the implementation class. + * <p> + * NFC tags are based on a number of independently developed technologies and offer a + * wide range of capabilities. The + * {@link TagTechnology} implementations provide access to these different + * technologies and capabilities. Some sub-classes map to technology + * specification (for example {@link NfcA}, {@link IsoDep}, others map to + * pseudo-technologies or capabilities (for example {@link Ndef}, {@link NdefFormatable}). + * <p> + * It is mandatory for all Android NFC devices to provide the following + * {@link TagTechnology} implementations. + * <ul> + * <li>{@link NfcA} (also known as ISO 14443-3A) + * <li>{@link NfcB} (also known as ISO 14443-3B) + * <li>{@link NfcF} (also known as JIS 6319-4) + * <li>{@link NfcV} (also known as ISO 15693) + * <li>{@link IsoDep} + * <li>{@link Ndef} on NFC Forum Type 1, Type 2, Type 3 or Type 4 compliant tags + * </ul> + * It is optional for Android NFC devices to provide the following + * {@link TagTechnology} implementations. If it is not provided, the + * Android device will never enumerate that class via {@link Tag#getTechList}. + * <ul> + * <li>{@link MifareClassic} + * <li>{@link MifareUltralight} + * <li>{@link NdefFormatable} must only be enumerated on tags for which this Android device + * is capable of formatting. Proprietary knowledge is often required to format a tag + * to make it NDEF compatible. + * </ul> + * <p> + * {@link TagTechnology} implementations provide methods that fall into two classes: + * <em>cached getters</em> and <em>I/O operations</em>. + * <h4>Cached getters</h4> + * These methods (usually prefixed by <code>get</code> or <code>is</code>) return + * properties of the tag, as determined at discovery time. These methods will never + * block or cause RF activity, and do not require {@link #connect} to have been called. + * They also never update, for example if a property is changed by an I/O operation with a tag + * then the cached getter will still return the result from tag discovery time. + * <h4>I/O operations</h4> + * I/O operations may require RF activity, and may block. They have the following semantics. + * <ul> + * <li>{@link #connect} must be called before using any other I/O operation. + * <li>{@link #close} must be called after completing I/O operations with a + * {@link TagTechnology}, and it will cancel all other blocked I/O operations on other threads + * (including {@link #connect} with {@link IOException}. + * <li>Only one {@link TagTechnology} can be connected at a time. Other calls to + * {@link #connect} will return {@link IOException}. + * <li>I/O operations may block, and should never be called on the main application + * thread. + * </ul> + */ public interface TagTechnology extends Closeable { /** * This technology is an instance of {@link NfcA}. @@ -90,22 +145,22 @@ public interface TagTechnology extends Closeable { public static final int MIFARE_ULTRALIGHT = 9; /** - * Get the {@link Tag} object this technology came from. + * Get the {@link Tag} object backing this {@link TagTechnology} object. + * @return the {@link Tag} backing this {@link TagTechnology} object. */ public Tag getTag(); /** - * Opens a connection to the {@link Tag} enabling interactive commands. The command set - * varies by the technology type. - * - * <p>This method blocks until the connection has been established. - * - * <p>A call to {@link #close} from another thread will cancel a blocked call and cause an - * IOException to be thrown on the thread that is blocked. + * Enable I/O operations to the tag from this {@link TagTechnology} object. + * <p>May cause RF activity and may block. Must not be called + * from the main application thread. A blocked call will be canceled with + * {@link IOException} by calling {@link #close} from another thread. + * <p>Only one {@link TagTechnology} object can be connected to a {@link Tag} at a time. + * <p>Applications must call {@link #close} when I/O operations are complete. * - * @see #reconnect() * @see #close() - * @throws IOException if the target is lost, or connect canceled + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or connect is canceled */ public void connect() throws IOException; @@ -113,40 +168,34 @@ public interface TagTechnology extends Closeable { * Re-connect to the {@link Tag} associated with this connection. Reconnecting to a tag can be * used to reset the state of the tag itself. * - * <p>This method blocks until the connection is re-established. - * - * <p>A call to {@link #close} from another thread will cancel a blocked call and cause an - * IOException to be thrown on the thread that is blocked. + * <p>May cause RF activity and may block. Must not be called + * from the main application thread. A blocked call will be canceled with + * {@link IOException} by calling {@link #close} from another thread. * * @see #connect() * @see #close() - * @throws IOException + * @throws TagLostException if the tag leaves the field + * @throws IOException if there is an I/O failure, or connect is canceled * @hide */ public void reconnect() throws IOException; /** - * Closes the connection to the {@link Tag}. This call is non-blocking and causes all blocking - * operations such as {@link #connect} to be canceled and immediately throw - * {@link java.io.IOException} on the thread that is blocked. - * - * <p> - * Once this method is called, this object cannot be re-used and should be discarded. Further - * calls to {@link #connect} will fail. + * Disable I/O operations to the tag from this {@link TagTechnology} object, and release resources. + * <p>Also causes all blocked I/O operations on other thread to be canceled and + * return with {@link IOException}. * * @see #connect() - * @see #reconnect() */ public void close() throws IOException; /** - * Helper to indicate if {@link #connect} has succeeded. - * <p> - * Does not cause RF activity, and does not block. - * @return true if {@link #connect} has completed successfully and the {@link Tag} is believed - * to be within range. Applications must still handle {@link java.io.IOException} - * while using methods that require a connection in case the connection is lost after this - * method returns. + * Helper to indicate if I/O operations should be possible. + * + * <p>Returns true if {@link #connect} has completed, and {@link #close} has not been + * called, and the {@link Tag} is not known to be out of range. + * <p>Does not cause RF activity, and does not block. + * @return true if I/O operations should be possible */ public boolean isConnected(); } |