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