I am trying to write a program to communicate with ESP32 modules via bluetooth. For the program to work, Bt must be turned on and the FINE_LOCATION permission granted. I am using API 29.
The code below works, but it can be done much better.
I am a beginner, this is the only way I can do it.
I have a few questions :
Can I use shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
together with ActivityResultContracts.RequestPermission()
, if yes how?
To achieve my goal if the user refuses the first time to grant permissions, I run an almost identical contract with a different dialog.How can this code be reduced?
How to simplify this constant checking:
if (conditions.isReady()) {
buildInterfaceOk()
} else buildInterfaceError()
Half my code seems redundant, I don't know how to get rid of it.
All these problems actually concern the first run, then everything is fine.
Code:
const val TAG = "DEBUG"
data class Conditions (var isBtEnabled : Boolean , var permissionsOk :Boolean){
fun isReady():Boolean{
if (isBtEnabled && permissionsOk) return true
else return false
}
fun log(){
Log.d("DEBUG","Conditions-> $isBtEnabled , $permissionsOk")
}}
class MainActivity : AppCompatActivity() {
private lateinit var bind: ActivityMainBinding
private lateinit var broadcastReceiver: BroadcastReceiver
private lateinit var bluetoothAdapter: BluetoothAdapter
private var conditions = Conditions(false, false)
private var requestBluetoothEnable =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
Log.d(TAG, "IT RESULT CODE: ${it.resultCode.toString()}")
//kiedy bt jest wlaczone , result -1 , kiedy wylaczone i wlaczamy i akceptujemy tez -1
//a jak odrzucamy to 0
if (it.resultCode == -1) {
conditions.log()
conditions.isBtEnabled = true
}
if (conditions.isReady()) {
buildInterfaceOk()
} else buildInterfaceError()
}
//use it when user denied first time
private val requestPermissionLocationSecond =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (granted) {
Log.d(TAG, "Permission granted by contract 2")
conditions.permissionsOk = checkPermissions()
if (conditions.isReady()) {
buildInterfaceOk()
} else buildInterfaceError()
} else {
val builder = AlertDialog.Builder(this@MainActivity)
builder.setTitle("V2 - Hi!")
builder.setMessage(
" Please go to the app settings and manually turn on " +
"\"location permission\". Without this permission, I do not work. "
)
builder.setPositiveButton("Ok") { dialog, which -> }
val dialog: AlertDialog = builder.create()
dialog.show()
Log.d(TAG, " V2-> Permission denied, - contract 2")
}
}
// first try to get permission
private var requestPermissionLocation =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (granted) {
Log.d(TAG, "Permission granted by contract 1")
conditions.permissionsOk = checkPermissions()
if (conditions.isReady()) {
buildInterfaceOk()
} else buildInterfaceError()
//shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_FINE_LOCATION)
} else {
Log.d(TAG, "Permission denied by contract 1")
val builder = AlertDialog.Builder(this@MainActivity)
builder.setTitle("V2 - Uprawnienie do lokalizacji")
builder.setMessage("I need these permissions to work with Bt devices ")
builder.setPositiveButton("YES") { dialog, which ->
requestPermissionLocationSecond.launch(android.Manifest.permission.ACCESS_FINE_LOCATION)
}
builder.setNegativeButton("No") { dialog, which -> }
val dialog: AlertDialog = builder.create()
dialog.show()
conditions.permissionsOk = checkPermissions()
if (conditions.isReady()) {
buildInterfaceOk()
} else buildInterfaceError()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
bind = ActivityMainBinding.inflate(layoutInflater)
super.onCreate(savedInstanceState)
setContentView(bind.root)
Log.d(TAG, "BUild version : ${Build.VERSION.SDK_INT} -> ${Build.VERSION.CODENAME}")
val currentDebug = getString(R.string.app_name)
Log.d(TAG, "CURRENT DEBUG : $currentDebug")
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
requestBluetoothEnable.launch(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE))
requestPermissionLocation.launch(Manifest.permission.ACCESS_FINE_LOCATION)
conditions.isBtEnabled = bluetoothAdapter.isEnabled
conditions.permissionsOk = checkPermissions()
Log.d(TAG, "FIRST conditions check :")
if (conditions.isReady()) {
conditions.log()
buildInterfaceOk()
}
}
private fun buildInterfaceOk() {
Log.d(TAG, "BUILDING INTERFACE : all is fine")
bind.tvInfo.text = "All is fine i can build interface"
}
private fun buildInterfaceError() {
Log.d(TAG, "BUILDING INTERFACE : errors")
bind.tvInfo.text = "Some errors..."
}
private fun checkPermissions(): Boolean {
val permissionsRequired =
arrayOf(
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN,
//Manifest.permission.BLUETOOTH_CONNECT, //to znow wymagane od S(API 31) ??
//Manifest.permission.BLUETOOTH_SCAN, //to znow wymagane od S(API 31) ??
Manifest.permission.ACCESS_FINE_LOCATION
//Manifest.permission.ACCESS_BACKGROUND_LOCATION
)
var permissionsOk = true
permissionsRequired.forEach { requiredPermission ->
if (ContextCompat.checkSelfPermission(
this.applicationContext,
requiredPermission
) == PackageManager.PERMISSION_GRANTED
) {
Log.d(TAG, "PERMISSION : $requiredPermission -> GRANTED")
} else {
Log.d(TAG, "PERMISSION : $requiredPermission -> NOT GRANTED")
permissionsOk = false
}
}
return permissionsOk
}
}