diff --git a/rxbluetooth/src/main/java/com/github/ivbaranov/rxbluetooth/RxBluetooth.java b/rxbluetooth/src/main/java/com/github/ivbaranov/rxbluetooth/RxBluetooth.java index 241f4bf..543695c 100644 --- a/rxbluetooth/src/main/java/com/github/ivbaranov/rxbluetooth/RxBluetooth.java +++ b/rxbluetooth/src/main/java/com/github/ivbaranov/rxbluetooth/RxBluetooth.java @@ -53,6 +53,7 @@ import static android.location.LocationManager.GPS_PROVIDER; import static android.location.LocationManager.NETWORK_PROVIDER; import static android.os.Build.VERSION.SDK_INT; +import static com.github.ivbaranov.rxbluetooth.Utils.createRfcommSocket; /** * Enables clients to listen to bluetooth events using RxJava Observables. @@ -479,7 +480,7 @@ public Observable observeBondState() { /** * Create connection to {@link BluetoothDevice} and returns a connected {@link BluetoothSocket} - * on successful connection. Notifies observers with {@link IOException} {@code onError()}. + * on successful connection. Notifies observers with {@link IOException} via {@code onError()}. * * @param bluetoothDevice bluetooth device to connect * @param uuid uuid for SDP record @@ -520,7 +521,7 @@ public Single connectAsServer(final String name, final UUID uui /** * Create connection to {@link BluetoothDevice} and returns a connected {@link BluetoothSocket} - * on successful connection. Notifies observers with {@link IOException} {@code onError()}. + * on successful connection. Notifies observers with {@link IOException} via {@code onError()}. * * @param bluetoothDevice bluetooth device to connect * @param uuid uuid for SDP record @@ -536,7 +537,42 @@ public Single connectAsClient(final BluetoothDevice bluetoothDe bluetoothSocket.connect(); emitter.onSuccess(bluetoothSocket); } catch (IOException e) { - if(bluetoothSocket != null) { + if (bluetoothSocket != null) { + try { + bluetoothSocket.close(); + } catch (IOException suppressed) { + if (SDK_INT >= 19) { + e.addSuppressed(suppressed); + } + } + } + emitter.onError(e); + } + } + }); + } + + /** + * Create connection to {@link BluetoothDevice} via createRfcommSocket and returns a connected {@link BluetoothSocket} + * on successful connection. + * Note: createRfcommSocket is not public API and hence this might break in the future. + * Notifies observers with {@link IOException} or any reflection related exception via {@code onError()}. + * + * @param bluetoothDevice bluetooth device to connect + * @param channel RFCOMM channel to connect to + * @return Single with connected {@link BluetoothSocket} on successful connection + */ + public Single connectAsClient(final BluetoothDevice bluetoothDevice, + final int channel) { + return Single.create(new SingleOnSubscribe() { + @Override public void subscribe(@NonNull SingleEmitter emitter) { + BluetoothSocket bluetoothSocket = null; + try { + bluetoothSocket = createRfcommSocket(bluetoothDevice, channel); + bluetoothSocket.connect(); + emitter.onSuccess(bluetoothSocket); + } catch (IOException e) { + if (bluetoothSocket != null) { try { bluetoothSocket.close(); } catch (IOException suppressed) { diff --git a/rxbluetooth/src/main/java/com/github/ivbaranov/rxbluetooth/Utils.java b/rxbluetooth/src/main/java/com/github/ivbaranov/rxbluetooth/Utils.java index 513f201..8c7b2d4 100644 --- a/rxbluetooth/src/main/java/com/github/ivbaranov/rxbluetooth/Utils.java +++ b/rxbluetooth/src/main/java/com/github/ivbaranov/rxbluetooth/Utils.java @@ -1,10 +1,14 @@ package com.github.ivbaranov.rxbluetooth; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSocket; import java.io.Closeable; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; final class Utils { - static void close(Closeable closeable) { + static void close(final Closeable closeable) { if (closeable != null) { try { closeable.close(); @@ -14,6 +18,20 @@ static void close(Closeable closeable) { } } + @SuppressWarnings("unchecked") static BluetoothSocket createRfcommSocket( + final BluetoothDevice device, final int channel) { + try { + Method method = BluetoothDevice.class.getMethod("createRfcommSocket", Integer.TYPE); + return (BluetoothSocket) method.invoke(device, channel); + } catch (final NoSuchMethodException e) { + throw new UnsupportedOperationException(e); + } catch (final InvocationTargetException e) { + throw new UnsupportedOperationException(e); + } catch (final IllegalAccessException e) { + throw new UnsupportedOperationException(e); + } + } + private Utils() { throw new AssertionError("No instances."); }