feat: show progress indicator for device ops
This commit is contained in:
@@ -108,6 +108,10 @@ open class BleListener(private val deviceAddress: String?) {
|
||||
|
||||
}
|
||||
|
||||
open fun onQueueSizeChange(groupedOps: Map<String, List<BleOperationType>>) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -263,6 +267,14 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
listeners.filter { n -> n.isRelevantMessage(address) }.forEach(notifier)
|
||||
}
|
||||
|
||||
private fun notifyListenersOfQueueChange(address: String) {
|
||||
notifyListeners(address) { listener ->
|
||||
listener.onQueueSizeChange(
|
||||
operationQueue.groupBy { o -> o.device.address }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Synchronized
|
||||
private fun enqueueOperation(operation: BleOperationType) {
|
||||
@@ -270,15 +282,17 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
stopScan()
|
||||
}
|
||||
operationQueue.add(operation)
|
||||
notifyListenersOfQueueChange(operation.device.address)
|
||||
if (pendingOperation == null) {
|
||||
doNextOperation()
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun signalEndOfOperation() {
|
||||
Log.d("ConnectionManager", "End of $pendingOperation")
|
||||
private fun signalEndOfOperation(op: BleOperationType) {
|
||||
Log.d("ConnectionManager", "End of $op")
|
||||
pendingOperation = null
|
||||
notifyListenersOfQueueChange(op.device.address)
|
||||
if (operationQueue.isNotEmpty()) {
|
||||
doNextOperation()
|
||||
}
|
||||
@@ -318,7 +332,7 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
"ConnectionManager",
|
||||
"Not connected to ${operation.device.address}! Aborting $operation operation."
|
||||
)
|
||||
signalEndOfOperation()
|
||||
signalEndOfOperation(operation)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -331,7 +345,7 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
notifyListeners(gatt.device.address) {
|
||||
it.onDisconnect(gatt)
|
||||
}
|
||||
signalEndOfOperation()
|
||||
signalEndOfOperation(operation)
|
||||
}
|
||||
|
||||
is MtuRequest -> with(operation) {
|
||||
@@ -348,7 +362,7 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
gatt.readCharacteristic(characteristic)
|
||||
} else {
|
||||
Log.e("ConnectionManager", "Char $charId (${serviceId}) is not readable!")
|
||||
signalEndOfOperation()
|
||||
signalEndOfOperation(operation)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -357,7 +371,7 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
val characteristic = gatt.getService(serviceId)?.getCharacteristic(charId);
|
||||
if (characteristic == null) {
|
||||
Log.e("ConnectionManager", "Char $charId (${serviceId}) not found!")
|
||||
signalEndOfOperation()
|
||||
signalEndOfOperation(operation)
|
||||
return
|
||||
}
|
||||
val descriptor = characteristic.getDescriptor(CCC_DESCRIPTOR_UUID)
|
||||
@@ -367,7 +381,7 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
"ConnectionManager", "Char ${characteristic.uuid} (service: $serviceId)" +
|
||||
" doesn't support notifications/indications"
|
||||
)
|
||||
signalEndOfOperation()
|
||||
signalEndOfOperation(operation)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -379,7 +393,7 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
"ConnectionManager", "setCharacteristicNotification to true " +
|
||||
"failed for ${characteristic.uuid} (service: $serviceId)"
|
||||
)
|
||||
signalEndOfOperation()
|
||||
signalEndOfOperation(operation)
|
||||
return
|
||||
}
|
||||
payload =
|
||||
@@ -393,7 +407,7 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
"ConnectionManager", "setCharacteristicNotification to false " +
|
||||
"failed for ${characteristic.uuid} (service: $serviceId)"
|
||||
)
|
||||
signalEndOfOperation()
|
||||
signalEndOfOperation(operation)
|
||||
return
|
||||
}
|
||||
payload = BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE
|
||||
@@ -428,8 +442,9 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
notifyListeners(gatt.device.address) {
|
||||
it.onConnect(gatt)
|
||||
}
|
||||
if (pendingOperation is Connect) {
|
||||
signalEndOfOperation()
|
||||
val operation = pendingOperation
|
||||
if (operation is Connect) {
|
||||
signalEndOfOperation(operation)
|
||||
}
|
||||
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
|
||||
Log.e(
|
||||
@@ -468,8 +483,9 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
}
|
||||
}
|
||||
|
||||
if (pendingOperation is DiscoverServicesRequest) {
|
||||
signalEndOfOperation()
|
||||
val operation = pendingOperation
|
||||
if (operation is DiscoverServicesRequest) {
|
||||
signalEndOfOperation(operation)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,8 +495,9 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
"ATT MTU changed to $mtu, success: ${status == BluetoothGatt.GATT_SUCCESS}"
|
||||
)
|
||||
|
||||
if (pendingOperation is MtuRequest) {
|
||||
signalEndOfOperation()
|
||||
val operation = pendingOperation
|
||||
if (operation is MtuRequest) {
|
||||
signalEndOfOperation(operation)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,7 +539,7 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
|
||||
val op = pendingOperation
|
||||
if (op is ReadChar && op.charId == characteristic.uuid && op.serviceId == characteristic.service.uuid) {
|
||||
signalEndOfOperation()
|
||||
signalEndOfOperation(op)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -546,7 +563,7 @@ class ConnectionManager(val context: Context, bleAdapter: BluetoothAdapter) {
|
||||
it.onUnsubscribe(gatt, descriptor)
|
||||
}
|
||||
}
|
||||
signalEndOfOperation()
|
||||
signalEndOfOperation(op)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,14 @@ import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.INVISIBLE
|
||||
import android.view.View.VISIBLE
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Button
|
||||
import android.widget.ListView
|
||||
import android.widget.PopupMenu
|
||||
import android.widget.ProgressBar
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
|
||||
@@ -33,6 +36,8 @@ interface DeviceListEntry {
|
||||
|
||||
val status: String?
|
||||
|
||||
var hasRunningOp: Boolean
|
||||
|
||||
fun getActions(): List<Action>
|
||||
|
||||
fun getMeasurements(): List<Measurement>
|
||||
@@ -59,6 +64,7 @@ class DeviceListAdapter(
|
||||
val statusView: TextView
|
||||
val measurementsListView: ListView
|
||||
val deviceActions: Button
|
||||
val deviceProgress: ProgressBar
|
||||
|
||||
|
||||
init {
|
||||
@@ -68,11 +74,13 @@ class DeviceListAdapter(
|
||||
statusView = view.findViewById(R.id.device_status)
|
||||
measurementsListView = view.findViewById(R.id.measurement_fields)
|
||||
deviceActions = view.findViewById(R.id.device_actions)
|
||||
deviceProgress = view.findViewById(R.id.device_progress)
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
fun bind(result: DeviceListEntry) {
|
||||
deviceNameView.text = result.name ?: "<N/A>"
|
||||
deviceProgress.visibility = if (result.hasRunningOp) VISIBLE else INVISIBLE
|
||||
macAddressView.text = result.address
|
||||
signalStrengthView.text = "${result.rssi ?: "-"} dBm"
|
||||
var signalStrengthIcon = R.drawable.signal_strength_weak
|
||||
|
||||
@@ -100,9 +100,11 @@ class KirbyDevice(
|
||||
private val connectionManager: ConnectionManager,
|
||||
private val bleDevice: BluetoothDevice,
|
||||
initialRssi: Int,
|
||||
override var hasRunningOp: Boolean = false,
|
||||
private val onStateChange: (device: KirbyDevice) -> Unit
|
||||
) : BleListener(bleDevice.address), DeviceListEntry {
|
||||
|
||||
|
||||
override fun onScanResult(callbackType: Int, result: ScanResult) {
|
||||
statuses.add(DeviceStatus.DISCOVERED)
|
||||
onStateChange(this)
|
||||
@@ -146,6 +148,11 @@ class KirbyDevice(
|
||||
onStateChange(this)
|
||||
}
|
||||
|
||||
override fun onQueueSizeChange(groupedOps: Map<String, List<BleOperationType>>) {
|
||||
hasRunningOp = groupedOps.getOrDefault(bleDevice.address, emptyList()).isNotEmpty()
|
||||
onStateChange(this)
|
||||
}
|
||||
|
||||
override var rssi = initialRssi
|
||||
set(value) {
|
||||
field = value
|
||||
|
||||
@@ -338,6 +338,8 @@ class DummyListEntry(override val address: String) : DeviceListEntry {
|
||||
override val status: String
|
||||
get() = "statusA, statusB"
|
||||
|
||||
override var hasRunningOp: Boolean = true
|
||||
|
||||
override fun getActions(): List<Action> {
|
||||
return listOf(object : Action {
|
||||
override fun getLabel(): String {
|
||||
|
||||
Reference in New Issue
Block a user