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 
connect()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 
push(NdefMessage msg)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 
close()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