From be575af3143dca262966f067249c9908e665b868 Mon Sep 17 00:00:00 2001 From: Damien Gaignon Date: Sat, 15 Oct 2022 18:06:01 +0200 Subject: [PATCH] Add BTBR service --- .../btbr/AbstractBTBRDeviceSupport.java | 155 +++++++++++ .../service/btbr/AbstractTransaction.java | 47 ++++ .../gadgetbridge/service/btbr/BtBRAction.java | 64 +++++ .../gadgetbridge/service/btbr/BtBRQueue.java | 250 ++++++++++++++++++ .../service/btbr/SocketCallback.java | 35 +++ .../service/btbr/Transaction.java | 71 +++++ .../service/btbr/TransactionBuilder.java | 89 +++++++ .../btbr/actions/AbortTransactionAction.java | 49 ++++ .../btbr/actions/CheckInitializedAction.java | 46 ++++ .../service/btbr/actions/PlainAction.java | 39 +++ .../btbr/actions/SetDeviceBusyAction.java | 53 ++++ .../btbr/actions/SetDeviceStateAction.java | 53 ++++ .../service/btbr/actions/WaitAction.java | 43 +++ .../service/btbr/actions/WriteAction.java | 83 ++++++ .../service/btle/AbstractBTLEOperation.java | 4 +- .../service/btle/ServerTransaction.java | 2 +- .../btle/ServerTransactionBuilder.java | 4 +- .../service/btle/Transaction.java | 2 +- .../service/btle/TransactionBuilder.java | 4 +- .../btle/profiles/AbstractBleProfile.java | 2 +- .../banglejs/BangleJSDeviceSupport.java | 2 +- .../casio/CasioGB6900DeviceSupport.java | 2 +- .../FetchStepCountDataOperation.java | 8 +- .../operations/GetConfigurationOperation.java | 6 +- .../casio/operations/InitOperationGB6900.java | 6 +- .../casio/operations/InitOperationGBX100.java | 8 +- .../casio/operations/SetAlarmOperation.java | 4 +- .../operations/SetConfigurationOperation.java | 14 +- .../devices/fitpro/FitProDeviceSupport.java | 2 +- .../service/devices/hplus/HPlusSupport.java | 2 +- .../huami/operations/InitOperation.java | 2 +- .../devices/id115/AbstractID115Operation.java | 2 +- .../devices/jyou/BFH16DeviceSupport.java | 2 +- .../service/devices/jyou/JYouSupport.java | 2 +- .../devices/lefun/LefunDeviceSupport.java | 2 +- .../lefun/requests/MultiFetchRequest.java | 2 +- .../lenovo/operations/InitOperation.java | 4 +- .../watchxplus/WatchXPlusDeviceSupport.java | 2 +- .../makibeshr3/MakibesHR3DeviceSupport.java | 2 +- .../operations/AbstractMiBandOperation.java | 2 +- .../miscale2/MiScale2DeviceSupport.java | 2 +- .../service/devices/no1f1/No1F1Support.java | 2 +- .../devices/supercars/SuperCarsSupport.java | 2 +- .../service/devices/tlw64/TLW64Support.java | 2 +- .../devices/waspos/WaspOSDeviceSupport.java | 2 +- .../devices/watch9/Watch9DeviceSupport.java | 2 +- .../watch9/operations/InitOperation.java | 4 +- 47 files changed, 1132 insertions(+), 55 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/AbstractBTBRDeviceSupport.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/AbstractTransaction.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/BtBRAction.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/BtBRQueue.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/SocketCallback.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/Transaction.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/TransactionBuilder.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/AbortTransactionAction.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/CheckInitializedAction.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/PlainAction.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/SetDeviceBusyAction.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/SetDeviceStateAction.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/WaitAction.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/WriteAction.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/AbstractBTBRDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/AbstractBTBRDeviceSupport.java new file mode 100644 index 000000000..053fb8a3b --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/AbstractBTBRDeviceSupport.java @@ -0,0 +1,155 @@ +/* Copyright (C) 2022 Damien Gaignon + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr; + +import org.slf4j.Logger; + +import android.location.Location; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.UUID; + +import nodomain.freeyourgadget.gadgetbridge.Logging; +import nodomain.freeyourgadget.gadgetbridge.model.Reminder; +import nodomain.freeyourgadget.gadgetbridge.model.WorldClock; +import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport; +import nodomain.freeyourgadget.gadgetbridge.service.btbr.actions.CheckInitializedAction; + +/** + * Abstract base class for devices connected through a serial protocol, like RFCOMM BT or TCP socket. + *

+ * The connection to the device and all communication is made with a generic {@link BtClassicIo}. + * Messages to the device are encoded + * sent via {@link BtClassicIo}. + * + * @see BtClassicIo + */ +public abstract class AbstractBTBRDeviceSupport extends AbstractDeviceSupport implements SocketCallback { + private BtBRQueue mQueue; + private UUID mSupportedService = null; + private Logger logger; + + public AbstractBTBRDeviceSupport(Logger logger) { + this.logger = logger; + if (logger == null) { + throw new IllegalArgumentException("logger must not be null"); + } + } + + @Override + public boolean connect() { + if (mQueue == null) { + mQueue = new BtBRQueue(getBluetoothAdapter(), getDevice(), getContext(), this, getSupportedService()); + } + return mQueue.connect(); + } + + /** + * Subclasses should populate the given builder to initialize the device (if necessary). + * + * @return the same builder as passed as the argument + */ + protected TransactionBuilder initializeDevice(TransactionBuilder builder) { + return builder; + } + + @Override + public void dispose() { + if (mQueue != null) { + mQueue.dispose(); + mQueue = null; + } + } + + public TransactionBuilder createTransactionBuilder(String taskName) { + return new TransactionBuilder(taskName); + } + + /** + * Ensures that the device is connected and (only then) performs the actions of the given + * transaction builder. + * + * In contrast to {@link #performInitialized(String)}, no initialization sequence is performed + * with the device, only the actions of the given builder are executed. + * @param transaction + * @throws IOException + * @see {@link #performInitialized(String)} + */ + public void performConnected(Transaction transaction) throws IOException { + if (!isConnected()) { + if (!connect()) { + throw new IOException("2: Unable to connect to device: " + getDevice()); + } + } + getQueue().add(transaction); + } + + public BtBRQueue getQueue() { + return mQueue; + } + + /** + * Subclasses should call this method to add services they support. + * Only supported services will be queried for characteristics. + * + * @param aSupportedService + */ + protected void addSupportedService(UUID aSupportedService) { + mSupportedService = aSupportedService; + } + + protected UUID getSupportedService() { + return mSupportedService; + } + + /** + * Utility method that may be used to log incoming messages when we don't know how to deal with them yet. + * + * @param value + */ + public void logMessageContent(byte[] value) { + logger.info("RECEIVED DATA WITH LENGTH: " + ((value != null) ? value.length : "(null)")); + Logging.logBytes(logger, value); + } + + public void onConnectionEstablished() { + initializeDevice(createTransactionBuilder("Initializing device")).queue(getQueue()); + } + + @Override + public void onSetFmFrequency(float frequency) {} + + @Override + public void onSetLedColor(int color) {} + + @Override + public void onSetGpsLocation(Location location) {} + + @Override + public void onSetWorldClocks(ArrayList clocks) {} + + @Override + public void onPowerOff() {} + + @Override + public void onSetPhoneVolume(final float volume) {} + + @Override + public void onSetReminders(ArrayList reminders) {} + +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/AbstractTransaction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/AbstractTransaction.java new file mode 100644 index 000000000..f042f859e --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/AbstractTransaction.java @@ -0,0 +1,47 @@ +/* Copyright (C) 2015-2021 Andreas Böhler, Andreas Shimokawa, Carsten + Pfeiffer, Daniele Gobbetti + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr; + +import java.text.DateFormat; +import java.util.Date; +import java.util.Locale; + +public abstract class AbstractTransaction { + private final String mName; + private final long creationTimestamp = System.currentTimeMillis(); + + public AbstractTransaction(String taskName) { + this.mName = taskName; + } + + public String getTaskName() { + return mName; + } + + protected String getCreationTime() { + return DateFormat.getTimeInstance(DateFormat.MEDIUM).format(new Date(creationTimestamp)); + } + + public abstract int getActionCount(); + + @Override + public String toString() { + return String.format(Locale.US, "%s: Transaction task: %s with %d actions", getCreationTime(), getTaskName(), getActionCount()); + } + +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/BtBRAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/BtBRAction.java new file mode 100644 index 000000000..6a9b48a7d --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/BtBRAction.java @@ -0,0 +1,64 @@ +/* Copyright (C) 2015-2021 Andreas Shimokawa, Carsten Pfeiffer, Uwe Hermann + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr; + +import android.bluetooth.BluetoothSocket; + +import java.util.Date; + +import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; + +/** + * This allows performing one socket request at a time. + * As they are asynchronous anyway, we encapsulate every socket request (only write) + * inside a runnable action. + *

+ * These actions are then executed one after another, ensuring that every action's result + * has been posted before invoking the next action. + *

+ * As there is only write action, this class will be needed for later usage. + */ +public abstract class BtBRAction { + private final long creationTimestamp; + + public BtBRAction() { + creationTimestamp = System.currentTimeMillis(); + } + + /** + * Returns true if this action expects an (async) result which must + * be waited for, before continuing with other actions. + *

+ */ + public abstract boolean expectsResult(); + + /** + * Executes this action, e.g. reads or write a Socket characteristic. + * + * @param socket the characteristic to manipulate, or null if none. + * @return true if the action was successful, false otherwise + */ + public abstract boolean run(BluetoothSocket socket); + + protected String getCreationTime() { + return DateTimeUtils.formatDateTime(new Date(creationTimestamp)); + } + + public String toString() { + return getCreationTime() + ": " + getClass().getSimpleName(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/BtBRQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/BtBRQueue.java new file mode 100644 index 000000000..5eeb57c9b --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/BtBRQueue.java @@ -0,0 +1,250 @@ +/* Copyright (C) 2022 Damien Gaignon +* +* 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 . +*/ +package nodomain.freeyourgadget.gadgetbridge.service.btbr; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSocket; +import android.content.Context; +import android.os.ParcelUuid; + +import androidx.annotation.Nullable; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.LinkedBlockingQueue; + +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; + +public final class BtBRQueue { + private static final Logger LOG = LoggerFactory.getLogger(BtBRQueue.class); + + private BluetoothAdapter mBtAdapter = null; + private BluetoothSocket mBtSocket = null; + private GBDevice mGbDevice; + private SocketCallback mCallback; + private UUID mService; + + private final BlockingQueue mTransactions = new LinkedBlockingQueue<>(); + private volatile boolean mDisposed; + private volatile boolean mCrashed; + + private Context mContext; + private CountDownLatch mConnectionLatch; + private CountDownLatch mAvailableData; + + private Thread writeThread = new Thread("Gadgetbridge IO writeThread") { + @Override + public void run() { + LOG.debug("Socket Write Thread started."); + + while (!mDisposed && !mCrashed) { + try { + AbstractTransaction qTransaction = mTransactions.take(); + if (!isConnected()) { + LOG.debug("Not connected, waiting for connection..."); + setDeviceConnectionState(GBDevice.State.NOT_CONNECTED); + // wait until the connection succeeds before running the actions + // Note that no automatic connection is performed. This has to be triggered + // on the outside typically by the DeviceSupport. The reason is that + // devices have different kinds of initializations and this class has no + // idea about them. + mConnectionLatch = new CountDownLatch(1); + mConnectionLatch.await(); + mConnectionLatch = null; + } + LOG.info("Ready for a new message exchange."); + Transaction transaction = (Transaction)qTransaction; + for (BtBRAction action : transaction.getActions()) { + if (LOG.isDebugEnabled()) { + LOG.debug("About to run action: " + action); + } + if (action.run(mBtSocket)) { + LOG.debug("Action ok: " + action); + } else { + LOG.error("Action returned false: " + action); + break; + } + } + } catch (InterruptedException ignored) { + mConnectionLatch = null; + LOG.debug("Thread interrupted"); + } catch (Throwable ex) { + LOG.error("IO Write Thread died: " + ex.getMessage(), ex); + mCrashed = true; + mConnectionLatch = null; + } + } + } + }; + + private Thread readThread = new Thread("Gadgetbridge IO readThread") { + @Override + public void run() { + LOG.debug("Queue Read Thread started."); + while (!mDisposed && !mCrashed) { + try { + if (!isConnected()) { + LOG.debug("not connected, waiting for connection..."); + // wait until the connection succeeds before running the actions + // Note that no automatic connection is performed. This has to be triggered + // on the outside typically by the DeviceSupport. The reason is that + // devices have different kinds of initializations and this class has no + // idea about them. + mConnectionLatch = new CountDownLatch(1); + mConnectionLatch.await(); + mConnectionLatch = null; + } + if (mAvailableData != null) { + if (mBtSocket.getInputStream().available() == 0) { + mAvailableData.countDown(); + } + } + byte[] data = new byte[1024]; + int len = mBtSocket.getInputStream().read(data); + LOG.debug("Received data: " + StringUtils.bytesToHex(data)); + mCallback.onSocketRead(Arrays.copyOf(data, len)); + } catch (InterruptedException ignored) { + mConnectionLatch = null; + LOG.debug("Thread interrupted"); + } catch (Throwable ex) { + LOG.error("IO Read Thread died: " + ex.getMessage(), ex); + mCrashed = true; + mConnectionLatch = null; + } + } + } + }; + + public BtBRQueue(BluetoothAdapter btAdapter, GBDevice gbDevice, Context context, SocketCallback socketCallback, UUID supportedService) { + mBtAdapter = btAdapter; + mGbDevice = gbDevice; + mContext = context; + mCallback = socketCallback; + mService = supportedService; + + writeThread.start(); + readThread.start(); + } + + /** + * Connects to the given remote device. Note that this does not perform any device + * specific initialization. This should be done in the specific {@link DeviceSupport} + * class. + * + * @return true whether the connection attempt was successfully triggered and false if that failed or if there is already a connection + */ + + protected boolean connect() { + if (isConnected()) { + LOG.warn("Ignoring connect() because already connected."); + return false; + } + + LOG.info("Attemping to connect to " + mGbDevice.getName()); + GBDevice.State originalState = mGbDevice.getState(); + setDeviceConnectionState(GBDevice.State.CONNECTING); + + try { + BluetoothDevice btDevice = mBtAdapter.getRemoteDevice(mGbDevice.getAddress()); + // UUID should be in a BluetoothSocket class and not in BluetoothSocketCharacteristic + mBtSocket = btDevice.createRfcommSocketToServiceRecord(mService); + mBtSocket.connect(); + if (mBtSocket.isConnected()) { + setDeviceConnectionState(GBDevice.State.CONNECTED); + } else { + LOG.debug("Connection not established"); + } + if (mConnectionLatch != null) { + mConnectionLatch.countDown(); + } + } catch (IOException e) { + LOG.error("Server socket cannot be started.", e); + setDeviceConnectionState(originalState); + mBtSocket = null; + return false; + } + + onConnectionEstablished(); + + return true; + } + + protected void onConnectionEstablished() { + mCallback.onConnectionEstablished(); + } + + public void disconnect() { + if (mBtSocket != null) { + try { + mAvailableData = new CountDownLatch(1); + mAvailableData.await(); + mAvailableData = null; + mBtSocket.close(); + } catch (IOException e) { + LOG.error(e.getMessage()); + } catch (InterruptedException e) { + LOG.error(e.getMessage()); + } + } + } + + protected boolean isConnected() { + return mGbDevice.isConnected(); + } + + /** + * Adds a transaction to the end of the queue. + * + * @param transaction + */ + public void add(Transaction transaction) { + LOG.debug("about to add: " + transaction); + if (!transaction.isEmpty()) { + mTransactions.add(transaction); + } + } + + protected void setDeviceConnectionState(GBDevice.State newState) { + LOG.debug("New device connection state: " + newState); + mGbDevice.setState(newState); + mGbDevice.sendDeviceUpdateIntent(mContext, GBDevice.DeviceUpdateSubject.DEVICE_STATE); + } + + public void dispose() { + if (mDisposed) { + return; + } + mDisposed = true; + disconnect(); + writeThread.interrupt(); + writeThread = null; + readThread.interrupt(); + readThread = null; + } + +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/SocketCallback.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/SocketCallback.java new file mode 100644 index 000000000..f31effc68 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/SocketCallback.java @@ -0,0 +1,35 @@ +/** Copyright (C) 2022 Damien Gaignon + * + * 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 . + */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr; + +/** + * Callback interface handling io events of a BluetoothSocket. + * It is the counterpart of GattCallback interface designed for GB. +*/ +public interface SocketCallback { + + void onConnectionEstablished(); + + /** + * Read data from InputStream of BluetoothSocket + * + * @param data + */ + void onSocketRead(byte[] data); + +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/Transaction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/Transaction.java new file mode 100644 index 000000000..46dd4c0a8 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/Transaction.java @@ -0,0 +1,71 @@ +/* Copyright (C) 2015-2021 Andreas Böhler, Andreas Shimokawa, Carsten + Pfeiffer, Daniele Gobbetti + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import androidx.annotation.Nullable; + +/** + * Groups a bunch of {@link BtBRAction actions} together, making sure + * that upon failure of one action, all subsequent actions are discarded. + * + * @author TREND + */ +public class Transaction extends AbstractTransaction { + private final List mActions = new ArrayList<>(4); + private + @Nullable + SocketCallback socketCallback; + + public Transaction(String taskName) { + super(taskName); + } + + public void add(BtBRAction action) { + mActions.add(action); + } + + public List getActions() { + return Collections.unmodifiableList(mActions); + } + + public boolean isEmpty() { + return mActions.isEmpty(); + } + + public void setCallback(@Nullable SocketCallback callback) { + socketCallback = callback; + } + + /** + * Returns the GattCallback for this transaction, or null if none. + */ + public + @Nullable + SocketCallback getSocketCallback() { + return socketCallback; + } + + @Override + public int getActionCount() { + return mActions.size(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/TransactionBuilder.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/TransactionBuilder.java new file mode 100644 index 000000000..2066d1d0e --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/TransactionBuilder.java @@ -0,0 +1,89 @@ +/* Copyright (C) 2022 Damien Gaignon + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr; + +import android.os.Build; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; + +import nodomain.freeyourgadget.gadgetbridge.service.btbr.actions.WaitAction; +import nodomain.freeyourgadget.gadgetbridge.service.btbr.actions.WriteAction; + +public class TransactionBuilder { + private static final Logger LOG = LoggerFactory.getLogger(TransactionBuilder.class); + + private final Transaction mTransaction; + private boolean mQueued; + + public TransactionBuilder(String taskName) { + mTransaction = new Transaction(taskName); + } + + public TransactionBuilder write(byte[] data) { + WriteAction action = new WriteAction(data); + return add(action); + } + + + /** + * Causes the queue to sleep for the specified time. + * Note that this is usually a bad idea, since it will not be able to process messages + * during that time. It is also likely to cause race conditions. + * @param millis the number of milliseconds to sleep + */ + public TransactionBuilder wait(int millis) { + WaitAction action = new WaitAction(millis); + return add(action); + } + + public TransactionBuilder add(BtBRAction action) { + mTransaction.add(action); + return this; + } + + /** + * Sets a SocketCallback instance that will be called when the transaction is executed, + * resulting in SocketCallback events. + * + * @param callback the callback to set, may be null + */ + public void setCallback(@Nullable SocketCallback callback) { + mTransaction.setCallback(callback); + } + + /** + * To be used as the final step to execute the transaction by the given queue. + * + * @param queue + */ + public void queue(BtBRQueue queue) { + if (mQueued) { + throw new IllegalStateException("This builder had already been queued. You must not reuse it."); + } + mQueued = true; + queue.add(mTransaction); + } + + public Transaction getTransaction() { + return mTransaction; + } + +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/AbortTransactionAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/AbortTransactionAction.java new file mode 100644 index 000000000..c7eed31da --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/AbortTransactionAction.java @@ -0,0 +1,49 @@ +/* Copyright (C) 2015-2021 Andreas Shimokawa, Carsten Pfeiffer + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr.actions; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import android.bluetooth.BluetoothSocket; + +/** + * A special action that checks for an abort-condition, and if met, the currently + * executing transaction will be aborted by returning false. + */ +public abstract class AbortTransactionAction extends PlainAction { + private static final Logger LOG = LoggerFactory.getLogger(AbortTransactionAction.class); + + public AbortTransactionAction() { + } + + @Override + public boolean run(BluetoothSocket socket) { + if (shouldAbort()) { + LOG.info("Aborting transaction because abort criteria met."); + return false; + } + return true; + } + + protected abstract boolean shouldAbort(); + + @Override + public String toString() { + return getCreationTime() + ": " + getClass().getSimpleName() + ": aborting? " + shouldAbort(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/CheckInitializedAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/CheckInitializedAction.java new file mode 100644 index 000000000..ff967c6a1 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/CheckInitializedAction.java @@ -0,0 +1,46 @@ +/* Copyright (C) 2015-2021 Andreas Shimokawa, Carsten Pfeiffer + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr.actions; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; + +/** + * A special action that is executed at the very front of the initialization + * sequence (transaction). It will abort the entire initialization sequence + * by returning false, when the device is already initialized. + */ +public class CheckInitializedAction extends AbortTransactionAction { + private static final Logger LOG = LoggerFactory.getLogger(CheckInitializedAction.class); + + private final GBDevice device; + + public CheckInitializedAction(GBDevice gbDevice) { + device = gbDevice; + } + + @Override + protected boolean shouldAbort() { + boolean abort = device.isInitialized(); + if (abort) { + LOG.info("Aborting device initialization, because already initialized: " + device); + } + return abort; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/PlainAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/PlainAction.java new file mode 100644 index 000000000..34341b8df --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/PlainAction.java @@ -0,0 +1,39 @@ +/* Copyright (C) 2015-2021 Andreas Shimokawa, Carsten Pfeiffer + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr.actions; + +import nodomain.freeyourgadget.gadgetbridge.service.btbr.BtBRAction; + +/** + * An abstract non-BTBR action. It performs no bluetooth operation, + * does not have a BluetoothSocketCharacteristic instance and expects no result. + */ +public abstract class PlainAction extends BtBRAction { + + public PlainAction() { + } + + @Override + public boolean expectsResult() { + return false; + } + + @Override + public String toString() { + return getCreationTime() + ": " + getClass().getSimpleName(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/SetDeviceBusyAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/SetDeviceBusyAction.java new file mode 100644 index 000000000..2c7990bd6 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/SetDeviceBusyAction.java @@ -0,0 +1,53 @@ +/* Copyright (C) 2015-2021 Andreas Shimokawa, Carsten Pfeiffer + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr.actions; + +import android.bluetooth.BluetoothSocket; +import android.content.Context; + +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; + +public class SetDeviceBusyAction extends PlainAction { + private final GBDevice device; + private final Context context; + private final String busyTask; + + /** + * When run, will mark the device as busy (or not busy). + * + * @param device the device to mark + * @param busyTask the task name to set as busy task, or null to mark as not busy + * @param context + */ + public SetDeviceBusyAction(GBDevice device, String busyTask, Context context) { + this.device = device; + this.busyTask = busyTask; + this.context = context; + } + + @Override + public boolean run(BluetoothSocket socket) { + device.setBusyTask(busyTask); + device.sendDeviceUpdateIntent(context); + return true; + } + + @Override + public String toString() { + return getCreationTime() + ": " + getClass().getName() + ": " + busyTask; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/SetDeviceStateAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/SetDeviceStateAction.java new file mode 100644 index 000000000..63a53c3f0 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/SetDeviceStateAction.java @@ -0,0 +1,53 @@ +/* Copyright (C) 2015-2021 Andreas Shimokawa, Carsten Pfeiffer + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr.actions; + +import android.bluetooth.BluetoothSocket; +import android.content.Context; + +import androidx.annotation.NonNull; + +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; + +public class SetDeviceStateAction extends PlainAction { + private final GBDevice device; + private final GBDevice.State deviceState; + private final Context context; + + public SetDeviceStateAction(GBDevice device, GBDevice.State deviceState, Context context) { + this.device = device; + this.deviceState = deviceState; + this.context = context; + } + + @Override + public boolean run(BluetoothSocket socket) { + device.setState(deviceState); + device.sendDeviceUpdateIntent(getContext(), GBDevice.DeviceUpdateSubject.DEVICE_STATE); + return true; + } + + public Context getContext() { + return context; + } + + @NonNull + @Override + public String toString() { + return super.toString() + " to " + deviceState; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/WaitAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/WaitAction.java new file mode 100644 index 000000000..48c8ab705 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/WaitAction.java @@ -0,0 +1,43 @@ +/* Copyright (C) 2015-2021 Andreas Shimokawa, Carsten Pfeiffer + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr.actions; + +import android.bluetooth.BluetoothSocket; + +/** + * An action that will cause the queue to sleep for the specified time. + * Note that this is usually a bad idea, since it will not be able to process messages + * during that time. It is also likely to cause race conditions. + */ +public class WaitAction extends PlainAction { + + private final int mMillis; + + public WaitAction(int millis) { + mMillis = millis; + } + + @Override + public boolean run(BluetoothSocket socket) { + try { + Thread.sleep(mMillis); + return true; + } catch (InterruptedException e) { + return false; + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/WriteAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/WriteAction.java new file mode 100644 index 000000000..69c5e1099 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btbr/actions/WriteAction.java @@ -0,0 +1,83 @@ +/* Copyright (C) 2015-2021 Andreas Shimokawa, Carsten Pfeiffer, Daniele + Gobbetti, Uwe Hermann + + 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 . */ +package nodomain.freeyourgadget.gadgetbridge.service.btbr.actions; + +import android.bluetooth.BluetoothSocket; + +import java.io.IOException; +import java.io.OutputStream; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import nodomain.freeyourgadget.gadgetbridge.Logging; +import nodomain.freeyourgadget.gadgetbridge.service.btbr.BtBRAction; + +/** + * Invokes a write operation on a given socket. + * The result status will be made available asynchronously through the + * {@link SocketCallback} + */ +public class WriteAction extends BtBRAction { + private static final Logger LOG = LoggerFactory.getLogger(WriteAction.class); + + private final byte[] value; + private OutputStream mOutputStream = null; + + public WriteAction(byte[] value) { + this.value = value; + } + + @Override + public boolean run(BluetoothSocket socket) { + try { + mOutputStream = socket.getOutputStream(); + if (mOutputStream == null) { + LOG.error("mOutStream is null"); + return false; + } + return writeValue(value); + } catch (IOException e) { + LOG.error("Can not get the output stream"); + } + return false; + } + + protected boolean writeValue(byte[] value) { + if (LOG.isDebugEnabled()) { + LOG.debug("writing to socket: " + Logging.formatBytes(value)); + } + try { + mOutputStream.write(value); + mOutputStream.flush(); + return true; + } catch (IOException e) { + LOG.error("Error writing to socket: ", e); + } + return false; + } + + protected final byte[] getValue() { + return value; + } + + @Override + public boolean expectsResult() { + return true; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEOperation.java index e8d18d6cf..55dd62231 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEOperation.java @@ -105,13 +105,13 @@ public abstract class AbstractBTLEOperation */ public TransactionBuilder performInitialized(String taskName) throws IOException { TransactionBuilder builder = mSupport.performInitialized(taskName); - builder.setGattCallback(this); + builder.setCallback(this); return builder; } public TransactionBuilder createTransactionBuilder(String taskName) { TransactionBuilder builder = getSupport().createTransactionBuilder(taskName); - builder.setGattCallback(this); + builder.setCallback(this); return builder; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/ServerTransaction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/ServerTransaction.java index 54a1dec19..e9682a933 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/ServerTransaction.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/ServerTransaction.java @@ -57,7 +57,7 @@ public class ServerTransaction extends AbstractTransaction { return String.format(Locale.US, "%s: Transaction task: %s with %d actions", getCreationTime(), getTaskName(), mActions.size()); } - public void setGattCallback(@Nullable GattServerCallback callback) { + public void setCallback(@Nullable GattServerCallback callback) { gattCallback = callback; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/ServerTransactionBuilder.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/ServerTransactionBuilder.java index 779dc6dfe..7d166a11d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/ServerTransactionBuilder.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/ServerTransactionBuilder.java @@ -54,8 +54,8 @@ public class ServerTransactionBuilder { * * @param callback the callback to set, may be null */ - public void setGattCallback(@Nullable GattServerCallback callback) { - mTransaction.setGattCallback(callback); + public void setCallback(@Nullable GattServerCallback callback) { + mTransaction.setCallback(callback); } public diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/Transaction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/Transaction.java index a64c256e6..90f8296c9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/Transaction.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/Transaction.java @@ -54,7 +54,7 @@ public class Transaction extends AbstractTransaction { return mActions.isEmpty(); } - public void setGattCallback(@Nullable GattCallback callback) { + public void setCallback(@Nullable GattCallback callback) { gattCallback = callback; modifyGattCallback = true; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/TransactionBuilder.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/TransactionBuilder.java index e622636a8..0e3b811e7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/TransactionBuilder.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/TransactionBuilder.java @@ -108,8 +108,8 @@ public class TransactionBuilder { * * @param callback the callback to set, may be null */ - public void setGattCallback(@Nullable GattCallback callback) { - mTransaction.setGattCallback(callback); + public void setCallback(@Nullable GattCallback callback) { + mTransaction.setCallback(callback); } public diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/AbstractBleProfile.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/AbstractBleProfile.java index 346586cf2..3bc3350e7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/AbstractBleProfile.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/profiles/AbstractBleProfile.java @@ -88,7 +88,7 @@ public abstract class AbstractBleProfile ex */ public TransactionBuilder performInitialized(String taskName) throws IOException { TransactionBuilder builder = mSupport.performInitialized(taskName); - builder.setGattCallback(this); + builder.setCallback(this); return builder; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java index b8b44b248..591ed6835 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/banglejs/BangleJSDeviceSupport.java @@ -313,7 +313,7 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport { rxCharacteristic = getCharacteristic(BangleJSConstants.UUID_CHARACTERISTIC_NORDIC_UART_RX); txCharacteristic = getCharacteristic(BangleJSConstants.UUID_CHARACTERISTIC_NORDIC_UART_TX); - builder.setGattCallback(this); + builder.setCallback(this); builder.notify(rxCharacteristic, true); Prefs devicePrefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress())); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioGB6900DeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioGB6900DeviceSupport.java index 19ac8a532..2e30bd5ba 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioGB6900DeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/CasioGB6900DeviceSupport.java @@ -171,7 +171,7 @@ public class CasioGB6900DeviceSupport extends CasioSupport { getDevice().setFirmwareVersion2("N/A"); - builder.setGattCallback(this); + builder.setCallback(this); configureWatch(builder); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/operations/FetchStepCountDataOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/operations/FetchStepCountDataOperation.java index c935e058e..281cc47bb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/operations/FetchStepCountDataOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casio/operations/FetchStepCountDataOperation.java @@ -51,7 +51,7 @@ public class FetchStepCountDataOperation extends AbstractBTLEOperation { this.authFlags = authFlags; this.cryptFlags = cryptFlags; this.builder = builder; - builder.setGattCallback(this); + builder.setCallback(this); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/id115/AbstractID115Operation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/id115/AbstractID115Operation.java index 5b4885c9c..a25d6ce07 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/id115/AbstractID115Operation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/id115/AbstractID115Operation.java @@ -62,7 +62,7 @@ public abstract class AbstractID115Operation extends AbstractBTLEOperation{ super(support); this.needsAuth = needsAuth; this.builder = builder; - builder.setGattCallback(this); + builder.setCallback(this); } @Override @@ -73,7 +73,7 @@ public class InitOperation extends AbstractBTLEOperation{ getSupport().logMessageContent(value); if (ArrayUtils.equals(value, Watch9Constants.RESP_AUTHORIZATION_TASK, 5) && value[8] == 0x01) { TransactionBuilder builder = getSupport().createTransactionBuilder("authInit"); - builder.setGattCallback(this); + builder.setCallback(this); builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext())); getSupport().initialize(builder).performImmediately(builder); } else {