2024-01-10 18:54:00 +01:00
|
|
|
/* Copyright (C) 2015-2024 Andreas Shimokawa, Carsten Pfeiffer, Damien
|
|
|
|
Gaignon, Daniel Dakhno, Uwe Hermann
|
2017-03-10 14:53:19 +01:00
|
|
|
|
|
|
|
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
|
2024-01-10 18:54:00 +01:00
|
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
2015-08-18 00:28:17 +02:00
|
|
|
package nodomain.freeyourgadget.gadgetbridge.service.btle;
|
2015-08-18 00:08:22 +02:00
|
|
|
|
|
|
|
import android.bluetooth.BluetoothGatt;
|
|
|
|
import android.bluetooth.BluetoothGattCharacteristic;
|
|
|
|
import android.bluetooth.BluetoothGattDescriptor;
|
|
|
|
import android.content.Context;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.util.UUID;
|
|
|
|
|
|
|
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
2016-01-07 00:33:20 +01:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.OperationStatus;
|
2015-08-18 00:08:22 +02:00
|
|
|
|
|
|
|
/**
|
2015-08-18 00:28:17 +02:00
|
|
|
* Abstract base class for a BTLEOperation, i.e. an operation that does more than
|
|
|
|
* just sending a few bytes to the device. It typically involves exchanging many messages
|
|
|
|
* between the mobile and the device.
|
2015-09-24 14:45:21 +02:00
|
|
|
* <p/>
|
2015-08-18 00:08:22 +02:00
|
|
|
* One operation may execute multiple @{link Transaction transactions} with each
|
|
|
|
* multiple @{link BTLEAction actions}.
|
2015-09-24 14:45:21 +02:00
|
|
|
* <p/>
|
2015-08-18 00:08:22 +02:00
|
|
|
* This class implements GattCallback so that subclasses may override those methods
|
|
|
|
* to handle those events.
|
2015-08-18 00:28:17 +02:00
|
|
|
* Note: by default all Gatt events are forwarded to AbstractBTLEDeviceSupport, subclasses may override
|
2015-08-18 00:08:22 +02:00
|
|
|
* this behavior.
|
|
|
|
*/
|
2015-08-18 00:28:17 +02:00
|
|
|
public abstract class AbstractBTLEOperation<T extends AbstractBTLEDeviceSupport> implements GattCallback, BTLEOperation {
|
|
|
|
private final T mSupport;
|
2016-01-07 00:33:20 +01:00
|
|
|
protected OperationStatus operationStatus = OperationStatus.INITIAL;
|
2017-11-01 23:04:52 +01:00
|
|
|
private String name;
|
2015-08-18 00:08:22 +02:00
|
|
|
|
2015-08-18 00:28:17 +02:00
|
|
|
protected AbstractBTLEOperation(T support) {
|
2015-08-18 00:08:22 +02:00
|
|
|
mSupport = support;
|
|
|
|
}
|
|
|
|
|
2015-12-06 23:39:41 +01:00
|
|
|
/**
|
|
|
|
* Performs this operation. The whole operation is asynchronous, i.e.
|
|
|
|
* this method quickly returns before the actual operation is finished.
|
|
|
|
* Calls #prePerform() and, if successful, #doPerform().
|
2016-02-29 20:54:39 +01:00
|
|
|
*
|
2015-12-06 23:39:41 +01:00
|
|
|
* @throws IOException
|
|
|
|
*/
|
|
|
|
@Override
|
|
|
|
public final void perform() throws IOException {
|
2016-01-07 00:33:20 +01:00
|
|
|
operationStatus = OperationStatus.STARTED;
|
2015-12-06 23:39:41 +01:00
|
|
|
prePerform();
|
2016-01-07 00:33:20 +01:00
|
|
|
operationStatus = OperationStatus.RUNNING;
|
2015-12-06 23:39:41 +01:00
|
|
|
doPerform();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Hook for subclasses to perform something before #doPerform() is invoked.
|
2016-02-29 20:54:39 +01:00
|
|
|
*
|
2015-12-06 23:39:41 +01:00
|
|
|
* @throws IOException
|
|
|
|
*/
|
|
|
|
protected void prePerform() throws IOException {
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Subclasses must implement this. When invoked, #prePerform() returned
|
|
|
|
* successfully.
|
|
|
|
* Note that subclasses HAVE TO call #operationFinished() when the entire
|
2016-12-01 20:18:36 +01:00
|
|
|
* operation is done (successful or not).
|
2016-02-29 20:54:39 +01:00
|
|
|
*
|
2015-12-06 23:39:41 +01:00
|
|
|
* @throws IOException
|
|
|
|
*/
|
|
|
|
protected abstract void doPerform() throws IOException;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* You MUST call this method when the operation has finished, either
|
2016-12-01 20:18:36 +01:00
|
|
|
* successfully or unsuccessfully.
|
2016-02-29 20:54:39 +01:00
|
|
|
*
|
2017-09-02 22:45:21 +02:00
|
|
|
* Subclasses must ensure that the {@link BtLEQueue queue's}'s gatt callback (set on the transaction builder by {@link #performInitialized(String)})
|
|
|
|
* is being unset, otherwise it will continue to receive events until another transaction is being executed by the queue.
|
|
|
|
*
|
2015-12-06 23:39:41 +01:00
|
|
|
* @throws IOException
|
|
|
|
*/
|
|
|
|
protected void operationFinished() throws IOException {
|
|
|
|
}
|
|
|
|
|
2015-08-18 00:08:22 +02:00
|
|
|
/**
|
2015-08-18 00:28:17 +02:00
|
|
|
* Delegates to the DeviceSupport instance and additionally sets this instance as the Gatt
|
2015-08-18 00:08:22 +02:00
|
|
|
* callback for the transaction.
|
2015-09-24 14:45:21 +02:00
|
|
|
*
|
2015-08-18 00:08:22 +02:00
|
|
|
* @param taskName
|
|
|
|
* @return
|
|
|
|
* @throws IOException
|
|
|
|
*/
|
|
|
|
public TransactionBuilder performInitialized(String taskName) throws IOException {
|
|
|
|
TransactionBuilder builder = mSupport.performInitialized(taskName);
|
2022-10-15 18:06:01 +02:00
|
|
|
builder.setCallback(this);
|
2015-08-18 00:08:22 +02:00
|
|
|
return builder;
|
|
|
|
}
|
|
|
|
|
2018-09-14 20:11:27 +02:00
|
|
|
public TransactionBuilder createTransactionBuilder(String taskName) {
|
|
|
|
TransactionBuilder builder = getSupport().createTransactionBuilder(taskName);
|
2022-10-15 18:06:01 +02:00
|
|
|
builder.setCallback(this);
|
2018-09-14 20:11:27 +02:00
|
|
|
return builder;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void performImmediately(TransactionBuilder builder) throws IOException {
|
|
|
|
mSupport.performImmediately(builder);
|
|
|
|
}
|
|
|
|
|
2015-08-18 00:08:22 +02:00
|
|
|
protected Context getContext() {
|
|
|
|
return mSupport.getContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected GBDevice getDevice() {
|
|
|
|
return mSupport.getDevice();
|
|
|
|
}
|
|
|
|
|
2017-11-01 23:04:52 +01:00
|
|
|
protected void setName(String name) {
|
|
|
|
this.name = name;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String getName() {
|
|
|
|
if (name != null) {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
String busyTask = getDevice().getBusyTask();
|
|
|
|
if (busyTask != null) {
|
|
|
|
return busyTask;
|
|
|
|
}
|
|
|
|
return getClass().getSimpleName();
|
|
|
|
}
|
|
|
|
|
2015-08-18 00:08:22 +02:00
|
|
|
protected BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
|
|
|
|
return mSupport.getCharacteristic(uuid);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected BtLEQueue getQueue() {
|
|
|
|
return mSupport.getQueue();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void unsetBusy() {
|
2016-06-28 23:07:24 +02:00
|
|
|
if (getDevice().isBusy()) {
|
|
|
|
getDevice().unsetBusyTask();
|
|
|
|
getDevice().sendDeviceUpdateIntent(getContext());
|
|
|
|
}
|
2015-08-18 00:08:22 +02:00
|
|
|
}
|
|
|
|
|
2016-01-07 00:33:20 +01:00
|
|
|
public boolean isOperationRunning() {
|
|
|
|
return operationStatus == OperationStatus.RUNNING;
|
|
|
|
}
|
|
|
|
|
2016-03-30 21:48:42 +02:00
|
|
|
public boolean isOperationFinished() {
|
|
|
|
return operationStatus == OperationStatus.FINISHED;
|
|
|
|
}
|
|
|
|
|
2015-08-18 00:28:17 +02:00
|
|
|
public T getSupport() {
|
2015-08-18 00:08:22 +02:00
|
|
|
return mSupport;
|
|
|
|
}
|
|
|
|
|
|
|
|
// All Gatt callbacks delegated to MiBandSupport
|
|
|
|
@Override
|
|
|
|
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
|
|
|
|
mSupport.onConnectionStateChange(gatt, status, newState);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onServicesDiscovered(BluetoothGatt gatt) {
|
|
|
|
mSupport.onServicesDiscovered(gatt);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2016-07-28 23:04:37 +02:00
|
|
|
public boolean onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
|
|
|
|
return mSupport.onCharacteristicRead(gatt, characteristic, status);
|
2015-08-18 00:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2016-07-28 23:04:37 +02:00
|
|
|
public boolean onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
|
|
|
|
return mSupport.onCharacteristicWrite(gatt, characteristic, status);
|
2015-08-18 00:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2016-07-28 23:04:37 +02:00
|
|
|
public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
|
|
|
|
return mSupport.onCharacteristicChanged(gatt, characteristic);
|
2015-08-18 00:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2016-07-28 23:04:37 +02:00
|
|
|
public boolean onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
|
|
|
|
return mSupport.onDescriptorRead(gatt, descriptor, status);
|
2015-08-18 00:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2016-07-28 23:04:37 +02:00
|
|
|
public boolean onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
|
|
|
|
return mSupport.onDescriptorWrite(gatt, descriptor, status);
|
2015-08-18 00:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
|
|
|
|
mSupport.onReadRemoteRssi(gatt, rssi, status);
|
|
|
|
}
|
2019-11-14 04:53:19 +01:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
|
|
|
|
mSupport.onMtuChanged(gatt, mtu, status);
|
|
|
|
}
|
2015-08-18 00:08:22 +02:00
|
|
|
}
|