diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 44be80c..57246a0 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -23,8 +23,8 @@ android {
applicationId = "f.cking.software"
minSdk = 29
targetSdk = 34
- versionCode = 1704045673
- versionName = "0.21.5-beta"
+ versionCode = 1704045674
+ versionName = "0.21.6-beta"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8150c57..0cf0938 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,12 +5,12 @@
-
+
diff --git a/app/src/main/java/f/cking/software/data/helpers/BleFiltersProvider.kt b/app/src/main/java/f/cking/software/data/helpers/BleFiltersProvider.kt
index c81b248..6f3f0a7 100644
--- a/app/src/main/java/f/cking/software/data/helpers/BleFiltersProvider.kt
+++ b/app/src/main/java/f/cking/software/data/helpers/BleFiltersProvider.kt
@@ -40,11 +40,13 @@ class BleFiltersProvider(
}
suspend fun getBGFilters(): List {
- return getKnownDevicesInteractor.execute().map {
- ScanFilter.Builder()
- .setDeviceAddress(it.address)
- .build()
- }
+ return getKnownDevicesInteractor.execute()
+ .take(KNOWN_DEVICES_LIMIT) // Limit filters to fit into android scan registerer limitations
+ .map {
+ ScanFilter.Builder()
+ .setDeviceAddress(it.address)
+ .build()
+ }
}
private object NearByData {
@@ -58,15 +60,18 @@ class BleFiltersProvider(
}
private object AirdropData {
- val bytes: ByteArray = listOf(0x05, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x0D, 0xC1, 0xF6, 0xFA, 0xE3, 0x11, 0x00, 0x00)
- .map { it.toUByte().toByte() }
- .toByteArray()
- val bytesMask: ByteArray = listOf(0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
- .map { it.toUByte().toByte() }
- .toByteArray()
+ val bytes: ByteArray =
+ listOf(0x05, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0B, 0x0D, 0xC1, 0xF6, 0xFA, 0xE3, 0x11, 0x00, 0x00)
+ .map { it.toUByte().toByte() }
+ .toByteArray()
+ val bytesMask: ByteArray =
+ listOf(0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
+ .map { it.toUByte().toByte() }
+ .toByteArray()
}
companion object {
+ private const val KNOWN_DEVICES_LIMIT = 3000
private val popularServicesUUID = setOf(
"0000fe8f-0000-1000-8000-00805f9b34fb",
"0000fe9f-0000-1000-8000-00805f9b34fb",
diff --git a/app/src/main/java/f/cking/software/data/helpers/BleScanErrorMapper.kt b/app/src/main/java/f/cking/software/data/helpers/BleScanErrorMapper.kt
new file mode 100644
index 0000000..78fe27a
--- /dev/null
+++ b/app/src/main/java/f/cking/software/data/helpers/BleScanErrorMapper.kt
@@ -0,0 +1,18 @@
+package f.cking.software.data.helpers
+
+import android.bluetooth.le.ScanCallback
+
+object BleScanErrorMapper {
+
+ fun map(errorCode: Int): String {
+ return when (errorCode) {
+ ScanCallback.SCAN_FAILED_ALREADY_STARTED -> "Scan already started"
+ ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED -> "Application registration failed"
+ ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED -> "Feature unsupported"
+ ScanCallback.SCAN_FAILED_INTERNAL_ERROR -> "Internal error"
+ ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES -> "Out of hardware resources"
+ ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY -> "Scanning too frequently"
+ else -> "Unknown error"
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/f/cking/software/data/helpers/BleScannerHelper.kt b/app/src/main/java/f/cking/software/data/helpers/BleScannerHelper.kt
index e8ab0ec..0b17400 100644
--- a/app/src/main/java/f/cking/software/data/helpers/BleScannerHelper.kt
+++ b/app/src/main/java/f/cking/software/data/helpers/BleScannerHelper.kt
@@ -119,9 +119,11 @@ class BleScannerHelper(
Timber.d("BLE Scan finished ${batch.count()} devices found")
scanListener?.onSuccess(batch.values.toList())
}
+
is ScanResultInternal.Failure -> {
- scanListener?.onFailure(BLEScanFailure(scanResult.errorCode))
+ scanListener?.onFailure(BLEScanFailure(scanResult.errorCode, BleScanErrorMapper.map(scanResult.errorCode)))
}
+
is ScanResultInternal.Canceled -> {
// do nothing
}
@@ -155,7 +157,8 @@ class BleScannerHelper(
object Canceled : ScanResultInternal
}
- class BLEScanFailure(errorCode: Int) : RuntimeException("BLE Scan failed with error code: $errorCode")
+ class BLEScanFailure(errorCode: Int, errorDescription: String) :
+ RuntimeException("BLE Scan failed with error code: $errorCode (${errorDescription})")
class BluetoothIsNotInitialized : RuntimeException("Bluetooth is turned off or not available on this device")
}
\ No newline at end of file
diff --git a/app/src/main/java/f/cking/software/service/BootBroadcastReceiver.kt b/app/src/main/java/f/cking/software/service/BootBroadcastReceiver.kt
index 0f22358..e361591 100644
--- a/app/src/main/java/f/cking/software/service/BootBroadcastReceiver.kt
+++ b/app/src/main/java/f/cking/software/service/BootBroadcastReceiver.kt
@@ -5,12 +5,21 @@ import android.content.Context
import android.content.Intent
import f.cking.software.data.helpers.PermissionHelper
import f.cking.software.data.repo.SettingsRepository
+import f.cking.software.domain.interactor.SaveReportInteractor
+import f.cking.software.domain.model.JournalEntry
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
import org.koin.java.KoinJavaComponent.inject
+import timber.log.Timber
class BootBroadcastReceiver : BroadcastReceiver() {
private val permissionHelper: PermissionHelper by inject(PermissionHelper::class.java)
private val settingsRepository: SettingsRepository by inject(SettingsRepository::class.java)
+ private val saveReportInteractor: SaveReportInteractor by inject(SaveReportInteractor::class.java)
+ private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
@@ -19,8 +28,23 @@ class BootBroadcastReceiver : BroadcastReceiver() {
}
private fun tryToRunService(context: Context) {
- if (settingsRepository.getRunOnStartup() && permissionHelper.checkAllPermissions()) {
- BgScanService.start(context)
+ if (settingsRepository.getRunOnStartup()) {
+ if (permissionHelper.checkAllPermissions()) {
+ try {
+ BgScanService.start(context)
+ } catch (error: Exception) {
+ Timber.e(error, "Failed to start service from the boot receiver")
+ val report = JournalEntry.Report.Error(
+ title = "[Launch on system startup error]: ${error.message ?: error::class.java}",
+ stackTrace = error.stackTraceToString(),
+ )
+ scope.launch {
+ saveReportInteractor.execute(report)
+ }
+ }
+ } else {
+ Timber.e("Not all permissions granted, can't start service from the boot receiver")
+ }
}
}
}
\ No newline at end of file