NdefMessage.java revision 590b73bc5b8e5f7b59bff1d9264a52388a5162e6
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
19dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pellyimport android.nfc.NdefRecord;
20dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pellyimport android.os.Parcel;
21dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pellyimport android.os.Parcelable;
22dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
23dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly/**
24dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * NDEF Message data.
25dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * <p>
26dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * Immutable data class. An NDEF message always contains zero or more NDEF
27dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly * records.
28dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly */
29dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pellypublic class NdefMessage implements Parcelable {
30590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    private static final byte FLAG_MB = (byte) 0x80;
31590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    private static final byte FLAG_ME = (byte) 0x40;
32590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
33590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    private final NdefRecord[] mRecords;
34590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
35590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    //TODO(npelly) FormatException
36dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    /**
37dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     * Create an NDEF message from raw bytes.
38dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     * <p>
39dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     * Validation is performed to make sure the Record format headers are valid,
40dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     * and the ID + TYPE + PAYLOAD fields are of the correct size.
41590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly     * @throws FormatException
42dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     *
43dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     * @hide
44dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     */
45590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    public NdefMessage(byte[] data) throws FormatException {
46590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        mRecords = null;  // stop compiler complaints about final field
47590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        if (parseNdefMessage(data) == -1) {
48590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            throw new FormatException("Error while parsing NDEF message");
49590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        }
50dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    }
51dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
52dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    /**
53dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     * Create an NDEF message from NDEF records.
54dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     */
55dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    public NdefMessage(NdefRecord[] records) {
56590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        mRecords = new NdefRecord[records.length];
57590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        System.arraycopy(records, 0, mRecords, 0, records.length);
58dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    }
59dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
60dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    /**
61dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     * Get the NDEF records inside this NDEF message.
62dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     *
63dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     * @return array of zero or more NDEF records.
64dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     */
65dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    public NdefRecord[] getRecords() {
66590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        return mRecords.clone();
67dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    }
68dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
69dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    /**
70dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     * Get a byte array representation of this NDEF message.
71dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     *
72dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     * @return byte array
73dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     * @hide
74dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly     */
75dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    public byte[] toByteArray() {
76590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        //TODO(nxp): do not return null
77590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        //TODO(nxp): allocate the byte array once, copy each record once
78590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        //TODO(nxp): process MB and ME flags outside loop
79590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        if ((mRecords == null) || (mRecords.length == 0))
80590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            return null;
81590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
82590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        byte[] msg = {};
83590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
84590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        for (int i = 0; i < mRecords.length; i++) {
85590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            byte[] record = mRecords[i].toByteArray();
86590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            byte[] tmp = new byte[msg.length + record.length];
87590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
88590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            /* Make sure the Message Begin flag is set only for the first record */
89590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            if (i == 0) {
90590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly                record[0] |= FLAG_MB;
91590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            } else {
92590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly                record[0] &= ~FLAG_MB;
93590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            }
94590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
95590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            /* Make sure the Message End flag is set only for the last record */
96590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            if (i == (mRecords.length - 1)) {
97590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly                record[0] |= FLAG_ME;
98590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            } else {
99590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly                record[0] &= ~FLAG_ME;
100590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            }
101590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
102590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            System.arraycopy(msg, 0, tmp, 0, msg.length);
103590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            System.arraycopy(record, 0, tmp, msg.length, record.length);
104590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
105590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            msg = tmp;
106590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        }
107590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
108590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        return msg;
109dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    }
110dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
111dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    public int describeContents() {
112dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly        return 0;
113dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    }
114dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
115dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    public void writeToParcel(Parcel dest, int flags) {
116590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        dest.writeInt(mRecords.length);
117590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly        dest.writeTypedArray(mRecords, flags);
118dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    }
119dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly
120dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    public static final Parcelable.Creator<NdefMessage> CREATOR =
121dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly            new Parcelable.Creator<NdefMessage>() {
122dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly        public NdefMessage createFromParcel(Parcel in) {
123590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            int recordsLength = in.readInt();
124590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            NdefRecord[] records = new NdefRecord[recordsLength];
125590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            in.readTypedArray(records, NdefRecord.CREATOR);
126590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            return new NdefMessage(records);
127dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly        }
128dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly        public NdefMessage[] newArray(int size) {
129590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly            return new NdefMessage[size];
130dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly        }
131dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly    };
132590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly
133590b73bc5b8e5f7b59bff1d9264a52388a5162e6Nick Pelly    private native int parseNdefMessage(byte[] data);
134dc993791fc3cf7a270921f7419b0c6b875bbd92bNick Pelly}