143 lines
5.2 KiB
Kotlin
143 lines
5.2 KiB
Kotlin
package com.example.tvcontroller.services
|
|
|
|
import android.bluetooth.BluetoothAdapter
|
|
import android.bluetooth.BluetoothManager
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.content.BroadcastReceiver
|
|
import android.content.IntentFilter
|
|
import android.content.pm.PackageManager
|
|
import android.os.Build
|
|
import android.util.Log
|
|
import androidx.core.content.ContextCompat.getSystemService
|
|
import com.example.tvcontroller.data.BluetoothDevice
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
import kotlinx.coroutines.flow.StateFlow
|
|
import kotlinx.coroutines.flow.asStateFlow
|
|
import kotlinx.coroutines.flow.update
|
|
|
|
class BluetoothService(private val context: Context) {
|
|
private var bluetoothManager: BluetoothManager =
|
|
getSystemService(context, BluetoothManager::class.java)!!;
|
|
private var bluetoothAdapter: BluetoothAdapter = bluetoothManager.adapter
|
|
private var bluetoothStateChangedCallbacks: MutableList<(Int) -> Unit> = mutableListOf()
|
|
private val _scannedDevices = MutableStateFlow<List<BluetoothDevice>>(emptyList())
|
|
var scannedDevices: StateFlow<List<BluetoothDevice>> = _scannedDevices.asStateFlow()
|
|
private val _pairedDevices = MutableStateFlow<List<BluetoothDevice>>(emptyList())
|
|
var pairedDevices: StateFlow<List<BluetoothDevice>> = _pairedDevices.asStateFlow()
|
|
|
|
private var bluetoothStateReceiver: BroadcastReceiver? = object : BroadcastReceiver() {
|
|
override fun onReceive(context: Context, intent: Intent) {
|
|
val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)
|
|
bluetoothStateChangedCallbacks.forEach { it(state) }
|
|
}
|
|
}
|
|
private var foundDeviceReceiver: BroadcastReceiver? = object : BroadcastReceiver() {
|
|
override fun onReceive(context: Context, intent: Intent) {
|
|
val device = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
intent.getParcelableExtra(
|
|
android.bluetooth.BluetoothDevice.EXTRA_DEVICE,
|
|
android.bluetooth.BluetoothDevice::class.java
|
|
)
|
|
} else {
|
|
intent.getParcelableExtra(android.bluetooth.BluetoothDevice.EXTRA_DEVICE)
|
|
}
|
|
if (device != null) {
|
|
val newDevice = BluetoothDevice.fromBluetoothDevice(device)
|
|
Log.i("BluetoothService", "Found device: $newDevice")
|
|
_scannedDevices.update { devices -> if (newDevice in devices) devices else devices + newDevice }
|
|
}
|
|
}
|
|
}
|
|
|
|
init {
|
|
registerBluetoothStateReceiver()
|
|
updatePairedDevices()
|
|
}
|
|
|
|
fun isBluetoothEnabled(): Boolean {
|
|
return bluetoothAdapter.isEnabled ?: false
|
|
}
|
|
|
|
private fun registerBluetoothStateReceiver() {
|
|
context.registerReceiver(
|
|
bluetoothStateReceiver, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
|
|
)
|
|
}
|
|
|
|
fun onBluetoothStateChanged(callback: (Int) -> Unit) {
|
|
bluetoothStateChangedCallbacks.add(callback)
|
|
}
|
|
|
|
fun offBluetoothStateChanged(callback: (Int) -> Unit) {
|
|
bluetoothStateChangedCallbacks.remove(callback)
|
|
}
|
|
|
|
fun cleanUp() {
|
|
context.unregisterReceiver(bluetoothStateReceiver)
|
|
context.unregisterReceiver(foundDeviceReceiver)
|
|
}
|
|
|
|
fun updatePairedDevices() {
|
|
try {
|
|
_pairedDevices.update {
|
|
bluetoothAdapter.bondedDevices.toList()
|
|
.map { device -> BluetoothDevice.fromBluetoothDevice(device) }
|
|
}
|
|
} catch (e: SecurityException) {
|
|
println("Error updating paired devices: $e")
|
|
}
|
|
}
|
|
|
|
fun startDiscovery() {
|
|
try {
|
|
if (bluetoothAdapter.isDiscovering) return
|
|
|
|
Log.i("BluetoothService", "Starting discovery")
|
|
context.registerReceiver(
|
|
foundDeviceReceiver,
|
|
IntentFilter(android.bluetooth.BluetoothDevice.ACTION_FOUND)
|
|
)
|
|
updatePairedDevices()
|
|
bluetoothAdapter.startDiscovery()
|
|
} catch (e: SecurityException) {
|
|
println("Error starting discovery: $e")
|
|
Log.e("BluetoothService", "Error starting discovery: $e")
|
|
}
|
|
}
|
|
|
|
fun stopDiscovery() {
|
|
context.unregisterReceiver(foundDeviceReceiver)
|
|
try {
|
|
bluetoothAdapter.cancelDiscovery()
|
|
} catch (e: SecurityException) {
|
|
println("Error stopping discovery: $e")
|
|
}
|
|
}
|
|
|
|
fun hasRequiredPermissions(): Boolean {
|
|
return BLUETOOTH_PERMISSIONS.all {
|
|
context.checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED
|
|
}
|
|
}
|
|
|
|
fun getBluetoothState(): Int {
|
|
return bluetoothAdapter.state
|
|
}
|
|
|
|
companion object {
|
|
val BLUETOOTH_PERMISSIONS = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
arrayOf(
|
|
android.Manifest.permission.BLUETOOTH,
|
|
android.Manifest.permission.BLUETOOTH_CONNECT,
|
|
android.Manifest.permission.BLUETOOTH_SCAN,
|
|
android.Manifest.permission.BLUETOOTH_ADMIN
|
|
)
|
|
} else {
|
|
arrayOf(
|
|
android.Manifest.permission.BLUETOOTH,
|
|
android.Manifest.permission.BLUETOOTH_ADMIN
|
|
)
|
|
}
|
|
}
|
|
} |