NdefRecord.java revision 8bede1704717f594a0f924a57ff46f6300347e30
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.nfc; 18 19import android.os.Parcel; 20import android.os.Parcelable; 21 22import java.lang.UnsupportedOperationException; 23 24/** 25 * Represents a logical (unchunked) NDEF (NFC Data Exchange Format) record. 26 * <p>An NDEF record always contains: 27 * <ul> 28 * <li>3-bit TNF (Type Name Format) field: Indicates how to interpret the type field 29 * <li>Variable length type: Describes the record format 30 * <li>Variable length ID: A unique identifier for the record 31 * <li>Variable length payload: The actual data payload 32 * </ul> 33 * <p>The underlying record 34 * representation may be chunked across several NDEF records when the payload is 35 * large. 36 * <p>This is an immutable data class. 37 */ 38public final class NdefRecord implements Parcelable { 39 /** 40 * Indicates no type, id, or payload is associated with this NDEF Record. 41 * <p> 42 * Type, id and payload fields must all be empty to be a valid TNF_EMPTY 43 * record. 44 */ 45 public static final short TNF_EMPTY = 0x00; 46 47 /** 48 * Indicates the type field uses the RTD type name format. 49 * <p> 50 * Use this TNF with RTD types such as RTD_TEXT, RTD_URI. 51 */ 52 public static final short TNF_WELL_KNOWN = 0x01; 53 54 /** 55 * Indicates the type field contains a value that follows the media-type BNF 56 * construct defined by RFC 2046. 57 */ 58 public static final short TNF_MIME_MEDIA = 0x02; 59 60 /** 61 * Indicates the type field contains a value that follows the absolute-URI 62 * BNF construct defined by RFC 3986. 63 */ 64 public static final short TNF_ABSOLUTE_URI = 0x03; 65 66 /** 67 * Indicates the type field contains a value that follows the RTD external 68 * name specification. 69 * <p> 70 * Note this TNF should not be used with RTD_TEXT or RTD_URI constants. 71 * Those are well known RTD constants, not external RTD constants. 72 */ 73 public static final short TNF_EXTERNAL_TYPE = 0x04; 74 75 /** 76 * Indicates the payload type is unknown. 77 * <p> 78 * This is similar to the "application/octet-stream" MIME type. The payload 79 * type is not explicitly encoded within the NDEF Message. 80 * <p> 81 * The type field must be empty to be a valid TNF_UNKNOWN record. 82 */ 83 public static final short TNF_UNKNOWN = 0x05; 84 85 /** 86 * Indicates the payload is an intermediate or final chunk of a chunked 87 * NDEF Record. 88 * <p> 89 * The payload type is specified in the first chunk, and subsequent chunks 90 * must use TNF_UNCHANGED with an empty type field. TNF_UNCHANGED must not 91 * be used in any other situation. 92 */ 93 public static final short TNF_UNCHANGED = 0x06; 94 95 /** 96 * Reserved TNF type. 97 * <p> 98 * The NFC Forum NDEF Specification v1.0 suggests for NDEF parsers to treat this 99 * value like TNF_UNKNOWN. 100 * @hide 101 */ 102 public static final short TNF_RESERVED = 0x07; 103 104 /** 105 * RTD Text type. For use with TNF_WELL_KNOWN. 106 */ 107 public static final byte[] RTD_TEXT = {0x54}; // "T" 108 109 /** 110 * RTD URI type. For use with TNF_WELL_KNOWN. 111 */ 112 public static final byte[] RTD_URI = {0x55}; // "U" 113 114 /** 115 * RTD Smart Poster type. For use with TNF_WELL_KNOWN. 116 */ 117 public static final byte[] RTD_SMART_POSTER = {0x53, 0x70}; // "Sp" 118 119 /** 120 * RTD Alternative Carrier type. For use with TNF_WELL_KNOWN. 121 */ 122 public static final byte[] RTD_ALTERNATIVE_CARRIER = {0x61, 0x63}; // "ac" 123 124 /** 125 * RTD Handover Carrier type. For use with TNF_WELL_KNOWN. 126 */ 127 public static final byte[] RTD_HANDOVER_CARRIER = {0x48, 0x63}; // "Hc" 128 129 /** 130 * RTD Handover Request type. For use with TNF_WELL_KNOWN. 131 */ 132 public static final byte[] RTD_HANDOVER_REQUEST = {0x48, 0x72}; // "Hr" 133 134 /** 135 * RTD Handover Select type. For use with TNF_WELL_KNOWN. 136 */ 137 public static final byte[] RTD_HANDOVER_SELECT = {0x48, 0x73}; // "Hs" 138 139 private static final byte FLAG_MB = (byte) 0x80; 140 private static final byte FLAG_ME = (byte) 0x40; 141 private static final byte FLAG_CF = (byte) 0x20; 142 private static final byte FLAG_SR = (byte) 0x10; 143 private static final byte FLAG_IL = (byte) 0x08; 144 145 private final byte mFlags; 146 private final short mTnf; 147 private final byte[] mType; 148 private final byte[] mId; 149 private final byte[] mPayload; 150 151 /** 152 * Construct an NDEF Record. 153 * <p> 154 * Applications should not attempt to manually chunk NDEF Records - the 155 * implementation of android.nfc will automatically chunk an NDEF Record 156 * when necessary (and only present a single logical NDEF Record to the 157 * application). So applications should not use TNF_UNCHANGED. 158 * 159 * @param tnf a 3-bit TNF constant 160 * @param type byte array, containing zero to 255 bytes, must not be null 161 * @param id byte array, containing zero to 255 bytes, must not be null 162 * @param payload byte array, containing zero to (2 ** 32 - 1) bytes, 163 * must not be null 164 */ 165 public NdefRecord(short tnf, byte[] type, byte[] id, byte[] payload) { 166 /* New NDEF records created by applications will have FLAG_MB|FLAG_ME 167 * set by default; when multiple records are stored in a 168 * {@link NdefMessage}, these flags will be corrected when the {@link NdefMessage} 169 * is serialized to bytes. 170 */ 171 this(tnf, type, id, payload, (byte)(FLAG_MB|FLAG_ME)); 172 } 173 174 /** 175 * @hide 176 */ 177 /*package*/ NdefRecord(short tnf, byte[] type, byte[] id, byte[] payload, byte flags) { 178 /* check arguments */ 179 if ((type == null) || (id == null) || (payload == null)) { 180 throw new IllegalArgumentException("Illegal null argument"); 181 } 182 183 if (tnf < 0 || tnf > 0x07) { 184 throw new IllegalArgumentException("TNF out of range " + tnf); 185 } 186 187 /* Determine if it is a short record */ 188 if(payload.length < 0xFF) { 189 flags |= FLAG_SR; 190 } 191 192 /* Determine if an id is present */ 193 if(id.length != 0) { 194 flags |= FLAG_IL; 195 } 196 197 mFlags = flags; 198 mTnf = tnf; 199 mType = type.clone(); 200 mId = id.clone(); 201 mPayload = payload.clone(); 202 } 203 204 /** 205 * Construct an NDEF Record from raw bytes. 206 * <p> 207 * Validation is performed to make sure the header is valid, and that 208 * the id, type and payload sizes appear to be valid. 209 * 210 * @throws FormatException if the data is not a valid NDEF record 211 */ 212 public NdefRecord(byte[] data) throws FormatException { 213 /* Prevent compiler to complain about unassigned final fields */ 214 mFlags = 0; 215 mTnf = 0; 216 mType = null; 217 mId = null; 218 mPayload = null; 219 /* Perform actual parsing */ 220 if (parseNdefRecord(data) == -1) { 221 throw new FormatException("Error while parsing NDEF record"); 222 } 223 } 224 225 /** 226 * Returns the 3-bit TNF. 227 * <p> 228 * TNF is the top-level type. 229 */ 230 public short getTnf() { 231 return mTnf; 232 } 233 234 /** 235 * Returns the variable length Type field. 236 * <p> 237 * This should be used in conjunction with the TNF field to determine the 238 * payload format. 239 */ 240 public byte[] getType() { 241 return mType.clone(); 242 } 243 244 /** 245 * Returns the variable length ID. 246 */ 247 public byte[] getId() { 248 return mId.clone(); 249 } 250 251 /** 252 * Returns the variable length payload. 253 */ 254 public byte[] getPayload() { 255 return mPayload.clone(); 256 } 257 258 /** 259 * Returns this entire NDEF Record as a byte array. 260 */ 261 public byte[] toByteArray() { 262 return generate(mFlags, mTnf, mType, mId, mPayload); 263 } 264 265 public int describeContents() { 266 return 0; 267 } 268 269 public void writeToParcel(Parcel dest, int flags) { 270 dest.writeInt(mFlags); 271 dest.writeInt(mTnf); 272 dest.writeInt(mType.length); 273 dest.writeByteArray(mType); 274 dest.writeInt(mId.length); 275 dest.writeByteArray(mId); 276 dest.writeInt(mPayload.length); 277 dest.writeByteArray(mPayload); 278 } 279 280 public static final Parcelable.Creator<NdefRecord> CREATOR = 281 new Parcelable.Creator<NdefRecord>() { 282 public NdefRecord createFromParcel(Parcel in) { 283 byte flags = (byte)in.readInt(); 284 short tnf = (short)in.readInt(); 285 int typeLength = in.readInt(); 286 byte[] type = new byte[typeLength]; 287 in.readByteArray(type); 288 int idLength = in.readInt(); 289 byte[] id = new byte[idLength]; 290 in.readByteArray(id); 291 int payloadLength = in.readInt(); 292 byte[] payload = new byte[payloadLength]; 293 in.readByteArray(payload); 294 295 return new NdefRecord(tnf, type, id, payload, flags); 296 } 297 public NdefRecord[] newArray(int size) { 298 return new NdefRecord[size]; 299 } 300 }; 301 302 private native int parseNdefRecord(byte[] data); 303 private native byte[] generate(short flags, short tnf, byte[] type, byte[] id, byte[] data); 304} 305