import android.util.Log;
/**
- * Represents the device's local NFC adapter.
+ * Represents the local NFC adapter.
* <p>
* Use the helper {@link #getDefaultAdapter(Context)} to get the default NFC
* adapter for this Android device.
+ * <p>
*/
public final class NfcAdapter {
private static final String TAG = "NFC";
/**
* Return true if this NFC Adapter has any features enabled.
- * <p>
- * If this method returns false, then applications should request the user
- * turn on NFC tag discovery in Settings.
- * <p>
- * If this method returns false, the NFC hardware is guaranteed not to
- * perform or respond to any NFC communication.
*
- * @return true if this NFC Adapter is enabled to discover new tags
+ * <p>Application may use this as a helper to suggest that the user
+ * should turn on NFC in Settings.
+ * <p>If this method returns false, the NFC hardware is guaranteed not to
+ * generate or respond to any NFC transactions.
+ *
+ * @return true if this NFC Adapter has any features enabled
*/
public boolean isEnabled() {
try {
}
/**
- * Enables foreground dispatching to the given Activity. This will force all NFC Intents that
- * match the given filters to be delivered to the activity bypassing the standard dispatch
- * mechanism. If no IntentFilters are given all the PendingIntent will be invoked for every
- * dispatch Intent.
+ * Enable foreground dispatch to the given Activity.
+ *
+ * <p>This will give give priority to the foreground activity when
+ * dispatching a discovered {@link Tag} to an application.
+ *
+ * <p>Activities must call {@link #disableForegroundDispatch} in
+ * their {@link Activity#onPause} callback.
+ *
+ * <p>a null set of intent filters will cause the forground activity
+ * to receive all tags.
*
- * This method must be called from the main thread.
+ * <p>This method must be called from the main thread, and
+ * only when the activity is in the foreground (resumed). *
*
* @param activity the Activity to dispatch to
* @param intent the PendingIntent to start for the dispatch
* @param filters the IntentFilters to override dispatching for, or null to always dispatch
- * @throws IllegalStateException
+ * @throws IllegalStateException if the Activity is not currently in the foreground
*/
public void enableForegroundDispatch(Activity activity, PendingIntent intent,
IntentFilter[] filters, String[][] techLists) {
}
/**
- * Disables foreground activity dispatching setup with
- * {@link #enableForegroundDispatch}.
+ * Disable foreground dispatch to the given activity.
*
- * <p>This must be called before the Activity returns from
- * it's <code>onPause()</code> or this method will throw an IllegalStateException.
+ * <p>After calling {@link #enableForegroundDispatch}, an activity
+ * must call this method before its {@link Activity#onPause} callback
+ * completes.
*
* <p>This method must be called from the main thread.
+ *
+ * @param activity the Activity to disable dispatch to
+ * @throws IllegalStateException if the Activity has already been paused
*/
public void disableForegroundDispatch(Activity activity) {
ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,
}
/**
- * Enable NDEF message push over P2P while this Activity is in the foreground. For this to
- * function properly the other NFC device being scanned must support the "com.android.npp"
- * NDEF push protocol.
+ * Enable NDEF message push over P2P while this Activity is in the foreground.
+ *
+ * <p>For this to function properly the other NFC device being scanned must
+ * support the "com.android.npp" NDEF push protocol. Support for this
+ * protocol is currently optional for Android NFC devices.
+ *
+ * <p>This method must be called from the main thread.
*
* <p><em>NOTE</em> While foreground NDEF push is active standard tag dispatch is disabled.
* Only the foreground activity may receive tag discovered dispatches via
* {@link #enableForegroundDispatch}.
+ *
+ * @param activity the foreground Activity
+ * @param msg a NDEF Message to push over P2P
+ * @throws IllegalStateException if the Activity is not currently in the foreground
+ * @throws OperationNotSupportedException if this Android device does not support NDEF push
*/
public void enableForegroundNdefPush(Activity activity, NdefMessage msg) {
if (activity == null || msg == null) {
}
/**
- * Disables foreground NDEF push setup with
- * {@link #enableForegroundNdefPush}.
+ * Disable NDEF message push over P2P.
*
- * <p>This must be called before the Activity returns from
- * it's <code>onPause()</code> or this method will throw an IllegalStateException.
+ * <p>After calling {@link #enableForegroundNdefPush}, an activity
+ * must call this method before its {@link Activity#onPause} callback
+ * completes.
*
* <p>This method must be called from the main thread.
+ *
+ * @param activity the Foreground activity
+ * @throws IllegalStateException if the Activity has already been paused
+ * @throws OperationNotSupportedException if this Android device does not support NDEF push
*/
public void disableForegroundNdefPush(Activity activity) {
ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,
private static final String TAG = "NfcSecureElement";
private INfcSecureElement mService;
-
-
+
+
/**
* @hide
*/
public byte [] exchangeAPDU(int handle,byte [] data) throws IOException {
-
+
// Perform exchange APDU
try {
}
public void closeSecureElementConnection(int handle) throws IOException {
-
+
try {
int status = mService.closeSecureElementConnection(handle);
// Handle potential errors
Log.e(TAG, "RemoteException in closeSecureElement(): ", e);
}
}
-
-
+
+
/**
* Returns target type. constants.
- *
+ *
* @return Secure Element technology type. The possible values are defined in
* {@link TagTechnology}
- *
+ *
*/
public int[] getSecureElementTechList(int handle) throws IOException {
try {
return null;
}
}
-
+
/**
* Returns Secure Element UID.
- *
+ *
* @return Secure Element UID.
*/
public byte[] getSecureElementUid(int handle) throws IOException {
-
+
byte[] uid = null;
- try {
+ try {
uid = mService.getSecureElementUid(handle);
// Handle potential errors
if (uid == null) {
package android.nfc;
+import android.content.Context;
import android.nfc.tech.IsoDep;
import android.nfc.tech.MifareClassic;
import android.nfc.tech.MifareUltralight;
import java.util.Arrays;
/**
- * Represents a (generic) discovered tag.
+ * Represents an NFC tag that has been discovered.
* <p>
- * A tag is a passive NFC element, such as NFC Forum Tag's, MIFARE class Tags,
- * Sony FeliCa Tags, etc.
+ * {@link Tag} is an immutable object that represents the state of a NFC tag at
+ * the time of discovery. It can be used as a handle to {@link TagTechnology} classes
+ * to perform advanced operations, or directly queried for its ID ({@link #getId} and the
+ * set of technologies it contains ({@link #getTechList}). Arrays passed to and
+ * returned by this class are *not* cloned, so be careful not to modify them.
+ * <p>
+ * A new tag object is created every time a tag is discovered (comes into range), even
+ * if it is the same physical tag. If a tag is removed and then returned into range, then
+ * only the most recent tag object can be successfully used to create a {@link TagTechnology}.
+ *
+ * <h3>Tag Dispatch</h3>
+ * When a tag is discovered, a {@link Tag} object is created and passed to a
+ * single application via the {@link NfcAdapter#EXTRA_TAG} extra in a
+ * {@link Context#startActivity} {@link android.content.Intent}. A four stage dispatch is used to select the
+ * most appropriate application to handle the tag. The Android OS executes each stage in order,
+ * and completes dispatch as soon as a single matching application is found. If there are multiple
+ * matching applications found at any one stage then the Android Activity Chooser dialog is shown
+ * to allow the user to select the application.
+ * <h4>1. Foreground activity dispatch</h4>
+ * A foreground activity that has called {@link NfcAdapter#enableForegroundDispatch} is
+ * given priority. See the documentation on {#link NfcAdapter#enableForegroundDispatch} for
+ * its usage.
+ * <h4>2. NDEF data dispatch</h4>
+ * If the tag contains NDEF data, then {@link Context#startActivity} is called with
+ * {@link NfcAdapter#ACTION_NDEF_DISCOVERED} and a data URI determined from the
+ * first NDEF Record in the first NDEF Message in the Tag. This allows NDEF tags to be given
+ * priority dispatch to applications that can handle the content.
+ * See {@link NfcAdapter#ACTION_NDEF_DISCOVERED} for more detail. If the tag does not contain
+ * NDEF data, or if no application is registered
+ * for {@link NfcAdapter#ACTION_NDEF_DISCOVERED} with a matching data URI then dispatch moves
+ * to stage 3.
+ * <h4>3. Tag Technology dispatch</h4>
+ * {@link Context#startActivity} is called with {@link NfcAdapter#ACTION_TECH_DISCOVERED} to
+ * dispatch the tag to an application that can handle the technologies present on the tag.
+ * Technologies are defined as sub-classes of {@link TagTechnology}, see the package
+ * {@link android.nfc.tech}. The Android OS looks for an application that can handle one or
+ * more technologies in the tag. See {@link NfcAdapter#ACTION_TECH_DISCOVERED for more detail.
+ * <h4>4. Fall-back dispatch</h4>
+ * If no application has been matched, then {@link Context#startActivity} is called with
+ * {@link NfcAdapter#ACTION_TAG_DISCOVERED}. This is intended as a fall-back mechanism.
+ * See {@link NfcAdapter#ACTION_TAG_DISCOVERED}.
+ *
* <p>
- * Tag's have a type and usually have a UID.
+ * <i>The Tag dispatch mechanism was designed to give a high probability of dispatching
+ * a tag to the correct application without showing the user an Application Chooser dialog.
+ * This is important for NFC interactions because they are very transient - if a user has to
+ * move the Android device to choose an application then the connection is broken.</i>
+ *
+ * <h3>NFC Tag Background</h3>
+ * An NFC tag is a passive NFC device, powered by the NFC field of this Android device while
+ * it is in range. Tag's can come in many forms, such as stickers, cards, key fob, or
+ * even embedded in a more sophisticated device.
* <p>
- * {@link Tag} objects are passed to applications via the {@link NfcAdapter#EXTRA_TAG} extra
- * in {@link NfcAdapter#ACTION_TAG_DISCOVERED} intents. A {@link Tag} object is immutable
- * and represents the state of the tag at the time of discovery. It can be
- * directly queried for its UID and Type, or used to create a {@link TagTechnology} using the
- * static <code>get()</code> methods on the varios tech classes.
+ * Tags can have a wide range of capabilities. Simple tags just offer read/write semantics,
+ * and contain some one time
+ * programmable areas to make read-only. More complex tags offer math operations
+ * and per-sector access control and authentication. The most sophisticated tags
+ * contain operating environments such as Javacard, allowing complex interactions with the
+ * applets executing on the tag. Use {@link TagTechnology} classes to access a broad
+ * range of capabilities available in NFC tags.
* <p>
- * A {@link Tag} can be used to create a {@link TagTechnology} only while the tag is in
- * range. If it is removed and then returned to range, then the most recent
- * {@link Tag} object (in {@link NfcAdapter#ACTION_TAG_DISCOVERED}) should be used to create a
- * {@link TagTechnology}.
- * <p>This is an immutable data class. All properties are set at Tag discovery
- * time and calls on this class will retrieve those read-only properties, and
- * not cause any further RF activity or block. Note however that arrays passed to and
- * returned by this class are *not* cloned, so be careful not to modify them.
*/
public final class Tag implements Parcelable {
/*package*/ final byte[] mId;
/**
* Get the Tag Identifier (if it has one).
- * <p>Tag ID is usually a serial number for the tag.
- *
- * @return ID, or null if it does not exist
+ * <p>The tag identifier is a low level serial number, used for anti-collision
+ * and identification.
+ * <p> Most tags have a stable unique identifier
+ * (UID), but some tags will generate a random ID every time they are discovered
+ * (RID), and there are some tags with no ID at all (the byte array will be zero-sized).
+ * <p> The size and format of an ID is specific to the RF technology used by the tag.
+ * <p> This function retrieves the ID as determined at discovery time, and does not
+ * perform any further RF communication or block.
+ * @return ID as byte array, never null
*/
public byte[] getId() {
return mId;
}
/**
- * Returns technologies present in the tag that this implementation understands,
- * or a zero length array if there are no supported technologies on this tag.
- *
- * The elements of the list are the names of the classes implementing the technology.
- *
+ * Get the technologies available in this tag, as fully qualified class names.
+ * <p>
+ * A technology is an implementation of the {@link TagTechnology} interface,
+ * and can be instantiated by calling the static <code>get(Tag)</code>
+ * method on the implementation with this Tag. The {@link TagTechnology}
+ * object can then be used to perform advanced, technology-specific operations on a tag.
+ * <p>
+ * Android defines a mandatory set of technologies that must be correctly
+ * enumerated by all Android NFC devices, and an optional
+ * set of proprietary technologies.
+ * See {@link TagTechnology} for more details.
+ * <p>
* The ordering of the returned array is undefined and should not be relied upon.
+ * @return an array of fully-qualified {@link TagTechnology} class-names.
*/
public String[] getTechList() {
return mTechStringList;
}
return false;
}
-
+
/** @hide */
public Bundle getTechExtras(int tech) {
int pos = -1;
return mTagService;
}
+ /**
+ * Human-readable description of the tag, for debugging.
+ */
@Override
public String toString() {
StringBuilder sb = new StringBuilder("TAG ")
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";
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;
return null;
}
}
-
+
/** @hide */
public IsoDep(Tag tag)
throws RemoteException {
}
/**
- * 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 {
}
/**
- * 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);
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};
/** 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;
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;
}
}
- /** 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
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:
}
}
- /** 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);
}
}
- /** 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);
}
}
- /** 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;
}
}
- // 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);
/**
* 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);
/**
* 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);
}
/**
- * 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);
}
/**
- * 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);
}
/**
- * 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);
}
/**
- * 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);
/**
* 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);
package android.nfc.tech;
import android.nfc.Tag;
+import android.nfc.TagLostException;
import android.os.RemoteException;
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
* 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 */
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;
}
}
- /** 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);
/**
* 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);
}
}
}
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;
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}
/** @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;
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 {
}
/**
- * 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) {
}
/**
- * 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();
}
/**
- * 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();
}
/**
- * 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) {
}
/**
- * 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();
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}
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;
}
/**
- * 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,
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 */
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;
}
/**
- * 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);
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 */
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;
}
/**
- * 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);
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 */
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;
}
}
+ /**
+ * 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);
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 */
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;
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);
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}.
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;
* 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();
}