Related
I'm trying to get working a Service that hosts a server, and whenever it receives data from it's one client it sends the data off to another server. Both of which are connected by a tcp socket that remains open indefinitely. I'm having trouble implementing single tcp sockets that both read and write correctly.
I'm receiving XML from both ends, and they're well defined. Some processing is done on the xml received and it needs to be added to a queue that handles it's order.
Ideally the connection going in either direction should remain open indefinitely.
But so far I'm seeing the Sockets just keep closing both this Service and the ServerCode are getting closed sockets and I'm not sure why.
Is there a way to establish connections to my two endpoints and keep the sockets open indefinitely?
public class routing extends Service {
private static final String TAG = "[RoutingService]";
private final IBinder mBinder = new RoutingBinder();
private final ScheduledThreadPoolExecutor mRoutingThreadPool = new ScheduledThreadPoolExecutor(2);
private boolean running = false;
private URI serverAddress;
private URI clientAddress;
private Thread serverServiceThread = new ClientService();
private Thread clientServiceThread = new ServerService();
private PriorityBlockingQueue<String> clientQueue;
private PriorityBlockingQueue<String> serverQueue;
public void setClientAddress(URI testServer) {
this.serverAddress = testServer;
this.mRoutingThreadPool.remove(clientServiceThread);
this.mRoutingThreadPool.scheduleWithFixedDelay(clientServiceThread, 0, 100, TimeUnit.MILLISECONDS);
}
public URI getServerAddress() {
return serverAddress;
}
public void setServerAddress(URI testServer) {
startRunning();
this.serverAddress = testServer;
this.mRoutingThreadPool.remove(serverServiceThread);
this.mRoutingThreadPool.scheduleWithFixedDelay(serverServiceThread, 0, 100, TimeUnit.MILLISECONDS);
}
public void startRunning() {
running = true;
}
public void stopRunning() {
running = false;
}
#Override
public void onCreate() {
super.onCreate();
serverQueue = new PriorityBlockingQueue<>();
clientQueue = new PriorityBlockingQueue<>();
}
#Override
public void onDestroy() {
stopRunning();
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public int onStartCommand(#Nullable Intent intent, int flags, int startId) {
clientAddress = URI.create("127.0.0.1:8054");
serverAddress = URI.create("192.168.2.1:7087");
startRunning();
setClientAddress(clientAddress);
setServerAddress(serverAddress);
return Service.START_STICKY;
}
public class RoutingBinder extends Binder {
public routing getService() {
return routing.this;
}
}
class ClientService extends Thread {
private Socket socket;
private Runnable ClientReader = new Runnable() {
#Override
public void run() {
if (socket != null && socket.isConnected()) {
try (InputStreamReader sr = new InputStreamReader(socket.getInputStream())) {
StringBuilder xml = new StringBuilder();
char[] buffer = new char[8192];
String content = "";
int read;
while ((read = sr.read(buffer, 0, buffer.length)) != -1) {
serverQueue.add(new String(buffer));
}
} catch (IOException e) {
Log.e("clientReader", "Error in testReading Thread.", e);
}
}
}
};
private Runnable ClientWriter = new Runnable() {
#Override
public void run() {
if (socket != null && socket.isConnected()) {
while (serverQueue != null && !serverQueue.isEmpty()) {
try (OutputStream os = socket.getOutputStream()) {
String xml = serverQueue.poll();
os.write(xml.getBytes());
os.flush();
} catch (IOException e) {
Log.e("clientWriter", "Error in testReading Thread.", e);
}
}
}
}
};
#Override
public void run() {
try (ServerSocket server = new ServerSocket(clientAddress.getPort())) {
try (Socket socket = server.accept()) {
socket.setSoTimeout(0);
Log.d("SOCKET", String.format("Local Port: %s. Remote Port: %s", socket.getLocalPort(), socket.getPort()));
this.socket = socket;
//Make the Threads
Thread reader = new Thread(ClientReader);
Thread writer = new Thread(ClientWriter);
//Start the Threads
reader.start();
writer.start();
//Start the Server
startRunning();
//Join on the Threads so this driver thread will wait until they finish.
reader.join();
writer.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
stopRunning();
}
}
class ServerService extends Thread {
private Socket socket;
private Runnable ServerReader = new Runnable() {
#Override
public void run() {
if (socket != null && !socket.isClosed()) {
try (InputStreamReader sr = new InputStreamReader(socket.getInputStream())) {
StringBuilder xml = new StringBuilder();
char[] buffer = new char[8192];
String content = "";
int read;
while ((read = sr.read(buffer, 0, buffer.length)) != -1) {
clientQueue.add(new String(buffer));
}
} catch (IOException e) {
Log.e("ServerReader", "Error in testReading Thread.", e);
}
}
}
};
private Runnable ServerWriter = new Runnable() {
#Override
public void run() {
if (socket != null && socket.isConnected()) {
try (OutputStream os = socket.getOutputStream()) {
while (clientQueue != null && !clientQueue.isEmpty()) {
String xml = clientQueue.poll();
os.write(xml.getBytes());
os.flush();
}
} catch (IOException e) {
Log.e("ServerWriter", "Error in testReading Thread.", e);
}
}
}
};
#Override
public void run() {
if (running) { //Service will keep spinning unti the testService ends the loop
try (Socket socket = new Socket(serverAddress.getHost(), serverAddress.getPort())) {
socket.setSoTimeout(0);
Log.d("SOCKET", String.format("Local test Port: %s. Remote test Port: %s", socket.getLocalPort(), socket.getPort()));
this.socket = socket;
//Make the Threads
final Thread writer = new Thread(ServerWriter);
final Thread reader = new Thread(ServerReader);
//Start the Threads
writer.start();
reader.start();
//Join on the Threads so this driver thread will wait until they finish.
writer.join();
reader.join();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Closing the input or output stream of a socket closes the other stream and the socket.
I'm trying to connect my device to another one via Bluetooth, but when I select the device I want to connect with, I get an IOException saying
read failed, socket might closed or timeout, read ret: -1
Just to illustrate how my app works, I have a RecyclerView populated with the devices my Bluetooth scan has found, then when I click an item the app is supposed to connect with that device.
Below is my the code for my connection thread:
private val MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb")
private lateinit var device: BluetoothDevice
private lateinit var onDeviceActionListener: OnDeviceActionListener
private lateinit var socket: BluetoothSocket
fun init(device: BluetoothDevice,
onDeviceActionListener: OnDeviceActionListener): ConnectionThread {
this.device = device
this.onDeviceActionListener = onDeviceActionListener
try {
socket = device.createRfcommSocketToServiceRecord(MY_UUID)
} catch (e: IOException) {
Log.e(TAG, "Error creating socket", e)
}
return this
}
override fun run() {
try {
socket.connect()
} catch (openException: IOException) {
Log.e(TAG, "Error opening connection. Trying to close...", openException)
try {
socket.close()
} catch (closeException: IOException) {
Log.e(TAG, "Error closing socket", closeException)
}
return
}
onDeviceActionListener.onDeviceConnect(device)
}
My guess is there is something wrong with my UUID. I've tried some other values but still didn't work.
Any help will be much appreciated.
Well, I don't see exactly what you are doing wrong here. However, I have done quite a bit of Bluetooth work. More recently just focused in BLE. You should be able to discover your nearby BT devices and see their UUIDs.
I have written a helper class about 3 years ago so it's a little old, but should be mostly the same code. Happy to share it with you if it helps.
public class BluetoothConnector {
private static final String TAG = Globals.SEARCH_STRING + BluetoothConnector.class.getSimpleName();
private static final String DEFAULT_SERVER_NAME_FOR_APP = "tn_bt_default_server";
private static final int DEFAULT_DISCOVERABLE_DURATION_MS = 30000;
private static final UUID DEFAULT_UUID = UUID.fromString("6534c201-039c-4e4f-89f9-5ca8cfeb9667");
public static final int ENABLE_DISCOVER_INTENT = 1002;
protected boolean mIsToastEnabled = false; //Access from calling class to enable toasting of progress to screen if necessary
private Handler mUIHandler;
private static ServerSocketThread mServerSocketThread;
private static ClientSocketThread mClientSocketThread;
private ManageConnectionThread mManageConnectionThread;
private Context mContext;
private IBluetoothDataListener mBluetoothDataListener;
public final Object ServerSocketLock = new Object();
public final Object ClientSocketLock = new Object();
public final Object ManageConnectionLock = new Object();
public BluetoothConnector(Context context, IBluetoothDataListener listener){
this(context, new Handler(Looper.getMainLooper()), listener);
}
public BluetoothConnector(Context context, Handler UIHandler, IBluetoothDataListener listener){
Log.v(TAG, "BluetoothConnector(context=" + context + ", Handler=" + UIHandler.getClass().getSimpleName() + ", IBluetoothDataListener=" + listener.getClass().getSimpleName());
mContext = context;
mUIHandler = UIHandler;
mBluetoothDataListener = listener;
}
public void makeThisDeviceDiscoverable(Activity callingActivity){
makeThisDeviceDiscoverable(callingActivity, BluetoothAdapter.getDefaultAdapter(), DEFAULT_DISCOVERABLE_DURATION_MS);
}
public void makeThisDeviceDiscoverable(Activity callingActivity, BluetoothAdapter adapter){
makeThisDeviceDiscoverable(callingActivity, adapter, DEFAULT_DISCOVERABLE_DURATION_MS);
}
public void makeThisDeviceDiscoverable(Activity callingActivity, int durationInMs){
makeThisDeviceDiscoverable(callingActivity, BluetoothAdapter.getDefaultAdapter(), durationInMs);
}
public void makeThisDeviceDiscoverable(Activity callingActivity, BluetoothAdapter adapter, int durationInMs) {
Log.v(TAG, "makeThisDeviceDiscoverable(callingActivity=" + callingActivity.getClass().getSimpleName() + ", BluetoothAdapter=" + (adapter == null ? "null" : adapter.getName()) + ", duration=" + String.valueOf(durationInMs));
if(adapter == null){
Log.v(TAG, "adapter is null");
}else if(adapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Log.v(TAG, "Launching Activity to request Discoverable Permission");
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, durationInMs);
callingActivity.startActivityForResult(discoverableIntent, ENABLE_DISCOVER_INTENT);
}else{
Log.v(TAG, "adapter is already in SCAN MODE");
}
}
public void awaitConnectionFromDevice(){
awaitConnectionFromDevice(DEFAULT_UUID, BluetoothAdapter.getDefaultAdapter());
}
public void awaitConnectionFromDevice(UUID commonKey){
awaitConnectionFromDevice(commonKey, BluetoothAdapter.getDefaultAdapter());
}
public void awaitConnectionFromDevice(BluetoothAdapter adapter){
awaitConnectionFromDevice(DEFAULT_UUID, adapter);
}
public void awaitConnectionFromDevice(UUID commonKey, BluetoothAdapter adapter){
Log.v(TAG, "awaitConnectionFromDevice for UUID: " + String.valueOf(commonKey) + ", BluetoothAdapter=" + (adapter == null ? "null" : adapter.getName()));
cancelDiscovery();
synchronized (ServerSocketLock){
if(mServerSocketThread != null){
Log.v(TAG, "Server Socket Thread was not null so canceling current Thread");
mServerSocketThread.cancel();
}
Log.v(TAG, "Attempting to Start new ServerThread");
mServerSocketThread = new ServerSocketThread(commonKey, adapter);
mServerSocketThread.start();
}
}
public void cancelAwaitingConnectionFromDevice(){
Log.v(TAG, "cancelAwaitingConnectionFromDevice");
synchronized (ServerSocketLock){
if(mServerSocketThread != null){
mServerSocketThread.cancel();
mServerSocketThread = null;
Log.v(TAG, "canceling Server Socket Thread");
}else{
Log.v(TAG, "Server Socket null, so not canceling");
}
}
}
public void startDiscovery() {
startDiscovery(BluetoothAdapter.getDefaultAdapter());
}
public void startDiscovery(BluetoothAdapter adapter){
Log.v(TAG, "startDiscovery to find list of devices in range");
adapter.startDiscovery();
}
public void cancelDiscovery() {
cancelDiscovery(BluetoothAdapter.getDefaultAdapter());
}
public void cancelDiscovery(BluetoothAdapter adapter){
Log.v(TAG, "cancelDiscovery");
adapter.cancelDiscovery();
}
public void connectToDevice(BluetoothDevice device){
connectToDevice(device, DEFAULT_UUID);
}
public void connectToDevice(BluetoothDevice device, UUID commonKey){
Log.v(TAG, "connectToDevice(BluetoothDevice=" + (device == null ? "null" : device.getName()) + ", UUID=" + String.valueOf(commonKey));
synchronized (ClientSocketLock){
if(mClientSocketThread != null){
Log.v(TAG, "Client Socket Thread was not null so canceling current Thread");
mClientSocketThread.cancel();
}else{
Log.v(TAG, "Client Socket Thread is NULL so not canceling");
}
Log.v(TAG, "ClientSocketThread Starting");
mClientSocketThread = new ClientSocketThread(device, commonKey);
mClientSocketThread.start();
}
}
public BluetoothDevice getBluetoothDeviceByMac(String mac){
Log.v(TAG, "getBluetoothDeviceByMac(mac=" + mac);
return getBluetoothDeviceByMac(mac, BluetoothAdapter.getDefaultAdapter());
}
public BluetoothDevice getBluetoothDeviceByMac(String mac, BluetoothAdapter adapter) {
Log.v(TAG, "getBluetoothDeviceByMac(mac=" + mac + ", BluetoothAdapter=" + (adapter == null ? "null" : adapter.getName()));
return adapter.getRemoteDevice(mac);
}
public ArrayList<KeyValueModel> getPairedDevices(){
return getPairedDevices(BluetoothAdapter.getDefaultAdapter());
}
public ArrayList<KeyValueModel> getPairedDevices(BluetoothAdapter adapter){
ArrayList<KeyValueModel> bondedDevices = new ArrayList<KeyValueModel>();
Set<BluetoothDevice> pairedDevices = adapter.getBondedDevices();
Log.v(TAG, "getPairedDevices Found " + pairedDevices.size() + " number of paired devices");
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice device : pairedDevices) {
// Add the name and address to an array adapter to show in a ListView
bondedDevices.add(new KeyValueModel(device.getAddress(), device.getName()));
}
}
return bondedDevices;
}
public static void unpairDevice(BluetoothDevice device){
Log.v(TAG, "unpairDevice");
try{
Method method = device.getClass().getMethod("removeBond", (Class[]) null);
method.invoke(device, (Object[]) null);
}catch (Exception ex){
Log.e(TAG, "Error Unpairing Device: " + ex.getMessage());
}
}
public boolean sendDataToConnectedDevice(byte[] data){
Log.v(TAG, "sendDataToConnectedDevice");
synchronized (ManageConnectionLock){
mManageConnectionThread.write(data);
return true;
}
}
public void setBluetoothDataListener(IBluetoothDataListener listener){
mBluetoothDataListener = listener;
}
public boolean getIsConnected(){
synchronized (ManageConnectionLock) {
return mManageConnectionThread != null && mManageConnectionThread.isAlive();
}
}
private void startManageConnectionThread(BluetoothSocket socket){
Log.v(TAG, "startManageConnectionThread for Socket: " + (socket == null ? "null" : socket.getClass().getSimpleName()));
synchronized (ManageConnectionLock) {
mManageConnectionThread = new ManageConnectionThread(socket);
mManageConnectionThread.start();
}
}
private void handleDataReceivedFromConnectedDevice(final byte[] bytes){
Log.v(TAG, "handleDataReceivedFromConnectedDevice");
Log.v(TAG, "bytes to Listener: " + new String(bytes));
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if (mBluetoothDataListener != null) {
mBluetoothDataListener.onReceivedPayloadFromConnectedDevice(bytes);
}
}
});
}else{
Log.v(TAG, "UIHandler was null so skipped sending payload to listener");
}
}
private void handleConnected(){
Log.e(TAG, "handleConnected");
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if(mBluetoothDataListener != null){
mBluetoothDataListener.onConnectedToTargetDevice();
}
}
});
}else{
Log.v(TAG, "UIHandler was null so skipped sending payload to listener");
}
}
private void handleDisconnected(){
Log.e(TAG, "handleDisconnected");
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if(mBluetoothDataListener != null){
mBluetoothDataListener.onDisconnectedFromTargetDevice();
}
}
});
}else{
Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener");
}
}
private void handleFailedToConnectAsServer(final Exception ex){
Log.e(TAG, "handleFailedToConnectAsServer ex: " + ex.getMessage());
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if(mBluetoothDataListener != null){
mBluetoothDataListener.onFailedToReceiveConnectionFromTargetDevice(ex);
}
}
});
}else{
Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener");
}
}
private void handleFailedToConnectAsClient(final Exception ex){
Log.e(TAG, "handleFailedToConnectAsClient ex: " + ex.getMessage());
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if(mBluetoothDataListener != null){
mBluetoothDataListener.onFailedToConnectToTargetDevice(ex);
}
}
});
}else{
Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener");
}
}
private void handleErrorInRetrievingData(final Exception ex){
Log.e(TAG, "handleErrorInRetrievingData ex: " + ex.getMessage());
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if(mBluetoothDataListener != null){
mBluetoothDataListener.onErrorReceivingPayloadFromConnectedDevice(ex);
}
}
});
}else{
Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener");
}
}
private void handleFailedToSendDataToConnectedDevice(final Exception ex){
Log.e(TAG, "handleFailedToSendDataToConnectedDevice ex: " + ex.getMessage());
if(mUIHandler != null && mBluetoothDataListener != null){
mUIHandler.post(new Runnable() {
#Override
public void run() {
if(mBluetoothDataListener != null){
mBluetoothDataListener.onFailedToSendDataToConnectedDevice(ex);
}
}
});
}else{
Log.v(TAG, "UIHandler or Listener was null so skipped sending payload to listener");
}
}
private void toastMessage(final String value){
if(!mIsToastEnabled || mUIHandler == null) {
return;
}
mUIHandler.post(new Runnable() {
#Override
public void run() {
try{
Toast.makeText(mContext, value, Toast.LENGTH_SHORT).show();
}catch(Exception ex){
Log.v(TAG, "Error Toasting, possibly bad handler, or context: " + ex.getMessage());
}
}
});
}
private class ServerSocketThread extends Thread{
private final String TAG = Globals.SEARCH_STRING + ServerSocketThread.class.getSimpleName();
private final BluetoothServerSocket mServerSocket;
public ServerSocketThread(UUID commonKey, BluetoothAdapter adapter) {
Log.v(TAG, "ServerSocketThread Constructor");
BluetoothServerSocket tmp = null;
try {
Log.v(TAG, "listening for RFComas Server: " + DEFAULT_SERVER_NAME_FOR_APP + ", and commonKey: " + String.valueOf(commonKey));
// MY_UUID is the app's UUID string, also used by the client code
tmp = adapter.listenUsingRfcommWithServiceRecord(DEFAULT_SERVER_NAME_FOR_APP, commonKey);
toastMessage("Listening for RFComm As Server on UUID: " + String.valueOf(commonKey));
} catch (IOException e) {
Log.e(TAG, "Error creating ServerSocket: " + e.getMessage());
toastMessage("Error Creating ServerSocket: " + e.getMessage());
}
mServerSocket = tmp;
}
public void run() {
Log.v(TAG, "ServerSocket run");
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (mServerSocket != null) {
try {
Log.v(TAG, "ServerSocket.accept()");
toastMessage("ServerSocket.accept()");
//Waits for Client Connection to pass Socket, then we close down
socket = mServerSocket.accept();
} catch (IOException e) {
Log.e(TAG, "ServerSocket.accept() Error: " + e.getMessage());
toastMessage("ServerSocket.accept() Error: " + e.getMessage());
handleFailedToConnectAsServer(e);
break;
}
// If a connection was accepted we don't need to keep server listening, so close unless multiple client/server connections is desired
if (socket != null) {
try{
Log.v(TAG, "ServerSocket Accepted Client Socket, Begin Listening Connect Thread");
toastMessage("ServerSocket Accepted Client Socket, Begin Listening Connect Thread");
// Do work to manage the connection (in a separate thread)
startManageConnectionThread(socket);
//mServerSocket.close();
}catch(Exception ex){
Log.e(TAG, "Exception closing Server Socket");
}
//break; //Add in Break if you want to shut down listening for connections
}else{
Log.v(TAG, "Socket wasn't accepted");
toastMessage("Socket wasn't accepted");
handleFailedToConnectAsServer(new Exception("Socket is Null"));
}
}
Log.v(TAG, "Exiting Server Accept Thread");
}
public void cancel() {
try {
Log.v(TAG, "ServerSocketThread Canceled");
mServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "ServerSocketThread Error: " + e.getMessage());
}
}
}
private class ClientSocketThread extends Thread{
private BluetoothSocket mSocket;
private final BluetoothDevice mDevice;
public ClientSocketThread(BluetoothDevice device, UUID commonKey) {
Log.v(TAG, "ClientSocketThread Constructor");
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
Log.v(TAG, "Client creating RFComm Socket to Server with UUID: " + String.valueOf(commonKey));
toastMessage("Client creating RFComm Socket to Server with UUID: " + String.valueOf(commonKey));
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(commonKey);
} catch (IOException e) {
Log.e(TAG, "Error creating Client Socket: " + e.getMessage());
toastMessage("Creating Socket Exception: " + e.getMessage());
handleFailedToConnectAsClient(e);
}
mSocket = tmp;
}
public void run() {
try {
if(mSocket == null){
Log.e(TAG, "Error Client Socket is Null, Canceling Client Thread");
return;
}
Log.v(TAG, "Client Connecting");
// Connect to the server, or timeout eventually
toastMessage("Client Connecting");
mSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and try the fallback method of reflection with port to connect
try {
Log.e("", "trying fallback...");
toastMessage("Client Connection Failed Exception: " + connectException.getMessage());
mSocket = (BluetoothSocket) mDevice.getClass().getMethod("createRfcommSocket", new Class[]{int.class}).invoke(mDevice, 1);
toastMessage("Client Connect Again Attempt 2, but with fall back Reflection and port");
Log.v(TAG, "Client Connect Again Attempt 2, but with fall back Reflection and port");
mSocket.connect();
Log.e("", "Connected");
toastMessage("Client Connected");
} catch (Exception ex) {
Log.e("", "Couldn't establish Bluetooth connection!");
toastMessage("Client Couldn't Establish Connection to Server: " + ex.getMessage());
handleFailedToConnectAsClient(ex);
return;
}
}
// Do work to manage the connection (in a separate thread)
startManageConnectionThread(mSocket);
}
public void cancel() {
try {
Log.v(TAG, "Client Socket cancel");
mSocket.close();
} catch (IOException e) {
Log.e(TAG, "Error Closing Socket");
}
}
}
private class ManageConnectionThread extends Thread {
/////////////
// MEMBERS //
/////////////
private final String TAG = Globals.SEARCH_STRING + ManageConnectionThread.class.getSimpleName();
private final BluetoothSocket mSocket;
private final InputStream mInStream;
private final OutputStream mOutStream;
//////////////////
// CONSTRUCTOR //
//////////////////
public ManageConnectionThread(BluetoothSocket socket) {
mSocket = socket;
handleConnected();
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
try {
Log.v(TAG, "ManageConnectionThread Constructor");
Log.v(TAG, "Connected to Socket = " + String.valueOf(socket.isConnected()));
toastMessage("Listening for input or output Stream");
Log.v(TAG, "Get InputStream");
tmpIn = socket.getInputStream();
Log.v(TAG, "Get OutputStream");
tmpOut = socket.getOutputStream();
} catch (IOException e) {
Log.e(TAG, "Error getting Socket Streams: " + e.getMessage());
toastMessage("Connect Thread: Error: " + e.getMessage());
handleErrorInRetrievingData(e);
}
mInStream = tmpIn;
mOutStream = tmpOut;
}
///////////////
// OVERRIDES //
///////////////
public void run() {
// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
byte[] data = new byte[16384];
int nRead;
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
while ((nRead = mInStream.read(data, 0, data.length)) != -1) {
//Log.v(TAG, "bytes Read: " + String.valueOf(nRead));
buffer.write(data, 0, nRead);
//TODO Find better way to find End Of Message rather than looking for }
String temp = new String(buffer.toByteArray());
//Log.v(TAG, "current Data: " + temp);
if(temp.contains("}")){
Log.v(TAG, "bytes reading complete");
handleDataReceivedFromConnectedDevice(buffer.toByteArray());
buffer.flush();
buffer = new ByteArrayOutputStream();
}else{
Log.v(TAG, "More bytes Available");
}
}
} catch (IOException e) {
Log.e(TAG, "Error reading inputStream");
handleErrorInRetrievingData(e);
break;
}
}
Log.v(TAG, "Exiting Managed Connection Thread");
handleDisconnected();
}
/////////////
// METHODS //
/////////////
public void write(byte[] bytes) {
try {
Log.v(TAG, "ManageConnectionThread write(bytes)");
mOutStream.write(bytes);
} catch (IOException e) {
Log.e(TAG, "Error Writing Stream: " + e.getMessage());
handleFailedToSendDataToConnectedDevice(e);
}
}
public void cancel() {
try {
Log.v(TAG, "ManageConnectionThread cancel");
handleDisconnected();
mSocket.close();
} catch (IOException e) {
Log.e(TAG, "Error Closing BluetoothSocket: " + e.getMessage());
}
}
}
public interface IBluetoothDataListener{
//////////////////////
// OVERRIDE METHODS //
//////////////////////
void onReceivedPayloadFromConnectedDevice(byte[] payload);
void onErrorReceivingPayloadFromConnectedDevice(Exception ex);
void onFailedToConnectToTargetDevice(Exception ex);
void onFailedToReceiveConnectionFromTargetDevice(Exception ex);
void onFailedToSendDataToConnectedDevice(Exception ex);
void onConnectedToTargetDevice();
void onDisconnectedFromTargetDevice();
}
}
Then of course you will want to make sure you have your broadcast receivers setup:
<receiver
android:name=".receivers.BluetoothChangedReceiver"
android:enabled="true" >
<intent-filter>
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
<action android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
<action android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
<action android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" />
<action android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
<action android:name="android.bluetooth.device.action.FOUND" />
<action android:name="android.bluetooth.device.action.DISAPPEARED" />
</intent-filter>
</receiver>
<receiver
android:name=".receivers.BluetoothDeviceReceiver"
android:enabled="true" >
<intent-filter>
<action android:name="android.bluetooth.device.action.FOUND" />
<action android:name="android.bluetooth.device.action.DISAPPEARED" />
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
<action android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
<action android:name="android.bluetooth.device.action.ACTION_ACL_DISCONNECT_REQUESTED" />
<action android:name="android.bluetooth.device.action.BOND_STATE_CHANGED" />
<action android:name="android.bluetooth.device.action.UUID" />
</intent-filter>
</receiver>
I'm trying to get two android phones to connect via bluetooth. I'm following the instructions here from the android online howto's, and I'm following pretty closely.
http://developer.android.com/guide/topics/connectivity/bluetooth.html
I can get bluetooth to connect once, but I have to restart the android device or the app itself in order to get it to connect a second time. This is not a problem during development because with each edit of the code the android studio program re-loads the app. It starts it and restarts it, so that during testing I can connect over and over. During actual use I have to restart the android phone or go to the applications manager option under settings and physically stop that app.
From the code below I can connect if I call these lines:
generateDefaultAdapter();
startDiscovery();
startThreadAccept();
startThreadConnect();
How do I get it so that the bluetooth connection can be initiated over and over again? I see the message 'unable to connect' from the inner class 'ConnectThread' and an IO error from a 'printStackTrace()' from that part of the code. The second time I try, I seem to be able to call the method 'stopConnection()' and then the lines above (starting with 'generateDefaultAdapter()') but I find I cannot connect.
package org.test;
//some import statements here...
public class Bluetooth {
public boolean mDebug = true;
public BluetoothAdapter mBluetoothAdapter;
public UUID mUUID = UUID.fromString(BLUETOOTH_UUID);
public Thread mAcceptThread;
public Thread mConnectThread;
public ConnectedThread mManageConnectionAccept;
public ConnectedThread mManageConnectionConnect;
public APDuellingBluetooth() {
}
public void generateDefaultAdapter() {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
}
if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled() ) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
(mDialogDuel.getActivity()).startActivityForResult(enableBtIntent, INTENT_ACTIVITY_BLUETOOTH_REQUEST_ENABLE);
}
}
public void cancelDiscovery() { if (mBluetoothAdapter != null) mBluetoothAdapter.cancelDiscovery();}
public void startDiscovery() { mBluetoothAdapter.startDiscovery();}
public BluetoothAdapter getBluetoothAdapter() {return mBluetoothAdapter;}
public void stopConnection () {
try {
if (mAcceptThread != null) {
mAcceptThread.interrupt();
//mAcceptThread.join();
mAcceptThread = null;
}
if (mConnectThread != null) {
mConnectThread.interrupt();
//mConnectThread.join();
mConnectThread = null;
}
if (mManageConnectionConnect != null) {
mManageConnectionConnect.cancel();
mManageConnectionConnect.interrupt();
mManageConnectionConnect = null;
}
if (mManageConnectionAccept != null) {
mManageConnectionAccept.cancel();
mManageConnectionAccept.interrupt();
mManageConnectionAccept = null;
}
}
catch(Exception e) {
e.printStackTrace();
}
}
public void startThreadAccept () {
if (mAcceptThread != null && !mAcceptThread.isInterrupted()) {
if (mDebug) System.out.println("server already open");
//return;
mAcceptThread.interrupt();
mAcceptThread = new AcceptThread();
}
else {
mAcceptThread = new AcceptThread();
}
if (mAcceptThread.getState() == Thread.State.NEW ){
//mAcceptThread.getState() == Thread.State.RUNNABLE) {
mAcceptThread.start();
}
}
public void startThreadConnect () {
BluetoothDevice mDevice = mBluetoothAdapter.getRemoteDevice(mChosen.getAddress());
//if (mDebug) System.out.println(mDevice.getAddress() + " -- " + mChosen.getAddress() );
if (mConnectThread != null && !mConnectThread.isInterrupted()) {
if (mDebug) System.out.println("client already open");
//return;
mConnectThread.interrupt();
mConnectThread = new ConnectThread(mDevice);
}
else {
mConnectThread = new ConnectThread(mDevice);
}
if (mConnectThread.getState() == Thread.State.NEW){// ||
//mConnectThread.getState() == Thread.State.RUNNABLE) {
mConnectThread.start();
}
}
public void manageConnectedSocketAccept(BluetoothSocket socket) {
String mTemp = mBluetoothAdapter.getName();
if (mDebug) {
System.out.println("socket accept from " + mTemp);
System.out.println("info accept " + socket.getRemoteDevice().toString());
}
if (mManageConnectionAccept != null && !mManageConnectionAccept.isInterrupted()) {
//mManageConnectionAccept.cancel();
//mManageConnectionAccept.interrupt();
if (mAcceptThread == null) System.out.println(" bad thread accept");
}
else {
mManageConnectionAccept = new ConnectedThread(socket, "accept");
}
if (mManageConnectionAccept.getState() == Thread.State.NEW ){//||
//mManageConnectionAccept.getState() == Thread.State.RUNNABLE) {
mManageConnectionAccept.start();
}
}
public void manageConnectedSocketConnect(BluetoothSocket socket) {
String mTemp = mBluetoothAdapter.getName();
if (mDebug) {
System.out.println("socket connect from " + mTemp);
System.out.println("info connect " + socket.getRemoteDevice().toString());
}
if (mManageConnectionConnect != null && !mManageConnectionConnect.isInterrupted()) {
//mManageConnectionConnect.cancel();
//mManageConnectionConnect.interrupt();
if (mConnectThread == null) System.out.print(" bad thread connect ");
}
else {
mManageConnectionConnect = new ConnectedThread(socket, "connect");
}
if (mManageConnectionConnect.getState() == Thread.State.NEW){// ||
//mManageConnectionConnect.getState() == Thread.State.RUNNABLE) {
mManageConnectionConnect.start();
}
}
public void decodeInput (String mIn, ConnectedThread mSource) {
// do something with info that is returned to me...
}
public void encodeOutput (String mMac1, String mMac2, int mLR1, int mLR2) {
String mTemp = composeOutputString ( mServer, mMac1,mMac2, mLR1, mLR2);
if (mManageConnectionConnect != null && mManageConnectionConnect.isConnected()) {
mManageConnectionConnect.write(mTemp.getBytes());
mManageConnectionConnect.flush();
}
if (mManageConnectionAccept != null && mManageConnectionAccept.isConnected()) {
mManageConnectionAccept.write(mTemp.getBytes());
mManageConnectionAccept.flush();
}
mTemp = composeOutputString ( mClient, mMac1,mMac2, mLR1, mLR2);
if (mManageConnectionConnect != null && mManageConnectionConnect.isConnected()) {
mManageConnectionConnect.write(mTemp.getBytes());
mManageConnectionConnect.flush();
}
if (mManageConnectionAccept != null && mManageConnectionAccept.isConnected()) {
mManageConnectionAccept.write(mTemp.getBytes());
mManageConnectionAccept.flush();
}
}
public String composeOutputString (SocketConnectData mData, String mMac1, String mMac2, int mLR1, int mLR2) {
// make a string here with the data I want to send...
String mTemp = new String();
return mTemp;
}
/////////////////////////////////////////////
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
private boolean mLoop = true;
public AcceptThread() {
// Use a temporary object that is later assigned to mmServerSocket,
// because mmServerSocket is final
mLoop = true;
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(mServiceNameReceive, mUUID );
} catch (IOException e) {
System.out.println("rfcomm problem ");
}
mmServerSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (mLoop) {
try {
if (mmServerSocket != null) {
socket = mmServerSocket.accept();
}
} catch (IOException e) {
if (mDebug) System.out.println("rfcomm accept problem");
e.printStackTrace();
break;
}
// If a connection was accepted
if (socket != null && ! isConnectionOpen() ) {
// Do work to manage the connection (in a separate thread)
manageConnectedSocketAccept(socket);
try {
mmServerSocket.close();
}
catch (IOException e) {}
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
mLoop = false;
mmServerSocket.close();
} catch (IOException e) { }
}
}
/////////////////////////////////////////////
private class ConnectThread extends Thread {
//private final BluetoothSocket mmSocket;
private BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
try {
tmp = device.createRfcommSocketToServiceRecord(mUUID);
if (mDebug) System.out.println("connect -- rf socket to service record " + tmp);
} catch (Exception e) {
System.out.println("exception -- rf socket to service record problem " + tmp);
}
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
}
//catch (InterruptedException e ) {System.out.println("interrupted exception");}
catch (IOException e) {
// Unable to connect; close the socket and get out
if (mDebug) System.out.println("unable to connect ");
e.printStackTrace(); // <---- I see output from this spot!!
try {
mmSocket.close();
} catch (IOException closeException) {
System.out.println("unable to close connection ");
}
return;
}
// Do work to manage the connection (in a separate thread)
if (mmSocket.isConnected() && ! isConnectionOpen()) {
manageConnectedSocketConnect(mmSocket);
}
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
public boolean isConnected() {
return mmSocket.isConnected();
}
}
/////////////////////////////////////////////
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public String mTypeName = "";
private boolean mLoop = true;
public StringWriter writer;
public ConnectedThread(BluetoothSocket socket, String type) {
mTypeName = type;
mLoop = true;
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
try {
writer = new StringWriter();
}
catch (Exception e) {}
}
public void run() {
byte[] buffer = new byte[1024]; //
int bytes; // bytes returned from read()
String [] mLines ;
// Keep listening to the InputStream until an exception occurs
while (mLoop) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
if (bytes == -1 || bytes == 0) {
if (mDebug) System.out.println("zero read");
return;
}
writer.append(new String(buffer, 0, bytes));
mLines = writer.toString().split("!");
if (mDebug) System.out.println( "lines " +mLines.length);
for (int i = 0; i < mLines.length; i ++ ) {
if (true) {
if (mDebug) System.out.println(" " + mLines[i]);
decodeInput (mLines[i], this);
}
}
} catch (Exception e) {
e.printStackTrace();
if (mDebug) System.out.println("read buffer problem");
break;
}
}
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) {
e.printStackTrace();
if (mDebug) System.out.println("bad write");
}
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mLoop = false;
mmSocket.close();
mmOutStream.close();
mmInStream.close();
} catch (IOException e) { }
}
public boolean isConnected() {
boolean mIsOpen = false;
try {
mIsOpen = mmSocket.isConnected() ;
} catch (Exception e) {}
return mIsOpen;
}
public void flush() {
try {
mmOutStream.flush();
}
catch (IOException e) {e.printStackTrace();}
}
}
///////////////////////////////////////////////
}
Thanks for your time.
EDIT: this is the error msg:
W/System.err﹕ java.io.IOException: read failed, socket might closed or timeout, read ret: -1
W/System.err﹕ at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:553)
W/System.err﹕ at android.bluetooth.BluetoothSocket.waitSocketSignal(BluetoothSocket.java:530)
W/System.err﹕ at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:357)
W/System.err﹕ at org.davidliebman.test.Bluetooth$ConnectThread.run(Bluetooth.java:761)
Try this:
Instead of restarting the app. Turn off the Bluetooth on the Android device and turn it back on after a 5-sec delay. If you could make the connection successfully, it typically a sign that you did not close the connection and socket completely. Log your code. Make sure the closing socket routine is smoothly executed. Check if the IOException you have in your cancel method of your ConnectedThread is not catching any exception:
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
// ADD LOG
mLoop = false;
mmSocket.close();
mmOutStream.close();
mmInStream.close();
// ADD LOG
} catch (IOException e) {
// ADD LOG}
}
I am developing a UDP chat app. All network processing is inside thread in a service. I am still getting this error message for 3.1 and 4.0 oeprating system. For versions 2.3 and below it is working fine. Question: should I create two apps, one for version 2.3 and below and another one for version 3.0 and higher? The error happens when the write(byte[] out) method is called according to LogCat.
If I disable StrictMode for ICS the app is working fine.
public class ChatService extends Service {
private Binder binder;
private ComThread comThread;
public IBinder onBind(Intent intent) {
return binder;
}
public void onCreate() {
}
public int onStartCommand(Intent intent, int flags, int startId) {
binder = new ChatServiceBinder();
start();
return super.onStartCommand(intent, flags, startId);
}
public synchronized void start() {
comThread = new ComThread();
comThread.start();
}
public void onDestroy() {
stop();
}
public void write(byte[] out) {
comThread.write(out);
}
public synchronized void stop() {
if (comThread != null) {
comThread.cancel();
comThread = null;
}
}
private class ComThread extends Thread {
private static final int BCAST_PORT = 2562;
DatagramSocket mSocket;
InetAddress myBcastIP, myLocalIP;
public ComThread() {
try {
myBcastIP = getBroadcastAddress();
if (D)
Log.d(TAG, "my bcast ip : " + myBcastIP);
myLocalIP = getLocalAddress();
if (D)
Log.d(TAG, "my local ip : " + myLocalIP);
mSocket = new DatagramSocket(BCAST_PORT);
mSocket.setBroadcast(true);
} catch (IOException e) {
Log.e(TAG, "Could not make socket", e);
}
}
public void run() {
try {
byte[] buf = new byte[1024];
if (D)
Log.d(TAG, "run(), com thread startet");
// Listen on socket to receive messages
while (true) {
DatagramPacket packet = new DatagramPacket(buf, buf.length);
mSocket.receive(packet);
InetAddress remoteIP = packet.getAddress();
if (remoteIP.equals(myLocalIP))
continue;
String s = new String(packet.getData(), 0,
packet.getLength());
if (D)
Log.d(TAG, "run(), " + s);
Message msg = new Message();
msg.obj = s;
msg.arg1 = MessageHandler.MSG_IN;
state.getHandler().sendMessage(msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Write broadcast packet.
*/
public void write(byte[] buffer) {
try {
String data = new String(buffer);
DatagramPacket packet = new DatagramPacket(data.getBytes(),
data.length(), myBcastIP, BCAST_PORT);
mSocket.send(packet);
} catch (Exception e) {
Log.e(TAG, "write(), Exception during write", e);
}
}
/**
* Calculate the broadcast IP we need to send the packet along.
*/
private InetAddress getBroadcastAddress() throws IOException {
WifiManager mWifi = (WifiManager) state
.getSystemService(Context.WIFI_SERVICE);
WifiInfo info = mWifi.getConnectionInfo();
if (D)
Log.d(TAG, "\nWiFi Status: " + info.toString());
// DhcpInfo is a simple object for retrieving the results of a DHCP
// request
DhcpInfo dhcp = mWifi.getDhcpInfo();
if (dhcp == null) {
Log.d(TAG, "Could not get dhcp info");
return null;
}
int broadcast = (dhcp.ipAddress & dhcp.netmask) | ~dhcp.netmask;
byte[] quads = new byte[4];
for (int k = 0; k < 4; k++)
quads[k] = (byte) ((broadcast >> k * 8) & 0xFF);
// Returns the InetAddress corresponding to the array of bytes.
return InetAddress.getByAddress(quads); // The high order byte is
// quads[0].
}
private InetAddress getLocalAddress() throws IOException {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface
.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf
.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress()) {
return inetAddress;
}
}
}
} catch (SocketException ex) {
Log.e(TAG, ex.toString());
}
return null;
}
public void cancel() {
try {
mSocket.close();
} catch (Exception e) {
Log.e(TAG, "close() of connect socket failed", e);
}
}
}
public class ChatServiceBinder extends Binder {
private ChatService service = ChatService.this;
public ChatService getService() {
return service;
}
}
}
}
Thanks.
A little late, and not a super great answer, but on Android 3+ Runnable won't be interpreted as permitted unless it's inside the service (not a sub-class as you have it). I know its a limiting check given the freedom you have to create pretty much anything you want however you want, but then again UDP multicasting isn't something all Android developers mess with. Hope this helps.
I'm pretty new to Android. Right now I'm trying to make a two-player Pong game using the Bluetooth API. I've more or less tried to copy the BluetoothChat tutorial on the Android website, but I still get an error where the socket immediately disconnects after I switch over to the ConnectedThread. Would anyone have any idea why this is?
I have each of the three types of threads as a private class on a screen of a menu. ConnectThread is split into reading and writing, and is placed inside the screen of the game.
public abstract class FindScreen extends EngineView {
private GUIFactory guiFact;
private TextButton backButton;
private ScrollingList buttonList;
public ConnectThread connectThread;
private BluetoothAdapter adapter;
public FindScreen(Context c, AndroidView aView) {
super(c, aView, 1);
adapter = BluetoothAdapter.getDefaultAdapter();
guiFact = new GUIFactory(new Vector2d(EngineConstants.CENTER_X,
EngineConstants.CENTER_Y), 8, 8, EngineConstants.VIRTUAL_W,
EngineConstants.VIRTUAL_H, EngineConstants.VIRTUAL_W / 32);
GUITask backTask = new GUITask() {
public void execute() {
goBack();
}
};
backButton = guiFact.newGradientTextButton(1, 6, 7, 7, backTask, "Back");
this.add(backButton, 0);
buttonList = guiFact.newScrollingList(1,1,7,6);
this.add(buttonList, 0);
}
#Override
public boolean onTouchEvent(MotionEvent e) {
backButton.executeIfContained(e.getX(), e.getY());
buttonList.executeIfContained(e.getX(), e.getY());
return true;
}
public void onIn() {
// Register for broadcasts when a device is discovered
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
context.registerReceiver(receiver, filter);
// Register for broadcasts when discovery has finished
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
context.registerReceiver(receiver, filter);
buttonList.clearButtons();
if(!adapter.startDiscovery()) { // if discovery doesn't start successfully, leave the screen
goBack();
}
}
public void onOut() {
if (adapter.isDiscovering()) {
adapter.cancelDiscovery();
}
context.unregisterReceiver(receiver);
if (connectThread != null) {
connectThread.cancel();
}
}
/**
* Return to the previous screen, the menu screen
*/
public abstract void goBack();
/**
* Do something after we've connected
* #param socket
*/
public abstract void connected(BluetoothSocket socket);
/**
* Broadcast receiver;
* Listens for discovered devices
* When discovery is finished, changes the list of discovered devices
* When discoverability is changed, changes text
*/
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
buttonList.addButton(device.getName(), new ConnectTask(device.getAddress()));
// }
// doDiscovery();
}
}
};
private class ConnectTask extends GUITask {
private String address;
public ConnectTask(String addr) {
address = addr;
}
#Override
public void execute() {
BluetoothDevice device = adapter.getRemoteDevice(address);
if (connectThread != null) {
connectThread.cancel();
}
connectThread = new ConnectThread(device);
connectThread.start();
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket socket;
private final BluetoothDevice device;
public ConnectThread(BluetoothDevice dev) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
device = dev;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(EngineConstants.MY_UUID);
} catch (IOException e) { }
socket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
if (adapter.isDiscovering()) {
adapter.cancelDiscovery();
}
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
socket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
socket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
connected(socket);
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
socket.close();
} catch (IOException e) { }
}
}
public abstract class HostScreen extends EngineView {
private GUIFactory guiFact;
private TextButton backButton;
private TextLabel waitText;
private BluetoothAdapter adapter;
public AcceptThread acceptThread;
private static final int DISCOVERY_LENGTH = 300;
public HostScreen(Context c, AndroidView aView) {
super(c, aView, 1);
adapter = BluetoothAdapter.getDefaultAdapter();
guiFact = new GUIFactory(new Vector2d(EngineConstants.CENTER_X,
EngineConstants.CENTER_Y), 8, 8, EngineConstants.VIRTUAL_W,
EngineConstants.VIRTUAL_H, EngineConstants.VIRTUAL_W / 32);
GUITask backTask = new GUITask() {
public void execute() {
goBack();
}
};
backButton = guiFact.newGradientTextButton(1, 6, 7, 7, backTask, "Back");
this.add(backButton, 0);
waitText = guiFact.newLabel(2, 3, 6, 4, Color.WHITE, "...");
this.add(waitText, 0);
}
public void onIn() {
if (adapter.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, DISCOVERY_LENGTH);
((Activity) context).startActivityForResult(discoverableIntent, EngineConstants.REQUEST_DISCOVERABLE);
}
if (!adapter.isEnabled()) {
Intent enableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
context.startActivity(enableIntent);
}
}
public void onOut() {
if (acceptThread != null) {
acceptThread.cancel();
}
}
public void discoverableAccepted() {
if (acceptThread != null) {
acceptThread.cancel();
}
acceptThread = new AcceptThread();
acceptThread.start();
}
public void discoverableDeclined() {
goBack();
}
/**
* Do something after we've connected
* #param socket
*/
public abstract void connected(BluetoothSocket socket);
#Override
public boolean onTouchEvent(MotionEvent e) {
backButton.executeIfContained(e.getX(), e.getY());
return true;
}
/**
* Return to the previous screen, the menu screen
*/
public abstract void goBack();
private class AcceptThread extends Thread {
private final BluetoothServerSocket serverSocket;
public AcceptThread() {
// Use a temporary object that is later assigned to mmServerSocket,
// because mmServerSocket is final
BluetoothServerSocket tmp = null;
try {
// MY_UUID is the app's UUID string, also used by the client code
tmp = adapter.listenUsingRfcommWithServiceRecord(EngineConstants.NAME, EngineConstants.MY_UUID);
} catch (IOException e) { }
serverSocket = tmp;
}
public void run() {
BluetoothSocket socket = null;
// Keep listening until exception occurs or a socket is returned
while (true) {
try {
socket = serverSocket.accept();
} catch (IOException e) {
break;
}
// If a connection was accepted
if (socket != null) {
// Do work to manage the connection (in a separate thread)
connected(socket);
try {
serverSocket.close();
} catch (IOException e) {
android.util.Log.d("Accept thread", "Could not close serverSocket");
}
break;
}
}
}
/** Will cancel the listening socket, and cause the thread to finish */
public void cancel() {
try {
serverSocket.close();
} catch (IOException e) { }
}
}
}
public class GameScreen extends EngineView {
public ConnectedThread connectedThread;
public ConnectedWriteThread writeThread;
private PacketHandler handler;
private final static int N_LAYERS = 4;
// layer 0 = walls
// layer 1 = puck
// layer 2 = paddles
// layer 3 = GUI
public Paddle enemyPaddle, playerPaddle;
public Puck puck;
private GUIFactory guiFact;
private TextLabel playerLabel, enemyLabel;
public int playerScore = 0, enemyScore = 0;
private boolean isHeld;
private float startX, startTouchX, moveToX;
private final static float MIN_X = Paddle.RADIUS, MAX_X = EngineConstants.VIRTUAL_W - MIN_X;
public float myPaddlePrevPosX;
public boolean enemyScoreChanged = false;
private final static long PACKET_RATE = 200;
private long packetTime = 0;
public GameScreen(Context c, final AndroidView aView) {
super(c, aView, N_LAYERS);
enemyPaddle = new Paddle(new Vector2d(EngineConstants.CENTER_X, EngineConstants.VIRTUAL_H/8f), 255, 255, 100, 100);
playerPaddle = new Paddle(new Vector2d(EngineConstants.CENTER_X, EngineConstants.VIRTUAL_H*7f/8f), 255, 100, 255, 100);
puck = new Puck();
this.add(enemyPaddle, 2);
this.add(playerPaddle, 2);
this.add(puck, 1);
guiFact = new GUIFactory(new Vector2d(EngineConstants.CENTER_X, EngineConstants.CENTER_Y), 8, 10, EngineConstants.VIRTUAL_W, EngineConstants.VIRTUAL_H, 0);
playerLabel = guiFact.newLabel(2, 4, 3, 5, Color.rgb(100, 150, 100), "0");
enemyLabel = guiFact.newLabel(7, 3, 8, 4, Color.rgb(150, 100, 100), "0");
this.add(playerLabel, 3);
this.add(enemyLabel, 3);
this.constraints.add(new BoxConstraint(puck, false, false, 0 + Puck.RADIUS));
this.constraints.add(new BoxConstraint(puck, false, true, EngineConstants.VIRTUAL_W - Puck.RADIUS));
myPaddlePrevPosX = playerPaddle.pos.x;
}
public void onOut() {
if (connectedThread != null) {
connectedThread.cancel();
}
if (writeThread != null) {
writeThread.cancel();
}
}
public void update(long interval) {
super.update(interval);
EngineFunctions.collide(playerPaddle, puck);
EngineFunctions.collide(enemyPaddle, puck);
if (puck.pos.y < 0) {
score(true);
} else if (puck.pos.y > EngineConstants.VIRTUAL_H) {
score(false);
}
packetTime += interval;
if (packetTime > PACKET_RATE) {
// android.util.Log.d("fillQueue", "called");
packetTime = 0;
writeThread.fillQueue();
}
}
private void score(boolean isPlayer) {
if (isPlayer) {
playerScore++;
playerLabel.setText(String.valueOf(playerScore));
} else {
enemyScore++;
enemyLabel.setText(String.valueOf(enemyScore));
enemyScoreChanged = true;
}
puck.pos.x = EngineConstants.CENTER_X;
puck.pos.y = EngineConstants.CENTER_Y;
puck.prevPos.x = EngineConstants.CENTER_X;
puck.prevPos.y = EngineConstants.CENTER_Y;
}
#Override
public boolean onTouchEvent(MotionEvent e) {
switch(e.getAction()) {
case MotionEvent.ACTION_DOWN:
if (playerPaddle.touching(e.getX(), e.getY())) {
isHeld = true;
startX = playerPaddle.pos.x;
startTouchX = e.getX();
}
break;
case MotionEvent.ACTION_MOVE:
if (isHeld) {
myPaddlePrevPosX = playerPaddle.pos.x;
moveToX = startX + (e.getX() - startTouchX);
if (moveToX < MIN_X) {
moveToX = MIN_X;
} else if (moveToX > MAX_X) {
moveToX = MAX_X;
}
playerPaddle.pos.x = moveToX;
playerPaddle.prevPos.x = moveToX;
}
break;
case MotionEvent.ACTION_UP:
isHeld = false;
break;
}
return true;
}
public void startNewConnectedThread(BluetoothSocket soc, boolean isServer) {
if (connectedThread != null) {
connectedThread.cancel();
}
connectedThread = new ConnectedThread(soc, handler);
connectedThread.start();
if (writeThread != null) {
writeThread.cancel();
}
writeThread = new ConnectedWriteThread(soc, handler, isServer);
writeThread.start();
}
public void setHandler(PacketHandler h) {
handler = h;
}
public class ConnectedThread extends Thread {
private final BluetoothSocket socket;
private final InputStream inStream;
private final BufferedReader in;
private PacketHandler handler;
public ConnectedThread(BluetoothSocket soc, PacketHandler pHandler) {
socket = soc;
handler = pHandler;
InputStream tmpIn = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
} catch (IOException e) {
}
inStream = tmpIn;
in = new BufferedReader(new InputStreamReader(inStream));
}
public void run() {
/*
// Keep listening to the InputStream until an exception occurs
android.util.Log.d("connectedThread", "started");
String str;
try {
inStream.read();
inStream.read();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
android.util.Log.d("connectedThread", "normal read is fine");
while (true) {
try {
// Read from the InputStream
str = in.readLine();
byte type = Byte.valueOf(str);
android.util.Log.d("connectedThread", "read");
handler.handlePacket(in, type);
} catch (IOException e) {
break;
}
}*/
for (int i = 0; i < 20; i++) {
try {
String str = in.readLine();
android.util.Log.d("read", str + " ");
} catch (IOException e) {
// TODO Auto-generated catch block
android.util.Log.d("io exception", e.getMessage() + " " + e.getLocalizedMessage() + " " + e.getCause());
}
}
while (true) {
}
}
/* Call this from the main Activity to shutdown the connection */
public void cancel() {
try {
socket.close();
} catch (IOException e) { }
}
}
public class ConnectedWriteThread extends Thread {
public ConcurrentLinkedQueue<String> que;
private final BluetoothSocket socket;
private final OutputStream outStream;
private final BufferedWriter out;
private PacketHandler handler;
private boolean isServ;
public ConnectedWriteThread(BluetoothSocket soc, PacketHandler pHandler, boolean isServer) {
socket = soc;
handler = pHandler;
isServ = isServer;
OutputStream tmpOut = null;
que = new ConcurrentLinkedQueue<String>();
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
outStream = tmpOut;
out = new BufferedWriter(new OutputStreamWriter(outStream));
}
public void run() {
// Keep listening to the InputStream until an exception occurs
android.util.Log.d("connectedThread", "started");
/*
try {
if (isServ) {
out.write(String.valueOf(EngineConstants.PACKET_SYNC) + '\n');
out.write(String.valueOf(0) + '\n');
}
} catch (IOException e1) {
android.util.Log.d("connectedThread", "io exception " + e1.getMessage() + " " + e1.getLocalizedMessage() + " " + e1.getCause());
}
//android.util.Log.d("connectedThread", "sent initial packet");
while (true) {
if (!que.isEmpty()) {
try {
out.write(que.poll());
out.flush();
// android.util.Log.d("connectedThread", "sent packet");
} catch (IOException e) {
android.util.Log.d("write thread", "io exception " + e.getMessage());
}
}
}*/
try {
outStream.write(3);
out.write("343567\n");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while (true) {
}
}
public void fillQueue() {
// android.util.Log.d("fillQueue", "in method");
handler.queuePacket(que);
}
/* Call this from the main Activity to send data to the remote device */
public void write(String str) {
try {
out.write(str);
} catch (IOException e) { }
}
/* Call this from the main Activity to shutdown the connection */
public void cancel() {
try {
socket.close();
} catch (IOException e) { }
}
}
Try to use reflection:
try {
BluetoothDevice mDevice = mBluetoothAdapter.getRemoteDevice("MAC of remote device");
Method m = mDevice.getClass().getMethod("createRfcommSocket",
new Class[] { int.class });
mSocket = (BluetoothSocket) m.invoke(mDevice, Integer.valueOf(1));
mSocket.connect();
} catch (NoSuchMethodException e) {
} catch (SecurityException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
} catch (Exception e) {}
And after some time in your thread
mInStream = mSocket.getInputStream();
mOutStream = mSocket.getOutputStream();
mInStream is InputStream() and mOutStream is OutputStream().
I came across this problem when used bluetooth connection on HTC device.