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>(emptyList()) var scannedDevices: StateFlow> = _scannedDevices.asStateFlow() private val _pairedDevices = MutableStateFlow>(emptyList()) var pairedDevices: StateFlow> = _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 ) } } }