feat: show progress indicator for device ops

This commit is contained in:
Fabian Christoffel
2023-06-26 18:17:29 +02:00
parent ec535b0ad2
commit e8a43711f4
5 changed files with 63 additions and 17 deletions

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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 {

View File

@@ -45,6 +45,18 @@
app:layout_constraintTop_toTopOf="parent"
tools:text="Device Name" />
<ProgressBar
android:id="@+id/device_progress"
android:layout_width="30dp"
android:layout_height="30dp"
app:layout_constraintEnd_toStartOf="@id/device_actions"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:visibility="invisible"
android:indeterminateTint="?attr/colorPrimary"
android:paddingEnd="10dp" />
<com.google.android.material.button.MaterialButton
android:id="@+id/device_actions"
style="@style/Widget.MaterialComponents.Button.Icon"