1ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton/* 2ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * Copyright (C) 2010 The Android Open Source Project 3ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * 4ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * Licensed under the Apache License, Version 2.0 (the "License"); 5ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * you may not use this file except in compliance with the License. 6ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * You may obtain a copy of the License at 7ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * 8ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * http://www.apache.org/licenses/LICENSE-2.0 9ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * 10ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * Unless required by applicable law or agreed to in writing, software 11ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * distributed under the License is distributed on an "AS IS" BASIS, 12ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * See the License for the specific language governing permissions and 14ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * limitations under the License. 15ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton */ 16ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 17ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamiltonpackage com.android.nfc.ndefpush; 18ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 19ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamiltonimport android.util.Log; 20ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 21ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamiltonimport android.nfc.NdefMessage; 22ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamiltonimport android.nfc.FormatException; 23ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 24ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamiltonimport java.io.ByteArrayInputStream; 25ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamiltonimport java.io.DataInputStream; 26ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamiltonimport java.io.ByteArrayOutputStream; 27ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamiltonimport java.io.DataOutputStream; 28ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 29ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton/** 30ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton * Implementation of the NDEF Push Protocol. 31ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton */ 32ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamiltonpublic class NdefPushProtocol { 33ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton public static final byte ACTION_IMMEDIATE = (byte) 0x01; 34ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton public static final byte ACTION_BACKGROUND = (byte) 0x02; 35ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 36ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton private static final String TAG = "NdefMessageSet"; 37ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton private static final byte VERSION = 1; 38ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 39ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton private int mNumMessages; 40ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton private byte[] mActions; 41ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton private NdefMessage[] mMessages; 42ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 43ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton public NdefPushProtocol(NdefMessage msg, byte action) { 44ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mNumMessages = 1; 45ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mActions = new byte[1]; 46ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mActions[0] = action; 47ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mMessages = new NdefMessage[1]; 48ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mMessages[0] = msg; 49ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 50ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 51ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton public NdefPushProtocol(byte[] actions, NdefMessage[] messages) { 52ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton if (actions.length != messages.length || actions.length == 0) { 53ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton throw new IllegalArgumentException( 54ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton "actions and messages must be the same size and non-empty"); 55ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 56ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 57ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton // Keep a copy of these arrays 58ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton int numMessages = actions.length; 59ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mActions = new byte[numMessages]; 60ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton System.arraycopy(actions, 0, mActions, 0, numMessages); 61ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mMessages = new NdefMessage[numMessages]; 62ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton System.arraycopy(messages, 0, mMessages, 0, numMessages); 63ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mNumMessages = numMessages; 64ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 65ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 66ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton public NdefPushProtocol(byte[] data) throws FormatException { 67ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton ByteArrayInputStream buffer = new ByteArrayInputStream(data); 68ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton DataInputStream input = new DataInputStream(buffer); 69ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 70ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton // Check version of protocol 71ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton byte version; 72ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton try { 73ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton version = input.readByte(); 74ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } catch (java.io.IOException e) { 75ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton Log.w(TAG, "Unable to read version"); 76ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton throw new FormatException("Unable to read version"); 77ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 78ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 79ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton if(version != VERSION) { 80ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton Log.w(TAG, "Got version " + version + ", expected " + VERSION); 81ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton throw new FormatException("Got version " + version + ", expected " + VERSION); 82ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 83ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 84ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton // Read numMessages 85ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton try { 86ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mNumMessages = input.readInt(); 87ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } catch(java.io.IOException e) { 88ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton Log.w(TAG, "Unable to read numMessages"); 89ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton throw new FormatException("Error while parsing NdefMessageSet"); 90ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 91ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton if(mNumMessages == 0) { 92ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton Log.w(TAG, "No NdefMessage inside NdefMessageSet packet"); 93ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton throw new FormatException("Error while parsing NdefMessageSet"); 94ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 95ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 96ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton // Read actions and messages 97ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mActions = new byte[mNumMessages]; 98ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mMessages = new NdefMessage[mNumMessages]; 99ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton for(int i = 0; i < mNumMessages; i++) { 100ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton // Read action 101ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton try { 102ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mActions[i] = input.readByte(); 103ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } catch(java.io.IOException e) { 104ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton Log.w(TAG, "Unable to read action for message " + i); 105ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton throw new FormatException("Error while parsing NdefMessageSet"); 106ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 107ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton // Read message length 108ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton int length; 109ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton try { 110ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton length = input.readInt(); 111ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } catch(java.io.IOException e) { 112ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton Log.w(TAG, "Unable to read length for message " + i); 113ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton throw new FormatException("Error while parsing NdefMessageSet"); 114ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 115ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton byte[] bytes = new byte[length]; 116ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton // Read message 117ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton int lengthRead; 118ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton try { 119ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton lengthRead = input.read(bytes); 120ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } catch(java.io.IOException e) { 121ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton Log.w(TAG, "Unable to read bytes for message " + i); 122ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton throw new FormatException("Error while parsing NdefMessageSet"); 123ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 124ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton if(length != lengthRead) { 125ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton Log.w(TAG, "Read " + lengthRead + " bytes but expected " + 126ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton length); 127ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton throw new FormatException("Error while parsing NdefMessageSet"); 128ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 129ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton // Create and store NdefMessage 130ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton try { 131ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton mMessages[i] = new NdefMessage(bytes); 132ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } catch(FormatException e) { 133ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton throw e; 134ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 135ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 136ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 137ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 138ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton public NdefMessage getImmediate() { 139ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton // Find and return the first immediate message 140ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton for(int i = 0; i < mNumMessages; i++) { 141ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton if(mActions[i] == ACTION_IMMEDIATE) { 142ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton return mMessages[i]; 143ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 144ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 145ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton return null; 146ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 147ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 148ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton public byte[] toByteArray() { 149ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024); 150ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton DataOutputStream output = new DataOutputStream(buffer); 151ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 152ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton try { 153ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton output.writeByte(VERSION); 154ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton output.writeInt(mNumMessages); 155ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton for(int i = 0; i < mNumMessages; i++) { 156ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton output.writeByte(mActions[i]); 157ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton byte[] bytes = mMessages[i].toByteArray(); 158ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton output.writeInt(bytes.length); 159ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton output.write(bytes); 160ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 161ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } catch(java.io.IOException e) { 162ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton return null; 163ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 164ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton 165ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton return buffer.toByteArray(); 166ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton } 167ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton} 168