Skip to content

Instantly share code, notes, and snippets.

@aldoborrero
Created October 14, 2016 14:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aldoborrero/576cf4c80fcd0dfcca7f88850fb0250f to your computer and use it in GitHub Desktop.
Save aldoborrero/576cf4c80fcd0dfcca7f88850fb0250f to your computer and use it in GitHub Desktop.
This class is a helper for performing Bluetooth operations in a reactive way. Part of this code is extracted from library RxBluetooth created Addenie (https://github.com/adennie/RxBluetooth/blob/master/rxbluetooth/src/main/java/com/andydennie/rxbluetooth/RxBluetooth.java)
public class BluetoothCompat {
public static boolean createBondCompat(final BluetoothDevice device)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
return device.createBond();
} else {
Method method = device.getClass().getMethod("createBond", (Class[]) null);
final Object invoke = method.invoke(device, (Object[]) null);
return (Boolean) invoke;
}
}
public static boolean removeBondCompat(final BluetoothDevice device) throws NoSuchMethodException, InvocationTargetException,
IllegalAccessException {
Method method = device.getClass().getMethod("removeBond", (Class[]) null);
final Object invoke = method.invoke(device, (Object[]) null);
return (Boolean) invoke;
}
private BluetoothCompat() {
throw new AssertionError("No instances!");
}
}
public class RxBluetoothHelper {
private static final Observable.Transformer<Integer, BondStatus> BOND_STATUS_TRANSFORMER = statusObservable -> statusObservable.map(status -> {
switch (status) {
case BluetoothDevice.BOND_NONE:
default:
return BondStatus.NONE;
case BluetoothDevice.BOND_BONDING:
return BondStatus.BONDING;
case BluetoothDevice.BOND_BONDED:
return BondStatus.BONDED;
}
});
public enum BondStatus {
NONE,
BONDING,
BONDED
}
public static Observable<BondStatus> bondStatus(@NonNull final BluetoothDevice device) {
return Observable.defer(() -> Observable.just(device.getBondState()).compose(BOND_STATUS_TRANSFORMER));
}
public static Observable<BondStatus> bond(@NonNull final Context context, @NonNull final BluetoothDevice device) {
return Observable.create(subscriber -> {
bondStatus(device).subscribe(bondStatus -> {
switch (bondStatus) {
case NONE:
observeDeviceBonding(context, device).compose(BOND_STATUS_TRANSFORMER).subscribe(subscriber);
try {
// TODO: Listen for createBond result and emit a associated value
BluetoothCompat.createBondCompat(device);
} catch (Exception e) {
subscriber.onError(new BluetoothIncompatibleBondingException(e));
}
break;
case BONDING:
subscriber.onError(new BluetoothBondingException("device is already in the process of bonding"));
break;
case BONDED:
subscriber.onNext(BondStatus.BONDED);
subscriber.onCompleted();
break;
}
});
});
}
public static Observable<BondStatus> removeBond(@NonNull final Context context, @NonNull final BluetoothDevice device) {
return Observable.create(subscriber -> {
bondStatus(device).subscribe(bondStatus -> {
switch (bondStatus) {
case NONE:
subscriber.onNext(BondStatus.NONE);
subscriber.onCompleted();
break;
case BONDING:
subscriber.onError(new BluetoothBondingException("device is already in the process of unbonding"));
break;
case BONDED:
observeDeviceBonding(context, device).compose(BOND_STATUS_TRANSFORMER).subscribe(subscriber);
try {
BluetoothCompat.removeBondCompat(device);
} catch (Exception e) {
subscriber.onError(new BluetoothIncompatibleBondingException(e));
}
break;
}
});
});
}
private static Observable<Integer> observeDeviceBonding(@NonNull final Context context, @NonNull final BluetoothDevice device) {
return observeBroadcast(context, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)).filter(pair -> {
BluetoothDevice bondingDevice = pair.getValue1().getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
return bondingDevice.equals(device);
})
.map(pair1 -> pair1.getValue1().getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1))
.skipWhile(state -> state != BluetoothDevice.BOND_BONDING)
.takeUntil(state -> state == BluetoothDevice.BOND_BONDED || state == BluetoothDevice.BOND_NONE);
}
private static Observable<Pair<Context, Intent>> observeBroadcast(final Context context, final IntentFilter filter) {
return Observable.create(new Observable.OnSubscribe<Pair<Context, Intent>>() {
@Override public void call(Subscriber<? super Pair<Context, Intent>> subscriber) {
final BroadcastReceiver receiver = new BroadcastReceiver() {
@Override public void onReceive(Context context, Intent intent) {
subscriber.onNext(Pair.with(context, intent));
}
};
context.registerReceiver(receiver, filter);
subscriber.add(Subscriptions.create(() -> context.unregisterReceiver(receiver)));
}
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment