package com.polidea.rxandroidble.internal.operations;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.os.DeadObjectException;
import com.polidea.rxandroidble.exceptions.BleException;
import com.polidea.rxandroidble.exceptions.BleScanException;
import com.polidea.rxandroidble.internal.RxBleInternalScanResult;
import com.polidea.rxandroidble.internal.RxBleLog;
import com.polidea.rxandroidble.internal.RxBleRadioOperation;
import com.polidea.rxandroidble.internal.util.RxBleAdapterWrapper;
import com.polidea.rxandroidble.internal.util.UUIDUtil;
import java.util.Collections;
import java.util.HashSet;
import java.util.UUID;
public class RxBleRadioOperationScan extends RxBleRadioOperation<RxBleInternalScanResult> {
private final RxBleAdapterWrapper rxBleAdapterWrapper;
private volatile boolean isStarted = false;
private volatile boolean isStopped = false;
private final BluetoothAdapter.LeScanCallback leScanCallback;
public RxBleRadioOperationScan(UUID[] filterServiceUUIDs, RxBleAdapterWrapper rxBleAdapterWrapper, final UUIDUtil uuidUtil) {
this.rxBleAdapterWrapper = rxBleAdapterWrapper;
final boolean isFilterDefined = filterServiceUUIDs != null && filterServiceUUIDs.length > 0;
final HashSet<UUID> filterUuids;
if (isFilterDefined) {
filterUuids = new HashSet<>(filterServiceUUIDs.length);
Collections.addAll(filterUuids, filterServiceUUIDs);
} else {
filterUuids = null;
}
this.leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
if (!isFilterDefined || uuidUtil.extractUUIDs(scanRecord).containsAll(filterUuids)) {
RxBleRadioOperationScan.this.onNext(new RxBleInternalScanResult(device, rssi, scanRecord));
}
}
};
}
@Override
protected void protectedRun() {
try {
boolean startLeScanStatus = rxBleAdapterWrapper.startLeScan(leScanCallback);
if (!startLeScanStatus) {
onError(new BleScanException(BleScanException.BLUETOOTH_CANNOT_START));
} else {
synchronized (this) { // synchronization added for stopping the scan
isStarted = true;
if (isStopped) {
stop();
}
}
}
} catch (Throwable throwable) {
isStarted = true;
RxBleLog.e(throwable, "Error while calling BluetoothAdapter.startLeScan()");
onError(new BleScanException(BleScanException.BLUETOOTH_CANNOT_START));
} finally {
releaseRadio();
}
}
// synchronized keyword added to be sure that operation will be stopped no matter which thread will call it
public synchronized void stop() {
isStopped = true;
if (isStarted) {
// TODO: [PU] 29.01.2016 https://code.google.com/p/android/issues/detail?id=160503
rxBleAdapterWrapper.stopLeScan(leScanCallback);
}
}
@Override
protected BleException provideException(DeadObjectException deadObjectException) {
return new BleScanException(BleScanException.BLUETOOTH_DISABLED, deadObjectException);
}
}