OSDN Git Service

Have getObjects() return ParsedNdefRecords
authorNick Kralevich <nnk@google.com>
Thu, 14 Oct 2010 21:34:08 +0000 (14:34 -0700)
committerNick Kralevich <nnk@google.com>
Thu, 14 Oct 2010 22:54:39 +0000 (15:54 -0700)
Change-Id: I7e5f8fdf2ae113f55cc5843f517a8a8b20ab00ee

apps/Tag/src/com/android/apps/tag/NdefUtil.java
apps/Tag/src/com/android/apps/tag/TagAdapter.java
apps/Tag/src/com/android/apps/tag/TagViewer.java
apps/Tag/src/com/android/apps/tag/record/ParsedNdefRecord.java [new file with mode: 0644]
apps/Tag/src/com/android/apps/tag/record/SmartPoster.java [moved from apps/Tag/src/com/android/apps/tag/SmartPoster.java with 77% similarity]
apps/Tag/src/com/android/apps/tag/record/TextRecord.java [new file with mode: 0644]
apps/Tag/src/com/android/apps/tag/record/UriRecord.java [new file with mode: 0644]
apps/Tag/tests/src/com/android/apps/tag/NdefUtilTest.java
apps/Tag/tests/src/com/android/apps/tag/SmartPosterTest.java

index 40f5bcf..eec7c19 100644 (file)
 
 package com.android.apps.tag;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.ImmutableBiMap;
+import com.android.apps.tag.record.ParsedNdefRecord;
+import com.android.apps.tag.record.SmartPoster;
+import com.android.apps.tag.record.TextRecord;
+import com.android.apps.tag.record.UriRecord;
 import com.google.common.collect.Iterables;
 import com.google.common.primitives.Bytes;
 
@@ -26,11 +27,8 @@ import android.net.Uri;
 import android.nfc.NdefMessage;
 import android.nfc.NdefRecord;
 
-import java.io.UnsupportedEncodingException;
-import java.net.URISyntaxException;
 import java.nio.charset.Charsets;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -42,51 +40,6 @@ public class NdefUtil {
     private static final byte[] EMPTY = new byte[0];
 
     /**
-     * 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 BiMap<Byte, String> URI_PREFIX_MAP = ImmutableBiMap.<Byte, String>builder()
-            .put((byte) 0x00, "")
-            .put((byte) 0x01, "http://www.")
-            .put((byte) 0x02, "https://www.")
-            .put((byte) 0x03, "http://")
-            .put((byte) 0x04, "https://")
-            .put((byte) 0x05, "tel:")
-            .put((byte) 0x06, "mailto:")
-            .put((byte) 0x07, "ftp://anonymous:anonymous@")
-            .put((byte) 0x08, "ftp://ftp.")
-            .put((byte) 0x09, "ftps://")
-            .put((byte) 0x0A, "sftp://")
-            .put((byte) 0x0B, "smb://")
-            .put((byte) 0x0C, "nfs://")
-            .put((byte) 0x0D, "ftp://")
-            .put((byte) 0x0E, "dav://")
-            .put((byte) 0x0F, "news:")
-            .put((byte) 0x10, "telnet://")
-            .put((byte) 0x11, "imap:")
-            .put((byte) 0x12, "rtsp://")
-            .put((byte) 0x13, "urn:")
-            .put((byte) 0x14, "pop:")
-            .put((byte) 0x15, "sip:")
-            .put((byte) 0x16, "sips:")
-            .put((byte) 0x17, "tftp:")
-            .put((byte) 0x18, "btspp://")
-            .put((byte) 0x19, "btl2cap://")
-            .put((byte) 0x1A, "btgoep://")
-            .put((byte) 0x1B, "tcpobex://")
-            .put((byte) 0x1C, "irdaobex://")
-            .put((byte) 0x1D, "file://")
-            .put((byte) 0x1E, "urn:epc:id:")
-            .put((byte) 0x1F, "urn:epc:tag:")
-            .put((byte) 0x20, "urn:epc:pat:")
-            .put((byte) 0x21, "urn:epc:raw:")
-            .put((byte) 0x22, "urn:epc:")
-            .put((byte) 0x23, "urn:nfc:")
-            .build();
-
-    /**
      * Create a new {@link NdefRecord} containing the supplied {@link Uri}.
      */
     public static NdefRecord toUriRecord(Uri uri) {
@@ -108,102 +61,12 @@ public class NdefUtil {
                 NdefRecord.RTD_URI, EMPTY, payload);
     }
 
-    /**
-     * Convert {@link NdefRecord} into a {@link Uri}.
-     *
-     * TODO: This class does not handle NdefRecords where the TNF
-     * (Type Name Format) of the class is {@link NdefRecord#TNF_ABSOLUTE_URI}.
-     * This should be fixed.
-     *
-     * @throws IllegalArgumentException if the NdefRecord is not a
-     *     record containing a URI.
-     */
-    public static Uri toUri(NdefRecord record) {
-        Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);
-        Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_URI));
-
-        byte[] payload = record.getPayload();
-
-        /*
-         * 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.
-         */
-
-        String prefix = URI_PREFIX_MAP.get(payload[0]);
-        byte[] fullUri = Bytes.concat(
-                prefix.getBytes(Charsets.UTF_8),
-                Arrays.copyOfRange(payload, 1, payload.length));
-
-        return Uri.parse(new String(fullUri, Charsets.UTF_8));
-    }
-
-    public static boolean isUri(NdefRecord record) {
-        try {
-            toUri(record);
-            return true;
-        } catch (IllegalArgumentException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Extracts payload text from Text type ndef record.
-     *
-     * @param record A ndef record. Must be {@link NdefRecord#TYPE_TEXT}.
-     * @return text payload.
-     */
-    public static String toText(NdefRecord record) {
-        Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);
-        Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_TEXT));
-        try {
-
-            byte[] payload = record.getPayload();
-
-            /*
-             * payload[0] contains the "Status Byte Encodings" field, per
-             * the NFC Forum "Text Record Type Definition" section 3.2.1.
-             *
-             * bit7 is the Text Encoding Field.
-             *
-             * if (Bit_7 == 0): The text is encoded in UTF-8
-             * if (Bit_7 == 1): The text is encoded in UTF16
-             *
-             * Bit_6 is reserved for future use and must be set to zero.
-             *
-             * Bits 5 to 0 are the length of the IANA language code.
-             */
-
-            String textEncoding = ((payload[0] & 0200) == 0) ? "UTF-8" : "UTF-16";
-            int languageCodeLength = payload[0] & 0077;
-
-            return new String(payload,
-                    languageCodeLength + 1,
-                    payload.length - languageCodeLength - 1,
-                    textEncoding);
-        } catch (UnsupportedEncodingException e) {
-            // should never happen unless we get a malformed tag.
-            throw new IllegalArgumentException(e);
-        }
-    }
-
-    public static boolean isText(NdefRecord record) {
-        try {
-            toText(record);
-            return true;
-        } catch (IllegalArgumentException e) {
-            return false;
-        }
-    }
-
-    public static Iterable<String> getTextFields(NdefMessage message) {
-        return Iterables.filter(getObjects(message), String.class);
+    public static Iterable<TextRecord> getTextFields(NdefMessage message) {
+        return Iterables.filter(getObjects(message), TextRecord.class);
     }
 
-    public static Iterable<Uri> getUris(NdefMessage message) {
-        return Iterables.filter(getObjects(message), Uri.class);
+    public static Iterable<UriRecord> getUris(NdefMessage message) {
+        return Iterables.filter(getObjects(message), UriRecord.class);
     }
 
     /**
@@ -214,15 +77,15 @@ public class NdefUtil {
      * <p>
      * TODO: Is this API too generic?  Should we keep it?
      */
-    public static Iterable<Object> getObjects(NdefMessage message) {
-        List<Object> retval = new ArrayList<Object>();
+    public static Iterable<ParsedNdefRecord> getObjects(NdefMessage message) {
+        List<ParsedNdefRecord> retval = new ArrayList<ParsedNdefRecord>();
         for (NdefRecord record : message.getRecords()) {
-            if (isUri(record)) {
-                retval.add(toUri(record));
-            } else if (isText(record)) {
-                retval.add(toText(record));
+            if (UriRecord.isUri(record)) {
+                retval.add(UriRecord.parse(record));
+            } else if (TextRecord.isText(record)) {
+                retval.add(TextRecord.parse(record));
             } else if (SmartPoster.isPoster(record)) {
-                retval.add(SmartPoster.from(record));
+                retval.add(SmartPoster.parse(record));
             }
         }
         return retval;
index f69c3ea..04bc46a 100644 (file)
@@ -32,6 +32,9 @@ import android.view.ViewGroup;
 import android.widget.Adapter;
 import android.widget.CursorAdapter;
 import android.widget.TextView;
+import com.android.apps.tag.record.SmartPoster;
+import com.android.apps.tag.record.TextRecord;
+import com.android.apps.tag.record.UriRecord;
 
 /**
  * A custom {@link Adapter} that renders tag entries for a list.
@@ -61,14 +64,17 @@ public class TagAdapter extends CursorAdapter {
             mainLine.setText("Invalid tag");
         } else {
             try {
-                SmartPoster poster = SmartPoster.from(msg.getRecords()[0]);
-                mainLine.setText(poster.getTitle());
+                SmartPoster poster = SmartPoster.parse(msg.getRecords()[0]);
+                TextRecord title = poster.getTitle();
+                if (title != null) {
+                    mainLine.setText(title.getText());
+                }
             } catch (IllegalArgumentException e) {
                 // Not a smart poster
                 NdefRecord record = msg.getRecords()[0];
                 Uri uri = null;
                 try {
-                    uri = NdefUtil.toUri(record);
+                    uri = UriRecord.parse(record).getUri();
                     mainLine.setText(uri.toString());
                 } catch (IllegalArgumentException e2) {
                     mainLine.setText("Not a smart poster or URL");
index 21f64e1..aac93c6 100644 (file)
@@ -20,7 +20,6 @@ import android.app.Activity;
 import android.content.Intent;
 import android.database.sqlite.SQLiteDatabase;
 import android.graphics.Color;
-import android.net.Uri;
 import android.nfc.NdefMessage;
 import android.nfc.NdefTag;
 import android.nfc.NfcAdapter;
@@ -31,6 +30,10 @@ import android.view.LayoutInflater;
 import android.view.WindowManager;
 import android.widget.LinearLayout;
 import android.widget.TextView;
+import com.android.apps.tag.record.ParsedNdefRecord;
+import com.android.apps.tag.record.SmartPoster;
+import com.android.apps.tag.record.TextRecord;
+import com.android.apps.tag.record.UriRecord;
 
 /**
  * An {@link Activity} which handles a broadcast of a new tag that the device just discovered.
@@ -92,25 +95,30 @@ public class TagViewer extends Activity {
         // Build the views from the logical records in the messages
         boolean first = true;
         for (NdefMessage msg : msgs) {
-            Iterable<Object> objects = NdefUtil.getObjects(msg);
-            for (Object object : objects) {
+            Iterable<ParsedNdefRecord> objects = NdefUtil.getObjects(msg);
+            for (ParsedNdefRecord object : objects) {
                 if (!first) {
                     list.addView(inflater.inflate(R.layout.tag_divider, list, false));
                     first = false;
                 }
 
-                if (object instanceof String) {
+                if (object instanceof TextRecord) {
+                    TextRecord textRecord = (TextRecord) object;
                     TextView text = (TextView) inflater.inflate(R.layout.tag_text, list, false);
-                    text.setText((CharSequence) object);
+                    text.setText(textRecord.getText());
                     list.addView(text);
-                } else if (object instanceof Uri) {
+                } else if (object instanceof UriRecord) {
+                    UriRecord uriRecord = (UriRecord) object;
                     TextView text = (TextView) inflater.inflate(R.layout.tag_text, list, false);
-                    text.setText(object.toString());
+                    text.setText(uriRecord.getUri().toString());
                     list.addView(text);
                 } else if (object instanceof SmartPoster) {
                     TextView text = (TextView) inflater.inflate(R.layout.tag_text, list, false);
                     SmartPoster poster = (SmartPoster) object;
-                    text.setText(poster.getTitle());
+                    TextRecord title = poster.getTitle();
+                    if (title != null) {
+                        text.setText(title.getText());
+                    }
                     list.addView(text);
                 }
             }
diff --git a/apps/Tag/src/com/android/apps/tag/record/ParsedNdefRecord.java b/apps/Tag/src/com/android/apps/tag/record/ParsedNdefRecord.java
new file mode 100644 (file)
index 0000000..8de4a3f
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apps.tag.record;
+
+/**
+ * TODO: come up with a better name.
+ */
+public interface ParsedNdefRecord {
+
+    // Just a placeholder for now.  Probably not needed nor desired.
+    public String getRecordType();
+}
  * limitations under the License.
  */
 
-package com.android.apps.tag;
+package com.android.apps.tag.record;
 
+import com.android.apps.tag.NdefUtil;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.Iterables;
 
-import android.net.Uri;
 import android.nfc.FormatException;
 import android.nfc.NdefMessage;
 import android.nfc.NdefRecord;
@@ -31,7 +31,7 @@ import javax.annotation.Nullable;
 /**
  * A representation of an NFC Forum "Smart Poster".
  */
-public class SmartPoster {
+public class SmartPoster implements ParsedNdefRecord {
 
     /**
      * NFC Forum Smart Poster Record Type Definition section 3.2.1.
@@ -41,7 +41,7 @@ public class SmartPoster {
      * This record is optional."
 
      */
-    private final String mTitleRecord;
+    private final TextRecord mTitleRecord;
 
     /**
      * NFC Forum Smart Poster Record Type Definition section 3.2.1.
@@ -50,32 +50,32 @@ public class SmartPoster {
      * records are just metadata about this record. There MUST be one URI
      * record and there MUST NOT be more than one."
      */
-    private final Uri mUriRecord;
+    private final UriRecord mUriRecord;
 
-    private SmartPoster(Uri uri, @Nullable String title) {
+    private SmartPoster(UriRecord uri, @Nullable TextRecord title) {
         mUriRecord = Preconditions.checkNotNull(uri);
         mTitleRecord = title;
     }
 
-    public Uri getUri() {
+    public UriRecord getUriRecord() {
         return mUriRecord;
     }
 
     /**
      * Returns the title of the smart poster.  This may be {@code null}.
      */
-    public String getTitle() {
+    public TextRecord getTitle() {
         return mTitleRecord;
     }
 
-    public static SmartPoster from(NdefRecord record) {
+    public static SmartPoster parse(NdefRecord record) {
         Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);
         Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_SMART_POSTER));
         try {
             NdefMessage subRecords = new NdefMessage(record.getPayload());
-            Uri uri = Iterables.getOnlyElement(NdefUtil.getUris(subRecords));
-            Iterable<String> textFields = NdefUtil.getTextFields(subRecords);
-            String title = null;
+            UriRecord uri = Iterables.getOnlyElement(NdefUtil.getUris(subRecords));
+            Iterable<TextRecord> textFields = NdefUtil.getTextFields(subRecords);
+            TextRecord title = null;
             if (!Iterables.isEmpty(textFields)) {
                 title = Iterables.get(textFields, 0);
             }
@@ -88,10 +88,15 @@ public class SmartPoster {
 
     public static boolean isPoster(NdefRecord record) {
         try {
-            from(record);
+            parse(record);
             return true;
         } catch (IllegalArgumentException e) {
             return false;
         }
     }
+
+    @Override
+    public String getRecordType() {
+        return "SmartPoster";
+    }
 }
diff --git a/apps/Tag/src/com/android/apps/tag/record/TextRecord.java b/apps/Tag/src/com/android/apps/tag/record/TextRecord.java
new file mode 100644 (file)
index 0000000..29d380d
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apps.tag.record;
+
+import android.nfc.NdefRecord;
+import com.google.common.base.Preconditions;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+
+/**
+ * An NFC Text Record
+ */
+public class TextRecord implements ParsedNdefRecord {
+
+    private final String mLanguageCode;
+    private final String mText;
+
+    private TextRecord(String languageCode, String text) {
+        mLanguageCode = Preconditions.checkNotNull(languageCode);
+        mText = Preconditions.checkNotNull(text);
+    }
+
+    @Override
+    public String getRecordType() {
+        return "Text";
+    }
+
+    public String getText() {
+        return mText;
+    }
+
+    public String getLanguageCode() {
+        return mLanguageCode;
+    }
+
+    // TODO: deal with text fields which span multiple NdefRecords
+    public static TextRecord parse(NdefRecord record) {
+        Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);
+        Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_TEXT));
+        try {
+
+            byte[] payload = record.getPayload();
+
+            /*
+             * payload[0] contains the "Status Byte Encodings" field, per
+             * the NFC Forum "Text Record Type Definition" section 3.2.1.
+             *
+             * bit7 is the Text Encoding Field.
+             *
+             * if (Bit_7 == 0): The text is encoded in UTF-8
+             * if (Bit_7 == 1): The text is encoded in UTF16
+             *
+             * Bit_6 is reserved for future use and must be set to zero.
+             *
+             * Bits 5 to 0 are the length of the IANA language code.
+             */
+
+            String textEncoding = ((payload[0] & 0200) == 0) ? "UTF-8" : "UTF-16";
+            int languageCodeLength = payload[0] & 0077;
+
+            String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
+            String text = new String(payload,
+                    languageCodeLength + 1,
+                    payload.length - languageCodeLength - 1,
+                    textEncoding);
+            return new TextRecord(languageCode, text);
+
+        } catch (UnsupportedEncodingException e) {
+            // should never happen unless we get a malformed tag.
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    public static boolean isText(NdefRecord record) {
+        try {
+            parse(record);
+            return true;
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+    }
+}
diff --git a/apps/Tag/src/com/android/apps/tag/record/UriRecord.java b/apps/Tag/src/com/android/apps/tag/record/UriRecord.java
new file mode 100644 (file)
index 0000000..eeba30b
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.apps.tag.record;
+
+import android.net.Uri;
+import android.nfc.NdefRecord;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.primitives.Bytes;
+
+import java.nio.charset.Charsets;
+import java.util.Arrays;
+
+/**
+ * A parsed record containing a Uri.
+ */
+public class UriRecord implements ParsedNdefRecord {
+    private static final byte[] EMPTY = new byte[0];
+
+    /**
+     * 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 BiMap<Byte, String> URI_PREFIX_MAP = ImmutableBiMap.<Byte, String>builder()
+            .put((byte) 0x00, "")
+            .put((byte) 0x01, "http://www.")
+            .put((byte) 0x02, "https://www.")
+            .put((byte) 0x03, "http://")
+            .put((byte) 0x04, "https://")
+            .put((byte) 0x05, "tel:")
+            .put((byte) 0x06, "mailto:")
+            .put((byte) 0x07, "ftp://anonymous:anonymous@")
+            .put((byte) 0x08, "ftp://ftp.")
+            .put((byte) 0x09, "ftps://")
+            .put((byte) 0x0A, "sftp://")
+            .put((byte) 0x0B, "smb://")
+            .put((byte) 0x0C, "nfs://")
+            .put((byte) 0x0D, "ftp://")
+            .put((byte) 0x0E, "dav://")
+            .put((byte) 0x0F, "news:")
+            .put((byte) 0x10, "telnet://")
+            .put((byte) 0x11, "imap:")
+            .put((byte) 0x12, "rtsp://")
+            .put((byte) 0x13, "urn:")
+            .put((byte) 0x14, "pop:")
+            .put((byte) 0x15, "sip:")
+            .put((byte) 0x16, "sips:")
+            .put((byte) 0x17, "tftp:")
+            .put((byte) 0x18, "btspp://")
+            .put((byte) 0x19, "btl2cap://")
+            .put((byte) 0x1A, "btgoep://")
+            .put((byte) 0x1B, "tcpobex://")
+            .put((byte) 0x1C, "irdaobex://")
+            .put((byte) 0x1D, "file://")
+            .put((byte) 0x1E, "urn:epc:id:")
+            .put((byte) 0x1F, "urn:epc:tag:")
+            .put((byte) 0x20, "urn:epc:pat:")
+            .put((byte) 0x21, "urn:epc:raw:")
+            .put((byte) 0x22, "urn:epc:")
+            .put((byte) 0x23, "urn:nfc:")
+            .build();
+
+    private final Uri mUri;
+
+    private UriRecord(Uri uri) {
+        this.mUri = Preconditions.checkNotNull(uri);
+    }
+
+    @Override
+    public String getRecordType() {
+        return "Uri";
+    }
+
+    public Uri getUri() {
+        return mUri;
+    }
+
+    /**
+     * Convert {@link android.nfc.NdefRecord} into a {@link android.net.Uri}.
+     *
+     * TODO: This class does not handle NdefRecords where the TNF
+     * (Type Name Format) of the class is {@link android.nfc.NdefRecord#TNF_ABSOLUTE_URI}.
+     * This should be fixed.
+     *
+     * @throws IllegalArgumentException if the NdefRecord is not a
+     *     record containing a URI.
+     */
+    public static UriRecord parse(NdefRecord record) {
+        Preconditions.checkArgument(record.getTnf() == NdefRecord.TNF_WELL_KNOWN);
+        Preconditions.checkArgument(Arrays.equals(record.getType(), NdefRecord.RTD_URI));
+
+        byte[] payload = record.getPayload();
+
+        /*
+         * 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.
+         */
+
+        String prefix = URI_PREFIX_MAP.get(payload[0]);
+        byte[] fullUri = Bytes.concat(
+                prefix.getBytes(Charsets.UTF_8),
+                Arrays.copyOfRange(payload, 1, payload.length));
+
+        return new UriRecord(Uri.parse(new String(fullUri, Charsets.UTF_8)));
+    }
+
+    public static boolean isUri(NdefRecord record) {
+        try {
+            parse(record);
+            return true;
+        } catch (IllegalArgumentException e) {
+            return false;
+        }
+    }
+}
index 12baf6f..24070ae 100644 (file)
@@ -17,6 +17,7 @@
 package com.android.apps.tag;
 
 import android.test.AndroidTestCase;
+import com.android.apps.tag.record.TextRecord;
 import com.google.common.primitives.Bytes;
 import android.nfc.NdefRecord;
 
@@ -46,6 +47,6 @@ public class NdefUtilTest extends AndroidTestCase {
         );
 
         NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data);
-        assertEquals(word, NdefUtil.toText(record));
+        assertEquals(word, TextRecord.parse(record).getText());
     }
 }
index 01ac817..8225197 100644 (file)
@@ -18,6 +18,7 @@ package com.android.apps.tag;
 
 import android.test.AndroidTestCase;
 import android.nfc.NdefMessage;
+import com.android.apps.tag.record.SmartPoster;
 
 /**
  * Tests for {@link SmartPoster}.
@@ -26,8 +27,8 @@ public class SmartPosterTest extends AndroidTestCase {
     public void testSmartPoster() throws Exception {
         NdefMessage msg = new NdefMessage(MockNdefMessages.REAL_NFC_MSG);
 
-        SmartPoster poster = SmartPoster.from(msg.getRecords()[0]);
-        assertEquals("NFC Forum Type 4 Tag", poster.getTitle());
-        assertEquals("http://www.nxp.com/nfc", poster.getUri().toString());
+        SmartPoster poster = SmartPoster.parse(msg.getRecords()[0]);
+        assertEquals("NFC Forum Type 4 Tag", poster.getTitle().getText());
+        assertEquals("http://www.nxp.com/nfc", poster.getUriRecord().getUri().toString());
     }
 }