package android.nfc.tech;
import android.nfc.ErrorCodes;
import android.nfc.FormatException;
import android.nfc.INfcTag;
import android.nfc.NdefMessage;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.TagLostException;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import java.io.IOException;
/**
* Provides access to NDEF content and operations on a {@link Tag}.
*
* <p>Acquire a {@link Ndef} object using {@link #get}.
*
* <p>NDEF is an NFC Forum data format. The data formats are implemented in
* {@link android.nfc.NdefMessage} and
* {@link android.nfc.NdefRecord}. This class provides methods to
* retrieve and modify the {@link android.nfc.NdefMessage}
* on a tag.
*
* <p>There are currently four NFC Forum standardized tag types that can be
* formatted to contain NDEF data.
* <ul>
* <li>NFC Forum Type 1 Tag ({@link #NFC_FORUM_TYPE_1}), such as the Innovision Topaz
* <li>NFC Forum Type 2 Tag ({@link #NFC_FORUM_TYPE_2}), such as the NXP MIFARE Ultralight
* <li>NFC Forum Type 3 Tag ({@link #NFC_FORUM_TYPE_3}), such as Sony Felica
* <li>NFC Forum Type 4 Tag ({@link #NFC_FORUM_TYPE_4}), such as NXP MIFARE Desfire
* </ul>
* It is mandatory for all Android devices with NFC to correctly enumerate
* {@link Ndef} on NFC Forum Tag Types 1-4, and implement all NDEF operations
* as defined in this class.
*
* <p>Some vendors have there own well defined specifications for storing NDEF data
* on tags that do not fall into the above categories. Android devices with NFC
* should enumerate and implement {@link Ndef} under these vendor specifications
* where possible, but it is not mandatory. {@link #getType} returns a String
* describing this specification, for example {@link #MIFARE_CLASSIC} is
* <code>com.nxp.ndef.mifareclassic</code>.
*
* <p>Android devices that support MIFARE Classic must also correctly
* implement {@link Ndef} on MIFARE Classic tags formatted to NDEF.
*
* <p>For guaranteed compatibility across all Android devices with NFC, it is
* recommended to use NFC Forum Types 1-4 in new deployments of NFC tags
* with NDEF payload. Vendor NDEF formats will not work on all Android devices.
*
* <p class="note"><strong>Note:</strong> Methods that perform I/O operations
* require the {@link android.Manifest.permission#NFC} permission.
*/
public final class Ndef extends BasicTagTechnology {
private static final String TAG = "NFC";
/** @hide */
public static final int NDEF_MODE_READ_ONLY = 1;
/** @hide */
public static final int NDEF_MODE_READ_WRITE = 2;
/** @hide */
public static final int NDEF_MODE_UNKNOWN = 3;
/** @hide */
public static final String EXTRA_NDEF_MSG = "ndefmsg";
/** @hide */
public static final String EXTRA_NDEF_MAXLENGTH = "ndefmaxlength";
/** @hide */
public static final String EXTRA_NDEF_CARDSTATE = "ndefcardstate";
/** @hide */
public static final String EXTRA_NDEF_TYPE = "ndeftype";
/** @hide */
public static final int TYPE_OTHER = -1;
/** @hide */
public static final int TYPE_1 = 1;
/** @hide */
public static final int TYPE_2 = 2;
/** @hide */
public static final int TYPE_3 = 3;
/** @hide */
public static final int TYPE_4 = 4;
/** @hide */
public static final int TYPE_MIFARE_CLASSIC = 101;
/** @hide */
public static final int TYPE_ICODE_SLI = 102;
/** @hide */
public static final String UNKNOWN = "android.ndef.unknown";
/** NFC Forum Tag Type 1 */
public static final String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1";
/** NFC Forum Tag Type 2 */
public static final String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2";
/** NFC Forum Tag Type 4 */
public static final String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3";
/** NFC Forum Tag Type 4 */
public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4";
/** NDEF on MIFARE Classic */
public static final String MIFARE_CLASSIC = "com.nxp.ndef.mifareclassic";
/**
* NDEF on iCODE SLI
* @hide
*/
public static final String ICODE_SLI = "com.nxp.ndef.icodesli";
private final int mMaxNdefSize;
private final int mCardState;
private final NdefMessage mNdefMsg;
private final int mNdefType;
/**
* Get an instance of {@link Ndef} for the given tag.
*
* <p>Returns null if {@link Ndef} was not enumerated in {@link Tag#getTechList}.
* This indicates the tag is not NDEF formatted, or that this tag
* is NDEF formatted but under a vendor specification that this Android
* device does not implement.
*
* <p>Does not cause any RF activity and does not block.
*
* @param tag an MIFARE Classic compatible tag
* @return MIFARE Classic object
*/
public static Ndef get(Tag tag) {
if (!tag.hasTech(TagTechnology.NDEF)) return null;
try {
return new Ndef(tag);
} catch (RemoteException e) {
return null;
}
}
/**
* Internal constructor, to be used by NfcAdapter
* @hide
*/
public Ndef(Tag tag) throws RemoteException {
super(tag, TagTechnology.NDEF);
Bundle extras = tag.getTechExtras(TagTechnology.NDEF);
if (extras != null) {
mMaxNdefSize = extras.getInt(EXTRA_NDEF_MAXLENGTH);
mCardState = extras.getInt(EXTRA_NDEF_CARDSTATE);
mNdefMsg = extras.getParcelable(EXTRA_NDEF_MSG);
mNdefType = extras.getInt(EXTRA_NDEF_TYPE);
} else {
throw new NullPointerException("NDEF tech extras are null.");
}
}
/**
* Get the {@link NdefMessage} that was read from the tag at discovery time.
*
* <p>If the NDEF Message is modified by an I/O operation then it
* will not be updated here, this function only returns what was discovered
* when the tag entered the field.
* <p>Does not cause any RF activity and does not block.
* @return NDEF Message read from the tag at discovery time
*/
public NdefMessage getCachedNdefMessage() {
return mNdefMsg;
}
/**
* Get the NDEF tag type.
*
* <p>Returns one of {@link #NFC_FORUM_TYPE_1}, {@link #NFC_FORUM_TYPE_2},
* {@link #NFC_FORUM_TYPE_3}, {@link #NFC_FORUM_TYPE_4},
* {@link #MIFARE_CLASSIC} or another NDEF tag type that has not yet been
* formalized in this Android API.
*
* <p>Does not cause any RF activity and does not block.
*
* @return a string representing the NDEF tag type
*/
public String getType() {
switch (mNdefType) {
case TYPE_1:
return NFC_FORUM_TYPE_1;
case TYPE_2:
return NFC_FORUM_TYPE_2;
case TYPE_3:
return NFC_FORUM_TYPE_3;
case TYPE_4:
return NFC_FORUM_TYPE_4;
case TYPE_MIFARE_CLASSIC:
return MIFARE_CLASSIC;
case TYPE_ICODE_SLI:
return ICODE_SLI;
default:
return UNKNOWN;
}
}
/**
* Get the maximum NDEF message size in bytes.
*
* <p>Does not cause any RF activity and does not block.
*
* @return size in bytes
*/
public int getMaxSize() {
return mMaxNdefSize;
}
/**
* Determine if the tag is writable.
*
* <p>NFC Forum tags can be in read-only or read-write states.
*
* <p>Does not cause any RF activity and does not block.
*
* <p>Requires {@link android.Manifest.permission#NFC} permission.
*
* @return true if the tag is writable
*/
public boolean isWritable() {
return (mCardState == NDEF_MODE_READ_WRITE);
}
/**
* Read the current {@link android.nfc.NdefMessage} on this tag.
*
* <p>This always reads the current NDEF Message stored on the tag.
*
* <p