diff --git a/lib_scanner/src/main/AndroidManifest.xml b/lib_scanner/src/main/AndroidManifest.xml index 0c84e474..9a69f4cb 100644 --- a/lib_scanner/src/main/AndroidManifest.xml +++ b/lib_scanner/src/main/AndroidManifest.xml @@ -1,15 +1,14 @@ + + - \ No newline at end of file diff --git a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ListOfDevicesScreen.kt b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ListOfDevicesScreen.kt deleted file mode 100644 index dd10e80c..00000000 --- a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ListOfDevicesScreen.kt +++ /dev/null @@ -1,71 +0,0 @@ -package no.nordicsemi.android.scanner - -import android.annotation.SuppressLint -import android.bluetooth.BluetoothDevice -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed -import androidx.compose.material.Button -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel -import no.nordicsemi.android.events.exhaustive - -@Composable -internal fun ListOfDevicesScreen(onDeviceSelected: (BluetoothDevice) -> Unit) { - - val viewModel = hiltViewModel() - - val result = viewModel.scannerResult.collectAsState().value - - when (result) { - is DeviceListResult -> DeviceListView(result.devices, onDeviceSelected) - is ScanningErrorResult -> ScanningErrorView() - }.exhaustive -} - -@SuppressLint("MissingPermission") -@Composable -private fun DeviceListView( - devices: List, - onDeviceSelected: (BluetoothDevice) -> Unit -) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Spacer(modifier = Modifier.height(16.dp)) - Text(stringResource(id = R.string.scanner__list_of_devices)) - Spacer(modifier = Modifier.height(16.dp)) - LazyColumn( - modifier = Modifier.padding(horizontal = 16.dp), - verticalArrangement = Arrangement.spacedBy(12.dp) - ) { - - itemsIndexed(devices) { _, device -> - Button( - modifier = Modifier.fillMaxWidth(), - onClick = { onDeviceSelected(device) } - ) { - Column { - Text(device.name ?: stringResource(id = R.string.scanner__no_name)) - Spacer(modifier = Modifier.height(8.dp)) - Text(text = device.address) - } - } - } - } - } -} - -@Composable -private fun ScanningErrorView() { - Text(text = stringResource(id = R.string.scanner__error)) -} diff --git a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ScannerNavigation.kt b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ScannerNavigation.kt index d419795a..c4f29664 100644 --- a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ScannerNavigation.kt +++ b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ScannerNavigation.kt @@ -9,9 +9,13 @@ import androidx.compose.ui.res.stringResource import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavController import no.nordicsemi.android.events.exhaustive -import no.nordicsemi.android.scanner.bluetooth.BluetoothNotAvailableScreen -import no.nordicsemi.android.scanner.bluetooth.BluetoothNotEnabledScreen -import no.nordicsemi.android.scanner.permissions.RequestPermissionScreen +import no.nordicsemi.android.scanner.tools.ScannerStatus +import no.nordicsemi.android.scanner.ui.BluetoothNotAvailableScreen +import no.nordicsemi.android.scanner.ui.BluetoothNotEnabledScreen +import no.nordicsemi.android.scanner.ui.NordicBleScannerViewModel +import no.nordicsemi.android.scanner.ui.RequestPermissionScreen +import no.nordicsemi.android.scanner.ui.ScanDeviceScreen +import no.nordicsemi.android.scanner.ui.ScannerViewEvent @Composable fun ScannerRoute(navController: NavController) { @@ -35,15 +39,6 @@ private fun ScannerScreen( ScannerStatus.PERMISSION_REQUIRED -> RequestPermissionScreen { onEvent(ScannerViewEvent.PERMISSION_CHECKED) } ScannerStatus.NOT_AVAILABLE -> BluetoothNotAvailableScreen() ScannerStatus.DISABLED -> BluetoothNotEnabledScreen { onEvent(ScannerViewEvent.BLUETOOTH_ENABLED) } - ScannerStatus.ENABLED -> { - onEvent(ScannerViewEvent.ENABLE_SCANNING) - ListOfDevicesScreen { - navController.previousBackStackEntry - ?.savedStateHandle - ?.set("result", it) - navController.popBackStack() - onEvent(ScannerViewEvent.DISABLE_SCANNING) - } - } + ScannerStatus.ENABLED -> ScanDeviceScreen(navController) }.exhaustive } diff --git a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/NordicBleScanner.kt b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/tools/NordicBleScanner.kt similarity index 97% rename from lib_scanner/src/main/java/no/nordicsemi/android/scanner/NordicBleScanner.kt rename to lib_scanner/src/main/java/no/nordicsemi/android/scanner/tools/NordicBleScanner.kt index 51598215..4e9dd055 100644 --- a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/NordicBleScanner.kt +++ b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/tools/NordicBleScanner.kt @@ -1,4 +1,4 @@ -package no.nordicsemi.android.scanner +package no.nordicsemi.android.scanner.tools import android.annotation.SuppressLint import android.bluetooth.BluetoothAdapter diff --git a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ScannerStatus.kt b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/tools/ScannerStatus.kt similarity index 66% rename from lib_scanner/src/main/java/no/nordicsemi/android/scanner/ScannerStatus.kt rename to lib_scanner/src/main/java/no/nordicsemi/android/scanner/tools/ScannerStatus.kt index 7c5888a9..5f992fe5 100644 --- a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ScannerStatus.kt +++ b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/tools/ScannerStatus.kt @@ -1,4 +1,4 @@ -package no.nordicsemi.android.scanner +package no.nordicsemi.android.scanner.tools enum class ScannerStatus { PERMISSION_REQUIRED, ENABLED, DISABLED, NOT_AVAILABLE diff --git a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/bluetooth/BluetoothNotAvailableScreen.kt b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ui/BluetoothNotAvailableScreen.kt similarity index 95% rename from lib_scanner/src/main/java/no/nordicsemi/android/scanner/bluetooth/BluetoothNotAvailableScreen.kt rename to lib_scanner/src/main/java/no/nordicsemi/android/scanner/ui/BluetoothNotAvailableScreen.kt index 898b1cf4..5594d858 100644 --- a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/bluetooth/BluetoothNotAvailableScreen.kt +++ b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ui/BluetoothNotAvailableScreen.kt @@ -1,4 +1,4 @@ -package no.nordicsemi.android.scanner.bluetooth +package no.nordicsemi.android.scanner.ui import android.app.Activity import android.bluetooth.BluetoothAdapter diff --git a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/NordicBleScannerViewModel.kt b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ui/NordicBleScannerViewModel.kt similarity index 81% rename from lib_scanner/src/main/java/no/nordicsemi/android/scanner/NordicBleScannerViewModel.kt rename to lib_scanner/src/main/java/no/nordicsemi/android/scanner/ui/NordicBleScannerViewModel.kt index fcedb47a..cf1ff187 100644 --- a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/NordicBleScannerViewModel.kt +++ b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ui/NordicBleScannerViewModel.kt @@ -1,9 +1,11 @@ -package no.nordicsemi.android.scanner +package no.nordicsemi.android.scanner.ui import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import no.nordicsemi.android.events.exhaustive +import no.nordicsemi.android.scanner.tools.NordicBleScanner +import no.nordicsemi.android.scanner.tools.ScannerStatus import javax.inject.Inject @HiltViewModel @@ -20,8 +22,6 @@ internal class NordicBleScannerViewModel @Inject constructor( when (event) { ScannerViewEvent.PERMISSION_CHECKED -> onPermissionChecked() ScannerViewEvent.BLUETOOTH_ENABLED -> onBluetoothEnabled() - ScannerViewEvent.ENABLE_SCANNING -> bleScanner.startScanning() - ScannerViewEvent.DISABLE_SCANNING -> bleScanner.stopScanning() }.exhaustive } @@ -36,7 +36,7 @@ internal class NordicBleScannerViewModel @Inject constructor( } enum class ScannerViewEvent { - PERMISSION_CHECKED, BLUETOOTH_ENABLED, ENABLE_SCANNING, DISABLE_SCANNING + PERMISSION_CHECKED, BLUETOOTH_ENABLED } internal data class NordicBleScannerState( diff --git a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/permissions/RequestPermissionScreen.kt b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ui/RequestPermissionScreen.kt similarity index 98% rename from lib_scanner/src/main/java/no/nordicsemi/android/scanner/permissions/RequestPermissionScreen.kt rename to lib_scanner/src/main/java/no/nordicsemi/android/scanner/ui/RequestPermissionScreen.kt index 87fd8283..6e7d5918 100644 --- a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/permissions/RequestPermissionScreen.kt +++ b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ui/RequestPermissionScreen.kt @@ -1,4 +1,4 @@ -package no.nordicsemi.android.scanner.permissions +package no.nordicsemi.android.scanner.ui import android.content.Context import android.content.Intent diff --git a/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ui/ScanDeviceScreen.kt b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ui/ScanDeviceScreen.kt new file mode 100644 index 00000000..aef0b6b2 --- /dev/null +++ b/lib_scanner/src/main/java/no/nordicsemi/android/scanner/ui/ScanDeviceScreen.kt @@ -0,0 +1,62 @@ +package no.nordicsemi.android.scanner.ui + +import android.app.Activity +import android.bluetooth.BluetoothDevice +import android.companion.AssociationRequest +import android.companion.BluetoothDeviceFilter +import android.companion.CompanionDeviceManager +import android.content.Context +import android.content.IntentSender +import android.os.Build +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.IntentSenderRequest +import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext +import androidx.navigation.NavController + +@Composable +fun ScanDeviceScreen(navController: NavController,) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val deviceFilter: BluetoothDeviceFilter = BluetoothDeviceFilter.Builder() + .build() + + val pairingRequest: AssociationRequest = AssociationRequest.Builder() + .build() + + val deviceManager = + LocalContext.current.getSystemService(Context.COMPANION_DEVICE_SERVICE) as CompanionDeviceManager + + val contract = ActivityResultContracts.StartIntentSenderForResult() + val launcher = rememberLauncherForActivityResult(contract = contract, onResult = { + if (it.resultCode == Activity.RESULT_OK) { + val deviceToPair: BluetoothDevice? = it.data?.getParcelableExtra( + CompanionDeviceManager.EXTRA_DEVICE) + navController.previousBackStackEntry + ?.savedStateHandle + ?.set("result", deviceToPair) + navController.popBackStack() + } + }) + + val hasBeenInvoked = remember { mutableStateOf(false) } + if (hasBeenInvoked.value) { + return + } + hasBeenInvoked.value = true + deviceManager.associate(pairingRequest, + object : CompanionDeviceManager.Callback() { + override fun onDeviceFound(chooserLauncher: IntentSender) { + val request = IntentSenderRequest.Builder(chooserLauncher).build() + launcher.launch(request) + } + + override fun onFailure(error: CharSequence?) { + } + }, null) + } else { + TODO("VERSION.SDK_INT < O") + } +} \ No newline at end of file