Home | History | Annotate | Download | only in ndefpush
      1 /*
      2  * Copyright (C) 2011 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 com.android.nfc.DeviceHost.LlcpSocket;
     20 import com.android.nfc.LlcpException;
     21 import com.android.nfc.NfcService;
     22 
     23 import android.nfc.NdefMessage;
     24 import android.util.Log;
     25 
     26 import java.io.IOException;
     27 import java.util.Arrays;
     28 
     29 /**
     30  * Simple client to push the local NDEF message to a server on the remote side of an
     31  * LLCP connection, using the Android Ndef Push Protocol.
     32  */
     33 public class NdefPushClient {
     34     private static final String TAG = "NdefPushClient";
     35     private static final int MIU = 128;
     36     private static final boolean DBG = true;
     37 
     38     private static final int DISCONNECTED = 0;
     39     private static final int CONNECTING = 1;
     40     private static final int CONNECTED = 2;
     41 
     42     final Object mLock = new Object();
     43     // Variables below locked on mLock
     44     private int mState = DISCONNECTED;
     45     private LlcpSocket mSocket;
     46 
     47     public void connect() throws IOException {
     48         synchronized (mLock) {
     49             if (mState != DISCONNECTED) {
     50                 throw new IOException("Socket still in use.");
     51             }
     52             mState = CONNECTING;
     53         }
     54         NfcService service = NfcService.getInstance();
     55         LlcpSocket sock = null;
     56         if (DBG) Log.d(TAG, "about to create socket");
     57         try {
     58             sock = service.createLlcpSocket(0, MIU, 1, 1024);
     59         } catch (LlcpException e) {
     60             synchronized (mLock) {
     61                 mState = DISCONNECTED;
     62             }
     63             throw new IOException("Could not create socket.");
     64         }
     65         try {
     66             if (DBG) Log.d(TAG, "about to connect to service " + NdefPushServer.SERVICE_NAME);
     67             sock.connectToService(NdefPushServer.SERVICE_NAME);
     68         } catch (IOException e) {
     69             if (sock != null) {
     70                 try {
     71                     sock.close();
     72                 } catch (IOException e2) {
     73 
     74                 }
     75             }
     76             synchronized (mLock) {
     77                 mState = DISCONNECTED;
     78             }
     79             throw new IOException("Could not connect service.");
     80         }
     81 
     82         synchronized (mLock) {
     83             mSocket = sock;
     84             mState = CONNECTED;
     85         }
     86     }
     87 
     88     public boolean push(NdefMessage msg) {
     89         LlcpSocket sock = null;
     90         synchronized (mLock) {
     91             if (mState != CONNECTED) {
     92                 Log.e(TAG, "Not connected to NPP.");
     93                 return false;
     94             }
     95             sock = mSocket;
     96         }
     97         // We only handle a single immediate action for now
     98         NdefPushProtocol proto = new NdefPushProtocol(msg, NdefPushProtocol.ACTION_IMMEDIATE);
     99         byte[] buffer = proto.toByteArray();
    100         int offset = 0;
    101         int remoteMiu;
    102 
    103         try {
    104             remoteMiu = sock.getRemoteMiu();
    105             if (DBG) Log.d(TAG, "about to send a " + buffer.length + " byte message");
    106             while (offset < buffer.length) {
    107                 int length = Math.min(buffer.length - offset, remoteMiu);
    108                 byte[] tmpBuffer = Arrays.copyOfRange(buffer, offset, offset+length);
    109                 if (DBG) Log.d(TAG, "about to send a " + length + " byte packet");
    110                 sock.send(tmpBuffer);
    111                 offset += length;
    112             }
    113             return true;
    114         } catch (IOException e) {
    115             Log.e(TAG, "couldn't send tag");
    116             if (DBG) Log.d(TAG, "exception:", e);
    117         } finally {
    118             if (sock != null) {
    119                 try {
    120                     if (DBG) Log.d(TAG, "about to close");
    121                     sock.close();
    122                 } catch (IOException e) {
    123                     // Ignore
    124                 }
    125             }
    126         }
    127         return false;
    128     }
    129 
    130     public void close() {
    131         synchronized (mLock) {
    132             if (mSocket != null) {
    133                 try {
    134                     if (DBG) Log.d(TAG, "About to close NPP socket.");
    135                     mSocket.close();
    136                 } catch (IOException e) {
    137                     // Ignore
    138                 }
    139                 mSocket = null;
    140             }
    141             mState = DISCONNECTED;
    142         }
    143     }
    144 }
    145