Implement methods introduced in draft #5 NFC API.

The API is implemented but still do not support muli-protocol tags.

Change-Id: I5cea3eec7b5b92e8e1106d4660e2400e4433e943
Signed-off-by: Nick Pelly <npelly@google.com>
diff --git a/core/java/android/nfc/NdefTag.java b/core/java/android/nfc/NdefTag.java
index 6d44e6e..45cdc31 100644
--- a/core/java/android/nfc/NdefTag.java
+++ b/core/java/android/nfc/NdefTag.java
@@ -16,6 +16,8 @@
 
 package android.nfc;
 
+import java.util.HashMap;
+
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -41,8 +43,8 @@
      * tag is discovered and by Parcelable methods.
      * @hide
      */
-    public NdefTag(int type, byte[] uid, int nativeHandle, NdefMessage[] messages) {
-        super(type, true, uid, nativeHandle);
+    public NdefTag(String typeName, byte[] uid, int nativeHandle, NdefMessage[] messages) {
+        super(typeName, true, uid, nativeHandle);
         mMessages = messages.clone();
     }
 
@@ -62,10 +64,22 @@
 
     /**
      * Get only the NDEF Messages from a single NDEF target on a tag.
+     * <p>
+     * This retrieves the NDEF Messages that were found on the Tag at discovery
+     * time. It does not cause any further RF activity, and does not block.
+     * <p>
+     * Most tags only contain a single NDEF message.
+     *
+     * @param target One of targets strings provided by getNdefTargets()
+     * @return NDEF Messages found at Tag discovery
      */
     public NdefMessage[] getNdefMessages(String target) {
-        //TODO(nxp): new api method
-        throw new UnsupportedOperationException();
+        // TODO: handle multiprotocol
+        String[] localTypes = convertToNdefType(mTypeName);
+        if (!target.equals(localTypes[0])) {
+            throw new IllegalArgumentException();
+        }
+        return getNdefMessages();
     }
 
     /** TODO(npelly):
@@ -79,13 +93,35 @@
     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;
+    }
+
     /**
      * Return the
      *
      * @return
      */
     public String[] getNdefTargets() {
-        throw new UnsupportedOperationException();
+        return convertToNdefType(mTypeName);
     }
 
     @Override
@@ -107,7 +143,7 @@
             int messagesLength = in.readInt();
             NdefMessage[] messages = new NdefMessage[messagesLength];
             in.readTypedArray(messages, NdefMessage.CREATOR);
-            return new NdefTag(tag.mType, tag.mUid, tag.mNativeHandle, messages);
+            return new NdefTag(tag.mTypeName, tag.mUid, tag.mNativeHandle, 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 8038d1a..4e9865c 100644
--- a/core/java/android/nfc/NdefTagConnection.java
+++ b/core/java/android/nfc/NdefTagConnection.java
@@ -39,8 +39,29 @@
      * Internal constructor, to be used by NfcAdapter
      * @hide
      */
-    NdefTagConnection(INfcAdapter service, NdefTag tag) throws RemoteException {
+    /* package private */ NdefTagConnection(INfcAdapter service, NdefTag tag, String target) throws RemoteException {
         super(service, tag);
+        String[] targets = tag.getNdefTargets();
+        int i;
+
+        // Check target validity
+        for (i=0; i<targets.length; i++) {
+            if (target.equals(targets[i])) {
+                break;
+            }
+        }
+        if (i >= targets.length) {
+            // Target not found
+            throw new IllegalArgumentException();
+        }
+    }
+
+    /**
+     * Internal constructor, to be used by NfcAdapter
+     * @hide
+     */
+    /* package private */ NdefTagConnection(INfcAdapter service, NdefTag tag) throws RemoteException {
+        this(service, tag, tag.getNdefTargets()[0]);
     }
 
     /**
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 37243f7..fb079f4 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -276,8 +276,12 @@
      * Create a raw tag connection to the specified Target
      */
     public RawTagConnection createRawTagConnection(Tag tag, String target) {
-        //TODO
-        throw new UnsupportedOperationException();
+        try {
+            return new RawTagConnection(mService, tag, target);
+        } catch (RemoteException e) {
+            Log.e(TAG, "NFC service died", e);
+            return null;
+        }
     }
 
     /**
@@ -296,7 +300,11 @@
      * Create an NDEF tag connection to the specified Target
      */
     public NdefTagConnection createNdefTagConnection(NdefTag tag, String target) {
-        //TODO
-        throw new UnsupportedOperationException();
+        try {
+            return new NdefTagConnection(mService, tag, target);
+        } catch (RemoteException e) {
+            Log.e(TAG, "NFC service died", e);
+            return null;
+        }
     }
 }
diff --git a/core/java/android/nfc/RawTagConnection.java b/core/java/android/nfc/RawTagConnection.java
index 50e2a5d..37d700c 100644
--- a/core/java/android/nfc/RawTagConnection.java
+++ b/core/java/android/nfc/RawTagConnection.java
@@ -39,14 +39,34 @@
     /*package*/ final INfcTag mTagService;
     /*package*/ final Tag mTag;
     /*package*/ boolean mIsConnected;
+    /*package*/ String mSelectedTarget;
 
     private static final String TAG = "NFC";
 
-    /* package private */ RawTagConnection(INfcAdapter service, Tag tag) throws RemoteException {
+    /* package private */ RawTagConnection(INfcAdapter service, Tag tag, String target) throws RemoteException {
+        String[] targets = tag.getRawTargets();
+        int i;
+
+        // Check target validity
+        for (i=0;i<targets.length;i++) {
+            if (target.equals(targets[i])) {
+                break;
+            }
+        }
+        if (i >= targets.length) {
+            // Target not found
+            throw new IllegalArgumentException();
+        }
+
         mService = service;
         mTagService = service.getNfcTagInterface();
         mService.openTagConnection(tag);  // TODO(nxp): don't connect until connect()
         mTag = tag;
+        mSelectedTarget = target;
+    }
+
+    /* package private */ RawTagConnection(INfcAdapter service, Tag tag) throws RemoteException {
+        this(service, tag, tag.getRawTargets()[0]);
     }
 
     /**
@@ -57,8 +77,7 @@
     }
 
     public String getTagTarget() {
-        //TODO
-        throw new UnsupportedOperationException();
+        return mSelectedTarget;
     }
 
     /**
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index ea21790..abf02b5 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -16,6 +16,8 @@
 
 package android.nfc;
 
+import java.util.HashMap;
+
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -113,17 +115,73 @@
 
     public static final String TARGET_OTHER = "other";
 
-    /*package*/ final int mType;
+    /*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;
+	}
+
     /**
      * Hidden constructor to be used by NFC service only.
      * @hide
      */
-    public Tag(int type, boolean isNdef, byte[] uid, int nativeHandle) {
-        mType = type;
+    public Tag(String typeName, boolean isNdef, byte[] uid, int nativeHandle) {
+        mTypeName = typeName;
         mIsNdef = isNdef;
         mUid = uid.clone();
         mNativeHandle = nativeHandle;
@@ -144,8 +202,7 @@
      * @return
      */
     public String[] getRawTargets() {
-        //TODO
-        throw new UnsupportedOperationException();
+        return convertToRaw(mTypeName);
     }
 
     /**
@@ -159,7 +216,7 @@
      * @hide
      */
     public int getType() {
-        return mType;
+        return convertToInt(mTypeName);
     }
 
     /**
@@ -188,7 +245,7 @@
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         boolean[] booleans = new boolean[] {mIsNdef};
-        dest.writeInt(mType);
+        dest.writeString(mTypeName);
         dest.writeBooleanArray(booleans);
         dest.writeInt(mUid.length);
         dest.writeByteArray(mUid);
@@ -199,7 +256,7 @@
             new Parcelable.Creator<Tag>() {
         public Tag createFromParcel(Parcel in) {
             boolean[] booleans = new boolean[1];
-            int type = in.readInt();
+            String type = in.readString();
             in.readBooleanArray(booleans);
             boolean isNdef = booleans[0];
             int uidLength = in.readInt();