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 17package com.android.nfc.ndefpush; 18 19import android.util.Log; 20 21import android.nfc.NdefMessage; 22import android.nfc.FormatException; 23 24import java.io.ByteArrayInputStream; 25import java.io.DataInputStream; 26import java.io.ByteArrayOutputStream; 27import java.io.DataOutputStream; 28 29/** 30 * Implementation of the NDEF Push Protocol. 31 */ 32public class NdefPushProtocol { 33 public static final byte ACTION_IMMEDIATE = (byte) 0x01; 34 public static final byte ACTION_BACKGROUND = (byte) 0x02; 35 36 private static final String TAG = "NdefMessageSet"; 37 private static final byte VERSION = 1; 38 39 private int mNumMessages; 40 private byte[] mActions; 41 private NdefMessage[] mMessages; 42 43 public NdefPushProtocol(NdefMessage msg, byte action) { 44 mNumMessages = 1; 45 mActions = new byte[1]; 46 mActions[0] = action; 47 mMessages = new NdefMessage[1]; 48 mMessages[0] = msg; 49 } 50 51 public NdefPushProtocol(byte[] actions, NdefMessage[] messages) { 52 if (actions.length != messages.length || actions.length == 0) { 53 throw new IllegalArgumentException( 54 "actions and messages must be the same size and non-empty"); 55 } 56 57 // Keep a copy of these arrays 58 int numMessages = actions.length; 59 mActions = new byte[numMessages]; 60 System.arraycopy(actions, 0, mActions, 0, numMessages); 61 mMessages = new NdefMessage[numMessages]; 62 System.arraycopy(messages, 0, mMessages, 0, numMessages); 63 mNumMessages = numMessages; 64 } 65 66 public NdefPushProtocol(byte[] data) throws FormatException { 67 ByteArrayInputStream buffer = new ByteArrayInputStream(data); 68 DataInputStream input = new DataInputStream(buffer); 69 70 // Check version of protocol 71 byte version; 72 try { 73 version = input.readByte(); 74 } catch (java.io.IOException e) { 75 Log.w(TAG, "Unable to read version"); 76 throw new FormatException("Unable to read version"); 77 } 78 79 if(version != VERSION) { 80 Log.w(TAG, "Got version " + version + ", expected " + VERSION); 81 throw new FormatException("Got version " + version + ", expected " + VERSION); 82 } 83 84 // Read numMessages 85 try { 86 mNumMessages = input.readInt(); 87 } catch(java.io.IOException e) { 88 Log.w(TAG, "Unable to read numMessages"); 89 throw new FormatException("Error while parsing NdefMessageSet"); 90 } 91 if(mNumMessages == 0) { 92 Log.w(TAG, "No NdefMessage inside NdefMessageSet packet"); 93 throw new FormatException("Error while parsing NdefMessageSet"); 94 } 95 96 // Read actions and messages 97 mActions = new byte[mNumMessages]; 98 mMessages = new NdefMessage[mNumMessages]; 99 for(int i = 0; i < mNumMessages; i++) { 100 // Read action 101 try { 102 mActions[i] = input.readByte(); 103 } catch(java.io.IOException e) { 104 Log.w(TAG, "Unable to read action for message " + i); 105 throw new FormatException("Error while parsing NdefMessageSet"); 106 } 107 // Read message length 108 int length; 109 try { 110 length = input.readInt(); 111 } catch(java.io.IOException e) { 112 Log.w(TAG, "Unable to read length for message " + i); 113 throw new FormatException("Error while parsing NdefMessageSet"); 114 } 115 byte[] bytes = new byte[length]; 116 // Read message 117 int lengthRead; 118 try { 119 lengthRead = input.read(bytes); 120 } catch(java.io.IOException e) { 121 Log.w(TAG, "Unable to read bytes for message " + i); 122 throw new FormatException("Error while parsing NdefMessageSet"); 123 } 124 if(length != lengthRead) { 125 Log.w(TAG, "Read " + lengthRead + " bytes but expected " + 126 length); 127 throw new FormatException("Error while parsing NdefMessageSet"); 128 } 129 // Create and store NdefMessage 130 try { 131 mMessages[i] = new NdefMessage(bytes); 132 } catch(FormatException e) { 133 throw e; 134 } 135 } 136 } 137 138 public NdefMessage getImmediate() { 139 // Find and return the first immediate message 140 for(int i = 0; i < mNumMessages; i++) { 141 if(mActions[i] == ACTION_IMMEDIATE) { 142 return mMessages[i]; 143 } 144 } 145 return null; 146 } 147 148 public byte[] toByteArray() { 149 ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024); 150 DataOutputStream output = new DataOutputStream(buffer); 151 152 try { 153 output.writeByte(VERSION); 154 output.writeInt(mNumMessages); 155 for(int i = 0; i < mNumMessages; i++) { 156 output.writeByte(mActions[i]); 157 byte[] bytes = mMessages[i].toByteArray(); 158 output.writeInt(bytes.length); 159 output.write(bytes); 160 } 161 } catch(java.io.IOException e) { 162 return null; 163 } 164 165 return buffer.toByteArray(); 166 } 167} 168