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 19 import android.os.Parcel; 20 import android.os.Parcelable; 21 22 /** 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. 29 */ 30 public final class NdefMessage implements Parcelable { 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 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. 41 * @throws FormatException 42 */ 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 } 48 } 49 50 /** 51 * Create an NDEF message from NDEF records. 52 */ 53 public NdefMessage(NdefRecord[] records) { 54 mRecords = new NdefRecord[records.length]; 55 System.arraycopy(records, 0, mRecords, 0, records.length); 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() { 64 return mRecords.clone(); 65 } 66 67 /** 68 * Returns a byte array representation of this entire NDEF message. 69 */ 70 public byte[] toByteArray() { 71 //TODO: allocate the byte array once, copy each record once 72 //TODO: process MB and ME flags outside loop 73 if ((mRecords == null) || (mRecords.length == 0)) 74 return new byte[0]; 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; 103 } 104 105 @Override 106 public int describeContents() { 107 return 0; 108 } 109 110 @Override 111 public void writeToParcel(Parcel dest, int flags) { 112 dest.writeInt(mRecords.length); 113 dest.writeTypedArray(mRecords, flags); 114 } 115 116 public static final Parcelable.Creator<NdefMessage> CREATOR = 117 new Parcelable.Creator<NdefMessage>() { 118 @Override 119 public NdefMessage createFromParcel(Parcel in) { 120 int recordsLength = in.readInt(); 121 NdefRecord[] records = new NdefRecord[recordsLength]; 122 in.readTypedArray(records, NdefRecord.CREATOR); 123 return new NdefMessage(records); 124 } 125 @Override 126 public NdefMessage[] newArray(int size) { 127 return new NdefMessage[size]; 128 } 129 }; 130 131 private native int parseNdefMessage(byte[] data); 132 }