• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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