IOException: read failed, socket might closed - Bluetooth on Android 4.3
I have finally found a workaround. The magic is hidden under the hood of the BluetoothDevice
class (see https://github.com/android/platform_frameworks_base/blob/android-4.3_r2/core/java/android/bluetooth/BluetoothDevice.java#L1037).
Now, when I receive that exception, I instantiate a fallback BluetoothSocket
, similar to the source code below. As you can see, invoking the hidden method createRfcommSocket
via reflections. I have no clue why this method is hidden. The source code defines it as public
though...
Class<?> clazz = tmp.getRemoteDevice().getClass();
Class<?>[] paramTypes = new Class<?>[] {Integer.TYPE};
Method m = clazz.getMethod("createRfcommSocket", paramTypes);
Object[] params = new Object[] {Integer.valueOf(1)};
fallbackSocket = (BluetoothSocket) m.invoke(tmp.getRemoteDevice(), params);
fallbackSocket.connect();
connect()
then does not fail any longer. I have experienced a few issues still. Basically, this sometimes blocks and fails. Rebooting the SPP-Device (plug off / plug in) helps in such cases. Sometimes I also get another Pairing request after connect()
even when the device is already bonded.
UPDATE:
here is a complete class, containing some nested classes. for a real implementation these could be held as seperate classes.
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.List;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;
public class BluetoothConnector {
private BluetoothSocketWrapper bluetoothSocket;
private BluetoothDevice device;
private boolean secure;
private BluetoothAdapter adapter;
private List<UUID> uuidCandidates;
private int candidate;
/**
* @param device the device
* @param secure if connection should be done via a secure socket
* @param adapter the Android BT adapter
* @param uuidCandidates a list of UUIDs. if null or empty, the Serial PP id is used
*/
public BluetoothConnector(BluetoothDevice device, boolean secure, BluetoothAdapter adapter,
List<UUID> uuidCandidates) {
this.device = device;
this.secure = secure;
this.adapter = adapter;
this.uuidCandidates = uuidCandidates;
if (this.uuidCandidates == null || this.uuidCandidates.isEmpty()) {
this.uuidCandidates = new ArrayList<UUID>();
this.uuidCandidates.add(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
}
}
public BluetoothSocketWrapper connect() throws IOException {
boolean success = false;
while (selectSocket()) {
adapter.cancelDiscovery();
try {
bluetoothSocket.connect();
success = true;
break;
} catch (IOException e) {
//try the fallback
try {
bluetoothSocket = new FallbackBluetoothSocket(bluetoothSocket.getUnderlyingSocket());
Thread.sleep(500);
bluetoothSocket.connect();
success = true;
break;
} catch (FallbackException e1) {
Log.w("BT", "Could not initialize FallbackBluetoothSocket classes.", e);
} catch (InterruptedException e1) {
Log.w("BT", e1.getMessage(), e1);
} catch (IOException e1) {
Log.w("BT", "Fallback failed. Cancelling.", e1);
}
}
}
if (!success) {
throw new IOException("Could not connect to device: "+ device.getAddress());
}
return bluetoothSocket;
}
private boolean selectSocket() throws IOException {
if (candidate >= uuidCandidates.size()) {
return false;
}
BluetoothSocket tmp;
UUID uuid = uuidCandidates.get(candidate++);
Log.i("BT", "Attempting to connect to Protocol: "+ uuid);
if (secure) {
tmp = device.createRfcommSocketToServiceRecord(uuid);
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(uuid);
}
bluetoothSocket = new NativeBluetoothSocket(tmp);
return true;
}
public static interface BluetoothSocketWrapper {
InputStream getInputStream() throws IOException;
OutputStream getOutputStream() throws IOException;
String getRemoteDeviceName();
void connect() throws IOException;
String getRemoteDeviceAddress();
void close() throws IOException;
BluetoothSocket getUnderlyingSocket();
}
public static class NativeBluetoothSocket implements BluetoothSocketWrapper {
private BluetoothSocket socket;
public NativeBluetoothSocket(BluetoothSocket tmp) {
this.socket = tmp;
}
@Override
public InputStream getInputStream() throws IOException {
return socket.getInputStream();
}
@Override
public OutputStream getOutputStream() throws IOException {
return socket.getOutputStream();
}
@Override
public String getRemoteDeviceName() {
return socket.getRemoteDevice().getName();
}
@Override
public void connect() throws IOException {
socket.connect();
}
@Override
public String getRemoteDeviceAddress() {
return socket.getRemoteDevice().getAddress();
}
@Override
public void close() throws IOException {
socket.close();
}
@Override
public BluetoothSocket getUnderlyingSocket() {
return socket;
}
}
public class FallbackBluetoothSocket extends NativeBluetoothSocket {
private BluetoothSocket fallbackSocket;
public FallbackBluetoothSocket(BluetoothSocket tmp) throws FallbackException {
super(tmp);
try
{
Class<?> clazz = tmp.getRemoteDevice().getClass();
Class<?>[] paramTypes = new Class<?>[] {Integer.TYPE};
Method m = clazz.getMethod("createRfcommSocket", paramTypes);
Object[] params = new Object[] {Integer.valueOf(1)};
fallbackSocket = (BluetoothSocket) m.invoke(tmp.getRemoteDevice(), params);
}
catch (Exception e)
{
throw new FallbackException(e);
}
}
@Override
public InputStream getInputStream() throws IOException {
return fallbackSocket.getInputStream();
}
@Override
public OutputStream getOutputStream() throws IOException {
return fallbackSocket.getOutputStream();
}
@Override
public void connect() throws IOException {
fallbackSocket.connect();
}
@Override
public void close() throws IOException {
fallbackSocket.close();
}
}
public static class FallbackException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
public FallbackException(Exception e) {
super(e);
}
}
}
Buetooth connection failed: read failed, socket might closed or timeout, read ret: -1
Try to use ,
createInsecureRfcommSocketToServiceRecord(MY_UUID)
in place of
createRfcommSocketToServiceRecord(MY_UUID)
This should fix the problem. Share your debugging results , if this doesn't fix the issue.
Also , don't generate random UUID(s), try the one below.
UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
Bluetooth connect failed. java.io.IOException: read failed, socket might closed or timeout, read ret: -1
In my situation,the bluetooth settings that comes with the system works.
So, I look the source code of the bluetooth settings.
And Copy the libframeworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth
into my project.
Use reflect to invoke the hide Class and function or variable.
Finally, it works.
I wish this could help.
AGAIN: read failed, socket might closed or timeout
I found my answer in another Question!. this link:
Android Connect Bluetooth device automatically after pairing programmatically
In Question discripe how connect(and it's answer complete it)
Note: before Test sure devices are Unpair
Android bluetooth connection throwing read failed, socket might closed or timeout, read ret android
I found the answer in the following question:-
IOException: read failed, socket might closed - Bluetooth on Android 4.3
Actually I had to use reflection only on the fall back, ie, inside the catch when the connect fails.
Related Topics
Get/Pick an Image from Android'S Built-In Gallery App Programmatically
How to Check a Certain Data Already Exists in Firestore or Not
J2Me/Android/Blackberry - Driving Directions, Route Between Two Locations
Handler VS Asynctask VS Thread
How to Listen For a Webview Finishing Loading a Url
How to Send Device to Device Notification by Using Fcm Without Using Xmpp or Any Other Script.
Getviewtypecount and Getitemviewtype Methods of Arrayadapter
How to Update Recyclerview Adapter Data
How to Resize a Bitmap in Android
Dexindexoverflowexception Only When Running Tests
Getting Exception "Illegalstateexception: Can Not Perform This Action After Onsaveinstancestate"
How to Pause/Sleep Thread or Process in Android
How to Create Custom Ratings Bar in Android
"Debug Certificate Expired" Error in Eclipse Android Plugins