Move NDEF URI helper method into android.nfc.NfcRecord

Change-Id: Ia044e45cbe2cd06c4844d15a57f1c1f392cf65cd
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index fe215fd..3fd26dd 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -16,10 +16,13 @@
 
 package android.nfc;
 
+import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import java.lang.UnsupportedOperationException;
+import java.nio.charset.Charsets;
+import java.util.Arrays;
 
 /**
  * Represents a logical (unchunked) NDEF (NFC Data Exchange Format) record.
@@ -142,6 +145,50 @@
     private static final byte FLAG_SR = (byte) 0x10;
     private static final byte FLAG_IL = (byte) 0x08;
 
+    /**
+     * NFC Forum "URI Record Type Definition"
+     *
+     * This is a mapping of "URI Identifier Codes" to URI string prefixes,
+     * per section 3.2.2 of the NFC Forum URI Record Type Definition document.
+     */
+    private static final String[] URI_PREFIX_MAP = new String[] {
+            "", // 0x00
+            "http://www.", // 0x01
+            "https://www.", // 0x02
+            "http://", // 0x03
+            "https://", // 0x04
+            "tel:", // 0x05
+            "mailto:", // 0x06
+            "ftp://anonymous:anonymous@", // 0x07
+            "ftp://ftp.", // 0x08
+            "ftps://", // 0x09
+            "sftp://", // 0x0A
+            "smb://", // 0x0B
+            "nfs://", // 0x0C
+            "ftp://", // 0x0D
+            "dav://", // 0x0E
+            "news:", // 0x0F
+            "telnet://", // 0x10
+            "imap:", // 0x11
+            "rtsp://", // 0x12
+            "urn:", // 0x13
+            "pop:", // 0x14
+            "sip:", // 0x15
+            "sips:", // 0x16
+            "tftp:", // 0x17
+            "btspp://", // 0x18
+            "btl2cap://", // 0x19
+            "btgoep://", // 0x1A
+            "tcpobex://", // 0x1B
+            "irdaobex://", // 0x1C
+            "file://", // 0x1D
+            "urn:epc:id:", // 0x1E
+            "urn:epc:tag:", // 0x1F
+            "urn:epc:pat:", // 0x20
+            "urn:epc:raw:", // 0x21
+            "urn:epc:", // 0x22
+    };
+
     private final byte mFlags;
     private final short mTnf;
     private final byte[] mType;
@@ -256,6 +303,50 @@
     }
 
     /**
+     * Helper to return the NdefRecord as a URI.
+     * TODO: Consider making a member method instead of static
+     * TODO: Consider more validation that this is a URI record
+     * TODO: Make a public API
+     * @hide
+     */
+    public static Uri parseWellKnownUriRecord(NdefRecord record) throws FormatException {
+        byte[] payload = record.getPayload();
+        if (payload.length < 2) {
+            throw new FormatException("Payload is not a valid URI (missing prefix)");
+        }
+
+        /*
+         * payload[0] contains the URI Identifier Code, per the
+         * NFC Forum "URI Record Type Definition" section 3.2.2.
+         *
+         * payload[1]...payload[payload.length - 1] contains the rest of
+         * the URI.
+         */
+        int prefixIndex = (payload[0] & 0xff);
+        if (prefixIndex < 0 || prefixIndex >= URI_PREFIX_MAP.length) {
+            throw new FormatException("Payload is not a valid URI (invalid prefix)");
+        }
+        String prefix = URI_PREFIX_MAP[prefixIndex];
+        byte[] fullUri = concat(prefix.getBytes(Charsets.UTF_8),
+                Arrays.copyOfRange(payload, 1, payload.length));
+        return Uri.parse(new String(fullUri, Charsets.UTF_8));
+    }
+
+    private static byte[] concat(byte[]... arrays) {
+        int length = 0;
+        for (byte[] array : arrays) {
+            length += array.length;
+        }
+        byte[] result = new byte[length];
+        int pos = 0;
+        for (byte[] array : arrays) {
+            System.arraycopy(array, 0, result, pos, array.length);
+            pos += array.length;
+        }
+        return result;
+    }
+
+    /**
      * Returns this entire NDEF Record as a byte array.
      */
     public byte[] toByteArray() {