mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
ble: standardize server actions (#5157)
This commit is contained in:
committed by
José Rebelo
parent
5526e9528e
commit
f03ac358fa
+6
-2
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019-2024 Andreas Böhler
|
||||
/* Copyright (C) 2019-2025 Andreas Böhler, Thomas Kuehne
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
@@ -19,6 +19,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.btle;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothGattServer;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
|
||||
/**
|
||||
@@ -64,7 +66,9 @@ public abstract class BtLEServerAction {
|
||||
return DateTimeUtils.formatLocalTime(creationTimestamp);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return getCreationTime() + ":" + getClass().getSimpleName() + " on device: " + getDevice().getAddress();
|
||||
return getCreationTime() + " " + getClass().getSimpleName() + " on " + getDevice().getAddress();
|
||||
}
|
||||
}
|
||||
|
||||
+21
-5
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019-2024 Andreas Böhler, Damien Gaignon
|
||||
/* Copyright (C) 2019-2025 Andreas Böhler, Damien Gaignon, Thomas Kuehne
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
@@ -17,11 +17,15 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.btle;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.NotifyCharacteristicChangedAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.ServerResponseAction;
|
||||
|
||||
public class ServerTransactionBuilder {
|
||||
@@ -34,6 +38,7 @@ public class ServerTransactionBuilder {
|
||||
mTransaction = new ServerTransaction(taskName);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ServerTransactionBuilder writeServerResponse(BluetoothDevice device, int requestId, int status, int offset, byte[] data) {
|
||||
if(device == null) {
|
||||
LOG.warn("Unable to write to device: null");
|
||||
@@ -43,7 +48,20 @@ public class ServerTransactionBuilder {
|
||||
return add(action);
|
||||
}
|
||||
|
||||
public ServerTransactionBuilder add(BtLEServerAction action) {
|
||||
@NonNull
|
||||
public ServerTransactionBuilder notifyCharacteristicChanged(@NonNull BluetoothDevice device,
|
||||
@NonNull BluetoothGattCharacteristic characteristic,
|
||||
@NonNull byte[] value) {
|
||||
if (device == null) {
|
||||
LOG.warn("Unable to write to device: null");
|
||||
return this;
|
||||
}
|
||||
BtLEServerAction action = new NotifyCharacteristicChangedAction(device, characteristic, value);
|
||||
return add(action);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public ServerTransactionBuilder add(@NonNull BtLEServerAction action) {
|
||||
mTransaction.add(action);
|
||||
return this;
|
||||
}
|
||||
@@ -66,10 +84,8 @@ public class ServerTransactionBuilder {
|
||||
|
||||
/**
|
||||
* To be used as the final step to execute the transaction by the given queue.
|
||||
*
|
||||
* @param queue
|
||||
*/
|
||||
public void queue(BtLEQueue queue) {
|
||||
public void queue(@NonNull BtLEQueue queue) {
|
||||
if (mQueued) {
|
||||
throw new IllegalStateException("This builder had already been queued. You must not reuse it.");
|
||||
}
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/* Copyright (C) 2023-2025 Frank Ertl, Thomas Kuehne
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.btle.actions;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.bluetooth.BluetoothGattServer;
|
||||
import android.bluetooth.BluetoothStatusCodes;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BleNamesResolver;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEServerAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
public class NotifyCharacteristicChangedAction extends BtLEServerAction {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(NotifyCharacteristicChangedAction.class);
|
||||
|
||||
private final BluetoothGattCharacteristic characteristic;
|
||||
private final byte[] value;
|
||||
|
||||
public NotifyCharacteristicChangedAction(@NonNull BluetoothDevice device,
|
||||
@NonNull BluetoothGattCharacteristic characteristic,
|
||||
byte[] value) {
|
||||
super(device);
|
||||
this.characteristic = characteristic;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expectsResult() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@Override
|
||||
public boolean run(BluetoothGattServer server) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
int status = server.notifyCharacteristicChanged(getDevice(), characteristic, false, value);
|
||||
if (status == BluetoothStatusCodes.SUCCESS) {
|
||||
return true;
|
||||
}
|
||||
LOG.error("notifyCharacteristicChanged {} failed: {}",
|
||||
characteristic.getUuid(), BleNamesResolver.getBluetoothStatusString(status));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (characteristic.setValue(value)) {
|
||||
if (server.notifyCharacteristicChanged(getDevice(), characteristic, false)) {
|
||||
return true;
|
||||
}
|
||||
LOG.error("notifyCharacteristicChanged {} failed", characteristic.getUuid());
|
||||
} else {
|
||||
LOG.error("setting value of characteristic {} failed", characteristic.getUuid());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
String uuid = characteristic == null ? "(null)" : characteristic.getUuid().toString();
|
||||
return super.toString() + " " + uuid + " - " + GB.hexdump(value);
|
||||
}
|
||||
}
|
||||
+12
-18
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019-2024 Andreas Böhler
|
||||
/* Copyright (C) 2019-2025 Andreas Böhler, Thomas Kuehne
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
@@ -16,24 +16,19 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.btle.actions;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothGattCallback;
|
||||
import android.bluetooth.BluetoothGattServer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.Logging;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEServerAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
/**
|
||||
* Invokes a response on a given GATT characteristic read.
|
||||
* The result status will be made available asynchronously through the
|
||||
* {@link BluetoothGattCallback}
|
||||
*/
|
||||
public class ServerResponseAction extends BtLEServerAction {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ServerResponseAction.class);
|
||||
|
||||
private final byte[] value;
|
||||
private final int requestId;
|
||||
private final int status;
|
||||
@@ -47,17 +42,10 @@ public class ServerResponseAction extends BtLEServerAction {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
@Override
|
||||
public boolean run(BluetoothGattServer server) {
|
||||
return writeValue(server, getDevice(), requestId, status, offset, value);
|
||||
}
|
||||
|
||||
protected boolean writeValue(BluetoothGattServer gattServer, BluetoothDevice device, int requestId, int status, int offset, byte[] value) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("writing to server: " + device.getAddress() + ": " + Logging.formatBytes(value));
|
||||
}
|
||||
|
||||
return gattServer.sendResponse(device, requestId, status, offset, value);
|
||||
return server.sendResponse(getDevice(), requestId, status, offset, getValue());
|
||||
}
|
||||
|
||||
protected final byte[] getValue() {
|
||||
@@ -68,4 +56,10 @@ public class ServerResponseAction extends BtLEServerAction {
|
||||
public boolean expectsResult() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " #" + requestId + " - " + GB.hexdump(getValue());
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -58,7 +58,6 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.ServerTransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.withingssteelhr.activity.WithingsActivityType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.withingssteelhr.communication.WithingsServerAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.withingssteelhr.communication.WithingsUUID;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.withingssteelhr.communication.conversation.ActivitySampleHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.withingssteelhr.communication.conversation.BatteryStateHandler;
|
||||
@@ -441,8 +440,8 @@ public class WithingsSteelHRDeviceSupport extends AbstractBTLESingleDeviceSuppor
|
||||
public void sendAncsNotificationSourceNotification(NotificationSource notificationSource) {
|
||||
try {
|
||||
ServerTransactionBuilder builder = performServer("notificationSourceNotification");
|
||||
notificationSourceCharacteristic.setValue(notificationSource.serialize());
|
||||
builder.add(new WithingsServerAction(device, notificationSourceCharacteristic));
|
||||
byte[] data = notificationSource.serialize();
|
||||
builder.notifyCharacteristicChanged(device, notificationSourceCharacteristic, data);
|
||||
builder.queue(getQueue());
|
||||
} catch (IOException e) {
|
||||
logger.error("Could not send notification.", e);
|
||||
@@ -454,8 +453,7 @@ public class WithingsSteelHRDeviceSupport extends AbstractBTLESingleDeviceSuppor
|
||||
try {
|
||||
ServerTransactionBuilder builder = performServer("dataSourceNotification");
|
||||
byte[] data = response.serialize();
|
||||
dataSourceCharacteristic.setValue(response.serialize());
|
||||
builder.add(new WithingsServerAction(device, dataSourceCharacteristic));
|
||||
builder.notifyCharacteristicChanged(device, dataSourceCharacteristic, data);
|
||||
builder.queue(getQueue());
|
||||
} catch (IOException e) {
|
||||
logger.error("Could not send notification.", e);
|
||||
|
||||
-43
@@ -1,43 +0,0 @@
|
||||
/* Copyright (C) 2023-2024 Frank Ertl
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.withingssteelhr.communication;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.bluetooth.BluetoothGattServer;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEServerAction;
|
||||
|
||||
public class WithingsServerAction extends BtLEServerAction
|
||||
{
|
||||
private BluetoothGattCharacteristic characteristic;
|
||||
|
||||
public WithingsServerAction(BluetoothDevice device, BluetoothGattCharacteristic characteristic) {
|
||||
super(device);
|
||||
this.characteristic = characteristic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expectsResult() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean run(BluetoothGattServer server) {
|
||||
return server.notifyCharacteristicChanged(getDevice(), characteristic, false);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user