1dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly/*
2dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * Copyright (C) 2010 The Android Open Source Project
3dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly *
4dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * Licensed under the Apache License, Version 2.0 (the "License");
5dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * you may not use this file except in compliance with the License.
6dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * You may obtain a copy of the License at
7dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly *
8dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly *      http://www.apache.org/licenses/LICENSE-2.0
9dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly *
10dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * Unless required by applicable law or agreed to in writing, software
11dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * distributed under the License is distributed on an "AS IS" BASIS,
12dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * See the License for the specific language governing permissions and
14dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * limitations under the License.
15dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly */
16dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
17dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pellypackage android.nfc;
18dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
19a356bf1cd81614a94ef6c720998792480ade4c84Nick Pellyimport java.nio.ByteBuffer;
20a356bf1cd81614a94ef6c720998792480ade4c84Nick Pellyimport java.util.Arrays;
21a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly
22dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pellyimport android.os.Parcel;
23dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pellyimport android.os.Parcelable;
24dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
25a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly
26dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly/**
27a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * Represents an immutable NDEF Message.
28a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * <p>
29a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * NDEF (NFC Data Exchange Format) is a light-weight binary format,
30a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * used to encapsulate typed data. It is specified by the NFC Forum,
31a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * for transmission and storage with NFC, however it is transport agnostic.
32a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * <p>
33a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * NDEF defines messages and records. An NDEF Record contains
34a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * typed data, such as MIME-type media, a URI, or a custom
35a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * application payload. An NDEF Message is a container for
36a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * one or more NDEF Records.
37a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * <p>
38a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * When an Android device receives an NDEF Message
39a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * (for example by reading an NFC tag) it processes it through
40a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * a dispatch mechanism to determine an activity to launch.
41a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * The type of the <em>first</em> record in the message has
42a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * special importance for message dispatch, so design this record
43a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * carefully.
44a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * <p>
45a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * Use {@link #NdefMessage(byte[])} to construct an NDEF Message from
46a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * binary data, or {@link #NdefMessage(NdefRecord[])} to
47a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * construct from one or more {@link NdefRecord}s.
48a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * <p class="note">
49a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * {@link NdefMessage} and {@link NdefRecord} implementations are
50a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * always available, even on Android devices that do not have NFC hardware.
51a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * <p class="note">
52a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * {@link NdefRecord}s are intended to be immutable (and thread-safe),
53a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * however they may contain mutable fields. So take care not to modify
54a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * mutable fields passed into constructors, or modify mutable fields
55a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * obtained by getter methods, unless such modification is explicitly
56a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * marked as safe.
57a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly *
58a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * @see NfcAdapter#ACTION_NDEF_DISCOVERED
59a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly * @see NdefRecord
60dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly */
6111b075e218b9921a953eeebe73fcd1a8a81f764bNick Pellypublic final class NdefMessage implements Parcelable {
62590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    private final NdefRecord[] mRecords;
63590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
64dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    /**
65a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * Construct an NDEF Message by parsing raw bytes.<p>
66a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * Strict validation of the NDEF binary structure is performed:
67a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * there must be at least one record, every record flag must
68a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * be correct, and the total length of the message must match
69a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * the length of the input data.<p>
70a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * This parser can handle chunked records, and converts them
71a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * into logical {@link NdefRecord}s within the message.<p>
72a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * Once the input data has been parsed to one or more logical
73a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * records, basic validation of the tnf, type, id, and payload fields
74a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * of each record is performed, as per the documentation on
75a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * on {@link NdefRecord#NdefRecord(short, byte[], byte[], byte[])}<p>
76a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * If either strict validation of the binary format fails, or
77a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * basic validation during record construction fails, a
78a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * {@link FormatException} is thrown<p>
79a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * Deep inspection of the type, id and payload fields of
80a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * each record is not performed, so it is possible to parse input
81a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * that has a valid binary format and confirms to the basic
82a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * validation requirements of
83a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * {@link NdefRecord#NdefRecord(short, byte[], byte[], byte[])},
84a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * but fails more strict requirements as specified by the
85a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * NFC Forum.
86a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     *
87a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * <p class="note">
88a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * It is safe to re-use the data byte array after construction:
89a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * this constructor will make an internal copy of all necessary fields.
90a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     *
91a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * @param data raw bytes to parse
92a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * @throws FormatException if the data cannot be parsed
93dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     */
94590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    public NdefMessage(byte[] data) throws FormatException {
95c97a552023c3c71079b39092e80c9b44f25a789bNick Pelly        if (data == null) throw new NullPointerException("data is null");
96a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        ByteBuffer buffer = ByteBuffer.wrap(data);
97a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly
98a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        mRecords = NdefRecord.parse(buffer, false);
99a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly
100a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        if (buffer.remaining() > 0) {
101a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly            throw new FormatException("trailing data");
102590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        }
103dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    }
104dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
105dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    /**
106a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * Construct an NDEF Message from one or more NDEF Records.
107a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     *
108a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * @param record first record (mandatory)
109a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * @param records additional records (optional)
110a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     */
111a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    public NdefMessage(NdefRecord record, NdefRecord ... records) {
112a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        // validate
113c97a552023c3c71079b39092e80c9b44f25a789bNick Pelly        if (record == null) throw new NullPointerException("record cannot be null");
114c97a552023c3c71079b39092e80c9b44f25a789bNick Pelly
115a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        for (NdefRecord r : records) {
116a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly            if (r == null) {
117a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly                throw new NullPointerException("record cannot be null");
118a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly            }
119a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        }
120a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly
121a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        mRecords = new NdefRecord[1 + records.length];
122a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        mRecords[0] = record;
123a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        System.arraycopy(records, 0, mRecords, 1, records.length);
124a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    }
125a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly
126a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    /**
127a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * Construct an NDEF Message from one or more NDEF Records.
128a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     *
129a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * @param records one or more records
130dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     */
131dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    public NdefMessage(NdefRecord[] records) {
132a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        // validate
133a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        if (records.length < 1) {
134a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly            throw new IllegalArgumentException("must have at least one record");
135a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        }
136a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        for (NdefRecord r : records) {
137a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly            if (r == null) {
138a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly                throw new NullPointerException("records cannot contain null");
139a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly            }
140a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        }
141a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly
142a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        mRecords = records;
143dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    }
144dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
145dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    /**
146a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * Get the NDEF Records inside this NDEF Message.<p>
147c97a552023c3c71079b39092e80c9b44f25a789bNick Pelly     * An {@link NdefMessage} always has one or more NDEF Records: so the
148c97a552023c3c71079b39092e80c9b44f25a789bNick Pelly     * following code to retrieve the first record is always safe
149c97a552023c3c71079b39092e80c9b44f25a789bNick Pelly     * (no need to check for null or array length >= 1):
150c97a552023c3c71079b39092e80c9b44f25a789bNick Pelly     * <pre>
151c97a552023c3c71079b39092e80c9b44f25a789bNick Pelly     * NdefRecord firstRecord = ndefMessage.getRecords()[0];
152c97a552023c3c71079b39092e80c9b44f25a789bNick Pelly     * </pre>
153dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     *
154a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * @return array of one or more NDEF records.
155dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     */
156dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    public NdefRecord[] getRecords() {
157a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        return mRecords;
158dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    }
159dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
160dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    /**
1611f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     * Return the length of this NDEF Message if it is written to a byte array
1621f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     * with {@link #toByteArray}.<p>
1631f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     * An NDEF Message can be formatted to bytes in different ways
1641f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     * depending on chunking, SR, and ID flags, so the length returned
1651f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     * by this method may not be equal to the length of the original
1661f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     * byte array used to construct this NDEF Message. However it will
1671f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     * always be equal to the length of the byte array produced by
1681f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     * {@link #toByteArray}.
1691f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     *
170d3cb80d2af423eccdeef2697a1ca45eadb241988Nick Pelly     * @return length of this NDEF Message when written to bytes with {@link #toByteArray}
1711f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     * @see #toByteArray
1721f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     */
1731f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly    public int getByteArrayLength() {
1741f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly        int length = 0;
1751f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly        for (NdefRecord r : mRecords) {
1761f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly            length += r.getByteLength();
1771f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly        }
1781f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly        return length;
1791f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly    }
1801f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly
1811f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly    /**
1821f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     * Return this NDEF Message as raw bytes.<p>
183a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * The NDEF Message is formatted as per the NDEF 1.0 specification,
184a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * and the byte array is suitable for network transmission or storage
185a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * in an NFC Forum NDEF compatible tag.<p>
186a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * This method will not chunk any records, and will always use the
187a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * short record (SR) format and omit the identifier field when possible.
188a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     *
189a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * @return NDEF Message in binary format
1901f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly     * @see getByteArrayLength
191dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     */
192dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    public byte[] toByteArray() {
1931f5badc1cb08f10ddf4b09aaaf34060a23999a51Nick Pelly        int length = getByteArrayLength();
194a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        ByteBuffer buffer = ByteBuffer.allocate(length);
195590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
196a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        for (int i=0; i<mRecords.length; i++) {
197a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly            boolean mb = (i == 0);  // first record
198a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly            boolean me = (i == mRecords.length - 1);  // last record
199a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly            mRecords[i].writeToByteBuffer(buffer, mb, me);
200590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        }
201590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
202a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        return buffer.array();
203dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    }
204dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
2053ebd59bb5dc9f421fd2b9b789ea824746d58fff7Jason parks    @Override
206dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    public int describeContents() {
207dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly        return 0;
208dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    }
209dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
2103ebd59bb5dc9f421fd2b9b789ea824746d58fff7Jason parks    @Override
211dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    public void writeToParcel(Parcel dest, int flags) {
212590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        dest.writeInt(mRecords.length);
213590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        dest.writeTypedArray(mRecords, flags);
214dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    }
215dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
216dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    public static final Parcelable.Creator<NdefMessage> CREATOR =
217dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly            new Parcelable.Creator<NdefMessage>() {
2183ebd59bb5dc9f421fd2b9b789ea824746d58fff7Jason parks        @Override
219dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly        public NdefMessage createFromParcel(Parcel in) {
220590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            int recordsLength = in.readInt();
221590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            NdefRecord[] records = new NdefRecord[recordsLength];
222590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            in.readTypedArray(records, NdefRecord.CREATOR);
223590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            return new NdefMessage(records);
224dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly        }
2253ebd59bb5dc9f421fd2b9b789ea824746d58fff7Jason parks        @Override
226dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly        public NdefMessage[] newArray(int size) {
227590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            return new NdefMessage[size];
228dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly        }
229dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    };
230590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
231a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    @Override
232a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    public int hashCode() {
233a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        return Arrays.hashCode(mRecords);
234a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    }
235a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly
236a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    /**
237a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * Returns true if the specified NDEF Message contains
238a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     * identical NDEF Records.
239a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly     */
240a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    @Override
241a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    public boolean equals(Object obj) {
242a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        if (this == obj) return true;
243a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        if (obj == null) return false;
244a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        if (getClass() != obj.getClass()) return false;
245a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        NdefMessage other = (NdefMessage) obj;
246a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        return Arrays.equals(mRecords, other.mRecords);
247a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    }
248a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly
249a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    @Override
250a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    public String toString() {
251a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly        return "NdefMessage " + Arrays.toString(mRecords);
252a356bf1cd81614a94ef6c720998792480ade4c84Nick Pelly    }
253dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly}