diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java index 79566f3bf..0ef82d27e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java @@ -79,6 +79,7 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im mQueue = new BtLEQueue(getBluetoothAdapter(), getDevice(), this, this, getContext(), mSupportedServerServices); mQueue.setAutoReconnect(getAutoReconnect()); mQueue.setImplicitGattCallbackModify(getImplicitCallbackModify()); + mQueue.setSendWriteRequestResponse(getSendWriteRequestResponse()); } return mQueue.connect(); } @@ -89,6 +90,19 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im } } + /** + * Whether to send a write request response to the device, if requested. The standard actually + * expects this to happen, but Gadgetbridge did not originally support it. This is set to false + * to prevent breaking devices that are somehow not expecting the response. + *

+ * See also: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/2831#issuecomment-941568 + * + * @return whether to send write request responses, if a response is requested + */ + public boolean getSendWriteRequestResponse() { + return false; + } + @Override public void setAutoReconnect(boolean enable) { super.setAutoReconnect(enable); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java index 81c19ab46..78d64ee29 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java @@ -82,6 +82,7 @@ public final class BtLEQueue { private final InternalGattServerCallback internalGattServerCallback; private boolean mAutoReconnect; private boolean mImplicitGattCallbackModify = true; + private boolean mSendWriteRequestResponse = false; private Thread dispatchThread = new Thread("Gadgetbridge GATT Dispatcher") { @@ -221,6 +222,10 @@ public final class BtLEQueue { mImplicitGattCallbackModify = enable; } + public void setSendWriteRequestResponse(final boolean enable) { + mSendWriteRequestResponse = enable; + } + protected boolean isConnected() { return mGbDevice.isConnected(); } @@ -756,8 +761,12 @@ public final class BtLEQueue { return; } LOG.debug("characteristic write request: " + device.getAddress() + " characteristic: " + characteristic.getUuid()); + boolean success = false; if (getCallbackToUse() != null) { - getCallbackToUse().onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value); + success = getCallbackToUse().onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value); + } + if (responseNeeded && mSendWriteRequestResponse) { + mBluetoothGattServer.sendResponse(device, requestId, success ? BluetoothGatt.GATT_SUCCESS : BluetoothGatt.GATT_FAILURE, 0, new byte[0]); } } @@ -778,10 +787,13 @@ public final class BtLEQueue { return; } LOG.debug("onDescriptorWriteRequest: " + device.getAddress()); + boolean success = false; if(getCallbackToUse() != null) { - getCallbackToUse().onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value); + success = getCallbackToUse().onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value); + } + if (responseNeeded && mSendWriteRequestResponse) { + mBluetoothGattServer.sendResponse(device, requestId, success ? BluetoothGatt.GATT_SUCCESS : BluetoothGatt.GATT_FAILURE, 0, new byte[0]); } } } - }