├── .buildscript ├── deploy_snapshot.sh └── update_version_in_readmes.sh ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── gradle-actions.yml ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── _config.yml ├── build.gradle ├── checkstyle.gradle ├── checkstyle.xml ├── dagger-compiler-shadow └── build.gradle ├── dagger-library-shadow ├── build.gradle └── gradle.properties ├── dependencies.gradle ├── gradle.properties ├── gradle ├── gradle-mvn-config.gradle ├── shadow-consumer-fix.gradle ├── shadow.gradle ├── src-gen-rxjava3-from-rxjava2.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── mockrxandroidble ├── .gitignore ├── README.md ├── build.gradle ├── gradle.properties └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── polidea │ │ └── rxandroidble2 │ │ └── mockrxandroidble │ │ ├── RxBleClientMock.java │ │ ├── RxBleConnectionMock.java │ │ ├── RxBleDeviceMock.java │ │ ├── RxBleScanRecordMock.java │ │ ├── RxBleScanResultMock.java │ │ ├── callbacks │ │ ├── RxBleCharacteristicReadCallback.java │ │ ├── RxBleCharacteristicWriteCallback.java │ │ ├── RxBleDescriptorReadCallback.java │ │ ├── RxBleDescriptorWriteCallback.java │ │ └── results │ │ │ ├── RxBleGattReadResultMock.java │ │ │ └── RxBleGattWriteResultMock.java │ │ └── internal │ │ └── ScanRecordDataConstructor.java │ └── test │ └── groovy │ └── com │ └── polidea │ └── rxandroidble2 │ └── mockrxandroidble │ ├── RxBleClientMockLegacyTest.groovy │ ├── RxBleClientMockTest.groovy │ ├── RxBleConnectionMockTest.groovy │ └── internal │ └── ScanRecordDataConstructorTest.groovy ├── mockrxandroidble3 ├── .gitignore ├── README.md ├── build.gradle └── gradle.properties ├── rxandroidble ├── .gitignore ├── build.gradle ├── gradle.properties ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── com │ │ └── polidea │ │ └── rxandroidble2 │ │ ├── ClientComponent.java │ │ ├── ClientScope.java │ │ ├── ConnectionParameters.java │ │ ├── ConnectionSetup.java │ │ ├── HiddenBluetoothGattCallback.java │ │ ├── LogConstants.java │ │ ├── LogOptions.java │ │ ├── NotificationSetupMode.java │ │ ├── PhyPair.java │ │ ├── RxBleAdapterStateObservable.java │ │ ├── RxBleClient.java │ │ ├── RxBleClientImpl.java │ │ ├── RxBleConnection.java │ │ ├── RxBleCustomOperation.java │ │ ├── RxBleDevice.java │ │ ├── RxBleDeviceServices.java │ │ ├── RxBlePhy.java │ │ ├── RxBlePhyOption.java │ │ ├── RxBleRadioOperationCustom.java │ │ ├── RxBleScanResult.java │ │ ├── Timeout.java │ │ ├── exceptions │ │ ├── BleAdapterDisabledException.java │ │ ├── BleAlreadyConnectedException.java │ │ ├── BleCannotSetCharacteristicNotificationException.java │ │ ├── BleCharacteristicNotFoundException.java │ │ ├── BleConflictingNotificationAlreadySetException.java │ │ ├── BleDescriptorNotFoundException.java │ │ ├── BleDisconnectedException.java │ │ ├── BleException.java │ │ ├── BleGattCallbackTimeoutException.java │ │ ├── BleGattCannotStartException.java │ │ ├── BleGattCharacteristicException.java │ │ ├── BleGattDescriptorException.java │ │ ├── BleGattException.java │ │ ├── BleGattOperationType.java │ │ ├── BleScanException.java │ │ └── BleServiceNotFoundException.java │ │ ├── helpers │ │ ├── AdvertisedServiceUUIDExtractor.java │ │ ├── ByteArrayBatchObservable.java │ │ ├── LocationServicesOkObservable.java │ │ └── ValueInterpreter.java │ │ ├── internal │ │ ├── BleIllegalOperationException.java │ │ ├── BluetoothGattCharacteristicProperty.java │ │ ├── DeviceComponent.java │ │ ├── DeviceModule.java │ │ ├── DeviceScope.java │ │ ├── PhyPairImpl.java │ │ ├── Priority.java │ │ ├── QueueOperation.java │ │ ├── RxBleDeviceImpl.java │ │ ├── RxBleDeviceProvider.java │ │ ├── RxBleLog.java │ │ ├── RxBlePhyImpl.java │ │ ├── RxBlePhyOptionImpl.java │ │ ├── ScanResultInterface.java │ │ ├── SingleResponseOperation.java │ │ ├── cache │ │ │ ├── CacheEntry.java │ │ │ ├── DeviceComponentCache.java │ │ │ └── DeviceComponentWeakReference.java │ │ ├── connection │ │ │ ├── BluetoothGattProvider.java │ │ │ ├── ConnectionComponent.java │ │ │ ├── ConnectionModule.java │ │ │ ├── ConnectionParametersImpl.java │ │ │ ├── ConnectionScope.java │ │ │ ├── ConnectionStateChangeListener.java │ │ │ ├── ConnectionSubscriptionWatcher.java │ │ │ ├── Connector.java │ │ │ ├── ConnectorImpl.java │ │ │ ├── ConstantPayloadSizeLimit.java │ │ │ ├── DescriptorWriter.java │ │ │ ├── DisconnectAction.java │ │ │ ├── DisconnectionRouter.java │ │ │ ├── DisconnectionRouterInput.java │ │ │ ├── DisconnectionRouterOutput.java │ │ │ ├── IllegalOperationChecker.java │ │ │ ├── IllegalOperationHandler.java │ │ │ ├── IllegalOperationMessageCreator.java │ │ │ ├── ImmediateSerializedBatchAckStrategy.java │ │ │ ├── LoggingIllegalOperationHandler.java │ │ │ ├── LongWriteOperationBuilderImpl.java │ │ │ ├── MtuBasedPayloadSizeLimit.java │ │ │ ├── MtuProvider.java │ │ │ ├── MtuWatcher.java │ │ │ ├── NativeCallbackDispatcher.java │ │ │ ├── NoRetryStrategy.java │ │ │ ├── NotificationAndIndicationManager.java │ │ │ ├── PayloadSizeLimitProvider.java │ │ │ ├── RxBleConnectionImpl.java │ │ │ ├── RxBleGattCallback.java │ │ │ ├── ServiceDiscoveryManager.java │ │ │ └── ThrowingIllegalOperationHandler.java │ │ ├── logger │ │ │ ├── LoggerSetup.java │ │ │ ├── LoggerUtil.java │ │ │ └── LoggerUtilBluetoothServices.java │ │ ├── operations │ │ │ ├── CharacteristicLongWriteOperation.java │ │ │ ├── CharacteristicReadOperation.java │ │ │ ├── CharacteristicWriteOperation.java │ │ │ ├── ConnectOperation.java │ │ │ ├── ConnectionPriorityChangeOperation.java │ │ │ ├── DescriptorReadOperation.java │ │ │ ├── DescriptorWriteOperation.java │ │ │ ├── DisconnectOperation.java │ │ │ ├── LegacyScanOperation.java │ │ │ ├── MtuRequestOperation.java │ │ │ ├── Operation.java │ │ │ ├── OperationsProvider.java │ │ │ ├── OperationsProviderImpl.java │ │ │ ├── PhyReadOperation.java │ │ │ ├── PhyUpdateOperation.java │ │ │ ├── ReadRssiOperation.java │ │ │ ├── ScanOperation.java │ │ │ ├── ScanOperationApi18.java │ │ │ ├── ScanOperationApi21.java │ │ │ ├── ServiceDiscoveryOperation.java │ │ │ └── TimeoutConfiguration.java │ │ ├── scan │ │ │ ├── AdvertisingSidExtractor.java │ │ │ ├── AdvertisingSidExtractorApi18.java │ │ │ ├── AdvertisingSidExtractorApi26.java │ │ │ ├── AndroidScanObjectsConverter.java │ │ │ ├── BackgroundScannerImpl.java │ │ │ ├── EmulatedScanFilterMatcher.java │ │ │ ├── ExternalScanSettingsExtension.java │ │ │ ├── InternalScanResultCreator.java │ │ │ ├── InternalToExternalScanResultConverter.java │ │ │ ├── IsConnectableChecker.java │ │ │ ├── IsConnectableCheckerApi18.java │ │ │ ├── IsConnectableCheckerApi26.java │ │ │ ├── RxBleInternalScanResult.java │ │ │ ├── RxBleInternalScanResultLegacy.java │ │ │ ├── ScanFilterInterface.java │ │ │ ├── ScanPreconditionsVerifier.java │ │ │ ├── ScanPreconditionsVerifierApi18.java │ │ │ ├── ScanPreconditionsVerifierApi24.java │ │ │ ├── ScanRecordImplCompat.java │ │ │ ├── ScanRecordImplNativeWrapper.java │ │ │ ├── ScanSettingsEmulator.java │ │ │ ├── ScanSetup.java │ │ │ ├── ScanSetupBuilder.java │ │ │ ├── ScanSetupBuilderImplApi18.java │ │ │ ├── ScanSetupBuilderImplApi21.java │ │ │ └── ScanSetupBuilderImplApi23.java │ │ ├── serialization │ │ │ ├── ClientOperationQueue.java │ │ │ ├── ClientOperationQueueImpl.java │ │ │ ├── ConnectionOperationQueue.java │ │ │ ├── ConnectionOperationQueueImpl.java │ │ │ ├── FIFORunnableEntry.java │ │ │ ├── OperationPriorityFifoBlockingQueue.java │ │ │ ├── QueueAwaitReleaseInterface.java │ │ │ ├── QueueReleaseInterface.java │ │ │ ├── QueueSemaphore.java │ │ │ └── RxBleThreadFactory.java │ │ └── util │ │ │ ├── ActiveCharacteristicNotification.java │ │ │ ├── BleConnectionCompat.java │ │ │ ├── BluetoothManagerWrapper.java │ │ │ ├── ByteAssociation.java │ │ │ ├── ByteAssociationUtil.java │ │ │ ├── CharacteristicChangedEvent.java │ │ │ ├── CharacteristicNotificationId.java │ │ │ ├── CharacteristicPropertiesParser.java │ │ │ ├── CheckerConnectPermission.java │ │ │ ├── CheckerLocationProvider.java │ │ │ ├── CheckerPermission.java │ │ │ ├── CheckerScanPermission.java │ │ │ ├── ClientStateObservable.java │ │ │ ├── DisposableUtil.java │ │ │ ├── LocationServicesOkObservableApi23Factory.java │ │ │ ├── LocationServicesStatus.java │ │ │ ├── LocationServicesStatusApi18.java │ │ │ ├── LocationServicesStatusApi23.java │ │ │ ├── LocationServicesStatusApi31.java │ │ │ ├── ObservableUtil.java │ │ │ ├── QueueReleasingEmitterWrapper.java │ │ │ ├── RxBleAdapterWrapper.java │ │ │ ├── ScanRecordParser.java │ │ │ └── UUIDUtil.java │ │ ├── scan │ │ ├── BackgroundScanner.java │ │ ├── IsConnectable.java │ │ ├── ScanCallbackType.java │ │ ├── ScanFilter.java │ │ ├── ScanRecord.java │ │ ├── ScanResult.java │ │ └── ScanSettings.java │ │ └── utils │ │ ├── ConnectionSharingAdapter.java │ │ ├── GattStatusParser.java │ │ └── StandardUUIDsParser.java │ └── test │ ├── groovy │ └── com │ │ └── polidea │ │ └── rxandroidble2 │ │ ├── DummyOperationQueue.groovy │ │ ├── MockBluetoothManagerWrapper.groovy │ │ ├── MockLocationServicesStatus.groovy │ │ ├── MockOperation.groovy │ │ ├── MockRxBleAdapterStateObservable.groovy │ │ ├── MockRxBleAdapterWrapper.groovy │ │ ├── MockSemaphore.groovy │ │ ├── RxBleAdapterStateObservableTest.groovy │ │ ├── RxBleClientTest.groovy │ │ ├── extensions │ │ └── TestSubscriberExtension.groovy │ │ ├── internal │ │ ├── DeviceComponentCacheTest.groovy │ │ ├── RxBleDeviceProviderTest.groovy │ │ ├── RxBleDeviceTest.groovy │ │ ├── SingleResponseOperationTest.groovy │ │ ├── cache │ │ │ └── MockDeviceReferenceProvider.groovy │ │ ├── connection │ │ │ ├── BluetoothGattProviderTest.groovy │ │ │ ├── ConnectorImplTest.groovy │ │ │ ├── DisconnectionRouterTest.groovy │ │ │ ├── IllegalOperationCheckerTest.groovy │ │ │ ├── MtuBasedPayloadSizeLimitTest.groovy │ │ │ ├── MtuWatcherTest.groovy │ │ │ ├── NotificationAndIndicationManagerTest.groovy │ │ │ ├── RxBleConnectionTest.groovy │ │ │ ├── RxBleGattCallbackPerformanceTest.groovy │ │ │ ├── RxBleGattCallbackTest.groovy │ │ │ └── ServiceDiscoveryManagerTest.groovy │ │ ├── operations │ │ │ ├── OperationCharacteristicLongWriteTest.groovy │ │ │ ├── OperationCharacteristicReadTest.groovy │ │ │ ├── OperationCharacteristicWriteTest.groovy │ │ │ ├── OperationConnectTest.groovy │ │ │ ├── OperationConnectionPriorityRequestTest.groovy │ │ │ ├── OperationDescriptorReadTest.groovy │ │ │ ├── OperationDescriptorWriteTest.groovy │ │ │ ├── OperationDisconnectTest.groovy │ │ │ ├── OperationMtuRequestTest.groovy │ │ │ ├── OperationPhyReadTest.groovy │ │ │ ├── OperationPhyUpdateTest.groovy │ │ │ ├── OperationReadRssiTest.groovy │ │ │ ├── OperationScanApi18Test.groovy │ │ │ ├── OperationScanApi21Test.groovy │ │ │ ├── OperationScanLegacyTest.groovy │ │ │ └── OperationServicesDiscoverTest.groovy │ │ ├── scan │ │ │ ├── BackgroundScannerTest.groovy │ │ │ ├── EmulatedScanFilterMatcherTest.groovy │ │ │ ├── ScanPreconditionsVerifierApi18Test.groovy │ │ │ ├── ScanPreconditionsVerifierApi24Test.groovy │ │ │ └── ScanSettingsEmulatorTest.groovy │ │ ├── serialization │ │ │ ├── FIFORunnableEntryTest.groovy │ │ │ ├── OperationPriorityFifoBlockingQueueTest.groovy │ │ │ └── OperationSynchronizerTest.groovy │ │ └── util │ │ │ ├── CheckerPermissionTest.groovy │ │ │ ├── CheckerScanPermissionTest.groovy │ │ │ ├── ClientStateObservableTest.groovy │ │ │ ├── LocationServicesOkObservableApi23FactoryTest.groovy │ │ │ ├── LocationServicesStatusApi18Test.groovy │ │ │ ├── LocationServicesStatusApi23Test.groovy │ │ │ ├── MockOperationTimeoutConfiguration.java │ │ │ ├── ObservableUtilTest.groovy │ │ │ ├── RxBleAdapterWrapperTest.groovy │ │ │ ├── ScanRecordParserTest.groovy │ │ │ └── UUIDUtilTest.groovy │ │ └── scan │ │ └── ScanFilterTest.groovy │ ├── java │ ├── android │ │ ├── app │ │ │ ├── Activity.java │ │ │ └── PendingIntent.java │ │ ├── bluetooth │ │ │ ├── BluetoothAdapter.java │ │ │ ├── BluetoothDevice.java │ │ │ ├── BluetoothGatt.java │ │ │ ├── BluetoothGattCallback.java │ │ │ ├── BluetoothGattCharacteristic.java │ │ │ ├── BluetoothGattDescriptor.java │ │ │ ├── BluetoothGattIncludedService.java │ │ │ ├── BluetoothGattService.java │ │ │ └── le │ │ │ │ ├── BluetoothLeScanner.java │ │ │ │ ├── ScanCallback.java │ │ │ │ ├── ScanFilter.java │ │ │ │ ├── ScanResult.java │ │ │ │ └── ScanSettings.java │ │ ├── content │ │ │ ├── BroadcastReceiver.java │ │ │ ├── Context.java │ │ │ ├── Intent.java │ │ │ ├── IntentFilter.java │ │ │ ├── MemorySharedPreferences.java │ │ │ └── res │ │ │ │ ├── Configuration.java │ │ │ │ └── Resources.java │ │ ├── location │ │ │ └── LocationManager.java │ │ ├── os │ │ │ ├── Build.java │ │ │ ├── Bundle.java │ │ │ ├── DeadObjectException.java │ │ │ ├── ParcelUuid.java │ │ │ └── RemoteException.java │ │ └── util │ │ │ ├── AndroidException.java │ │ │ ├── Log.java │ │ │ ├── Pair.java │ │ │ └── SparseArray.java │ ├── com │ │ └── polidea │ │ │ └── rxandroidble2 │ │ │ ├── exceptions │ │ │ ├── BleCannotSetCharacteristicNotificationExceptionTest.java │ │ │ ├── BleDisconnectedExceptionTest.java │ │ │ ├── BleGattExceptionTest.java │ │ │ └── BleScanExceptionTest.java │ │ │ └── helpers │ │ │ └── ByteArrayBatchObservableTest.java │ └── utils │ │ └── MockUtils.java │ └── resources │ └── META-INF │ └── services │ └── org.codehaus.groovy.runtime.ExtensionModule ├── rxandroidble3 ├── .gitignore ├── README.md ├── build.gradle ├── consumer-rules.pro ├── gradle.properties └── proguard-rules.pro ├── sample-kotlin ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── kotlin │ │ └── com │ │ │ └── polidea │ │ │ └── rxandroidble2 │ │ │ └── samplekotlin │ │ │ ├── DeviceActivity.kt │ │ │ ├── SampleApplication.kt │ │ │ ├── example1_scanning │ │ │ ├── ScanActivity.kt │ │ │ └── ScanResultsAdapter.kt │ │ │ ├── example1a_background_scanning │ │ │ ├── BackgroundScanActivity.kt │ │ │ └── ScanReceiver.kt │ │ │ ├── example2_connection │ │ │ └── ConnectionExampleActivity.kt │ │ │ ├── example3_discovery │ │ │ ├── DiscoveryResultsAdapter.kt │ │ │ └── ServiceDiscoveryExampleActivity.kt │ │ │ ├── example4_characteristic │ │ │ ├── CharacteristicOperationExampleActivity.kt │ │ │ └── advanced │ │ │ │ ├── AdvancedCharacteristicOperationExampleActivity.kt │ │ │ │ ├── Presenter.kt │ │ │ │ └── PresenterEvent.kt │ │ │ ├── example5_rssi_periodic │ │ │ └── RssiPeriodicExampleActivity.kt │ │ │ ├── example7_long_write │ │ │ └── LongWriteExampleActivity.kt │ │ │ └── util │ │ │ ├── BluetoothGatt.kt │ │ │ ├── ByteArray.kt │ │ │ ├── ConnectPermission.kt │ │ │ ├── RxAndroidBle.kt │ │ │ ├── ScanExceptionHandler.kt │ │ │ ├── ScanPermission.kt │ │ │ └── UI.kt │ └── res │ │ ├── drawable │ │ └── ic_keyboard_arrow_right_24dp.xml │ │ ├── layout │ │ ├── activity_device.xml │ │ ├── activity_example1.xml │ │ ├── activity_example1a.xml │ │ ├── activity_example2.xml │ │ ├── activity_example3.xml │ │ ├── activity_example4.xml │ │ ├── activity_example4_advanced.xml │ │ ├── activity_example5.xml │ │ ├── activity_example6.xml │ │ ├── item_discovery_characteristic.xml │ │ └── item_discovery_service.xml │ │ ├── menu │ │ └── menu_scan.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── backup_descriptor.xml │ └── test │ └── kotlin │ └── com │ └── polidea │ └── rxandroidble2 │ └── samplekotlin │ └── example4_characteristic │ └── advanced │ └── PresenterTest.kt ├── sample ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── ic_launcher-web.png │ ├── java │ └── com │ │ └── polidea │ │ └── rxandroidble2 │ │ └── sample │ │ ├── DeviceActivity.java │ │ ├── SampleApplication.java │ │ ├── example1_scanning │ │ ├── ScanActivity.java │ │ └── ScanResultsAdapter.java │ │ ├── example1a_background_scanning │ │ ├── BackgroundScanActivity.java │ │ └── ScanReceiver.java │ │ ├── example2_connection │ │ └── ConnectionExampleActivity.java │ │ ├── example3_discovery │ │ ├── DiscoveryResultsAdapter.java │ │ └── ServiceDiscoveryExampleActivity.java │ │ ├── example4_characteristic │ │ ├── CharacteristicOperationExampleActivity.java │ │ └── advanced │ │ │ ├── AdvancedCharacteristicOperationExampleActivity.java │ │ │ ├── Presenter.java │ │ │ └── PresenterEvent.java │ │ ├── example5_rssi_periodic │ │ └── RssiPeriodicExampleActivity.java │ │ ├── example7_long_write │ │ └── LongWriteExampleActivity.java │ │ └── util │ │ ├── ConnectPermission.java │ │ ├── HexString.java │ │ ├── ScanExceptionHandler.java │ │ └── ScanPermission.java │ └── res │ ├── drawable │ └── ic_keyboard_arrow_right_24dp.xml │ ├── layout │ ├── activity_device.xml │ ├── activity_example1.xml │ ├── activity_example1a.xml │ ├── activity_example2.xml │ ├── activity_example3.xml │ ├── activity_example4.xml │ ├── activity_example4_advanced.xml │ ├── activity_example5.xml │ ├── activity_example6.xml │ ├── item_discovery_characteristic.xml │ └── item_discovery_service.xml │ ├── menu │ └── menu_scan.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-v21 │ └── styles.xml │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── settings.gradle └── site ├── RX-Android.png ├── polidea_logo.png ├── viking-large.jpeg └── viking-small.jpg /.buildscript/update_version_in_readmes.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Recommended pre-commit hook for people releasing RxAndroidBle 3 | # This script updates all README.md files with the current value of VERSION_NAME specified in 4 | # $root/gradle.properties when following conditions are met: 5 | # - this script is run on the release branch 6 | # - the VERSION_NAME has changed 7 | # - the VERSION_NAME is not a "SNAPSHOT" release 8 | 9 | # Check if on release branch 10 | current_branch="$(git branch --show-current)" 11 | release_branch='master' 12 | echo current_branch: "$current_branch", release_branch: "$release_branch" 13 | if [[ $current_branch != "$release_branch" ]]; then 14 | exit 0 15 | fi 16 | echo not equal 17 | 18 | # Check if VERSION_NAME changed 19 | this_script_path="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 20 | root_project_path="${this_script_path%/*}" 21 | git stash -m "PRE-COMMIT-VERSIONS-CHANGE-CHECK-PREPARE" --keep-index --include-untracked 22 | git stash -m "PRE-COMMIT-VERSIONS-CHANGE-CHECK" 23 | version_name_line=$(grep ^VERSION_NAME= "$root_project_path"/gradle.properties) 24 | version_name_old=${version_name_line##*=} 25 | git stash pop 26 | git add . 27 | git stash pop 28 | version_name_line=$(grep ^VERSION_NAME= "$root_project_path"/gradle.properties) 29 | version_name_new=${version_name_line##*=} 30 | if [[ $version_name_old -eq $version_name_new ]]; then 31 | exit 0 32 | fi 33 | 34 | # Check if VERSION_NAME is not SNAPSHOT 35 | if [[ $version_name_new == *"SNAPSHOT"* ]]; then 36 | exit 0 37 | fi 38 | 39 | # Update version for gradle and maven in all README.md files 40 | git stash -m "PRE-COMMIT-HOOK-STASH" --keep-index 41 | find "$root_project_path" -name README.md \ 42 | -exec sed -i '' \ 43 | -e "s~\(.*implementation .*:\)\(.*\)\(\\\"\)~\1$version_name_new\3~g" \ 44 | -e "s~\(.*\)\(.*\)\(<\/version>\)~\1$version_name_new\3~g" {} ";" \ 45 | -exec git add {} ";" 46 | git stash pop 47 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Handle line endings automatically for files detected as text 2 | # and leave all files detected as binary untouched. 3 | * text=auto 4 | 5 | # Never modify line endings of our bash scripts 6 | *.sh -crlf 7 | 8 | # 9 | # The above will handle all files NOT found below 10 | # 11 | # These files are text and should be normalized (Convert crlf => lf) 12 | *.css text 13 | *.gradle text 14 | *.html text 15 | *.java text 16 | *.js text 17 | *.json text 18 | *.kt text 19 | *.md text 20 | *.properties text 21 | *.txt text 22 | *.xml text 23 | *.yml text 24 | 25 | # These files are binary and should be left untouched 26 | # (binary is macro for -text -diff) 27 | *.class binary 28 | *.jar binary 29 | *.gif binary 30 | *.jpg binary 31 | *.png binary 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Disclaimer (to save your and our time) 2 | You intend to post an issue that is not a bug report nor a feature request. Great! We are always happy and open to discuss how 3 | the library or it's documentation can be improved. 4 | 5 | However if you are new to Bluetooth Low Energy and do not know how to accomplish what you want — this is not the best place to 6 | seek knowledge. It will be quicker for you and will save our time if you consider using Google first as there are plenty of 7 | very good articles out there. 8 | 9 | In case you are not very familiar with RxJava or how could you use RxAndroidBle in your use case you should search 10 | www.stackoverflow.com for tag `rxandroidble` as there are already quite a few questions asked (and answered!) which could 11 | address your issue. 12 | 13 | After reading the above disclaimer you can delete it. :) 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Smartphone (please complete the following information):** 24 | - Device: [e.g. Google Pixel] 25 | - OS: [e.g. Android 10] 26 | - Library version: [e.g. 1.10.5] 27 | 28 | **Logs from the application when bug occurs (this will greatly help in quick understanding the problem)** 29 | To turn on logs use: 30 | ``` 31 | RxBleClient.updateLogOptions(new LogOptions.Builder() 32 | .setLogLevel(LogConstants.DEBUG) 33 | .setMacAddressLogSetting(LogConstants.MAC_ADDRESS_FULL) 34 | .setUuidsLogSetting(LogConstants.UUIDS_FULL) 35 | .setShouldLogAttributeValues(true) 36 | .build() 37 | ); 38 | ``` 39 | ``` 40 | // please paste the logs here 41 | ``` 42 | 43 | **Additional context** 44 | Add any other context about the problem here. 45 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement, idea 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/gradle-actions.yml: -------------------------------------------------------------------------------- 1 | name: "Gradle Actions" 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | gradle_validation: 6 | name: "Validate Gradle Wrapper" 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: "Checkout Repository" 10 | uses: actions/checkout@v2 11 | - name: "Validate" 12 | uses: gradle/wrapper-validation-action@v1 13 | gradle_tasks: 14 | name: "Gradle Tasks" 15 | runs-on: ubuntu-latest 16 | needs: gradle_validation 17 | steps: 18 | - name: "Checkout Repository" 19 | uses: actions/checkout@v3 20 | - name: "Set up Android JDK environment" 21 | uses: actions/setup-java@v3.11.0 22 | with: 23 | distribution: 'adopt' 24 | java-version: '11' 25 | java-package: jdk 26 | - name: "Run Checkstyle" 27 | run: ./gradlew checkstyle 28 | - name: "Run Unit Tests — RxAndroidBle: RxJava2" 29 | run: ./gradlew :rxandroidble:testReleaseUnitTest 30 | - name: "Run Unit Tests — MockClient: RxJava2" 31 | run: ./gradlew :mockrxandroidble:testReleaseUnitTest 32 | - name: "Run Unit Tests — RxAndroidBle: RxJava3" 33 | run: ./gradlew :rxandroidble3:testReleaseUnitTest 34 | - name: "Run Unit Tests — MockClient: RxJava3" 35 | run: ./gradlew :mockrxandroidble3:testReleaseUnitTest 36 | - name: "Run Unit Tests — Sample Kotlin" 37 | run: ./gradlew :sample-kotlin:testReleaseUnitTest 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .gradle 3 | local.properties 4 | *.iml 5 | /build 6 | dagger-compiler-shadow/build 7 | dagger-library-shadow/build 8 | rxandroidble3/src 9 | mockrxandroidble3/src 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: android 2 | 3 | android: 4 | components: 5 | - tools 6 | - build-tools-29.0.2 7 | - android-29 8 | - extra-android-m2repository 9 | licenses: 10 | - 'android-sdk-license-.+' 11 | 12 | jdk: 13 | - oraclejdk8 14 | 15 | after_success: 16 | - .buildscript/deploy_snapshot.sh 17 | 18 | notifications: 19 | email: false 20 | 21 | before_cache: 22 | - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock 23 | 24 | cache: 25 | directories: 26 | - $HOME/.m2 27 | - $HOME/.gradle/caches/ 28 | - $HOME/.gradle/wrapper/ 29 | 30 | script: 31 | - ./gradlew checkstyle assembleRelease test -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /checkstyle.gradle: -------------------------------------------------------------------------------- 1 | subprojects { project -> 2 | group = GROUP 3 | version = VERSION_NAME 4 | 5 | apply plugin: 'checkstyle' 6 | 7 | checkstyle { 8 | toolVersion = '8.20' 9 | } 10 | 11 | task checkstyle(type: Checkstyle) { 12 | configFile rootProject.file('checkstyle.xml') 13 | source 'src/main/java' 14 | ignoreFailures false 15 | showViolations true 16 | include '**/*.java' 17 | 18 | classpath = files() 19 | } 20 | } -------------------------------------------------------------------------------- /dagger-compiler-shadow/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | dependencies { 3 | classpath "gradle.plugin.com.github.johnrengelman:shadow:$rootProject.ext.shadowPluginVersion" 4 | } 5 | } 6 | 7 | apply plugin: 'com.github.johnrengelman.shadow' 8 | apply plugin: 'java' 9 | apply from: rootProject.file('gradle/shadow.gradle') 10 | 11 | import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer 12 | shadowJar { 13 | mustRunAfter jar 14 | transform(ServiceFileTransformer) 15 | classifier = '' 16 | } 17 | 18 | dependencies { 19 | implementation rootProject.ext.libs.dagger_compiler 20 | } 21 | 22 | java { 23 | sourceCompatibility = rootProject.ext.sourceCompatibilityVersion 24 | targetCompatibility = rootProject.ext.targetCompatibilityVersion 25 | } 26 | -------------------------------------------------------------------------------- /dagger-library-shadow/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | dependencies { 3 | classpath "gradle.plugin.com.github.johnrengelman:shadow:$rootProject.ext.shadowPluginVersion" 4 | } 5 | } 6 | 7 | apply plugin: 'com.github.johnrengelman.shadow' 8 | apply plugin: 'java' 9 | apply plugin: 'com.vanniktech.maven.publish' 10 | apply from: rootProject.file('gradle/shadow.gradle') 11 | apply from: rootProject.file('gradle/gradle-mvn-config.gradle') 12 | 13 | import com.github.jengelman.gradle.plugins.shadow.transformers.ServiceFileTransformer 14 | shadowJar { 15 | mustRunAfter jar 16 | transform(ServiceFileTransformer) 17 | classifier = '' 18 | } 19 | 20 | artifacts { 21 | archives shadowJar 22 | } 23 | 24 | shadowJar { 25 | // Dagger 2.25.4 introduced a file for tracking purposes. This can break apps using Dagger. 26 | // See https://github.com/dariuszseweryn/RxAndroidBle/issues/789 27 | // Source https://github.com/google/dagger/commit/709098caaf4c7124f5e5313c1aa9ab34fced0031 28 | exclude('META-INF/com.google.dagger_dagger.version') 29 | } 30 | 31 | dependencies { 32 | implementation rootProject.ext.libs.dagger 33 | } 34 | 35 | java { 36 | sourceCompatibility = rootProject.ext.sourceCompatibilityVersion 37 | targetCompatibility = rootProject.ext.targetCompatibilityVersion 38 | } 39 | 40 | task javadocs(type: Javadoc) { 41 | source = sourceSets.main.java.source 42 | classpath += configurations.compileClasspath 43 | } 44 | 45 | task javadocsJar(type: Jar, dependsOn: javadocs) { 46 | archiveClassifier.set('javadoc') 47 | from javadocs.destinationDir 48 | } 49 | 50 | task sourcesJar(type: Jar) { 51 | archiveClassifier.set('sources') 52 | from sourceSets.main.allSource 53 | } 54 | -------------------------------------------------------------------------------- /dagger-library-shadow/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=dagger-library-shadow 2 | POM_NAME=DaggerShadow 3 | POM_PACKAGING=jar 4 | POM_DESCRIPTION=Shadow library for Dagger dependency injection 5 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | GROUP=com.polidea.rxandroidble2 2 | VERSION_NAME=1.19.0 3 | 4 | POM_DESCRIPTION=RxJava backed support for Bluetooth Low Energy in Android 5 | 6 | POM_URL=https://github.com/dariuszseweryn/RxAndroidBle 7 | POM_SCM_URL=https://github.com/dariuszseweryn/RxAndroidBle 8 | POM_SCM_CONNECTION=scm:git:git://github.com/dariuszseweryn/RxAndroidBle.git 9 | POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/dariuszseweryn/RxAndroidBle.git 10 | 11 | POM_LICENCE_NAME=The Apache Software License, Version 2.0 12 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 13 | POM_LICENCE_DIST=repo 14 | 15 | POM_DEVELOPER_ID=dariuszseweryn 16 | POM_DEVELOPER_NAME=Dariusz Seweryn 17 | 18 | android.useAndroidX=true 19 | android.enableJetifier=false 20 | android.disableAutomaticComponentCreation=true 21 | 22 | org.gradle.jvmargs=-Xmx4g \ 23 | --add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ 24 | --add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \ 25 | --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED 26 | 27 | -------------------------------------------------------------------------------- /gradle/shadow-consumer-fix.gradle: -------------------------------------------------------------------------------- 1 | // Fixes problem with Android Studio not seeing shadowed libraries (dagger & javax) 2 | // Based on: https://github.com/johnrengelman/shadow/issues/264#issuecomment-814265839 3 | 4 | // Related change in rxandroidble build.gradle: 5 | // implementation project(path: ':dagger-library-shadow', transitive: false, configuration: 'shadow') 6 | // Become this: 7 | // implementation files(tasks.getByPath(':dagger-library-shadow:shadowJar').archiveFile) 8 | 9 | // Additional difference is that now :dagger-library-shadow is packed into :rxandroidble aar 10 | // and dagger-library-shadow no longer needs to be distributed to maven 11 | 12 | // Since the following references a subproject's task, 13 | // it will need to be run after the subproject has been evaluated. 14 | // You will likely need to put the following block toward the end 15 | // of your project's build.gradle for it to work. 16 | 17 | apply plugin: 'org.jetbrains.gradle.plugin.idea-ext' 18 | idea.project.settings { 19 | taskTriggers { 20 | beforeSync tasks.getByPath(':dagger-library-shadow:shadowJar') 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /gradle/shadow.gradle: -------------------------------------------------------------------------------- 1 | shadowJar { 2 | relocate 'dagger', 'bleshadow.dagger' 3 | relocate 'javax.inject', 'bleshadow.javax.inject' 4 | } -------------------------------------------------------------------------------- /gradle/src-gen-rxjava3-from-rxjava2.gradle: -------------------------------------------------------------------------------- 1 | // copies and transforms sources compatible with RxJava 2 to RxJava 3 2 | 3 | copy { 4 | from "../${project.name.substring(0, project.name.length() - 1)}/src" 5 | into 'src' 6 | includeEmptyDirs = false 7 | eachFile { 8 | name = name.replace('rxandroidble2', 'rxandroidble3') 9 | path = path.replace('rxandroidble2', 'rxandroidble3') 10 | filter { 11 | it.replace('rxandroidble2', 'rxandroidble3') 12 | .replaceAll('io\\.reactivex\\.([a-z]+)', 'io.reactivex.rxjava3.$1') 13 | .replaceAll('io\\.reactivex\\.([A-Z][a-z]+)', 'io.reactivex.rxjava3.core.$1') 14 | .replace('import io.reactivex.rxjava3.disposables.Disposables', 'import io.reactivex.rxjava3.disposables.Disposable') 15 | .replace('Disposables.fromAction', 'Disposable.fromAction') 16 | .replace('Disposables.empty()', 'Disposable.empty()') 17 | .replace('com.jakewharton.rxrelay2.BehaviorRelay', 'com.jakewharton.rxrelay3.BehaviorRelay') 18 | .replace('.startWith(', '.startWithItem(') 19 | .replace('import com.jakewharton.rxrelay2', 'import com.jakewharton.rxrelay3') 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dariuszseweryn/RxAndroidBle/596feb87346cabc7667e2760f347d379e406b757/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Jul 21 16:09:04 BST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip 7 | -------------------------------------------------------------------------------- /mockrxandroidble/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /mockrxandroidble/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply plugin: 'groovyx.android' 3 | apply plugin: 'com.vanniktech.maven.publish' 4 | apply from: rootProject.file('gradle/gradle-mvn-config.gradle') 5 | 6 | android { 7 | namespace 'com.polidea.rxandroidble2.mockrxandroidble' 8 | 9 | compileSdkVersion 32 10 | 11 | defaultConfig { 12 | minSdkVersion 18 13 | targetSdkVersion 32 14 | } 15 | 16 | compileOptions { 17 | sourceCompatibility rootProject.ext.targetCompatibilityVersion 18 | targetCompatibility rootProject.ext.targetCompatibilityVersion 19 | } 20 | 21 | testOptions { 22 | unitTests.returnDefaultValues = true 23 | unitTests.all { 24 | testLogging { 25 | events "passed", "skipped", "failed", "standardOut", "standardError" 26 | outputs.upToDateWhen { false } 27 | showStandardStreams = true 28 | } 29 | } 30 | } 31 | 32 | lint { 33 | abortOnError false 34 | } 35 | 36 | preBuild.dependsOn 'checkstyle' 37 | 38 | sourceSets { 39 | test { 40 | java { 41 | srcDir("../rxandroidble/src/test/java") // Add android stubs from main lib tests 42 | } 43 | } 44 | } 45 | } 46 | 47 | afterEvaluate { project -> 48 | // add explicit dependencies to compile groovy when testing 49 | testDebugUnitTest.dependsOn 'compileDebugUnitTestGroovyWithGroovyc' 50 | testReleaseUnitTest.dependsOn 'compileReleaseUnitTestGroovyWithGroovyc' 51 | } 52 | 53 | dependencies { 54 | 55 | // Test dependencies 56 | testImplementation rootProject.ext.libs.junit 57 | testImplementation rootProject.ext.libs.groovy 58 | testImplementation rootProject.ext.libs.spock 59 | api project(path: ':rxandroidble') 60 | api rootProject.ext.libs.rxjava2 61 | } 62 | -------------------------------------------------------------------------------- /mockrxandroidble/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=mockclient 2 | POM_NAME=MockingSupport 3 | POM_PACKAGING=aar 4 | POM_DESCRIPTION=Mocking support for RxAndroidBle library 5 | -------------------------------------------------------------------------------- /mockrxandroidble/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /mockrxandroidble/src/main/java/com/polidea/rxandroidble2/mockrxandroidble/RxBleScanResultMock.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.mockrxandroidble; 2 | 3 | import com.polidea.rxandroidble2.scan.IsConnectable; 4 | import com.polidea.rxandroidble2.RxBleDevice; 5 | import com.polidea.rxandroidble2.internal.ScanResultInterface; 6 | import com.polidea.rxandroidble2.scan.ScanCallbackType; 7 | import com.polidea.rxandroidble2.scan.ScanRecord; 8 | import com.polidea.rxandroidble2.scan.ScanResult; 9 | 10 | public class RxBleScanResultMock extends ScanResult implements ScanResultInterface { 11 | public RxBleScanResultMock(RxBleDevice bleDevice, int rssi, long timestampNanos, 12 | ScanCallbackType callbackType, ScanRecord scanRecord, 13 | IsConnectable isConnectable, Integer advertisingSid) { 14 | super(bleDevice, rssi, timestampNanos, callbackType, scanRecord, isConnectable, advertisingSid); 15 | } 16 | 17 | public String getAddress() { 18 | RxBleDevice device = getBleDevice(); 19 | return device == null ? null : device.getMacAddress(); 20 | } 21 | 22 | public String getDeviceName() { 23 | RxBleDevice device = getBleDevice(); 24 | return device == null ? null : device.getName(); 25 | } 26 | 27 | public ScanCallbackType getScanCallbackType() { 28 | return getCallbackType(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /mockrxandroidble/src/main/java/com/polidea/rxandroidble2/mockrxandroidble/callbacks/RxBleCharacteristicReadCallback.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.mockrxandroidble.callbacks; 2 | 3 | import android.bluetooth.BluetoothGattCharacteristic; 4 | 5 | import com.polidea.rxandroidble2.mockrxandroidble.callbacks.results.RxBleGattReadResultMock; 6 | import com.polidea.rxandroidble2.mockrxandroidble.RxBleDeviceMock; 7 | 8 | /** 9 | * An interface for a user callback for handling characteristic read requests 10 | */ 11 | public interface RxBleCharacteristicReadCallback { 12 | 13 | /** 14 | * Handles a read on a GATT characteristic 15 | * @param device the device being read from 16 | * @param characteristic the characteristic being read from 17 | * @param result the result handler 18 | * @throws Exception on error 19 | */ 20 | void handle(RxBleDeviceMock device, BluetoothGattCharacteristic characteristic, RxBleGattReadResultMock result) throws Exception; 21 | } 22 | -------------------------------------------------------------------------------- /mockrxandroidble/src/main/java/com/polidea/rxandroidble2/mockrxandroidble/callbacks/RxBleCharacteristicWriteCallback.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.mockrxandroidble.callbacks; 2 | 3 | import android.bluetooth.BluetoothGattCharacteristic; 4 | 5 | import com.polidea.rxandroidble2.mockrxandroidble.callbacks.results.RxBleGattWriteResultMock; 6 | import com.polidea.rxandroidble2.mockrxandroidble.RxBleDeviceMock; 7 | 8 | /** 9 | * An interface for a user callback for handling characteristic write requests 10 | */ 11 | public interface RxBleCharacteristicWriteCallback { 12 | 13 | /** 14 | * Handles a write on a GATT characteristic 15 | * @param device the device being written to 16 | * @param characteristic the characteristic being written to 17 | * @param data the data being written 18 | * @param result the result handler 19 | * @throws Exception on error 20 | */ 21 | void handle(RxBleDeviceMock device, 22 | BluetoothGattCharacteristic characteristic, 23 | byte[] data, 24 | RxBleGattWriteResultMock result) throws Exception; 25 | } 26 | -------------------------------------------------------------------------------- /mockrxandroidble/src/main/java/com/polidea/rxandroidble2/mockrxandroidble/callbacks/RxBleDescriptorReadCallback.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.mockrxandroidble.callbacks; 2 | 3 | import android.bluetooth.BluetoothGattDescriptor; 4 | 5 | import com.polidea.rxandroidble2.mockrxandroidble.callbacks.results.RxBleGattReadResultMock; 6 | import com.polidea.rxandroidble2.mockrxandroidble.RxBleDeviceMock; 7 | 8 | /** 9 | * An interface for a user callback for handling descriptor read requests 10 | */ 11 | public interface RxBleDescriptorReadCallback { 12 | 13 | /** 14 | * Handles a read on a GATT descriptor 15 | * @param device the device being read from 16 | * @param descriptor the descriptor being read from 17 | * @param result the result handler 18 | * @throws Exception on error 19 | */ 20 | void handle(RxBleDeviceMock device, BluetoothGattDescriptor descriptor, RxBleGattReadResultMock result) throws Exception; 21 | } 22 | -------------------------------------------------------------------------------- /mockrxandroidble/src/main/java/com/polidea/rxandroidble2/mockrxandroidble/callbacks/RxBleDescriptorWriteCallback.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.mockrxandroidble.callbacks; 2 | 3 | import android.bluetooth.BluetoothGattDescriptor; 4 | 5 | import com.polidea.rxandroidble2.mockrxandroidble.callbacks.results.RxBleGattWriteResultMock; 6 | import com.polidea.rxandroidble2.mockrxandroidble.RxBleDeviceMock; 7 | 8 | /** 9 | * An interface for a user callback for handling descriptor write requests 10 | */ 11 | public interface RxBleDescriptorWriteCallback { 12 | 13 | /** 14 | * Handles a write on a GATT descriptor 15 | * @param device the device being written to 16 | * @param descriptor the descriptor being written to 17 | * @param data the data being written 18 | * @param result the result handler 19 | * @throws Exception on error 20 | */ 21 | void handle(RxBleDeviceMock device, BluetoothGattDescriptor descriptor, byte[] data, RxBleGattWriteResultMock result) throws Exception; 22 | } 23 | -------------------------------------------------------------------------------- /mockrxandroidble/src/main/java/com/polidea/rxandroidble2/mockrxandroidble/callbacks/results/RxBleGattReadResultMock.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.mockrxandroidble.callbacks.results; 2 | 3 | /** 4 | * An interface for the user to respond to a read request 5 | */ 6 | public interface RxBleGattReadResultMock { 7 | /** 8 | * Respond with success 9 | * @param data The data to be returned in response to the read request 10 | */ 11 | void success(byte[] data); 12 | 13 | /** 14 | * Respond with failure 15 | * @param status The ATT status (error code) 16 | */ 17 | void failure(int status); 18 | 19 | /** 20 | * Trigger a disconnection 21 | * @param status The disconnection status (error code) 22 | */ 23 | void disconnect(int status); 24 | } 25 | -------------------------------------------------------------------------------- /mockrxandroidble/src/main/java/com/polidea/rxandroidble2/mockrxandroidble/callbacks/results/RxBleGattWriteResultMock.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.mockrxandroidble.callbacks.results; 2 | 3 | /** 4 | * An interface for the user to respond to a write request 5 | */ 6 | public interface RxBleGattWriteResultMock { 7 | /** 8 | * Respond with success 9 | */ 10 | void success(); 11 | 12 | /** 13 | * Respond with failure 14 | * @param status The ATT status (error code) 15 | */ 16 | void failure(int status); 17 | 18 | /** 19 | * Trigger a disconnection 20 | * @param status The disconnection status (error code) 21 | */ 22 | void disconnect(int status); 23 | } 24 | -------------------------------------------------------------------------------- /mockrxandroidble3/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /mockrxandroidble3/gradle.properties: -------------------------------------------------------------------------------- 1 | GROUP=com.polidea.rxandroidble3 2 | POM_ARTIFACT_ID=mockclient 3 | POM_NAME=MockingSupport 4 | POM_PACKAGING=aar 5 | POM_DESCRIPTION=Mocking support for RxAndroidBle library 6 | -------------------------------------------------------------------------------- /rxandroidble/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /rxandroidble/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_ARTIFACT_ID=rxandroidble 2 | POM_NAME=RxAndroidBle 3 | POM_PACKAGING=aar 4 | -------------------------------------------------------------------------------- /rxandroidble/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/dariuszseweryn/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # RxAndroidBle 20 | -keepclassmembers class * extends android.bluetooth.BluetoothGattCallback { 21 | # This method is hidden in AOSP sources and therefore Proguard strips it by default 22 | public void onConnectionUpdated(android.bluetooth.BluetoothGatt, int, int, int, int); 23 | } 24 | -------------------------------------------------------------------------------- /rxandroidble/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 7 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/ClientScope.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import bleshadow.javax.inject.Scope; 7 | 8 | @Scope 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface ClientScope { 11 | 12 | } -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/ConnectionParameters.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2; 2 | 3 | import androidx.annotation.IntRange; 4 | 5 | /** 6 | * An interface representing connection parameters update 7 | */ 8 | public interface ConnectionParameters { 9 | 10 | /** 11 | * Returns the connection interval used on this connection, 1.25ms unit. Valid range is from 6 (7.5ms) to 3200 (4000ms) 12 | * 13 | * @return the connection interval 14 | */ 15 | @IntRange(from = 6, to = 3200) 16 | int getConnectionInterval(); 17 | 18 | /** 19 | * Returns the slave latency for the connection in number of connection events. Valid range is from 0 to 499 20 | * 21 | * @return the slave latency 22 | */ 23 | @IntRange(from = 0, to = 499) 24 | int getSlaveLatency(); 25 | 26 | /** 27 | * Returns the supervision timeout for this connection, in 10ms unit. Valid range is from 10 (0.1s) to 3200 (32s) 28 | * 29 | * @return the supervision timeout 30 | */ 31 | @IntRange(from = 10, to = 3200) 32 | int getSupervisionTimeout(); 33 | } 34 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/HiddenBluetoothGattCallback.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2; 2 | 3 | import android.bluetooth.BluetoothGatt; 4 | 5 | /** 6 | * An interface that represents methods hidden in {@link android.bluetooth.BluetoothGattCallback} 7 | */ 8 | public interface HiddenBluetoothGattCallback { 9 | 10 | void onConnectionUpdated(BluetoothGatt gatt, int interval, int latency, int timeout, int status); 11 | } 12 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/NotificationSetupMode.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2; 2 | 3 | public enum NotificationSetupMode { 4 | /** 5 | * Configures notifications according to the standard. The `Observable` is emitted after both the system notification is set 6 | * and the CLIENT_CHARACTERISTIC_CONFIG descriptor was written so the notification is fully set up. If a device starts to notify 7 | * right after CLIENT_CHARACTERISTIC_CONFIG is written then some early notifications may be lost — see {@link #QUICK_SETUP} 8 | */ 9 | DEFAULT, 10 | /** 11 | * Compatibility mode for devices that do not contain CLIENT_CHARACTERISTIC_CONFIG 12 | */ 13 | COMPAT, 14 | /** 15 | * Configures notifications according to the standard but in contrast to the {@link #DEFAULT} mode the `Observable` is emitted 16 | * before the CLIENT_CHARACTERISTIC_CONFIG is written. The CLIENT_CHARACTERISTIC_CONFIG is scheduled for write when the emitted 17 | * `Observable` is subscribed for the first time and any potential error connected with the descriptor write will be emitted 18 | * on the parent Observable> as in {@link #DEFAULT} case and `Observable` will complete. This mode may be 19 | * useful for devices that start to notify right after CLIENT_CHARACTERISTIC_CONFIG write 20 | */ 21 | QUICK_SETUP 22 | } 23 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/PhyPair.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2; 2 | 3 | 4 | import androidx.annotation.NonNull; 5 | import androidx.annotation.Nullable; 6 | 7 | import java.util.Set; 8 | 9 | /** 10 | * The interface used for results of {@link RxBleConnection#readPhy()} and {@link RxBleConnection#setPreferredPhy(Set, Set, RxBlePhyOption)} 11 | */ 12 | public interface PhyPair { 13 | 14 | @NonNull 15 | RxBlePhy getTxPhy(); 16 | 17 | @NonNull 18 | RxBlePhy getRxPhy(); 19 | 20 | int hashCode(); 21 | 22 | boolean equals(@Nullable Object obj); 23 | } 24 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/RxBlePhy.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2; 2 | 3 | import android.bluetooth.BluetoothDevice; 4 | 5 | import com.polidea.rxandroidble2.internal.RxBlePhyImpl; 6 | 7 | import java.util.Set; 8 | 9 | /** 10 | * The interface used in {@link Set} for requesting PHY when calling {@link RxBleConnection#setPreferredPhy(Set, Set, RxBlePhyOption)} and 11 | * inside {@link PhyPair} as results of {@link RxBleConnection#readPhy()} and 12 | * {@link RxBleConnection#setPreferredPhy(Set, Set, RxBlePhyOption)} 13 | */ 14 | public interface RxBlePhy { 15 | 16 | /** 17 | * Bluetooth LE 1M PHY. 18 | */ 19 | RxBlePhy PHY_1M = RxBlePhyImpl.PHY_1M; 20 | 21 | /** 22 | * Bluetooth LE 2M PHY. 23 | */ 24 | RxBlePhy PHY_2M = RxBlePhyImpl.PHY_2M; 25 | 26 | /** 27 | * Bluetooth LE Coded PHY. 28 | */ 29 | RxBlePhy PHY_CODED = RxBlePhyImpl.PHY_CODED; 30 | 31 | /** 32 | * Corresponds to e.g. {@link BluetoothDevice#PHY_LE_CODED_MASK} 33 | */ 34 | int getMask(); 35 | 36 | /** 37 | * Corresponds to e.g. {@link BluetoothDevice#PHY_LE_CODED} 38 | */ 39 | int getValue(); 40 | } 41 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/RxBlePhyOption.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2; 2 | 3 | import com.polidea.rxandroidble2.internal.RxBlePhyOptionImpl; 4 | 5 | /** 6 | * Coding to be used when transmitting on the LE Coded PHY. 7 | */ 8 | public interface RxBlePhyOption { 9 | /** 10 | * No preferred coding. 11 | */ 12 | RxBlePhyOption PHY_OPTION_NO_PREFERRED = RxBlePhyOptionImpl.PHY_OPTION_NO_PREFERRED; 13 | 14 | /** 15 | * Prefer the S=2 coding. 16 | */ 17 | RxBlePhyOption PHY_OPTION_S2 = RxBlePhyOptionImpl.PHY_OPTION_S2; 18 | 19 | /** 20 | * Prefer the S=8 coding. 21 | */ 22 | RxBlePhyOption PHY_OPTION_S8 = RxBlePhyOptionImpl.PHY_OPTION_S8; 23 | 24 | /** 25 | * 26 | * @return integer value representing PHY option, e.g. {@link android.bluetooth.BluetoothDevice#PHY_OPTION_S2} 27 | */ 28 | int getValue(); 29 | } 30 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/RxBleScanResult.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2; 2 | 3 | import com.polidea.rxandroidble2.internal.logger.LoggerUtil; 4 | 5 | /** 6 | * Represents a scan result from Bluetooth LE scan. 7 | */ 8 | public class RxBleScanResult { 9 | 10 | private final RxBleDevice bleDevice; 11 | private final int rssi; 12 | private final byte[] scanRecord; 13 | 14 | public RxBleScanResult(RxBleDevice bleDevice, int rssi, byte[] scanRecords) { 15 | this.bleDevice = bleDevice; 16 | this.rssi = rssi; 17 | this.scanRecord = scanRecords; 18 | } 19 | 20 | /** 21 | * Returns {@link RxBleDevice} which is a handle for Bluetooth operations on a device. It may be used to establish connection, 22 | * get MAC address and/or get the device name. 23 | */ 24 | public RxBleDevice getBleDevice() { 25 | return bleDevice; 26 | } 27 | 28 | /** 29 | * Returns signal strength indication received during scan operation. 30 | * 31 | * @return the rssi value 32 | */ 33 | public int getRssi() { 34 | return rssi; 35 | } 36 | 37 | /** 38 | * The scan record of Bluetooth LE advertisement. 39 | * 40 | * @return Array of data containing full ADV packet. 41 | */ 42 | public byte[] getScanRecord() { 43 | return scanRecord; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "RxBleScanResult{" 49 | + "bleDevice=" + bleDevice 50 | + ", rssi=" + rssi 51 | + ", scanRecord=" + LoggerUtil.bytesToHex(scanRecord) 52 | + '}'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/Timeout.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | public class Timeout { 6 | 7 | public final TimeUnit timeUnit; 8 | public final long timeout; 9 | 10 | public Timeout(long timeout, TimeUnit timeUnit) { 11 | this.timeUnit = timeUnit; 12 | this.timeout = timeout; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/exceptions/BleAdapterDisabledException.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | public class BleAdapterDisabledException extends BleException { 4 | // Disconnection related to disabled Bluetooth adapter 5 | } 6 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/exceptions/BleAlreadyConnectedException.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | 4 | /** 5 | * An exception being emitted from an {@link io.reactivex.Observable} returned by the function 6 | * {@link com.polidea.rxandroidble2.RxBleDevice#establishConnection(boolean)} or other establishConnection() overloads when this kind 7 | * of observable was already subscribed and {@link com.polidea.rxandroidble2.RxBleConnection} is currently being established or active. 8 | * 9 | *

