Home | History | Annotate | Download | only in ndefpush
      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 com.android.nfc.ndefpush;
     18 
     19 import android.util.Log;
     20 
     21 import android.nfc.NdefMessage;
     22 import android.nfc.FormatException;
     23 
     24 import java.io.ByteArrayInputStream;
     25 import java.io.DataInputStream;
     26 import java.io.ByteArrayOutputStream;
     27 import java.io.DataOutputStream;
     28 
     29 /**
     30  * Implementation of the NDEF Push Protocol.
     31  */
     32 public 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