diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/casiogb6900/CasioGB6900Constants.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/casiogb6900/CasioGB6900Constants.java
index f86d0b9b8..af779fc2c 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/casiogb6900/CasioGB6900Constants.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/casiogb6900/CasioGB6900Constants.java
@@ -64,6 +64,17 @@ public final class CasioGB6900Constants {
public static final UUID FUNCTION_SWITCH_CHARACTERISTIC = UUID.fromString("26eb001e-b012-49a8-b1f8-394fb2032b0f");
public static final String MUSIC_MESSAGE = "Music";
+ // Link Loss
+
+ public static final UUID LINK_LOSS_SERVICE = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb");
+
+ // TxPower
+
+ public static final UUID TX_POWER_SERVICE_UUID = UUID.fromString("00001804-0000-1000-8000-00805f9b34fb");
+ public static final UUID TX_POWER_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002a07-0000-1000-8000-00805f9b34fb");
+ // Settings
+ public static final UUID CASIO_SETTING_FOR_BLE_CHARACTERISTIC_UUID = UUID.fromString("26eb000f-b012-49a8-b1f8-394fb2032b0f");
+
// Notification Types
public static final byte CALL_NOTIFICATION_ID = 3;
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casiogb6900/CasioGATTServer.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casiogb6900/CasioGATTServer.java
index 530255ea9..a25202330 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casiogb6900/CasioGATTServer.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casiogb6900/CasioGATTServer.java
@@ -17,6 +17,7 @@
along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.service.devices.casiogb6900;
+import android.app.PendingIntent;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
@@ -25,12 +26,20 @@ import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.content.Context;
+import android.content.Intent;
+import android.support.v4.content.LocalBroadcastManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import nodomain.freeyourgadget.gadgetbridge.GBApplication;
+import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
import nodomain.freeyourgadget.gadgetbridge.devices.casiogb6900.CasioGB6900Constants;
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
+import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
+import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
+import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
class CasioGATTServer extends BluetoothGattServerCallback {
private static final Logger LOG = LoggerFactory.getLogger(CasioGATTServer.class);
@@ -142,6 +151,18 @@ class CasioGATTServer extends BluetoothGattServerCallback {
if (newState == BluetoothGattServer.STATE_DISCONNECTED) {
}
+ if (newState == BluetoothGattServer.STATE_CONNECTED) {
+ GBDevice.State devState = mDeviceSupport.getDevice().getState();
+ Intent deviceCommunicationServiceIntent = new Intent(mContext, DeviceCommunicationService.class);
+ if (devState.equals(GBDevice.State.WAITING_FOR_RECONNECT) || devState.equals(GBDevice.State.NOT_CONNECTED)) {
+ LOG.info("Forcing re-connect because GATT server has been reconnected.");
+ deviceCommunicationServiceIntent.setAction(DeviceService.ACTION_CONNECT);
+ deviceCommunicationServiceIntent.putExtra(GBDevice.EXTRA_DEVICE, device);
+ LocalBroadcastManager.getInstance(mContext).sendBroadcast(deviceCommunicationServiceIntent);
+ //PendingIntent reconnectPendingIntent = PendingIntent.getService(mContext, 2, deviceCommunicationServiceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ //builder.addAction(R.drawable.ic_notification, context.getString(R.string.controlcenter_connect), reconnectPendingIntent);
+ }
+ }
}
@Override
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casiogb6900/CasioGATTThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casiogb6900/CasioGATTThread.java
index 2491a80c3..ecd668746 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casiogb6900/CasioGATTThread.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casiogb6900/CasioGATTThread.java
@@ -25,6 +25,7 @@ public class CasioGATTThread extends Thread {
CasioGATTServer mServer = null;
private static final Logger LOG = LoggerFactory.getLogger(CasioGATTThread.class);
private boolean mStopFlag = false;
+ private final Object waitObject = new Object();
public CasioGATTThread(Context context, CasioGB6900DeviceSupport deviceSupport)
{
@@ -36,18 +37,25 @@ public class CasioGATTThread extends Thread {
}
@Override
- public void run()
- {
- if(!mServer.initialize()) {
+ public void run() {
+ if (!mServer.initialize()) {
LOG.error("Error initializing CasioGATTServer. Has the context been set?");
return;
}
- while(!mStopFlag) {
- try {
- wait(100);
- } catch(Exception e)
- {
+ long waitTime = 60 * 1000;
+
+ while (!mStopFlag) {
+ synchronized (waitObject) {
+ try {
+ waitObject.wait(waitTime);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ if (mStopFlag) {
+ break;
}
}
mServer.close();
@@ -55,6 +63,9 @@ public class CasioGATTThread extends Thread {
public void quit() {
mStopFlag = true;
+ synchronized (waitObject) {
+ waitObject.notify();
+ }
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casiogb6900/CasioGB6900DeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casiogb6900/CasioGB6900DeviceSupport.java
index c085909d0..d82dc19fc 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casiogb6900/CasioGB6900DeviceSupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/casiogb6900/CasioGB6900DeviceSupport.java
@@ -20,6 +20,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.casiogb6900;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattService;
import android.content.Context;
import android.net.Uri;
@@ -45,23 +46,24 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.GattService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
private static final Logger LOG = LoggerFactory.getLogger(CasioGB6900DeviceSupport.class);
- public BluetoothGattCharacteristic mCasioCharact1 = null;
- public BluetoothGattCharacteristic mCasioCharact2 = null;
- public BluetoothGattCharacteristic mCasioCharact3 = null;
- public BluetoothGattCharacteristic mCasioCharact4 = null;
- public BluetoothGattCharacteristic mCasioCharact5 = null;
- private CasioGATTThread mThread = null;
+ private ArrayList mCasioCharacteristics = new ArrayList();
+ private CasioGATTThread mThread;
+ private CasioHandlerThread mHandlerThread = null;
private MusicSpec mBufferMusicSpec = null;
private MusicStateSpec mBufferMusicStateSpec = null;
+ private BluetoothGatt mBtGatt = null;
public CasioGB6900DeviceSupport() {
super(LOG);
+ addSupportedService(GattService.UUID_SERVICE_IMMEDIATE_ALERT);
addSupportedService(CasioGB6900Constants.CASIO_VIRTUAL_SERVER_SERVICE);
addSupportedService(CasioGB6900Constants.ALERT_SERVICE_UUID);
addSupportedService(CasioGB6900Constants.CASIO_IMMEDIATE_ALERT_SERVICE_UUID);
@@ -70,6 +72,8 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
addSupportedService(CasioGB6900Constants.WATCH_FEATURES_SERVICE_UUID);
addSupportedService(CasioGB6900Constants.CASIO_PHONE_ALERT_STATUS_SERVICE);
addSupportedService(CasioGB6900Constants.MORE_ALERT_SERVICE_UUID);
+ addSupportedService(CasioGB6900Constants.TX_POWER_SERVICE_UUID);
+ addSupportedService(CasioGB6900Constants.LINK_LOSS_SERVICE);
mThread = new CasioGATTThread(getContext(), this);
}
@@ -80,6 +84,34 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
mThread.start();
}
+ @Override
+ public void dispose() {
+ LOG.info("Dispose");
+ close();
+
+ super.dispose();
+ }
+
+ private void close() {
+ if (mHandlerThread != null) {
+ mHandlerThread.quit();
+ mHandlerThread.interrupt();
+ mHandlerThread = null;
+ }
+
+ if(mThread != null) {
+ mThread.quit();
+ mThread.interrupt();
+ mThread = null;
+ }
+ }
+
+ @Override
+ public void onServicesDiscovered(BluetoothGatt gatt) {
+ mBtGatt = gatt;
+ super.onServicesDiscovered(gatt);
+ }
+
@Override
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
LOG.info("Initializing");
@@ -87,24 +119,57 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
gbDevice.setState(GBDevice.State.INITIALIZING);
gbDevice.sendDeviceUpdateIntent(getContext());
- mCasioCharact1 = getCharacteristic(CasioGB6900Constants.CASIO_A_NOT_COM_SET_NOT);
- mCasioCharact2 = getCharacteristic(CasioGB6900Constants.CASIO_A_NOT_W_REQ_NOT);
- mCasioCharact3 = getCharacteristic(CasioGB6900Constants.FUNCTION_SWITCH_CHARACTERISTIC);
- mCasioCharact4 = getCharacteristic(CasioGB6900Constants.ALERT_LEVEL_CHARACTERISTIC_UUID);
- mCasioCharact5 = getCharacteristic(CasioGB6900Constants.RINGER_CONTROL_POINT);
+ addCharacteristics();
builder.setGattCallback(this);
- builder.notify(mCasioCharact1, true);
- builder.notify(mCasioCharact2, true);
- builder.notify(mCasioCharact3, true);
- builder.notify(mCasioCharact4, true);
- builder.notify(mCasioCharact5, true);
+
+ enableNotifications(builder, true);
+
+ configureWatch(builder);
LOG.info("Initialization Done");
return builder;
}
+ // FIXME: Replace hardcoded values by configuration
+ private void configureWatch(TransactionBuilder builder) {
+ if (mBtGatt == null)
+ return;
+
+ byte value[] = new byte[]{GattCharacteristic.MILD_ALERT};
+
+ BluetoothGattService llService = mBtGatt.getService(CasioGB6900Constants.LINK_LOSS_SERVICE);
+ BluetoothGattCharacteristic charact = llService.getCharacteristic(CasioGB6900Constants.ALERT_LEVEL_CHARACTERISTIC_UUID);
+ builder.write(charact, value);
+ }
+
+ private void addCharacteristics() {
+ mCasioCharacteristics.clear();
+ mCasioCharacteristics.add(getCharacteristic(CasioGB6900Constants.CASIO_A_NOT_COM_SET_NOT));
+ mCasioCharacteristics.add(getCharacteristic(CasioGB6900Constants.CASIO_A_NOT_W_REQ_NOT));
+ mCasioCharacteristics.add(getCharacteristic(CasioGB6900Constants.FUNCTION_SWITCH_CHARACTERISTIC));
+ mCasioCharacteristics.add(getCharacteristic(CasioGB6900Constants.ALERT_LEVEL_CHARACTERISTIC_UUID));
+ mCasioCharacteristics.add(getCharacteristic(CasioGB6900Constants.RINGER_CONTROL_POINT));
+ }
+
+ public boolean enableNotifications(TransactionBuilder builder, boolean enable) {
+ for(BluetoothGattCharacteristic charact : mCasioCharacteristics) {
+ builder.notify(charact, enable);
+ }
+ return true;
+ }
+
+ public void readTxPowerLevel() {
+ try {
+ TransactionBuilder builder = performInitialized("readTxPowerLevel");
+ builder.read(getCharacteristic(CasioGB6900Constants.TX_POWER_LEVEL_CHARACTERISTIC_UUID));
+ builder.queue(getQueue());
+ } catch (IOException e) {
+ LOG.warn("readTxPowerLevel failed: " + e.getMessage());
+ }
+ }
+
private void writeCasioCurrentTime(TransactionBuilder builder) {
byte[] arr = new byte[10];
Calendar cal = Calendar.getInstance();
@@ -172,6 +237,10 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
{
case (byte) 1:
LOG.info("Initialization done, setting state to INITIALIZED");
+ if(mHandlerThread == null) {
+ mHandlerThread = new CasioHandlerThread(getDevice(), getContext(), this);
+ mHandlerThread.start();
+ }
gbDevice.setState(GBDevice.State.INITIALIZED);
gbDevice.sendDeviceUpdateIntent(getContext());
handled = true;
@@ -195,7 +264,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
{
TransactionBuilder builder = createTransactionBuilder("writeCasioCurrentTime");
writeCasioCurrentTime(builder);
- performImmediately(builder);
+ performConnected(builder.getTransaction());
handled = true;
} catch (IOException e) {
LOG.warn("handleTimeRequests::writeCasioCurrentTime failed: " + e.getMessage());
@@ -206,7 +275,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
{
TransactionBuilder builder = createTransactionBuilder("writeCasioLocalTimeInformation");
writeCasioLocalTimeInformation(builder);
- performImmediately(builder);
+ performConnected(builder.getTransaction());
handled = true;
} catch (IOException e) {
LOG.warn("handleTimeRequests::writeCasioLocalTimeInformation failed: " + e.getMessage());
@@ -221,7 +290,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
{
TransactionBuilder builder = createTransactionBuilder("writeCasioVirtualServerFeature");
writeCasioVirtualServerFeature(builder);
- performImmediately(builder);
+ performConnected(builder.getTransaction());
} catch (IOException e) {
LOG.warn("handleServerFeatureRequests failed: " + e.getMessage());
}
@@ -251,15 +320,35 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport {
return handled;
}
+ @Override
+ public boolean onCharacteristicRead(BluetoothGatt gatt,
+ BluetoothGattCharacteristic characteristic, int status) {
+
+ UUID characteristicUUID = characteristic.getUuid();
+ byte[] data = characteristic.getValue();
+
+ if(data.length == 0)
+ return true;
+
+ if(characteristicUUID.equals(CasioGB6900Constants.TX_POWER_LEVEL_CHARACTERISTIC_UUID)) {
+ String str = "onCharacteristicRead: Received power level: ";
+ for(int i=0; i. */
+package nodomain.freeyourgadget.gadgetbridge.service.devices.casiogb6900;
+
+import android.content.Context;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import nodomain.freeyourgadget.gadgetbridge.devices.casiogb6900.CasioGB6900Constants;
+import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
+import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
+import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceIoThread;
+
+public class CasioHandlerThread extends GBDeviceIoThread {
+ private static final Logger LOG = LoggerFactory.getLogger(CasioHandlerThread.class);
+ private boolean mQuit = false;
+ private CasioGB6900DeviceSupport mDeviceSupport;
+ private final Object waitObject = new Object();
+ //private CasioGATTServer mServer = null;
+
+ private int TX_PERIOD = 60;
+
+ private Calendar mTxTime = GregorianCalendar.getInstance();
+
+ public CasioHandlerThread(GBDevice gbDevice, Context context, CasioGB6900DeviceSupport deviceSupport) {
+ super(gbDevice, context);
+ LOG.info("Initializing Casio Handler Thread");
+ mQuit = false;
+ //mServer = new CasioGATTServer(context, deviceSupport);
+ mDeviceSupport = deviceSupport;
+ }
+
+ @Override
+ public void run() {
+ mQuit = false;
+
+ /*
+ if(!mServer.initialize()) {
+ LOG.error("Error initializing CasioGATTServer. Has the context been set?");
+ return;
+ }
+ */
+
+ long waitTime = TX_PERIOD * 1000;
+ while (!mQuit) {
+
+ if (waitTime > 0) {
+ synchronized (waitObject) {
+ try {
+ waitObject.wait(waitTime);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ if (mQuit) {
+ break;
+ }
+
+ if (gbDevice.getState() == GBDevice.State.NOT_CONNECTED) {
+ quit();
+ }
+
+ Calendar now = GregorianCalendar.getInstance();
+
+ if (now.compareTo(mTxTime) > 0) {
+ requestTxPowerLevel();
+ }
+
+ now = GregorianCalendar.getInstance();
+ waitTime = mTxTime.getTimeInMillis() - now.getTimeInMillis();
+ }
+
+ }
+
+ public void requestTxPowerLevel() {
+ try {
+ mDeviceSupport.readTxPowerLevel();
+
+ } catch(Exception e) {
+
+ }
+
+ mTxTime = GregorianCalendar.getInstance();
+ mTxTime.add(Calendar.SECOND, TX_PERIOD);
+ synchronized (waitObject) {
+ waitObject.notify();
+ }
+ }
+
+ @Override
+ public void quit() {
+ LOG.info("CasioHandlerThread: Quit Handler Thread");
+ mQuit = true;
+ synchronized (waitObject) {
+ waitObject.notify();
+ }
+ }
+
+}