From 8b33b8fd629ea10954af3d205ac6d7e63ee2c537 Mon Sep 17 00:00:00 2001 From: Filippo Del Frari Date: Fri, 13 Sep 2019 08:13:12 +0200 Subject: [PATCH 1/4] Replaced Emitter with ObservableEmitter in ScanOperation Interface. Fix: replaced onError() with tryOnError() in ScanOperationApi21 --- .../internal/operations/LegacyScanOperation.java | 4 ++-- .../rxandroidble2/internal/operations/ScanOperation.java | 9 ++++----- .../internal/operations/ScanOperationApi18.java | 4 ++-- .../internal/operations/ScanOperationApi21.java | 6 +++--- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/LegacyScanOperation.java b/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/LegacyScanOperation.java index 37845ceda..57da7f229 100644 --- a/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/LegacyScanOperation.java +++ b/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/LegacyScanOperation.java @@ -17,7 +17,7 @@ import java.util.Set; import java.util.UUID; -import io.reactivex.Emitter; +import io.reactivex.ObservableEmitter; public class LegacyScanOperation extends ScanOperation { @@ -38,7 +38,7 @@ public LegacyScanOperation(UUID[] filterServiceUUIDs, RxBleAdapterWrapper rxBleA } @Override - BluetoothAdapter.LeScanCallback createScanCallback(final Emitter emitter) { + BluetoothAdapter.LeScanCallback createScanCallback(final ObservableEmitter emitter) { return new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { diff --git a/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ScanOperation.java b/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ScanOperation.java index b1ce80b4a..ba7ac9a3f 100644 --- a/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ScanOperation.java +++ b/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ScanOperation.java @@ -9,7 +9,6 @@ import com.polidea.rxandroidble2.internal.serialization.QueueReleaseInterface; import com.polidea.rxandroidble2.internal.util.RxBleAdapterWrapper; -import io.reactivex.Emitter; import io.reactivex.ObservableEmitter; import io.reactivex.functions.Cancellable; @@ -67,21 +66,21 @@ protected BleException provideException(DeadObjectException deadObjectException) * @return the scan callback type to use with {@link #startScan(RxBleAdapterWrapper, Object)} * and {@link #stopScan(RxBleAdapterWrapper, Object)} */ - abstract SCAN_CALLBACK_TYPE createScanCallback(Emitter emitter); + abstract SCAN_CALLBACK_TYPE createScanCallback(ObservableEmitter emitter); /** * Function that should start the scan using passed {@link RxBleAdapterWrapper} and {@link SCAN_CALLBACK_TYPE} callback * @param rxBleAdapterWrapper the {@link RxBleAdapterWrapper} to use - * @param scanCallback the {@link SCAN_CALLBACK_TYPE} returned by {@link #createScanCallback(Emitter)} to start + * @param scanCallback the {@link SCAN_CALLBACK_TYPE} returned by {@link #createScanCallback(ObservableEmitter)} to start * @return true if successful */ abstract boolean startScan(RxBleAdapterWrapper rxBleAdapterWrapper, SCAN_CALLBACK_TYPE scanCallback); /** * Method that should stop the scan for a given {@link SCAN_CALLBACK_TYPE} that was previously returned - * by {@link #createScanCallback(Emitter)} + * by {@link #createScanCallback(ObservableEmitter)} * @param rxBleAdapterWrapper the {@link RxBleAdapterWrapper} to use - * @param scanCallback the {@link SCAN_CALLBACK_TYPE} returned by {@link #createScanCallback(Emitter)} to stop + * @param scanCallback the {@link SCAN_CALLBACK_TYPE} returned by {@link #createScanCallback(ObservableEmitter)} to stop */ abstract void stopScan(RxBleAdapterWrapper rxBleAdapterWrapper, SCAN_CALLBACK_TYPE scanCallback); } diff --git a/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ScanOperationApi18.java b/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ScanOperationApi18.java index 66490a533..7218da91b 100644 --- a/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ScanOperationApi18.java +++ b/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ScanOperationApi18.java @@ -13,7 +13,7 @@ import com.polidea.rxandroidble2.internal.scan.RxBleInternalScanResult; import com.polidea.rxandroidble2.internal.util.RxBleAdapterWrapper; -import io.reactivex.Emitter; +import io.reactivex.ObservableEmitter; public class ScanOperationApi18 extends ScanOperation { @@ -34,7 +34,7 @@ public ScanOperationApi18( } @Override - BluetoothAdapter.LeScanCallback createScanCallback(final Emitter emitter) { + BluetoothAdapter.LeScanCallback createScanCallback(final ObservableEmitter emitter) { return new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { diff --git a/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ScanOperationApi21.java b/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ScanOperationApi21.java index ebd5a54b5..4c0468cd7 100644 --- a/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ScanOperationApi21.java +++ b/rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ScanOperationApi21.java @@ -23,7 +23,7 @@ import java.util.Arrays; import java.util.List; -import io.reactivex.Emitter; +import io.reactivex.ObservableEmitter; @RequiresApi(21 /* Build.VERSION_CODES.LOLLIPOP */) public class ScanOperationApi21 extends ScanOperation { @@ -57,7 +57,7 @@ public ScanOperationApi21( } @Override - ScanCallback createScanCallback(final Emitter emitter) { + ScanCallback createScanCallback(final ObservableEmitter emitter) { return new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { @@ -90,7 +90,7 @@ public void onBatchScanResults(List results) { @Override public void onScanFailed(int errorCode) { - emitter.onError(new BleScanException(errorCodeToBleErrorCode(errorCode))); + emitter.tryOnError(new BleScanException(errorCodeToBleErrorCode(errorCode))); } }; } From 17e1a949470a5fd9986ef66b8dc7351f09e9d0ad Mon Sep 17 00:00:00 2001 From: filippodelfra Date: Fri, 13 Sep 2019 19:41:04 +0200 Subject: [PATCH 2/4] Added test for onScanFailed() throwing while observable is disposed --- .../operations/OperationScanApi21Test.groovy | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/operations/OperationScanApi21Test.groovy b/rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/operations/OperationScanApi21Test.groovy index 6d7a355bd..96a1e3560 100644 --- a/rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/operations/OperationScanApi21Test.groovy +++ b/rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/operations/OperationScanApi21Test.groovy @@ -184,6 +184,21 @@ public class OperationScanApi21Test extends Specification { [true, true] | 2 } + def "onScanFailed() should not throw if Observable is already disposed."() { + + given: + def capturedLeScanCallbackRef = captureScanCallback() + prepareObjectUnderTest(Mock(ScanSettings), null, null) + def testSubscriber = objectUnderTest.run(mockQueueReleaseInterface).test() + + when: + testSubscriber.dispose() + capturedLeScanCallbackRef.get().onScanFailed(ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED) + + then: + testSubscriber.assertNoErrors() + } + private AtomicReference captureScanCallback() { AtomicReference scanCallbackAtomicReference = new AtomicReference<>() mockAdapterWrapper.startLeScan(_, _, _) >> { List _, ScanSettings _1, ScanCallback scanCallback -> From 05e1dd7dd210a2fa4079587382de0baf62987d1c Mon Sep 17 00:00:00 2001 From: Filippo Del Frari Date: Mon, 16 Sep 2019 15:20:29 +0200 Subject: [PATCH 3/4] Updated "onScanFailed() should not throw if Observable is already disposed" Test --- .../operations/OperationScanApi21Test.groovy | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/operations/OperationScanApi21Test.groovy b/rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/operations/OperationScanApi21Test.groovy index 96a1e3560..11a897b85 100644 --- a/rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/operations/OperationScanApi21Test.groovy +++ b/rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/operations/OperationScanApi21Test.groovy @@ -14,6 +14,7 @@ import com.polidea.rxandroidble2.internal.serialization.QueueReleaseInterface import com.polidea.rxandroidble2.internal.util.RxBleAdapterWrapper import com.polidea.rxandroidble2.scan.ScanFilter import com.polidea.rxandroidble2.scan.ScanSettings +import io.reactivex.plugins.RxJavaPlugins import spock.lang.Specification import spock.lang.Unroll @@ -188,6 +189,7 @@ public class OperationScanApi21Test extends Specification { given: def capturedLeScanCallbackRef = captureScanCallback() + def rxUnhandledExceptionRef = captureRxUnhandledExceptions() prepareObjectUnderTest(Mock(ScanSettings), null, null) def testSubscriber = objectUnderTest.run(mockQueueReleaseInterface).test() @@ -196,7 +198,8 @@ public class OperationScanApi21Test extends Specification { capturedLeScanCallbackRef.get().onScanFailed(ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED) then: - testSubscriber.assertNoErrors() + rxUnhandledExceptionRef.get() == null + } private AtomicReference captureScanCallback() { @@ -207,6 +210,14 @@ public class OperationScanApi21Test extends Specification { return scanCallbackAtomicReference } + private AtomicReference captureRxUnhandledExceptions() { + AtomicReference unhandledExceptionAtomicReference = new AtomicReference<>() + RxJavaPlugins.setErrorHandler({ throwable -> + unhandledExceptionAtomicReference.set(throwable) + }) + return unhandledExceptionAtomicReference + } + private static class MockBleAdapterWrapper extends RxBleAdapterWrapper { Semaphore acquireBeforeReturnStartScan = null From 264d8d24abdde90f87fef13564505343f233a22b Mon Sep 17 00:00:00 2001 From: Filippo Del Frari Date: Wed, 18 Sep 2019 13:41:37 +0200 Subject: [PATCH 4/4] Improved test --- .../internal/operations/OperationScanApi21Test.groovy | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/operations/OperationScanApi21Test.groovy b/rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/operations/OperationScanApi21Test.groovy index 11a897b85..087c76e8c 100644 --- a/rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/operations/OperationScanApi21Test.groovy +++ b/rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/operations/OperationScanApi21Test.groovy @@ -185,21 +185,24 @@ public class OperationScanApi21Test extends Specification { [true, true] | 2 } - def "onScanFailed() should not throw if Observable is already disposed."() { + def "onScanFailed() should not result in exception being passed to RxJavaPlugins.onErrorHandler() if Observable was disposed."() { given: def capturedLeScanCallbackRef = captureScanCallback() def rxUnhandledExceptionRef = captureRxUnhandledExceptions() prepareObjectUnderTest(Mock(ScanSettings), null, null) def testSubscriber = objectUnderTest.run(mockQueueReleaseInterface).test() + testSubscriber.dispose() when: - testSubscriber.dispose() capturedLeScanCallbackRef.get().onScanFailed(ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED) then: rxUnhandledExceptionRef.get() == null + cleanup: + RxJavaPlugins.setErrorHandler(null) + } private AtomicReference captureScanCallback() { @@ -210,7 +213,7 @@ public class OperationScanApi21Test extends Specification { return scanCallbackAtomicReference } - private AtomicReference captureRxUnhandledExceptions() { + private static AtomicReference captureRxUnhandledExceptions() { AtomicReference unhandledExceptionAtomicReference = new AtomicReference<>() RxJavaPlugins.setErrorHandler({ throwable -> unhandledExceptionAtomicReference.set(throwable)