diff options
| author | Nick Pelly <npelly@google.com> | 2010-10-21 21:42:24 -0700 |
|---|---|---|
| committer | Nick Pelly <npelly@google.com> | 2010-10-22 16:29:43 -0700 |
| commit | 07f3bee2db8b6e93ebbf7222676bd9f468e85569 (patch) | |
| tree | 4d1d6a9f81252ebda078954da4380b470f0b320b /core/java | |
| parent | 67496e591dca9c7faa07f6e1c8849c9d5af4edb9 (diff) | |
Push Tag/NdefTag implementation details into the service.
Tag/NdefTag objects should just be simple data objects. Push the mapping of
internal tag type to public rawTarget/ndefTarget into Nfc Service.
This gives an oppurtunity to clean up some Tag/NdefTag API methods. Most
significantly, adding createMockTag() and createMockNdefTag() to help with
application testing.
There will probably be some more tweaking of the types/targets in
Tag/NdefTag to come, this commit makes that a lot easier.
Also:
- Introduce getActivationBytes() and getPollBytes(). These are just stubs
for NFC service to implement, we have feedback these are really important
to help identify NFC tags.
- Based on outside advice, remove 3B_PRIME (roll into 3B) and TOPAZ (roll
into 3A).
Change-Id: I3e6789c047f6ee5c298bf76c65e0885cf3c15d97
Signed-off-by: Nick Pelly <npelly@google.com>
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/nfc/NdefTag.java | 207 | ||||
| -rw-r--r-- | core/java/android/nfc/NdefTagConnection.java | 10 | ||||
| -rw-r--r-- | core/java/android/nfc/NfcAdapter.java | 12 | ||||
| -rw-r--r-- | core/java/android/nfc/RawTagConnection.java | 6 | ||||
| -rw-r--r-- | core/java/android/nfc/Tag.java | 295 |
5 files changed, 301 insertions, 229 deletions
diff --git a/core/java/android/nfc/NdefTag.java b/core/java/android/nfc/NdefTag.java index 45cdc317f010..d8681dc21798 100644 --- a/core/java/android/nfc/NdefTag.java +++ b/core/java/android/nfc/NdefTag.java @@ -16,8 +16,6 @@ package android.nfc; -import java.util.HashMap; - import android.os.Parcel; import android.os.Parcelable; @@ -33,19 +31,92 @@ import android.os.Parcelable; * is possible for {@link NdefTag}s to contain multiple {@link NdefMessage}s. * <p>{@link NfcAdapter#createNdefTagConnection createNdefTagConnection()} can be used to modify the * contents of some tags. - * <p>This is an immutable data class. + * <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 class NdefTag extends Tag implements Parcelable { - private final NdefMessage[] mMessages; + /** + * Target for NFC Forum Type 1 compliant tag. + * <p>This is based on Jewel/Topaz technology + */ + public static final String TARGET_TYPE_1 = "type_1"; + + /** + * Target for NFC Forum Type 2 compliant tag. + * <p>This is based on Mifare Ultralight technology. + */ + public static final String TARGET_TYPE_2 = "type_2"; /** - * Hidden constructor to be used by NFC service when a - * tag is discovered and by Parcelable methods. + * Target for NFC Forum Type 3 compliant tag. + * <p>This is based on Felica technology. + */ + public static final String TARGET_TYPE_3 = "type_3"; + + /** + * Target for NFC Forum Type 4 compliant tag. + * <p>This is based on Mifare Desfire technology. + */ + public static final String TARGET_TYPE_4 = "type_4"; + + /** + * Target for NFC Forum Enabled: Mifare Classic tag. + * <p>This is not strictly a NFC Forum tag type, but is a common + * NDEF message container. + */ + public static final String TARGET_MIFARE_CLASSIC = "type_mifare_classic"; + + /** + * Any other target. + */ + public static final String TARGET_OTHER = "other"; + + private final String[] mNdefTargets; + private final NdefMessage[][] mMessages; // one NdefMessage[] per NDEF target + private NdefMessage[] mFlatMessages; // collapsed mMessages, built lazily, protected by (this) + + /** + * Hidden constructor to be used by NFC service only. * @hide */ - public NdefTag(String typeName, byte[] uid, int nativeHandle, NdefMessage[] messages) { - super(typeName, true, uid, nativeHandle); - mMessages = messages.clone(); + public NdefTag(byte[] id, String[] rawTargets, byte[] pollBytes, byte[] activationBytes, + int serviceHandle, String[] ndefTargets, NdefMessage[][] messages) { + super(id, true, rawTargets, pollBytes, activationBytes, serviceHandle); + if (ndefTargets == null || messages == null) { + throw new IllegalArgumentException("ndefTargets or messages cannot be null"); + } + if (ndefTargets.length != messages.length){ + throw new IllegalArgumentException("ndefTargets and messages arrays must match"); + } + for (NdefMessage[] ms : messages) { + if (ms == null) { + throw new IllegalArgumentException("messages elements cannot be null"); + } + } + mNdefTargets = ndefTargets; + mMessages = messages; + } + + /** + * Construct a mock NdefTag. + * <p>This is an application constructed tag, so NfcAdapter methods on this + * Tag such as {@link NfcAdapter#createRawTagConnection} will fail with + * {@link IllegalArgumentException} since it does not represent a physical Tag. + * <p>This constructor might be useful for mock testing. + * @param id The tag identifier, can be null + * @param rawTargets must not be null + * @param pollBytes can be null + * @param activationBytes can be null + * @param ndefTargets NDEF target array, such as {TARGET_TYPE_2}, cannot be null + * @param messages messages, one array per NDEF target, cannot be null + * @return freshly constructed NdefTag + */ + public static NdefTag createMockNdefTag(byte[] id, String[] rawTargets, byte[] pollBytes, + byte[] activationBytes, String[] ndefTargets, NdefMessage[][] messages) { + // set serviceHandle to 0 to indicate mock tag + return new NdefTag(id, rawTargets, pollBytes, activationBytes, 0, ndefTargets, messages); } /** @@ -59,7 +130,29 @@ public class NdefTag extends Tag implements Parcelable { * @return NDEF Messages found at Tag discovery */ public NdefMessage[] getNdefMessages() { - return mMessages.clone(); + // common-case optimization + if (mMessages.length == 1) { + return mMessages[0]; + } + + // return cached flat array + synchronized(this) { + if (mFlatMessages != null) { + return mFlatMessages; + } + // not cached - build a flat array + int sz = 0; + for (NdefMessage[] ms : mMessages) { + sz += ms.length; + } + mFlatMessages = new NdefMessage[sz]; + int i = 0; + for (NdefMessage[] ms : mMessages) { + System.arraycopy(ms, 0, mFlatMessages, i, ms.length); + i += ms.length; + } + return mFlatMessages; + } } /** @@ -70,58 +163,25 @@ public class NdefTag extends Tag implements Parcelable { * <p> * Most tags only contain a single NDEF message. * - * @param target One of targets strings provided by getNdefTargets() + * @param target one of targets strings provided by getNdefTargets() * @return NDEF Messages found at Tag discovery */ public NdefMessage[] getNdefMessages(String target) { - // TODO: handle multiprotocol - String[] localTypes = convertToNdefType(mTypeName); - if (!target.equals(localTypes[0])) { - throw new IllegalArgumentException(); - } - return getNdefMessages(); - } - - /** TODO(npelly): - * - check that any single tag can only have one of each NDEF type - * - ok to include mifare_classic? - */ - public static final String TARGET_TYPE_1 = "type_1"; - public static final String TARGET_TYPE_2 = "type_2"; - public static final String TARGET_TYPE_3 = "type_3"; - public static final String TARGET_TYPE_4 = "type_4"; - public static final String TARGET_MIFARE_CLASSIC = "type_mifare_classic"; - public static final String TARGET_OTHER = "other"; - - private static final HashMap<String, String[]> NDEF_TYPES_CONVERTION_TABLE = new HashMap<String, String[]>() { - { - // TODO: handle multiprotocol - // TODO: move INTERNAL_TARGET_Type to TARGET_TYPE mapping to NFC service - put(Tag.INTERNAL_TARGET_TYPE_JEWEL, new String[] { NdefTag.TARGET_TYPE_1 }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_UL, new String[] { NdefTag.TARGET_TYPE_2 }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_1K, new String[] { NdefTag.TARGET_MIFARE_CLASSIC }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_4K, new String[] { NdefTag.TARGET_MIFARE_CLASSIC }); - put(Tag.INTERNAL_TARGET_TYPE_FELICA, new String[] { NdefTag.TARGET_TYPE_3 }); - put(Tag.INTERNAL_TARGET_TYPE_ISO14443_4, new String[] { NdefTag.TARGET_TYPE_4 }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_DESFIRE, new String[] { NdefTag.TARGET_TYPE_4 }); + for (int i=0; i<mNdefTargets.length; i++) { + if (target.equals(mNdefTargets[i])) { + return mMessages[i]; + } } - }; - - private String[] convertToNdefType(String internalTypeName) { - String[] result = NDEF_TYPES_CONVERTION_TABLE.get(internalTypeName); - if (result == null) { - return new String[] { NdefTag.TARGET_OTHER }; - } - return result; + throw new IllegalArgumentException("target (" + target + ") not found"); } /** - * Return the + * Return the NDEF targets on this Tag that support NDEF messages. * * @return */ public String[] getNdefTargets() { - return convertToNdefType(mTypeName); + return mNdefTargets; } @Override @@ -131,19 +191,50 @@ public class NdefTag extends Tag implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); + // Tag fields + dest.writeInt(mIsNdef ? 1 : 0); + writeBytesWithNull(dest, mId); + dest.writeInt(mRawTargets.length); + dest.writeStringArray(mRawTargets); + writeBytesWithNull(dest, mPollBytes); + writeBytesWithNull(dest, mActivationBytes); + dest.writeInt(mServiceHandle); + + // NdefTag fields + dest.writeInt(mNdefTargets.length); + dest.writeStringArray(mNdefTargets); dest.writeInt(mMessages.length); - dest.writeTypedArray(mMessages, flags); + for (NdefMessage[] ms : mMessages) { + dest.writeTypedArray(ms, flags); + } } public static final Parcelable.Creator<NdefTag> CREATOR = new Parcelable.Creator<NdefTag>() { public NdefTag createFromParcel(Parcel in) { - Tag tag = Tag.CREATOR.createFromParcel(in); - int messagesLength = in.readInt(); - NdefMessage[] messages = new NdefMessage[messagesLength]; - in.readTypedArray(messages, NdefMessage.CREATOR); - return new NdefTag(tag.mTypeName, tag.mUid, tag.mNativeHandle, messages); + boolean isNdef = (in.readInt() == 1); + if (!isNdef) { + throw new IllegalArgumentException("Creating NdefTag from Tag parcel"); + } + + // Tag fields + byte[] id = readBytesWithNull(in); + String[] rawTargets = new String[in.readInt()]; + in.readStringArray(rawTargets); + byte[] pollBytes = readBytesWithNull(in); + byte[] activationBytes = readBytesWithNull(in); + int serviceHandle = in.readInt(); + + // NdefTag fields + String[] ndefTargets = new String[in.readInt()]; + in.readStringArray(ndefTargets); + NdefMessage[][] messages = new NdefMessage[in.readInt()][]; + for (int i=0; i<messages.length; i++) { + messages[i] = new NdefMessage[in.readInt()]; + in.readTypedArray(messages[i], NdefMessage.CREATOR); + } + return new NdefTag(id, rawTargets, pollBytes, activationBytes, serviceHandle, + ndefTargets, messages); } public NdefTag[] newArray(int size) { return new NdefTag[size]; diff --git a/core/java/android/nfc/NdefTagConnection.java b/core/java/android/nfc/NdefTagConnection.java index 4795fa72ec6c..321b0eca1685 100644 --- a/core/java/android/nfc/NdefTagConnection.java +++ b/core/java/android/nfc/NdefTagConnection.java @@ -81,9 +81,9 @@ public class NdefTagConnection extends RawTagConnection { //TODO(nxp): do not use getLastError(), it is racy try { NdefMessage[] msgArray = new NdefMessage[1]; - NdefMessage msg = mTagService.read(mTag.mNativeHandle); + NdefMessage msg = mTagService.read(mTag.mServiceHandle); if (msg == null) { - int errorCode = mTagService.getLastError(mTag.mNativeHandle); + int errorCode = mTagService.getLastError(mTag.mServiceHandle); switch (errorCode) { case ErrorCodes.ERROR_IO: throw new IOException(); @@ -121,7 +121,7 @@ public class NdefTagConnection extends RawTagConnection { */ public void writeNdefMessage(NdefMessage message) throws IOException, FormatException { try { - int errorCode = mTagService.write(mTag.mNativeHandle, message); + int errorCode = mTagService.write(mTag.mServiceHandle, message); switch (errorCode) { case ErrorCodes.SUCCESS: break; @@ -148,7 +148,7 @@ public class NdefTagConnection extends RawTagConnection { */ public boolean makeReadOnly() throws IOException { try { - int errorCode = mTagService.makeReadOnly(mTag.mNativeHandle); + int errorCode = mTagService.makeReadOnly(mTag.mServiceHandle); switch (errorCode) { case ErrorCodes.SUCCESS: return true; @@ -175,7 +175,7 @@ public class NdefTagConnection extends RawTagConnection { */ public int getModeHint() throws IOException { try { - int result = mTagService.getModeHint(mTag.mNativeHandle); + int result = mTagService.getModeHint(mTag.mServiceHandle); if (ErrorCodes.isError(result)) { switch (result) { case ErrorCodes.ERROR_IO: diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index 6884abb59c99..7f4b4a260ac9 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -327,6 +327,9 @@ public final class NfcAdapter { * <p>Requires {@link android.Manifest.permission#NFC} permission. */ public RawTagConnection createRawTagConnection(Tag tag) { + if (tag.mServiceHandle == 0) { + throw new IllegalArgumentException("mock tag cannot be used for connections"); + } try { return new RawTagConnection(mService, tag); } catch (RemoteException e) { @@ -340,6 +343,9 @@ public final class NfcAdapter { * <p>Requires {@link android.Manifest.permission#NFC} permission. */ public RawTagConnection createRawTagConnection(Tag tag, String target) { + if (tag.mServiceHandle == 0) { + throw new IllegalArgumentException("mock tag cannot be used for connections"); + } try { return new RawTagConnection(mService, tag, target); } catch (RemoteException e) { @@ -353,6 +359,9 @@ public final class NfcAdapter { * <p>Requires {@link android.Manifest.permission#NFC} permission. */ public NdefTagConnection createNdefTagConnection(NdefTag tag) { + if (tag.mServiceHandle == 0) { + throw new IllegalArgumentException("mock tag cannot be used for connections"); + } try { return new NdefTagConnection(mService, tag); } catch (RemoteException e) { @@ -366,6 +375,9 @@ public final class NfcAdapter { * <p>Requires {@link android.Manifest.permission#NFC} permission. */ public NdefTagConnection createNdefTagConnection(NdefTag tag, String target) { + if (tag.mServiceHandle == 0) { + throw new IllegalArgumentException("mock tag cannot be used for connections"); + } try { return new NdefTagConnection(mService, tag, target); } catch (RemoteException e) { diff --git a/core/java/android/nfc/RawTagConnection.java b/core/java/android/nfc/RawTagConnection.java index 1261db10a86c..cf8283b762be 100644 --- a/core/java/android/nfc/RawTagConnection.java +++ b/core/java/android/nfc/RawTagConnection.java @@ -100,7 +100,7 @@ public class RawTagConnection { } try { - return mTagService.isPresent(mTag.mNativeHandle); + return mTagService.isPresent(mTag.mServiceHandle); } catch (RemoteException e) { Log.e(TAG, "NFC service died", e); return false; @@ -135,7 +135,7 @@ public class RawTagConnection { public void close() { mIsConnected = false; try { - mTagService.close(mTag.mNativeHandle); + mTagService.close(mTag.mServiceHandle); } catch (RemoteException e) { Log.e(TAG, "NFC service died", e); } @@ -154,7 +154,7 @@ public class RawTagConnection { */ public byte[] transceive(byte[] data) throws IOException { try { - byte[] response = mTagService.transceive(mTag.mNativeHandle, data); + byte[] response = mTagService.transceive(mTag.mServiceHandle, data); if (response == null) { throw new IOException("transcieve failed"); } diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java index abf02b5024f2..7741ad2ae462 100644 --- a/core/java/android/nfc/Tag.java +++ b/core/java/android/nfc/Tag.java @@ -16,8 +16,6 @@ package android.nfc; -import java.util.HashMap; - import android.os.Parcel; import android.os.Parcelable; @@ -39,202 +37,168 @@ import android.os.Parcelable; * 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 RawTagConnection}. - * <p>This is an immutable data class. + * <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 class Tag implements Parcelable { - - /** - * @hide - */ - public static final int NFC_TAG_ISO14443_A = 1; /* phNfc_eISO14443_A_PICC */ - - /** - * @hide - */ - public static final int NFC_TAG_ISO14443_4A = 2; /* phNfc_eISO14443_4A_PICC */ - - /** - * @hide - */ - public static final int NFC_TAG_ISO14443_3A = 3; /* phNfc_eISO14443_3A_PICC */ - - /** - * @hide - */ - public static final int NFC_TAG_MIFARE = 4; /* phNfc_eMifare_PICC */ - - /** - * @hide - */ - public static final int NFC_TAG_ISO14443_B = 5; /* phNfc_eISO14443_B_PICC */ - /** - * @hide + * ISO 14443-3A technology. + * <p> + * Includes Topaz (which is -3A compatible) */ - public static final int NFC_TAG_ISO14443_4B = 6; /* phNfc_eISO14443_4B_PICC */ + public static final String TARGET_ISO_14443_3A = "iso14443_3a"; /** - * @hide + * ISO 14443-3B technology. */ - public static final int NFC_TAG_ISO14443_B_PRIME = 7; /* phNfc_eISO14443_BPrime_PICC */ + public static final String TARGET_ISO_14443_3B = "iso14443_3b"; /** - * @hide + * ISO 14443-4 technology. */ - public static final int NFC_TAG_FELICA = 8; /* phNfc_eFelica_PICC */ + public static final String TARGET_ISO_14443_4 = "iso14443_4"; /** - * @hide + * ISO 15693 technology, commonly known as RFID. */ - public static final int NFC_TAG_JEWEL = 9; /* phNfc_eJewel_PICC */ + public static final String TARGET_ISO_15693 = "iso15693"; /** - * @hide + * JIS X-6319-4 technology, commonly known as Felica. */ - public static final int NFC_TAG_ISO15693 = 10; /* phNfc_eISO15693_PICC */ + public static final String TARGET_JIS_X_6319_4 = "jis_x_6319_4"; /** - * @hide + * Any other technology. */ - public static final int NFC_TAG_OTHER = 11; /* phNfc_ePICC_DevType */ - - - public static final String TARGET_ISO_14443_3A = "iso14443_3a"; - - public static final String TARGET_ISO_14443_3B = "iso14443_3b"; - - public static final String TARGET_ISO_14443_3B_PRIME = "iso14443_3b"; - - public static final String TARGET_ISO_14443_4 = "iso14443_4"; - - public static final String TARGET_ISO_15693 = "iso15693"; - - public static final String TARGET_JIS_X_6319_4 = "jis_x_6319_4"; - - public static final String TARGET_TOPAZ = "topaz"; - public static final String TARGET_OTHER = "other"; - /*package*/ final String mTypeName; /*package*/ final boolean mIsNdef; - /*package*/ final byte[] mUid; - /*package*/ final int mNativeHandle; - - /*package*/ static final String INTERNAL_TARGET_TYPE_ISO14443_3A = "Iso14443-3A"; - /*package*/ static final String INTERNAL_TARGET_TYPE_ISO14443_3B = "Iso14443-3B"; - /*package*/ static final String INTERNAL_TARGET_TYPE_ISO14443_4 = "Iso14443-4"; - /*package*/ static final String INTERNAL_TARGET_TYPE_MIFARE_UL = "MifareUL"; - /*package*/ static final String INTERNAL_TARGET_TYPE_MIFARE_1K = "Mifare1K"; - /*package*/ static final String INTERNAL_TARGET_TYPE_MIFARE_4K = "Mifare4K"; - /*package*/ static final String INTERNAL_TARGET_TYPE_MIFARE_DESFIRE = "MifareDESFIRE"; - /*package*/ static final String INTERNAL_TARGET_TYPE_MIFARE_UNKNOWN = "Unknown Mifare"; - /*package*/ static final String INTERNAL_TARGET_TYPE_FELICA = "Felica"; - /*package*/ static final String INTERNAL_TARGET_TYPE_JEWEL = "Jewel"; - /*package*/ static final String INTERNAL_TARGET_TYPE_UNKNOWN = "Unknown Type"; - - private static final HashMap<String, Integer> INT_TYPES_CONVERTION_TABLE = new HashMap<String, Integer>() { - { - put(Tag.INTERNAL_TARGET_TYPE_ISO14443_3A, Tag.NFC_TAG_ISO14443_A ); - put(Tag.INTERNAL_TARGET_TYPE_ISO14443_3B, Tag.NFC_TAG_ISO14443_B ); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_UL, Tag.NFC_TAG_MIFARE ); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_1K, Tag.NFC_TAG_MIFARE ); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_4K, Tag.NFC_TAG_MIFARE ); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_DESFIRE, Tag.NFC_TAG_MIFARE ); - put(Tag.INTERNAL_TARGET_TYPE_FELICA, Tag.NFC_TAG_FELICA ); - put(Tag.INTERNAL_TARGET_TYPE_JEWEL, Tag.NFC_TAG_JEWEL ); - } - }; - - private int convertToInt(String internalTypeName) { - Integer result = INT_TYPES_CONVERTION_TABLE.get(internalTypeName); - if (result == null) { - return Tag.NFC_TAG_OTHER; - } - return result; - } - - private static final HashMap<String, String[]> RAW_TYPES_CONVERTION_TABLE = new HashMap<String, String[]>() { - { - /* TODO: handle multiprotocol */ - put(Tag.INTERNAL_TARGET_TYPE_ISO14443_3A, new String[] { Tag.TARGET_ISO_14443_3A }); - put(Tag.INTERNAL_TARGET_TYPE_ISO14443_3B, new String[] { Tag.TARGET_ISO_14443_3B }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_UL, new String[] { Tag.TARGET_ISO_14443_3A }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_1K, new String[] { Tag.TARGET_ISO_14443_3A }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_4K, new String[] { Tag.TARGET_ISO_14443_3A }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_DESFIRE, new String[] { Tag.TARGET_ISO_14443_3A }); - put(Tag.INTERNAL_TARGET_TYPE_MIFARE_UNKNOWN, new String[] { Tag.TARGET_ISO_14443_3A }); - put(Tag.INTERNAL_TARGET_TYPE_FELICA, new String[] { Tag.TARGET_JIS_X_6319_4 }); - put(Tag.INTERNAL_TARGET_TYPE_JEWEL, new String[] { Tag.TARGET_TOPAZ }); - } - }; - - private String[] convertToRaw(String internalTypeName) { - String[] result = RAW_TYPES_CONVERTION_TABLE.get(internalTypeName); - if (result == null) { - return new String[] { Tag.TARGET_OTHER }; - } - return result; - } + /*package*/ final byte[] mId; + /*package*/ final String[] mRawTargets; + /*package*/ final byte[] mPollBytes; + /*package*/ final byte[] mActivationBytes; + /*package*/ final int mServiceHandle; // for use by NFC service, 0 indicates a mock /** - * Hidden constructor to be used by NFC service only. + * Hidden constructor to be used by NFC service and internal classes. * @hide */ - public Tag(String typeName, boolean isNdef, byte[] uid, int nativeHandle) { - mTypeName = typeName; + public Tag(byte[] id, boolean isNdef, String[] rawTargets, byte[] pollBytes, + byte[] activationBytes, int serviceHandle) { + if (rawTargets == null) { + throw new IllegalArgumentException("rawTargets cannot be null"); + } mIsNdef = isNdef; - mUid = uid.clone(); - mNativeHandle = nativeHandle; + mId = id; + mRawTargets = rawTargets; + mPollBytes = pollBytes; + mActivationBytes = activationBytes; + mServiceHandle = serviceHandle; + } + + /** + * Construct a mock Tag. + * <p>This is an application constructed tag, so NfcAdapter methods on this + * Tag such as {@link NfcAdapter#createRawTagConnection} will fail with + * {@link IllegalArgumentException} since it does not represent a physical Tag. + * <p>This constructor might be useful for mock testing. + * @param id The tag identifier, can be null + * @param rawTargets must not be null + * @param pollBytes can be null + * @param activationBytes can be null + * @return freshly constructed tag + */ + public static Tag createMockTag(byte[] id, String[] rawTargets, byte[] pollBytes, + byte[] activationBytes) { + // set serviceHandle to 0 to indicate mock tag + return new Tag(id, false, rawTargets, pollBytes, activationBytes, 0); } /** * For use by NfcService only. * @hide */ - public int getHandle() { - return mNativeHandle; + public int getServiceHandle() { + return mServiceHandle; } /** * Return the available targets that this NFC adapter can use to create * a RawTagConnection. * - * @return + * @return raw targets, will not be null */ public String[] getRawTargets() { - return convertToRaw(mTypeName); + return mRawTargets; } /** - * Get the Tag type. - * <p> - * The Tag type is one of the NFC_TAG constants. It is read at discovery - * time and this method does not cause any further RF activity and does not - * block. + * Get the Tag Identifier (if it has one). + * <p>Tag ID is usually a serial number for the tag. * - * @return a NFC_TAG constant - * @hide + * @return ID, or null if it does not exist + */ + public byte[] getId() { + return mId; + } + + /** + * Get the low-level bytes returned by this Tag at poll-time. + * <p>These can be used to help with advanced identification of a Tag. + * <p>The meaning of these bytes depends on the Tag technology. + * @return poll bytes, or null if they do not exist for this Tag technology */ - public int getType() { - return convertToInt(mTypeName); + public byte[] getPollBytes() { + return mPollBytes; } /** - * Get the Tag Identifier (if it has one). - * <p> - * Tag ID is usually a serial number for the tag. - * <p> - * The Tag ID is read at discovery time and this method does not cause any - * further RF activity and does not block. - * - * @return ID, or null if it does not exist + * Get the low-level bytes returned by this Tag at activation-time. + * <p>These can be used to help with advanced identification of a Tag. + * <p>The meaning of these bytes depends on the Tag technology. + * @return activation bytes, or null if they do not exist for this Tag technology */ - public byte[] getId() { - if (mUid.length > 0) { - return mUid.clone(); - } else { - return null; + public byte[] getActivationBytes() { + return mActivationBytes; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("TAG ") + .append("uid = ") + .append(mId) + .append(" poll ") + .append(mPollBytes) + .append(" activation ") + .append(mActivationBytes) + .append(" Raw ["); + for (String s : mRawTargets) { + sb.append(s) + .append(", "); + } + return sb.toString(); + } + + /*package*/ static byte[] readBytesWithNull(Parcel in) { + int len = in.readInt(); + byte[] result = null; + if (len > 0) { + result = new byte[len]; + in.readByteArray(result); } + return result; + } + + /*package*/ static void writeBytesWithNull(Parcel out, byte[] b) { + if (b == null) { + out.writeInt(-1); + return; + } + out.writeInt(b.length); + out.writeByteArray(b); } @Override @@ -242,29 +206,34 @@ public class Tag implements Parcelable { return 0; } + @Override public void writeToParcel(Parcel dest, int flags) { - boolean[] booleans = new boolean[] {mIsNdef}; - dest.writeString(mTypeName); - dest.writeBooleanArray(booleans); - dest.writeInt(mUid.length); - dest.writeByteArray(mUid); - dest.writeInt(mNativeHandle); + dest.writeInt(mIsNdef ? 1 : 0); + writeBytesWithNull(dest, mId); + dest.writeInt(mRawTargets.length); + dest.writeStringArray(mRawTargets); + writeBytesWithNull(dest, mPollBytes); + writeBytesWithNull(dest, mActivationBytes); + dest.writeInt(mServiceHandle); } public static final Parcelable.Creator<Tag> CREATOR = new Parcelable.Creator<Tag>() { public Tag createFromParcel(Parcel in) { - boolean[] booleans = new boolean[1]; - String type = in.readString(); - in.readBooleanArray(booleans); - boolean isNdef = booleans[0]; - int uidLength = in.readInt(); - byte[] uid = new byte[uidLength]; - in.readByteArray(uid); - int nativeHandle = in.readInt(); - - return new Tag(type, isNdef, uid, nativeHandle); + boolean isNdef = (in.readInt() == 1); + if (isNdef) { + throw new IllegalArgumentException("Creating Tag from NdefTag parcel"); + } + // Tag fields + byte[] id = Tag.readBytesWithNull(in); + String[] rawTargets = new String[in.readInt()]; + in.readStringArray(rawTargets); + byte[] pollBytes = Tag.readBytesWithNull(in); + byte[] activationBytes = Tag.readBytesWithNull(in); + int serviceHandle = in.readInt(); + + return new Tag(id, isNdef, rawTargets, pollBytes, activationBytes, serviceHandle); } public Tag[] newArray(int size) { return new Tag[size]; |
