diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
new file mode 100644
index 0000000..15655ac
--- /dev/null
+++ b/.idea/deploymentTargetDropDown.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/sensortestingapp/MainActivity.kt b/app/src/main/java/com/example/sensortestingapp/MainActivity.kt
index d1c5dc3..cdebebe 100644
--- a/app/src/main/java/com/example/sensortestingapp/MainActivity.kt
+++ b/app/src/main/java/com/example/sensortestingapp/MainActivity.kt
@@ -3,27 +3,45 @@ package com.example.sensortestingapp
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
+import android.app.AlertDialog
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.Context
+import android.content.DialogInterface
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
-import com.google.android.material.snackbar.Snackbar
+import android.view.Menu
+import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
import androidx.core.view.WindowCompat
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
-import android.view.Menu
-import android.view.MenuItem
-import androidx.core.content.ContextCompat
import com.example.sensortestingapp.databinding.ActivityMainBinding
private const val ENABLE_BLUETOOTH_REQUEST_CODE = 1
+private const val RUNTIME_PERMISSION_REQUEST_CODE = 2
+
+fun Context.hasPermission(permissionType: String): Boolean {
+ return ContextCompat.checkSelfPermission(this, permissionType) ==
+ PackageManager.PERMISSION_GRANTED
+}
+
+fun Context.hasRequiredRuntimePermissions(): Boolean {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ hasPermission(Manifest.permission.BLUETOOTH_SCAN) &&
+ hasPermission(Manifest.permission.BLUETOOTH_CONNECT)
+ } else {
+ hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)
+ }
+}
+
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
@@ -48,9 +66,10 @@ class MainActivity : AppCompatActivity() {
setupActionBarWithNavController(navController, appBarConfiguration)
binding.fab.setOnClickListener { view ->
- Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
- .setAnchorView(R.id.fab)
- .setAction("Action", null).show()
+ startBleScan()
+// Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
+// .setAnchorView(R.id.fab)
+// .setAction("Action", null).show()
}
}
@@ -94,6 +113,44 @@ class MainActivity : AppCompatActivity() {
}
}
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ when (requestCode) {
+ RUNTIME_PERMISSION_REQUEST_CODE -> {
+ val containsPermanentDenial = permissions.zip(grantResults.toTypedArray()).any {
+ it.second == PackageManager.PERMISSION_DENIED &&
+ !ActivityCompat.shouldShowRequestPermissionRationale(this, it.first)
+ }
+ val containsDenial = grantResults.any { it == PackageManager.PERMISSION_DENIED }
+ val allGranted = grantResults.all { it == PackageManager.PERMISSION_GRANTED }
+ when {
+ containsPermanentDenial -> {
+ // TODO: Handle permanent denial (e.g., show AlertDialog with justification)
+ // Note: The user will need to navigate to App Settings and manually grant
+ // permissions that were permanently denied
+ }
+
+ containsDenial -> {
+ requestRelevantRuntimePermissions()
+ }
+
+ allGranted && hasRequiredRuntimePermissions() -> {
+ startBleScan()
+ }
+
+ else -> {
+ // Unexpected scenario encountered when handling permissions
+ recreate()
+ }
+ }
+ }
+ }
+ }
+
@SuppressLint("MissingPermission")
private fun promptEnableBluetooth() {
if (!bluetoothAdapter.isEnabled) {
@@ -102,4 +159,93 @@ class MainActivity : AppCompatActivity() {
}
}
+ private fun startBleScan() {
+ if (!hasRequiredRuntimePermissions()) {
+ requestRelevantRuntimePermissions()
+ } else { /* TODO: Actually perform scan */
+ }
+ }
+
+ private fun Activity.requestRelevantRuntimePermissions() {
+ if (hasRequiredRuntimePermissions()) {
+ return
+ }
+ when {
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.S -> {
+ requestLocationPermission()
+ }
+
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
+ requestBluetoothPermissions()
+ }
+ }
+ }
+
+ private fun requestLocationPermission() {
+
+
+ val onClick = { dialog: DialogInterface, which: Int ->
+ ActivityCompat.requestPermissions(
+ this,
+ arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
+ RUNTIME_PERMISSION_REQUEST_CODE
+ )
+ }
+
+
+ runOnUiThread {
+ val builder = AlertDialog.Builder(this)
+
+ with(builder)
+ {
+ setTitle("Location permission required")
+ setMessage(
+ "Starting from Android M (6.0), the system requires apps to be granted " +
+ "location access in order to scan for BLE devices."
+ )
+ setCancelable(false)
+ setPositiveButton(
+ android.R.string.ok,
+ DialogInterface.OnClickListener(function = onClick)
+ )
+ show()
+ }
+ }
+ }
+
+ private fun requestBluetoothPermissions() {
+
+ val onClick = { dialog: DialogInterface, which: Int ->
+ ActivityCompat.requestPermissions(
+ this,
+ arrayOf(
+ Manifest.permission.BLUETOOTH_SCAN,
+ Manifest.permission.BLUETOOTH_CONNECT
+ ),
+ RUNTIME_PERMISSION_REQUEST_CODE
+ )
+ }
+
+
+ runOnUiThread {
+ val builder = AlertDialog.Builder(this)
+
+ with(builder)
+ {
+ setTitle("Bluetooth permission required")
+ setMessage(
+ "Starting from Android 12, the system requires apps to be granted " +
+ "Bluetooth access in order to scan for and connect to BLE devices."
+ )
+ setCancelable(false)
+ setPositiveButton(
+ android.R.string.ok,
+ DialogInterface.OnClickListener(function = onClick)
+ )
+ show()
+ }
+ }
+
+ }
+
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 16313e0..406189e 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -28,6 +28,6 @@
android:layout_gravity="bottom|end"
android:layout_marginEnd="@dimen/fab_margin"
android:layout_marginBottom="16dp"
- app:srcCompat="@android:drawable/ic_dialog_email" />
+ app:srcCompat="@android:drawable/stat_sys_data_bluetooth" />
\ No newline at end of file