kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
commit
f56f5a1a5f
|
@ -42,7 +42,7 @@ android {
|
|||
defaultConfig {
|
||||
applicationId "com.geeksville.mesh"
|
||||
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
|
||||
versionName "2.0.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
|
|
@ -11,23 +11,21 @@
|
|||
android:name="android.hardware.location.gps"
|
||||
android:required="false" />
|
||||
|
||||
<!-- TODO - wait for targetSdkVersion 31
|
||||
<!– Request legacy Bluetooth permissions on older devices –>
|
||||
<!-- Request legacy Bluetooth permissions on older devices -->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH"
|
||||
android:maxSdkVersion="30" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
|
||||
android:maxSdkVersion="30" />
|
||||
|
||||
<!– API 31+ Bluetooth permissions –>
|
||||
<!-- API 31+ Bluetooth permissions -->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
|
||||
android:usesPermissionFlags="neverForLocation" />
|
||||
-->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
android:usesPermissionFlags="neverForLocation"
|
||||
tools:targetApi="s" />
|
||||
|
||||
<!-- 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_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||
|
||||
<!-- This permission is required for analytics - and soon the MQTT gateway -->
|
||||
|
|
|
@ -8,7 +8,10 @@ import android.content.pm.PackageManager
|
|||
import android.hardware.usb.UsbDevice
|
||||
import android.hardware.usb.UsbManager
|
||||
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.view.Menu
|
||||
import android.view.MenuItem
|
||||
|
@ -19,20 +22,14 @@ import androidx.activity.result.contract.ActivityResultContracts
|
|||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.FragmentTransaction
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import com.geeksville.mesh.android.BindFailedException
|
||||
import com.geeksville.mesh.android.GeeksvilleApplication
|
||||
import com.geeksville.mesh.android.Logging
|
||||
import com.geeksville.mesh.android.ServiceClient
|
||||
import com.geeksville.mesh.android.*
|
||||
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.model.BTScanModel
|
||||
import com.geeksville.mesh.model.BluetoothViewModel
|
||||
|
@ -130,8 +127,9 @@ class MainActivity : BaseActivity(), Logging {
|
|||
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
|
||||
if (!permissions.entries.all { it.value }) {
|
||||
errormsg("User denied permissions")
|
||||
showSnackbar(getString(R.string.permission_missing_31))
|
||||
showSnackbar(permissionMissing)
|
||||
}
|
||||
requestedEnable = false
|
||||
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
|
||||
private fun askToRate() {
|
||||
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)
|
||||
|
||||
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() {
|
||||
|
@ -728,11 +658,22 @@ class MainActivity : BaseActivity(), Logging {
|
|||
super.onStart()
|
||||
|
||||
bluetoothViewModel.enabled.observe(this) { enabled ->
|
||||
if (!enabled && !requestedEnable) {
|
||||
if (!isInTestLab && scanModel.selectedBluetooth) {
|
||||
requestedEnable = true
|
||||
if (!enabled && !requestedEnable && scanModel.selectedBluetooth) {
|
||||
requestedEnable = true
|
||||
if (hasBluetoothPermission()) {
|
||||
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,14 +8,15 @@ import android.companion.CompanionDeviceManager
|
|||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.hardware.usb.UsbManager
|
||||
import android.os.Build
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.geeksville.mesh.MainActivity
|
||||
import com.geeksville.mesh.R
|
||||
|
||||
/**
|
||||
* @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?
|
||||
get() {
|
||||
|
@ -36,7 +37,7 @@ val Context.locationManager: LocationManager get() = requireNotNull(getSystemSer
|
|||
* @return true if CompanionDeviceManager API is present
|
||||
*/
|
||||
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)
|
||||
else false
|
||||
|
||||
|
@ -51,6 +52,16 @@ fun Context.hasGps(): Boolean = locationManager.allProviders.contains(LocationMa
|
|||
fun Context.gpsDisabled(): Boolean =
|
||||
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
|
||||
*/
|
||||
|
@ -67,12 +78,12 @@ fun Context.getMissingPermissions(perms: List<String>): Array<String> = perms.fi
|
|||
fun Context.getBluetoothPermissions(): Array<String> {
|
||||
val perms = mutableListOf<String>()
|
||||
|
||||
/* TODO - wait for targetSdkVersion 31
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
|
||||
perms.add(Manifest.permission.BLUETOOTH_SCAN)
|
||||
perms.add(Manifest.permission.BLUETOOTH_CONNECT)
|
||||
} else if (!hasCompanionDeviceApi()) {
|
||||
perms.add(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
}
|
||||
*/
|
||||
return getMissingPermissions(perms)
|
||||
}
|
||||
|
||||
|
@ -109,7 +120,7 @@ fun Context.hasLocationPermission() = getLocationPermissions().isEmpty()
|
|||
fun Context.getBackgroundPermissions(): Array<String> {
|
||||
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)
|
||||
|
||||
return getMissingPermissions(perms)
|
||||
|
|
|
@ -128,10 +128,9 @@ class BTScanModel @Inject constructor(
|
|||
debug("BTScanModel cleared")
|
||||
}
|
||||
|
||||
private val bluetoothAdapter = context.bluetoothManager?.adapter
|
||||
private val deviceManager get() = context.deviceManager
|
||||
val hasCompanionDeviceApi get() = context.hasCompanionDeviceApi()
|
||||
private val hasBluetoothPermission get() = application.hasBluetoothPermission()
|
||||
val hasCompanionDeviceApi get() = application.hasCompanionDeviceApi()
|
||||
val hasBluetoothPermission get() = application.hasBluetoothPermission()
|
||||
private val usbManager get() = context.usbManager
|
||||
|
||||
var selectedAddress: String? = null
|
||||
|
@ -219,8 +218,8 @@ class BTScanModel @Inject constructor(
|
|||
fun setupScan(): Boolean {
|
||||
selectedAddress = radioInterfaceService.getDeviceAddress()
|
||||
|
||||
return if (bluetoothAdapter == null || MockInterface.addressValid(context, usbRepository, "")) {
|
||||
warn("No bluetooth adapter. Running under emulation?")
|
||||
return if (MockInterface.addressValid(context, usbRepository, "")) {
|
||||
warn("Running under emulator/test lab")
|
||||
|
||||
val testnodes = listOf(
|
||||
DeviceListEntry("Included simulator", "m", true),
|
||||
|
@ -273,14 +272,16 @@ class BTScanModel @Inject constructor(
|
|||
|
||||
private var networkDiscovery: Job? = null
|
||||
fun startScan() {
|
||||
_spinner.value = true
|
||||
|
||||
// Start Network Service Discovery (find TCP devices)
|
||||
networkDiscovery = nsdRepository.networkDiscoveryFlow()
|
||||
.onEach { addDevice(TCPDeviceListEntry(it)) }
|
||||
.launchIn(CoroutineScope(Dispatchers.Main))
|
||||
|
||||
if (hasCompanionDeviceApi) {
|
||||
startCompanionScan()
|
||||
} else startClassicScan()
|
||||
if (hasBluetoothPermission) {
|
||||
if (hasCompanionDeviceApi) startCompanionScan() else startClassicScan()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
|
@ -290,7 +291,6 @@ class BTScanModel @Inject constructor(
|
|||
|
||||
if (bluetoothLeScanner != null) { // could be null if bluetooth is disabled
|
||||
debug("starting classic scan")
|
||||
_spinner.value = true
|
||||
|
||||
// filter and only accept devices that have our service
|
||||
val filter =
|
||||
|
@ -373,7 +373,6 @@ class BTScanModel @Inject constructor(
|
|||
@SuppressLint("NewApi")
|
||||
private fun startCompanionScan() {
|
||||
debug("starting companion scan")
|
||||
_spinner.value = true
|
||||
deviceManager?.associate(
|
||||
associationRequest(),
|
||||
@SuppressLint("NewApi")
|
||||
|
@ -479,7 +478,11 @@ class BTScanModel @Inject constructor(
|
|||
}
|
||||
|
||||
val permissionIntent =
|
||||
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.S) {
|
||||
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)
|
||||
activity.registerReceiver(usbReceiver, filter)
|
||||
usbManager.requestPermission(it.usb.device, permissionIntent)
|
||||
|
|
|
@ -56,7 +56,9 @@ class BluetoothRepository @Inject constructor(
|
|||
}
|
||||
|
||||
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? {
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package com.geeksville.mesh.repository.radio
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothGattCharacteristic
|
||||
import android.bluetooth.BluetoothGattService
|
||||
import android.bluetooth.BluetoothManager
|
||||
import android.content.Context
|
||||
import com.geeksville.mesh.android.Logging
|
||||
import com.geeksville.mesh.android.bluetoothManager
|
||||
import com.geeksville.mesh.concurrent.handledLaunch
|
||||
import com.geeksville.mesh.repository.usb.UsbRepository
|
||||
import com.geeksville.mesh.service.*
|
||||
|
@ -110,22 +108,15 @@ class BluetoothInterface(
|
|||
val BTM_FROMNUM_CHARACTER: UUID =
|
||||
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 */
|
||||
@SuppressLint("NewApi", "MissingPermission")
|
||||
override fun addressValid(
|
||||
context: Context,
|
||||
usbRepository: UsbRepository, // Temporary until dependency injection transition is completed
|
||||
rest: String
|
||||
): Boolean {
|
||||
val allPaired = getBluetoothAdapter(context)?.bondedDevices.orEmpty()
|
||||
.map { it.address }.toSet()
|
||||
/// Get our bluetooth adapter (should always succeed except on emulator
|
||||
val allPaired = context.bluetoothManager?.adapter?.bondedDevices.orEmpty()
|
||||
.map { it.address }.toSet()
|
||||
return if (!allPaired.contains(rest)) {
|
||||
warn("Ignoring stale bond to ${rest.anonymize}")
|
||||
false
|
||||
|
@ -170,7 +161,7 @@ class BluetoothInterface(
|
|||
init {
|
||||
// Note: this call does no comms, it just creates the device object (even if the
|
||||
// device is off/not connected)
|
||||
val device = getBluetoothAdapter(context)?.getRemoteDevice(address)
|
||||
val device = context.bluetoothManager?.adapter?.getRemoteDevice(address)
|
||||
if (device != null) {
|
||||
info("Creating radio interface service. device=${address.anonymize}")
|
||||
|
||||
|
|
|
@ -106,7 +106,11 @@ class MeshServiceNotifications(
|
|||
)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -261,7 +261,10 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
|
||||
if (permissions.entries.all { it.value }) {
|
||||
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 =
|
||||
|
@ -271,7 +274,10 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
if (myActivity.hasBackgroundPermission()) {
|
||||
binding.provideLocationCheckbox.isChecked = true
|
||||
} 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
|
||||
|
@ -506,37 +512,34 @@ class SettingsFragment : ScreenFragment("Settings"), Logging {
|
|||
val requestPermissionAndScanLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
|
||||
if (permissions.entries.all { it.value }) {
|
||||
checkLocationEnabled()
|
||||
checkBTEnabled()
|
||||
if (!scanModel.hasCompanionDeviceApi) checkLocationEnabled()
|
||||
scanLeDevice()
|
||||
} else {
|
||||
errormsg("User denied scan permissions")
|
||||
showSnackbar(getString(R.string.permission_missing))
|
||||
showSnackbar(requireContext().permissionMissing)
|
||||
}
|
||||
bluetoothViewModel.permissionsUpdated()
|
||||
}
|
||||
|
||||
binding.changeRadioButton.setOnClickListener {
|
||||
debug("User clicked changeRadioButton")
|
||||
checkBTEnabled()
|
||||
if ((scanModel.hasCompanionDeviceApi)) {
|
||||
scanLeDevice()
|
||||
} else {
|
||||
// Location is the only runtime permission for classic bluetooth scan
|
||||
if (myActivity.hasLocationPermission()) {
|
||||
checkLocationEnabled()
|
||||
scanLeDevice()
|
||||
} else {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(getString(R.string.required_permissions))
|
||||
.setMessage(getString(R.string.permission_missing))
|
||||
.setNeutralButton(R.string.cancel) { _, _ ->
|
||||
warn("User bailed due to permissions")
|
||||
}
|
||||
.setPositiveButton(R.string.accept) { _, _ ->
|
||||
info("requesting scan permissions")
|
||||
requestPermissionAndScanLauncher.launch(myActivity.getLocationPermissions())
|
||||
}
|
||||
.show()
|
||||
}
|
||||
scanLeDevice()
|
||||
if (scanModel.hasBluetoothPermission) {
|
||||
checkBTEnabled()
|
||||
if (!scanModel.hasCompanionDeviceApi) checkLocationEnabled()
|
||||
} else {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(getString(R.string.required_permissions))
|
||||
.setMessage(requireContext().permissionMissing)
|
||||
.setNeutralButton(R.string.cancel) { _, _ ->
|
||||
warn("User bailed due to permissions")
|
||||
}
|
||||
.setPositiveButton(R.string.accept) { _, _ ->
|
||||
info("requesting scan permissions")
|
||||
requestPermissionAndScanLauncher.launch(myActivity.getBluetoothPermissions())
|
||||
}
|
||||
.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue