下面列出了io.reactivex.functions.Cancellable#com.polidea.rxandroidble2.exceptions.BleScanException 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Override
public void verify(boolean checkLocationProviderState) {
scanPreconditionVerifierApi18.verify(checkLocationProviderState);
/*
* Android 7.0 (API 24) introduces an undocumented scan throttle for applications that try to scan more than 5 times during
* a 30 second window. More on the topic: https://blog.classycode.com/undocumented-android-7-ble-behavior-changes-d1a9bd87d983
*/
// TODO: [DS] 27.06.2017 Think if persisting this information through Application close is needed
final int oldestCheckTimestampIndex = getOldestCheckTimestampIndex();
final long oldestCheckTimestamp = previousChecks[oldestCheckTimestampIndex];
final long currentCheckTimestamp = timeScheduler.now(TimeUnit.MILLISECONDS);
if (currentCheckTimestamp - oldestCheckTimestamp < EXCESSIVE_SCANNING_PERIOD) {
throw new BleScanException(
BleScanException.UNDOCUMENTED_SCAN_THROTTLE,
new Date(oldestCheckTimestamp + EXCESSIVE_SCANNING_PERIOD)
);
}
previousChecks[oldestCheckTimestampIndex] = currentCheckTimestamp;
}
@RequiresApi(26 /* Build.VERSION_CODES.O */)
@Override
public void scanBleDeviceInBackground(@NonNull PendingIntent callbackIntent, ScanSettings scanSettings, ScanFilter... scanFilters) {
if (Build.VERSION.SDK_INT < 26 /* Build.VERSION_CODES.O */) {
RxBleLog.w("PendingIntent based scanning is available for Android O and higher only.");
return;
}
if (!rxBleAdapterWrapper.isBluetoothEnabled()) {
RxBleLog.w("PendingIntent based scanning is available only when Bluetooth is ON.");
throw new BleScanException(BleScanException.BLUETOOTH_DISABLED);
}
RxBleLog.i("Requesting pending intent based scan.");
final List<android.bluetooth.le.ScanFilter> nativeScanFilters = scanObjectsConverter.toNativeFilters(scanFilters);
final android.bluetooth.le.ScanSettings nativeScanSettings = scanObjectsConverter.toNativeSettings(scanSettings);
final int scanStartResult = rxBleAdapterWrapper.startLeScan(nativeScanFilters, nativeScanSettings, callbackIntent);
if (scanStartResult != NO_ERROR) {
final BleScanException bleScanException = new BleScanException(scanStartResult);
RxBleLog.w(bleScanException, "Failed to start scan"); // TODO?
throw bleScanException;
}
}
@Override
public List<ScanResult> onScanResultReceived(@NonNull Intent intent) {
final int callbackType = intent.getIntExtra(BluetoothLeScanner.EXTRA_CALLBACK_TYPE, -1);
final int errorCode = intent.getIntExtra(BluetoothLeScanner.EXTRA_ERROR_CODE, NO_ERROR);
final List<android.bluetooth.le.ScanResult> nativeScanResults = extractScanResults(intent);
ArrayList<ScanResult> scanResults = new ArrayList<>();
if (errorCode == NO_ERROR) {
for (android.bluetooth.le.ScanResult result : nativeScanResults) {
scanResults.add(convertScanResultToRxAndroidBLEModel(callbackType, result));
}
return scanResults;
} else {
throw new BleScanException(errorCode);
}
}
@BleScanException.Reason
static int errorCodeToBleErrorCode(int errorCode) {
switch (errorCode) {
case ScanCallback.SCAN_FAILED_ALREADY_STARTED:
return BleScanException.SCAN_FAILED_ALREADY_STARTED;
case ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED:
return BleScanException.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED;
case ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED:
return BleScanException.SCAN_FAILED_FEATURE_UNSUPPORTED;
case ScanCallback.SCAN_FAILED_INTERNAL_ERROR:
return BleScanException.SCAN_FAILED_INTERNAL_ERROR;
case 5: // ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES
return BleScanException.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES;
default:
RxBleLog.w("Encountered unknown scanning error code: %d -> check android.bluetooth.le.ScanCallback");
return BleScanException.UNKNOWN_ERROR_CODE;
}
}
@Override
final protected void protectedRun(final ObservableEmitter<SCAN_RESULT_TYPE> emitter, QueueReleaseInterface queueReleaseInterface) {
final SCAN_CALLBACK_TYPE scanCallback = createScanCallback(emitter);
try {
emitter.setCancellable(new Cancellable() {
@Override
public void cancel() {
RxBleLog.i("Scan operation is requested to stop.");
stopScan(rxBleAdapterWrapper, scanCallback);
}
});
RxBleLog.i("Scan operation is requested to start.");
boolean startLeScanStatus = startScan(rxBleAdapterWrapper, scanCallback);
if (!startLeScanStatus) {
emitter.tryOnError(new BleScanException(BleScanException.BLUETOOTH_CANNOT_START));
}
} catch (Throwable throwable) {
RxBleLog.w(throwable, "Error while calling the start scan function");
emitter.tryOnError(new BleScanException(BleScanException.BLUETOOTH_CANNOT_START, throwable));
} finally {
queueReleaseInterface.release();
}
}
/**
* This {@link Observable} will not emit values by design. It may only emit {@link BleScanException} if
* bluetooth adapter is turned down.
*/
<T> Observable<T> bluetoothAdapterOffExceptionObservable() {
return rxBleAdapterStateObservable
.filter(new Predicate<BleAdapterState>() {
@Override
public boolean test(BleAdapterState state) {
return state != BleAdapterState.STATE_ON;
}
})
.firstElement()
.flatMap(new Function<BleAdapterState, MaybeSource<T>>() {
@Override
public MaybeSource<T> apply(BleAdapterState bleAdapterState) {
return Maybe.error(new BleScanException(BleScanException.BLUETOOTH_DISABLED));
}
})
.toObservable();
}
private void scanBleDeviceInBackground() {
if (VERSION.SDK_INT >= VERSION_CODES.O) {
try {
rxBleClient.getBackgroundScanner().scanBleDeviceInBackground(
callbackIntent,
new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.build(),
new ScanFilter.Builder()
.setDeviceAddress("5C:31:3E:BF:F7:34")
// add custom filters if needed
.build()
);
} catch (BleScanException scanException) {
Log.w("BackgroundScanActivity", "Failed to start background scan", scanException);
ScanExceptionHandler.handleException(this, scanException);
}
}
}
/**
* Show toast with error message appropriate to exception reason.
*
* @param context current Activity context
* @param exception BleScanException to show error message for
*/
public static void handleException(final Activity context, final BleScanException exception) {
final String text;
final int reason = exception.getReason();
// Special case, as there might or might not be a retry date suggestion
if (reason == BleScanException.UNDOCUMENTED_SCAN_THROTTLE) {
text = getUndocumentedScanThrottleErrorMessage(context, exception.getRetryDateSuggestion());
} else {
// Handle all other possible errors
final Integer resId = ERROR_MESSAGES.get(reason);
if (resId != null) {
text = context.getString(resId);
} else {
// unknown error - return default message
Log.w("Scanning", String.format("No message found for reason=%d. Consider adding one.", reason));
text = context.getString(R.string.error_unknown_error);
}
}
Log.w("Scanning", text, exception);
Toast.makeText(context, text, Toast.LENGTH_SHORT).show();
}
private synchronized void onScanFailure(Throwable throwable) {
UserError.Log.d(TAG, "onScanFailure: " + throwable);
if (throwable instanceof BleScanException) {
final String info = handleBleScanException((BleScanException) throwable);
// lastScanError = info;
UserError.Log.d(TAG, info);
if (((BleScanException) throwable).getReason() == BleScanException.BLUETOOTH_DISABLED) {
// Attempt to turn bluetooth on
if (ratelimit("bluetooth_toggle_on", 30)) {
UserError.Log.d(TAG, "Pause before Turn Bluetooth on");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
//
}
UserError.Log.e(TAG, "Trying to Turn Bluetooth on");
JoH.setBluetoothEnabled(xdrip.getAppContext(), true);
}
}
}
// TODO count scan duration
stopScan();
releaseWakeLock();
background_automata(5000);
}
private synchronized void onScanFailure(Throwable throwable) {
UserError.Log.d(TAG, "onScanFailure: " + throwable);
if (throwable instanceof BleScanException) {
final String info = handleBleScanException((BleScanException) throwable);
// lastScanError = info;
UserError.Log.d(TAG, info);
if (((BleScanException) throwable).getReason() == BleScanException.BLUETOOTH_DISABLED) {
// Attempt to turn bluetooth on
if (ratelimit("bluetooth_toggle_on", 30)) {
UserError.Log.d(TAG, "Pause before Turn Bluetooth on");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
//
}
UserError.Log.e(TAG, "Trying to Turn Bluetooth on");
JoH.setBluetoothEnabled(xdrip.getAppContext(), true);
}
}
}
// TODO count scan duration
stopScan();
releaseWakeLock();
background_automata(5000);
}
@Override
public void verify(boolean checkLocationProviderState) {
if (!rxBleAdapterWrapper.hasBluetoothAdapter()) {
throw new BleScanException(BleScanException.BLUETOOTH_NOT_AVAILABLE);
} else if (!rxBleAdapterWrapper.isBluetoothEnabled()) {
throw new BleScanException(BleScanException.BLUETOOTH_DISABLED);
} else if (!locationServicesStatus.isLocationPermissionOk()) {
throw new BleScanException(BleScanException.LOCATION_PERMISSION_MISSING);
} else if (checkLocationProviderState && !locationServicesStatus.isLocationProviderOk()) {
throw new BleScanException(BleScanException.LOCATION_SERVICES_DISABLED);
}
}
@RequiresApi(26 /* Build.VERSION_CODES.O */)
@Override
public void onReceive(Context context, Intent intent) {
BackgroundScanner backgroundScanner = SampleApplication.getRxBleClient(context).getBackgroundScanner();
try {
final List<ScanResult> scanResults = backgroundScanner.onScanResultReceived(intent);
Log.i("ScanReceiver", "Scan results received: " + scanResults);
} catch (BleScanException exception) {
Log.w("ScanReceiver", "Failed to scan devices", exception);
}
}
protected synchronized void onScanFailure(Throwable throwable) {
UserError.Log.d(TAG, "onScanFailure: " + throwable);
if (throwable instanceof BleScanException) {
final String info = HandleBleScanException.handle(TAG, (BleScanException) throwable);
UserError.Log.d(TAG, "Scan failure: " + info);
if (!lastFailureReason.equals(info) || JoH.ratelimit("scanmeister-fail-error", 600)) {
UserError.Log.e(TAG, "Failed to scan: " + info);
lastFailureReason = info;
}
if (((BleScanException) throwable).getReason() == BleScanException.BLUETOOTH_DISABLED) {
// Attempt to turn bluetooth on
if (ratelimit("bluetooth_toggle_on", 30)) {
UserError.Log.d(TAG, "Pause before Turn Bluetooth on");
JoH.threadSleep(2000);
UserError.Log.e(TAG, "Trying to Turn Bluetooth on");
JoH.setBluetoothEnabled(xdrip.getAppContext(), true);
}
}
processCallBacks(address, SCAN_FAILED_CALLBACK);
} else if (throwable instanceof TimeoutException) {
// note this code path not always reached - see inevitable task
processCallBacks(address, SCAN_TIMEOUT_CALLBACK);
}
stopScan("Scan failure");
releaseWakeLock();
}
protected synchronized void onScanFailure(Throwable throwable) {
UserError.Log.d(TAG, "onScanFailure: " + throwable);
if (throwable instanceof BleScanException) {
final String info = HandleBleScanException.handle(TAG, (BleScanException) throwable);
UserError.Log.d(TAG, "Scan failure: " + info);
if (!lastFailureReason.equals(info) || JoH.ratelimit("scanmeister-fail-error", 600)) {
UserError.Log.e(TAG, "Failed to scan: " + info);
lastFailureReason = info;
}
if (((BleScanException) throwable).getReason() == BleScanException.BLUETOOTH_DISABLED) {
// Attempt to turn bluetooth on
if (ratelimit("bluetooth_toggle_on", 30)) {
UserError.Log.d(TAG, "Pause before Turn Bluetooth on");
JoH.threadSleep(2000);
UserError.Log.e(TAG, "Trying to Turn Bluetooth on");
JoH.setBluetoothEnabled(xdrip.getAppContext(), true);
}
}
processCallBacks(address, SCAN_FAILED_CALLBACK);
} else if (throwable instanceof TimeoutException) {
// note this code path not always reached - see inevitable task
processCallBacks(address, SCAN_TIMEOUT_CALLBACK);
}
stopScan("Scan failure");
releaseWakeLock();
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
android.util.Log.d("BackgroundScanReceiver", "GOT SCAN INTENT!! " + action);
if (action != null && action.equals(ACTION_NAME)) {
String caller = intent.getStringExtra(CALLING_CLASS);
if (caller == null) caller = this.getClass().getSimpleName();
// TODO by class name?
final BackgroundScanner backgroundScanner = RxBleProvider.getSingleton().getBackgroundScanner();
try {
final List<ScanResult> scanResults = backgroundScanner.onScanResultReceived(intent);
final String matchedMac = scanResults.get(0).getBleDevice().getMacAddress();
final String matchedName = scanResults.get(0).getBleDevice().getName();
final boolean calledBack = processCallbacks(caller, matchedMac, matchedName, SCAN_FOUND_CALLBACK);
UserError.Log.d(caller, "Scan results received: " + matchedMac + " " + scanResults);
if (!calledBack) {
try {
// bit of an ugly fix to system wide persistent nature of background scans and lack of proper support for one hit over various android devices
backgroundScanner.stopBackgroundBleScan(PendingIntent.getBroadcast(xdrip.getAppContext(), 142, // must match original
intent, PendingIntent.FLAG_UPDATE_CURRENT));
} catch (Exception e) {
//
}
}
} catch (NullPointerException | BleScanException exception) {
UserError.Log.e(caller, "Failed to scan devices" + exception);
}
}
// ignore invalid actions
}
protected synchronized void onScanFailure(Throwable throwable) {
UserError.Log.d(TAG, "onScanFailure: " + throwable);
if (throwable instanceof BleScanException) {
final String info = HandleBleScanException.handle(TAG, (BleScanException) throwable);
UserError.Log.d(TAG, "Scan failure: " + info);
if (!lastFailureReason.equals(info) || JoH.ratelimit("scanmeister-fail-error", 600)) {
UserError.Log.e(TAG, "Failed to scan: " + info);
lastFailureReason = info;
}
if (((BleScanException) throwable).getReason() == BleScanException.BLUETOOTH_DISABLED) {
// Attempt to turn bluetooth on
if (ratelimit("bluetooth_toggle_on", 30)) {
UserError.Log.d(TAG, "Pause before Turn Bluetooth on");
JoH.threadSleep(2000);
UserError.Log.e(TAG, "Trying to Turn Bluetooth on");
JoH.setBluetoothEnabled(xdrip.getAppContext(), true);
}
}
processCallBacks(address, SCAN_FAILED_CALLBACK);
} else if (throwable instanceof TimeoutException) {
// note this code path not always reached - see inevitable task
processCallBacks(address, SCAN_TIMEOUT_CALLBACK);
}
stopScan("Scan failure");
releaseWakeLock();
}
protected synchronized void onScanFailure(Throwable throwable) {
UserError.Log.d(TAG, "onScanFailure: " + throwable);
if (throwable instanceof BleScanException) {
final String info = HandleBleScanException.handle(TAG, (BleScanException) throwable);
UserError.Log.d(TAG, "Scan failure: " + info);
if (!lastFailureReason.equals(info) || JoH.ratelimit("scanmeister-fail-error", 600)) {
UserError.Log.e(TAG, "Failed to scan: " + info);
lastFailureReason = info;
}
if (((BleScanException) throwable).getReason() == BleScanException.BLUETOOTH_DISABLED) {
// Attempt to turn bluetooth on
if (ratelimit("bluetooth_toggle_on", 30)) {
UserError.Log.d(TAG, "Pause before Turn Bluetooth on");
JoH.threadSleep(2000);
UserError.Log.e(TAG, "Trying to Turn Bluetooth on");
JoH.setBluetoothEnabled(xdrip.getAppContext(), true);
}
}
processCallBacks(address, SCAN_FAILED_CALLBACK);
} else if (throwable instanceof TimeoutException) {
// note this code path not always reached - see inevitable task
processCallBacks(address, SCAN_TIMEOUT_CALLBACK);
}
stopScan("Scan failure");
releaseWakeLock();
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
android.util.Log.d("BackgroundScanReceiver", "GOT SCAN INTENT!! " + action);
if (action != null && action.equals(ACTION_NAME)) {
String caller = intent.getStringExtra(CALLING_CLASS);
if (caller == null) caller = this.getClass().getSimpleName();
// TODO by class name?
final BackgroundScanner backgroundScanner = RxBleProvider.getSingleton().getBackgroundScanner();
try {
final List<ScanResult> scanResults = backgroundScanner.onScanResultReceived(intent);
final String matchedMac = scanResults.get(0).getBleDevice().getMacAddress();
final String matchedName = scanResults.get(0).getBleDevice().getName();
final boolean calledBack = processCallbacks(caller, matchedMac, matchedName, SCAN_FOUND_CALLBACK);
UserError.Log.d(caller, "Scan results received: " + matchedMac + " " + scanResults);
if (!calledBack) {
try {
// bit of an ugly fix to system wide persistent nature of background scans and lack of proper support for one hit over various android devices
backgroundScanner.stopBackgroundBleScan(PendingIntent.getBroadcast(xdrip.getAppContext(), 142, // must match original
intent, PendingIntent.FLAG_UPDATE_CURRENT));
} catch (Exception e) {
//
}
}
} catch (NullPointerException | BleScanException exception) {
UserError.Log.e(caller, "Failed to scan devices" + exception);
}
}
// ignore invalid actions
}
@Override
protected BleException provideException(DeadObjectException deadObjectException) {
return new BleScanException(BleScanException.BLUETOOTH_DISABLED, deadObjectException);
}
private void onScanFailure(Throwable throwable) {
if (throwable instanceof BleScanException) {
ScanExceptionHandler.handleException(this, (BleScanException) throwable);
}
}
protected String handleBleScanException(BleScanException bleScanException) {
return HandleBleScanException.handle(TAG, bleScanException);
}
protected String handleBleScanException(BleScanException bleScanException) {
return HandleBleScanException.handle(TAG, bleScanException);
}
void verify(boolean checkLocationProviderState) throws BleScanException;