Actuellement, j'essaie de faire face à une exception étrange lors de l'ouverture d'un BluetoothSocket sur ma Nexus 7 (2012), avec Android 4.3 (Build JWR66Y, je suppose la deuxième mise à jour 4.3). J'ai vu quelques messages connexes (par ex. https://stackoverflow.com/questions/13648373/bluetoothsocket-connect-throwing-exception-read-failed ), mais aucun ne semble fournir une solution de contournement pour ce problème. De plus, comme suggéré dans ces fils de discussion, le réappairage n'aide pas, et le fait d'essayer constamment de se connecter (par une boucle stupide) n'a également aucun effet.
J'ai affaire à un dispositif intégré (un adaptateur de voiture OBD-II non nominatif, similaire à l'adaptateur de voiture OBD-II). http://images04.olx.com/ui/15/53/76/1316534072_254254776_2-OBD-II-BLUTOOTH-ADAPTERSCLEAR-CHECK-ENGINE-LIGHTS-WITH-YOUR-PHONE-Oceanside.jpg ). Mon téléphone Android 2.3.7 n'a aucun problème de connexion, et le Xperia d'un collègue (Android 4.1.2) fonctionne également. Un autre Google Nexus (je ne sais pas si c'est un 'One' ou un 'S', mais pas un '4') ne fonctionne pas non plus avec Android 4.3.
Voici un extrait de l'établissement de la connexion. Il s'exécute dans son propre Thread, créé au sein d'un Service.
private class ConnectThread extends Thread {
private static final UUID EMBEDDED_BOARD_SPP = UUID
.fromString("00001101-0000-1000-8000-00805F9B34FB");
private BluetoothAdapter adapter;
private boolean secure;
private BluetoothDevice device;
private List<UUID> uuidCandidates;
private int candidate;
protected boolean started;
public ConnectThread(BluetoothDevice device, boolean secure) {
logger.info("initiliasing connection to device "+device.getName() +" / "+ device.getAddress());
adapter = BluetoothAdapter.getDefaultAdapter();
this.secure = secure;
this.device = device;
setName("BluetoothConnectThread");
if (!startQueryingForUUIDs()) {
this.uuidCandidates = Collections.singletonList(EMBEDDED_BOARD_SPP);
this.start();
} else{
logger.info("Using UUID discovery mechanism.");
}
/*
* it will start upon the broadcast receive otherwise
*/
}
private boolean startQueryingForUUIDs() {
Class<?> cl = BluetoothDevice.class;
Class<?>[] par = {};
Method fetchUuidsWithSdpMethod;
try {
fetchUuidsWithSdpMethod = cl.getMethod("fetchUuidsWithSdp", par);
} catch (NoSuchMethodException e) {
logger.warn(e.getMessage());
return false;
}
Object[] args = {};
try {
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice deviceExtra = intent.getParcelableExtra("android.bluetooth.device.extra.DEVICE");
Parcelable[] uuidExtra = intent.getParcelableArrayExtra("android.bluetooth.device.extra.UUID");
uuidCandidates = new ArrayList<UUID>();
for (Parcelable uuid : uuidExtra) {
uuidCandidates.add(UUID.fromString(uuid.toString()));
}
synchronized (ConnectThread.this) {
if (!ConnectThread.this.started) {
ConnectThread.this.start();
ConnectThread.this.started = true;
unregisterReceiver(this);
}
}
}
};
registerReceiver(receiver, new IntentFilter("android.bleutooth.device.action.UUID"));
registerReceiver(receiver, new IntentFilter("android.bluetooth.device.action.UUID"));
fetchUuidsWithSdpMethod.invoke(device, args);
} catch (IllegalArgumentException e) {
logger.warn(e.getMessage());
return false;
} catch (IllegalAccessException e) {
logger.warn(e.getMessage());
return false;
} catch (InvocationTargetException e) {
logger.warn(e.getMessage());
return false;
}
return true;
}
public void run() {
boolean success = false;
while (selectSocket()) {
if (bluetoothSocket == null) {
logger.warn("Socket is null! Cancelling!");
deviceDisconnected();
openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION);
}
// Always cancel discovery because it will slow down a connection
adapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
bluetoothSocket.connect();
success = true;
break;
} catch (IOException e) {
// Close the socket
try {
shutdownSocket();
} catch (IOException e2) {
logger.warn(e2.getMessage(), e2);
}
}
}
if (success) {
deviceConnected();
} else {
deviceDisconnected();
openTroubleshootingActivity(TroubleshootingActivity.BLUETOOTH_EXCEPTION);
}
}
private boolean selectSocket() {
if (candidate >= uuidCandidates.size()) {
return false;
}
BluetoothSocket tmp;
UUID uuid = uuidCandidates.get(candidate++);
logger.info("Attempting to connect to SDP "+ uuid);
try {
if (secure) {
tmp = device.createRfcommSocketToServiceRecord(
uuid);
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(
uuid);
}
bluetoothSocket = tmp;
return true;
} catch (IOException e) {
logger.warn(e.getMessage() ,e);
}
return false;
}
}
Le code échoue à bluetoothSocket.connect()
. Je reçois un java.io.IOException: read failed, socket might closed, read ret: -1
. Voici la source correspondante sur GitHub : https://github.com/Android/platform_frameworks_base/blob/Android-4.3_r2/core/java/Android/bluetooth/BluetoothSocket.java#L504 Il est appelé par readInt(), appelé à partir de https://github.com/Android/platform_frameworks_base/blob/Android-4.3_r2/core/java/Android/bluetooth/BluetoothSocket.java#L319
Un vidage des métadonnées de la socket utilisée a donné les informations suivantes. Ce sont exactement les mêmes sur la Nexus 7 et mon téléphone 2.3.7.
Bluetooth Device 'OBDII'
Address: 11:22:33:DD:EE:FF
Bond state: 12 (bonded)
Type: 1
Class major version: 7936
Class minor version: 7936
Class Contents: 0
Contents: 0
Je possède d'autres adaptateurs OBD-II (plus étendus) et ils fonctionnent tous. Y a-t-il une chance que je rate quelque chose ou s'agit-il d'un bug dans Android ?