[O] Split permissions activity

This commit is contained in:
Azalea Gui
2023-01-23 16:25:38 -05:00
parent cdba873abb
commit 92e57c5283
6 changed files with 124 additions and 181 deletions
+3
View File
@@ -18,6 +18,9 @@
android:supportsRtl="true"
android:theme="@style/Theme.WearSync"
tools:targetApi="31">
<activity
android:name=".ActivityPermissions"
android:exported="false" />
<activity
android:name=".ActivityScan"
android:exported="false" />
@@ -0,0 +1,67 @@
package org.hydev.wearsync
import android.Manifest
import android.app.AlertDialog
import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.os.Build.VERSION.SDK_INT
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
class ActivityPermissions : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_permissions)
checkPermissions()
}
private fun checkPermissions() {
val missing = getMissingPermissions()
if (missing.isNotEmpty()) {
requestPermissions(missing.toTypedArray(), ACCESS_LOCATION_REQUEST)
}
else finish()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
println(grantResults.map { it })
// Check if all permission were granted
if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) finish()
else {
AlertDialog.Builder(this)
.setTitle("Location permission is required for scanning Bluetooth peripherals")
.setMessage("Please grant permissions")
.setPositiveButton("Retry") { dialogInterface, _ ->
dialogInterface.cancel()
checkPermissions()
}
.create()
.show()
}
}
companion object {
private const val ACCESS_LOCATION_REQUEST = 2
fun Context.hasPermissions() = getMissingPermissions().isEmpty()
fun Context.requiredPermissions(): Array<String>
{
val sdk = applicationInfo.targetSdkVersion
return if (SDK_INT >= Build.VERSION_CODES.S && sdk >= Build.VERSION_CODES.S) {
arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT)
} else if (SDK_INT >= Build.VERSION_CODES.Q && sdk >= Build.VERSION_CODES.Q) {
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
} else arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION)
}
fun Context.getMissingPermissions(): List<String> {
return requiredPermissions().filter { checkSelfPermission(it) != PackageManager.PERMISSION_GRANTED }
}
}
}
@@ -1,23 +1,10 @@
package org.hydev.wearsync
import android.Manifest
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.provider.Settings
import android.widget.ArrayAdapter
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.welie.blessed.BluetoothPeripheral
import kotlinx.coroutines.*
@@ -25,7 +12,6 @@ import kotlinx.coroutines.flow.consumeAsFlow
import org.hydev.wearsync.bles.BluetoothHandler
import org.hydev.wearsync.bles.ObservationUnit
import org.hydev.wearsync.databinding.ActivityScanBinding
import timber.log.Timber
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
@@ -35,50 +21,18 @@ class ActivityScan : AppCompatActivity() {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val dateFormat: DateFormat = SimpleDateFormat("dd-MM-yyyy HH:mm:ss", Locale.ENGLISH)
private val enableBluetoothRequest =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
// Bluetooth has been enabled
checkPermissions()
} else {
// Bluetooth has not been enabled, try again
askToEnableBluetooth()
}
}
private val bluetoothManager by lazy { getSystemService(BLUETOOTH_SERVICE) as BluetoothManager }
private val blueMan by lazy { blueMan() }
private lateinit var bluetoothHandler: BluetoothHandler
private fun askToEnableBluetooth() {
val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)
enableBluetoothRequest.launch(enableBtIntent)
}
@SuppressLint("MissingPermission")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityScanBinding.inflate(layoutInflater)
setContentView(binding.root)
registerReceiver(
locationServiceStateReceiver,
IntentFilter(LocationManager.MODE_CHANGED_ACTION)
)
}
override fun onResume() {
super.onResume()
if (bluetoothManager.adapter != null) {
if (!isBluetoothEnabled) askToEnableBluetooth() else checkPermissions()
} else {
Timber.e("This device has no Bluetooth hardware")
}
initBluetoothHandler()
}
private val isBluetoothEnabled: Boolean
get() = bluetoothManager.adapter?.isEnabled ?: false
private val central get() = bluetoothHandler.central
@SuppressLint("MissingPermission")
@@ -89,7 +43,7 @@ class ActivityScan : AppCompatActivity() {
println("OnCreate called, Initializing...")
// List bonded device addresses
val pairedDevices = bluetoothManager.adapter.bondedDevices.toList()
val pairedDevices = blueMan.adapter.bondedDevices.toList()
val pairedAddresses = pairedDevices.map { it.address }.toSet()
// Scan devices
@@ -213,134 +167,4 @@ class ActivityScan : AppCompatActivity() {
}
}
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(locationServiceStateReceiver)
}
private val locationServiceStateReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if (action != null && action == LocationManager.MODE_CHANGED_ACTION) {
val isEnabled = areLocationServicesEnabled()
Timber.i("Location service state changed to: %s", if (isEnabled) "on" else "off")
checkPermissions()
}
}
}
private fun getPeripheral(peripheralAddress: String): BluetoothPeripheral {
return bluetoothHandler.central.getPeripheral(peripheralAddress)
}
private fun checkPermissions() {
val missingPermissions = getMissingPermissions(requiredPermissions)
if (missingPermissions.isNotEmpty()) {
requestPermissions(missingPermissions, ACCESS_LOCATION_REQUEST)
} else {
checkIfLocationIsNeeded()
}
}
private fun getMissingPermissions(requiredPermissions: Array<String>): Array<String> {
val missingPermissions: MutableList<String> = ArrayList()
for (requiredPermission in requiredPermissions) {
if (checkSelfPermission(requiredPermission) != PackageManager.PERMISSION_GRANTED) {
missingPermissions.add(requiredPermission)
}
}
return missingPermissions.toTypedArray()
}
private val requiredPermissions: Array<String>
get() {
val targetSdkVersion = applicationInfo.targetSdkVersion
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && targetSdkVersion >= Build.VERSION_CODES.S) {
arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && targetSdkVersion >= Build.VERSION_CODES.Q) {
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
} else arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION)
}
private fun checkIfLocationIsNeeded() {
val targetSdkVersion = applicationInfo.targetSdkVersion
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S && targetSdkVersion < Build.VERSION_CODES.S) {
// Check if Location services are on because they are required to make scanning work for SDK < 31
if (checkLocationServices()) {
initBluetoothHandler()
}
} else {
initBluetoothHandler()
}
}
private fun areLocationServicesEnabled(): Boolean {
val locationManager = getSystemService(LOCATION_SERVICE) as LocationManager
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
locationManager.isLocationEnabled
} else {
val isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
val isNetworkEnabled =
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
isGpsEnabled || isNetworkEnabled
}
}
private fun checkLocationServices(): Boolean {
return if (!areLocationServicesEnabled()) {
AlertDialog.Builder(this)
.setTitle("Location services are not enabled")
.setMessage("Scanning for Bluetooth peripherals requires locations services to be enabled.") // Want to enable?
.setPositiveButton("Enable") { dialogInterface, _ ->
dialogInterface.cancel()
startActivity(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS))
}
.setNegativeButton("Cancel") { dialog, _ ->
// if this button is clicked, just close
// the dialog box and do nothing
dialog.cancel()
}
.create()
.show()
false
} else {
true
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
// Check if all permission were granted
var allGranted = true
for (result in grantResults) {
if (result != PackageManager.PERMISSION_GRANTED) {
allGranted = false
break
}
}
if (allGranted) {
checkIfLocationIsNeeded()
} else {
AlertDialog.Builder(this)
.setTitle("Location permission is required for scanning Bluetooth peripherals")
.setMessage("Please grant permissions")
.setPositiveButton("Retry") { dialogInterface, _ ->
dialogInterface.cancel()
checkPermissions()
}
.create()
.show()
}
}
companion object {
private const val REQUEST_ENABLE_BT = 1
private const val ACCESS_LOCATION_REQUEST = 2
}
}
@@ -1,7 +1,12 @@
package org.hydev.wearsync
import android.bluetooth.BluetoothManager
import android.content.Context
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar
fun View.snack(msg: String) = Snackbar.make(this, msg, Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
.setAction("Action", null).show()
fun Context.blueMan() = getSystemService(AppCompatActivity.BLUETOOTH_SERVICE) as BluetoothManager
@@ -1,13 +1,16 @@
package org.hydev.wearsync
import android.annotation.SuppressLint
import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar
import org.hydev.wearsync.ActivityPermissions.Companion.hasPermissions
import org.hydev.wearsync.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity()
@@ -17,6 +20,21 @@ class MainActivity : AppCompatActivity()
val pref get() = getSharedPreferences("settings", Context.MODE_PRIVATE)
val mac get() = pref.getString("device", "None")
val enableBluetoothRequest =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == RESULT_OK) {
// Bluetooth has been enabled
} else {
// Bluetooth has not been enabled, try again
ensureBluetooth()
}
}
fun ensureBluetooth() {
if (blueMan().adapter?.isEnabled == false)
enableBluetoothRequest.launch(Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE))
}
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?)
{
@@ -35,13 +53,20 @@ class MainActivity : AppCompatActivity()
println("owo")
}
if (!hasPermissions()) startActivity(Intent(this, ActivityPermissions::class.java))
}
override fun onResume()
{
super.onResume()
ensureBluetooth()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean
{
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ActivityPermissions">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Required permissions are not available.\nPlease allow permissions"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>