Home | History | Annotate | Download | only in handover
      1 /*
      2  * Copyright (C) 2012 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 package com.android.nfc.handover;
     17 
     18 import android.nfc.FormatException;
     19 import android.nfc.NdefMessage;
     20 import android.util.Log;
     21 
     22 import com.android.nfc.LlcpException;
     23 import com.android.nfc.NfcService;
     24 import com.android.nfc.DeviceHost.LlcpSocket;
     25 
     26 import java.io.ByteArrayOutputStream;
     27 import java.io.IOException;
     28 import java.util.Arrays;
     29 
     30 public final class HandoverClient {
     31     private static final String TAG = "HandoverClient";
     32     private static final int MIU = 128;
     33     private static final boolean DBG = false;
     34 
     35     private static final int DISCONNECTED = 0;
     36     private static final int CONNECTING = 1;
     37     private static final int CONNECTED = 2;
     38 
     39     private static final Object mLock = new Object();
     40 
     41     // Variables below synchronized on mLock
     42     LlcpSocket mSocket;
     43     int mState;
     44 
     45     public void connect() throws IOException {
     46         synchronized (mLock) {
     47             if (mState != DISCONNECTED) {
     48                 throw new IOException("Socket in use.");
     49             }
     50             mState = CONNECTING;
     51         }
     52         NfcService service = NfcService.getInstance();
     53         LlcpSocket sock = null;
     54         try {
     55             sock = service.createLlcpSocket(0, MIU, 1, 1024);
     56         } catch (LlcpException e) {
     57             synchronized (mLock) {
     58                 mState = DISCONNECTED;
     59             }
     60             throw new IOException("Could not create socket");
     61         }
     62         try {
     63             if (DBG) Log.d(TAG, "about to connect to service " +
     64                     HandoverServer.HANDOVER_SERVICE_NAME);
     65             sock.connectToService(HandoverServer.HANDOVER_SERVICE_NAME);
     66         } catch (IOException e) {
     67             if (sock != null) {
     68                 try {
     69                     sock.close();
     70                 } catch (IOException e2) {
     71                     // Ignore
     72                 }
     73             }
     74             synchronized (mLock) {
     75                 mState = DISCONNECTED;
     76             }
     77             throw new IOException("Could not connect to handover service");
     78         }
     79         synchronized (mLock) {
     80             mSocket = sock;
     81             mState = CONNECTED;
     82         }
     83     }
     84 
     85     public void close() {
     86         synchronized (mLock) {
     87             if (mSocket != null) {
     88                 try {
     89                     mSocket.close();
     90                 } catch (IOException e) {
     91                     // Ignore
     92                 }
     93                 mSocket = null;
     94             }
     95             mState = DISCONNECTED;
     96         }
     97     }
     98     public NdefMessage sendHandoverRequest(NdefMessage msg) throws IOException {
     99         if (msg == null) return null;
    100 
    101         LlcpSocket sock = null;
    102         synchronized (mLock) {
    103             if (mState != CONNECTED) {
    104                 throw new IOException("Socket not connected");
    105             }
    106             sock = mSocket;
    107         }
    108         int offset = 0;
    109         byte[] buffer = msg.toByteArray();
    110         ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
    111 
    112         try {
    113             int remoteMiu = sock.getRemoteMiu();
    114             if (DBG) Log.d(TAG, "about to send a " + buffer.length + " byte message");
    115             while (offset < buffer.length) {
    116                 int length = Math.min(buffer.length - offset, remoteMiu);
    117                 byte[] tmpBuffer = Arrays.copyOfRange(buffer, offset, offset+length);
    118                 if (DBG) Log.d(TAG, "about to send a " + length + " byte packet");
    119                 sock.send(tmpBuffer);
    120                 offset += length;
    121             }
    122 
    123             // Now, try to read back the handover response
    124             byte[] partial = new byte[sock.getLocalMiu()];
    125             NdefMessage handoverSelectMsg = null;
    126             while (true) {
    127                 int size = sock.receive(partial);
    128                 if (size < 0) {
    129                     break;
    130                 }
    131                 byteStream.write(partial, 0, size);
    132                 try {
    133                     handoverSelectMsg = new NdefMessage(byteStream.toByteArray());
    134                     // If we get here, message is complete
    135                     break;
    136                 } catch (FormatException e) {
    137                     // Ignore, and try to fetch more bytes
    138                 }
    139             }
    140             return handoverSelectMsg;
    141         } catch (IOException e) {
    142             if (DBG) Log.d(TAG, "couldn't connect to handover service");
    143         } finally {
    144             if (sock != null) {
    145                 try {
    146                     if (DBG) Log.d(TAG, "about to close");
    147                     sock.close();
    148                 } catch (IOException e) {
    149                     // Ignore
    150                 }
    151             }
    152             try {
    153                 byteStream.close();
    154             } catch (IOException e) {
    155                 // Ignore
    156             }
    157         }
    158         return null;
    159     }
    160 }
    161