diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 0e8590d..fb912c6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -18,6 +18,9 @@
android:supportsRtl="true"
android:theme="@style/Theme.WearSync"
tools:targetApi="31">
+
diff --git a/app/src/main/java/org/hydev/wearsync/ActivityPermissions.kt b/app/src/main/java/org/hydev/wearsync/ActivityPermissions.kt
new file mode 100644
index 0000000..81bb8f4
--- /dev/null
+++ b/app/src/main/java/org/hydev/wearsync/ActivityPermissions.kt
@@ -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, 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
+ {
+ 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 {
+ return requiredPermissions().filter { checkSelfPermission(it) != PackageManager.PERMISSION_GRANTED }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/hydev/wearsync/ActivityScan.kt b/app/src/main/java/org/hydev/wearsync/ActivityScan.kt
index a9640c3..762501c 100644
--- a/app/src/main/java/org/hydev/wearsync/ActivityScan.kt
+++ b/app/src/main/java/org/hydev/wearsync/ActivityScan.kt
@@ -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): Array {
- val missingPermissions: MutableList = ArrayList()
- for (requiredPermission in requiredPermissions) {
- if (checkSelfPermission(requiredPermission) != PackageManager.PERMISSION_GRANTED) {
- missingPermissions.add(requiredPermission)
- }
- }
- return missingPermissions.toTypedArray()
- }
-
- private val requiredPermissions: Array
- 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,
- 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
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/org/hydev/wearsync/Extensions.kt b/app/src/main/java/org/hydev/wearsync/Extensions.kt
index d9776af..6a9947b 100644
--- a/app/src/main/java/org/hydev/wearsync/Extensions.kt
+++ b/app/src/main/java/org/hydev/wearsync/Extensions.kt
@@ -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()
\ No newline at end of file
+ .setAction("Action", null).show()
+
+fun Context.blueMan() = getSystemService(AppCompatActivity.BLUETOOTH_SERVICE) as BluetoothManager
diff --git a/app/src/main/java/org/hydev/wearsync/MainActivity.kt b/app/src/main/java/org/hydev/wearsync/MainActivity.kt
index 62610b6..c904a0e 100644
--- a/app/src/main/java/org/hydev/wearsync/MainActivity.kt
+++ b/app/src/main/java/org/hydev/wearsync/MainActivity.kt
@@ -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
}
diff --git a/app/src/main/res/layout/activity_permissions.xml b/app/src/main/res/layout/activity_permissions.xml
new file mode 100644
index 0000000..69346e5
--- /dev/null
+++ b/app/src/main/res/layout/activity_permissions.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
\ No newline at end of file