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