Make automatic reconnect after connection loss configurable #293

Mi Band: automatically reconnect when the device is back in range

Also: #89
here
cpfeiffer 2016-04-28 23:17:13 +02:00
parent eca5d40efe
commit 5e02724c4c
12 changed files with 103 additions and 14 deletions

View File

@ -34,6 +34,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
@ -57,6 +58,7 @@ public class GBApplication extends Application {
private static LimitedQueue mIDSenderLookup = new LimitedQueue(16);
private static Appender<ILoggingEvent> fileLogger;
private static Prefs prefs;
private static GBPrefs gbPrefs;
public static final String ACTION_QUIT
= "nodomain.freeyourgadget.gadgetbridge.gbapplication.action.quit";
@ -91,6 +93,7 @@ public class GBApplication extends Application {
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs = new Prefs(sharedPrefs);
gbPrefs = new GBPrefs(prefs);
// don't do anything here before we set up logging, otherwise
// slf4j may be implicitly initialized before we properly configured it.
@ -366,4 +369,8 @@ public class GBApplication extends Application {
public static Prefs getPrefs() {
return prefs;
}
public static GBPrefs getGBPrefs() {
return gbPrefs;
}
}

View File

@ -59,6 +59,7 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
protected GBDevice gbDevice;
private BluetoothAdapter btAdapter;
private Context context;
private boolean autoReconnect;
public void setContext(GBDevice gbDevice, BluetoothAdapter btAdapter, Context context) {
this.gbDevice = gbDevice;
@ -81,6 +82,16 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
return gbDevice.isInitialized();
}
@Override
public void setAutoReconnect(boolean enable) {
autoReconnect = enable;
}
@Override
public boolean getAutoReconnect() {
return autoReconnect;
}
@Override
public GBDevice getDevice() {
return gbDevice;

View File

@ -6,6 +6,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.IBinder;
@ -37,6 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_APP_CONFIGURE;
@ -88,7 +90,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOT
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_PERFORM_PAIR;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_URI;
public class DeviceCommunicationService extends Service {
public class DeviceCommunicationService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final Logger LOG = LoggerFactory.getLogger(DeviceCommunicationService.class);
private boolean mStarted = false;
@ -130,6 +132,9 @@ public class DeviceCommunicationService extends Service {
super.onCreate();
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(GBDevice.ACTION_DEVICE_CHANGED));
mFactory = new DeviceSupportFactory(this);
Prefs prefs = GBApplication.getPrefs();
prefs.getPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
@ -190,8 +195,10 @@ public class DeviceCommunicationService extends Service {
btDeviceAddress = gbDevice.getAddress();
}
boolean autoReconnect = GBPrefs.AUTO_RECONNECT_DEFAULT;
if (prefs != null) {
prefs.getPreferences().edit().putString("last_device_address", btDeviceAddress).apply();
autoReconnect = prefs.getPreferences().getBoolean(GBPrefs.AUTO_RECONNECT, GBPrefs.AUTO_RECONNECT_DEFAULT);
}
if (gbDevice != null && !isConnecting() && !isConnected()) {
@ -203,6 +210,7 @@ public class DeviceCommunicationService extends Service {
if (pair) {
deviceSupport.pair();
} else {
deviceSupport.setAutoReconnect(autoReconnect);
deviceSupport.connect();
}
} else {
@ -478,6 +486,8 @@ public class DeviceCommunicationService extends Service {
@Override
public void onDestroy() {
GBApplication.getPrefs().getPreferences().unregisterOnSharedPreferenceChangeListener(this);
LOG.debug("DeviceCommunicationService is being destroyed");
super.onDestroy();
@ -514,4 +524,14 @@ public class DeviceCommunicationService extends Service {
return name;
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (GBPrefs.AUTO_RECONNECT.equals(key)) {
boolean autoReconnect = GBApplication.getGBPrefs().getAutoReconnect();
if (mDeviceSupport != null) {
mDeviceSupport.setAutoReconnect(autoReconnect);
}
}
}
}

View File

@ -62,6 +62,20 @@ public interface DeviceSupport extends EventHandler {
*/
boolean useAutoConnect();
/**
* Configures this instance to automatically attempt to reconnect after a connection loss.
* How, how long, or how often is up to the implementation.
* Note that tome implementations may not support automatic reconnection at all.
* @param enable
*/
void setAutoReconnect(boolean enable);
/**
* Returns whether this instance to configured to automatically attempt to reconnect after a
* connection loss.
*/
boolean getAutoReconnect();
/**
* Attempts to pair and connect this device with the gadget device. Success
* will be reported via a device change Intent.

View File

@ -56,6 +56,16 @@ public class ServiceDeviceSupport implements DeviceSupport {
return delegate.connect();
}
@Override
public void setAutoReconnect(boolean enable) {
delegate.setAutoReconnect(enable);
}
@Override
public boolean getAutoReconnect() {
return delegate.getAutoReconnect();
}
@Override
public void dispose() {
delegate.dispose();

View File

@ -42,10 +42,19 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im
public boolean connect() {
if (mQueue == null) {
mQueue = new BtLEQueue(getBluetoothAdapter(), getDevice(), this, getContext());
mQueue.setAutoReconnect(getAutoReconnect());
}
return mQueue.connect();
}
@Override
public void setAutoReconnect(boolean enable) {
super.setAutoReconnect(enable);
if (mQueue != null) {
mQueue.setAutoReconnect(enable);
}
}
/**
* Subclasses should populate the given builder to initialize the device (if necessary).
*

View File

@ -34,12 +34,6 @@ public final class BtLEQueue {
private final GBDevice mGbDevice;
private final BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mBluetoothGatt;
/**
* When an automatic reconnect was attempted after a connection breakdown (error)
*/
private long lastReconnectTime = System.currentTimeMillis();
private static final long MIN_MILLIS_BEFORE_RECONNECT = 1000 * 60 * 5; // 5 minutes
private final BlockingQueue<Transaction> mTransactions = new LinkedBlockingQueue<>();
private volatile boolean mDisposed;
@ -51,6 +45,7 @@ public final class BtLEQueue {
private CountDownLatch mConnectionLatch;
private BluetoothGattCharacteristic mWaitCharacteristic;
private final InternalGattCallback internalGattCallback;
private boolean mAutoReconnect;
private Thread dispatchThread = new Thread("GadgetBridge GATT Dispatcher") {
@ -130,6 +125,10 @@ public final class BtLEQueue {
dispatchThread.start();
}
public void setAutoReconnect(boolean enable) {
mAutoReconnect = enable;
}
protected boolean isConnected() {
return mGbDevice.isConnected();
}
@ -222,11 +221,9 @@ public final class BtLEQueue {
* @return true if a reconnection attempt was made, or false otherwise
*/
private boolean maybeReconnect() {
long currentTime = System.currentTimeMillis();
if (currentTime - lastReconnectTime >= MIN_MILLIS_BEFORE_RECONNECT) {
LOG.info("Automatic reconnection attempt...");
lastReconnectTime = currentTime;
return connect();
if (mAutoReconnect && mBluetoothGatt != null) {
LOG.info("Enabling automatic ble reconnect...");
return mBluetoothGatt.connect();
}
return false;
}

View File

@ -365,7 +365,7 @@ public class PebbleIoThread extends GBDeviceIoThread {
LOG.info(e.getMessage());
mIsConnected = false;
int reconnectAttempts = prefs.getInt("pebble_reconnect_attempts", 10);
if (reconnectAttempts > 0) {
if (GBApplication.getGBPrefs().getAutoReconnect() && reconnectAttempts > 0) {
gbDevice.setState(GBDevice.State.CONNECTING);
gbDevice.sendDeviceUpdateIntent(getContext());
int delaySeconds = 1;

View File

@ -0,0 +1,16 @@
package nodomain.freeyourgadget.gadgetbridge.util;
public class GBPrefs {
public static final String AUTO_RECONNECT = "general_autocreconnect";
public static boolean AUTO_RECONNECT_DEFAULT = true;
private final Prefs mPrefs;
public GBPrefs(Prefs prefs) {
mPrefs = prefs;
}
public boolean getAutoReconnect() {
return mPrefs.getBoolean(AUTO_RECONNECT, AUTO_RECONNECT_DEFAULT);
}
}

View File

@ -244,5 +244,6 @@
<string name="updatefirmwareoperation_firmware_not_sent">Firmware not sent</string>
<string name="charts_legend_heartrate">Heart Rate</string>
<string name="live_activity_heart_rate">Heart Rate</string>
<string name="pref_title_general_autocreonnect">Reconnect automatically</string>
</resources>

View File

@ -7,6 +7,10 @@
android:defaultValue="false"
android:key="general_autoconnectonbluetooth"
android:title="@string/pref_title_general_autoconnectonbluetooth" />
<CheckBoxPreference
android:defaultValue="false"
android:key="general_autocreconnect"
android:title="@string/pref_title_general_autocreonnect" />
<ListPreference
android:defaultValue="default"
android:key="audio_player"

View File

@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0'
classpath 'com.android.tools.build:gradle:2.1.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files