129 lines
4.5 KiB
Kotlin
129 lines
4.5 KiB
Kotlin
package com.example.tvcontroller.services
|
|
|
|
import android.Manifest
|
|
import android.bluetooth.BluetoothAdapter
|
|
import android.bluetooth.BluetoothManager
|
|
import android.bluetooth.BluetoothSocket
|
|
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
|
|
import kotlinx.io.IOException
|
|
import java.util.UUID
|
|
|
|
private const val SERIAL_PORT_SERVICE_UUID = "00001101-0000-1000-8000-00805F9B34FB"
|
|
private const val TAG = "BluetoothService"
|
|
|
|
class BluetoothService(private val context: Context) {
|
|
private var bluetoothManager: BluetoothManager =
|
|
getSystemService(context, BluetoothManager::class.java)!!
|
|
private var bluetoothAdapter: BluetoothAdapter = bluetoothManager.adapter
|
|
|
|
private val _pairedDevices = MutableStateFlow<List<BluetoothDevice>>(emptyList())
|
|
var pairedDevices: StateFlow<List<BluetoothDevice>> = _pairedDevices.asStateFlow()
|
|
private var clientSocket: BluetoothSocket? = null
|
|
|
|
private var bluetoothStateChangedCallbacks: MutableList<(Int) -> Unit> = mutableListOf()
|
|
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) }
|
|
}
|
|
}
|
|
|
|
init {
|
|
context.registerReceiver(
|
|
bluetoothStateReceiver, IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
|
|
)
|
|
updatePairedDevices()
|
|
}
|
|
|
|
fun isBluetoothEnabled(): Boolean {
|
|
return bluetoothAdapter.isEnabled
|
|
}
|
|
|
|
fun onBluetoothStateChanged(callback: (Int) -> Unit) {
|
|
bluetoothStateChangedCallbacks.add(callback)
|
|
}
|
|
|
|
fun offBluetoothStateChanged(callback: (Int) -> Unit) {
|
|
bluetoothStateChangedCallbacks.remove(callback)
|
|
}
|
|
|
|
fun cleanUp() {
|
|
context.unregisterReceiver(bluetoothStateReceiver)
|
|
bluetoothStateChangedCallbacks.clear()
|
|
closeBluetoothConnection()
|
|
}
|
|
|
|
fun updatePairedDevices() {
|
|
try {
|
|
_pairedDevices.update {
|
|
bluetoothAdapter.bondedDevices.toList()
|
|
.map { device -> BluetoothDevice.fromBluetoothDevice(device) }
|
|
}
|
|
} catch (e: SecurityException) {
|
|
println("Error updating paired devices: $e")
|
|
}
|
|
}
|
|
|
|
fun connectToDevice(device: BluetoothDevice) {
|
|
Log.i(TAG, "Initiating connection process")
|
|
if (context.checkSelfPermission(Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED) {
|
|
Log.e(TAG, "Bluetooth permission not granted")
|
|
return
|
|
}
|
|
Log.i(TAG, "Connecting to device: $device")
|
|
try {
|
|
var androidBluetoothDevice = bluetoothAdapter.getRemoteDevice(device.getAddress())
|
|
Log.i(TAG, "Creating socket to device: $device")
|
|
clientSocket = androidBluetoothDevice.createRfcommSocketToServiceRecord(
|
|
UUID.fromString(SERIAL_PORT_SERVICE_UUID)
|
|
)
|
|
Log.i(TAG, "Connecting to socket")
|
|
clientSocket?.connect()
|
|
Log.i(TAG, "Connected to device: $device")
|
|
} catch (e: IOException) {
|
|
Log.e(TAG, "Error connecting to device: $e")
|
|
}
|
|
}
|
|
|
|
fun hasRequiredPermissions(): Boolean {
|
|
return BLUETOOTH_PERMISSIONS.all {
|
|
context.checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED
|
|
}
|
|
}
|
|
|
|
fun getBluetoothState(): Int {
|
|
return bluetoothAdapter.state
|
|
}
|
|
|
|
fun closeBluetoothConnection() {
|
|
clientSocket?.close()
|
|
clientSocket = null
|
|
}
|
|
|
|
companion object {
|
|
val BLUETOOTH_PERMISSIONS = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
|
arrayOf(
|
|
Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN
|
|
)
|
|
} else {
|
|
arrayOf(
|
|
Manifest.permission.BLUETOOTH,
|
|
Manifest.permission.BLUETOOTH_CONNECT,
|
|
Manifest.permission.BLUETOOTH_SCAN,
|
|
Manifest.permission.BLUETOOTH_ADMIN
|
|
)
|
|
}
|
|
}
|
|
} |