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 79f03b8ee..530255ea9 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 @@ -29,8 +29,6 @@ import android.content.Context; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.CountDownLatch; - import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl; import nodomain.freeyourgadget.gadgetbridge.devices.casiogb6900.CasioGB6900Constants; @@ -47,12 +45,15 @@ class CasioGATTServer extends BluetoothGattServerCallback { mDeviceSupport = deviceSupport; } - public void setContext(Context ctx) - { + public void setContext(Context ctx) { mContext = ctx; } boolean initialize() { + if(mContext == null) { + return false; + } + BluetoothManager bluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE); if (bluetoothManager == null) { return false; @@ -81,6 +82,7 @@ class CasioGATTServer extends BluetoothGattServerCallback { return true; } + @Override public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { if (!characteristic.getUuid().equals(CasioGB6900Constants.NAME_OF_APP_CHARACTERISTIC_UUID)) { @@ -95,7 +97,7 @@ class CasioGATTServer extends BluetoothGattServerCallback { } } - + @Override public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { @@ -103,12 +105,16 @@ class CasioGATTServer extends BluetoothGattServerCallback { LOG.warn("unexpected write request"); return; } - if((value[0] & 0x03) == 0) - { + + if(mDeviceSupport == null) { + LOG.warn("mDeviceSupport is null, did initialization complete?"); + return; + } + + if((value[0] & 0x03) == 0) { int button = value[1] & 0x0f; LOG.info("Button pressed: " + button); - switch(button) - { + switch(button) { case 3: musicCmd.event = GBDeviceEventMusicControl.Event.NEXT; break; @@ -118,18 +124,18 @@ class CasioGATTServer extends BluetoothGattServerCallback { case 1: musicCmd.event = GBDeviceEventMusicControl.Event.PLAYPAUSE; break; - case 0: - - break; + default: + LOG.warn("Unhandled button received: " + button); + return; } mDeviceSupport.evaluateGBDeviceEvent(musicCmd); } - else - { + else { LOG.info("received from device: " + value.toString()); } } + @Override public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { LOG.info("Connection state change for device: " + device.getAddress() + " status = " + status + " newState = " + newState); @@ -138,6 +144,7 @@ class CasioGATTServer extends BluetoothGattServerCallback { } } + @Override public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { @@ -147,11 +154,12 @@ class CasioGATTServer extends BluetoothGattServerCallback { } } - + @Override public void onServiceAdded(int status, BluetoothGattService service) { LOG.info("onServiceAdded() status = " + status + " service = " + service.getUuid()); } + @Override public void onNotificationSent(BluetoothDevice bluetoothDevice, int status) { LOG.info("onNotificationSent() status = " + status + " to device " + bluetoothDevice.getAddress()); } @@ -160,6 +168,7 @@ class CasioGATTServer extends BluetoothGattServerCallback { if (mBluetoothGattServer != null) { mBluetoothGattServer.clearServices(); mBluetoothGattServer.close(); + mBluetoothGattServer = null; } } 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 6ed5426ca..2491a80c3 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 @@ -18,25 +18,31 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.casiogb6900; import android.content.Context; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class CasioGATTThread extends Thread { CasioGATTServer mServer = null; + private static final Logger LOG = LoggerFactory.getLogger(CasioGATTThread.class); + private boolean mStopFlag = false; public CasioGATTThread(Context context, CasioGB6900DeviceSupport deviceSupport) { mServer = new CasioGATTServer(context, deviceSupport); } - public void setContext(Context ctx) - { + public void setContext(Context ctx) { mServer.setContext(ctx); } @Override public void run() { - mServer.initialize(); - while(true) - { + if(!mServer.initialize()) { + LOG.error("Error initializing CasioGATTServer. Has the context been set?"); + return; + } + while(!mStopFlag) { try { wait(100); } catch(Exception e) @@ -44,5 +50,12 @@ public class CasioGATTThread extends Thread { } } + mServer.close(); } + + public void quit() { + mStopFlag = true; + } + + } 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 ef2ae3b1b..c085909d0 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 @@ -105,8 +105,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { return builder; } - private void writeCasioCurrentTime(TransactionBuilder builder) - { + private void writeCasioCurrentTime(TransactionBuilder builder) { byte[] arr = new byte[10]; Calendar cal = Calendar.getInstance(); @@ -135,8 +134,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { } } - private void writeCasioLocalTimeInformation(TransactionBuilder builder) - { + private void writeCasioLocalTimeInformation(TransactionBuilder builder) { Calendar cal = Calendar.getInstance(); int zoneOffset = (int)TimeUnit.MILLISECONDS.toMinutes(cal.get(Calendar.ZONE_OFFSET)); int dstOffset = (int)TimeUnit.MILLISECONDS.toMinutes(cal.get(Calendar.DST_OFFSET)); @@ -152,8 +150,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { } - private void writeCasioVirtualServerFeature(TransactionBuilder builder) - { + private void writeCasioVirtualServerFeature(TransactionBuilder builder) { byte byte0 = (byte)0; byte0 |= 1; // Casio Current Time Service byte0 |= 2; // Casio Alert Notification Service @@ -169,59 +166,87 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { } } - private boolean handleCasioCom(byte[] data) - { + private boolean handleInitResponse(byte data) { boolean handled = false; - switch(data[0]) // ServiceID - actually an int + switch(data) { - case 0: - switch(data[2]) - { - case (byte) 1: - LOG.info("Initialization done, setting state to INITIALIZED"); - gbDevice.setState(GBDevice.State.INITIALIZED); - gbDevice.sendDeviceUpdateIntent(getContext()); - break; - } + case (byte) 1: + LOG.info("Initialization done, setting state to INITIALIZED"); + gbDevice.setState(GBDevice.State.INITIALIZED); + gbDevice.sendDeviceUpdateIntent(getContext()); + handled = true; break; - case 2: - switch(data[2]) // Request Type - { - case (byte) 1: - try - { - TransactionBuilder builder = createTransactionBuilder("writeCasioCurrentTime"); - writeCasioCurrentTime(builder); - performImmediately(builder); - handled = true; - } catch (IOException e) { - LOG.warn(e.getMessage()); - } - break; - case (byte) 2: - try - { - TransactionBuilder builder = createTransactionBuilder("writeCasioLocalTimeInformation"); - writeCasioLocalTimeInformation(builder); - performImmediately(builder); - handled = true; - } catch (IOException e) { - LOG.warn(e.getMessage()); - } - break; - } + default: + LOG.warn("handleInitResponse: Error initializing device, received unexpected value: " + data); + gbDevice.setState(GBDevice.State.NOT_CONNECTED); + gbDevice.sendDeviceUpdateIntent(getContext()); + handled = true; break; - case 7: + } + return handled; + } + + private boolean handleTimeRequests(byte data) { + boolean handled = false; + switch(data) // Request Type + { + case (byte) 1: try { - TransactionBuilder builder = createTransactionBuilder("writeCasioVirtualServerFeature"); - writeCasioVirtualServerFeature(builder); + TransactionBuilder builder = createTransactionBuilder("writeCasioCurrentTime"); + writeCasioCurrentTime(builder); performImmediately(builder); handled = true; } catch (IOException e) { - LOG.warn(e.getMessage()); + LOG.warn("handleTimeRequests::writeCasioCurrentTime failed: " + e.getMessage()); } break; + case (byte) 2: + try + { + TransactionBuilder builder = createTransactionBuilder("writeCasioLocalTimeInformation"); + writeCasioLocalTimeInformation(builder); + performImmediately(builder); + handled = true; + } catch (IOException e) { + LOG.warn("handleTimeRequests::writeCasioLocalTimeInformation failed: " + e.getMessage()); + } + break; + } + return handled; + } + + private boolean handleServerFeatureRequests(byte data) { + try + { + TransactionBuilder builder = createTransactionBuilder("writeCasioVirtualServerFeature"); + writeCasioVirtualServerFeature(builder); + performImmediately(builder); + } catch (IOException e) { + LOG.warn("handleServerFeatureRequests failed: " + e.getMessage()); + } + return true; + } + + private boolean handleCasioCom(byte[] data) { + boolean handled = false; + + if(data.length < 3) { + LOG.warn("handleCasioCom failed: Received unexpected request (too short)"); + return false; + } + + switch(data[0]) // ServiceID + { + case 0: + handled = handleInitResponse(data[2]); + break; + case 2: + handled = handleTimeRequests(data[2]); + break; + case 7: + handled = handleServerFeatureRequests(data[2]); + break; } return handled; } @@ -240,32 +265,27 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { if (data.length == 0) return true; - if(characteristicUUID.equals(CasioGB6900Constants.CASIO_A_NOT_W_REQ_NOT)) - { + if(characteristicUUID.equals(CasioGB6900Constants.CASIO_A_NOT_W_REQ_NOT)) { handled = handleCasioCom(data); } - if(characteristicUUID.equals(CasioGB6900Constants.CASIO_A_NOT_COM_SET_NOT)) - { + if(characteristicUUID.equals(CasioGB6900Constants.CASIO_A_NOT_COM_SET_NOT)) { handled = handleCasioCom(data); } - if(characteristicUUID.equals(CasioGB6900Constants.ALERT_LEVEL_CHARACTERISTIC_UUID)) - { + if(characteristicUUID.equals(CasioGB6900Constants.ALERT_LEVEL_CHARACTERISTIC_UUID)) { GBDeviceEventFindPhone findPhoneEvent = new GBDeviceEventFindPhone(); if(data[0] == 0x02) { findPhoneEvent.event = GBDeviceEventFindPhone.Event.START; } - else - { + else { findPhoneEvent.event = GBDeviceEventFindPhone.Event.STOP; } evaluateGBDeviceEvent(findPhoneEvent); handled = true; } - if(characteristicUUID.equals(CasioGB6900Constants.RINGER_CONTROL_POINT)) - { + if(characteristicUUID.equals(CasioGB6900Constants.RINGER_CONTROL_POINT)) { if(data[0] == 0x02) { LOG.info("Mute/ignore call event not yet supported by GB"); @@ -273,8 +293,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { handled = true; } - if(!handled) - { + if(!handled) { LOG.info("Unhandled characteristic change: " + characteristicUUID + " code: " + String.format("0x%1x ...", data[0])); } return true; @@ -299,7 +318,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { LOG.info("Showing notification, title: " + title + " message (not sent): " + message); performConnected(builder.getTransaction()); } catch (IOException e) { - LOG.warn(e.getMessage()); + LOG.warn("showNotification failed: " + e.getMessage()); } } @@ -347,7 +366,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { writeCasioCurrentTime(builder); performConnected(builder.getTransaction()); } catch(IOException e) { - LOG.warn(e.getMessage()); + LOG.warn("onSetTime failed: " + e.getMessage()); } } @@ -357,6 +376,9 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { case CallSpec.CALL_INCOMING: showNotification(CasioGB6900Constants.CALL_NOTIFICATION_ID, callSpec.name, callSpec.number); break; + default: + LOG.info("not sending CallSpec since only CALL_INCOMING is handled"); + break; } } @@ -367,7 +389,6 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { @Override public void onSetMusicState(MusicStateSpec stateSpec) { - LOG.info("onSetMusicState"); if(stateSpec != mBufferMusicStateSpec) { mBufferMusicStateSpec = stateSpec; @@ -402,13 +423,12 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { builder.write(getCharacteristic(CasioGB6900Constants.MORE_ALERT_FOR_LONG_UUID), arr); performConnected(builder.getTransaction()); } catch (IOException e) { - LOG.warn(e.getMessage()); + LOG.warn("sendMusicInfo failed: " + e.getMessage()); } } @Override public void onSetMusicInfo(MusicSpec musicSpec) { - LOG.info("onSetMusicInfo"); if(musicSpec != mBufferMusicSpec) { mBufferMusicSpec = musicSpec; @@ -457,11 +477,7 @@ public class CasioGB6900DeviceSupport extends AbstractBTLEDeviceSupport { @Override public void onReset(int flags) { - try { - } catch(Exception e) { - LOG.warn(e.getMessage()); - } } @Override