10 | * To prevent this exception from being emitted one must either:
11 | * * always unsubscribe from the above mentioned Observable before subscribing again
12 | * * {@link io.reactivex.Observable#share()} or {@link io.reactivex.Observable#publish()} the above mentioned 13 | * Observable so it will be subscribed only once 14 | *

15 | */ 16 | public class BleAlreadyConnectedException extends BleException { 17 | 18 | public BleAlreadyConnectedException(String macAddress) { 19 | super("Already connected to device with MAC address " + macAddress); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/exceptions/BleCharacteristicNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | import java.util.UUID; 4 | 5 | /** 6 | * An exception being emitted from {@link com.polidea.rxandroidble2.RxBleDeviceServices#getCharacteristic(UUID)} or any 7 | * {@link com.polidea.rxandroidble2.RxBleConnection} function that accepts {@link UUID} in case the said UUID is not found 8 | * in the discovered device services. 9 | */ 10 | public class BleCharacteristicNotFoundException extends BleException { 11 | 12 | private final UUID characteristicUUID; 13 | 14 | public BleCharacteristicNotFoundException(UUID characteristicUUID) { 15 | super("Characteristic not found with UUID " + characteristicUUID); 16 | this.characteristicUUID = characteristicUUID; 17 | } 18 | 19 | /** 20 | * Returns characteristic UUID that has not been found 21 | * @deprecated Use {@link #getCharacteristicUUID()} 22 | * 23 | * @return the UUID 24 | */ 25 | @Deprecated 26 | public UUID getCharactersisticUUID() { 27 | return characteristicUUID; 28 | } 29 | 30 | /** 31 | * Returns characteristic UUID that has not been found 32 | * 33 | * @return the UUID 34 | */ 35 | public UUID getCharacteristicUUID() { 36 | return characteristicUUID; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/exceptions/BleConflictingNotificationAlreadySetException.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | import java.util.UUID; 4 | 5 | /** 6 | * An exception being emitted from {@link com.polidea.rxandroidble2.RxBleConnection#setupNotification(UUID)}/ 7 | * {@link com.polidea.rxandroidble2.RxBleConnection#setupIndication(UUID)} or overloads in case when an opposite 8 | * type (indication/notification) was already set. 9 | * 10 | * To make it possible to set this type of notification/indication the previous one must be unsubscribed. 11 | */ 12 | public class BleConflictingNotificationAlreadySetException extends BleException { 13 | 14 | private final UUID characteristicUuid; 15 | 16 | private final boolean alreadySetIsIndication; 17 | 18 | public BleConflictingNotificationAlreadySetException(UUID characteristicUuid, boolean alreadySetIsIndication) { 19 | super("Characteristic " + characteristicUuid 20 | + " notification already set to " + (alreadySetIsIndication ? "indication" : "notification")); 21 | this.characteristicUuid = characteristicUuid; 22 | this.alreadySetIsIndication = alreadySetIsIndication; 23 | } 24 | 25 | public UUID getCharacteristicUuid() { 26 | return characteristicUuid; 27 | } 28 | 29 | public boolean indicationAlreadySet() { 30 | return alreadySetIsIndication; 31 | } 32 | 33 | public boolean notificationAlreadySet() { 34 | return !alreadySetIsIndication; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/exceptions/BleDescriptorNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | import java.util.UUID; 4 | 5 | public class BleDescriptorNotFoundException extends BleException { 6 | 7 | private final UUID descriptorUUID; 8 | 9 | public BleDescriptorNotFoundException(UUID descriptorUUID) { 10 | super("Descriptor not found with UUID " + descriptorUUID); 11 | this.descriptorUUID = descriptorUUID; 12 | } 13 | 14 | public UUID getDescriptorUUID() { 15 | return descriptorUUID; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/exceptions/BleException.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | /** 4 | * Base class of exceptions in this project. 5 | */ 6 | public class BleException extends RuntimeException { 7 | 8 | public BleException() { 9 | super(); 10 | } 11 | 12 | public BleException(String message) { 13 | super(message); 14 | } 15 | 16 | public BleException(Throwable throwable) { 17 | super(throwable); 18 | } 19 | 20 | public BleException(String message, Throwable throwable) { 21 | super(message, throwable); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/exceptions/BleGattCallbackTimeoutException.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | 4 | import android.bluetooth.BluetoothGatt; 5 | 6 | /** 7 | * This exception is used when a call on a {@link BluetoothGatt} has returned true (succeeded) but the corresponding 8 | * {@link android.bluetooth.BluetoothGattCallback} callback was not called after a certain time (usually 30 seconds) 9 | * which is considered a Android OS BLE Stack misbehaviour 10 | */ 11 | public class BleGattCallbackTimeoutException extends BleGattException { 12 | 13 | public BleGattCallbackTimeoutException(BluetoothGatt gatt, BleGattOperationType bleGattOperationType) { 14 | super(gatt, bleGattOperationType); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/exceptions/BleGattCannotStartException.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | import android.bluetooth.BluetoothGatt; 4 | 5 | /** 6 | * An exception emitted from {@link com.polidea.rxandroidble2.RxBleConnection} functions when the underlying {@link BluetoothGatt} 7 | * returns `false` from {@link BluetoothGatt#readRemoteRssi()} or other functions associated with device interaction. 8 | */ 9 | public class BleGattCannotStartException extends BleGattException { 10 | 11 | @Deprecated 12 | public BleGattCannotStartException(BleGattOperationType bleGattOperationType) { 13 | super(null, bleGattOperationType); 14 | } 15 | 16 | public BleGattCannotStartException(BluetoothGatt gatt, BleGattOperationType bleGattOperationType) { 17 | super(gatt, bleGattOperationType); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/exceptions/BleGattCharacteristicException.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | 4 | import android.bluetooth.BluetoothGatt; 5 | import android.bluetooth.BluetoothGattCharacteristic; 6 | 7 | /** 8 | * An exception being emitted from {@link com.polidea.rxandroidble2.RxBleConnection#readCharacteristic(BluetoothGattCharacteristic)} 9 | * or other characteristic related observables when the {@link android.bluetooth.BluetoothGattCallback} is called with status other than 10 | * {@link android.bluetooth.BluetoothGatt#GATT_SUCCESS} 11 | */ 12 | public class BleGattCharacteristicException extends BleGattException { 13 | 14 | public final BluetoothGattCharacteristic characteristic; 15 | 16 | public BleGattCharacteristicException( 17 | BluetoothGatt gatt, 18 | BluetoothGattCharacteristic characteristic, 19 | int status, 20 | BleGattOperationType bleGattOperationType 21 | ) { 22 | super(gatt, status, bleGattOperationType); 23 | this.characteristic = characteristic; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/exceptions/BleGattDescriptorException.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | 4 | import android.bluetooth.BluetoothGatt; 5 | import android.bluetooth.BluetoothGattDescriptor; 6 | 7 | public class BleGattDescriptorException extends BleGattException { 8 | 9 | public final BluetoothGattDescriptor descriptor; 10 | 11 | public BleGattDescriptorException( 12 | BluetoothGatt gatt, 13 | BluetoothGattDescriptor descriptor, 14 | int status, 15 | BleGattOperationType bleGattOperationType 16 | ) { 17 | super(gatt, status, bleGattOperationType); 18 | this.descriptor = descriptor; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/exceptions/BleServiceNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | import java.util.UUID; 4 | 5 | /** 6 | * An exception emitted from {@link com.polidea.rxandroidble2.RxBleDeviceServices} or {@link com.polidea.rxandroidble2.RxBleConnection} 7 | * functions that take service's {@link UUID} as a param in case the service with the corresponding UUID is not found in the discovered 8 | * services. 9 | */ 10 | public class BleServiceNotFoundException extends BleException { 11 | 12 | private final UUID serviceUUID; 13 | 14 | public BleServiceNotFoundException(UUID serviceUUID) { 15 | super("BLE Service not found with UUID " + serviceUUID); 16 | this.serviceUUID = serviceUUID; 17 | } 18 | 19 | public UUID getServiceUUID() { 20 | return serviceUUID; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/helpers/AdvertisedServiceUUIDExtractor.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.helpers; 2 | 3 | 4 | import androidx.annotation.NonNull; 5 | import androidx.annotation.Nullable; 6 | 7 | import com.polidea.rxandroidble2.internal.util.ScanRecordParser; 8 | 9 | import java.util.Arrays; 10 | import java.util.HashSet; 11 | import java.util.List; 12 | import java.util.Set; 13 | import java.util.UUID; 14 | 15 | public class AdvertisedServiceUUIDExtractor { 16 | 17 | private final ScanRecordParser parser; 18 | 19 | public AdvertisedServiceUUIDExtractor() { 20 | parser = new ScanRecordParser(); 21 | } 22 | 23 | public List extractUUIDs(byte[] scanResult) { 24 | return parser.extractUUIDs(scanResult); 25 | } 26 | 27 | @NonNull 28 | public Set toDistinctSet(@Nullable UUID[] uuids) { 29 | if (uuids == null) uuids = new UUID[0]; 30 | return new HashSet<>(Arrays.asList(uuids)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/BleIllegalOperationException.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal; 2 | 3 | import androidx.annotation.RestrictTo; 4 | 5 | import java.util.UUID; 6 | 7 | /** 8 | * This exception is thrown when a non-supported operation has been requested upon a characteristic, eg. write operation on a 9 | * characteristic with only read property. 10 | */ 11 | public class BleIllegalOperationException extends RuntimeException { 12 | 13 | public final UUID characteristicUUID; 14 | public final @BluetoothGattCharacteristicProperty int supportedProperties; 15 | public final @BluetoothGattCharacteristicProperty int neededProperties; 16 | 17 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 18 | public BleIllegalOperationException(String message, 19 | UUID characteristicUUID, 20 | @BluetoothGattCharacteristicProperty int supportedProperties, 21 | @BluetoothGattCharacteristicProperty int neededProperties) { 22 | super(message); 23 | this.characteristicUUID = characteristicUUID; 24 | this.supportedProperties = supportedProperties; 25 | this.neededProperties = neededProperties; 26 | } 27 | } -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/BluetoothGattCharacteristicProperty.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal; 2 | 3 | import android.bluetooth.BluetoothGattCharacteristic; 4 | import androidx.annotation.IntDef; 5 | 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | 9 | /** 10 | * Annotation denoting that annotated int is either one or combination of flags describing characteristic properties 11 | * from {@link BluetoothGattCharacteristic}. 12 | */ 13 | @Retention(RetentionPolicy.SOURCE) 14 | @IntDef(flag = true, 15 | value = {BluetoothGattCharacteristic.PROPERTY_READ, 16 | BluetoothGattCharacteristic.PROPERTY_BROADCAST, 17 | BluetoothGattCharacteristic.PROPERTY_WRITE, 18 | BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, 19 | BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE, 20 | BluetoothGattCharacteristic.PROPERTY_INDICATE, 21 | BluetoothGattCharacteristic.PROPERTY_NOTIFY}) 22 | public @interface BluetoothGattCharacteristicProperty { } 23 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/DeviceComponent.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal; 2 | 3 | import static com.polidea.rxandroidble2.internal.DeviceModule.MAC_ADDRESS; 4 | 5 | import com.polidea.rxandroidble2.RxBleDevice; 6 | 7 | import bleshadow.dagger.BindsInstance; 8 | import bleshadow.dagger.Subcomponent; 9 | import bleshadow.javax.inject.Named; 10 | 11 | @DeviceScope 12 | @Subcomponent(modules = {DeviceModule.class}) 13 | public interface DeviceComponent { 14 | 15 | @Subcomponent.Builder 16 | interface Builder { 17 | DeviceComponent build(); 18 | 19 | @BindsInstance 20 | Builder macAddress(@Named(MAC_ADDRESS) String deviceMacAddress); 21 | } 22 | 23 | @DeviceScope 24 | RxBleDevice provideDevice(); 25 | } 26 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/DeviceScope.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import bleshadow.javax.inject.Scope; 7 | 8 | @Scope 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface DeviceScope { 11 | 12 | } -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/PhyPairImpl.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal; 2 | 3 | 4 | import androidx.annotation.NonNull; 5 | import androidx.annotation.Nullable; 6 | 7 | import com.polidea.rxandroidble2.PhyPair; 8 | import com.polidea.rxandroidble2.RxBlePhy; 9 | 10 | import java.util.Objects; 11 | 12 | public class PhyPairImpl implements PhyPair { 13 | public final RxBlePhy txPhy; 14 | public final RxBlePhy rxPhy; 15 | 16 | public PhyPairImpl(@NonNull final RxBlePhy txPhy, @NonNull final RxBlePhy rxPhy) { 17 | this.txPhy = txPhy; 18 | this.rxPhy = rxPhy; 19 | } 20 | 21 | @NonNull 22 | @Override 23 | public RxBlePhy getTxPhy() { 24 | return txPhy; 25 | } 26 | 27 | @NonNull 28 | @Override 29 | public RxBlePhy getRxPhy() { 30 | return rxPhy; 31 | } 32 | 33 | @Override 34 | public int hashCode() { 35 | return Objects.hash(rxPhy, txPhy); 36 | } 37 | 38 | @Override 39 | public boolean equals(@Nullable Object obj) { 40 | if (obj == this) return true; 41 | if (!(obj instanceof PhyPair)) return false; 42 | PhyPair phyPair = (PhyPair) obj; 43 | return txPhy.equals(phyPair.getTxPhy()) && rxPhy.equals(phyPair.getRxPhy()); 44 | } 45 | 46 | @NonNull 47 | @Override 48 | public String toString() { 49 | return "PhyPair{" 50 | + "txPhy=" + txPhy 51 | + ", rxPhy=" + rxPhy 52 | + '}'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/Priority.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal; 2 | 3 | 4 | /** 5 | * The class representing a priority with which an {@link QueueOperation} should be executed. 6 | * Used in @Override definedPriority() 7 | */ 8 | public class Priority { 9 | 10 | public static final Priority HIGH = new Priority(100); 11 | public static final Priority NORMAL = new Priority(50); 12 | public static final Priority LOW = new Priority(0); 13 | final int priority; 14 | 15 | private Priority(int priority) { 16 | 17 | this.priority = priority; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/ScanResultInterface.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal; 2 | 3 | import com.polidea.rxandroidble2.scan.ScanCallbackType; 4 | import com.polidea.rxandroidble2.scan.ScanRecord; 5 | 6 | public interface ScanResultInterface { 7 | /** 8 | * Get the address from the device 9 | */ 10 | String getAddress(); 11 | 12 | /** 13 | * Get the device name from the device (not from scan record) 14 | */ 15 | String getDeviceName(); 16 | 17 | /** 18 | * Get the RSSI of the scan result 19 | */ 20 | int getRssi(); 21 | 22 | /** 23 | * Get the scan record 24 | */ 25 | ScanRecord getScanRecord(); 26 | 27 | /** 28 | * Get the timestamp the scan result was produced 29 | */ 30 | long getTimestampNanos(); 31 | 32 | /** 33 | * Get the type of scan callback 34 | */ 35 | ScanCallbackType getScanCallbackType(); 36 | 37 | /** 38 | * Get the advertising set id 39 | */ 40 | Integer getAdvertisingSid(); 41 | } 42 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/cache/CacheEntry.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.cache; 2 | 3 | import com.polidea.rxandroidble2.internal.DeviceComponent; 4 | 5 | import java.util.Map; 6 | 7 | class CacheEntry implements Map.Entry { 8 | 9 | private final String string; 10 | private final DeviceComponentWeakReference deviceComponentWeakReference; 11 | 12 | CacheEntry(String string, DeviceComponentWeakReference deviceComponentWeakReference) { 13 | this.string = string; 14 | this.deviceComponentWeakReference = deviceComponentWeakReference; 15 | } 16 | 17 | @Override 18 | public boolean equals(Object o) { 19 | if (this == o) { 20 | return true; 21 | } 22 | if (!(o instanceof CacheEntry)) { 23 | return false; 24 | } 25 | 26 | CacheEntry that = (CacheEntry) o; 27 | 28 | return string.equals(that.getKey()) && deviceComponentWeakReference.equals(that.deviceComponentWeakReference); 29 | 30 | } 31 | 32 | @Override 33 | public String getKey() { 34 | return string; 35 | } 36 | 37 | @Override 38 | public DeviceComponent getValue() { 39 | return deviceComponentWeakReference.get(); 40 | } 41 | 42 | @Override 43 | public int hashCode() { 44 | int result = string.hashCode(); 45 | result = 31 * result + deviceComponentWeakReference.hashCode(); 46 | return result; 47 | } 48 | 49 | @Override 50 | public DeviceComponent setValue(DeviceComponent object) { 51 | throw new UnsupportedOperationException("Not implemented"); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/cache/DeviceComponentWeakReference.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.cache; 2 | 3 | import com.polidea.rxandroidble2.internal.DeviceComponent; 4 | 5 | import java.lang.ref.ReferenceQueue; 6 | import java.lang.ref.WeakReference; 7 | 8 | class DeviceComponentWeakReference extends WeakReference { 9 | 10 | public interface Provider { 11 | 12 | DeviceComponentWeakReference provide(DeviceComponent rxBleDevice); 13 | } 14 | 15 | DeviceComponentWeakReference(DeviceComponent device) { 16 | super(device); 17 | } 18 | 19 | @SuppressWarnings("unused") 20 | DeviceComponentWeakReference(DeviceComponent r, ReferenceQueue q) { 21 | super(r, q); 22 | } 23 | 24 | boolean contains(Object object) { 25 | final DeviceComponent thisDevice = get(); 26 | return object instanceof DeviceComponent 27 | && thisDevice != null 28 | && thisDevice.provideDevice() == ((DeviceComponent) object).provideDevice(); 29 | } 30 | 31 | @Override 32 | public boolean equals(Object o) { 33 | if (!(o instanceof WeakReference)) { 34 | return false; 35 | } 36 | WeakReference aWeakReference = (WeakReference) o; 37 | final DeviceComponent thisComponent = get(); 38 | final Object otherThing = aWeakReference.get(); 39 | return thisComponent != null 40 | && otherThing instanceof DeviceComponent 41 | && thisComponent.provideDevice().equals(((DeviceComponent) otherThing).provideDevice()); 42 | } 43 | 44 | @Override 45 | public int hashCode() { 46 | return get() != null ? get().hashCode() : 0; 47 | } 48 | 49 | public boolean isEmpty() { 50 | return get() == null; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/BluetoothGattProvider.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | import android.bluetooth.BluetoothGatt; 4 | import androidx.annotation.NonNull; 5 | 6 | import java.util.concurrent.atomic.AtomicReference; 7 | 8 | import bleshadow.javax.inject.Inject; 9 | 10 | @ConnectionScope 11 | public class BluetoothGattProvider { 12 | 13 | private final AtomicReference reference = new AtomicReference<>(); 14 | 15 | @Inject 16 | BluetoothGattProvider() { 17 | } 18 | 19 | /** 20 | * Provides most recent instance of the BluetoothGatt. Keep in mind that the gatt may not be available, hence null will be returned. 21 | */ 22 | public BluetoothGatt getBluetoothGatt() { 23 | return reference.get(); 24 | } 25 | 26 | /** 27 | * Updates GATT instance storage if it wasn't initialized previously. 28 | */ 29 | public void updateBluetoothGatt(@NonNull BluetoothGatt bluetoothGatt) { 30 | reference.compareAndSet(null, bluetoothGatt); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/ConnectionParametersImpl.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | import com.polidea.rxandroidble2.ConnectionParameters; 4 | 5 | 6 | public class ConnectionParametersImpl implements ConnectionParameters { 7 | 8 | private final int interval, latency, timeout; 9 | 10 | ConnectionParametersImpl(int interval, int latency, int timeout) { 11 | this.interval = interval; 12 | this.latency = latency; 13 | this.timeout = timeout; 14 | } 15 | 16 | @Override 17 | public int getConnectionInterval() { 18 | return interval; 19 | } 20 | 21 | @Override 22 | public int getSlaveLatency() { 23 | return latency; 24 | } 25 | 26 | @Override 27 | public int getSupervisionTimeout() { 28 | return timeout; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/ConnectionScope.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | import bleshadow.javax.inject.Scope; 7 | 8 | @Scope 9 | @Retention(RetentionPolicy.RUNTIME) 10 | public @interface ConnectionScope { 11 | 12 | } -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/ConnectionStateChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | 4 | import com.polidea.rxandroidble2.RxBleConnection; 5 | 6 | public interface ConnectionStateChangeListener { 7 | 8 | void onConnectionStateChange(RxBleConnection.RxBleConnectionState rxBleConnectionState); 9 | } 10 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/ConnectionSubscriptionWatcher.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | 4 | /** 5 | * Interface for all classes that should be called when the user subscribes to/disposes 6 | * {@link com.polidea.rxandroidble2.RxBleDevice#establishConnection(boolean)} 7 | * 8 | * The binding which injects the interface to a {@link ConnectorImpl} is in {@link ConnectionModule} 9 | */ 10 | public interface ConnectionSubscriptionWatcher { 11 | 12 | /** 13 | * Method to be called when the user subscribes to an individual 14 | * {@link com.polidea.rxandroidble2.RxBleDevice#establishConnection(boolean)} 15 | */ 16 | void onConnectionSubscribed(); 17 | 18 | /** 19 | * Method to be called when the user disposes an individual 20 | * {@link com.polidea.rxandroidble2.RxBleDevice#establishConnection(boolean)} 21 | */ 22 | void onConnectionUnsubscribed(); 23 | } 24 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/Connector.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | 4 | import com.polidea.rxandroidble2.ConnectionSetup; 5 | import com.polidea.rxandroidble2.RxBleConnection; 6 | 7 | import io.reactivex.Observable; 8 | 9 | public interface Connector { 10 | 11 | Observable prepareConnection(ConnectionSetup autoConnect); 12 | } 13 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/ConstantPayloadSizeLimit.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | 4 | import androidx.annotation.RestrictTo; 5 | 6 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 7 | class ConstantPayloadSizeLimit implements PayloadSizeLimitProvider { 8 | 9 | private final int limit; 10 | 11 | ConstantPayloadSizeLimit(int limit) { 12 | this.limit = limit; 13 | } 14 | 15 | @Override 16 | public int getPayloadSizeLimit() { 17 | return limit; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/DescriptorWriter.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | 4 | import android.bluetooth.BluetoothGattDescriptor; 5 | 6 | import com.polidea.rxandroidble2.internal.operations.OperationsProvider; 7 | import com.polidea.rxandroidble2.internal.serialization.ConnectionOperationQueue; 8 | 9 | import bleshadow.javax.inject.Inject; 10 | import io.reactivex.Completable; 11 | 12 | @ConnectionScope 13 | class DescriptorWriter { 14 | 15 | private final ConnectionOperationQueue operationQueue; 16 | private final OperationsProvider operationsProvider; 17 | 18 | @Inject 19 | DescriptorWriter(ConnectionOperationQueue operationQueue, OperationsProvider operationsProvider) { 20 | this.operationQueue = operationQueue; 21 | this.operationsProvider = operationsProvider; 22 | } 23 | 24 | Completable writeDescriptor(BluetoothGattDescriptor bluetoothGattDescriptor, byte[] data) { 25 | return operationQueue.queue(operationsProvider.provideWriteDescriptor(bluetoothGattDescriptor, data)) 26 | .ignoreElements(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/DisconnectAction.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | import com.polidea.rxandroidble2.internal.operations.DisconnectOperation; 4 | import com.polidea.rxandroidble2.internal.serialization.ClientOperationQueue; 5 | 6 | import bleshadow.javax.inject.Inject; 7 | 8 | import io.reactivex.internal.functions.Functions; 9 | 10 | @ConnectionScope 11 | class DisconnectAction implements ConnectionSubscriptionWatcher { 12 | 13 | private final ClientOperationQueue clientOperationQueue; 14 | private final DisconnectOperation operationDisconnect; 15 | 16 | @Inject 17 | DisconnectAction(ClientOperationQueue clientOperationQueue, DisconnectOperation operationDisconnect) { 18 | this.clientOperationQueue = clientOperationQueue; 19 | this.operationDisconnect = operationDisconnect; 20 | } 21 | 22 | @Override 23 | public void onConnectionSubscribed() { 24 | // do nothing 25 | } 26 | 27 | @Override 28 | public void onConnectionUnsubscribed() { 29 | clientOperationQueue 30 | .queue(operationDisconnect) 31 | .subscribe( 32 | Functions.emptyConsumer(), 33 | Functions.emptyConsumer() 34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/DisconnectionRouterInput.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | 4 | import android.bluetooth.BluetoothGatt; 5 | import com.polidea.rxandroidble2.exceptions.BleDisconnectedException; 6 | import com.polidea.rxandroidble2.exceptions.BleGattException; 7 | 8 | /** 9 | * Interface for routing causes of the disconnection. This may be for instance errors caused by 10 | * {@link android.bluetooth.BluetoothGattCallback#onConnectionStateChange(BluetoothGatt, int, int)} 11 | */ 12 | interface DisconnectionRouterInput { 13 | 14 | /** 15 | * Method to be called whenever a connection braking exception happens. 16 | * 17 | * @param disconnectedException the exception that happened 18 | */ 19 | void onDisconnectedException(BleDisconnectedException disconnectedException); 20 | 21 | /** 22 | * Method to be called whenever a BluetoothGattCallback.onConnectionStateChange() will get called with status != GATT_SUCCESS 23 | * 24 | * @param disconnectedGattException the exception that happened 25 | */ 26 | void onGattConnectionStateException(BleGattException disconnectedGattException); 27 | } 28 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/DisconnectionRouterOutput.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | 4 | import com.polidea.rxandroidble2.exceptions.BleException; 5 | 6 | import io.reactivex.Observable; 7 | 8 | /** 9 | * Interface to output disconnection error causes. It is used for instance to notify when the 10 | * {@link com.polidea.rxandroidble2.internal.serialization.ConnectionOperationQueue} should terminate because of a connection error 11 | */ 12 | public interface DisconnectionRouterOutput { 13 | 14 | /** 15 | * Function returning an Observable that will only emit value in case of a disconnection (will never emit an error) 16 | * 17 | * @return the Observable 18 | */ 19 | Observable asValueOnlyObservable(); 20 | 21 | /** 22 | * Function returning an Observable that will only throw error in case of a disconnection (will never emit value) 23 | * 24 | * @param the type of returned observable 25 | * @return the Observable 26 | */ 27 | Observable asErrorOnlyObservable(); 28 | } 29 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/IllegalOperationHandler.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | 4 | import android.bluetooth.BluetoothGattCharacteristic; 5 | import androidx.annotation.Nullable; 6 | 7 | import com.polidea.rxandroidble2.internal.BluetoothGattCharacteristicProperty; 8 | import com.polidea.rxandroidble2.internal.BleIllegalOperationException; 9 | 10 | /** 11 | * Handler for {@link IllegalOperationChecker#checkAnyPropertyMatches(BluetoothGattCharacteristic, int)} response. 12 | */ 13 | public abstract class IllegalOperationHandler { 14 | 15 | protected final IllegalOperationMessageCreator messageCreator; 16 | 17 | IllegalOperationHandler(IllegalOperationMessageCreator messageCreator) { 18 | this.messageCreator = messageCreator; 19 | } 20 | 21 | public abstract @Nullable BleIllegalOperationException handleMismatchData(BluetoothGattCharacteristic characteristic, 22 | @BluetoothGattCharacteristicProperty int neededProperties); 23 | } 24 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/IllegalOperationMessageCreator.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | import android.bluetooth.BluetoothGattCharacteristic; 4 | 5 | import com.polidea.rxandroidble2.internal.BluetoothGattCharacteristicProperty; 6 | import com.polidea.rxandroidble2.internal.logger.LoggerUtil; 7 | import com.polidea.rxandroidble2.internal.util.CharacteristicPropertiesParser; 8 | 9 | import java.util.Locale; 10 | 11 | import bleshadow.javax.inject.Inject; 12 | 13 | public class IllegalOperationMessageCreator { 14 | 15 | private final CharacteristicPropertiesParser propertiesParser; 16 | 17 | @Inject 18 | public IllegalOperationMessageCreator(CharacteristicPropertiesParser propertiesParser) { 19 | this.propertiesParser = propertiesParser; 20 | } 21 | 22 | @SuppressWarnings("WrongConstant") 23 | public String createMismatchMessage(BluetoothGattCharacteristic characteristic, 24 | @BluetoothGattCharacteristicProperty int neededProperties) { 25 | return String.format( 26 | Locale.getDefault(), 27 | "Characteristic %s supports properties: %s (%d) does not have any property matching %s (%d)", 28 | LoggerUtil.getUuidToLog(characteristic.getUuid()), 29 | propertiesParser.propertiesIntToString(characteristic.getProperties()), 30 | characteristic.getProperties(), 31 | propertiesParser.propertiesIntToString(neededProperties), 32 | neededProperties 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/ImmediateSerializedBatchAckStrategy.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | import com.polidea.rxandroidble2.RxBleConnection; 4 | 5 | import io.reactivex.Observable; 6 | 7 | public class ImmediateSerializedBatchAckStrategy implements RxBleConnection.WriteOperationAckStrategy { 8 | 9 | @Override 10 | public Observable apply(Observable objectObservable) { 11 | return objectObservable; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/LoggingIllegalOperationHandler.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | import android.bluetooth.BluetoothGattCharacteristic; 4 | 5 | import com.polidea.rxandroidble2.internal.BleIllegalOperationException; 6 | import com.polidea.rxandroidble2.internal.RxBleLog; 7 | 8 | import bleshadow.javax.inject.Inject; 9 | 10 | /** 11 | * Implementation of {@link IllegalOperationHandler}. This class logs a warning if there was no match between possessed 12 | * and requested properties. 13 | */ 14 | public class LoggingIllegalOperationHandler extends IllegalOperationHandler { 15 | 16 | @Inject 17 | public LoggingIllegalOperationHandler(IllegalOperationMessageCreator messageCreator) { 18 | super(messageCreator); 19 | } 20 | 21 | /** 22 | * This method logs a warning. 23 | * @param characteristic the characteristic upon which the operation was requested 24 | * @param neededProperties bitmask of properties needed by the operation 25 | */ 26 | @Override 27 | public BleIllegalOperationException handleMismatchData(BluetoothGattCharacteristic characteristic, int neededProperties) { 28 | RxBleLog.w(messageCreator.createMismatchMessage(characteristic, neededProperties)); 29 | return null; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/MtuBasedPayloadSizeLimit.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | 4 | import androidx.annotation.RestrictTo; 5 | 6 | import com.polidea.rxandroidble2.RxBleConnection; 7 | 8 | import bleshadow.javax.inject.Inject; 9 | import bleshadow.javax.inject.Named; 10 | 11 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 12 | @ConnectionScope 13 | class MtuBasedPayloadSizeLimit implements PayloadSizeLimitProvider { 14 | 15 | private final RxBleConnection rxBleConnection; 16 | private final int gattWriteMtuOverhead; 17 | private final int maxAttributeLength; 18 | 19 | @Inject 20 | MtuBasedPayloadSizeLimit(RxBleConnection rxBleConnection, 21 | @Named(ConnectionComponent.NamedInts.GATT_WRITE_MTU_OVERHEAD) int gattWriteMtuOverhead, 22 | @Named(ConnectionComponent.NamedInts.GATT_MAX_ATTR_LENGTH) int maxAttributeLength) { 23 | this.rxBleConnection = rxBleConnection; 24 | this.gattWriteMtuOverhead = gattWriteMtuOverhead; 25 | this.maxAttributeLength = maxAttributeLength; 26 | } 27 | 28 | @Override 29 | public int getPayloadSizeLimit() { 30 | int maxWritePayloadForMtu = rxBleConnection.getMtu() - gattWriteMtuOverhead; 31 | // See https://issuetracker.google.com/issues/307234027} 32 | return Math.min(maxWritePayloadForMtu, maxAttributeLength); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/MtuProvider.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | 4 | interface MtuProvider { 5 | 6 | int getMtu(); 7 | } 8 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/NoRetryStrategy.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | import com.polidea.rxandroidble2.RxBleConnection; 4 | 5 | import io.reactivex.Observable; 6 | import io.reactivex.functions.Function; 7 | 8 | public class NoRetryStrategy implements RxBleConnection.WriteOperationRetryStrategy { 9 | 10 | @Override 11 | public Observable apply(Observable observable) { 12 | return observable.flatMap(new Function>() { 13 | @Override 14 | public Observable apply(LongWriteFailure longWriteFailure) { 15 | return Observable.error(longWriteFailure.getCause()); 16 | } 17 | }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/PayloadSizeLimitProvider.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | 4 | import androidx.annotation.RestrictTo; 5 | 6 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 7 | public interface PayloadSizeLimitProvider { 8 | 9 | int getPayloadSizeLimit(); 10 | } 11 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/connection/ThrowingIllegalOperationHandler.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection; 2 | 3 | import android.bluetooth.BluetoothGattCharacteristic; 4 | 5 | import com.polidea.rxandroidble2.internal.BleIllegalOperationException; 6 | 7 | import bleshadow.javax.inject.Inject; 8 | 9 | /** 10 | * Implementation of {@link IllegalOperationHandler}. This class logs an error and returns {@link BleIllegalOperationException} if there 11 | * was no match between possessed and requested properties. 12 | */ 13 | public class ThrowingIllegalOperationHandler extends IllegalOperationHandler { 14 | 15 | @Inject 16 | public ThrowingIllegalOperationHandler(IllegalOperationMessageCreator messageCreator) { 17 | super(messageCreator); 18 | } 19 | 20 | /** 21 | * This method logs an error and returns a {@link BleIllegalOperationException}. 22 | * @param characteristic the characteristic upon which the operation was requested 23 | * @param neededProperties bitmask of properties needed by the operation 24 | */ 25 | @Override 26 | public BleIllegalOperationException handleMismatchData(BluetoothGattCharacteristic characteristic, int neededProperties) { 27 | String message = messageCreator.createMismatchMessage(characteristic, neededProperties); 28 | return new BleIllegalOperationException(message, 29 | characteristic.getUuid(), 30 | characteristic.getProperties(), 31 | neededProperties); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/MtuRequestOperation.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.operations; 2 | 3 | import android.bluetooth.BluetoothGatt; 4 | import androidx.annotation.RequiresApi; 5 | 6 | import com.polidea.rxandroidble2.exceptions.BleGattOperationType; 7 | import com.polidea.rxandroidble2.internal.SingleResponseOperation; 8 | import com.polidea.rxandroidble2.internal.connection.RxBleGattCallback; 9 | 10 | import bleshadow.javax.inject.Inject; 11 | 12 | import io.reactivex.Single; 13 | 14 | @RequiresApi(21 /* Build.VERSION_CODES.LOLLIPOP */) 15 | public class MtuRequestOperation extends SingleResponseOperation { 16 | 17 | private final int mtu; 18 | 19 | @Inject 20 | MtuRequestOperation( 21 | RxBleGattCallback rxBleGattCallback, 22 | BluetoothGatt bluetoothGatt, 23 | TimeoutConfiguration timeoutConfiguration, int requestedMtu) { 24 | super(bluetoothGatt, rxBleGattCallback, BleGattOperationType.ON_MTU_CHANGED, timeoutConfiguration); 25 | mtu = requestedMtu; 26 | } 27 | 28 | @Override 29 | protected Single getCallback(RxBleGattCallback rxBleGattCallback) { 30 | return rxBleGattCallback.getOnMtuChanged().firstOrError(); 31 | } 32 | 33 | @Override 34 | protected boolean startOperation(BluetoothGatt bluetoothGatt) { 35 | return bluetoothGatt.requestMtu(mtu); 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return "MtuRequestOperation{" 41 | + super.toString() 42 | + ", mtu=" + mtu 43 | + '}'; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/Operation.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.operations; 2 | 3 | 4 | import androidx.annotation.RestrictTo; 5 | 6 | import com.polidea.rxandroidble2.internal.Priority; 7 | import com.polidea.rxandroidble2.internal.serialization.QueueReleaseInterface; 8 | 9 | import io.reactivex.Observable; 10 | 11 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 12 | public interface Operation extends Comparable> { 13 | 14 | Observable run(QueueReleaseInterface queueReleaseInterface); 15 | 16 | Priority definedPriority(); 17 | } 18 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/PhyReadOperation.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.operations; 2 | 3 | import android.bluetooth.BluetoothGatt; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.annotation.RequiresApi; 7 | import androidx.annotation.RequiresPermission; 8 | 9 | import com.polidea.rxandroidble2.PhyPair; 10 | import com.polidea.rxandroidble2.exceptions.BleGattOperationType; 11 | import com.polidea.rxandroidble2.internal.SingleResponseOperation; 12 | import com.polidea.rxandroidble2.internal.connection.ConnectionModule; 13 | import com.polidea.rxandroidble2.internal.connection.RxBleGattCallback; 14 | 15 | import bleshadow.javax.inject.Inject; 16 | import bleshadow.javax.inject.Named; 17 | import io.reactivex.Single; 18 | 19 | @RequiresApi(26 /* Build.VERSION_CODES.O */) 20 | public class PhyReadOperation extends SingleResponseOperation { 21 | 22 | @Inject 23 | PhyReadOperation(RxBleGattCallback bleGattCallback, BluetoothGatt bluetoothGatt, 24 | @Named(ConnectionModule.OPERATION_TIMEOUT) TimeoutConfiguration timeoutConfiguration) { 25 | super(bluetoothGatt, bleGattCallback, BleGattOperationType.PHY_READ, timeoutConfiguration); 26 | } 27 | 28 | @Override 29 | protected Single getCallback(RxBleGattCallback rxBleGattCallback) { 30 | return rxBleGattCallback.getOnPhyRead().firstOrError(); 31 | } 32 | 33 | @Override 34 | @RequiresPermission("android.permission.BLUETOOTH_CONNECT") 35 | protected boolean startOperation(BluetoothGatt bluetoothGatt) { 36 | bluetoothGatt.readPhy(); 37 | return true; 38 | } 39 | 40 | @NonNull 41 | @Override 42 | public String toString() { 43 | return "PhyReadOperation{" + super.toString() + '}'; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/ReadRssiOperation.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.operations; 2 | 3 | import android.bluetooth.BluetoothGatt; 4 | 5 | import com.polidea.rxandroidble2.exceptions.BleGattOperationType; 6 | import com.polidea.rxandroidble2.internal.SingleResponseOperation; 7 | import com.polidea.rxandroidble2.internal.connection.ConnectionModule; 8 | import com.polidea.rxandroidble2.internal.connection.RxBleGattCallback; 9 | 10 | import bleshadow.javax.inject.Inject; 11 | import bleshadow.javax.inject.Named; 12 | 13 | import io.reactivex.Single; 14 | 15 | public class ReadRssiOperation extends SingleResponseOperation { 16 | 17 | @Inject 18 | ReadRssiOperation(RxBleGattCallback bleGattCallback, BluetoothGatt bluetoothGatt, 19 | @Named(ConnectionModule.OPERATION_TIMEOUT) TimeoutConfiguration timeoutConfiguration) { 20 | super(bluetoothGatt, bleGattCallback, BleGattOperationType.READ_RSSI, timeoutConfiguration); 21 | } 22 | 23 | @Override 24 | protected Single getCallback(RxBleGattCallback rxBleGattCallback) { 25 | return rxBleGattCallback.getOnRssiRead().firstOrError(); 26 | } 27 | 28 | @Override 29 | protected boolean startOperation(BluetoothGatt bluetoothGatt) { 30 | return bluetoothGatt.readRemoteRssi(); 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "ReadRssiOperation{" + super.toString() + '}'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/operations/TimeoutConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.operations; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import io.reactivex.Scheduler; 6 | 7 | 8 | public class TimeoutConfiguration { 9 | 10 | public final long timeout; 11 | public final TimeUnit timeoutTimeUnit; 12 | public final Scheduler timeoutScheduler; 13 | 14 | public TimeoutConfiguration(long timeout, TimeUnit timeoutTimeUnit, Scheduler timeoutScheduler) { 15 | this.timeout = timeout; 16 | this.timeoutTimeUnit = timeoutTimeUnit; 17 | this.timeoutScheduler = timeoutScheduler; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "{value=" + timeout 23 | + ", timeUnit=" + timeoutTimeUnit 24 | + '}'; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/AdvertisingSidExtractor.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | import android.bluetooth.le.ScanResult; 4 | 5 | import androidx.annotation.RestrictTo; 6 | 7 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 8 | public interface AdvertisingSidExtractor { 9 | Integer extract(ScanResult scanResult); 10 | } 11 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/AdvertisingSidExtractorApi18.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | import android.bluetooth.le.ScanResult; 4 | 5 | import bleshadow.javax.inject.Inject; 6 | 7 | public class AdvertisingSidExtractorApi18 implements AdvertisingSidExtractor { 8 | @Inject 9 | public AdvertisingSidExtractorApi18() { 10 | } 11 | 12 | @Override 13 | public Integer extract(ScanResult scanResult) { 14 | return null; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/AdvertisingSidExtractorApi26.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | import android.bluetooth.le.ScanResult; 4 | 5 | import androidx.annotation.RequiresApi; 6 | import androidx.annotation.RestrictTo; 7 | 8 | import bleshadow.javax.inject.Inject; 9 | 10 | @RequiresApi(26 /* Build.VERSION_CODES.O */) 11 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 12 | public class AdvertisingSidExtractorApi26 implements AdvertisingSidExtractor { 13 | @Inject 14 | public AdvertisingSidExtractorApi26() { 15 | } 16 | 17 | @Override 18 | public Integer extract(ScanResult scanResult) { 19 | return scanResult.getAdvertisingSid(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/EmulatedScanFilterMatcher.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | 4 | import androidx.annotation.Nullable; 5 | import java.util.Arrays; 6 | 7 | public class EmulatedScanFilterMatcher { 8 | 9 | @Nullable 10 | private final ScanFilterInterface[] scanFilters; 11 | private final boolean isEmpty; 12 | 13 | public EmulatedScanFilterMatcher(@Nullable ScanFilterInterface... scanFilters) { 14 | this.scanFilters = scanFilters; 15 | boolean tempIsEmpty = true; 16 | if (scanFilters != null && scanFilters.length != 0) { 17 | for (ScanFilterInterface scanFilter : scanFilters) { 18 | if (!scanFilter.isAllFieldsEmpty()) { 19 | tempIsEmpty = false; 20 | break; 21 | } 22 | } 23 | } 24 | isEmpty = tempIsEmpty; 25 | } 26 | 27 | public boolean matches(RxBleInternalScanResult internalScanResult) { 28 | if (scanFilters == null || scanFilters.length == 0) { 29 | return true; 30 | } 31 | 32 | for (ScanFilterInterface scanFilter : scanFilters) { 33 | if (scanFilter.matches(internalScanResult)) { 34 | return true; 35 | } 36 | } 37 | 38 | return false; 39 | } 40 | 41 | public boolean isEmpty() { 42 | return isEmpty; 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return "emulatedFilters=" + Arrays.toString(scanFilters); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/ExternalScanSettingsExtension.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | /** 4 | * An interface that describes what library extensions should be added to {@link com.polidea.rxandroidble2.scan.ScanSettings} 5 | */ 6 | public interface ExternalScanSettingsExtension> { 7 | 8 | boolean shouldCheckLocationProviderState(); 9 | 10 | // [DS 18.09.2019] Introduced to be sure that new ScanSettings properties will not break workaround introduced in 11 | // ScanSettingsBuilderImplApi21 12 | /** 13 | * Copies the current ScanSettings with changed callback type. 14 | * 15 | * @param callbackType callback type of the copied object 16 | * @return new ScanSettings object with copied properties and new callback type 17 | */ 18 | R copyWithCallbackType(int callbackType); 19 | 20 | interface Builder> { 21 | 22 | /** 23 | * Set whether a check if Location Services are (any Location Provider is) turned on before scheduling a BLE scan start. 24 | * Some Android devices will not return any {@link com.polidea.rxandroidble2.scan.ScanResult} if Location Services are 25 | * disabled. 26 | * 27 | * @param shouldCheck true if Location Services should be checked before the scan 28 | * @return the builder 29 | */ 30 | T setShouldCheckLocationServicesState(boolean shouldCheck); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/InternalToExternalScanResultConverter.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | 4 | import androidx.annotation.RestrictTo; 5 | 6 | import com.polidea.rxandroidble2.internal.RxBleDeviceProvider; 7 | import com.polidea.rxandroidble2.scan.ScanResult; 8 | 9 | import bleshadow.javax.inject.Inject; 10 | 11 | import io.reactivex.functions.Function; 12 | 13 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 14 | public class InternalToExternalScanResultConverter implements Function { 15 | 16 | private final RxBleDeviceProvider deviceProvider; 17 | 18 | @Inject 19 | public InternalToExternalScanResultConverter(RxBleDeviceProvider deviceProvider) { 20 | this.deviceProvider = deviceProvider; 21 | } 22 | 23 | @Override 24 | public ScanResult apply(RxBleInternalScanResult rxBleInternalScanResult) { 25 | return new ScanResult( 26 | deviceProvider.getBleDevice(rxBleInternalScanResult.getBluetoothDevice().getAddress()), 27 | rxBleInternalScanResult.getRssi(), 28 | rxBleInternalScanResult.getTimestampNanos(), 29 | rxBleInternalScanResult.getScanCallbackType(), 30 | rxBleInternalScanResult.getScanRecord(), 31 | rxBleInternalScanResult.isConnectable(), 32 | rxBleInternalScanResult.getAdvertisingSid() 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/IsConnectableChecker.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | import android.bluetooth.le.ScanResult; 4 | 5 | import androidx.annotation.RestrictTo; 6 | 7 | import com.polidea.rxandroidble2.scan.IsConnectable; 8 | 9 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 10 | public interface IsConnectableChecker { 11 | IsConnectable check(ScanResult scanResult); 12 | } 13 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/IsConnectableCheckerApi18.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | import android.bluetooth.le.ScanResult; 4 | 5 | import androidx.annotation.RestrictTo; 6 | 7 | import com.polidea.rxandroidble2.scan.IsConnectable; 8 | import bleshadow.javax.inject.Inject; 9 | 10 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 11 | public class IsConnectableCheckerApi18 implements IsConnectableChecker { 12 | 13 | @Inject 14 | public IsConnectableCheckerApi18() { 15 | } 16 | 17 | @Override 18 | public IsConnectable check(ScanResult scanResult) { 19 | return IsConnectable.LEGACY_UNKNOWN; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/IsConnectableCheckerApi26.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | import android.bluetooth.le.ScanResult; 4 | 5 | import androidx.annotation.RequiresApi; 6 | import androidx.annotation.RestrictTo; 7 | 8 | import com.polidea.rxandroidble2.scan.IsConnectable; 9 | import bleshadow.javax.inject.Inject; 10 | 11 | @RequiresApi(26 /* Build.VERSION_CODES.O */) 12 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 13 | public class IsConnectableCheckerApi26 implements IsConnectableChecker { 14 | 15 | @Inject 16 | public IsConnectableCheckerApi26() { 17 | } 18 | 19 | @Override 20 | public IsConnectable check(ScanResult scanResult) { 21 | return scanResult.isConnectable() ? IsConnectable.CONNECTABLE : IsConnectable.NOT_CONNECTABLE; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/RxBleInternalScanResultLegacy.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | import android.bluetooth.BluetoothDevice; 4 | 5 | public class RxBleInternalScanResultLegacy { 6 | 7 | private final BluetoothDevice bluetoothDevice; 8 | private final int rssi; 9 | private final byte[] scanRecord; 10 | 11 | public RxBleInternalScanResultLegacy(BluetoothDevice bleDevice, int rssi, byte[] scanRecords) { 12 | this.bluetoothDevice = bleDevice; 13 | this.rssi = rssi; 14 | this.scanRecord = scanRecords; 15 | } 16 | 17 | public BluetoothDevice getBluetoothDevice() { 18 | return bluetoothDevice; 19 | } 20 | 21 | public int getRssi() { 22 | return rssi; 23 | } 24 | 25 | public byte[] getScanRecord() { 26 | return scanRecord; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/ScanFilterInterface.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | import com.polidea.rxandroidble2.internal.ScanResultInterface; 4 | 5 | public interface ScanFilterInterface { 6 | 7 | boolean isAllFieldsEmpty(); 8 | 9 | boolean matches(ScanResultInterface scanResult); 10 | } 11 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/ScanPreconditionsVerifier.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | 4 | import com.polidea.rxandroidble2.exceptions.BleScanException; 5 | 6 | public interface ScanPreconditionsVerifier { 7 | 8 | void verify(boolean checkLocationProviderState) throws BleScanException; 9 | } 10 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/ScanPreconditionsVerifierApi18.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | 4 | import com.polidea.rxandroidble2.exceptions.BleScanException; 5 | import com.polidea.rxandroidble2.internal.util.LocationServicesStatus; 6 | import com.polidea.rxandroidble2.internal.util.RxBleAdapterWrapper; 7 | 8 | import bleshadow.javax.inject.Inject; 9 | 10 | @SuppressWarnings("WeakerAccess") 11 | public class ScanPreconditionsVerifierApi18 implements ScanPreconditionsVerifier { 12 | 13 | final RxBleAdapterWrapper rxBleAdapterWrapper; 14 | 15 | final LocationServicesStatus locationServicesStatus; 16 | 17 | @Inject 18 | public ScanPreconditionsVerifierApi18(RxBleAdapterWrapper rxBleAdapterWrapper, LocationServicesStatus locationServicesStatus) { 19 | this.rxBleAdapterWrapper = rxBleAdapterWrapper; 20 | this.locationServicesStatus = locationServicesStatus; 21 | } 22 | 23 | @Override 24 | public void verify(boolean checkLocationProviderState) { 25 | if (!rxBleAdapterWrapper.hasBluetoothAdapter()) { 26 | throw new BleScanException(BleScanException.BLUETOOTH_NOT_AVAILABLE); 27 | } else if (!rxBleAdapterWrapper.isBluetoothEnabled()) { 28 | throw new BleScanException(BleScanException.BLUETOOTH_DISABLED); 29 | } else if (!locationServicesStatus.isLocationPermissionOk()) { 30 | throw new BleScanException(BleScanException.LOCATION_PERMISSION_MISSING); 31 | } else if (checkLocationProviderState && !locationServicesStatus.isLocationProviderOk()) { 32 | throw new BleScanException(BleScanException.LOCATION_SERVICES_DISABLED); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/ScanSetup.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | 4 | import androidx.annotation.RestrictTo; 5 | 6 | import com.polidea.rxandroidble2.internal.operations.Operation; 7 | 8 | import io.reactivex.ObservableTransformer; 9 | 10 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 11 | public class ScanSetup { 12 | 13 | /** 14 | * The scan operation for the device API level 15 | */ 16 | public final Operation scanOperation; 17 | /** 18 | * Some functionality (behaviour) is not supported by hardware on older APIs. scanOperationBehaviourEmulatorTransformer is returned 19 | * by {@link ScanSetupBuilder} from combined emulation transformers provided by {@link ScanSettingsEmulator} 20 | */ 21 | public final ObservableTransformer scanOperationBehaviourEmulatorTransformer; 22 | 23 | public ScanSetup( 24 | Operation scanOperation, 25 | ObservableTransformer scanOperationBehaviourEmulatorTransformer 26 | ) { 27 | this.scanOperation = scanOperation; 28 | this.scanOperationBehaviourEmulatorTransformer = scanOperationBehaviourEmulatorTransformer; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/scan/ScanSetupBuilder.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan; 2 | 3 | 4 | import androidx.annotation.RestrictTo; 5 | import com.polidea.rxandroidble2.scan.ScanFilter; 6 | import com.polidea.rxandroidble2.scan.ScanSettings; 7 | 8 | @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) 9 | public interface ScanSetupBuilder { 10 | 11 | ScanSetup build(ScanSettings scanSettings, ScanFilter... scanFilters); 12 | } 13 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/serialization/ClientOperationQueue.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.serialization; 2 | 3 | import com.polidea.rxandroidble2.internal.operations.Operation; 4 | 5 | import io.reactivex.Observable; 6 | 7 | /** 8 | * Interface used for serialization of {@link Operation} execution. 9 | * 10 | * Native Android BLE API is asynchronous but does not queue operations on it's own. Operations like scanning, connecting, reading, writing 11 | * in order to be successfully started need to be serialized at different levels. 12 | *
13 | * i.e. When dealing with a {@link android.bluetooth.BluetoothGatt} each read and write needs to be synchronized but changing connection 14 | * priority does not. 15 | *
16 | * i.e.2 When starting to connect the {@link android.bluetooth.BluetoothGatt} the Android Stack does queue direct connections internally 17 | * but due to a bug the callback may not be called — serializing connection establishment does allow for proper timeout management in this 18 | * case 19 | */ 20 | public interface ClientOperationQueue { 21 | 22 | /** 23 | * Function that queues an {@link Operation} for execution. 24 | * @param operation the operation to execute 25 | * @param type of the operation values 26 | * @return the observable representing the operation execution 27 | */ 28 | Observable queue(Operation operation); 29 | } 30 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/serialization/ConnectionOperationQueue.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.serialization; 2 | 3 | import com.polidea.rxandroidble2.exceptions.BleException; 4 | 5 | /** 6 | * {@inheritDoc} 7 | */ 8 | public interface ConnectionOperationQueue extends ClientOperationQueue { 9 | 10 | /** 11 | * A method for terminating all operations that are still queued on the connection. 12 | * @param disconnectedException the exception to be passed to all queued operations subscribers 13 | */ 14 | void terminate(BleException disconnectedException); 15 | } 16 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/serialization/OperationPriorityFifoBlockingQueue.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.serialization; 2 | 3 | 4 | import java.util.concurrent.PriorityBlockingQueue; 5 | 6 | class OperationPriorityFifoBlockingQueue { 7 | 8 | private final PriorityBlockingQueue q = new PriorityBlockingQueue<>(); 9 | 10 | public void add(FIFORunnableEntry fifoRunnableEntry) { 11 | q.add(fifoRunnableEntry); 12 | } 13 | 14 | public FIFORunnableEntry take() throws InterruptedException { 15 | return q.take(); 16 | } 17 | 18 | public FIFORunnableEntry takeNow() { 19 | return q.poll(); 20 | } 21 | 22 | public boolean isEmpty() { 23 | return q.isEmpty(); 24 | } 25 | 26 | public boolean remove(FIFORunnableEntry fifoRunnableEntry) { 27 | for (FIFORunnableEntry entry : q) { 28 | if (entry == fifoRunnableEntry) { 29 | return q.remove(entry); 30 | } 31 | } 32 | return false; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/serialization/QueueAwaitReleaseInterface.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.serialization; 2 | 3 | 4 | /** 5 | * Interface used for blocking the Operation Queue before executing next command. 6 | * 7 | * @see QueueReleaseInterface 8 | * @see QueueSemaphore 9 | * @see ClientOperationQueue 10 | * @see ConnectionOperationQueue 11 | */ 12 | public interface QueueAwaitReleaseInterface { 13 | 14 | void awaitRelease() throws InterruptedException; 15 | } 16 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/serialization/QueueReleaseInterface.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.serialization; 2 | 3 | 4 | /** 5 | * Interface used for releasing the Operation Queue so it may proceed with execution of the next operation 6 | * 7 | * @see QueueAwaitReleaseInterface 8 | * @see QueueSemaphore 9 | * @see ClientOperationQueue 10 | * @see ConnectionOperationQueue 11 | */ 12 | public interface QueueReleaseInterface { 13 | 14 | void release(); 15 | } 16 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/serialization/QueueSemaphore.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.serialization; 2 | 3 | 4 | import com.polidea.rxandroidble2.internal.RxBleLog; 5 | import java.util.concurrent.atomic.AtomicBoolean; 6 | 7 | class QueueSemaphore implements QueueReleaseInterface, QueueAwaitReleaseInterface { 8 | 9 | private final AtomicBoolean isReleased = new AtomicBoolean(false); 10 | 11 | @Override 12 | public synchronized void awaitRelease() throws InterruptedException { 13 | while (!isReleased.get()) { 14 | try { 15 | wait(); 16 | } catch (InterruptedException e) { 17 | if (!isReleased.get()) { 18 | RxBleLog.w(e, "Queue's awaitRelease() has been interrupted abruptly " 19 | + "while it wasn't released by the release() method."); 20 | } 21 | } 22 | } 23 | } 24 | 25 | @Override 26 | public synchronized void release() { 27 | if (isReleased.compareAndSet(false, true)) { 28 | notify(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/serialization/RxBleThreadFactory.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.serialization; 2 | 3 | import io.reactivex.internal.schedulers.NonBlockingThread; 4 | import java.util.concurrent.ThreadFactory; 5 | import java.util.concurrent.atomic.AtomicLong; 6 | 7 | 8 | public class RxBleThreadFactory extends AtomicLong implements ThreadFactory { 9 | 10 | @Override 11 | public Thread newThread(Runnable r) { 12 | String name = "RxBleThread-" + incrementAndGet(); 13 | Thread t = new RxBleNonBlockingThread(r, name); 14 | t.setPriority(Thread.NORM_PRIORITY); 15 | t.setDaemon(true); 16 | return t; 17 | } 18 | 19 | static final class RxBleNonBlockingThread extends Thread implements NonBlockingThread { 20 | RxBleNonBlockingThread(Runnable run, String name) { 21 | super(run, name); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/ActiveCharacteristicNotification.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util; 2 | 3 | 4 | import io.reactivex.Observable; 5 | 6 | public class ActiveCharacteristicNotification { 7 | 8 | public final Observable> notificationObservable; 9 | 10 | public final boolean isIndication; 11 | 12 | public ActiveCharacteristicNotification(Observable> notificationObservable, boolean isIndication) { 13 | this.notificationObservable = notificationObservable; 14 | this.isIndication = isIndication; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/BluetoothManagerWrapper.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util; 2 | 3 | import android.bluetooth.BluetoothDevice; 4 | import android.bluetooth.BluetoothManager; 5 | import android.bluetooth.BluetoothProfile; 6 | 7 | import java.util.List; 8 | 9 | import bleshadow.javax.inject.Inject; 10 | 11 | public class BluetoothManagerWrapper { 12 | 13 | private final BluetoothManager bluetoothManager; 14 | 15 | @Inject 16 | public BluetoothManagerWrapper(BluetoothManager bluetoothManager) { 17 | this.bluetoothManager = bluetoothManager; 18 | } 19 | 20 | public List getConnectedPeripherals() { 21 | return bluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/ByteAssociationUtil.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util; 2 | 3 | import android.bluetooth.BluetoothGattDescriptor; 4 | 5 | import java.util.UUID; 6 | 7 | import io.reactivex.functions.Function; 8 | import io.reactivex.functions.Predicate; 9 | 10 | public class ByteAssociationUtil { 11 | 12 | private ByteAssociationUtil() { 13 | } 14 | 15 | public static Predicate> characteristicUUIDPredicate(final UUID characteristicUUID) { 16 | return new Predicate>() { 17 | @Override 18 | public boolean test(ByteAssociation uuidPair) { 19 | return uuidPair.first.equals(characteristicUUID); 20 | } 21 | }; 22 | } 23 | 24 | public static Function, byte[]> getBytesFromAssociation() { 25 | return new Function, byte[]>() { 26 | @Override 27 | public byte[] apply(ByteAssociation byteAssociation) { 28 | return byteAssociation.second; 29 | } 30 | }; 31 | } 32 | 33 | public static Predicate> 34 | descriptorPredicate(final BluetoothGattDescriptor bluetoothGattDescriptor) { 35 | return new Predicate>() { 36 | @Override 37 | public boolean test(ByteAssociation uuidPair) { 38 | return uuidPair.first.equals(bluetoothGattDescriptor); 39 | } 40 | }; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/CharacteristicChangedEvent.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util; 2 | 3 | 4 | import java.util.Arrays; 5 | import java.util.UUID; 6 | 7 | public class CharacteristicChangedEvent extends CharacteristicNotificationId { 8 | 9 | public final byte[] data; 10 | 11 | public CharacteristicChangedEvent(UUID uuid, Integer instanceId, byte[] data) { 12 | super(uuid, instanceId); 13 | this.data = data; 14 | } 15 | 16 | @Override 17 | public boolean equals(Object o) { 18 | if (this == o) { 19 | return true; 20 | } 21 | if (!(o instanceof CharacteristicChangedEvent)) { 22 | return o instanceof CharacteristicNotificationId && super.equals(o); 23 | } 24 | if (!super.equals(o)) { 25 | return false; 26 | } 27 | 28 | CharacteristicChangedEvent that = (CharacteristicChangedEvent) o; 29 | 30 | return Arrays.equals(data, that.data); 31 | 32 | } 33 | 34 | @Override 35 | public int hashCode() { 36 | int result = super.hashCode(); 37 | result = 31 * result + Arrays.hashCode(data); 38 | return result; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "CharacteristicChangedEvent{" 44 | + "UUID=" + first.toString() 45 | + ", instanceId=" + second.toString() 46 | + ", data=" + Arrays.toString(data) 47 | + '}'; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/CharacteristicNotificationId.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util; 2 | 3 | 4 | import android.util.Pair; 5 | import java.util.UUID; 6 | 7 | public class CharacteristicNotificationId extends Pair { 8 | 9 | public CharacteristicNotificationId(UUID uuid, Integer instanceId) { 10 | super(uuid, instanceId); 11 | } 12 | 13 | @Override 14 | public String toString() { 15 | return "CharacteristicNotificationId{" 16 | + "UUID=" + first.toString() 17 | + ", instanceId=" + second.toString() 18 | + '}'; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/CheckerConnectPermission.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util; 2 | 3 | 4 | import com.polidea.rxandroidble2.ClientComponent; 5 | import com.polidea.rxandroidble2.ClientScope; 6 | 7 | import bleshadow.javax.inject.Inject; 8 | import bleshadow.javax.inject.Named; 9 | 10 | @ClientScope 11 | public class CheckerConnectPermission { 12 | 13 | private final CheckerPermission checkerPermission; 14 | private final String[][] connectPermissions; 15 | 16 | @Inject 17 | CheckerConnectPermission( 18 | CheckerPermission checkerPermission, 19 | @Named(ClientComponent.PlatformConstants.STRING_ARRAY_CONNECT_PERMISSIONS) String[][] connectPermissions 20 | ) { 21 | this.checkerPermission = checkerPermission; 22 | this.connectPermissions = connectPermissions; 23 | } 24 | 25 | public boolean isConnectRuntimePermissionGranted() { 26 | boolean allNeededPermissionsGranted = true; 27 | for (String[] neededPermissions : connectPermissions) { 28 | allNeededPermissionsGranted &= checkerPermission.isAnyPermissionGranted(neededPermissions); 29 | } 30 | return allNeededPermissionsGranted; 31 | } 32 | 33 | public String[] getRecommendedConnectRuntimePermissions() { 34 | int allPermissionsCount = 0; 35 | for (String[] permissionsArray : connectPermissions) { 36 | allPermissionsCount += permissionsArray.length; 37 | } 38 | String[] resultPermissions = new String[allPermissionsCount]; 39 | int i = 0; 40 | for (String[] permissionsArray : connectPermissions) { 41 | for (String permission : permissionsArray) { 42 | resultPermissions[i++] = permission; 43 | } 44 | } 45 | return resultPermissions; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/CheckerPermission.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageManager; 5 | import android.os.Process; 6 | 7 | import com.polidea.rxandroidble2.ClientScope; 8 | 9 | import java.util.HashSet; 10 | import java.util.Set; 11 | 12 | import bleshadow.javax.inject.Inject; 13 | 14 | @ClientScope 15 | public class CheckerPermission { 16 | 17 | private final Context context; 18 | private final Set grantedPermissions = new HashSet<>(); 19 | 20 | @Inject 21 | CheckerPermission(Context context) { 22 | this.context = context; 23 | } 24 | 25 | boolean isAnyPermissionGranted(String[] acceptablePermissions) { 26 | for (String acceptablePermission : acceptablePermissions) { 27 | if (isPermissionGranted(acceptablePermission)) { 28 | return true; 29 | } 30 | } 31 | return false; 32 | } 33 | 34 | /** 35 | * Copied from android.support.v4.content.ContextCompat for backwards compatibility 36 | * @param permission the permission to check 37 | * @return true is granted 38 | */ 39 | private boolean isPermissionGranted(String permission) { 40 | if (permission == null) { 41 | throw new IllegalArgumentException("permission is null"); 42 | } 43 | 44 | if (grantedPermissions.contains(permission)) { 45 | return true; 46 | } 47 | 48 | boolean isGranted = context.checkPermission(permission, Process.myPid(), Process.myUid()) == PackageManager.PERMISSION_GRANTED; 49 | 50 | if (isGranted) { 51 | grantedPermissions.add(permission); 52 | } 53 | 54 | return isGranted; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/CheckerScanPermission.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util; 2 | 3 | 4 | import com.polidea.rxandroidble2.ClientComponent; 5 | import com.polidea.rxandroidble2.ClientScope; 6 | 7 | import bleshadow.javax.inject.Inject; 8 | import bleshadow.javax.inject.Named; 9 | 10 | @ClientScope 11 | public class CheckerScanPermission { 12 | 13 | private final CheckerPermission checkerPermission; 14 | private final String[][] scanPermissions; 15 | 16 | @Inject 17 | CheckerScanPermission( 18 | CheckerPermission checkerPermission, 19 | @Named(ClientComponent.PlatformConstants.STRING_ARRAY_SCAN_PERMISSIONS) String[][] scanPermissions 20 | ) { 21 | this.checkerPermission = checkerPermission; 22 | this.scanPermissions = scanPermissions; 23 | } 24 | 25 | public boolean isScanRuntimePermissionGranted() { 26 | boolean allNeededPermissionsGranted = true; 27 | for (String[] neededPermissions : scanPermissions) { 28 | allNeededPermissionsGranted &= checkerPermission.isAnyPermissionGranted(neededPermissions); 29 | } 30 | return allNeededPermissionsGranted; 31 | } 32 | 33 | public String[] getRecommendedScanRuntimePermissions() { 34 | int allPermissionsCount = 0; 35 | for (String[] permissionsArray : scanPermissions) { 36 | allPermissionsCount += permissionsArray.length; 37 | } 38 | String[] resultPermissions = new String[allPermissionsCount]; 39 | int i = 0; 40 | for (String[] permissionsArray : scanPermissions) { 41 | for (String permission : permissionsArray) { 42 | resultPermissions[i++] = permission; 43 | } 44 | } 45 | return resultPermissions; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/LocationServicesStatus.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util; 2 | 3 | 4 | public interface LocationServicesStatus { 5 | 6 | boolean isLocationPermissionOk(); 7 | boolean isLocationProviderOk(); 8 | } 9 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/LocationServicesStatusApi18.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util; 2 | 3 | import bleshadow.javax.inject.Inject; 4 | 5 | public class LocationServicesStatusApi18 implements LocationServicesStatus { 6 | 7 | @Inject 8 | LocationServicesStatusApi18() { 9 | 10 | } 11 | 12 | public boolean isLocationPermissionOk() { 13 | return true; 14 | } 15 | 16 | public boolean isLocationProviderOk() { 17 | return true; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/internal/util/ObservableUtil.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util; 2 | 3 | 4 | import io.reactivex.Observable; 5 | import io.reactivex.ObservableTransformer; 6 | 7 | public class ObservableUtil { 8 | 9 | private static final ObservableTransformer IDENTITY_TRANSFORMER 10 | = new ObservableTransformer() { 11 | @Override 12 | public Observable apply(Observable rxBleInternalScanResultObservable) { 13 | return rxBleInternalScanResultObservable; 14 | } 15 | }; 16 | 17 | private ObservableUtil() { 18 | 19 | } 20 | 21 | public static Observable justOnNext(T onNext) { 22 | return Observable.never().startWith(onNext); 23 | } 24 | 25 | @SuppressWarnings("unchecked") 26 | public static ObservableTransformer identityTransformer() { 27 | return (ObservableTransformer) IDENTITY_TRANSFORMER; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/scan/IsConnectable.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.scan; 2 | 3 | public enum IsConnectable { 4 | LEGACY_UNKNOWN, 5 | CONNECTABLE, 6 | NOT_CONNECTABLE 7 | } 8 | -------------------------------------------------------------------------------- /rxandroidble/src/main/java/com/polidea/rxandroidble2/scan/ScanCallbackType.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.scan; 2 | 3 | 4 | public enum ScanCallbackType { 5 | CALLBACK_TYPE_ALL_MATCHES, 6 | CALLBACK_TYPE_FIRST_MATCH, 7 | CALLBACK_TYPE_MATCH_LOST, 8 | CALLBACK_TYPE_BATCH, 9 | CALLBACK_TYPE_UNSPECIFIED, 10 | CALLBACK_TYPE_UNKNOWN 11 | } 12 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/DummyOperationQueue.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2 2 | 3 | import com.polidea.rxandroidble2.exceptions.BleException 4 | import com.polidea.rxandroidble2.internal.operations.Operation 5 | import com.polidea.rxandroidble2.internal.serialization.ConnectionOperationQueue 6 | import com.polidea.rxandroidble2.internal.util.DisposableUtil 7 | import io.reactivex.Observable 8 | import io.reactivex.ObservableEmitter 9 | import io.reactivex.ObservableOnSubscribe 10 | import io.reactivex.annotations.NonNull 11 | 12 | class DummyOperationQueue implements ConnectionOperationQueue { 13 | public final MockSemaphore semaphore = new MockSemaphore() 14 | 15 | @Override 16 | def Observable queue(Operation operation) { 17 | return Observable.create(new ObservableOnSubscribe() { 18 | @Override 19 | void subscribe(@NonNull ObservableEmitter tEmitter) throws Exception { 20 | semaphore.awaitRelease() 21 | def disposableObserver = operation 22 | .run(semaphore) 23 | .subscribeWith(DisposableUtil.disposableObserverFromEmitter(tEmitter)) 24 | tEmitter.setDisposable(disposableObserver) 25 | } 26 | }) 27 | } 28 | 29 | @Override 30 | void terminate(BleException disconnectException) { 31 | // do nothing 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/MockBluetoothManagerWrapper.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2 2 | 3 | import android.bluetooth.BluetoothDevice 4 | import android.bluetooth.BluetoothManager 5 | import com.polidea.rxandroidble2.internal.util.BluetoothManagerWrapper 6 | 7 | class MockBluetoothManagerWrapper extends BluetoothManagerWrapper { 8 | 9 | private List connectedPeripherals = new ArrayList<>() 10 | 11 | MockBluetoothManagerWrapper() { 12 | super(null) 13 | } 14 | 15 | MockBluetoothManagerWrapper(BluetoothManager bluetoothManager) { 16 | super(bluetoothManager) 17 | } 18 | 19 | def addConnectedPeripheral(BluetoothDevice bluetoothDevice) { 20 | connectedPeripherals.add(bluetoothDevice) 21 | } 22 | 23 | @Override 24 | List getConnectedPeripherals() { 25 | return connectedPeripherals 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/MockLocationServicesStatus.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2 2 | 3 | import com.polidea.rxandroidble2.internal.util.LocationServicesStatus 4 | 5 | class MockLocationServicesStatus implements LocationServicesStatus { 6 | boolean isLocationPermissionOk = true 7 | boolean isLocationProviderOk = true 8 | 9 | MockLocationServicesStatus() { 10 | } 11 | 12 | @Override 13 | boolean isLocationPermissionOk() { 14 | return isLocationPermissionOk 15 | } 16 | 17 | @Override 18 | boolean isLocationProviderOk() { 19 | return isLocationProviderOk 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/MockRxBleAdapterStateObservable.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2 2 | 3 | import com.polidea.rxandroidble2.internal.util.DisposableUtil 4 | import io.reactivex.Observable 5 | import io.reactivex.ObservableEmitter 6 | import io.reactivex.ObservableOnSubscribe 7 | import io.reactivex.annotations.NonNull 8 | import io.reactivex.subjects.ReplaySubject 9 | 10 | class MockRxBleAdapterStateObservable { 11 | 12 | public final ReplaySubject relay = ReplaySubject.create() 13 | 14 | public final ReplaySubject getRelay() { 15 | return relay 16 | } 17 | 18 | public Observable asObservable() { 19 | Observable.create(new ObservableOnSubscribe() { 20 | @Override 21 | void subscribe(@NonNull ObservableEmitter observableEmitter) throws Exception { 22 | def subscription = relay.subscribeWith(DisposableUtil.disposableObserverFromEmitter(observableEmitter)) 23 | observableEmitter.setDisposable(subscription) 24 | } 25 | }) 26 | } 27 | 28 | def disableBluetooth() { 29 | relay.onNext(RxBleAdapterStateObservable.BleAdapterState.STATE_OFF) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/MockSemaphore.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2 2 | 3 | import com.polidea.rxandroidble2.internal.serialization.QueueAwaitReleaseInterface 4 | import com.polidea.rxandroidble2.internal.serialization.QueueReleaseInterface 5 | 6 | class MockSemaphore implements QueueReleaseInterface, QueueAwaitReleaseInterface { 7 | int permits = 0 8 | 9 | MockSemaphore() { 10 | } 11 | 12 | @Override 13 | void awaitRelease() throws InterruptedException { 14 | permits++ 15 | } 16 | 17 | @Override 18 | void release() { 19 | permits-- 20 | } 21 | 22 | boolean isReleased() { 23 | permits <= 0 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/cache/MockDeviceReferenceProvider.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.cache 2 | 3 | import com.polidea.rxandroidble2.internal.DeviceComponent 4 | 5 | 6 | class MockDeviceReferenceProvider implements DeviceComponentWeakReference.Provider { 7 | 8 | 9 | private final HashMap> devices = new HashMap<>() 10 | 11 | class MockDeviceComponentWeakReference extends DeviceComponentWeakReference { 12 | 13 | MockDeviceComponentWeakReference(DeviceComponent device) { 14 | super(device) 15 | } 16 | 17 | public release() { 18 | clear() 19 | } 20 | 21 | @Override 22 | boolean isEmpty() { 23 | return super.isEmpty() 24 | } 25 | } 26 | 27 | @Override 28 | DeviceComponentWeakReference provide(DeviceComponent component) { 29 | def reference = new MockDeviceComponentWeakReference(component) 30 | storeReference(component, reference) 31 | return reference 32 | } 33 | 34 | public releaseReferenceFor(DeviceComponent component) { 35 | devices.get(component)?.each { it.release() } 36 | } 37 | 38 | private storeReference(DeviceComponent component, MockDeviceComponentWeakReference reference) { 39 | 40 | if (devices.containsKey(component)) { 41 | devices.get(component).add(reference) 42 | } else { 43 | devices.put(component, [reference]) 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/connection/BluetoothGattProviderTest.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection 2 | 3 | import android.bluetooth.BluetoothGatt 4 | import spock.lang.Specification 5 | 6 | class BluetoothGattProviderTest extends Specification { 7 | BluetoothGattProvider objectUnderTest 8 | 9 | def setup() { 10 | objectUnderTest = new BluetoothGattProvider() 11 | } 12 | 13 | def "should return null when asked for GATT initially"() { 14 | when: 15 | def capturedGatt = objectUnderTest.getBluetoothGatt() 16 | 17 | then: 18 | capturedGatt == null 19 | } 20 | 21 | def "should provide most first captured GATT instance"() { 22 | given: 23 | def firstGatt = Mock(BluetoothGatt) 24 | def secondGatt = Mock(BluetoothGatt) 25 | objectUnderTest.updateBluetoothGatt(firstGatt) 26 | objectUnderTest.updateBluetoothGatt(secondGatt) 27 | 28 | when: 29 | def capturedGatt = objectUnderTest.getBluetoothGatt() 30 | 31 | then: 32 | capturedGatt == firstGatt 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/connection/MtuBasedPayloadSizeLimitTest.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.connection 2 | 3 | import com.polidea.rxandroidble2.RxBleConnection 4 | import spock.lang.Specification 5 | import spock.lang.Unroll 6 | 7 | 8 | class MtuBasedPayloadSizeLimitTest extends Specification { 9 | 10 | def mockBleConnection = Mock RxBleConnection 11 | 12 | MtuBasedPayloadSizeLimit objectUnderTest 13 | 14 | private void prepareObjectUnderTest(int gattWriteMtuOverhead, int maxAttributeLength) { 15 | objectUnderTest = new MtuBasedPayloadSizeLimit(mockBleConnection, gattWriteMtuOverhead, maxAttributeLength) 16 | } 17 | 18 | @Unroll 19 | def "should return current MTU decreased by the write MTU overhead but no more than the maxAttributeLength"() { 20 | 21 | given: 22 | prepareObjectUnderTest(gattWriteMtuOverhead, maxAttributeLength) 23 | mockBleConnection.getMtu() >> currentMtu 24 | 25 | expect: 26 | objectUnderTest.getPayloadSizeLimit() == expectedValue 27 | 28 | where: 29 | currentMtu | gattWriteMtuOverhead | maxAttributeLength | expectedValue 30 | 10 | 2 | 2000 | 8 31 | 2000 | 32 | 2000 | 1968 32 | 10 | 2 | 512 | 8 33 | 2000 | 32 | 512 | 512 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/scan/EmulatedScanFilterMatcherTest.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.scan 2 | 3 | import spock.lang.Specification 4 | import spock.lang.Unroll 5 | 6 | class EmulatedScanFilterMatcherTest extends Specification { 7 | 8 | private EmulatedScanFilterMatcher objectUnderTest 9 | 10 | @Unroll 11 | def "should return proper value when called isEmpty()"() { 12 | 13 | given: 14 | objectUnderTest = new EmulatedScanFilterMatcher(scanFilters) 15 | 16 | expect: 17 | objectUnderTest.isEmpty() == result 18 | 19 | where: 20 | result | scanFilters 21 | true | null 22 | true | mockScanFilters() 23 | true | mockScanFilters(true) 24 | false | mockScanFilters(false) 25 | true | mockScanFilters(true, true) 26 | false | mockScanFilters(true, false) 27 | false | mockScanFilters(false, true) 28 | true | mockScanFilters(true, true, true) 29 | false | mockScanFilters(false, true, true) 30 | false | mockScanFilters(true, false, true) 31 | false | mockScanFilters(true, true, false) 32 | } 33 | 34 | private def mockScanFilters(Boolean... empty) { 35 | ScanFilterInterface[] scanFilterInterfaces = new ScanFilterInterface[empty.length] 36 | for (int i = 0; i < empty.length; i++) { 37 | def scanFilter = Mock(ScanFilterInterface) 38 | scanFilter.isAllFieldsEmpty() >> empty[i] 39 | scanFilterInterfaces[i] = scanFilter 40 | } 41 | return scanFilterInterfaces 42 | } 43 | } -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/util/CheckerPermissionTest.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util 2 | 3 | import android.content.Context 4 | import android.content.pm.PackageManager 5 | import spock.lang.Specification 6 | 7 | class CheckerPermissionTest extends Specification { 8 | 9 | String testPermissionString = "random.package.RANDOM_PERMISSION" 10 | def testPermissionArray = new String[] { testPermissionString } 11 | def mockContext = Mock Context 12 | CheckerPermission objectUnderTest 13 | 14 | def "should cache granted permissions"() { 15 | 16 | given: 17 | objectUnderTest = new CheckerPermission(mockContext) 18 | 19 | when: 20 | def result0 = objectUnderTest.isAnyPermissionGranted(testPermissionArray) 21 | def result1 = objectUnderTest.isAnyPermissionGranted(testPermissionArray) 22 | 23 | then: 24 | 1 * mockContext.checkPermission(testPermissionString, _, _) >> PackageManager.PERMISSION_GRANTED 25 | 26 | and: 27 | result0 28 | result1 29 | } 30 | 31 | def "should call context each time if permission is not granted"() { 32 | 33 | given: 34 | objectUnderTest = new CheckerPermission(mockContext) 35 | 36 | when: 37 | def result0 = objectUnderTest.isAnyPermissionGranted(testPermissionArray) 38 | def result1 = objectUnderTest.isAnyPermissionGranted(testPermissionArray) 39 | 40 | then: 41 | 2 * mockContext.checkPermission(testPermissionString, _, _) >> PackageManager.PERMISSION_DENIED 42 | 43 | and: 44 | !result0 45 | !result1 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/util/CheckerScanPermissionTest.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util 2 | 3 | 4 | import spock.lang.Specification 5 | import spock.lang.Unroll 6 | 7 | class CheckerScanPermissionTest extends Specification { 8 | CheckerScanPermission objectUnderTest 9 | 10 | @Unroll 11 | def "return input data concatenated if needed"() { 12 | 13 | given: 14 | objectUnderTest = new CheckerScanPermission(null, repackToArray(permissions)) 15 | 16 | expect: 17 | objectUnderTest.getRecommendedScanRuntimePermissions() == (expectedPermissions.toArray(new String[0])) 18 | 19 | where: 20 | permissions | expectedPermissions 21 | [] | [] 22 | [[], []] | [] 23 | [["p0", "p1"]] | ["p0", "p1"] 24 | [["p0", "p1"], []] | ["p0", "p1"] 25 | [["p0"], ["p1"]] | ["p0", "p1"] 26 | [["p0", "p1"], ["p2"]] | ["p0", "p1", "p2"] 27 | [["p0", "p1"], ["p2"], ["p3"]] | ["p0", "p1", "p2", "p3"] 28 | } 29 | 30 | String[][] repackToArray(ArrayList> permissions) { 31 | def result = new String[permissions.size()][] 32 | for (i in 0.. permissionsArrayInner = permissions.get(i) 34 | result[i] = permissionsArrayInner.toArray(new String[0]) 35 | } 36 | return result 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/util/LocationServicesStatusApi18Test.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util 2 | 3 | import spock.lang.Specification 4 | 5 | class LocationServicesStatusApi18Test extends Specification { 6 | 7 | LocationServicesStatusApi18 objectUnderTest 8 | 9 | private prepareObjectUnderTest() { 10 | objectUnderTest = new LocationServicesStatusApi18() 11 | } 12 | 13 | def "isLocationPermissionOk should return true"() { 14 | 15 | given: 16 | prepareObjectUnderTest() 17 | 18 | expect: 19 | objectUnderTest.isLocationPermissionOk() 20 | } 21 | 22 | def "isLocationProviderOk should return true"() { 23 | 24 | given: 25 | prepareObjectUnderTest() 26 | 27 | expect: 28 | objectUnderTest.isLocationProviderOk() 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/util/MockOperationTimeoutConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util; 2 | 3 | import com.polidea.rxandroidble2.internal.operations.TimeoutConfiguration; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import io.reactivex.Scheduler; 8 | 9 | 10 | public class MockOperationTimeoutConfiguration extends TimeoutConfiguration { 11 | 12 | public static final int TIMEOUT_IN_SEC = 30; 13 | 14 | public MockOperationTimeoutConfiguration(int seconds, Scheduler timeoutScheduler) { 15 | super(seconds, TimeUnit.SECONDS, timeoutScheduler); 16 | } 17 | 18 | public MockOperationTimeoutConfiguration(Scheduler timeoutScheduler) { 19 | this(TIMEOUT_IN_SEC, timeoutScheduler); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rxandroidble/src/test/groovy/com/polidea/rxandroidble2/internal/util/ObservableUtilTest.groovy: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.internal.util 2 | 3 | import spock.lang.Specification 4 | 5 | class ObservableUtilTest extends Specification { 6 | 7 | def "should pass through parameter on subscribe and not complete"() { 8 | given: 9 | String someObject = "someText" 10 | 11 | when: 12 | def testObserver = ObservableUtil.justOnNext(someObject).test() 13 | 14 | then: 15 | testObserver.assertValue(someObject) 16 | testObserver.assertNotComplete() 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/app/PendingIntent.java: -------------------------------------------------------------------------------- 1 | package android.app; 2 | import android.os.Parcel; 3 | import android.os.Parcelable; 4 | /** 5 | * Stubs, only used for mocks 6 | */ 7 | public class PendingIntent implements Parcelable { 8 | public PendingIntent() { 9 | } 10 | @Override 11 | public int describeContents() { 12 | return 0; 13 | } 14 | @Override 15 | public void writeToParcel(Parcel dest, int flags) { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/bluetooth/BluetoothGattCallback.java: -------------------------------------------------------------------------------- 1 | package android.bluetooth; 2 | /** 3 | * Used to create callbacks 4 | */ 5 | public abstract class BluetoothGattCallback { 6 | public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) { 7 | } 8 | public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) { 9 | } 10 | public void onConnectionStateChange(BluetoothGatt gatt, int status, 11 | int newState) { 12 | } 13 | public void onServicesDiscovered(BluetoothGatt gatt, int status) { 14 | } 15 | public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, 16 | int status) { 17 | } 18 | public void onCharacteristicWrite(BluetoothGatt gatt, 19 | BluetoothGattCharacteristic characteristic, int status) { 20 | } 21 | public void onCharacteristicChanged(BluetoothGatt gatt, 22 | BluetoothGattCharacteristic characteristic) { 23 | } 24 | public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, 25 | int status) { 26 | } 27 | public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, 28 | int status) { 29 | } 30 | public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { 31 | } 32 | public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { 33 | } 34 | public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) { 35 | } 36 | public void onConnectionUpdated(BluetoothGatt gatt, int interval, int latency, int timeout, 37 | int status) { 38 | } 39 | public void onServiceChanged(BluetoothGatt gatt) { 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/bluetooth/BluetoothGattIncludedService.java: -------------------------------------------------------------------------------- 1 | package android.bluetooth; 2 | import android.os.Parcel; 3 | import android.os.ParcelUuid; 4 | import android.os.Parcelable; 5 | import java.util.UUID; 6 | /** 7 | * Used for mocks 8 | */ 9 | public class BluetoothGattIncludedService implements Parcelable { 10 | public BluetoothGattIncludedService(UUID uuid, int instanceId, int serviceType) { 11 | } 12 | @Override 13 | public int describeContents() { 14 | return 0; 15 | } 16 | @Override 17 | public void writeToParcel(Parcel out, int flags) { 18 | } 19 | public static final Creator CREATOR = 20 | new Creator() { 21 | public BluetoothGattIncludedService createFromParcel(Parcel in) { 22 | return new BluetoothGattIncludedService(in); 23 | } 24 | public BluetoothGattIncludedService[] newArray(int size) { 25 | return new BluetoothGattIncludedService[size]; 26 | } 27 | }; 28 | private BluetoothGattIncludedService(Parcel in) { 29 | } 30 | public UUID getUuid() { 31 | return null; 32 | } 33 | public int getInstanceId() { 34 | return 0; 35 | } 36 | public int getType() { 37 | return 0; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/bluetooth/le/BluetoothLeScanner.java: -------------------------------------------------------------------------------- 1 | package android.bluetooth.le; 2 | import android.bluetooth.BluetoothAdapter; 3 | 4 | /** 5 | * Only used for constants currently 6 | */ 7 | public class BluetoothLeScanner { 8 | public static final String EXTRA_LIST_SCAN_RESULT = 9 | "android.bluetooth.le.extra.LIST_SCAN_RESULT"; 10 | public static final String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE"; 11 | public static final String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE"; 12 | public BluetoothLeScanner(BluetoothAdapter bluetoothAdapter) { 13 | 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/bluetooth/le/ScanCallback.java: -------------------------------------------------------------------------------- 1 | package android.bluetooth.le; 2 | import java.util.List; 3 | 4 | /** 5 | * Used for mocks and constants 6 | */ 7 | public abstract class ScanCallback { 8 | public static final int SCAN_FAILED_ALREADY_STARTED = 1; 9 | public static final int SCAN_FAILED_APPLICATION_REGISTRATION_FAILED = 2; 10 | public void onScanResult(int callbackType, ScanResult result) { 11 | } 12 | public void onBatchScanResults(List results) { 13 | } 14 | public void onScanFailed(int errorCode) { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/content/BroadcastReceiver.java: -------------------------------------------------------------------------------- 1 | package android.content; 2 | /** 3 | * Used to create callbacks 4 | */ 5 | public abstract class BroadcastReceiver { 6 | public BroadcastReceiver() { 7 | } 8 | public void onReceive(Context context, Intent intent) { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/content/Context.java: -------------------------------------------------------------------------------- 1 | package android.content; 2 | 3 | import android.content.res.Resources; 4 | /** 5 | * Used for mocks 6 | */ 7 | public abstract class Context { 8 | 9 | public abstract String getPackageName(); 10 | 11 | public abstract Resources getResources(); 12 | public abstract ContentResolver getContentResolver(); 13 | public abstract Intent registerReceiver(BroadcastReceiver receiver, IntentFilter intentFilter); 14 | public abstract void unregisterReceiver(BroadcastReceiver receiver); 15 | public abstract int checkPermission(String permission, int pid, int uid); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/content/IntentFilter.java: -------------------------------------------------------------------------------- 1 | package android.content; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | import android.util.AndroidException; 6 | /** 7 | * Instances created, so must have implementation of action 8 | */ 9 | public class IntentFilter implements Parcelable { 10 | 11 | @Override 12 | public int describeContents() { 13 | return 0; 14 | } 15 | 16 | @Override 17 | public void writeToParcel(Parcel dest, int flags) { 18 | 19 | } 20 | 21 | public static class MalformedMimeTypeException extends AndroidException { 22 | public MalformedMimeTypeException() { 23 | } 24 | public MalformedMimeTypeException(String name) { 25 | super(name); 26 | } 27 | } 28 | public static IntentFilter create(String action, String dataType) { 29 | try { 30 | return new IntentFilter(action, dataType); 31 | } catch (MalformedMimeTypeException e) { 32 | throw new RuntimeException("Bad MIME type", e); 33 | } 34 | } 35 | String mAction; 36 | public IntentFilter(String action, String dataType) 37 | throws MalformedMimeTypeException { 38 | mAction = action; 39 | } 40 | public IntentFilter(String action) 41 | throws MalformedMimeTypeException { 42 | mAction = action; 43 | 44 | } 45 | public final boolean hasAction(String action) { 46 | return action.equals(mAction); 47 | } 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/content/res/Configuration.java: -------------------------------------------------------------------------------- 1 | package android.content.res; 2 | import android.os.Parcel; 3 | import android.os.Parcelable; 4 | /** 5 | * Used for mocks and constants 6 | */ 7 | public final class Configuration implements Parcelable, Comparable { 8 | public static final int NAVIGATION_UNDEFINED = 0; 9 | public static final int NAVIGATION_NONAV = 1; 10 | public static final int NAVIGATION_DPAD = 2; 11 | public static final int NAVIGATION_TRACKBALL = 3; 12 | public static final int NAVIGATION_WHEEL = 4; 13 | public int navigation; 14 | public Configuration() { 15 | this.navigation = 0; 16 | } 17 | public Configuration(int navigation) { 18 | this.navigation = navigation; 19 | } 20 | @Override 21 | public int describeContents() { 22 | return 0; 23 | } 24 | @Override 25 | public void writeToParcel(Parcel dest, int flags) { 26 | } 27 | @Override 28 | public int compareTo(Configuration o) { 29 | return 0; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/content/res/Resources.java: -------------------------------------------------------------------------------- 1 | package android.content.res; 2 | /** 3 | * Used for mocks and constants 4 | */ 5 | public class Resources { 6 | public Configuration getConfiguration() { 7 | return configuration; 8 | } 9 | public void setConfiguration(Configuration configuration) { 10 | this.configuration = configuration; 11 | } 12 | private Configuration configuration; 13 | public Resources(Configuration configuration) { 14 | this.configuration = configuration; 15 | } 16 | public final class Theme { 17 | } 18 | public String getResourceName(int resid) { 19 | return null; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/location/LocationManager.java: -------------------------------------------------------------------------------- 1 | package android.location; 2 | 3 | /** 4 | * Used for constant 5 | */ 6 | public class LocationManager { 7 | 8 | public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED"; 9 | } 10 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/os/DeadObjectException.java: -------------------------------------------------------------------------------- 1 | package android.os; 2 | /** 3 | * Used for exceptions 4 | */ 5 | public class DeadObjectException extends RemoteException { 6 | public DeadObjectException() { 7 | super(); 8 | } 9 | public DeadObjectException(String message) { 10 | super(message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/os/RemoteException.java: -------------------------------------------------------------------------------- 1 | package android.os; 2 | import android.util.AndroidException; 3 | /** 4 | * Used for exceptions 5 | */ 6 | public class RemoteException extends AndroidException { 7 | public RemoteException() { 8 | super(); 9 | } 10 | public RemoteException(String message) { 11 | super(message); 12 | } 13 | public RemoteException(String message, Throwable cause, boolean enableSuppression, 14 | boolean writableStackTrace) { 15 | super(message, cause, enableSuppression, writableStackTrace); 16 | } 17 | public RemoteException(Throwable cause) { 18 | this(cause.getMessage(), cause, true, false); 19 | } 20 | public RuntimeException rethrowAsRuntimeException() { 21 | throw new RuntimeException(this); 22 | } 23 | public RuntimeException rethrowFromSystemServer() { 24 | if (this instanceof DeadObjectException) { 25 | throw new RuntimeException(new DeadSystemException()); 26 | } else { 27 | throw new RuntimeException(this); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/util/AndroidException.java: -------------------------------------------------------------------------------- 1 | package android.util; 2 | /** 3 | * Used for exceptions 4 | */ 5 | public class AndroidException extends Exception { 6 | public AndroidException() { 7 | } 8 | public AndroidException(String name) { 9 | super(name); 10 | } 11 | public AndroidException(String name, Throwable cause) { 12 | super(name, cause); 13 | } 14 | public AndroidException(Exception cause) { 15 | super(cause); 16 | } 17 | protected AndroidException(String message, Throwable cause, boolean enableSuppression, 18 | boolean writableStackTrace) { 19 | super(message, cause, enableSuppression, writableStackTrace); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/util/Pair.java: -------------------------------------------------------------------------------- 1 | package android.util; 2 | import java.util.Objects; 3 | /** 4 | * Must have implementation 5 | */ 6 | public class Pair { 7 | public final F first; 8 | public final S second; 9 | public Pair(F first, S second) { 10 | this.first = first; 11 | this.second = second; 12 | } 13 | @Override 14 | public boolean equals(Object o) { 15 | if (!(o instanceof Pair)) { 16 | return false; 17 | } 18 | Pair p = (Pair) o; 19 | return Objects.equals(p.first, first) && Objects.equals(p.second, second); 20 | } 21 | @Override 22 | public int hashCode() { 23 | return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode()); 24 | } 25 | @Override 26 | public String toString() { 27 | return "Pair{" + String.valueOf(first) + " " + String.valueOf(second) + "}"; 28 | } 29 | public static Pair create(A a, B b) { 30 | return new Pair(a, b); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/android/util/SparseArray.java: -------------------------------------------------------------------------------- 1 | package android.util; 2 | import java.util.ArrayList; 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | /** 6 | * Must have implementation 7 | */ 8 | public class SparseArray { 9 | private final ArrayList keys = new ArrayList<>(); 10 | private final HashMap mHashMap = new HashMap<>(); 11 | public SparseArray() { 12 | } 13 | public void put(int key, E value) { 14 | mHashMap.put(key, value); 15 | keys.add(key); 16 | Collections.sort(keys); 17 | } 18 | public void append(int key, E value) { 19 | put(key, value); 20 | } 21 | public E get(int key) { 22 | return mHashMap.get(key); 23 | } 24 | public int size() { 25 | return mHashMap.size(); 26 | } 27 | public int keyAt(int i) { 28 | if (i > keys.size()) { 29 | throw new ArrayIndexOutOfBoundsException(i); 30 | } 31 | return keys.get(i); 32 | } 33 | } -------------------------------------------------------------------------------- /rxandroidble/src/test/java/com/polidea/rxandroidble2/exceptions/BleCannotSetCharacteristicNotificationExceptionTest.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import android.bluetooth.BluetoothGattCharacteristic; 6 | 7 | import org.junit.jupiter.api.Test; 8 | import org.mockito.Mockito; 9 | 10 | import java.util.UUID; 11 | 12 | public class BleCannotSetCharacteristicNotificationExceptionTest { 13 | 14 | @Test 15 | public void toStringShouldContainMessage() { 16 | // given 17 | BluetoothGattCharacteristic mockCharacteristic = Mockito.mock(BluetoothGattCharacteristic.class); 18 | Mockito.when(mockCharacteristic.getUuid()).thenReturn(new UUID(1, 2)); 19 | BleCannotSetCharacteristicNotificationException out = new BleCannotSetCharacteristicNotificationException( 20 | mockCharacteristic, 21 | BleCannotSetCharacteristicNotificationException.CANNOT_SET_LOCAL_NOTIFICATION, 22 | new Exception("because")); 23 | 24 | // expect 25 | assertEquals(out.toString(), 26 | "com.polidea.rxandroidble2.exceptions.BleCannotSetCharacteristicNotificationException: " + 27 | "Cannot set local notification (code 1) with characteristic UUID 00000000-0000-0001-0000-000000000002"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/com/polidea/rxandroidble2/exceptions/BleDisconnectedExceptionTest.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | public class BleDisconnectedExceptionTest { 8 | 9 | @SuppressWarnings("deprecation") 10 | @Test 11 | public void toStringShouldContainMessageWithUnknownStatus() { 12 | // given 13 | BleDisconnectedException out = new BleDisconnectedException("myBluetoothAddress"); 14 | 15 | // expect 16 | assertEquals(out.toString(), "com.polidea.rxandroidble2.exceptions.BleDisconnectedException: Disconnected from MAC='XX:XX:XX:XX:XX:XX' with status -1 (UNKNOWN)"); 17 | } 18 | 19 | @Test 20 | public void toStringShouldContainMessageWithStatus() { 21 | // given 22 | int expectedStatus = 129; // 0x81 23 | BleDisconnectedException out = new BleDisconnectedException("myBluetoothAddress", expectedStatus); 24 | 25 | // expect 26 | assertEquals(out.toString(), "com.polidea.rxandroidble2.exceptions.BleDisconnectedException: Disconnected from MAC='XX:XX:XX:XX:XX:XX' with status 129 (GATT_INTERNAL_ERROR)"); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/com/polidea/rxandroidble2/exceptions/BleGattExceptionTest.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import android.bluetooth.BluetoothGatt; 6 | 7 | import org.junit.jupiter.api.Test; 8 | 9 | import utils.MockUtils; 10 | 11 | public class BleGattExceptionTest { 12 | 13 | @Test 14 | public void toStringShouldContainMessage() { 15 | // given 16 | BluetoothGatt mockBtGatt = MockUtils.bluetoothGatt("AA:BB:CC:DD:EE:FF"); 17 | BleGattException out = new BleGattException(mockBtGatt, 10, BleGattOperationType.CONNECTION_STATE); 18 | 19 | // expect 20 | assertEquals(out.toString(), 21 | "com.polidea.rxandroidble2.exceptions.BleGattException: GATT exception from MAC='XX:XX:XX:XX:XX:XX', status 10 (GATT_NOT_FOUND), " + 22 | "type BleGattOperation{description='CONNECTION_STATE'}. " + 23 | "(Look up status 0x0a here " + 24 | "https://cs.android.com/android/platform/superproject/+/master:packages/modules/Bluetooth/system/stack/include/gatt_api.h)"); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/com/polidea/rxandroidble2/exceptions/BleScanExceptionTest.java: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.exceptions; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | 5 | import org.junit.jupiter.api.Test; 6 | 7 | public class BleScanExceptionTest { 8 | 9 | @Test 10 | public void toStringShouldContainMessage() { 11 | // given 12 | BleScanException out = new BleScanException(BleScanException.BLUETOOTH_DISABLED); 13 | 14 | // expect 15 | assertEquals(out.toString(), "com.polidea.rxandroidble2.exceptions.BleScanException: Bluetooth disabled (code 1)"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /rxandroidble/src/test/java/utils/MockUtils.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import android.bluetooth.BluetoothDevice; 4 | import android.bluetooth.BluetoothGatt; 5 | 6 | import org.mockito.Mockito; 7 | 8 | public class MockUtils { 9 | 10 | public static BluetoothGatt bluetoothGatt(String deviceAddress) { 11 | BluetoothGatt bluetoothGatt = Mockito.mock(BluetoothGatt.class); 12 | BluetoothDevice bluetoothDevice = Mockito.mock(BluetoothDevice.class); 13 | Mockito.when(bluetoothGatt.getDevice()).thenReturn(bluetoothDevice); 14 | Mockito.when(bluetoothDevice.getAddress()).thenReturn(deviceAddress); 15 | return bluetoothGatt; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /rxandroidble/src/test/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule: -------------------------------------------------------------------------------- 1 | moduleName = testsubscriber-module 2 | moduleVersion = 1.0 3 | extensionClasses = com.polidea.rxandroidble2.extensions.TestSubscriberExtension -------------------------------------------------------------------------------- /rxandroidble3/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /rxandroidble3/README.md: -------------------------------------------------------------------------------- 1 | 'src' is generated from 'rxandroidble' by script in 'gradle/src-gen-rxjava3-from-rxjava2.gradle' 2 | -------------------------------------------------------------------------------- /rxandroidble3/consumer-rules.pro: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dariuszseweryn/RxAndroidBle/596feb87346cabc7667e2760f347d379e406b757/rxandroidble3/consumer-rules.pro -------------------------------------------------------------------------------- /rxandroidble3/gradle.properties: -------------------------------------------------------------------------------- 1 | GROUP=com.polidea.rxandroidble3 2 | POM_ARTIFACT_ID=rxandroidble 3 | POM_NAME=RxAndroidBle 4 | POM_PACKAGING=aar 5 | -------------------------------------------------------------------------------- /rxandroidble3/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/dariuszseweryn/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # RxAndroidBle 20 | -keepclassmembers class * extends android.bluetooth.BluetoothGattCallback { 21 | # This method is hidden in AOSP sources and therefore Proguard strips it by default 22 | public void onConnectionUpdated(android.bluetooth.BluetoothGatt, int, int, int, int); 23 | } 24 | -------------------------------------------------------------------------------- /sample-kotlin/.gitignore: -------------------------------------------------------------------------------- 1 | build/ -------------------------------------------------------------------------------- /sample-kotlin/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/pawelurban/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /sample-kotlin/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dariuszseweryn/RxAndroidBle/596feb87346cabc7667e2760f347d379e406b757/sample-kotlin/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /sample-kotlin/src/main/kotlin/com/polidea/rxandroidble2/samplekotlin/DeviceActivity.kt: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.samplekotlin 2 | 3 | import android.content.Context 4 | import android.content.Intent 5 | import android.os.Bundle 6 | import androidx.appcompat.app.AppCompatActivity 7 | import com.polidea.rxandroidble2.samplekotlin.example2_connection.ConnectionExampleActivity 8 | import com.polidea.rxandroidble2.samplekotlin.example3_discovery.ServiceDiscoveryExampleActivity 9 | import kotlinx.android.synthetic.main.activity_device.connect 10 | import kotlinx.android.synthetic.main.activity_device.discovery 11 | 12 | private const val EXTRA_MAC_ADDRESS = "extra_mac_address" 13 | 14 | class DeviceActivity : AppCompatActivity() { 15 | 16 | companion object { 17 | fun newInstance(context: Context, macAddress: String): Intent = 18 | Intent(context, DeviceActivity::class.java).apply { putExtra(EXTRA_MAC_ADDRESS, macAddress) } 19 | } 20 | 21 | private lateinit var macAddress: String 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | setContentView(R.layout.activity_device) 26 | 27 | macAddress = intent.getStringExtra(EXTRA_MAC_ADDRESS)!! 28 | supportActionBar!!.subtitle = getString(R.string.mac_address, macAddress) 29 | 30 | connect.setOnClickListener { startActivity(ConnectionExampleActivity.newInstance(this, macAddress)) } 31 | discovery.setOnClickListener { startActivity(ServiceDiscoveryExampleActivity.newInstance(this, macAddress)) } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /sample-kotlin/src/main/kotlin/com/polidea/rxandroidble2/samplekotlin/SampleApplication.kt: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.samplekotlin 2 | 3 | import android.app.Application 4 | import com.polidea.rxandroidble2.LogConstants 5 | import com.polidea.rxandroidble2.LogOptions 6 | import com.polidea.rxandroidble2.RxBleClient 7 | 8 | class SampleApplication : Application() { 9 | 10 | companion object { 11 | lateinit var rxBleClient: RxBleClient 12 | private set 13 | } 14 | 15 | override fun onCreate() { 16 | super.onCreate() 17 | rxBleClient = RxBleClient.create(this) 18 | RxBleClient.updateLogOptions(LogOptions.Builder() 19 | .setLogLevel(LogConstants.INFO) 20 | .setMacAddressLogSetting(LogConstants.MAC_ADDRESS_FULL) 21 | .setUuidsLogSetting(LogConstants.UUIDS_FULL) 22 | .setShouldLogAttributeValues(true) 23 | .build() 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /sample-kotlin/src/main/kotlin/com/polidea/rxandroidble2/samplekotlin/example1a_background_scanning/ScanReceiver.kt: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.samplekotlin.example1a_background_scanning 2 | 3 | import android.app.PendingIntent 4 | import android.content.BroadcastReceiver 5 | import android.content.Context 6 | import android.content.Intent 7 | import android.util.Log 8 | import androidx.annotation.RequiresApi 9 | import com.polidea.rxandroidble2.exceptions.BleScanException 10 | import com.polidea.rxandroidble2.samplekotlin.SampleApplication 11 | 12 | private const val SCAN_REQUEST_CODE = 42 13 | 14 | class ScanReceiver : BroadcastReceiver() { 15 | 16 | companion object { 17 | fun newPendingIntent(context: Context): PendingIntent = 18 | Intent(context, ScanReceiver::class.java).let { 19 | PendingIntent.getBroadcast(context, SCAN_REQUEST_CODE, it, 0) 20 | } 21 | } 22 | 23 | @RequiresApi(26 /* Build.VERSION_CODES.O */) 24 | override fun onReceive(context: Context, intent: Intent) { 25 | val backgroundScanner = SampleApplication.rxBleClient.backgroundScanner 26 | try { 27 | val scanResults = backgroundScanner.onScanResultReceived(intent) 28 | Log.i("ScanReceiver", "Scan results received: $scanResults") 29 | } catch (exception: BleScanException) { 30 | Log.e("ScanReceiver", "Failed to scan devices", exception) 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /sample-kotlin/src/main/kotlin/com/polidea/rxandroidble2/samplekotlin/example4_characteristic/advanced/PresenterEvent.kt: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.samplekotlin.example4_characteristic.advanced 2 | 3 | /** 4 | * Operation type for result or error. 5 | */ 6 | internal enum class Type { 7 | 8 | READ, WRITE, NOTIFY, INDICATE 9 | } 10 | 11 | /** 12 | * A dummy sealed class hierarchy to indicate what events may be emitted by the [Presenter]. 13 | */ 14 | internal sealed class PresenterEvent 15 | 16 | internal data class InfoEvent(val infoText: String) : PresenterEvent() 17 | 18 | internal data class ResultEvent(val result: List, val type: Type) : PresenterEvent() 19 | 20 | internal data class ErrorEvent(val error: Throwable, val type: Type) : PresenterEvent() 21 | 22 | internal data class CompatibilityModeEvent(val isCompatibility: Boolean) : PresenterEvent() 23 | -------------------------------------------------------------------------------- /sample-kotlin/src/main/kotlin/com/polidea/rxandroidble2/samplekotlin/util/BluetoothGatt.kt: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.samplekotlin.util 2 | 3 | import android.bluetooth.BluetoothGattCharacteristic 4 | 5 | fun BluetoothGattCharacteristic.hasProperty(property: Int): Boolean = (properties and property) > 0 -------------------------------------------------------------------------------- /sample-kotlin/src/main/kotlin/com/polidea/rxandroidble2/samplekotlin/util/ByteArray.kt: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.samplekotlin.util 2 | 3 | fun ByteArray.toHex() = joinToString("") { String.format("%02X", (it.toInt() and 0xff)) } -------------------------------------------------------------------------------- /sample-kotlin/src/main/kotlin/com/polidea/rxandroidble2/samplekotlin/util/ConnectPermission.kt: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.samplekotlin.util 2 | 3 | import android.app.Activity 4 | import android.content.pm.PackageManager 5 | import androidx.core.app.ActivityCompat 6 | import com.polidea.rxandroidble2.RxBleClient 7 | 8 | private const val REQUEST_PERMISSION_BLE_CONNECT = 102 9 | 10 | internal fun Activity.requestConnectionPermission(client: RxBleClient) = 11 | ActivityCompat.requestPermissions( 12 | this, 13 | /* 14 | * the below would cause a ArrayIndexOutOfBoundsException on API < 31. Yet it should not be called then as runtime 15 | * permissions are not needed and RxBleClient.isConnectRuntimePermissionGranted() returns `true` 16 | */ 17 | arrayOf(client.recommendedConnectRuntimePermissions[0]), 18 | REQUEST_PERMISSION_BLE_CONNECT 19 | ) 20 | 21 | internal fun isConnectionPermissionGranted(requestCode: Int, grantResults: IntArray) = 22 | requestCode == REQUEST_PERMISSION_BLE_CONNECT && grantResults[0] == PackageManager.PERMISSION_GRANTED 23 | -------------------------------------------------------------------------------- /sample-kotlin/src/main/kotlin/com/polidea/rxandroidble2/samplekotlin/util/RxAndroidBle.kt: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.samplekotlin.util 2 | 3 | import com.polidea.rxandroidble2.RxBleConnection 4 | import com.polidea.rxandroidble2.RxBleDevice 5 | 6 | /** 7 | * Returns `true` if connection state is [CONNECTED][RxBleConnection.RxBleConnectionState.CONNECTED]. 8 | */ 9 | internal val RxBleDevice.isConnected: Boolean 10 | get() = connectionState == RxBleConnection.RxBleConnectionState.CONNECTED 11 | -------------------------------------------------------------------------------- /sample-kotlin/src/main/kotlin/com/polidea/rxandroidble2/samplekotlin/util/ScanPermission.kt: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.samplekotlin.util 2 | 3 | import android.app.Activity 4 | import android.content.pm.PackageManager 5 | import androidx.core.app.ActivityCompat 6 | import com.polidea.rxandroidble2.RxBleClient 7 | 8 | private const val REQUEST_PERMISSION_BLE_SCAN = 101 9 | 10 | internal fun Activity.requestScanPermission(client: RxBleClient) = 11 | ActivityCompat.requestPermissions( 12 | this, 13 | /* 14 | * the below would cause a ArrayIndexOutOfBoundsException on API < 23. Yet it should not be called then as runtime 15 | * permissions are not needed and RxBleClient.isScanRuntimePermissionGranted() returns `true` 16 | */ 17 | arrayOf(client.recommendedScanRuntimePermissions[0]), 18 | REQUEST_PERMISSION_BLE_SCAN 19 | ) 20 | 21 | internal fun isScanPermissionGranted(requestCode: Int, grantResults: IntArray) = 22 | requestCode == REQUEST_PERMISSION_BLE_SCAN && grantResults[0] == PackageManager.PERMISSION_GRANTED 23 | -------------------------------------------------------------------------------- /sample-kotlin/src/main/kotlin/com/polidea/rxandroidble2/samplekotlin/util/UI.kt: -------------------------------------------------------------------------------- 1 | package com.polidea.rxandroidble2.samplekotlin.util 2 | 3 | import android.app.Activity 4 | import androidx.annotation.StringRes 5 | import com.google.android.material.snackbar.Snackbar 6 | 7 | internal fun Activity.showSnackbarShort(text: CharSequence) { 8 | Snackbar.make(findViewById(android.R.id.content), text, Snackbar.LENGTH_SHORT).show() 9 | } 10 | 11 | internal fun Activity.showSnackbarShort(@StringRes text: Int) { 12 | Snackbar.make(findViewById(android.R.id.content), text, Snackbar.LENGTH_SHORT).show() 13 | } -------------------------------------------------------------------------------- /sample-kotlin/src/main/res/drawable/ic_keyboard_arrow_right_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /sample-kotlin/src/main/res/layout/activity_device.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 |