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>
This commit is contained in:
@ -100172,6 +100172,29 @@
|
||||
>
|
||||
<implements name="android.os.Parcelable">
|
||||
</implements>
|
||||
<method name="createMockNdefTag"
|
||||
return="android.nfc.NdefTag"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="true"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="id" type="byte[]">
|
||||
</parameter>
|
||||
<parameter name="rawTargets" type="java.lang.String[]">
|
||||
</parameter>
|
||||
<parameter name="pollBytes" type="byte[]">
|
||||
</parameter>
|
||||
<parameter name="activationBytes" type="byte[]">
|
||||
</parameter>
|
||||
<parameter name="ndefTargets" type="java.lang.String[]">
|
||||
</parameter>
|
||||
<parameter name="messages" type="android.nfc.NdefMessage[][]">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="getNdefMessages"
|
||||
return="android.nfc.NdefMessage[]"
|
||||
abstract="false"
|
||||
@ -100641,6 +100664,25 @@
|
||||
>
|
||||
<implements name="android.os.Parcelable">
|
||||
</implements>
|
||||
<method name="createMockTag"
|
||||
return="android.nfc.Tag"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="true"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
<parameter name="id" type="byte[]">
|
||||
</parameter>
|
||||
<parameter name="rawTargets" type="java.lang.String[]">
|
||||
</parameter>
|
||||
<parameter name="pollBytes" type="byte[]">
|
||||
</parameter>
|
||||
<parameter name="activationBytes" type="byte[]">
|
||||
</parameter>
|
||||
</method>
|
||||
<method name="describeContents"
|
||||
return="int"
|
||||
abstract="false"
|
||||
@ -100652,6 +100694,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getActivationBytes"
|
||||
return="byte[]"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getId"
|
||||
return="byte[]"
|
||||
abstract="false"
|
||||
@ -100663,6 +100716,17 @@
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getPollBytes"
|
||||
return="byte[]"
|
||||
abstract="false"
|
||||
native="false"
|
||||
synchronized="false"
|
||||
static="false"
|
||||
final="false"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</method>
|
||||
<method name="getRawTargets"
|
||||
return="java.lang.String[]"
|
||||
abstract="false"
|
||||
@ -100721,17 +100785,6 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="TARGET_ISO_14443_3B_PRIME"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""iso14443_3b""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="TARGET_ISO_14443_4"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
@ -100776,17 +100829,6 @@
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
<field name="TARGET_TOPAZ"
|
||||
type="java.lang.String"
|
||||
transient="false"
|
||||
volatile="false"
|
||||
value=""topaz""
|
||||
static="true"
|
||||
final="true"
|
||||
deprecated="not deprecated"
|
||||
visibility="public"
|
||||
>
|
||||
</field>
|
||||
</class>
|
||||
</package>
|
||||
<package name="android.opengl"
|
||||
|
@ -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";
|
||||
|
||||
/**
|
||||
* Hidden constructor to be used by NFC service when a
|
||||
* tag is discovered and by Parcelable methods.
|
||||
* 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";
|
||||
|
||||
/**
|
||||
* 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();
|
||||
for (int i=0; i<mNdefTargets.length; i++) {
|
||||
if (target.equals(mNdefTargets[i])) {
|
||||
return mMessages[i];
|
||||
}
|
||||
}
|
||||
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 });
|
||||
}
|
||||
};
|
||||
|
||||
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];
|
||||
|
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
* ISO 14443-3A technology.
|
||||
* <p>
|
||||
* Includes Topaz (which is -3A compatible)
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public static final int NFC_TAG_ISO14443_4B = 6; /* phNfc_eISO14443_4B_PICC */
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final int NFC_TAG_ISO14443_B_PRIME = 7; /* phNfc_eISO14443_BPrime_PICC */
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final int NFC_TAG_FELICA = 8; /* phNfc_eFelica_PICC */
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final int NFC_TAG_JEWEL = 9; /* phNfc_eJewel_PICC */
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final int NFC_TAG_ISO15693 = 10; /* phNfc_eISO15693_PICC */
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final int NFC_TAG_OTHER = 11; /* phNfc_ePICC_DevType */
|
||||
|
||||
|
||||
public static final String TARGET_ISO_14443_3A = "iso14443_3a";
|
||||
|
||||
/**
|
||||
* ISO 14443-3B technology.
|
||||
*/
|
||||
public static final String TARGET_ISO_14443_3B = "iso14443_3b";
|
||||
|
||||
public static final String TARGET_ISO_14443_3B_PRIME = "iso14443_3b";
|
||||
|
||||
/**
|
||||
* ISO 14443-4 technology.
|
||||
*/
|
||||
public static final String TARGET_ISO_14443_4 = "iso14443_4";
|
||||
|
||||
/**
|
||||
* ISO 15693 technology, commonly known as RFID.
|
||||
*/
|
||||
public static final String TARGET_ISO_15693 = "iso15693";
|
||||
|
||||
/**
|
||||
* JIS X-6319-4 technology, commonly known as Felica.
|
||||
*/
|
||||
public static final String TARGET_JIS_X_6319_4 = "jis_x_6319_4";
|
||||
|
||||
public static final String TARGET_TOPAZ = "topaz";
|
||||
|
||||
/**
|
||||
* Any other technology.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return a NFC_TAG constant
|
||||
* @hide
|
||||
*/
|
||||
public int getType() {
|
||||
return convertToInt(mTypeName);
|
||||
return mRawTargets;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p>Tag ID is usually a serial number for the tag.
|
||||
*
|
||||
* @return ID, or null if it does not exist
|
||||
*/
|
||||
public byte[] getId() {
|
||||
if (mUid.length > 0) {
|
||||
return mUid.clone();
|
||||
} else {
|
||||
return null;
|
||||
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 byte[] getPollBytes() {
|
||||
return mPollBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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[] 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();
|
||||
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(type, isNdef, uid, nativeHandle);
|
||||
return new Tag(id, isNdef, rawTargets, pollBytes, activationBytes, serviceHandle);
|
||||
}
|
||||
public Tag[] newArray(int size) {
|
||||
return new Tag[size];
|
||||
|
Reference in New Issue
Block a user