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