NdefPushServer.java revision 57d376f1ee1a3939977b95759525585abb9601fb
1/*
2 * Copyright (C) 2010 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
17package com.android.nfc.mytag;
18
19import com.android.internal.nfc.LlcpException;
20import com.android.internal.nfc.LlcpServiceSocket;
21import com.android.internal.nfc.LlcpSocket;
22import com.android.nfc.NfcService;
23
24import android.nfc.FormatException;
25import android.nfc.NdefMessage;
26import android.nfc.NfcAdapter;
27import android.util.Log;
28
29import java.io.ByteArrayOutputStream;
30import java.io.IOException;
31
32/**
33 * A simple server that accepts NDEF messages pushed to it over an LLCP connection. Those messages
34 * are typically set on the client side by using {@link NfcAdapter#setLocalNdefMessage}.
35 */
36public class MyTagServer {
37    private static final String TAG = "~~~~~~~~~~~~~~~";
38    private static final boolean DBG = true;
39    private static final int SERVICE_SAP = 0x20;
40
41    static final String SERVICE_NAME = "com.android.mytag";
42
43    NfcService mService = NfcService.getInstance();
44    /** Protected by 'this', null when stopped, non-null when running */
45    ServerThread mServerThread = null;
46
47    /** Connection class, used to handle incoming connections */
48    private class ConnectionThread extends Thread {
49        private LlcpSocket mSock;
50
51        ConnectionThread(LlcpSocket sock) {
52            mSock = sock;
53        }
54
55        @Override
56        public void run() {
57            if (DBG) Log.d(TAG, "starting connection thread");
58            try {
59                ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024);
60                byte[] partial = new byte[1024];
61                int size;
62                boolean connectionBroken = false;
63
64                // Get raw data from remote server
65                while(!connectionBroken) {
66                    try {
67                        size = mSock.receive(partial);
68                        if (DBG) Log.d(TAG, "read " + size + " bytes");
69                        if (size < 0) {
70                            connectionBroken = true;
71                            break;
72                        } else {
73                            buffer.write(partial, 0, size);
74                        }
75                    } catch (IOException e) {
76                        // Connection broken
77                        connectionBroken = true;
78                        if (DBG) Log.d(TAG, "connection broken");
79                    }
80                }
81
82                // Build NDEF message from the stream
83                NdefMessage msg = new NdefMessage(buffer.toByteArray());
84                if (DBG) Log.d(TAG, "got message " + msg.toString());
85
86                // Send the intent for the fake tag
87                mService.sendMockNdefTag(msg);
88            } catch (FormatException e) {
89                Log.e(TAG, "badly formatted NDEF message, ignoring", e);
90            }
91        }
92    };
93
94    /** Server class, used to listen for incoming connection request */
95    class ServerThread extends Thread {
96        boolean mRunning = true;
97        LlcpServiceSocket mServerSocket;
98
99        @Override
100        public void run() {
101            if (DBG) Log.d(TAG, "about create LLCP service socket");
102            mServerSocket = mService.createLlcpServiceSocket(SERVICE_SAP, null,
103                    128, 1, 1024);
104            if (mServerSocket == null) {
105                Log.d(TAG, "failed to create LLCP service socket");
106                return;
107            }
108            if (DBG) Log.d(TAG, "created LLCP service socket");
109            try {
110                while (mRunning) {
111                    if (DBG) Log.d(TAG, "about to accept");
112                    LlcpSocket communicationSocket = mServerSocket.accept();
113                    if (DBG) Log.d(TAG, "accept returned " + communicationSocket);
114                    if (communicationSocket != null) {
115                        new ConnectionThread(communicationSocket).start();
116                    }
117                }
118            } catch (LlcpException e) {
119                Log.e(TAG, "llcp error", e);
120            } catch (IOException e) {
121                Log.e(TAG, "IO error", e);
122            } finally {
123                if (mServerSocket != null) mServerSocket.close();
124            }
125        }
126
127        public void shutdown() {
128            mRunning = false;
129            if (mServerSocket != null) {
130                mServerSocket.close();
131            }
132        }
133    };
134
135    public void start() {
136        synchronized (this) {
137            if (DBG) Log.d(TAG, "start, thread = " + mServerThread);
138            if (mServerThread == null) {
139                if (DBG) Log.d(TAG, "starting new server thread");
140                mServerThread = new ServerThread();
141                mServerThread.start();
142            }
143        }
144    }
145
146    public void stop() {
147        synchronized (this) {
148            if (DBG) Log.d(TAG, "stop, thread = " + mServerThread);
149            if (mServerThread != null) {
150                if (DBG) Log.d(TAG, "shuting down server thread");
151                mServerThread.shutdown();
152                mServerThread = null;
153            }
154        }
155    }
156}
157