BluetoothOppRfcommListener.java revision 41ef8d494511c040451f2f887cb31c3100746b61
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; 38import java.net.SocketException; 39 40import android.bluetooth.BluetoothAdapter; 41import android.bluetooth.BluetoothServerSocket; 42import android.bluetooth.BluetoothSocket; 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 = "BtOpp RfcommListener"; 52 53 private volatile boolean mInterrupted; 54 55 private Thread mSocketAcceptThread; 56 57 private Handler mCallback; 58 59 private static final int ACCEPT_WAIT_TIMEOUT = 5000; 60 61 private static final int CREATE_RETRY_TIME = 10; 62 63 public static final int DEFAULT_OPP_CHANNEL = 12; 64 65 public static final int MSG_INCOMING_BTOPP_CONNECTION = 100; 66 67 private final int mBtOppRfcommChannel; 68 69 private final BluetoothAdapter mAdapter; 70 71 public BluetoothOppRfcommListener(BluetoothAdapter adapter) { 72 this(adapter, DEFAULT_OPP_CHANNEL); 73 } 74 75 public BluetoothOppRfcommListener(BluetoothAdapter adapter, int channel) { 76 mBtOppRfcommChannel = channel; 77 mAdapter = adapter; 78 } 79 80 public synchronized boolean start(Handler callback) { 81 if (mSocketAcceptThread == null) { 82 mCallback = callback; 83 if (Constants.LOGV) { 84 Log.v(TAG, "create mSocketAcceptThread"); 85 } 86 mSocketAcceptThread = new Thread(TAG) { 87 88 public void run() { 89 if (Constants.LOGV) { 90 Log.v(TAG, "BluetoothOppRfcommListener thread starting"); 91 } 92 if (Constants.USE_TCP_DEBUG) { 93 ServerSocket mServerSocket = null; 94 try { 95 if (Constants.LOGVV) { 96 Log.v(TAG, "Create ServerSocket on port " 97 + Constants.TCP_DEBUG_PORT); 98 } 99 100 mServerSocket = new ServerSocket(Constants.TCP_DEBUG_PORT, 1); 101 102 } catch (IOException e) { 103 Log.e(TAG, "Error listing on port" + Constants.TCP_DEBUG_PORT); 104 mInterrupted = true; 105 } 106 while (!mInterrupted) { 107 try { 108 mServerSocket.setSoTimeout(ACCEPT_WAIT_TIMEOUT); 109 Socket clientSocket = mServerSocket.accept(); 110 111 if (clientSocket == null) { 112 if (Constants.LOGVV) { 113 Log.v(TAG, "incomming connection time out"); 114 } 115 } else { 116 if (Constants.LOGV) { 117 Log.v(TAG, "TCP Socket connected!"); 118 } 119 Log.d(TAG, "remote addr is " 120 + clientSocket.getRemoteSocketAddress()); 121 TestTcpTransport transport = new TestTcpTransport(clientSocket); 122 Message msg = Message.obtain(); 123 msg.setTarget(mCallback); 124 msg.what = MSG_INCOMING_BTOPP_CONNECTION; 125 msg.obj = transport; 126 msg.sendToTarget(); 127 } 128 } catch (SocketException e) { 129 if (Constants.LOGVV) { 130 Log.v(TAG, "Error accept connection " + e); 131 } 132 } catch (IOException e) { 133 if (Constants.LOGVV) { 134 Log.v(TAG, "Error accept connection " + e); 135 } 136 } 137 } 138 if (Constants.LOGV) { 139 Log.v(TAG, "TCP listen thread finished"); 140 } 141 try { 142 mServerSocket.close(); 143 } catch (IOException e) { 144 Log.e(TAG, "Error close mServerSocker " + e); 145 } 146 } else { 147 BluetoothServerSocket mServerSocket = null; 148 boolean serverOK = true; 149 150 /* 151 * it's possible that create will fail in some cases. 152 * retry for 10 times 153 */ 154 if (Constants.LOGVV) { 155 Log.v(TAG, "Create BluetoothServerSocket on channel " 156 + mBtOppRfcommChannel); 157 } 158 for (int i = 0; i < CREATE_RETRY_TIME && !mInterrupted; i++) { 159 try { 160 mServerSocket = 161 mAdapter.listenUsingInsecureRfcommOn(mBtOppRfcommChannel); 162 } catch (IOException e1) { 163 Log.d(TAG, "Error create RfcommServerSocket " + e1); 164 serverOK = false; 165 } 166 if (!serverOK) { 167 synchronized (this) { 168 try { 169 if (Constants.LOGVV) { 170 Log.v(TAG, "wait 3 seconds"); 171 } 172 Thread.sleep(3000); 173 } catch (InterruptedException e) { 174 Log.e(TAG, "socketAcceptThread thread was interrupted (3)"); 175 mInterrupted = true; 176 } 177 } 178 } else { 179 break; 180 } 181 } 182 if (!serverOK) { 183 Log.e(TAG, "Error start listening after " + CREATE_RETRY_TIME + " try"); 184 mInterrupted = true; 185 } 186 187 BluetoothSocket clientSocket; 188 while (!mInterrupted) { 189 try { 190 clientSocket = mServerSocket.accept(ACCEPT_WAIT_TIMEOUT); 191 if (Constants.LOGVV) { 192 Log.v(TAG, "BluetoothSocket connected!"); 193 Log.v(TAG, "remote device is " + clientSocket.getRemoteDevice()); 194 } 195 BluetoothOppRfcommTransport transport = new BluetoothOppRfcommTransport( 196 clientSocket); 197 Message msg = Message.obtain(); 198 msg.setTarget(mCallback); 199 msg.what = MSG_INCOMING_BTOPP_CONNECTION; 200 msg.obj = transport; 201 msg.sendToTarget(); 202 } catch (IOException e) { 203 //TODO later accept should not throw exception 204 if (Constants.LOGVV) { 205 //Log.v(TAG, "Error accept connection " + e); 206 } 207 } 208 } 209 try { 210 if (mServerSocket != null) { 211 if (Constants.LOGVV) { 212 Log.v(TAG, "close mServerSocket"); 213 } 214 mServerSocket.close(); 215 //TODO 216 //mServerSocket.destroy(); 217 } 218 } catch (IOException e) { 219 Log.e(TAG, "Errro close mServerSocket " + e); 220 } 221 if (Constants.LOGV) { 222 Log.v(TAG, "BluetoothSocket listen thread finished"); 223 } 224 } 225 } 226 }; 227 mInterrupted = false; 228 mSocketAcceptThread.start(); 229 } 230 return true; 231 } 232 233 public synchronized void stop() { 234 if (mSocketAcceptThread != null) { 235 if (Constants.LOGV) { 236 Log.v(TAG, "stopping Connect Thread"); 237 } 238 mInterrupted = true; 239 try { 240 mSocketAcceptThread.interrupt(); 241 if (Constants.LOGVV) { 242 Log.v(TAG, "waiting for thread to terminate"); 243 } 244 mSocketAcceptThread.join(); 245 mSocketAcceptThread = null; 246 mCallback = null; 247 } catch (InterruptedException e) { 248 if (Constants.LOGVV) { 249 Log.v(TAG, "Interrupted waiting for Accept Thread to join"); 250 } 251 } 252 } 253 } 254} 255