1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-13 08:30:39 +02:00

Use a custom IntentListener callback instead of LocalBroadcastManager for ble profiles

The issue here is the following:

- we used intents in the generic BleProfile classes to notify about the results of e.g. certain read requests
- we used to send these results asynchronously via LocalBroadcastManager.sendBroadcast(), which always used the main thread for sending
- however, we noticed that reconnecting to devices sometimes failed because the results arrived too late and the next action in the BLE queue lacked the necessary information
- the fix was to use LocalBroadcastManager.setBroadcastSync(), so that the results arrive in time
- this unfortunately meant that they were not sent in the main thread anymore, and especially, this would send all pending intents that were previously queued via sendBroadcast() also in the "wrong" thread (in order to keep the order of events)

The fix is to use a custom IntentListener callback interface for synchronous notifications of ble profile results
*without* also causing other, previously queued intents to be sent.

Fixes #1218
This commit is contained in:
cpfeiffer 2018-08-18 00:39:14 +02:00
parent 98cd54657a
commit 50295864f5
5 changed files with 41 additions and 59 deletions

View File

@ -22,6 +22,9 @@ import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
@ -44,10 +47,26 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
public abstract class AbstractBleProfile<T extends AbstractBTLEDeviceSupport> extends AbstractGattCallback {
private final T mSupport;
private List<IntentListener> listeners = new ArrayList<IntentListener>(1);
public AbstractBleProfile(T support) {
this.mSupport = support;
}
public void addListener(IntentListener listener) {
if (listener != null && !listeners.contains(listener)) {
listeners.add(listener);
}
}
public boolean removeListener(IntentListener listener) {
return listeners.remove(listener);
}
protected List<IntentListener> getListeners() {
return Collections.unmodifiableList(listeners);
}
/**
* All notifications should be sent through this methods to make them testable.
* @param intent the intent to broadcast
@ -55,7 +74,9 @@ public abstract class AbstractBleProfile<T extends AbstractBTLEDeviceSupport> ex
protected void notify(Intent intent) {
// note: we send synchronously in order to keep the processing order of BLE events
// in BtleQueue and the reception of results.
LocalBroadcastManager.getInstance(getContext()).sendBroadcastSync(intent);
for (IntentListener listener : listeners) {
listener.notify(intent);
}
}
/**

View File

@ -0,0 +1,10 @@
package nodomain.freeyourgadget.gadgetbridge.service.btle.profiles;
import android.content.Intent;
/**
* Callback interface for delivering results of ble requests.
*/
public interface IntentListener {
void notify(Intent intent);
}

View File

@ -23,12 +23,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.hplus;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.support.v4.content.LocalBroadcastManager;
import android.widget.Toast;
import org.apache.commons.lang3.ArrayUtils;
@ -63,7 +58,6 @@ import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
@ -79,35 +73,17 @@ public class HPlusSupport extends AbstractBTLEDeviceSupport {
private HPlusHandlerThread syncHelper;
private DeviceType deviceType = DeviceType.UNKNOWN;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String s = intent.getAction();
if (s.equals(DeviceInfoProfile.ACTION_DEVICE_INFO)) {
handleDeviceInfo((nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo) intent.getParcelableExtra(DeviceInfoProfile.EXTRA_DEVICE_INFO));
}
}
};
public HPlusSupport(DeviceType type) {
super(LOG);
LOG.info("HPlusSupport Instance Created");
deviceType = type;
addSupportedService(HPlusConstants.UUID_SERVICE_HP);
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext());
IntentFilter intentFilter = new IntentFilter();
broadcastManager.registerReceiver(mReceiver, intentFilter);
}
@Override
public void dispose() {
LOG.info("Dispose");
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext());
broadcastManager.unregisterReceiver(mReceiver);
close();
super.dispose();

View File

@ -102,6 +102,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactionAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.IntentListener;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.heartrate.HeartRateProfile;
@ -151,9 +152,9 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
private static final Logger LOG = LoggerFactory.getLogger(HuamiSupport.class);
private final DeviceInfoProfile<HuamiSupport> deviceInfoProfile;
private final HeartRateProfile<HuamiSupport> heartRateProfile;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
private final IntentListener mListener = new IntentListener() {
@Override
public void onReceive(Context context, Intent intent) {
public void notify(Intent intent) {
String s = intent.getAction();
if (DeviceInfoProfile.ACTION_DEVICE_INFO.equals(s)) {
handleDeviceInfo((nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo) intent.getParcelableExtra(DeviceInfoProfile.EXTRA_DEVICE_INFO));
@ -197,22 +198,10 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
addSupportedService(HuamiService.UUID_SERVICE_FIRMWARE_SERVICE);
deviceInfoProfile = new DeviceInfoProfile<>(this);
deviceInfoProfile.addListener(mListener);
addSupportedProfile(deviceInfoProfile);
heartRateProfile = new HeartRateProfile<>(this);
addSupportedProfile(heartRateProfile);
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext());
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(DeviceInfoProfile.ACTION_DEVICE_INFO);
intentFilter.addAction(DeviceService.ACTION_MIBAND2_AUTH);
broadcastManager.registerReceiver(mReceiver, intentFilter);
}
@Override
public void dispose() {
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext());
broadcastManager.unregisterReceiver(mReceiver);
super.dispose();
}
@Override

View File

@ -18,12 +18,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.vibratissimo;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.support.v4.content.LocalBroadcastManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -46,6 +42,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSuppo
import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.IntentListener;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.battery.BatteryInfoProfile;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfoProfile;
@ -56,9 +53,9 @@ public class VibratissimoSupport extends AbstractBTLEDeviceSupport {
private final BatteryInfoProfile<VibratissimoSupport> batteryInfoProfile;
private final GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
private final GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo();
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
private final IntentListener mListener = new IntentListener() {
@Override
public void onReceive(Context context, Intent intent) {
public void notify(Intent intent) {
String s = intent.getAction();
if (s.equals(DeviceInfoProfile.ACTION_DEVICE_INFO)) {
handleDeviceInfo((nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.deviceinfo.DeviceInfo) intent.getParcelableExtra(DeviceInfoProfile.EXTRA_DEVICE_INFO));
@ -77,15 +74,11 @@ public class VibratissimoSupport extends AbstractBTLEDeviceSupport {
addSupportedService(UUID.fromString("00001523-1212-efde-1523-785feabcd123"));
deviceInfoProfile = new DeviceInfoProfile<>(this);
deviceInfoProfile.addListener(mListener);
batteryInfoProfile = new BatteryInfoProfile<>(this);
batteryInfoProfile.addListener(mListener);
addSupportedProfile(deviceInfoProfile);
addSupportedProfile(batteryInfoProfile);
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext());
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BatteryInfoProfile.ACTION_BATTERY_INFO);
intentFilter.addAction(DeviceInfoProfile.ACTION_DEVICE_INFO);
broadcastManager.registerReceiver(mReceiver, intentFilter);
}
private void handleBatteryInfo(nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.battery.BatteryInfo info) {
@ -93,13 +86,6 @@ public class VibratissimoSupport extends AbstractBTLEDeviceSupport {
handleGBDeviceEvent(batteryCmd);
}
@Override
public void dispose() {
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext());
broadcastManager.unregisterReceiver(mReceiver);
super.dispose();
}
@Override
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));