DO NOT MERGE

Reconcile documentation updates from gingerbread to honeycomb.

Change-Id: I8c199906beb5cd3c290ded123d6aefd0d1697f30
This commit is contained in:
Nick Pelly
2011-02-02 22:37:40 -08:00
parent 699a096943
commit a8d3f02aaa
13 changed files with 1019 additions and 363 deletions

View File

@@ -26,14 +26,17 @@ import android.content.Context;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.IPackageManager; import android.content.pm.IPackageManager;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.nfc.tech.MifareClassic;
import android.nfc.tech.Ndef;
import android.nfc.tech.NfcA;
import android.nfc.tech.NfcF;
import android.os.IBinder; import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.util.Log; import android.util.Log;
/** /**
* Represents the device's local NFC adapter. * Represents the local NFC adapter.
* <p> * <p>
* Use the helper {@link #getDefaultAdapter(Context)} to get the default NFC * Use the helper {@link #getDefaultAdapter(Context)} to get the default NFC
* adapter for this Android device. * adapter for this Android device.
@@ -43,30 +46,85 @@ public final class NfcAdapter {
/** /**
* Intent to start an activity when a tag with NDEF payload is discovered. * Intent to start an activity when a tag with NDEF payload is discovered.
* If the tag has and NDEF payload this intent is started before
* {@link #ACTION_TECH_DISCOVERED}.
* *
* If any activities respond to this intent neither * <p>The system inspects the first {@link NdefRecord} in the first {@link NdefMessage} and
* looks for a URI, SmartPoster, or MIME record. If a URI or SmartPoster record is found the
* intent will contain the URI in its data field. If a MIME record is found the intent will
* contain the MIME type in its type field. This allows activities to register
* {@link IntentFilter}s targeting specific content on tags. Activities should register the
* most specific intent filters possible to avoid the activity chooser dialog, which can
* disrupt the interaction with the tag as the user interacts with the screen.
*
* <p>If the tag has an NDEF payload this intent is started before
* {@link #ACTION_TECH_DISCOVERED}. If any activities respond to this intent neither
* {@link #ACTION_TECH_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started. * {@link #ACTION_TECH_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started.
*/ */
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED"; public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
/** /**
* Intent to started when a tag is discovered. The data URI is formated as * Intent to start an activity when a tag is discovered and activities are registered for the
* {@code vnd.android.nfc://tag/} with the path having a directory entry for each technology * specific technologies on the tag.
* in the {@link Tag#getTechList()} is sorted ascending order.
* *
* This intent is started after {@link #ACTION_NDEF_DISCOVERED} and before * <p>To receive this intent an activity must include an intent filter
* {@link #ACTION_TAG_DISCOVERED} * for this action and specify the desired tech types in a
* manifest <code>meta-data</code> entry. Here is an example manfiest entry:
* <pre>
* &lt;activity android:name=".nfc.TechFilter" android:label="NFC/TechFilter"&gt;
* &lt;!-- Add a technology filter --&gt;
* &lt;intent-filter&gt;
* &lt;action android:name="android.nfc.action.TECH_DISCOVERED" /&gt;
* &lt;/intent-filter&gt;
* *
* If any activities respond to this intent {@link #ACTION_TAG_DISCOVERED} will not be started. * &lt;meta-data android:name="android.nfc.action.TECH_DISCOVERED"
* android:resource="@xml/filter_nfc"
* /&gt;
* &lt;/activity&gt;
* </pre>
*
* <p>The meta-data XML file should contain one or more <code>tech-list</code> entries
* each consisting or one or more <code>tech</code> entries. The <code>tech</code> entries refer
* to the qualified class name implementing the technology, for example "android.nfc.tech.NfcA".
*
* <p>A tag matches if any of the
* <code>tech-list</code> sets is a subset of {@link Tag#getTechList() Tag.getTechList()}. Each
* of the <code>tech-list</code>s is considered independently and the
* activity is considered a match is any single <code>tech-list</code> matches the tag that was
* discovered. This provides AND and OR semantics for filtering desired techs. Here is an
* example that will match any tag using {@link NfcF} or any tag using {@link NfcA},
* {@link MifareClassic}, and {@link Ndef}:
*
* <pre>
* &lt;resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"&gt;
* &lt;!-- capture anything using NfcF --&gt;
* &lt;tech-list&gt;
* &lt;tech&gt;android.nfc.tech.NfcF&lt;/tech&gt;
* &lt;/tech-list&gt;
*
* &lt;!-- OR --&gt;
*
* &lt;!-- capture all MIFARE Classics with NDEF payloads --&gt;
* &lt;tech-list&gt;
* &lt;tech&gt;android.nfc.tech.NfcA&lt;/tech&gt;
* &lt;tech&gt;android.nfc.tech.MifareClassic&lt;/tech&gt;
* &lt;tech&gt;android.nfc.tech.Ndef&lt;/tech&gt;
* &lt;/tech-list&gt;
* &lt;/resources&gt;
* </pre>
*
* <p>This intent is started after {@link #ACTION_NDEF_DISCOVERED} and before
* {@link #ACTION_TAG_DISCOVERED}. If any activities respond to {@link #ACTION_NDEF_DISCOVERED}
* this intent will not be started. If any activities respond to this intent
* {@link #ACTION_TAG_DISCOVERED} will not be started.
*/ */
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED"; public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
/** /**
* Intent to start an activity when a tag is discovered. * Intent to start an activity when a tag is discovered.
*
* <p>This intent will not be started when a tag is discovered if any activities respond to
* {@link #ACTION_NDEF_DISCOVERED} or {@link #ACTION_TECH_DISCOVERED} for the current tag.
*/ */
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED"; public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
@@ -78,17 +136,23 @@ public final class NfcAdapter {
public static final String ACTION_TAG_LEFT_FIELD = "android.nfc.action.TAG_LOST"; public static final String ACTION_TAG_LEFT_FIELD = "android.nfc.action.TAG_LOST";
/** /**
* Mandatory Tag extra for the ACTION_TAG intents. * Mandatory extra containing the {@link Tag} that was discovered for the
* {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
* {@link #ACTION_TAG_DISCOVERED} intents.
*/ */
public static final String EXTRA_TAG = "android.nfc.extra.TAG"; public static final String EXTRA_TAG = "android.nfc.extra.TAG";
/** /**
* Optional NdefMessage[] extra for the ACTION_TAG intents. * Optional extra containing an array of {@link NdefMessage} present on the discovered tag for
* the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
* {@link #ACTION_TAG_DISCOVERED} intents.
*/ */
public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES"; public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
/** /**
* Optional byte[] extra for the tag identifier. * Optional extra containing a byte array containing the ID of the discovered tag for
* the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
* {@link #ACTION_TAG_DISCOVERED} intents.
*/ */
public static final String EXTRA_ID = "android.nfc.extra.ID"; public static final String EXTRA_ID = "android.nfc.extra.ID";
@@ -359,14 +423,13 @@ public final class NfcAdapter {
/** /**
* Return true if this NFC Adapter has any features enabled. * 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() { public boolean isEnabled() {
try { try {
@@ -414,17 +477,37 @@ public final class NfcAdapter {
} }
/** /**
* Enables foreground dispatching to the given Activity. This will force all NFC Intents that * Enable foreground dispatch to the given Activity.
* 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.
* *
* This method must be called from the main thread. * <p>This will give give priority to the foreground activity when
* dispatching a discovered {@link Tag} to an application.
*
* <p>If any IntentFilters are provided to this method they are used to match dispatch Intents
* for both the {@link NfcAdapter#ACTION_NDEF_DISCOVERED} and
* {@link NfcAdapter#ACTION_TAG_DISCOVERED}. Since {@link NfcAdapter#ACTION_TECH_DISCOVERED}
* relies on meta data outside of the IntentFilter matching for that dispatch Intent is handled
* by passing in the tech lists separately. Each first level entry in the tech list represents
* an array of technologies that must all be present to match. If any of the first level sets
* match then the dispatch is routed through the given PendingIntent. In other words, the second
* level is ANDed together and the first level entries are ORed together.
*
* <p>If you pass {@code null} for both the {@code filters} and {@code techLists} parameters
* that acts a wild card and will cause the foreground activity to receive all tags via the
* {@link NfcAdapter#ACTION_TAG_DISCOVERED} intent.
*
* <p>This method must be called from the main thread, and only when the activity is in the
* foreground (resumed). Also, activities must call {@link #disableForegroundDispatch} before
* the completion of their {@link Activity#onPause} callback to disable foreground dispatch
* after it has been enabled.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
* *
* @param activity the Activity to dispatch to * @param activity the Activity to dispatch to
* @param intent the PendingIntent to start for the dispatch * @param intent the PendingIntent to start for the dispatch
* @param filters the IntentFilters to override dispatching for, or null to always dispatch * @param filters the IntentFilters to override dispatching for, or null to always dispatch
* @throws IllegalStateException * @param techLists the tech lists used to perform matching for dispatching of the
* {@link NfcAdapter#ACTION_TECH_DISCOVERED} intent
* @throws IllegalStateException if the Activity is not currently in the foreground
*/ */
public void enableForegroundDispatch(Activity activity, PendingIntent intent, public void enableForegroundDispatch(Activity activity, PendingIntent intent,
IntentFilter[] filters, String[][] techLists) { IntentFilter[] filters, String[][] techLists) {
@@ -450,13 +533,18 @@ public final class NfcAdapter {
} }
/** /**
* Disables foreground activity dispatching setup with * Disable foreground dispatch to the given activity.
* {@link #enableForegroundDispatch}.
* *
* <p>This must be called before the Activity returns from * <p>After calling {@link #enableForegroundDispatch}, an activity
* it's <code>onPause()</code> or this method will throw an IllegalStateException. * must call this method before its {@link Activity#onPause} callback
* completes.
* *
* <p>This method must be called from the main thread. * <p>This method must be called from the main thread.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param activity the Activity to disable dispatch to
* @throws IllegalStateException if the Activity has already been paused
*/ */
public void disableForegroundDispatch(Activity activity) { public void disableForegroundDispatch(Activity activity) {
ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity, ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,
@@ -484,13 +572,24 @@ public final class NfcAdapter {
} }
/** /**
* Enable NDEF message push over P2P while this Activity is in the foreground. For this to * Enable NDEF message push over P2P while this Activity is in the foreground.
* function properly the other NFC device being scanned must support the "com.android.npp"
* NDEF push protocol.
* *
* <p><em>NOTE</em> While foreground NDEF push is active standard tag dispatch is disabled. * <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 class="note"><em>NOTE:</em> While foreground NDEF push is active standard tag dispatch is disabled.
* Only the foreground activity may receive tag discovered dispatches via * Only the foreground activity may receive tag discovered dispatches via
* {@link #enableForegroundDispatch}. * {@link #enableForegroundDispatch}.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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) { public void enableForegroundNdefPush(Activity activity, NdefMessage msg) {
if (activity == null || msg == null) { if (activity == null || msg == null) {
@@ -510,13 +609,19 @@ public final class NfcAdapter {
} }
/** /**
* Disables foreground NDEF push setup with * Disable NDEF message push over P2P.
* {@link #enableForegroundNdefPush}.
* *
* <p>This must be called before the Activity returns from * <p>After calling {@link #enableForegroundNdefPush}, an activity
* it's <code>onPause()</code> or this method will throw an IllegalStateException. * must call this method before its {@link Activity#onPause} callback
* completes.
* *
* <p>This method must be called from the main thread. * <p>This method must be called from the main thread.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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) { public void disableForegroundNdefPush(Activity activity) {
ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity, ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,

View File

@@ -16,6 +16,7 @@
package android.nfc; package android.nfc;
import android.content.Context;
import android.nfc.tech.IsoDep; import android.nfc.tech.IsoDep;
import android.nfc.tech.MifareClassic; import android.nfc.tech.MifareClassic;
import android.nfc.tech.MifareUltralight; import android.nfc.tech.MifareUltralight;
@@ -33,27 +34,76 @@ import android.os.Parcelable;
import java.util.Arrays; import java.util.Arrays;
/** /**
* Represents a (generic) discovered tag. * Represents an NFC tag that has been discovered.
* <p> * <p>
* A tag is a passive NFC element, such as NFC Forum Tag's, MIFARE class Tags, * {@link Tag} is an immutable object that represents the state of a NFC tag at
* Sony FeliCa Tags, etc. * 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 via {@link #getId} and the
* set of technologies it contains via {@link #getTechList}. Arrays passed to and
* returned by this class are <em>not</em> cloned, so be careful not to modify them.
* <p> * <p>
* Tag's have a type and usually have a UID. * 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 activity via the {@link NfcAdapter#EXTRA_TAG} extra in an
* {@link android.content.Intent} via {@link Context#startActivity}. A four stage dispatch is used
* to select the
* most appropriate activity to handle the tag. The Android OS executes each stage in order,
* and completes dispatch as soon as a single matching activity is found. If there are multiple
* matching activities found at any one stage then the Android activity chooser dialog is shown
* to allow the user to select the activity to receive the tag.
*
* <p>The Tag dispatch mechanism was designed to give a high probability of dispatching
* a tag to the correct activity without showing the user an activity 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 will likely be broken.
*
* <h4>1. Foreground activity dispatch</h4>
* A foreground activity that has called
* {@link NfcAdapter#enableForegroundDispatch NfcAdapter.enableForegroundDispatch()} is
* given priority. See the documentation on
* {@link NfcAdapter#enableForegroundDispatch NfcAdapter.enableForegroundDispatch()} for
* its usage.
* <h4>2. NDEF data dispatch</h4>
* If the tag contains NDEF data the system inspects the first {@link NdefRecord} in the first
* {@link NdefMessage}. If the record is a URI, SmartPoster, or MIME data
* {@link Context#startActivity} is called with {@link NfcAdapter#ACTION_NDEF_DISCOVERED}. For URI
* and SmartPoster records the URI is put into the intent's data field. For MIME records the MIME
* type is put in the intent's type field. This allows activities to register to be launched only
* when data they know how to handle is present on a tag. This is the preferred method of handling
* data on a tag since NDEF data can be stored on many types of tags and doesn't depend on a
* specific tag technology.
* See {@link NfcAdapter#ACTION_NDEF_DISCOVERED} for more detail. If the tag does not contain
* NDEF data, or if no activity is registered
* for {@link NfcAdapter#ACTION_NDEF_DISCOVERED} with a matching data URI or MIME type 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 activity 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 activity 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 activity 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}.
*
* <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 fobs, or
* even embedded in a more sophisticated device.
* <p> * <p>
* {@link Tag} objects are passed to applications via the {@link NfcAdapter#EXTRA_TAG} extra * Tags can have a wide range of capabilities. Simple tags just offer read/write semantics,
* in {@link NfcAdapter#ACTION_TAG_DISCOVERED} intents. A {@link Tag} object is immutable * and contain some one time
* and represents the state of the tag at the time of discovery. It can be * programmable areas to make read-only. More complex tags offer math operations
* directly queried for its UID and Type, or used to create a {@link TagTechnology} using the * and per-sector access control and authentication. The most sophisticated tags
* static <code>get()</code> methods on the varios tech classes. * contain operating environments allowing complex interactions with the
* code executing on the tag. Use {@link TagTechnology} classes to access a broad
* range of capabilities available in NFC tags.
* <p> * <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 { public final class Tag implements Parcelable {
/*package*/ final byte[] mId; /*package*/ final byte[] mId;
@@ -149,21 +199,35 @@ public final class Tag implements Parcelable {
/** /**
* Get the Tag Identifier (if it has one). * Get the Tag Identifier (if it has one).
* <p>Tag ID is usually a serial number for the tag. * <p>The tag identifier is a low level serial number, used for anti-collision
* * and identification.
* @return ID, or null if it does not exist * <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() { public byte[] getId() {
return mId; return mId;
} }
/** /**
* Returns technologies present in the tag that this implementation understands, * Get the technologies available in this tag, as fully qualified class names.
* or a zero length array if there are no supported technologies on this tag. * <p>
* * A technology is an implementation of the {@link TagTechnology} interface,
* The elements of the list are the names of the classes implementing the technology. * 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. * 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() { public String[] getTechList() {
return mTechStringList; return mTechStringList;
@@ -198,6 +262,9 @@ public final class Tag implements Parcelable {
return mTagService; return mTagService;
} }
/**
* Human-readable description of the tag, for debugging.
*/
@Override @Override
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder("TAG ") StringBuilder sb = new StringBuilder("TAG ")

View File

@@ -24,18 +24,17 @@ import android.util.Log;
import java.io.IOException; import java.io.IOException;
/** /**
* A low-level connection to a {@link Tag} using the ISO-DEP technology, also known as * Provides access to ISO-DEP (ISO 14443-4) properties and I/O operations on a {@link Tag}.
* ISO1443-4.
* *
* <p>You can acquire this kind of connection with {@link #get}. * <p>Acquire an {@link IsoDep} object using {@link #get}.
* Use this class to send and receive data with {@link #transceive transceive()}. * <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).
* *
* <p>Applications must implement their own protocol stack on top of * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
* {@link #transceive transceive()}. * require the {@link android.Manifest.permission#NFC} permission.
*
* <p class="note"><strong>Note:</strong>
* Use of this class requires the {@link android.Manifest.permission#NFC}
* permission.
*/ */
public final class IsoDep extends BasicTagTechnology { public final class IsoDep extends BasicTagTechnology {
private static final String TAG = "NFC"; private static final String TAG = "NFC";
@@ -49,10 +48,13 @@ public final class IsoDep extends BasicTagTechnology {
private byte[] mHistBytes = null; private byte[] mHistBytes = null;
/** /**
* Returns an instance of this tech for the given tag. If the tag doesn't support * Get an instance of {@link IsoDep} for the given tag.
* this tech type null is returned. * <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) { public static IsoDep get(Tag tag) {
if (!tag.hasTech(TagTechnology.ISO_DEP)) return null; if (!tag.hasTech(TagTechnology.ISO_DEP)) return null;
@@ -75,13 +77,16 @@ public final class IsoDep extends BasicTagTechnology {
} }
/** /**
* Sets the timeout of an IsoDep transceive transaction in milliseconds. * Set the timeout of {@link #transceive} in milliseconds.
* If the transaction has not completed before the timeout, * <p>The timeout only applies to ISO-DEP {@link #transceive}, and is
* any ongoing {@link #transceive} operation will be * reset to a default value when {@link #close} is called.
* aborted and the connection to the tag is lost. This setting is applied * <p>Setting a longer timeout may be useful when performing
* only to the {@link Tag} object linked to this technology and will be * transactions that require a long processing time on the tag
* reset when {@link IsoDep#close} is called. * such as key generation.
* The default transaction timeout is 300 milliseconds. *
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param timeout timeout value in milliseconds
*/ */
public void setTimeout(int timeout) { public void setTimeout(int timeout) {
try { try {
@@ -102,29 +107,53 @@ 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() { public byte[] getHistoricalBytes() {
return mHistBytes; 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() { public byte[] getHiLayerResponse() {
return mHiLayerResponse; return mHiLayerResponse;
} }
/** /**
* Send data to a tag and receive the response. * Send raw ISO-DEP data to the 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.
* *
* @param data bytes to send * <p>Applications must only send the INF payload, and not the start of frame and
* @return bytes received in response * end of frame indicators. Applications do not need to fragment the payload, it
* @throws IOException if the target is lost or connection closed * 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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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 { public byte[] transceive(byte[] data) throws IOException {
return transceive(data, true); return transceive(data, true);

View File

@@ -25,32 +25,64 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder; 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 * <p>Acquire a {@link MifareClassic} object using {@link #get}.
* MIFARE Classic tags will still be scanned, but will only show the NfcA technology.
* *
* <p>MIFARE Classic tags have sectors that each contain blocks. The block size is constant at * <p>MIFARE Classic is also known as MIFARE Standard.
* 16 bytes, but the number of sectors and the sector size varies by product. MIFARE has encryption * <p>MIFARE Classic tags are divided into sectors, and each sector is sub-divided into
* built in and each sector has two keys associated with it, as well as ACLs to determine what * blocks. Block size is always 16 bytes ({@link #BLOCK_SIZE}. Sector size varies.
* level acess each key grants. Before operating on a sector you must call either * <ul>
* {@link #authenticateSectorWithKeyA(int, byte[])} or * <li>MIFARE Classic Mini are 320 bytes ({@link #SIZE_MINI}), with 5 sectors each of 4 blocks.
* {@link #authenticateSectorWithKeyB(int, byte[])} to gain authorization for your request. * <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 NXP specification for NDEF on MIFARE Classic.
*
* <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}.
*
* <p class="note"><strong>Note:</strong> Methods that perform I/O operations
* require the {@link android.Manifest.permission#NFC} permission.
*/ */
public final class MifareClassic extends BasicTagTechnology { public final class MifareClassic extends BasicTagTechnology {
/** /**
* The well-known default MIFARE read key. All keys are set to this at the factory. * The default factory key.
* Using this key will effectively make the payload in the sector public.
*/ */
public static final byte[] KEY_DEFAULT = public static final byte[] KEY_DEFAULT =
{(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF}; {(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 = public static final byte[] KEY_MIFARE_APPLICATION_DIRECTORY =
{(byte)0xA0,(byte)0xA1,(byte)0xA2,(byte)0xA3,(byte)0xA4,(byte)0xA5}; {(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 = public static final byte[] KEY_NFC_FORUM =
{(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7}; {(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7};
@@ -64,19 +96,19 @@ public final class MifareClassic extends BasicTagTechnology {
/** A MIFARE Pro tag */ /** A MIFARE Pro tag */
public static final int TYPE_PRO = 2; 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; 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; 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. * contain 16 blocks.
*/ */
public static final int SIZE_4K = 4096; 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; 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; public static final int BLOCK_SIZE = 16;
private static final int MAX_BLOCK_COUNT = 256; private static final int MAX_BLOCK_COUNT = 256;
@@ -87,10 +119,14 @@ public final class MifareClassic extends BasicTagTechnology {
private int mSize; private int mSize;
/** /**
* Returns an instance of this tech for the given tag. If the tag doesn't support * Get an instance of {@link MifareClassic} for the given tag.
* this tech type null is returned. * <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) { public static MifareClassic get(Tag tag) {
if (!tag.hasTech(TagTechnology.MIFARE_CLASSIC)) return null; if (!tag.hasTech(TagTechnology.MIFARE_CLASSIC)) return null;
@@ -160,17 +196,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() { public int getType() {
return mType; 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() { public int getSize() {
return mSize; 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. * These are actually smart-cards that emulate a Mifare Classic interface.
* They can be treated identically to a Mifare Classic tag. * They can be treated identically to a Mifare Classic tag.
* @hide * @hide
@@ -179,7 +229,11 @@ public final class MifareClassic extends BasicTagTechnology {
return mIsEmulated; 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() { public int getSectorCount() {
switch (mSize) { switch (mSize) {
case SIZE_1K: case SIZE_1K:
@@ -195,12 +249,22 @@ 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() { public int getBlockCount() {
return mSize / BLOCK_SIZE; 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) { public int getBlockCountInSector(int sectorIndex) {
validateSector(sectorIndex); validateSector(sectorIndex);
@@ -211,7 +275,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) { public int blockToSector(int blockIndex) {
validateBlock(blockIndex); validateBlock(blockIndex);
@@ -222,7 +292,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) { public int sectorToBlock(int sectorIndex) {
if (sectorIndex < 32) { if (sectorIndex < 32) {
return sectorIndex * 4; return sectorIndex * 4;
@@ -231,22 +307,55 @@ public final class MifareClassic extends BasicTagTechnology {
} }
} }
// Methods that require connect()
/** /**
* Authenticate a sector. * Authenticate a sector with key A.
* <p>Every sector has an A and B key with different access privileges, *
* this method attempts to authenticate against the A key. * <p>Successful authentication of a sector with key A enables other
* <p>This requires a that the tag be connected. * 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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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 { public boolean authenticateSectorWithKeyA(int sectorIndex, byte[] key) throws IOException {
return authenticate(sectorIndex, key, true); return authenticate(sectorIndex, key, true);
} }
/** /**
* Authenticate a sector. * Authenticate a sector with key B.
* <p>Every sector has an A and B key with different access privileges, *
* this method attempts to authenticate against the B key. * <p>Successful authentication of a sector with key B enables other
* <p>This requires a that the tag be connected. * 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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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 { public boolean authenticateSectorWithKeyB(int sectorIndex, byte[] key) throws IOException {
return authenticate(sectorIndex, key, false); return authenticate(sectorIndex, key, false);
@@ -291,8 +400,17 @@ public final class MifareClassic extends BasicTagTechnology {
/** /**
* Read 16-byte block. * 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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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 { public byte[] readBlock(int blockIndex) throws IOException {
validateBlock(blockIndex); validateBlock(blockIndex);
@@ -304,8 +422,17 @@ public final class MifareClassic extends BasicTagTechnology {
/** /**
* Write 16-byte block. * 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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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 { public void writeBlock(int blockIndex, byte[] data) throws IOException {
validateBlock(blockIndex); validateBlock(blockIndex);
@@ -323,9 +450,18 @@ public final class MifareClassic extends BasicTagTechnology {
} }
/** /**
* Increment a value block, and store the result in temporary memory. * Increment a value block, storing the result in the temporary block on the tag.
* @param blockIndex *
* @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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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 { public void increment(int blockIndex, int value) throws IOException {
validateBlock(blockIndex); validateBlock(blockIndex);
@@ -342,9 +478,18 @@ public final class MifareClassic extends BasicTagTechnology {
} }
/** /**
* Decrement a value block, and store the result in temporary memory. * Decrement a value block, storing the result in the temporary block on the tag.
* @param blockIndex *
* @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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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 { public void decrement(int blockIndex, int value) throws IOException {
validateBlock(blockIndex); validateBlock(blockIndex);
@@ -361,9 +506,17 @@ public final class MifareClassic extends BasicTagTechnology {
} }
/** /**
* Copy from temporary memory to value block. * Copy from the temporary block to a value block.
* @param blockIndex *
* @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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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 { public void transfer(int blockIndex) throws IOException {
validateBlock(blockIndex); validateBlock(blockIndex);
@@ -375,9 +528,17 @@ public final class MifareClassic extends BasicTagTechnology {
} }
/** /**
* Copy from value block to temporary memory. * Copy from a value block to the temporary block.
* @param blockIndex *
* @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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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 { public void restore(int blockIndex) throws IOException {
validateBlock(blockIndex); validateBlock(blockIndex);
@@ -390,15 +551,18 @@ public final class MifareClassic extends BasicTagTechnology {
/** /**
* Send raw NfcA data to a tag and receive the response. * 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 * <p>This is equivalent to connecting to this tag via {@link NfcA}
* @return bytes received in response * and calling {@link NfcA#transceive}. Note that all MIFARE Classic
* @throws IOException if the target is lost or connection closed * 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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @see NfcA#transceive
*/ */
public byte[] transceive(byte[] data) throws IOException { public byte[] transceive(byte[] data) throws IOException {
return transceive(data, true); return transceive(data, true);

View File

@@ -17,6 +17,7 @@
package android.nfc.tech; package android.nfc.tech;
import android.nfc.Tag; import android.nfc.Tag;
import android.nfc.TagLostException;
import android.os.RemoteException; import android.os.RemoteException;
import java.io.IOException; import java.io.IOException;
@@ -24,14 +25,13 @@ import java.io.IOException;
//TOOD: Ultralight C 3-DES authentication, one-way counter //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 * <p>Acquire a {@link MifareUltralight} object using {@link #get}.
* MIFARE Ultralight class tags will still be scanned, but will only show the NfcA technology.
* *
* <p>MIFARE Ultralight compatible tags have 4 byte pages. The read command * <p>MIFARE Ultralight compatible tags have 4 byte pages {@link #PAGE_SIZE}.
* returns 4 pages (16 bytes) at a time, for speed. The write command operates * The primary operations on an Ultralight tag are {@link #readPages} and
* on a single page (4 bytes) to minimize EEPROM write cycles. * {@link #writePage}.
* *
* <p>The original MIFARE Ultralight consists of a 64 byte EEPROM. The first * <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 * 4 pages are for the OTP area, manufacturer data, and locking bits. They are
@@ -44,6 +44,16 @@ import java.io.IOException;
* and authentication configuration and are readable. The final 4 pages are for * and authentication configuration and are readable. The final 4 pages are for
* the authentication key and are not readable. For more information see the * the authentication key and are not readable. For more information see the
* NXP data sheet MF0ICU2. * 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.
*
* <p class="note"><strong>Note:</strong> Methods that perform I/O operations
* require the {@link android.Manifest.permission#NFC} permission.
*/ */
public final class MifareUltralight extends BasicTagTechnology { public final class MifareUltralight extends BasicTagTechnology {
/** A MIFARE Ultralight compatible tag of unknown type */ /** A MIFARE Ultralight compatible tag of unknown type */
@@ -62,10 +72,15 @@ public final class MifareUltralight extends BasicTagTechnology {
private int mType; private int mType;
/** /**
* Returns an instance of this tech for the given tag. If the tag doesn't support * Get an instance of {@link MifareUltralight} for the given tag.
* this tech type null is returned. * <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) { public static MifareUltralight get(Tag tag) {
if (!tag.hasTech(TagTechnology.MIFARE_ULTRALIGHT)) return null; if (!tag.hasTech(TagTechnology.MIFARE_ULTRALIGHT)) return null;
@@ -93,28 +108,43 @@ public final class MifareUltralight extends BasicTagTechnology {
} }
} }
/** Returns the type of the tag. /**
* <p>It is very hard to always accurately classify a MIFARE Ultralight * Return the MIFARE Ultralight type of the tag.
* compatible tag as Ultralight original or Ultralight C. So consider * <p>One of {@link #TYPE_ULTRALIGHT} or {@link #TYPE_ULTRALIGHT_C} or
* {@link #getType} a hint. */ * {@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() { public int getType() {
return mType; return mType;
} }
// Methods that require connect()
/** /**
* Read 4 pages (16 bytes). * 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 * return pages that have been wrapped back to the first blocks. MIFARE
* Ultralight tags have readable blocks 0x00 through 0x0F. So a read to * Ultralight tags have readable blocks 0x00 through 0x0F. So a read to
* block offset 0x0E would return blocks 0x0E, 0x0F, 0x00, 0x01. MIFARE * block offset 0x0E would return blocks 0x0E, 0x0F, 0x00, 0x01. MIFARE
* Ultralight C tags have readable blocks 0x00 through 0x2B. So a read to * Ultralight C tags have readable blocks 0x00 through 0x2B. So a read to
* block 0x2A would return blocks 0x2A, 0x2B, 0x00, 0x01. * 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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param pageOffset index of first page to read, starting from 0
* @return 4 pages (16 bytes) * @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 { public byte[] readPages(int pageOffset) throws IOException {
validatePageOffset(pageOffset); validatePageOffset(pageOffset);
@@ -126,12 +156,20 @@ public final class MifareUltralight extends BasicTagTechnology {
/** /**
* Write 1 page (4 bytes). * 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 * <p>The MIFARE Ultralight protocol always writes 1 page at a time, to
* @param data The data to write * minimize EEPROM write cycles.
* @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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param pageOffset 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 { public void writePage(int pageOffset, byte[] data) throws IOException {
validatePageOffset(pageOffset); validatePageOffset(pageOffset);
@@ -147,15 +185,18 @@ public final class MifareUltralight extends BasicTagTechnology {
/** /**
* Send raw NfcA data to a tag and receive the response. * 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 * <p>This is equivalent to connecting to this tag via {@link NfcA}
* @return bytes received in response * and calling {@link NfcA#transceive}. Note that all MIFARE Classic
* @throws IOException if the target is lost or connection closed * 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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @see NfcA#transceive
*/ */
public byte[] transceive(byte[] data) throws IOException { public byte[] transceive(byte[] data) throws IOException {
return transceive(data, true); return transceive(data, true);

View File

@@ -22,6 +22,7 @@ import android.nfc.INfcTag;
import android.nfc.NdefMessage; import android.nfc.NdefMessage;
import android.nfc.NfcAdapter; import android.nfc.NfcAdapter;
import android.nfc.Tag; import android.nfc.Tag;
import android.nfc.TagLostException;
import android.os.Bundle; import android.os.Bundle;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
@@ -29,15 +30,44 @@ import android.util.Log;
import java.io.IOException; import java.io.IOException;
/** /**
* A high-level connection to a {@link Tag} using one of the NFC type 1, 2, 3, or 4 technologies * Provides access to NDEF content and operations on a {@link Tag}.
* 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()}
* *
* <p>You can acquire this kind of connection with {@link #get}. * <p>Acquire a {@link Ndef} object using {@link #get}.
* *
* <p class="note"><strong>Note:</strong> * <p>NDEF is an NFC Forum data format. The data formats are implemented in
* Use of this class requires the {@link android.Manifest.permission#NFC} * {@link android.nfc.NdefMessage} and
* permission. * {@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> Methods that perform I/O operations
* require the {@link android.Manifest.permission#NFC} permission.
*/ */
public final class Ndef extends BasicTagTechnology { public final class Ndef extends BasicTagTechnology {
private static final String TAG = "NFC"; private static final String TAG = "NFC";
@@ -77,14 +107,15 @@ public final class Ndef extends BasicTagTechnology {
/** @hide */ /** @hide */
public static final String UNKNOWN = "android.ndef.unknown"; 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"; 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"; 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"; 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"; 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"; public static final String MIFARE_CLASSIC = "com.nxp.ndef.mifareclassic";
private final int mMaxNdefSize; private final int mMaxNdefSize;
@@ -93,10 +124,17 @@ public final class Ndef extends BasicTagTechnology {
private final int mNdefType; private final int mNdefType;
/** /**
* Returns an instance of this tech for the given tag. If the tag doesn't support * Get an instance of {@link Ndef} for the given tag.
* this tech type null is returned.
* *
* @param tag The tag to get the tech from * <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.
*
* <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) { public static Ndef get(Tag tag) {
if (!tag.hasTech(TagTechnology.NDEF)) return null; if (!tag.hasTech(TagTechnology.NDEF)) return null;
@@ -126,22 +164,29 @@ public final class Ndef extends BasicTagTechnology {
} }
/** /**
* Get the primary NDEF message on this tag. This data is read at discovery time * Get the {@link NdefMessage} that was read from the tag at discovery time.
* and does not require a connection. *
* <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() { public NdefMessage getCachedNdefMessage() {
return mNdefMsg; 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}, * <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 #NFC_FORUM_TYPE_3}, {@link #NFC_FORUM_TYPE_4},
* {@link #MIFARE_CLASSIC} or another NDEF tag type that is not yet in the * {@link #MIFARE_CLASSIC} or another NDEF tag type that has not yet been
* Android API. * formalized in this Android API.
* <p>Android devices with NFC support must always correctly enumerate *
* NFC Forum tag types, and may optionally enumerate * <p>Does not cause any RF activity and does not block.
* {@link #MIFARE_CLASSIC} since it requires proprietary technology. *
* @return a string representing the NDEF tag type
*/ */
public String getType() { public String getType() {
switch (mNdefType) { switch (mNdefType) {
@@ -161,25 +206,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() { public int getMaxSize() {
return mMaxNdefSize; 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. * <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() { public boolean isWritable() {
return (mCardState == NDEF_MODE_READ_WRITE); return (mCardState == NDEF_MODE_READ_WRITE);
} }
// Methods that require connect()
/** /**
* Get the primary NDEF message on this tag. This data is read actively * Read the current {@link android.nfc.NdefMessage} on this tag.
* and requires a connection. *
* <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 { public NdefMessage getNdefMessage() throws IOException, FormatException {
checkConnected(); checkConnected();
@@ -212,8 +276,18 @@ public final class Ndef extends BasicTagTechnology {
} }
/** /**
* Overwrite the primary NDEF message * Overwrite the {@link NdefMessage} on this tag.
* @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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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 { public void writeNdefMessage(NdefMessage msg) throws IOException, FormatException {
checkConnected(); checkConnected();
@@ -244,8 +318,11 @@ public final class Ndef extends BasicTagTechnology {
} }
/** /**
* Indicates whether a tag can be made read-only with * Indicates whether a tag can be made read-only with {@link #makeReadOnly()}.
* {@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() { public boolean canMakeReadOnly() {
if (mNdefType == TYPE_1 || mNdefType == TYPE_2) { if (mNdefType == TYPE_1 || mNdefType == TYPE_2) {
@@ -256,11 +333,22 @@ public final class Ndef extends BasicTagTechnology {
} }
/** /**
* Sets the CC field to indicate this tag is read-only * Make a tag read-only.
* and permanently sets the lock bits to prevent any further NDEF *
* modifications. * <p>This sets the CC field to indicate the tag is read-only,
* This is a one-way process and can not be reverted! * and where possible permanently sets the lock bits to prevent
* @throws IOException * 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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @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 { public boolean makeReadOnly() throws IOException {
checkConnected(); checkConnected();

View File

@@ -22,28 +22,39 @@ import android.nfc.INfcTag;
import android.nfc.NdefMessage; import android.nfc.NdefMessage;
import android.nfc.NfcAdapter; import android.nfc.NfcAdapter;
import android.nfc.Tag; import android.nfc.Tag;
import android.nfc.TagLostException;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import java.io.IOException; 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 class="note"><strong>Note:</strong> * <p>Android devices with NFC must only enumerate and implement this
* Use of this class requires the {@link android.Manifest.permission#NFC} * class for tags for which it can format to NDEF.
* permission. *
* <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> Methods that perform I/O operations
* require the {@link android.Manifest.permission#NFC} permission.
*/ */
public final class NdefFormatable extends BasicTagTechnology { public final class NdefFormatable extends BasicTagTechnology {
private static final String TAG = "NFC"; private static final String TAG = "NFC";
/** /**
* Returns an instance of this tech for the given tag. If the tag doesn't support * Get an instance of {@link NdefFormatable} for the given tag.
* this tech type null is returned. * <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) { public static NdefFormatable get(Tag tag) {
if (!tag.hasTech(TagTechnology.NDEF_FORMATABLE)) return null; if (!tag.hasTech(TagTechnology.NDEF_FORMATABLE)) return null;
@@ -63,20 +74,44 @@ public final class NdefFormatable extends BasicTagTechnology {
} }
/** /**
* Formats a tag as NDEF, if possible. You may supply a first * Format a tag as NDEF, and write a {@link NdefMessage}.
* NdefMessage to be written on the tag. *
* <p>Either all steps succeed, or an IOException is thrown if any one step * <p>This is a multi-step process, an IOException is thrown
* fails. * 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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param firstMessage the NDEF message to write after formatting, can 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 format(NdefMessage firstMessage) throws IOException, FormatException { public void format(NdefMessage firstMessage) throws IOException, FormatException {
format(firstMessage, false); format(firstMessage, false);
} }
/** /**
* Formats a tag as NDEF, if possible. You may supply a first * Formats a tag as NDEF, write a {@link NdefMessage}, and make read-only.
* NdefMessage to be written on the tag. *
* <p>Either all steps succeed, or an IOException is thrown if any one step * <p>This is a multi-step process, an IOException is thrown
* fails. * 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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
*
* @param firstMessage 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 { public void formatReadOnly(NdefMessage firstMessage) throws IOException, FormatException {
format(firstMessage, true); format(firstMessage, true);

View File

@@ -23,18 +23,14 @@ import android.os.RemoteException;
import java.io.IOException; import java.io.IOException;
/** /**
* A low-level connection to a {@link Tag} using the NFC-A technology, also known as * Provides access to NFC-A (ISO 14443-3A) properties and I/O operations on a {@link Tag}.
* ISO1443-3A.
* *
* <p>You can acquire this kind of connection with {@link #get}. * <p>Acquire a {@link NfcA} object using {@link #get}.
* Use this class to send and receive data with {@link #transceive transceive()}. * <p>The primary NFC-A I/O operation is {@link #transceive}. Applications must
* implement their own protocol stack on top of {@link #transceive}.
* *
* <p>Applications must implement their own protocol stack on top of * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
* {@link #transceive transceive()}. * require the {@link android.Manifest.permission#NFC} permission.
*
* <p class="note"><strong>Note:</strong>
* Use of this class requires the {@link android.Manifest.permission#NFC}
* permission.
*/ */
public final class NfcA extends BasicTagTechnology { public final class NfcA extends BasicTagTechnology {
/** @hide */ /** @hide */
@@ -46,10 +42,13 @@ public final class NfcA extends BasicTagTechnology {
private byte[] mAtqa; private byte[] mAtqa;
/** /**
* Returns an instance of this tech for the given tag. If the tag doesn't support * Get an instance of {@link NfcA} for the given tag.
* this tech type null is returned. * <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) { public static NfcA get(Tag tag) {
if (!tag.hasTech(TagTechnology.NFC_A)) return null; if (!tag.hasTech(TagTechnology.NFC_A)) return null;
@@ -69,29 +68,46 @@ 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() { public byte[] getAtqa() {
return mAtqa; 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() { public short getSak() {
return mSak; return mSak;
} }
/** /**
* Send data to a tag and receive the response. * Send raw NFC-A commands to the tag and receive the response.
* <p> *
* This method will block until the response is received. It can be canceled * <p>Applications must not append the EoD (CRC) to the payload,
* with {@link #close}. * it will be automatically calculated.
* <p>Requires {@link android.Manifest.permission#NFC} permission. * <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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
* *
* @param data bytes to send * @param data bytes to send
* @return bytes received in response * @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 { public byte[] transceive(byte[] data) throws IOException {
return transceive(data, true); return transceive(data, true);

View File

@@ -23,18 +23,14 @@ import android.os.RemoteException;
import java.io.IOException; import java.io.IOException;
/** /**
* A low-level connection to a {@link Tag} using the NFC-B technology, also known as * Provides access to NFC-B (ISO 14443-3B) properties and I/O operations on a {@link Tag}.
* ISO1443-3B.
* *
* <p>You can acquire this kind of connection with {@link #get}. * <p>Acquire a {@link NfcB} object using {@link #get}.
* Use this class to send and receive data with {@link #transceive transceive()}. * <p>The primary NFC-B I/O operation is {@link #transceive}. Applications must
* implement their own protocol stack on top of {@link #transceive}.
* *
* <p>Applications must implement their own protocol stack on top of * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
* {@link #transceive transceive()}. * require the {@link android.Manifest.permission#NFC} permission.
*
* <p class="note"><strong>Note:</strong>
* Use of this class requires the {@link android.Manifest.permission#NFC}
* permission.
*/ */
public final class NfcB extends BasicTagTechnology { public final class NfcB extends BasicTagTechnology {
/** @hide */ /** @hide */
@@ -46,10 +42,13 @@ public final class NfcB extends BasicTagTechnology {
private byte[] mProtInfo; private byte[] mProtInfo;
/** /**
* Returns an instance of this tech for the given tag. If the tag doesn't support * Get an instance of {@link NfcB} for the given tag.
* this tech type null is returned. * <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) { public static NfcB get(Tag tag) {
if (!tag.hasTech(TagTechnology.NFC_B)) return null; if (!tag.hasTech(TagTechnology.NFC_B)) return null;
@@ -69,31 +68,45 @@ public final class NfcB extends BasicTagTechnology {
} }
/** /**
* Returns the Application Data bytes from the ATQB/SENSB_RES * Return the Application Data bytes from ATQB/SENSB_RES at tag discovery.
* bytes discovered 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() { public byte[] getApplicationData() {
return mAppData; return mAppData;
} }
/** /**
* Returns the Protocol Info bytes from the ATQB/SENSB_RES * Return the Protocol Info bytes from ATQB/SENSB_RES at tag discovery.
* bytes discovered 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() { public byte[] getProtocolInfo() {
return mProtInfo; return mProtInfo;
} }
/** /**
* Send data to a tag and receive the response. * Send raw NFC-B commands to the tag and receive the response.
* <p> *
* This method will block until the response is received. It can be canceled * <p>Applications must not append the EoD (CRC) to the payload,
* with {@link #close}. * it will be automatically calculated.
* <p>Requires {@link android.Manifest.permission#NFC} permission. * <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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
* *
* @param data bytes to send * @param data bytes to send
* @return bytes received in response * @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 { public byte[] transceive(byte[] data) throws IOException {
return transceive(data, true); return transceive(data, true);

View File

@@ -23,18 +23,14 @@ import android.os.RemoteException;
import java.io.IOException; import java.io.IOException;
/** /**
* A low-level connection to a {@link Tag} using the NFC-F technology, also known as * Provides access to NFC-F (JIS 6319-4) properties and I/O operations on a {@link Tag}.
* JIS6319-4.
* *
* <p>You can acquire this kind of connection with {@link #get}. * <p>Acquire a {@link NfcF} object using {@link #get}.
* Use this class to send and receive data with {@link #transceive transceive()}. * <p>The primary NFC-F I/O operation is {@link #transceive}. Applications must
* implement their own protocol stack on top of {@link #transceive}.
* *
* <p>Applications must implement their own protocol stack on top of * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
* {@link #transceive transceive()}. * require the {@link android.Manifest.permission#NFC} permission.
*
* <p class="note"><strong>Note:</strong>
* Use of this class requires the {@link android.Manifest.permission#NFC}
* permission.
*/ */
public final class NfcF extends BasicTagTechnology { public final class NfcF extends BasicTagTechnology {
/** @hide */ /** @hide */
@@ -46,10 +42,13 @@ public final class NfcF extends BasicTagTechnology {
private byte[] mManufacturer = null; private byte[] mManufacturer = null;
/** /**
* Returns an instance of this tech for the given tag. If the tag doesn't support * Get an instance of {@link NfcF} for the given tag.
* this tech type null is returned. * <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) { public static NfcF get(Tag tag) {
if (!tag.hasTech(TagTechnology.NFC_F)) return null; if (!tag.hasTech(TagTechnology.NFC_F)) return null;
@@ -70,24 +69,44 @@ 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() { public byte[] getSystemCode() {
return mSystemCode; 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() { public byte[] getManufacturer() {
return mManufacturer; return mManufacturer;
} }
/** /**
* Send data to a tag and receive the response. * Send raw NFC-F commands to the tag and receive the response.
* <p> *
* This method will block until the response is received. It can be canceled * <p>Applications must not append the SoD (length) or EoD (CRC) to the payload,
* with {@link #close}. * it will be automatically calculated.
* <p>Requires {@link android.Manifest.permission#NFC} permission. *
* <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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
* *
* @param data bytes to send * @param data bytes to send
* @return bytes received in response * @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 { public byte[] transceive(byte[] data) throws IOException {
return transceive(data, true); return transceive(data, true);

View File

@@ -23,18 +23,14 @@ import android.os.RemoteException;
import java.io.IOException; import java.io.IOException;
/** /**
* A low-level connection to a {@link Tag} using NFC vicinity technology, also known as * Provides access to NFC-V (ISO 15693) properties and I/O operations on a {@link Tag}.
* ISO15693.
* *
* <p>You can acquire this kind of connection with {@link #get}. * <p>Acquire a {@link NfcV} object using {@link #get}.
* Use this class to send and receive data with {@link #transceive transceive()}. * <p>The primary NFC-V I/O operation is {@link #transceive}. Applications must
* implement their own protocol stack on top of {@link #transceive}.
* *
* <p>Applications must implement their own protocol stack on top of * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
* {@link #transceive transceive()}. * require the {@link android.Manifest.permission#NFC} permission.
*
* <p class="note"><strong>Note:</strong>
* Use of this class requires the {@link android.Manifest.permission#NFC}
* permission.
*/ */
public final class NfcV extends BasicTagTechnology { public final class NfcV extends BasicTagTechnology {
/** @hide */ /** @hide */
@@ -47,10 +43,13 @@ public final class NfcV extends BasicTagTechnology {
private byte mDsfId; private byte mDsfId;
/** /**
* Returns an instance of this tech for the given tag. If the tag doesn't support * Get an instance of {@link NfcV} for the given tag.
* this tech type null is returned. * <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) { public static NfcV get(Tag tag) {
if (!tag.hasTech(TagTechnology.NFC_V)) return null; if (!tag.hasTech(TagTechnology.NFC_V)) return null;
@@ -69,24 +68,45 @@ public final class NfcV extends BasicTagTechnology {
mDsfId = extras.getByte(EXTRA_DSFID); 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() { public byte getResponseFlags() {
return mRespFlags; 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() { public byte getDsfId() {
return mDsfId; return mDsfId;
} }
/** /**
* Send data to a tag and receive the response. * Send raw NFC-V commands to the tag and receive the response.
* <p> *
* This method will block until the response is received. It can be canceled * <p>Applications must not append the CRC to the payload,
* with {@link #close}. * it will be automatically calculated. The application does
* <p>Requires {@link android.Manifest.permission#NFC} permission. * 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.
*
* <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
* *
* @param data bytes to send * @param data bytes to send
* @return bytes received in response * @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 { public byte[] transceive(byte[] data) throws IOException {
return transceive(data, true); return transceive(data, true);

View File

@@ -21,6 +21,64 @@ import android.nfc.Tag;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; 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>
*
* <p class="note"><strong>Note:</strong> Methods that perform I/O operations
* require the {@link android.Manifest.permission#NFC} permission.
*/
public interface TagTechnology extends Closeable { public interface TagTechnology extends Closeable {
/** /**
* This technology is an instance of {@link NfcA}. * This technology is an instance of {@link NfcA}.
@@ -90,22 +148,24 @@ public interface TagTechnology extends Closeable {
public static final int MIFARE_ULTRALIGHT = 9; 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(); public Tag getTag();
/** /**
* Opens a connection to the {@link Tag} enabling interactive commands. The command set * Enable I/O operations to the tag from this {@link TagTechnology} object.
* varies by the technology type. * <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.
* *
* <p>This method blocks until the connection has been established. * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
* *
* <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.
*
* @see #reconnect()
* @see #close() * @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; public void connect() throws IOException;
@@ -113,40 +173,39 @@ public interface TagTechnology extends Closeable {
* Re-connect to the {@link Tag} associated with this connection. Reconnecting to a tag can be * 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. * used to reset the state of the tag itself.
* *
* <p>This method blocks until the connection is re-established. * <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>A call to {@link #close} from another thread will cancel a blocked call and cause an * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
* IOException to be thrown on the thread that is blocked.
* *
* @see #connect() * @see #connect()
* @see #close() * @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 * @hide
*/ */
public void reconnect() throws IOException; public void reconnect() throws IOException;
/** /**
* Closes the connection to the {@link Tag}. This call is non-blocking and causes all blocking * Disable I/O operations to the tag from this {@link TagTechnology} object, and release resources.
* operations such as {@link #connect} to be canceled and immediately throw * <p>Also causes all blocked I/O operations on other thread to be canceled and
* {@link java.io.IOException} on the thread that is blocked. * return with {@link IOException}.
* *
* <p> * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
* Once this method is called, this object cannot be re-used and should be discarded. Further
* calls to {@link #connect} will fail.
* *
* @see #connect() * @see #connect()
* @see #reconnect()
*/ */
public void close() throws IOException; public void close() throws IOException;
/** /**
* Helper to indicate if {@link #connect} has succeeded. * Helper to indicate if I/O operations should be possible.
* <p> *
* Does not cause RF activity, and does not block. * <p>Returns true if {@link #connect} has completed, and {@link #close} has not been
* @return true if {@link #connect} has completed successfully and the {@link Tag} is believed * called, and the {@link Tag} is not known to be out of range.
* to be within range. Applications must still handle {@link java.io.IOException} * <p>Does not cause RF activity, and does not block.
* while using methods that require a connection in case the connection is lost after this *
* method returns. * @return true if I/O operations should be possible
*/ */
public boolean isConnected(); public boolean isConnected();
} }