From 34ad088b883bc8969ca5607fb112b6bd6d03804a Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 27 Nov 2016 09:49:28 +0100 Subject: [PATCH] Pebble: Experimental support for BLE on all models via dev option in Pebble Settings HOWTO: 1) Pair you normal Pebble (not necessary if already done), make sure it was connected once 2) Unpair your LE pebble if already paired 3) Switch on "Always prefer BLE" in Pebble Settings 4) Tap on the + in Control Center to add a new device 5) Pair your Pebble-LE XXXX or Pebble Time LE XXXX inside Gadgetbridge's Device Discovery actibity Now Gadgetbridge will connect to your LE Pebble when tapping on Pebble XXXX if "Always Prefer BLE" option is enabled. You can easily switch back to classic LE by turning that option off again --- .../gadgetbridge/daogen/GBDaoGenerator.java | 7 +- .../devices/pebble/PebblePairingActivity.java | 111 ++++++++++++++---- .../gadgetbridge/impl/GBDevice.java | 20 ++++ .../service/DeviceCommunicationService.java | 2 +- .../devices/pebble/PebbleIoThread.java | 24 ++-- .../devices/pebble/ble/PebbleLESupport.java | 9 +- .../service/serial/GBDeviceIoThread.java | 2 +- .../gadgetbridge/util/DeviceHelper.java | 6 +- app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/preferences.xml | 5 + 10 files changed, 144 insertions(+), 44 deletions(-) diff --git a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java index 3a197772..63e5d713 100644 --- a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java +++ b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java @@ -40,13 +40,18 @@ public class GBDaoGenerator { private static final String TIMESTAMP_TO = "timestampTo"; public static void main(String[] args) throws Exception { - Schema schema = new Schema(14, MAIN_PACKAGE + ".entities"); + Schema schema = new Schema(15, MAIN_PACKAGE + ".entities"); Entity userAttributes = addUserAttributes(schema); Entity user = addUserInfo(schema, userAttributes); Entity deviceAttributes = addDeviceAttributes(schema); Entity device = addDevice(schema, deviceAttributes); + + // yeah deep shit, has to be here (after device) for db upgrade and column order + // because addDevice adds a property to deviceAttributes also.... + deviceAttributes.addStringProperty("volatileIdentifier"); + Entity tag = addTag(schema); Entity userDefinedActivityOverlay = addActivityDescription(schema, tag, user); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebblePairingActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebblePairingActivity.java index f6fe4f60..c221ef9f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebblePairingActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebblePairingActivity.java @@ -14,14 +14,22 @@ import android.widget.Toast; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; + +import de.greenrobot.dao.query.Query; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenter; import nodomain.freeyourgadget.gadgetbridge.activities.DiscoveryActivity; import nodomain.freeyourgadget.gadgetbridge.activities.GBActivity; +import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; +import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; +import nodomain.freeyourgadget.gadgetbridge.entities.Device; +import nodomain.freeyourgadget.gadgetbridge.entities.DeviceDao; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; +import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; import nodomain.freeyourgadget.gadgetbridge.util.GB; public class PebblePairingActivity extends GBActivity { @@ -30,6 +38,7 @@ public class PebblePairingActivity extends GBActivity { private boolean isPairing; private boolean isLEPebble; private String macAddress; + private BluetoothDevice mBtDevice; private final BroadcastReceiver mPairingReceiver = new BroadcastReceiver() { @Override @@ -59,7 +68,7 @@ public class PebblePairingActivity extends GBActivity { if (bondState == BluetoothDevice.BOND_BONDED) { LOG.info("Bonded with " + device.getAddress()); if (!isLEPebble) { - performConnect(device); + performConnect(null); } } else if (bondState == BluetoothDevice.BOND_BONDING) { LOG.info("Bonding in progress with " + device.getAddress()); @@ -84,12 +93,34 @@ public class PebblePairingActivity extends GBActivity { macAddress = intent.getStringExtra(DeviceCoordinator.EXTRA_DEVICE_MAC_ADDRESS); if (macAddress == null) { Toast.makeText(this, getString(R.string.message_cannot_pair_no_mac), Toast.LENGTH_SHORT).show(); - startActivity(new Intent(this, DiscoveryActivity.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)); - finish(); + returnToPairingActivity(); return; } - startPairing(); + mBtDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(macAddress); + if (mBtDevice == null) { + GB.toast(this, "No such Bluetooth Device: " + macAddress, Toast.LENGTH_LONG, GB.ERROR); + returnToPairingActivity(); + return; + } + + isLEPebble = mBtDevice.getType() == BluetoothDevice.DEVICE_TYPE_LE; + + GBDevice gbDevice = null; + if (isLEPebble) { + if (mBtDevice.getName().startsWith("Pebble-LE ") || mBtDevice.getName().startsWith("Pebble Time LE ")) { + if (!GBApplication.getPrefs().getBoolean("pebble_force_le", false)) { + GB.toast(this, "Please switch on \"Always prefer BLE\" option in Pebble settings before pairing you Pebble LE", Toast.LENGTH_LONG, GB.ERROR); + returnToPairingActivity(); + return; + } + gbDevice = getMatchingParentDeviceFromDB(mBtDevice); + if (gbDevice == null) { + return; + } + } + } + startPairing(gbDevice); } @Override @@ -104,10 +135,11 @@ public class PebblePairingActivity extends GBActivity { if (isPairing) { stopPairing(); } + super.onDestroy(); } - private void startPairing() { + private void startPairing(GBDevice gbDevice) { isPairing = true; message.setText(getString(R.string.pairing, macAddress)); @@ -116,12 +148,7 @@ public class PebblePairingActivity extends GBActivity { filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED); registerReceiver(mBondingReceiver, filter); - BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(macAddress); - if (device != null) { - performPair(device); - } else { - GB.toast(this, "No such Bluetooth Device: " + macAddress, Toast.LENGTH_LONG, GB.ERROR); - } + performPair(gbDevice); } private void pairingFinished(boolean pairedSuccessfully) { @@ -147,31 +174,69 @@ public class PebblePairingActivity extends GBActivity { isPairing = false; } - protected void performPair(BluetoothDevice device) { - int bondState = device.getBondState(); + protected void performPair(GBDevice gbDevice) { + int bondState = mBtDevice.getBondState(); if (bondState == BluetoothDevice.BOND_BONDED) { - GB.toast(getString(R.string.pairing_already_bonded, device.getName(), device.getAddress()), Toast.LENGTH_SHORT, GB.INFO); + GB.toast(getString(R.string.pairing_already_bonded, mBtDevice.getName(), mBtDevice.getAddress()), Toast.LENGTH_SHORT, GB.INFO); return; } if (bondState == BluetoothDevice.BOND_BONDING) { - GB.toast(this, getString(R.string.pairing_in_progress, device.getName(), macAddress), Toast.LENGTH_LONG, GB.INFO); + GB.toast(this, getString(R.string.pairing_in_progress, mBtDevice.getName(), macAddress), Toast.LENGTH_LONG, GB.INFO); return; } - GB.toast(this, getString(R.string.pairing_creating_bond_with, device.getName(), macAddress), Toast.LENGTH_LONG, GB.INFO); + GB.toast(this, getString(R.string.pairing_creating_bond_with, mBtDevice.getName(), macAddress), Toast.LENGTH_LONG, GB.INFO); GBApplication.deviceService().disconnect(); // just to make sure... - if (device.getType() == BluetoothDevice.DEVICE_TYPE_LE) { - isLEPebble = true; - performConnect(device); + + if (isLEPebble) { + performConnect(gbDevice); } else { - isLEPebble = false; - device.createBond(); + mBtDevice.createBond(); } } - private void performConnect(BluetoothDevice device) { - GBDevice gbDevice = new GBDevice(device.getAddress(), device.getName(), DeviceType.PEBBLE); + private void performConnect(GBDevice gbDevice) { + if (gbDevice == null) { + gbDevice = new GBDevice(mBtDevice.getAddress(), mBtDevice.getName(), DeviceType.PEBBLE); + } GBApplication.deviceService().connect(gbDevice); } + + private void returnToPairingActivity() { + startActivity(new Intent(this, DiscoveryActivity.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)); + finish(); + } + + private GBDevice getMatchingParentDeviceFromDB(BluetoothDevice btDevice) { + String expectedSuffix = btDevice.getName(); + expectedSuffix = expectedSuffix.replace("Pebble-LE ", ""); + expectedSuffix = expectedSuffix.replace("Pebble Time LE ", ""); + expectedSuffix = expectedSuffix.substring(0, 2) + ":" + expectedSuffix.substring(2); + LOG.info("will try to find a Pebble with BT address suffix " + expectedSuffix); + GBDevice gbDevice = null; + try (DBHandler dbHandler = GBApplication.acquireDB()) { + DaoSession session = dbHandler.getDaoSession(); + DeviceDao deviceDao = session.getDeviceDao(); + Query query = deviceDao.queryBuilder().where(DeviceDao.Properties.Type.eq(1), DeviceDao.Properties.Identifier.like("%" + expectedSuffix)).build(); + List devices = query.list(); + if (devices.size() == 0) { + GB.toast("Please pair your non-LE Pebble before pairing the LE one", Toast.LENGTH_SHORT, GB.INFO); + returnToPairingActivity(); + return null; + } else if (devices.size() > 1) { + GB.toast("Can not match this Pebble LE to a unique device", Toast.LENGTH_SHORT, GB.INFO); + returnToPairingActivity(); + return null; + } + DeviceHelper deviceHelper = DeviceHelper.getInstance(); + gbDevice = deviceHelper.toGBDevice(devices.get(0)); + gbDevice.setVolatileAddress(btDevice.getAddress()); + } catch (Exception e) { + GB.toast("Error retrieving devices from database", Toast.LENGTH_SHORT, GB.ERROR); + returnToPairingActivity(); + return null; + } + return gbDevice; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java index 7fbee9bf..c32f2a2a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java @@ -45,8 +45,10 @@ public class GBDevice implements Parcelable { private static final String DEVINFO_FW_VER = "FW: "; private static final String DEVINFO_HR_VER = "HR: "; private static final String DEVINFO_ADDR = "ADDR: "; + private static final String DEVINFO_ADDR2 = "ADDR2: "; private String mName; private final String mAddress; + private String mVolatileAddress; private final DeviceType mDeviceType; private String mFirmwareVersion; private String mFirmwareVersion2; @@ -60,7 +62,12 @@ public class GBDevice implements Parcelable { private List mDeviceInfos; public GBDevice(String address, String name, DeviceType deviceType) { + this(address, null, name, deviceType); + } + + public GBDevice(String address, String address2, String name, DeviceType deviceType) { mAddress = address; + mVolatileAddress = address2; mName = (name != null) ? name : mAddress; mDeviceType = deviceType; validate(); @@ -69,6 +76,7 @@ public class GBDevice implements Parcelable { private GBDevice(Parcel in) { mName = in.readString(); mAddress = in.readString(); + mVolatileAddress = in.readString(); mDeviceType = DeviceType.values()[in.readInt()]; mFirmwareVersion = in.readString(); mFirmwareVersion2 = in.readString(); @@ -88,6 +96,7 @@ public class GBDevice implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(mName); dest.writeString(mAddress); + dest.writeString(mVolatileAddress); dest.writeInt(mDeviceType.ordinal()); dest.writeString(mFirmwareVersion); dest.writeString(mFirmwareVersion2); @@ -123,6 +132,10 @@ public class GBDevice implements Parcelable { return mAddress; } + public String getVolatileAddress() { + return mVolatileAddress; + } + public String getFirmwareVersion() { return mFirmwareVersion; } @@ -142,6 +155,10 @@ public class GBDevice implements Parcelable { mFirmwareVersion2 = firmwareVersion2; } + public void setVolatileAddress(String volatileAddress) { + mVolatileAddress = volatileAddress; + } + /** * Returns the specific model/hardware revision of this device. * This information is not always available, typically only when the device is initialized @@ -416,6 +433,9 @@ public class GBDevice implements Parcelable { if (mAddress != null) { result.add(new GenericItem(DEVINFO_ADDR, mAddress)); } + if (mVolatileAddress != null) { + result.add(new GenericItem(DEVINFO_ADDR2, mVolatileAddress)); + } Collections.sort(result); return result; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index ef36a80b..7473ec79 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -174,8 +174,8 @@ public class DeviceCommunicationService extends Service implements SharedPrefere DaoSession session = dbHandler.getDaoSession(); if (DBHelper.findDevice(device, session) == null) { DBHelper dbHelper = new DBHelper(context); + DBHelper.getDevice(device, session); // implicitly creates it :P if (dbHelper.getOldActivityDatabaseHandler() != null) { - DBHelper.getDevice(device, session); // implicitly creates it :P Intent startIntent = new Intent(context, OnboardingActivity.class); startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startIntent.putExtra(GBDevice.EXTRA_DEVICE, device); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index 01b43168..7f459a4d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -64,7 +64,7 @@ class PebbleIoThread extends GBDeviceIoThread { public static final String PEBBLEKIT_ACTION_APP_START = "com.getpebble.action.app.START"; public static final String PEBBLEKIT_ACTION_APP_STOP = "com.getpebble.action.app.STOP"; - final Prefs prefs = GBApplication.getPrefs(); + private final Prefs prefs = GBApplication.getPrefs(); private final PebbleProtocol mPebbleProtocol; private final PebbleSupport mPebbleSupport; @@ -174,27 +174,31 @@ class PebbleIoThread extends GBDeviceIoThread { } @Override - protected boolean connect(String btDeviceAddress) { + protected boolean connect() { + String deviceAddress = gbDevice.getAddress(); GBDevice.State originalState = gbDevice.getState(); gbDevice.setState(GBDevice.State.CONNECTING); gbDevice.sendDeviceUpdateIntent(getContext()); try { // contains only one ":"? then it is addr:port - int firstColon = btDeviceAddress.indexOf(":"); - if (firstColon == btDeviceAddress.lastIndexOf(":")) { + int firstColon = deviceAddress.indexOf(":"); + if (firstColon == deviceAddress.lastIndexOf(":")) { mIsTCP = true; - InetAddress serverAddr = InetAddress.getByName(btDeviceAddress.substring(0, firstColon)); - mTCPSocket = new Socket(serverAddr, Integer.parseInt(btDeviceAddress.substring(firstColon + 1))); + InetAddress serverAddr = InetAddress.getByName(deviceAddress.substring(0, firstColon)); + mTCPSocket = new Socket(serverAddr, Integer.parseInt(deviceAddress.substring(firstColon + 1))); mInStream = mTCPSocket.getInputStream(); mOutStream = mTCPSocket.getOutputStream(); } else { mIsTCP = false; - BluetoothDevice btDevice = mBtAdapter.getRemoteDevice(btDeviceAddress); + if (gbDevice.getVolatileAddress() != null && prefs.getBoolean("pebble_force_le", false)) { + deviceAddress = gbDevice.getVolatileAddress(); + } + BluetoothDevice btDevice = mBtAdapter.getRemoteDevice(deviceAddress); if (btDevice.getType() == BluetoothDevice.DEVICE_TYPE_LE) { LOG.info("Ok this seems to be a LE Pebble, try LE Support, trouble ahead!"); mInStream = new PipedInputStream(); mOutStream = new PipedOutputStream(); - mPebbleLESupport = new PebbleLESupport(this.getContext(),btDeviceAddress,(PipedInputStream)mInStream,(PipedOutputStream)mOutStream); // secret branch :P + mPebbleLESupport = new PebbleLESupport(this.getContext(), btDevice, (PipedInputStream) mInStream, (PipedOutputStream) mOutStream); } else { ParcelUuid uuids[] = btDevice.getUuids(); if (uuids == null) { @@ -232,7 +236,7 @@ class PebbleIoThread extends GBDeviceIoThread { @Override public void run() { - mIsConnected = connect(gbDevice.getAddress()); + mIsConnected = connect(); if (!mIsConnected) { if (GBApplication.getGBPrefs().getAutoReconnect()) { gbDevice.setState(GBDevice.State.WAITING_FOR_RECONNECT); @@ -388,7 +392,7 @@ class PebbleIoThread extends GBDeviceIoThread { int delaySeconds = 1; while (reconnectAttempts-- > 0 && !mQuit && !mIsConnected) { LOG.info("Trying to reconnect (attempts left " + reconnectAttempts + ")"); - mIsConnected = connect(gbDevice.getAddress()); + mIsConnected = connect(); if (!mIsConnected) { try { Thread.sleep(delaySeconds * 1000); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleLESupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleLESupport.java index 7aacff68..9254cdcb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleLESupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/ble/PebbleLESupport.java @@ -1,8 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.ble; -import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothManager; import android.content.Context; import org.slf4j.Logger; @@ -22,8 +20,8 @@ public class PebbleLESupport { private PipedOutputStream mPipedOutputStream; private int mMTU = 20; - public PebbleLESupport(Context context, final String btDeviceAddress, PipedInputStream pipedInputStream, PipedOutputStream pipedOutputStream) { - + public PebbleLESupport(Context context, final BluetoothDevice btDevice, PipedInputStream pipedInputStream, PipedOutputStream pipedOutputStream) { + mBtDevice = btDevice; mPipedInputStream = new PipedInputStream(); mPipedOutputStream = new PipedOutputStream(); try { @@ -33,9 +31,6 @@ public class PebbleLESupport { LOG.warn("could not connect input stream"); } - BluetoothManager manager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); - BluetoothAdapter adapter = manager.getAdapter(); - mBtDevice = adapter.getRemoteDevice(btDeviceAddress); mPebbleGATTServer = new PebbleGATTServer(this, context, mBtDevice); mPebbleGATTServer.initialize(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceIoThread.java index 31be6f02..a61d6a58 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceIoThread.java @@ -21,7 +21,7 @@ public abstract class GBDeviceIoThread extends Thread { return gbDevice; } - protected boolean connect(String btDeviceAddress) { + protected boolean connect() { return false; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java index df4a76f8..b16445a8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java @@ -192,7 +192,7 @@ public class DeviceHelper { * @param dbDevice * @return */ - private GBDevice toGBDevice(Device dbDevice) { + public GBDevice toGBDevice(Device dbDevice) { DeviceType deviceType = DeviceType.fromKey(dbDevice.getType()); GBDevice gbDevice = new GBDevice(dbDevice.getIdentifier(), dbDevice.getName(), deviceType); List deviceAttributesList = dbDevice.getDeviceAttributesList(); @@ -201,6 +201,7 @@ public class DeviceHelper { DeviceAttributes attrs = deviceAttributesList.get(0); gbDevice.setFirmwareVersion(attrs.getFirmwareVersion1()); gbDevice.setFirmwareVersion2(attrs.getFirmwareVersion2()); + gbDevice.setVolatileAddress(attrs.getVolatileIdentifier()); } return gbDevice; @@ -211,6 +212,9 @@ public class DeviceHelper { List result = new ArrayList<>(pairedDevices.size()); DeviceHelper deviceHelper = DeviceHelper.getInstance(); for (BluetoothDevice pairedDevice : pairedDevices) { + if (pairedDevice.getName() != null && (pairedDevice.getName().startsWith("Pebble-LE ") || pairedDevice.getName().startsWith("Pebble Time LE "))) { + continue; // ignore LE Pebble (this is part of the main device now (volatileAddress) + } GBDevice device = deviceHelper.toSupportedDevice(pairedDevice); if (device != null) { result.add(device); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c4d60953..1c8e5e8d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -118,6 +118,8 @@ This option forces using the latest notification protocol depending on the firmware version. ENABLE ONLY IF YOU KNOW WHAT YOU ARE DOING! Enable untested features Enable features that are untested. ENABLE ONLY IF YOU KNOW WHAT YOU ARE DOING! + Always prefer BLE + Use experimental Pebble LE support for all Pebbles instead of BT classic, requires paring a "Pebble LE" after non LE had been connected once Reconnection Attempts not connected diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 483f6deb..6dd3371b 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -336,6 +336,11 @@ android:key="pebble_force_untested" android:summary="@string/pref_summary_pebble_forceuntested" android:title="@string/pref_title_pebble_forceuntested" /> +