BluetoothOppRfcommListener.java revision b5cc776c9353a203cdde97e62b25f05d9633d14c
1/*
2 * Copyright (c) 2008-2009, Motorola, Inc.
3 *
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * - Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * - Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * - Neither the name of the Motorola, Inc. nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package com.android.bluetooth.opp;
34
35import java.io.IOException;
36import java.net.ServerSocket;
37import java.net.Socket;
38
39import android.bluetooth.BluetoothAdapter;
40import android.bluetooth.BluetoothServerSocket;
41import android.bluetooth.BluetoothSocket;
42import android.bluetooth.BluetoothUuid;
43import android.os.Handler;
44import android.os.Message;
45import android.util.Log;
46
47/**
48 * This class listens on OPUSH channel for incoming connection
49 */
50public class BluetoothOppRfcommListener {
51    private static final String TAG = "BtOppRfcommListener";
52
53    private static final boolean V = Constants.VERBOSE;
54
55    public static final int MSG_INCOMING_BTOPP_CONNECTION = 100;
56
57    private volatile boolean mInterrupted;
58    private volatile boolean mFinish;
59
60    private Thread mSocketAcceptThread;
61
62    private Handler mCallback;
63
64    private static final int CREATE_RETRY_TIME = 10;
65
66    private final BluetoothAdapter mAdapter;
67
68    private BluetoothServerSocket mBtServerSocket = null;
69
70    private ServerSocket mTcpServerSocket = null;
71
72    public BluetoothOppRfcommListener(BluetoothAdapter adapter) {
73        mAdapter = adapter;
74    }
75
76
77    public synchronized boolean start(Handler callback) {
78        if (mSocketAcceptThread == null) {
79            mCallback = callback;
80
81            mSocketAcceptThread = new Thread(TAG) {
82
83                public void run() {
84                    if (Constants.USE_TCP_DEBUG) {
85                        try {
86                            if (V) Log.v(TAG, "Create TCP ServerSocket");
87                            mTcpServerSocket = new ServerSocket(Constants.TCP_DEBUG_PORT, 1);
88                        } catch (IOException e) {
89                            Log.e(TAG, "Error listing on port" + Constants.TCP_DEBUG_PORT);
90                            mInterrupted = true;
91                        }
92                        while (!mInterrupted) {
93                            try {
94                                Socket clientSocket = mTcpServerSocket.accept();
95
96                                if (V) Log.v(TAG, "Socket connected!");
97                                TestTcpTransport transport = new TestTcpTransport(clientSocket);
98                                Message msg = Message.obtain();
99                                msg.setTarget(mCallback);
100                                msg.what = MSG_INCOMING_BTOPP_CONNECTION;
101                                msg.obj = transport;
102                                msg.sendToTarget();
103
104                            } catch (IOException e) {
105                                Log.e(TAG, "Error accept connection " + e);
106                            }
107                        }
108                        if (V) Log.v(TAG, "TCP listen thread finished");
109                    } else {
110                        boolean serverOK = true;
111
112                        /*
113                         * it's possible that create will fail in some cases.
114                         * retry for 10 times
115                         */
116                        for (int i = 0; i < CREATE_RETRY_TIME && !mInterrupted; i++) {
117                            try {
118                                if (V) Log.v(TAG, "Starting RFCOMM listener....");
119                                mBtServerSocket = mAdapter.listenUsingInsecureRfcommWithServiceRecord("OBEX Object Push", BluetoothUuid.ObexObjectPush.getUuid());
120                                if (V) Log.v(TAG, "Started RFCOMM listener....");
121                            } catch (IOException e1) {
122                                Log.e(TAG, "Error create RfcommServerSocket " + e1);
123                                serverOK = false;
124                            }
125                            if (!serverOK) {
126                                synchronized (this) {
127                                    try {
128                                        if (V) Log.v(TAG, "Wait 3 seconds");
129                                        Thread.sleep(3000);
130                                    } catch (InterruptedException e) {
131                                        Log.e(TAG, "socketAcceptThread thread was interrupted (3)");
132                                        mInterrupted = true;
133                                    }
134                                }
135                            } else {
136                                break;
137                            }
138                        }
139                        if (!serverOK) {
140                            Log.e(TAG, "Error start listening after " + CREATE_RETRY_TIME + " try");
141                            mInterrupted = true;
142                        }
143                        if (!mInterrupted) {
144                            Log.i(TAG, "Accept thread started.");
145                        }
146                        BluetoothSocket clientSocket;
147                        while (!mInterrupted) {
148                            try {
149                                if (V) Log.v(TAG, "Accepting connection...");
150                                if (mBtServerSocket == null) {
151
152                                }
153                                BluetoothServerSocket sSocket = mBtServerSocket;
154                                if (sSocket ==null) {
155                                    mInterrupted = true;
156
157                                } else {
158                                    clientSocket = mBtServerSocket.accept();
159                                    if (V) Log.v(TAG, "Accepted connection from "
160                                        + clientSocket.getRemoteDevice());
161                                    BluetoothOppRfcommTransport transport = new BluetoothOppRfcommTransport(
162                                        clientSocket);
163                                    Message msg = Message.obtain();
164                                    msg.setTarget(mCallback);
165                                    msg.what = MSG_INCOMING_BTOPP_CONNECTION;
166                                    msg.obj = transport;
167                                    msg.sendToTarget();
168                                }
169                            } catch (IOException e) {
170                                Log.e(TAG, "Error accept connection " + e);
171                            }
172                        }
173                        Log.i(TAG, "BluetoothSocket listen thread finished");
174                    }
175                }
176            };
177            mInterrupted = false;
178            if(!Constants.USE_TCP_SIMPLE_SERVER) {
179                mSocketAcceptThread.start();
180            }
181        }
182        return true;
183    }
184
185    public synchronized void stop() {
186        if (mSocketAcceptThread != null) {
187            Log.i(TAG, "stopping Accept Thread");
188
189            mInterrupted = true;
190             if (Constants.USE_TCP_DEBUG) {
191                if (V) Log.v(TAG, "close mTcpServerSocket");
192                if (mTcpServerSocket != null) {
193                    try {
194                        mTcpServerSocket.close();
195                        mTcpServerSocket = null;
196                    } catch (IOException e) {
197                        Log.e(TAG, "Error close mTcpServerSocket");
198                    }
199                }
200            } else {
201                if (V) Log.v(TAG, "close mBtServerSocket");
202
203                if (mBtServerSocket != null) {
204                    try {
205                        mBtServerSocket.close();
206                        mBtServerSocket = null;
207                    } catch (IOException e) {
208                        Log.e(TAG, "Error close mBtServerSocket");
209                    }
210                }
211            }
212            try {
213                mSocketAcceptThread.interrupt();
214                if (V) Log.v(TAG, "waiting for thread to terminate");
215                mSocketAcceptThread.join();
216                mSocketAcceptThread = null;
217                mCallback = null;
218            } catch (InterruptedException e) {
219                if (V) Log.v(TAG, "Interrupted waiting for Accept Thread to join");
220            }
221        }
222    }
223}
224