Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 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 | |
| 17 | package android.nfc; |
| 18 | |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 19 | import android.os.Parcel; |
| 20 | import android.os.Parcelable; |
| 21 | |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 22 | /** |
Scott Main | c9f7890 | 2010-10-15 09:15:09 -0700 | [diff] [blame] | 23 | * Represents an NDEF (NFC Data Exchange Format) data message that contains one or more {@link |
| 24 | * NdefRecord}s. |
| 25 | * <p>An NDEF message includes "records" that can contain different sets of data, such as |
| 26 | * MIME-type media, a URI, or one of the supported RTD types (see {@link NdefRecord}). An NDEF |
| 27 | * message always contains zero or more NDEF records.</p> |
| 28 | * <p>This is an immutable data class. |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 29 | */ |
Nick Pelly | 11b075e | 2010-10-28 13:39:37 -0700 | [diff] [blame] | 30 | public final class NdefMessage implements Parcelable { |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 31 | private static final byte FLAG_MB = (byte) 0x80; |
| 32 | private static final byte FLAG_ME = (byte) 0x40; |
| 33 | |
| 34 | private final NdefRecord[] mRecords; |
| 35 | |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 36 | /** |
| 37 | * Create an NDEF message from raw bytes. |
| 38 | * <p> |
| 39 | * Validation is performed to make sure the Record format headers are valid, |
| 40 | * and the ID + TYPE + PAYLOAD fields are of the correct size. |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 41 | * @throws FormatException |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 42 | */ |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 43 | public NdefMessage(byte[] data) throws FormatException { |
| 44 | mRecords = null; // stop compiler complaints about final field |
| 45 | if (parseNdefMessage(data) == -1) { |
| 46 | throw new FormatException("Error while parsing NDEF message"); |
| 47 | } |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 48 | } |
| 49 | |
| 50 | /** |
| 51 | * Create an NDEF message from NDEF records. |
| 52 | */ |
| 53 | public NdefMessage(NdefRecord[] records) { |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 54 | mRecords = new NdefRecord[records.length]; |
| 55 | System.arraycopy(records, 0, mRecords, 0, records.length); |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 56 | } |
| 57 | |
| 58 | /** |
| 59 | * Get the NDEF records inside this NDEF message. |
| 60 | * |
| 61 | * @return array of zero or more NDEF records. |
| 62 | */ |
| 63 | public NdefRecord[] getRecords() { |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 64 | return mRecords.clone(); |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 65 | } |
| 66 | |
| 67 | /** |
Jeff Hamilton | da83f51 | 2010-10-21 22:39:30 -0500 | [diff] [blame] | 68 | * Returns a byte array representation of this entire NDEF message. |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 69 | */ |
| 70 | public byte[] toByteArray() { |
Nick Pelly | 11b075e | 2010-10-28 13:39:37 -0700 | [diff] [blame] | 71 | //TODO: allocate the byte array once, copy each record once |
| 72 | //TODO: process MB and ME flags outside loop |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 73 | if ((mRecords == null) || (mRecords.length == 0)) |
Jason parks | 3ebd59b | 2010-11-02 20:03:52 -0500 | [diff] [blame] | 74 | return new byte[0]; |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 75 | |
| 76 | byte[] msg = {}; |
| 77 | |
| 78 | for (int i = 0; i < mRecords.length; i++) { |
| 79 | byte[] record = mRecords[i].toByteArray(); |
| 80 | byte[] tmp = new byte[msg.length + record.length]; |
| 81 | |
| 82 | /* Make sure the Message Begin flag is set only for the first record */ |
| 83 | if (i == 0) { |
| 84 | record[0] |= FLAG_MB; |
| 85 | } else { |
| 86 | record[0] &= ~FLAG_MB; |
| 87 | } |
| 88 | |
| 89 | /* Make sure the Message End flag is set only for the last record */ |
| 90 | if (i == (mRecords.length - 1)) { |
| 91 | record[0] |= FLAG_ME; |
| 92 | } else { |
| 93 | record[0] &= ~FLAG_ME; |
| 94 | } |
| 95 | |
| 96 | System.arraycopy(msg, 0, tmp, 0, msg.length); |
| 97 | System.arraycopy(record, 0, tmp, msg.length, record.length); |
| 98 | |
| 99 | msg = tmp; |
| 100 | } |
| 101 | |
| 102 | return msg; |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 103 | } |
| 104 | |
Jason parks | 3ebd59b | 2010-11-02 20:03:52 -0500 | [diff] [blame] | 105 | @Override |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 106 | public int describeContents() { |
| 107 | return 0; |
| 108 | } |
| 109 | |
Jason parks | 3ebd59b | 2010-11-02 20:03:52 -0500 | [diff] [blame] | 110 | @Override |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 111 | public void writeToParcel(Parcel dest, int flags) { |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 112 | dest.writeInt(mRecords.length); |
| 113 | dest.writeTypedArray(mRecords, flags); |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 114 | } |
| 115 | |
| 116 | public static final Parcelable.Creator<NdefMessage> CREATOR = |
| 117 | new Parcelable.Creator<NdefMessage>() { |
Jason parks | 3ebd59b | 2010-11-02 20:03:52 -0500 | [diff] [blame] | 118 | @Override |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 119 | public NdefMessage createFromParcel(Parcel in) { |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 120 | int recordsLength = in.readInt(); |
| 121 | NdefRecord[] records = new NdefRecord[recordsLength]; |
| 122 | in.readTypedArray(records, NdefRecord.CREATOR); |
| 123 | return new NdefMessage(records); |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 124 | } |
Jason parks | 3ebd59b | 2010-11-02 20:03:52 -0500 | [diff] [blame] | 125 | @Override |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 126 | public NdefMessage[] newArray(int size) { |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 127 | return new NdefMessage[size]; |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 128 | } |
| 129 | }; |
Nick Pelly | 590b73b | 2010-10-12 13:00:50 -0700 | [diff] [blame] | 130 | |
| 131 | private native int parseNdefMessage(byte[] data); |
Nick Pelly | dc99379 | 2010-10-04 11:17:25 -0700 | [diff] [blame] | 132 | } |