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 */ 16package com.android.nfc.handover; 17 18import android.nfc.FormatException; 19import android.nfc.NdefMessage; 20import android.util.Log; 21 22import com.android.nfc.LlcpException; 23import com.android.nfc.NfcService; 24import com.android.nfc.DeviceHost.LlcpSocket; 25 26import java.io.ByteArrayOutputStream; 27import java.io.IOException; 28import java.util.Arrays; 29 30public 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