Merge pull request #515 from andrekir/targetsdk31

update targetSdkVersion to 31
master
Andre K 2022-11-04 18:47:54 -03:00 zatwierdzone przez GitHub
commit f56f5a1a5f
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
9 zmienionych plików z 99 dodań i 146 usunięć

Wyświetl plik

@ -42,7 +42,7 @@ android {
defaultConfig { defaultConfig {
applicationId "com.geeksville.mesh" applicationId "com.geeksville.mesh"
minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works) minSdkVersion 21 // The oldest emulator image I have tried is 22 (though 21 probably works)
targetSdkVersion 30 targetSdkVersion 31
versionCode 30000 // format is Mmmss (where M is 1+the numeric major number versionCode 30000 // format is Mmmss (where M is 1+the numeric major number
versionName "2.0.0" versionName "2.0.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

Wyświetl plik

@ -11,23 +11,21 @@
android:name="android.hardware.location.gps" android:name="android.hardware.location.gps"
android:required="false" /> android:required="false" />
<!-- TODO - wait for targetSdkVersion 31 <!-- Request legacy Bluetooth permissions on older devices -->
&lt;!&ndash; Request legacy Bluetooth permissions on older devices &ndash;&gt;
<uses-permission android:name="android.permission.BLUETOOTH" <uses-permission android:name="android.permission.BLUETOOTH"
android:maxSdkVersion="30" /> android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
android:maxSdkVersion="30" /> android:maxSdkVersion="30" />
&lt;!&ndash; API 31+ Bluetooth permissions &ndash;&gt; <!-- API 31+ Bluetooth permissions -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" <uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation" /> android:usesPermissionFlags="neverForLocation"
--> tools:targetApi="s" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Permissions required for providing location (from phone GPS) to mesh --> <!-- Permissions required for providing location (from phone GPS) to mesh -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!-- This permission is required for analytics - and soon the MQTT gateway --> <!-- This permission is required for analytics - and soon the MQTT gateway -->

Wyświetl plik

@ -8,7 +8,10 @@ import android.content.pm.PackageManager
import android.hardware.usb.UsbDevice import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager import android.hardware.usb.UsbManager
import android.net.Uri import android.net.Uri
import android.os.* import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.os.RemoteException
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
@ -19,20 +22,14 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction import androidx.fragment.app.FragmentTransaction
import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.adapter.FragmentStateAdapter
import com.geeksville.mesh.android.BindFailedException import com.geeksville.mesh.android.*
import com.geeksville.mesh.android.GeeksvilleApplication
import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.android.ServiceClient
import com.geeksville.mesh.concurrent.handledLaunch import com.geeksville.mesh.concurrent.handledLaunch
import com.geeksville.mesh.android.getMissingPermissions
import com.geeksville.mesh.android.isGooglePlayAvailable
import com.geeksville.mesh.databinding.ActivityMainBinding import com.geeksville.mesh.databinding.ActivityMainBinding
import com.geeksville.mesh.model.BTScanModel import com.geeksville.mesh.model.BTScanModel
import com.geeksville.mesh.model.BluetoothViewModel import com.geeksville.mesh.model.BluetoothViewModel
@ -130,8 +127,9 @@ class MainActivity : BaseActivity(), Logging {
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
if (!permissions.entries.all { it.value }) { if (!permissions.entries.all { it.value }) {
errormsg("User denied permissions") errormsg("User denied permissions")
showSnackbar(getString(R.string.permission_missing_31)) showSnackbar(permissionMissing)
} }
requestedEnable = false
bluetoothViewModel.permissionsUpdated() bluetoothViewModel.permissionsUpdated()
} }
@ -181,71 +179,6 @@ class MainActivity : BaseActivity(), Logging {
} }
} }
/** Get the minimum permissions our app needs to run correctly
*/
private fun getMinimumPermissions(): Array<String> {
val perms = mutableListOf<String>()
// We only need this for logging to capture files for the simulator - turn off for production
// perms.add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
/* TODO - wait for targetSdkVersion 31
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
perms.add(Manifest.permission.BLUETOOTH_SCAN)
perms.add(Manifest.permission.BLUETOOTH_CONNECT)
}
*/
return getMissingPermissions(perms)
}
/** Possibly prompt user to grant permissions
* @param shouldShowDialog usually true, but in cases where we've already shown a dialog elsewhere we skip it.
*
* @return true if we already have the needed permissions
*/
private fun requestPermission(
missingPerms: Array<String> = getMinimumPermissions(),
shouldShowDialog: Boolean = true
): Boolean =
if (missingPerms.isNotEmpty()) {
val shouldShow = missingPerms.filter {
ActivityCompat.shouldShowRequestPermissionRationale(this, it)
}
fun doRequest() {
info("requesting permissions")
// Ask for all the missing perms
requestPermissionsLauncher.launch(missingPerms)
}
if (shouldShow.isNotEmpty() && shouldShowDialog) {
// DID_REQUEST_PERM is an
// app-defined int constant. The callback method gets the
// result of the request.
warn("Permissions $shouldShow missing, we should show dialog")
MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.required_permissions))
.setMessage(getString(R.string.permission_missing_31))
.setNeutralButton(R.string.cancel) { _, _ ->
warn("User bailed due to permissions")
}
.setPositiveButton(R.string.accept) { _, _ ->
doRequest()
}
.show()
} else {
info("Permissions $missingPerms missing, no need to show dialog, just asking OS")
doRequest()
}
false
} else {
// Permission has already been granted
debug("We have our required permissions")
true
}
/// Ask user to rate in play store /// Ask user to rate in play store
private fun askToRate() { private fun askToRate() {
exceptionReporter { // we don't want to crash our app because of bugs in this optional feature exceptionReporter { // we don't want to crash our app because of bugs in this optional feature
@ -296,9 +229,6 @@ class MainActivity : BaseActivity(), Logging {
handleIntent(intent) handleIntent(intent)
if (isGooglePlayAvailable(this)) askToRate() if (isGooglePlayAvailable(this)) askToRate()
// if (!isInTestLab) - very important - even in test lab we must request permissions because we need location perms for some of our tests to pass
requestPermission()
} }
private fun initToolbar() { private fun initToolbar() {
@ -728,11 +658,22 @@ class MainActivity : BaseActivity(), Logging {
super.onStart() super.onStart()
bluetoothViewModel.enabled.observe(this) { enabled -> bluetoothViewModel.enabled.observe(this) { enabled ->
if (!enabled && !requestedEnable) { if (!enabled && !requestedEnable && scanModel.selectedBluetooth) {
if (!isInTestLab && scanModel.selectedBluetooth) { requestedEnable = true
requestedEnable = true if (hasBluetoothPermission()) {
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE) val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
bleRequestEnable.launch(enableBtIntent) bleRequestEnable.launch(enableBtIntent)
} else {
MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.required_permissions))
.setMessage(permissionMissing)
.setNeutralButton(R.string.cancel) { _, _ ->
warn("User bailed due to permissions")
}
.setPositiveButton(R.string.accept) { _, _ ->
info("requesting permissions")
requestPermissionsLauncher.launch(getBluetoothPermissions()) }
.show()
} }
} }
} }

Wyświetl plik

@ -8,14 +8,15 @@ import android.companion.CompanionDeviceManager
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.hardware.usb.UsbManager import android.hardware.usb.UsbManager
import android.os.Build
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.geeksville.mesh.MainActivity import com.geeksville.mesh.MainActivity
import com.geeksville.mesh.R
/** /**
* @return null on platforms without a BlueTooth driver (i.e. the emulator) * @return null on platforms without a BlueTooth driver (i.e. the emulator)
*/ */
val Context.bluetoothManager: BluetoothManager? get() = getSystemService(Context.BLUETOOTH_SERVICE) as? BluetoothManager? val Context.bluetoothManager: BluetoothManager?
get() = getSystemService(Context.BLUETOOTH_SERVICE).takeIf { hasBluetoothPermission() } as? BluetoothManager?
val Context.deviceManager: CompanionDeviceManager? val Context.deviceManager: CompanionDeviceManager?
get() { get() {
@ -36,7 +37,7 @@ val Context.locationManager: LocationManager get() = requireNotNull(getSystemSer
* @return true if CompanionDeviceManager API is present * @return true if CompanionDeviceManager API is present
*/ */
fun Context.hasCompanionDeviceApi(): Boolean = fun Context.hasCompanionDeviceApi(): Boolean =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O)
packageManager.hasSystemFeature(PackageManager.FEATURE_COMPANION_DEVICE_SETUP) packageManager.hasSystemFeature(PackageManager.FEATURE_COMPANION_DEVICE_SETUP)
else false else false
@ -51,6 +52,16 @@ fun Context.hasGps(): Boolean = locationManager.allProviders.contains(LocationMa
fun Context.gpsDisabled(): Boolean = fun Context.gpsDisabled(): Boolean =
if (hasGps()) !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) else false if (hasGps()) !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) else false
/**
* return the text string of the permissions missing
*/
val Context.permissionMissing: String
get() = if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.S) {
getString(R.string.permission_missing)
} else {
getString(R.string.permission_missing_31)
}
/** /**
* return a list of the permissions we don't have * return a list of the permissions we don't have
*/ */
@ -67,12 +78,12 @@ fun Context.getMissingPermissions(perms: List<String>): Array<String> = perms.fi
fun Context.getBluetoothPermissions(): Array<String> { fun Context.getBluetoothPermissions(): Array<String> {
val perms = mutableListOf<String>() val perms = mutableListOf<String>()
/* TODO - wait for targetSdkVersion 31 if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
perms.add(Manifest.permission.BLUETOOTH_SCAN) perms.add(Manifest.permission.BLUETOOTH_SCAN)
perms.add(Manifest.permission.BLUETOOTH_CONNECT) perms.add(Manifest.permission.BLUETOOTH_CONNECT)
} else if (!hasCompanionDeviceApi()) {
perms.add(Manifest.permission.ACCESS_FINE_LOCATION)
} }
*/
return getMissingPermissions(perms) return getMissingPermissions(perms)
} }
@ -109,7 +120,7 @@ fun Context.hasLocationPermission() = getLocationPermissions().isEmpty()
fun Context.getBackgroundPermissions(): Array<String> { fun Context.getBackgroundPermissions(): Array<String> {
val perms = mutableListOf(Manifest.permission.ACCESS_FINE_LOCATION) val perms = mutableListOf(Manifest.permission.ACCESS_FINE_LOCATION)
if (Build.VERSION.SDK_INT >= 29) // only added later if (android.os.Build.VERSION.SDK_INT >= 29) // only added later
perms.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION) perms.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
return getMissingPermissions(perms) return getMissingPermissions(perms)

Wyświetl plik

@ -128,10 +128,9 @@ class BTScanModel @Inject constructor(
debug("BTScanModel cleared") debug("BTScanModel cleared")
} }
private val bluetoothAdapter = context.bluetoothManager?.adapter
private val deviceManager get() = context.deviceManager private val deviceManager get() = context.deviceManager
val hasCompanionDeviceApi get() = context.hasCompanionDeviceApi() val hasCompanionDeviceApi get() = application.hasCompanionDeviceApi()
private val hasBluetoothPermission get() = application.hasBluetoothPermission() val hasBluetoothPermission get() = application.hasBluetoothPermission()
private val usbManager get() = context.usbManager private val usbManager get() = context.usbManager
var selectedAddress: String? = null var selectedAddress: String? = null
@ -219,8 +218,8 @@ class BTScanModel @Inject constructor(
fun setupScan(): Boolean { fun setupScan(): Boolean {
selectedAddress = radioInterfaceService.getDeviceAddress() selectedAddress = radioInterfaceService.getDeviceAddress()
return if (bluetoothAdapter == null || MockInterface.addressValid(context, usbRepository, "")) { return if (MockInterface.addressValid(context, usbRepository, "")) {
warn("No bluetooth adapter. Running under emulation?") warn("Running under emulator/test lab")
val testnodes = listOf( val testnodes = listOf(
DeviceListEntry("Included simulator", "m", true), DeviceListEntry("Included simulator", "m", true),
@ -273,14 +272,16 @@ class BTScanModel @Inject constructor(
private var networkDiscovery: Job? = null private var networkDiscovery: Job? = null
fun startScan() { fun startScan() {
_spinner.value = true
// Start Network Service Discovery (find TCP devices) // Start Network Service Discovery (find TCP devices)
networkDiscovery = nsdRepository.networkDiscoveryFlow() networkDiscovery = nsdRepository.networkDiscoveryFlow()
.onEach { addDevice(TCPDeviceListEntry(it)) } .onEach { addDevice(TCPDeviceListEntry(it)) }
.launchIn(CoroutineScope(Dispatchers.Main)) .launchIn(CoroutineScope(Dispatchers.Main))
if (hasCompanionDeviceApi) { if (hasBluetoothPermission) {
startCompanionScan() if (hasCompanionDeviceApi) startCompanionScan() else startClassicScan()
} else startClassicScan() }
} }
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
@ -290,7 +291,6 @@ class BTScanModel @Inject constructor(
if (bluetoothLeScanner != null) { // could be null if bluetooth is disabled if (bluetoothLeScanner != null) { // could be null if bluetooth is disabled
debug("starting classic scan") debug("starting classic scan")
_spinner.value = true
// filter and only accept devices that have our service // filter and only accept devices that have our service
val filter = val filter =
@ -373,7 +373,6 @@ class BTScanModel @Inject constructor(
@SuppressLint("NewApi") @SuppressLint("NewApi")
private fun startCompanionScan() { private fun startCompanionScan() {
debug("starting companion scan") debug("starting companion scan")
_spinner.value = true
deviceManager?.associate( deviceManager?.associate(
associationRequest(), associationRequest(),
@SuppressLint("NewApi") @SuppressLint("NewApi")
@ -479,7 +478,11 @@ class BTScanModel @Inject constructor(
} }
val permissionIntent = val permissionIntent =
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.S) {
PendingIntent.getBroadcast(activity, 0, Intent(ACTION_USB_PERMISSION), 0) PendingIntent.getBroadcast(activity, 0, Intent(ACTION_USB_PERMISSION), 0)
} else {
PendingIntent.getBroadcast(activity, 0, Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE)
}
val filter = IntentFilter(ACTION_USB_PERMISSION) val filter = IntentFilter(ACTION_USB_PERMISSION)
activity.registerReceiver(usbReceiver, filter) activity.registerReceiver(usbReceiver, filter)
usbManager.requestPermission(it.usb.device, permissionIntent) usbManager.requestPermission(it.usb.device, permissionIntent)

Wyświetl plik

@ -56,7 +56,9 @@ class BluetoothRepository @Inject constructor(
} }
fun getRemoteDevice(address: String): BluetoothDevice? { fun getRemoteDevice(address: String): BluetoothDevice? {
return bluetoothAdapterLazy.get()?.takeIf { isValid(address) }?.getRemoteDevice(address) return bluetoothAdapterLazy.get()
?.takeIf { application.hasBluetoothPermission() && isValid(address) }
?.getRemoteDevice(address)
} }
fun getBluetoothLeScanner(): BluetoothLeScanner? { fun getBluetoothLeScanner(): BluetoothLeScanner? {

Wyświetl plik

@ -1,12 +1,10 @@
package com.geeksville.mesh.repository.radio package com.geeksville.mesh.repository.radio
import android.annotation.SuppressLint
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothGattCharacteristic import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattService import android.bluetooth.BluetoothGattService
import android.bluetooth.BluetoothManager
import android.content.Context import android.content.Context
import com.geeksville.mesh.android.Logging import com.geeksville.mesh.android.Logging
import com.geeksville.mesh.android.bluetoothManager
import com.geeksville.mesh.concurrent.handledLaunch import com.geeksville.mesh.concurrent.handledLaunch
import com.geeksville.mesh.repository.usb.UsbRepository import com.geeksville.mesh.repository.usb.UsbRepository
import com.geeksville.mesh.service.* import com.geeksville.mesh.service.*
@ -110,22 +108,15 @@ class BluetoothInterface(
val BTM_FROMNUM_CHARACTER: UUID = val BTM_FROMNUM_CHARACTER: UUID =
UUID.fromString("ed9da18c-a800-4f66-a670-aa7547e34453") UUID.fromString("ed9da18c-a800-4f66-a670-aa7547e34453")
/// Get our bluetooth adapter (should always succeed except on emulator
private fun getBluetoothAdapter(context: Context): BluetoothAdapter? {
val bluetoothManager =
context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
return bluetoothManager.adapter
}
/** Return true if this address is still acceptable. For BLE that means, still bonded */ /** Return true if this address is still acceptable. For BLE that means, still bonded */
@SuppressLint("NewApi", "MissingPermission")
override fun addressValid( override fun addressValid(
context: Context, context: Context,
usbRepository: UsbRepository, // Temporary until dependency injection transition is completed usbRepository: UsbRepository, // Temporary until dependency injection transition is completed
rest: String rest: String
): Boolean { ): Boolean {
val allPaired = getBluetoothAdapter(context)?.bondedDevices.orEmpty() /// Get our bluetooth adapter (should always succeed except on emulator
.map { it.address }.toSet() val allPaired = context.bluetoothManager?.adapter?.bondedDevices.orEmpty()
.map { it.address }.toSet()
return if (!allPaired.contains(rest)) { return if (!allPaired.contains(rest)) {
warn("Ignoring stale bond to ${rest.anonymize}") warn("Ignoring stale bond to ${rest.anonymize}")
false false
@ -170,7 +161,7 @@ class BluetoothInterface(
init { init {
// Note: this call does no comms, it just creates the device object (even if the // Note: this call does no comms, it just creates the device object (even if the
// device is off/not connected) // device is off/not connected)
val device = getBluetoothAdapter(context)?.getRemoteDevice(address) val device = context.bluetoothManager?.adapter?.getRemoteDevice(address)
if (device != null) { if (device != null) {
info("Creating radio interface service. device=${address.anonymize}") info("Creating radio interface service. device=${address.anonymize}")

Wyświetl plik

@ -106,7 +106,11 @@ class MeshServiceNotifications(
) )
private val openAppIntent: PendingIntent by lazy { private val openAppIntent: PendingIntent by lazy {
PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), 0) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), 0)
} else {
PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), PendingIntent.FLAG_IMMUTABLE)
}
} }
/** /**

Wyświetl plik

@ -261,7 +261,10 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
if (permissions.entries.all { it.value }) { if (permissions.entries.all { it.value }) {
binding.provideLocationCheckbox.isChecked = true binding.provideLocationCheckbox.isChecked = true
} else debug("User denied background permission") } else {
debug("User denied background permission")
showSnackbar(getString(R.string.why_background_required))
}
} }
val requestLocationAndBackgroundLauncher = val requestLocationAndBackgroundLauncher =
@ -271,7 +274,10 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
if (myActivity.hasBackgroundPermission()) { if (myActivity.hasBackgroundPermission()) {
binding.provideLocationCheckbox.isChecked = true binding.provideLocationCheckbox.isChecked = true
} else requestBackgroundAndCheckLauncher.launch(myActivity.getBackgroundPermissions()) } else requestBackgroundAndCheckLauncher.launch(myActivity.getBackgroundPermissions())
} else debug("User denied location permission") } else {
debug("User denied location permission")
showSnackbar(getString(R.string.why_background_required))
}
} }
// init our region spinner // init our region spinner
@ -506,37 +512,34 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
val requestPermissionAndScanLauncher = val requestPermissionAndScanLauncher =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions -> registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
if (permissions.entries.all { it.value }) { if (permissions.entries.all { it.value }) {
checkLocationEnabled() checkBTEnabled()
if (!scanModel.hasCompanionDeviceApi) checkLocationEnabled()
scanLeDevice() scanLeDevice()
} else { } else {
errormsg("User denied scan permissions") errormsg("User denied scan permissions")
showSnackbar(getString(R.string.permission_missing)) showSnackbar(requireContext().permissionMissing)
} }
bluetoothViewModel.permissionsUpdated()
} }
binding.changeRadioButton.setOnClickListener { binding.changeRadioButton.setOnClickListener {
debug("User clicked changeRadioButton") debug("User clicked changeRadioButton")
checkBTEnabled() scanLeDevice()
if ((scanModel.hasCompanionDeviceApi)) { if (scanModel.hasBluetoothPermission) {
scanLeDevice() checkBTEnabled()
} else { if (!scanModel.hasCompanionDeviceApi) checkLocationEnabled()
// Location is the only runtime permission for classic bluetooth scan } else {
if (myActivity.hasLocationPermission()) { MaterialAlertDialogBuilder(requireContext())
checkLocationEnabled() .setTitle(getString(R.string.required_permissions))
scanLeDevice() .setMessage(requireContext().permissionMissing)
} else { .setNeutralButton(R.string.cancel) { _, _ ->
MaterialAlertDialogBuilder(requireContext()) warn("User bailed due to permissions")
.setTitle(getString(R.string.required_permissions)) }
.setMessage(getString(R.string.permission_missing)) .setPositiveButton(R.string.accept) { _, _ ->
.setNeutralButton(R.string.cancel) { _, _ -> info("requesting scan permissions")
warn("User bailed due to permissions") requestPermissionAndScanLauncher.launch(myActivity.getBluetoothPermissions())
} }
.setPositiveButton(R.string.accept) { _, _ -> .show()
info("requesting scan permissions")
requestPermissionAndScanLauncher.launch(myActivity.getLocationPermissions())
}
.show()
}
} }
} }
} }