blob: fe215fd1057f421e6d4b649d4954e7d32273fd52 [file] [log] [blame]
Nick Pellydc993792010-10-04 11:17:25 -07001/*
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/**
Scott Mainc9f78902010-10-15 09:15:09 -070025 * Represents a logical (unchunked) NDEF (NFC Data Exchange Format) record.
26 * <p>An NDEF record always contains:
Nick Pellydc993792010-10-04 11:17:25 -070027 * <ul>
Scott Mainc9f78902010-10-15 09:15:09 -070028 * <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
Nick Pellydc993792010-10-04 11:17:25 -070032 * </ul>
Scott Mainc9f78902010-10-15 09:15:09 -070033 * <p>The underlying record
Nick Pellydc993792010-10-04 11:17:25 -070034 * representation may be chunked across several NDEF records when the payload is
35 * large.
Scott Mainc9f78902010-10-15 09:15:09 -070036 * <p>This is an immutable data class.
Nick Pellydc993792010-10-04 11:17:25 -070037 */
Nick Pelly11b075e2010-10-28 13:39:37 -070038public final class NdefRecord implements Parcelable {
Nick Pellydc993792010-10-04 11:17:25 -070039 /**
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
Nick Pelly590b73b2010-10-12 13:00:50 -0700139 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
Nick Pellydc993792010-10-04 11:17:25 -0700151 /**
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) {
Martijn Coenen8bede172011-04-08 16:42:22 +0200166 /* 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) {
Nick Pelly590b73b2010-10-12 13:00:50 -0700178 /* check arguments */
179 if ((type == null) || (id == null) || (payload == null)) {
180 throw new IllegalArgumentException("Illegal null argument");
181 }
182
Nick Kralevich6df23602010-10-15 16:09:19 -0700183 if (tnf < 0 || tnf > 0x07) {
184 throw new IllegalArgumentException("TNF out of range " + tnf);
185 }
186
Nick Pelly590b73b2010-10-12 13:00:50 -0700187 /* 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();
Nick Pellydc993792010-10-04 11:17:25 -0700202 }
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 */
Sylvain Fonteneaudd7341f2010-10-17 15:32:33 -0700212 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 }
Nick Pellydc993792010-10-04 11:17:25 -0700223 }
224
225 /**
226 * Returns the 3-bit TNF.
227 * <p>
228 * TNF is the top-level type.
229 */
230 public short getTnf() {
Nick Pelly590b73b2010-10-12 13:00:50 -0700231 return mTnf;
Nick Pellydc993792010-10-04 11:17:25 -0700232 }
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() {
Nick Pelly590b73b2010-10-12 13:00:50 -0700241 return mType.clone();
Nick Pellydc993792010-10-04 11:17:25 -0700242 }
243
244 /**
245 * Returns the variable length ID.
246 */
247 public byte[] getId() {
Nick Pelly590b73b2010-10-12 13:00:50 -0700248 return mId.clone();
Nick Pellydc993792010-10-04 11:17:25 -0700249 }
250
251 /**
252 * Returns the variable length payload.
253 */
254 public byte[] getPayload() {
Nick Pelly590b73b2010-10-12 13:00:50 -0700255 return mPayload.clone();
Nick Pellydc993792010-10-04 11:17:25 -0700256 }
257
258 /**
Jeff Hamiltonda83f512010-10-21 22:39:30 -0500259 * Returns this entire NDEF Record as a byte array.
Nick Pellydc993792010-10-04 11:17:25 -0700260 */
261 public byte[] toByteArray() {
Nick Pelly590b73b2010-10-12 13:00:50 -0700262 return generate(mFlags, mTnf, mType, mId, mPayload);
Nick Pellydc993792010-10-04 11:17:25 -0700263 }
264
Nick Pellydc993792010-10-04 11:17:25 -0700265 public int describeContents() {
266 return 0;
267 }
268
Nick Pellydc993792010-10-04 11:17:25 -0700269 public void writeToParcel(Parcel dest, int flags) {
Martijn Coenen8bede172011-04-08 16:42:22 +0200270 dest.writeInt(mFlags);
Nick Pelly590b73b2010-10-12 13:00:50 -0700271 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);
Nick Pellydc993792010-10-04 11:17:25 -0700278 }
279
280 public static final Parcelable.Creator<NdefRecord> CREATOR =
281 new Parcelable.Creator<NdefRecord>() {
282 public NdefRecord createFromParcel(Parcel in) {
Martijn Coenen8bede172011-04-08 16:42:22 +0200283 byte flags = (byte)in.readInt();
Nick Pelly590b73b2010-10-12 13:00:50 -0700284 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
Martijn Coenen8bede172011-04-08 16:42:22 +0200295 return new NdefRecord(tnf, type, id, payload, flags);
Nick Pellydc993792010-10-04 11:17:25 -0700296 }
297 public NdefRecord[] newArray(int size) {
Nick Pelly590b73b2010-10-12 13:00:50 -0700298 return new NdefRecord[size];
Nick Pellydc993792010-10-04 11:17:25 -0700299 }
300 };
Nick Pelly590b73b2010-10-12 13:00:50 -0700301
Sylvain Fonteneaudd7341f2010-10-17 15:32:33 -0700302 private native int parseNdefRecord(byte[] data);
Nick Pelly590b73b2010-10-12 13:00:50 -0700303 private native byte[] generate(short flags, short tnf, byte[] type, byte[] id, byte[] data);
Martijn Coenen8bede172011-04-08 16:42:22 +0200304}