diff --git a/examples/example-android/androidBleSdkTestApp/app/src/main/java/polar/com/androidblesdk/MainActivity.java b/examples/example-android/androidBleSdkTestApp/app/src/main/java/polar/com/androidblesdk/MainActivity.java index 3c718cac..1ff6df4c 100644 --- a/examples/example-android/androidBleSdkTestApp/app/src/main/java/polar/com/androidblesdk/MainActivity.java +++ b/examples/example-android/androidBleSdkTestApp/app/src/main/java/polar/com/androidblesdk/MainActivity.java @@ -272,12 +272,7 @@ public void polarFtpFeatureReady(@NonNull String s) { ppg.setOnClickListener(v -> { if(ppgDisposable == null) { - ppgDisposable = api.requestPpgSettings(DEVICE_ID).toFlowable().flatMap(new Function>() { - @Override - public Publisher apply(PolarSensorSetting polarPPGSettings) throws Exception { - return api.startOhrPPGStreaming(DEVICE_ID,polarPPGSettings.maxSettings()); - } - }).subscribe( + ppgDisposable = api.requestPpgSettings(DEVICE_ID).toFlowable().flatMap((Function>) polarPPGSettings -> api.startOhrPPGStreaming(DEVICE_ID,polarPPGSettings.maxSettings())).subscribe( polarOhrPPGData -> { for( PolarOhrPPGData.PolarOhrPPGSample data : polarOhrPPGData.samples ){ Log.d(TAG," ppg0: " + data.ppg0 + " ppg1: " + data.ppg1 + " ppg2: " + data.ppg2 + "ambient: " + data.ambient); diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/advertisement/BleAdvertisementContent.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/advertisement/BleAdvertisementContent.java index 28208b70..d98b7961 100644 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/advertisement/BleAdvertisementContent.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/advertisement/BleAdvertisementContent.java @@ -7,10 +7,11 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; +import java.util.Objects; public class BleAdvertisementContent { - private HashMap advertisementData = new HashMap<>(); // current - private HashMap advertisementDataAll = new HashMap<>(); // current + "history" + private HashMap advertisementData = new HashMap<>(); // current + private HashMap advertisementDataAll = new HashMap<>(); // current + "history" private String name = ""; private String polarDeviceType = ""; private long polarDeviceIdInt = 0; @@ -24,9 +25,9 @@ public class BleAdvertisementContent { private int medianRssi = -100; private int rssi = -100; - public void processAdvertisementData( HashMap advData, - BleUtils.EVENT_TYPE advertisementEventType, - int rssi ) { + public void processAdvertisementData(HashMap advData, + BleUtils.EVENT_TYPE advertisementEventType, + int rssi) { // start access of atomic section this.advertisementData.clear(); this.advertisementData.putAll(advData); @@ -34,36 +35,38 @@ public void processAdvertisementData( HashMap advData, this.advertisementEventType = advertisementEventType; this.advertisetTimeStamp = System.currentTimeMillis() / 1000L; if (advertisementData.containsKey(BleUtils.AD_TYPE.GAP_ADTYPE_LOCAL_NAME_COMPLETE)) { - String name = new String(advertisementData.get(BleUtils.AD_TYPE.GAP_ADTYPE_LOCAL_NAME_COMPLETE)); + String name = new String(Objects.requireNonNull(advertisementData.get(BleUtils.AD_TYPE.GAP_ADTYPE_LOCAL_NAME_COMPLETE))); processName(name); } else if (advertisementData.containsKey(BleUtils.AD_TYPE.GAP_ADTYPE_LOCAL_NAME_SHORT)) { - String name = new String(advertisementData.get(BleUtils.AD_TYPE.GAP_ADTYPE_LOCAL_NAME_SHORT)); + String name = new String(Objects.requireNonNull(advertisementData.get(BleUtils.AD_TYPE.GAP_ADTYPE_LOCAL_NAME_SHORT))); processName(name); } // manufacturer data if (advertisementData.containsKey(BleUtils.AD_TYPE.GAP_ADTYPE_MANUFACTURER_SPECIFIC)) { byte[] content = advertisementData.get(BleUtils.AD_TYPE.GAP_ADTYPE_MANUFACTURER_SPECIFIC); - if ( content.length > 3 && content[0] == 0x6B && content[1] == 0x00) { - int offset=2; - while (offset < content.length){ + if (Objects.requireNonNull(content).length > 3 && content[0] == 0x6B && content[1] == 0x00) { + int offset = 2; + while (offset < content.length) { int gpbDataBit = (content[offset] & 0x40); - switch (gpbDataBit){ - case 0:{ - if ( (offset+3) <= content.length ) { - byte[] subset = Arrays.copyOfRange(content,offset - 2, content.length ); + switch (gpbDataBit) { + case 0: { + if ((offset + 3) <= content.length) { + byte[] subset = Arrays.copyOfRange(content, offset - 2, content.length); polarHrAdvertisement.processPolarManufacturerData(subset); } offset += 5; break; } - case 0x40:{ + case 0x40: { // gpb data, no handling for now offset += 1; - if( offset < content.length ) offset += (content[offset] & 0x000000FF) + 1; + if (offset < content.length) + offset += (content[offset] & 0x000000FF) + 1; else offset = content.length; break; } - default: offset = content.length; + default: + offset = content.length; } } } @@ -91,14 +94,14 @@ private void processName(final String name) { String[] names = this.name.split(" "); if (names.length > 2) { polarDeviceType = names[1]; - polarDeviceId = names[names.length-1]; - if( polarDeviceId.length() == 7 ){ - polarDeviceId = BlePolarDeviceIdUtility.assemblyFullPolarDeviceId(names[names.length-1]); + polarDeviceId = names[names.length - 1]; + if (polarDeviceId.length() == 7) { + polarDeviceId = BlePolarDeviceIdUtility.assemblyFullPolarDeviceId(names[names.length - 1]); this.name = "Polar " + polarDeviceType + " " + polarDeviceId; } try { polarDeviceIdInt = Long.parseLong(polarDeviceId, 16); - } catch(NumberFormatException ex){ + } catch (NumberFormatException ex) { // ignore polarDeviceIdInt = 0; } @@ -111,13 +114,14 @@ private void processName(final String name) { } } - public void resetAdvertisementData(){ + public void resetAdvertisementData() { advertisementData.clear(); advertisementDataAll.clear(); } /** * Get the Device ID contain in GAP local name for Polar Devices. + * * @return String that for "Polar H7 20346EAB" will contain "20346EAB" */ public String getPolarDeviceId() { @@ -126,6 +130,7 @@ public String getPolarDeviceId() { /** * Get the Device type contain in GAP local name for Polar Devices. + * * @return String that for "Polar H7 20346EAB" will contain "H7" */ public String getPolarDeviceType() { @@ -201,22 +206,22 @@ public BleUtils.EVENT_TYPE getAdvertisementEventType() { public boolean isNonConnectableAdvertisement() { return polarDeviceId.length() != 0 && !(advertisementData.containsKey(BleUtils.AD_TYPE.GAP_ADTYPE_16BIT_MORE) || - advertisementData.containsKey(BleUtils.AD_TYPE.GAP_ADTYPE_16BIT_COMPLETE)); + advertisementData.containsKey(BleUtils.AD_TYPE.GAP_ADTYPE_16BIT_COMPLETE)); } /** * @param service in hex string format like "180D" * @return true if found */ - public boolean containsService(final String service){ + public boolean containsService(final String service) { if (advertisementData.containsKey(BleUtils.AD_TYPE.GAP_ADTYPE_16BIT_MORE) || - advertisementData.containsKey(BleUtils.AD_TYPE.GAP_ADTYPE_16BIT_COMPLETE)) { + advertisementData.containsKey(BleUtils.AD_TYPE.GAP_ADTYPE_16BIT_COMPLETE)) { byte[] uuids = advertisementData.containsKey(BleUtils.AD_TYPE.GAP_ADTYPE_16BIT_MORE) ? advertisementData.get(BleUtils.AD_TYPE.GAP_ADTYPE_16BIT_MORE) : advertisementData.get(BleUtils.AD_TYPE.GAP_ADTYPE_16BIT_COMPLETE); - for(int i=0; i < uuids.length; i += 2){ - String hexUUid = String.format("%02X%02X",uuids[i+1],uuids[i]); - if( hexUUid.equals(service) ){ + for (int i = 0; i < Objects.requireNonNull(uuids).length; i += 2) { + String hexUUid = String.format("%02X%02X", uuids[i + 1], uuids[i]); + if (hexUUid.equals(service)) { return true; } } diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/advertisement/BlePolarHrAdvertisement.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/advertisement/BlePolarHrAdvertisement.java index 76a81238..eaa7ab42 100644 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/advertisement/BlePolarHrAdvertisement.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/advertisement/BlePolarHrAdvertisement.java @@ -1,7 +1,7 @@ package com.androidcommunications.polar.api.ble.model.advertisement; public class BlePolarHrAdvertisement { - + private int batteryStatus; private int sensorContact; private int ucAdvFrameCounter; @@ -13,7 +13,7 @@ public class BlePolarHrAdvertisement { private int slowAverageHr; private byte[] currentData; - public void processPolarManufacturerData(byte[] data){ + void processPolarManufacturerData(byte[] data) { currentData = data; batteryStatus = data[2] & 0x01; sensorContact = (data[2] & 0x02) >> 1; @@ -23,14 +23,14 @@ public void processPolarManufacturerData(byte[] data){ statusFlags = (data[2] & 0x80) >> 7; khzCode = data[3]; fastAverageHr = (data[4] & 0x000000FF); - if( data.length == 6 ){ + if (data.length == 6) { slowAverageHr = (data[5] & 0x000000FF); } else { slowAverageHr = (data[4] & 0x000000FF); } } - public boolean isPresent(){ + public boolean isPresent() { return currentData != null; } @@ -74,11 +74,11 @@ public int getHrForDisplay() { return slowAverageHr; } - public boolean isOldH7H6(){ + public boolean isOldH7H6() { return currentData.length == 5; } - public boolean isH7Update(){ + public boolean isH7Update() { return !isOldH7H6(); } } diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/BleGattBase.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/BleGattBase.java index b015886f..e823fb74 100755 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/BleGattBase.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/BleGattBase.java @@ -148,7 +148,6 @@ public void reset(){ public abstract void processServiceData(UUID characteristic, byte[] data, int status, boolean notifying); public abstract void processServiceDataWritten(UUID characteristic, int status); - public abstract String toString(); public Completable clientReady(boolean checkConnection) { // override in client if required @@ -327,28 +326,25 @@ public void setIsPrimaryService(boolean isPrimaryService) { * @return Observable stream, only complete or error is produced */ public Completable waitServiceDiscovered(final boolean checkConnection){ - return Completable.create(new CompletableOnSubscribe() { - @Override - public void subscribe(CompletableEmitter emitter) { - try { - if (!checkConnection || txInterface.isConnected()) { - synchronized (serviceDiscovered) { - if (serviceDiscovered.get()) { - emitter.onComplete(); - return; - } - serviceDiscovered.wait(); - if (txInterface.isConnected() && serviceDiscovered.get()) { - emitter.onComplete(); - return; - } + return Completable.create(emitter -> { + try { + if (!checkConnection || txInterface.isConnected()) { + synchronized (serviceDiscovered) { + if (serviceDiscovered.get()) { + emitter.onComplete(); + return; + } + serviceDiscovered.wait(); + if (txInterface.isConnected() && serviceDiscovered.get()) { + emitter.onComplete(); + return; } } - throw new BleDisconnected(); - } catch (Exception ex){ - if(!emitter.isDisposed()){ - emitter.tryOnError(ex); - } + } + throw new BleDisconnected(); + } catch (Exception ex){ + if(!emitter.isDisposed()){ + emitter.tryOnError(ex); } } }).subscribeOn(Schedulers.io()); @@ -363,43 +359,40 @@ public void subscribe(CompletableEmitter emitter) { */ public Completable waitNotificationEnabled(final UUID uuid, final boolean checkConnection, final Scheduler scheduler) { final AtomicInteger integer = getNotificationAtomicInteger(uuid); - return Completable.create(new CompletableOnSubscribe() { - @Override - public void subscribe(CompletableEmitter emitter) { - try { - if (!checkConnection || txInterface.isConnected()) { - if (integer != null) { + return Completable.create(emitter -> { + try { + if (!checkConnection || txInterface.isConnected()) { + if (integer != null) { + if (integer.get() == ATT_SUCCESS) { + emitter.onComplete(); + return; + } + synchronized (integer) { if (integer.get() == ATT_SUCCESS) { emitter.onComplete(); return; + } else if (integer.get() != -1) { + throw new BleAttributeError("Failed to set characteristic notification or indication ", integer.get()); } - synchronized (integer) { - if (integer.get() == ATT_SUCCESS) { - emitter.onComplete(); - return; - } else if (integer.get() != -1) { + integer.wait(); + if (integer.get() != ATT_SUCCESS && !emitter.isDisposed()) { + if (integer.get() != -1) { throw new BleAttributeError("Failed to set characteristic notification or indication ", integer.get()); + } else { + throw new BleDisconnected(); } - integer.wait(); - if (integer.get() != ATT_SUCCESS && !emitter.isDisposed()) { - if (integer.get() != -1) { - throw new BleAttributeError("Failed to set characteristic notification or indication ", integer.get()); - } else { - throw new BleDisconnected(); - } - } - emitter.onComplete(); } - } else { - throw new BleCharacteristicNotFound(); + emitter.onComplete(); } } else { - throw new BleDisconnected(); - } - } catch (Exception ex){ - if(!emitter.isDisposed()){ - emitter.tryOnError(ex); + throw new BleCharacteristicNotFound(); } + } else { + throw new BleDisconnected(); + } + } catch (Exception ex){ + if(!emitter.isDisposed()){ + emitter.tryOnError(ex); } } }).subscribeOn(scheduler); diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleBattClient.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleBattClient.java index ed795aee..218a56bc 100644 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleBattClient.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleBattClient.java @@ -1,5 +1,7 @@ package com.androidcommunications.polar.api.ble.model.gatt.client; +import android.support.annotation.NonNull; + import com.androidcommunications.polar.api.ble.exceptions.BleDisconnected; import com.androidcommunications.polar.api.ble.model.gatt.BleGattBase; import com.androidcommunications.polar.api.ble.model.gatt.BleGattTxInterface; @@ -57,7 +59,7 @@ public void processServiceDataWritten(UUID characteristic, int status) { } @Override - public String toString() { + public @NonNull String toString() { return "Battery service"; } @@ -86,8 +88,8 @@ public Single waitBatteryLevelUpdate(final boolean checkConnection){ /** * monitor battery notifications - * @param checkConnection - * @return + * @param checkConnection false = no is connected check before observer added, true = check's is connected
+ * @return Observable */ public Flowable monitorBatteryLevelUpdate(final boolean checkConnection) { final FlowableEmitter[] observer = new FlowableEmitter[1]; diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleDisClient.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleDisClient.java index d0244973..6fb1604c 100644 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleDisClient.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleDisClient.java @@ -1,5 +1,6 @@ package com.androidcommunications.polar.api.ble.model.gatt.client; +import android.support.annotation.NonNull; import android.util.Pair; import com.androidcommunications.polar.api.ble.exceptions.BleAttributeError; @@ -84,7 +85,7 @@ public void processServiceDataWritten(UUID characteristic, int status) { } @Override - public String toString() { + public @NonNull String toString() { return "Device info service"; } diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleGapClient.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleGapClient.java index b067df17..eba0b215 100644 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleGapClient.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleGapClient.java @@ -1,5 +1,7 @@ package com.androidcommunications.polar.api.ble.model.gatt.client; +import android.support.annotation.NonNull; + import com.androidcommunications.polar.api.ble.exceptions.BleDisconnected; import com.androidcommunications.polar.api.ble.model.gatt.BleGattBase; import com.androidcommunications.polar.api.ble.model.gatt.BleGattTxInterface; @@ -64,7 +66,7 @@ public void processServiceDataWritten(UUID characteristic, int status) { } @Override - public String toString() { + public @NonNull String toString() { return "GAP service with values device name: "; } diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleH7SettingsClient.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleH7SettingsClient.java index d944b626..b6111f11 100644 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleH7SettingsClient.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleH7SettingsClient.java @@ -1,5 +1,7 @@ package com.androidcommunications.polar.api.ble.model.gatt.client; +import android.support.annotation.NonNull; + import com.androidcommunications.polar.api.ble.exceptions.BleCharacteristicNotFound; import com.androidcommunications.polar.api.ble.exceptions.BleDisconnected; import com.androidcommunications.polar.api.ble.exceptions.BleNotSupported; @@ -113,7 +115,7 @@ public void processServiceDataWritten(UUID characteristic, int status) { } @Override - public String toString() { + public @NonNull String toString() { return "Legacy H7 settings client"; } diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleHrClient.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleHrClient.java index d679602e..16766dd2 100755 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleHrClient.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleHrClient.java @@ -1,5 +1,7 @@ package com.androidcommunications.polar.api.ble.model.gatt.client; +import android.support.annotation.NonNull; + import com.androidcommunications.polar.api.ble.model.gatt.BleGattBase; import com.androidcommunications.polar.api.ble.model.gatt.BleGattTxInterface; import com.androidcommunications.polar.common.ble.AtomicSet; @@ -99,7 +101,7 @@ public void processServiceDataWritten(UUID characteristic, int status) { } @Override - public String toString() { + public @NonNull String toString() { // and so on return "HR gatt client"; } diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePMDClient.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePMDClient.java index 3bab33eb..9e3860f9 100644 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePMDClient.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePMDClient.java @@ -1,5 +1,6 @@ package com.androidcommunications.polar.api.ble.model.gatt.client; +import android.support.annotation.NonNull; import android.util.Pair; import com.androidcommunications.polar.api.ble.BleLogger; @@ -657,7 +658,7 @@ public void processServiceDataWritten(UUID characteristic, int status) { } @Override - public String toString() { + public @NonNull String toString() { return "PMD Client"; } diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePabClient.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePabClient.java deleted file mode 100644 index 0e3b8756..00000000 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePabClient.java +++ /dev/null @@ -1,313 +0,0 @@ -package com.androidcommunications.polar.api.ble.model.gatt.client; - -import android.util.Pair; - -import com.androidcommunications.polar.api.ble.exceptions.BleCharacteristicNotificationNotEnabled; -import com.androidcommunications.polar.api.ble.exceptions.BleDisconnected; -import com.androidcommunications.polar.api.ble.model.gatt.BleGattBase; -import com.androidcommunications.polar.api.ble.model.gatt.BleGattTxInterface; -import com.androidcommunications.polar.common.ble.AtomicSet; -import com.androidcommunications.polar.common.ble.RxUtils; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.UUID; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -import io.reactivex.BackpressureStrategy; -import io.reactivex.Completable; -import io.reactivex.Flowable; -import io.reactivex.FlowableEmitter; -import io.reactivex.FlowableOnSubscribe; -import io.reactivex.Scheduler; -import io.reactivex.Single; -import io.reactivex.SingleEmitter; -import io.reactivex.SingleOnSubscribe; -import io.reactivex.annotations.NonNull; -import io.reactivex.functions.Action; -import io.reactivex.schedulers.Schedulers; - -public class BlePabClient extends BleGattBase { - - public static final byte SUCCESS = 0x01; - public static final byte OP_CODE_NOT_SUPPORTED = 0x02; - public static final byte INVALID_PARAMETER = 0x03; - public static final byte OPERATION_FAILED = 0x04; - public static final byte NOT_ALLOWED = 0x05; - - - public final static UUID PAB_SERVICE = UUID.fromString("FB00AA20-02E7-F387-1CAD-8ACD2D8DF0C8"); - public final static UUID PAB_FEATURE = UUID.fromString("FB00AA21-02E7-F387-1CAD-8ACD2D8DF0C8"); - public final static UUID PAB_CP = UUID.fromString("FB00AA22-02E7-F387-1CAD-8ACD2D8DF0C8"); - public final static UUID PAB_STATUS = UUID.fromString("FB00AA23-02E7-F387-1CAD-8ACD2D8DF0C8"); - - public static final byte RESPONSE_CODE = (byte)0xF0; - - private final Object pabMutex = new Object(); - private final Object mutexFeature = new Object(); - private PabFeature pabFeature = null; - private AtomicInteger pabCpEnabled; - private LinkedBlockingQueue > CpInputQueue = new LinkedBlockingQueue<>(); - private Scheduler scheduler = Schedulers.newThread(); - private final AtomicSet> statusObservers = new AtomicSet<>(); - - public enum Message{ - PAB_UNKNOWN(0), - PAB_START_SCAN(1), - PAB_STOP_SCAN(2), - PAB_DISPLAY_SENSOR(3), - PAB_REMOVE_SENSOR(4), - PAB_PAIR_SENSOR(5), - PAB_CLEAR_PAIRING(6); - private int numVal; - - Message(int numVal) { - this.numVal = numVal; - } - - public int getNumVal() { - return numVal; - } - }; - - - - public static class PabStatus{ - public static final int PAB_STATUS_UNKNOWN = 0; - public static final int PAB_STATUS_SCAN_RESULT = 1; - public static final int PAB_STATUS_SENSOR_CONNECTED =2; - public static final int PAB_STATUS_SENSOR_DISCONNECTED = 3; - public static final int PAB_STATUS_SENSOR_PAIRED = 4; - public static final int PAB_STATUS_HR_VALUE = 5; - public static final int PAB_STATUS_TORQUE_DATA = 6; - public static final int PAB_STATUS_POWER_DATA = 7; - public static final int PAB_STATUS_INFORMATIVE_EVENT = 100; - private int status_type; - - private byte[] payload; - - public PabStatus(byte[] data) { - if( data.length >= 1 ) { - status_type = (int)data[0]; - if(data.length > 1) - payload = new byte[data.length - 1]; - System.arraycopy(data, 1, payload, 0, data.length - 1); - } else { - status_type = PAB_STATUS_UNKNOWN; - payload = new byte[0]; - } - } - - public int getStatus_type() { - return status_type; - } - - public byte[] getPayload() { - return payload; - } - } - - public static class Response{ - private byte responseCode; - private Message opCode; - private byte status; - - public Response(byte[] data) { - if( data.length > 2 ) { - responseCode = data[0]; - opCode = Message.values()[data[1]]; - status = data[2]; - } else { - opCode = Message.PAB_UNKNOWN; - responseCode = 0; - status = 0; - } - } - - public byte getResponseCode() { - return responseCode; - } - - public Message getOpCode() { - return opCode; - } - - public byte getStatus() { - return status; - } - - @Override - public String toString(){ - return "Response code: " + String.format("%02x", responseCode) + - " op code: " + opCode + - " status: " + String.format("%02x", status); - } - } - - public static class PabFeature{ - // feature boolean's - public boolean hrm_supported = false; - - - - public PabFeature(byte[] data){ - hrm_supported = (data[0] & 0x01) == 1; - // = ((data[0] & 0x02) >> 1) == 1; - //accSupported = ((data[0] & 0x04) >> 2) == 1; - //ppSupported = ((data[0] & 0x08) != 0); - } - } - - public BlePabClient(BleGattTxInterface txInterface) { - super(txInterface, PAB_SERVICE); - addCharacteristicRead(PAB_FEATURE); - addCharacteristicNotification(PAB_CP); - addCharacteristicNotification(PAB_STATUS); - pabCpEnabled = getNotificationAtomicInteger(PAB_CP); - } - - @Override - public void reset() { - super.reset(); - CpInputQueue.clear(); - - synchronized (mutexFeature) { - pabFeature = null; - mutexFeature.notifyAll(); - } - RxUtils.postDisconnectedAndClearList(statusObservers); - } - - @Override - public void processServiceData(UUID characteristic, final byte[] data, int status, boolean notifying) { - if(status==0){ - if(characteristic.equals(PAB_CP)){ - CpInputQueue.add(new Pair(data,status)); - }else if(characteristic.equals(PAB_FEATURE)){ - synchronized (mutexFeature) { - pabFeature = new PabFeature(data); - mutexFeature.notifyAll(); - } - }else if(characteristic.equals(PAB_STATUS)){ - RxUtils.emitNext(statusObservers, new RxUtils.Emitter>() { - @Override - public void item(FlowableEmitter object) { - object.onNext(new PabStatus(data)); - } - }); - } - } - } - - @Override - public void processServiceDataWritten(UUID characteristic, int status) { - // add some implementation later if needed - } - - @Override - public String toString() { - synchronized (pabFeature) { - if (pabFeature != null) { - return "PAB service with values hrm supported: " + String.valueOf(pabFeature.hrm_supported); - } else { - return "PAB service"; - } - } - } - - private void sendPabCommandAndProcessResponse(SingleEmitter subscriber, byte[] packet){ - try { - txInterface.transmitMessages(BlePabClient.this,PAB_SERVICE,PAB_CP, Arrays.asList(packet),true); - Pair pair = null; - pair = CpInputQueue.poll(3, TimeUnit.SECONDS); - if(!subscriber.isDisposed()) { - if (pair != null && pair.second == 0) { - Response response = new Response(pair.first); - subscriber.onSuccess(response); - } else if(!subscriber.isDisposed()){ - subscriber.tryOnError(new Throwable("Pab response failed in receive in timeline")); - } - } - } catch (Throwable throwable) { - if(!subscriber.isDisposed()) { - subscriber.tryOnError(throwable); - } - } - } - - @Override - public Completable clientReady(boolean checkConnection) { - return waitNotificationEnabled(PAB_CP,checkConnection); - } - - /** - * Produces: onNext: when response message from device has been received - * onError: if reponse read fails e.g. timeout etc... - * onCompleted: produced after onNext - * @param command - * @param params - * @return Observable stream, @see Rx Observer - */ - public Single sendControlPointCommand(final Message command, final byte[] params) { - return Single.create(new SingleOnSubscribe() { - @Override - public void subscribe(SingleEmitter subscriber) throws Exception { - // force pab operation to be 'atomic' - synchronized (pabMutex) { - if (pabCpEnabled.get() == ATT_SUCCESS) { - CpInputQueue.clear(); - ByteBuffer bb = ByteBuffer.allocate(1 + params.length); - bb.put(new byte[]{(byte)command.getNumVal()}); - bb.put(params); - sendPabCommandAndProcessResponse(subscriber, bb.array()); - }else if(!subscriber.isDisposed()){ - subscriber.tryOnError(new BleCharacteristicNotificationNotEnabled("PAB control point not enabled")); - } - } - } - }).subscribeOn(scheduler); - } - - public Single readFeature(){ - return Single.create(new SingleOnSubscribe() { - @Override - public void subscribe(SingleEmitter subscriber) throws Exception { - try { - synchronized (mutexFeature) { - if( pabFeature == null ) { - mutexFeature.wait(); - } - } - } catch (InterruptedException e) { - if(!subscriber.isDisposed()) { - subscriber.tryOnError(e.getCause()); - } - return; - } - if( pabFeature != null ) { - subscriber.onSuccess(pabFeature); - } else if(!subscriber.isDisposed()) { - subscriber.tryOnError(new BleDisconnected()); - } - } - }).subscribeOn(Schedulers.newThread()); - } - - public Flowable monitorStatusNotifications(){ - final FlowableEmitter[] listener = new FlowableEmitter[1]; - return Flowable.create(new FlowableOnSubscribe() { - @Override - public void subscribe(@NonNull FlowableEmitter subscriber) throws Exception { - listener[0] = subscriber; - statusObservers.add(subscriber); - } - },BackpressureStrategy.BUFFER).doFinally(new Action() { - @Override - public void run() throws Exception { - statusObservers.remove(listener[0]); - } - }).serialize(); - } -} diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePfcClient.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePfcClient.java index 4a0d3c72..d15e398b 100644 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePfcClient.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePfcClient.java @@ -1,5 +1,6 @@ package com.androidcommunications.polar.api.ble.model.gatt.client; +import android.support.annotation.NonNull; import android.util.Pair; import com.androidcommunications.polar.api.ble.exceptions.BleAttributeError; @@ -191,7 +192,7 @@ public void processServiceDataWritten(UUID characteristic, int status) { } @Override - public String toString() { + public @NonNull String toString() { return "PFC service with values broadcast supported: " + String.valueOf(pfcFeature.broadcastSupported) + " 5khz supported: " + String.valueOf(pfcFeature.khzSupported); } diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePsdClient.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePsdClient.java index 24bc53b0..8aaf619d 100644 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePsdClient.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BlePsdClient.java @@ -1,5 +1,6 @@ package com.androidcommunications.polar.api.ble.model.gatt.client; +import android.support.annotation.NonNull; import android.util.Pair; import com.androidcommunications.polar.api.ble.exceptions.BleAttributeError; @@ -268,7 +269,7 @@ public void processServiceDataWritten(UUID characteristic, int status) { } @Override - public String toString() { + public @NonNull String toString() { return "psd client"; } diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleRscClient.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleRscClient.java index 89ffb1f7..e1a71d44 100644 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleRscClient.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/BleRscClient.java @@ -1,5 +1,7 @@ package com.androidcommunications.polar.api.ble.model.gatt.client; +import android.support.annotation.NonNull; + import com.androidcommunications.polar.api.ble.BleLogger; import com.androidcommunications.polar.api.ble.model.gatt.BleGattBase; import com.androidcommunications.polar.api.ble.model.gatt.BleGattTxInterface; @@ -68,8 +70,8 @@ public void processServiceData(UUID characteristic, byte[] data, int status, boo final boolean TotalDistancePresent = (flags & 0x02) == 0x02; final boolean Running = (flags & 0x04) == 0x04; - final long Speed = (long)(data[index++] | (data[index++] << 8)); - final long Cadence = (long)data[index++]; + final long Speed = (data[index++] | (data[index++] << 8)); + final long Cadence = data[index++]; long StrideLength = 0; long TotalDistance = 0; @@ -78,7 +80,7 @@ public void processServiceData(UUID characteristic, byte[] data, int status, boo StrideLength = (data[index++] | (data[index++] << 8)); if(TotalDistancePresent) - TotalDistance = (long)(data[index++] | (data[index++] << 8) | data[index++] << 16 | data[index++] << 24); + TotalDistance = (data[index++] | (data[index++] << 8) | data[index++] << 16 | data[index] << 24); final long finalStrideLength = StrideLength; final long finalTotalDistance = TotalDistance; @@ -96,8 +98,7 @@ public void processServiceDataWritten(UUID characteristic, int status) { } @Override - public String toString() { - // and so on + public @NonNull String toString() { return "RSC service "; } diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/psftp/BlePsFtpClient.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/psftp/BlePsFtpClient.java index a057f5f0..4db1ad07 100644 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/psftp/BlePsFtpClient.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/api/ble/model/gatt/client/psftp/BlePsFtpClient.java @@ -1,5 +1,6 @@ package com.androidcommunications.polar.api.ble.model.gatt.client.psftp; +import android.support.annotation.NonNull; import android.util.Pair; import com.androidcommunications.polar.api.ble.BleLogger; @@ -171,7 +172,7 @@ public void processServiceDataWrittenWithResponse(UUID characteristic, int statu } @Override - public String toString() { + public @NonNull String toString() { return "RFC77 Service"; } diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/AttributeOperation.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/AttributeOperation.java index ac2ee26b..4bb4c36c 100644 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/AttributeOperation.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/AttributeOperation.java @@ -70,7 +70,7 @@ public byte[] getData() { return data; } - public BluetoothGattCharacteristic getCharacteristic() { + @NonNull public BluetoothGattCharacteristic getCharacteristic() { return characteristic; } diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/BDDeviceListenerImpl.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/BDDeviceListenerImpl.java index c80e8d11..3b167643 100755 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/BDDeviceListenerImpl.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/BDDeviceListenerImpl.java @@ -231,6 +231,11 @@ public void cancelDeviceConnection(BDDeviceSessionImpl session) { } } + @Override + public boolean isPowered() { + return bleActive(); + } + @Override public void connectionHandlerResumeScanning() { scanCallback.startScan(); @@ -318,7 +323,6 @@ public boolean isScanningNeeded() { return observers.size() != 0 || sessions.fetch(smartPolarDeviceSession1 -> smartPolarDeviceSession1.getSessionState() == BleDeviceSession.DeviceSessionState.SESSION_OPEN_PARK) != null; } - @Override public void setBlePowerStateCallback(@Nullable BlePowerStateChangedCallback cb) { this.powerStateChangedCallback = cb; diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/BDDeviceSessionImpl.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/BDDeviceSessionImpl.java index 99b8738a..52a53caf 100755 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/BDDeviceSessionImpl.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/BDDeviceSessionImpl.java @@ -63,11 +63,11 @@ public class BDDeviceSessionImpl extends BleDeviceSession implements BleGattTxIn @VisibleForTesting public BDDeviceSessionImpl(){} - public BDDeviceSessionImpl(Context context, - BluetoothDevice bluetoothDevice, - BDScanCallback scanCallback, - BDBondingListener bondingManager, - BleGattFactory factory) { + BDDeviceSessionImpl(Context context, + BluetoothDevice bluetoothDevice, + BDScanCallback scanCallback, + BDBondingListener bondingManager, + BleGattFactory factory) { super(); this.context = context; this.handler = new Handler(context.getMainLooper()); @@ -169,7 +169,6 @@ public Completable authenticate() { observer[0] = new BDBondingListener.BondingObserver(bluetoothDevice) { @Override public void bonding() { - //subscriber.onNext(new HashMap()); } @Override @@ -305,7 +304,6 @@ public int transportQueueSize() { } void handleDisconnection() { - // do nothing BleLogger.d(TAG, "disconnected"); advertisementContent.resetAdvertisementData(); attOperations.clear(); @@ -571,7 +569,11 @@ void handleDescriptorRead(BluetoothGattDescriptor descriptor, byte[] value, int processNextAttributeOperation(true); } - void handleDescriptorWrite(final BluetoothGattService service, final BluetoothGattCharacteristic characteristic, final BluetoothGattDescriptor descriptor, byte[] value, int status) { + void handleDescriptorWrite(final BluetoothGattService service, + final BluetoothGattCharacteristic characteristic, + final BluetoothGattDescriptor descriptor, + byte[] value, + int status) { BleLogger.d(TAG, "onDescriptorWrite uuid: " + characteristic.getUuid().toString() + " status: " + status); switch (status) { case BleGattBase.ATT_INSUFFICIENT_AUTHENTICATION: diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/connection/ConnectionHandler.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/connection/ConnectionHandler.java index b1cf8e8e..32f2b26c 100755 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/connection/ConnectionHandler.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/connection/ConnectionHandler.java @@ -204,10 +204,15 @@ private void free(final BDDeviceSessionImpl session, ConnectionHandlerAction act private void connecting(final BDDeviceSessionImpl session, ConnectionHandlerAction action) { switch (action) { case ENTRY: { - scannerInterface.connectionHandlerRequestStopScanning(); - current = session; - updateSessionState(session, BleDeviceSession.DeviceSessionState.SESSION_OPENING); - connectionInterface.connectDevice(session); + if (connectionInterface.isPowered()) { + scannerInterface.connectionHandlerRequestStopScanning(); + current = session; + updateSessionState(session, BleDeviceSession.DeviceSessionState.SESSION_OPENING); + connectionInterface.connectDevice(session); + } else { + BleLogger.w(TAG, "ble not powered exiting connecting state"); + changeState(session, ConnectionHandlerState.FREE); + } break; } case EXIT: { diff --git a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/connection/ConnectionInterface.java b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/connection/ConnectionInterface.java index cdf18435..6b2458e6 100755 --- a/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/connection/ConnectionInterface.java +++ b/sources/Android/android-communications/src/main/java/com/androidcommunications/polar/enpoints/ble/bluedroid/host/connection/ConnectionInterface.java @@ -6,4 +6,5 @@ public interface ConnectionInterface { void connectDevice(BDDeviceSessionImpl session); void disconnectDevice(BDDeviceSessionImpl session); void cancelDeviceConnection(BDDeviceSessionImpl session); + boolean isPowered(); } diff --git a/sources/Android/android-communications/src/main/java/polar/com/sdk/impl/BDBleApiImpl.java b/sources/Android/android-communications/src/main/java/polar/com/sdk/impl/BDBleApiImpl.java index 06831a96..8fe2de43 100644 --- a/sources/Android/android-communications/src/main/java/polar/com/sdk/impl/BDBleApiImpl.java +++ b/sources/Android/android-communications/src/main/java/polar/com/sdk/impl/BDBleApiImpl.java @@ -37,6 +37,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -308,7 +309,7 @@ public void connectToDevice(final String identifier) throws PolarInvalidArgument BleDeviceSession session = fetchSession(identifier); if (session == null || session.getSessionState() == SESSION_CLOSED) { if (connectSubscriptions.containsKey(identifier)) { - connectSubscriptions.get(identifier).dispose(); + Objects.requireNonNull(connectSubscriptions.get(identifier)).dispose(); connectSubscriptions.remove(identifier); } if (session != null) { @@ -336,7 +337,7 @@ public void disconnectFromDevice(String identifier) throws PolarInvalidArgument } } if (connectSubscriptions.containsKey(identifier)) { - connectSubscriptions.get(identifier).dispose(); + Objects.requireNonNull(connectSubscriptions.get(identifier)).dispose(); connectSubscriptions.remove(identifier); } } @@ -767,9 +768,7 @@ protected void setupDevice(final BleDeviceSession session) { } return Flowable.empty(); }).subscribe( - o -> { - - }, + o -> { }, throwable -> logError(throwable.getMessage()), () -> log("complete")); }