mirror of
https://github.com/aljazceru/Android-nRF-Toolbox.git
synced 2025-12-21 16:34:23 +01:00
CGMS refactored to use new BLE Common Library
This commit is contained in:
@@ -28,20 +28,22 @@ import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.bluetooth.BluetoothGattService;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.UUID;
|
||||
|
||||
import no.nordicsemi.android.ble.BleManager;
|
||||
import no.nordicsemi.android.ble.Request;
|
||||
import no.nordicsemi.android.ble.common.callback.RecordAccessControlPointDataCallback;
|
||||
import no.nordicsemi.android.ble.common.callback.cgm.CGMSpecificOpsControlPointDataCallback;
|
||||
import no.nordicsemi.android.ble.common.callback.cgm.ContinuousGlucoseMeasurementDataCallback;
|
||||
import no.nordicsemi.android.ble.common.data.RecordAccessControlPointData;
|
||||
import no.nordicsemi.android.ble.common.data.cgm.CGMSpecificOpsControlPointData;
|
||||
import no.nordicsemi.android.ble.data.Data;
|
||||
import no.nordicsemi.android.log.LogContract;
|
||||
import no.nordicsemi.android.nrftoolbox.battery.BatteryManager;
|
||||
import no.nordicsemi.android.nrftoolbox.parser.CGMMeasurementParser;
|
||||
import no.nordicsemi.android.nrftoolbox.parser.CGMSpecificOpsControlPointParser;
|
||||
import no.nordicsemi.android.nrftoolbox.parser.RecordAccessControlPointParser;
|
||||
import no.nordicsemi.android.nrftoolbox.utility.DebugLogger;
|
||||
|
||||
public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
||||
private static final String TAG = "CGMSManager";
|
||||
@@ -50,6 +52,7 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
||||
* Cycling Speed and Cadence service UUID
|
||||
*/
|
||||
public static final UUID CGMS_UUID = UUID.fromString("0000181F-0000-1000-8000-00805f9b34fb");
|
||||
private static final UUID CGM_FEAURE_UUID = UUID.fromString("00002AA8-0000-1000-8000-00805f9b34fb");
|
||||
private static final UUID CGM_MEASUREMENT_UUID = UUID.fromString("00002AA7-0000-1000-8000-00805f9b34fb");
|
||||
private static final UUID CGM_OPS_CONTROL_POINT_UUID = UUID.fromString("00002AAC-0000-1000-8000-00805f9b34fb");
|
||||
/**
|
||||
@@ -57,49 +60,15 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
||||
*/
|
||||
private static final UUID RACP_UUID = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb");
|
||||
|
||||
private static final int OP_CODE_REPORT_STORED_RECORDS = 1;
|
||||
private static final int OP_CODE_DELETE_STORED_RECORDS = 2;
|
||||
private static final int OP_CODE_ABORT_OPERATION = 3;
|
||||
private static final int OP_CODE_REPORT_NUMBER_OF_RECORDS = 4;
|
||||
private static final int OP_CODE_NUMBER_OF_STORED_RECORDS_RESPONSE = 5;
|
||||
private static final int OP_CODE_RESPONSE_CODE = 6;
|
||||
|
||||
private static final int OPERATOR_NULL = 0;
|
||||
private static final int OPERATOR_ALL_RECORDS = 1;
|
||||
private static final int OPERATOR_LESS_THEN_OR_EQUAL = 2;
|
||||
private static final int OPERATOR_GREATER_THEN_OR_EQUAL = 3;
|
||||
private static final int OPERATOR_WITHING_RANGE = 4;
|
||||
private static final int OPERATOR_FIRST_RECORD = 5;
|
||||
private static final int OPERATOR_LAST_RECORD = 6;
|
||||
|
||||
/**
|
||||
* The filter type is used for range operators ({@link #OPERATOR_LESS_THEN_OR_EQUAL}, {@link #OPERATOR_GREATER_THEN_OR_EQUAL}, {@link #OPERATOR_WITHING_RANGE}.<br/>
|
||||
* The syntax of the operand is: [Filter Type][Minimum][Maximum].<br/>
|
||||
* This filter selects the records by the sequence number.
|
||||
*/
|
||||
private static final int FILTER_TYPE_SEQUENCE_NUMBER = 1;
|
||||
/**
|
||||
* The filter type is used for range operators ({@link #OPERATOR_LESS_THEN_OR_EQUAL}, {@link #OPERATOR_GREATER_THEN_OR_EQUAL}, {@link #OPERATOR_WITHING_RANGE}.<br/>
|
||||
* The syntax of the operand is: [Filter Type][Minimum][Maximum].<br/>
|
||||
* This filter selects the records by the user facing time (base time + offset time).
|
||||
*/
|
||||
private static final int FILTER_TYPE_USER_FACING_TIME = 2;
|
||||
private static final int RESPONSE_SUCCESS = 1;
|
||||
private static final int RESPONSE_OP_CODE_NOT_SUPPORTED = 2;
|
||||
private static final int RESPONSE_INVALID_OPERATOR = 3;
|
||||
private static final int RESPONSE_OPERATOR_NOT_SUPPORTED = 4;
|
||||
private static final int RESPONSE_INVALID_OPERAND = 5;
|
||||
private static final int RESPONSE_NO_RECORDS_FOUND = 6;
|
||||
private static final int RESPONSE_ABORT_UNSUCCESSFUL = 7;
|
||||
private static final int RESPONSE_PROCEDURE_NOT_COMPLETED = 8;
|
||||
private static final int RESPONSE_OPERAND_NOT_SUPPORTED = 9;
|
||||
|
||||
private BluetoothGattCharacteristic mCGMFeatureCharacteristic;
|
||||
private BluetoothGattCharacteristic mCGMMeasurementCharacteristic;
|
||||
private BluetoothGattCharacteristic mCGMOpsControlPointCharacteristic;
|
||||
private BluetoothGattCharacteristic mCGMSpecificOpsControlPointCharacteristic;
|
||||
private BluetoothGattCharacteristic mRecordAccessControlPointCharacteristic;
|
||||
|
||||
private SparseArray<CGMSRecord> mRecords = new SparseArray<>();
|
||||
private boolean mAbort;
|
||||
/** A flag set to true if the remote device supports E2E CRC. */
|
||||
private boolean mSecured;
|
||||
private long mSessionStartTime;
|
||||
|
||||
CGMSManager(final Context context) {
|
||||
@@ -118,164 +87,151 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
||||
|
||||
@Override
|
||||
protected void initialize(@NonNull final BluetoothDevice device) {
|
||||
// Enable Battery service
|
||||
super.initialize(device);
|
||||
enableNotifications(mCGMMeasurementCharacteristic);
|
||||
enableIndications(mCGMOpsControlPointCharacteristic)
|
||||
.done(() -> mSessionStartTime = System.currentTimeMillis());
|
||||
writeCharacteristic(mCGMOpsControlPointCharacteristic, new byte[] { 26 });
|
||||
enableIndications(mRecordAccessControlPointCharacteristic);
|
||||
|
||||
// Enable Continuous Glucose Measurement notifications
|
||||
enableNotifications(mCGMMeasurementCharacteristic)
|
||||
.with(new ContinuousGlucoseMeasurementDataCallback() {
|
||||
@Override
|
||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
||||
log(LogContract.Log.Level.APPLICATION, "\"" + CGMMeasurementParser.parse(mCGMMeasurementCharacteristic) + "\" received");
|
||||
super.onDataReceived(device, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContinuousGlucoseMeasurementReceived(@NonNull final BluetoothDevice device, final float glucoseConcentration, @Nullable final Float cgmTrend, @Nullable final Float cgmQuality, final CGMStatus status, final int timeOffset, final boolean secured) {
|
||||
final long timestamp = mSessionStartTime + (timeOffset * 60000L); // Sequence number is in minutes since Start Session
|
||||
final CGMSRecord record = new CGMSRecord(timeOffset, glucoseConcentration, timestamp);
|
||||
mCallbacks.onCGMValueReceived(device, record);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContinuousGlucoseMeasurementReceivedWithCrcError(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
||||
log(LogContract.Log.Level.WARNING, "Continuous Glucose Measurement record received with CRC error");
|
||||
}
|
||||
})
|
||||
.fail((error) -> log(LogContract.Log.Level.WARNING, "Failed to enable Continuous Glucose Measurement notifications (" + error + ")"));
|
||||
|
||||
// Enable CGM Specific Ops indications
|
||||
enableIndications(mCGMSpecificOpsControlPointCharacteristic)
|
||||
.with(new CGMSpecificOpsControlPointDataCallback() {
|
||||
@Override
|
||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
||||
log(LogContract.Log.Level.APPLICATION, "\"" + CGMSpecificOpsControlPointParser.parse(mCGMSpecificOpsControlPointCharacteristic) + "\" received");
|
||||
super.onDataReceived(device, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCGMSpecificOpsOperationCompleted(@NonNull final BluetoothDevice device, final int requestCode, final boolean secured) {
|
||||
switch (requestCode) {
|
||||
case CGM_OP_CODE_START_SESSION:
|
||||
mSessionStartTime = System.currentTimeMillis();
|
||||
log(LogContract.Log.Level.APPLICATION, "Session started");
|
||||
break;
|
||||
case CGM_OP_CODE_STOP_SESSION:
|
||||
mSessionStartTime = 0;
|
||||
log(LogContract.Log.Level.APPLICATION, "Session stopped");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCGMSpecificOpsOperationError(@NonNull final BluetoothDevice device, final int requestCode, final int error, final boolean secured) {
|
||||
switch (requestCode) {
|
||||
case CGM_OP_CODE_START_SESSION:
|
||||
mSessionStartTime = 0;
|
||||
log(LogContract.Log.Level.WARNING, "Session not started, error " + error);
|
||||
break;
|
||||
case CGM_OP_CODE_STOP_SESSION:
|
||||
mSessionStartTime = 0;
|
||||
log(LogContract.Log.Level.APPLICATION, "Session stopped, error " + error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCGMSpecificOpsResponseReceivedWithCrcError(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
||||
log(LogContract.Log.Level.ERROR, "Request failed: CRC error");
|
||||
}
|
||||
});
|
||||
|
||||
enableIndications(mRecordAccessControlPointCharacteristic)
|
||||
.with(new RecordAccessControlPointDataCallback() {
|
||||
@Override
|
||||
public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) {
|
||||
log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(mRecordAccessControlPointCharacteristic) + "\" received");
|
||||
super.onDataReceived(device, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecordAccessOperationCompleted(@NonNull final BluetoothDevice device, final int requestCode) {
|
||||
switch (requestCode) {
|
||||
case RACP_OP_CODE_ABORT_OPERATION:
|
||||
mCallbacks.onOperationAborted(device);
|
||||
break;
|
||||
default:
|
||||
mCallbacks.onOperationCompleted(device);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecordAccessOperationCompletedWithNoRecordsFound(@NonNull final BluetoothDevice device, final int requestCode) {
|
||||
mCallbacks.onOperationCompleted(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNumberOfRecordsReceived(@NonNull final BluetoothDevice device, final int numberOfRecords) {
|
||||
mCallbacks.onNumberOfRecordsRequested(device, numberOfRecords);
|
||||
if (numberOfRecords > 0) {
|
||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportNumberOfAllStoredRecords());
|
||||
} else {
|
||||
mCallbacks.onOperationCompleted(device);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecordAccessOperationError(@NonNull final BluetoothDevice device, final int requestCode, final int errorCode) {
|
||||
log(LogContract.Log.Level.WARNING, "Record Access operation failed (error " + errorCode + ")");
|
||||
if (errorCode == RACP_ERROR_OP_CODE_NOT_SUPPORTED) {
|
||||
mCallbacks.onOperationNotSupported(device);
|
||||
} else {
|
||||
mCallbacks.onOperationFailed(device);
|
||||
}
|
||||
}
|
||||
})
|
||||
.fail((error) -> log(LogContract.Log.Level.WARNING, "Failed to enabled Record Access Control Point indications (error " + error + ")"));
|
||||
|
||||
// Start Continuous Glucose session
|
||||
writeCharacteristic(mCGMSpecificOpsControlPointCharacteristic, CGMSpecificOpsControlPointData.startSession(mSecured))
|
||||
.done(() -> log(LogContract.Log.Level.APPLICATION, "\"" + CGMSpecificOpsControlPointParser.parse(mCGMSpecificOpsControlPointCharacteristic) + "\" sent"))
|
||||
.fail((error) -> log(LogContract.Log.Level.ERROR, "Failed to start session (error " + error + ")"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||
final BluetoothGattService service = gatt.getService(CGMS_UUID);
|
||||
if (service != null) {
|
||||
mCGMFeatureCharacteristic = service.getCharacteristic(CGM_FEAURE_UUID);
|
||||
mCGMMeasurementCharacteristic = service.getCharacteristic(CGM_MEASUREMENT_UUID);
|
||||
mCGMOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
|
||||
mCGMSpecificOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
|
||||
mRecordAccessControlPointCharacteristic = service.getCharacteristic(RACP_UUID);
|
||||
}
|
||||
return mCGMMeasurementCharacteristic != null && mCGMOpsControlPointCharacteristic != null && mRecordAccessControlPointCharacteristic != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) {
|
||||
super.isOptionalServiceSupported(gatt); // ignore the result
|
||||
final BluetoothGattService service = gatt.getService(CGMS_UUID);
|
||||
if (service != null) {
|
||||
mCGMOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
|
||||
}
|
||||
return mCGMOpsControlPointCharacteristic != null;
|
||||
return mCGMFeatureCharacteristic != null && mCGMMeasurementCharacteristic != null &&
|
||||
mCGMSpecificOpsControlPointCharacteristic != null && mRecordAccessControlPointCharacteristic != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDeviceDisconnected() {
|
||||
super.onDeviceDisconnected();
|
||||
mCGMOpsControlPointCharacteristic = null;
|
||||
mCGMFeatureCharacteristic = null;
|
||||
mCGMMeasurementCharacteristic = null;
|
||||
mCGMSpecificOpsControlPointCharacteristic = null;
|
||||
mRecordAccessControlPointCharacteristic = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCharacteristicWrite(@NonNull final BluetoothGatt gatt, @NonNull final BluetoothGattCharacteristic characteristic) {
|
||||
if (characteristic.getUuid().equals(RACP_UUID)) {
|
||||
log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(characteristic) + "\" sent");
|
||||
} else { // uuid == CGM_OPS_CONTROL_POINT_UUID
|
||||
log(LogContract.Log.Level.APPLICATION, "\"" + CGMSpecificOpsControlPointParser.parse(characteristic) + "\" sent");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCharacteristicNotified(@NonNull final BluetoothGatt gatt, @NonNull final BluetoothGattCharacteristic characteristic) {
|
||||
log(LogContract.Log.Level.APPLICATION, "\"" + CGMMeasurementParser.parse(characteristic) + "\" received");
|
||||
|
||||
// CGM Measurement characteristic may have one or more CGM records
|
||||
int totalSize = characteristic.getValue().length;
|
||||
int offset = 0;
|
||||
while (offset < totalSize) {
|
||||
final int cgmSize = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
|
||||
final float cgmValue = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset + 2);
|
||||
final int sequenceNumber = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset + 4);
|
||||
final long timestamp = mSessionStartTime + (sequenceNumber * 60000L); // Sequence number is in minutes since Start Session
|
||||
|
||||
//This will send callback to CGMSActivity when new concentration value is received from CGMS device
|
||||
final CGMSRecord cgmsRecord = new CGMSRecord(sequenceNumber, cgmValue, timestamp);
|
||||
mRecords.put(cgmsRecord.sequenceNumber, cgmsRecord);
|
||||
mCallbacks.onCGMValueReceived(gatt.getDevice(), cgmsRecord);
|
||||
|
||||
offset += cgmSize;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCharacteristicIndicated(@NonNull final BluetoothGatt gatt, @NonNull final BluetoothGattCharacteristic characteristic) {
|
||||
if (characteristic.getUuid().equals(RACP_UUID)) {
|
||||
log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(characteristic) + "\" received");
|
||||
|
||||
// Record Access Control Point characteristic
|
||||
int offset = 0;
|
||||
final int opCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
|
||||
offset += 2; // skip the operator
|
||||
|
||||
if (opCode == OP_CODE_NUMBER_OF_STORED_RECORDS_RESPONSE) {
|
||||
// We've obtained the number of all records
|
||||
final int number = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset);
|
||||
|
||||
mCallbacks.onNumberOfRecordsRequested(gatt.getDevice(), number);
|
||||
|
||||
// Request the records
|
||||
if (number > 0) {
|
||||
final BluetoothGattCharacteristic racpCharacteristic = mRecordAccessControlPointCharacteristic;
|
||||
setOpCode(racpCharacteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_ALL_RECORDS);
|
||||
writeCharacteristic(racpCharacteristic);
|
||||
} else {
|
||||
mCallbacks.onOperationCompleted(gatt.getDevice());
|
||||
}
|
||||
} else if (opCode == OP_CODE_RESPONSE_CODE) {
|
||||
final int requestedOpCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset);
|
||||
final int responseCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 1);
|
||||
DebugLogger.d(TAG, "Response result for: " + requestedOpCode + " is: " + responseCode);
|
||||
|
||||
switch (responseCode) {
|
||||
case RESPONSE_SUCCESS:
|
||||
if (!mAbort)
|
||||
mCallbacks.onOperationCompleted(gatt.getDevice());
|
||||
else
|
||||
mCallbacks.onOperationAborted(gatt.getDevice());
|
||||
break;
|
||||
case RESPONSE_NO_RECORDS_FOUND:
|
||||
mCallbacks.onOperationCompleted(gatt.getDevice());
|
||||
break;
|
||||
case RESPONSE_OP_CODE_NOT_SUPPORTED:
|
||||
mCallbacks.onOperationNotSupported(gatt.getDevice());
|
||||
break;
|
||||
case RESPONSE_PROCEDURE_NOT_COMPLETED:
|
||||
case RESPONSE_ABORT_UNSUCCESSFUL:
|
||||
default:
|
||||
mCallbacks.onOperationFailed(gatt.getDevice());
|
||||
break;
|
||||
}
|
||||
mAbort = false;
|
||||
}
|
||||
} else { // uuid == CGM_OPS_CONTROL_POINT_UUID
|
||||
log(LogContract.Log.Level.APPLICATION, "\"" + CGMSpecificOpsControlPointParser.parse(characteristic) + "\" received");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes given operation parameters to the characteristic
|
||||
*
|
||||
* @param characteristic the characteristic to write. This must be the Record Access Control Point characteristic
|
||||
* @param opCode the operation code
|
||||
* @param operator the operator (see {@link #OPERATOR_NULL} and others
|
||||
* @param params optional parameters (one for >=, <=, two for the range, none for other operators)
|
||||
*/
|
||||
private void setOpCode(final BluetoothGattCharacteristic characteristic, final int opCode, final int operator, final Integer... params) {
|
||||
final int size = 2 + ((params.length > 0) ? 1 : 0) + params.length * 2; // 1 byte for opCode, 1 for operator, 1 for filter type (if parameters exists) and 2 for each parameter
|
||||
characteristic.setValue(new byte[size]);
|
||||
|
||||
// write the operation code
|
||||
int offset = 0;
|
||||
characteristic.setValue(opCode, BluetoothGattCharacteristic.FORMAT_UINT8, offset);
|
||||
offset += 1;
|
||||
|
||||
// write the operator. This is always present but may be equal to OPERATOR_NULL
|
||||
characteristic.setValue(operator, BluetoothGattCharacteristic.FORMAT_UINT8, offset);
|
||||
offset += 1;
|
||||
|
||||
// if parameters exists, append them. Parameters should be sorted from minimum to maximum. Currently only one or two params are allowed
|
||||
if (params.length > 0) {
|
||||
// our implementation use only sequence number as a filer type
|
||||
characteristic.setValue(FILTER_TYPE_SEQUENCE_NUMBER, BluetoothGattCharacteristic.FORMAT_UINT8, offset);
|
||||
offset += 1;
|
||||
|
||||
for (final Integer i : params) {
|
||||
characteristic.setValue(i, BluetoothGattCharacteristic.FORMAT_UINT16, offset);
|
||||
offset += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of CGM records obtained from this device. The key in the array is the
|
||||
*/
|
||||
@@ -288,12 +244,12 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
||||
*/
|
||||
public void clear() {
|
||||
mRecords.clear();
|
||||
mCallbacks.onDatasetClear(getBluetoothDevice());
|
||||
mCallbacks.onDatasetCleared(getBluetoothDevice());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain the last (most recent) record from glucose device. The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access
|
||||
* Control Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of error.
|
||||
* Control Point indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void getLastRecord() {
|
||||
if (mRecordAccessControlPointCharacteristic == null)
|
||||
@@ -301,15 +257,13 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
||||
|
||||
clear();
|
||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
||||
|
||||
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
|
||||
setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_LAST_RECORD);
|
||||
writeCharacteristic(characteristic);
|
||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportLastStoredRecord());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain the first (oldest) record from glucose device. The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control
|
||||
* Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of error.
|
||||
* Sends the request to obtain the first (oldest) record from glucose device.
|
||||
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control
|
||||
* Point indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void getFirstRecord() {
|
||||
if (mRecordAccessControlPointCharacteristic == null)
|
||||
@@ -317,29 +271,25 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
||||
|
||||
clear();
|
||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
||||
|
||||
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
|
||||
setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_FIRST_RECORD);
|
||||
writeCharacteristic(characteristic);
|
||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportFirstStoredRecord());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends abort operation signal to the device
|
||||
* Sends abort operation signal to the device.
|
||||
*/
|
||||
public void abort() {
|
||||
if (mRecordAccessControlPointCharacteristic == null)
|
||||
return;
|
||||
|
||||
mAbort = true;
|
||||
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
|
||||
setOpCode(characteristic, OP_CODE_ABORT_OPERATION, OPERATOR_NULL);
|
||||
writeCharacteristic(characteristic);
|
||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.abortOperation());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain all records from glucose device. Initially we want to notify him/her about the number of the records so the {@link #OP_CODE_REPORT_NUMBER_OF_RECORDS} is send. The
|
||||
* data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of
|
||||
* error.
|
||||
* Sends the request to obtain all records from glucose device. Initially we want to notify the user
|
||||
* about the number of the records so the Report Number of Stored Records request is send. The
|
||||
* data will be returned to Glucose Measurement characteristic as a notification followed by
|
||||
* Record Access Control Point indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void getAllRecords() {
|
||||
if (mRecordAccessControlPointCharacteristic == null)
|
||||
@@ -347,16 +297,14 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
||||
|
||||
clear();
|
||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
||||
|
||||
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
|
||||
setOpCode(characteristic, OP_CODE_REPORT_NUMBER_OF_RECORDS, OPERATOR_ALL_RECORDS);
|
||||
writeCharacteristic(characteristic);
|
||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportNumberOfAllStoredRecords());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain all records from glucose device. Initially we want to notify him/her about the number of the records so the {@link #OP_CODE_REPORT_NUMBER_OF_RECORDS} is send. The
|
||||
* data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of
|
||||
* error.
|
||||
* Sends the request to obtain all records from glucose device. Initially we want to notify the user
|
||||
* about the number of the records so the Report Number of Stored Records request is send. The
|
||||
* data will be returned to Glucose Measurement characteristic as a notification followed by
|
||||
* Record Access Control Point indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void refreshRecords() {
|
||||
if (mRecordAccessControlPointCharacteristic == null)
|
||||
@@ -367,28 +315,27 @@ public class CGMSManager extends BatteryManager<CGMSManagerCallbacks> {
|
||||
} else {
|
||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
||||
|
||||
// obtain the last sequence number
|
||||
// Obtain the last sequence number
|
||||
final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1;
|
||||
|
||||
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
|
||||
setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_GREATER_THEN_OR_EQUAL, sequenceNumber);
|
||||
writeCharacteristic(characteristic);
|
||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber));
|
||||
// Info:
|
||||
// Operators OPERATOR_GREATER_THEN_OR_EQUAL, OPERATOR_LESS_THEN_OR_EQUAL and OPERATOR_RANGE are not supported by the CGMS sample from SDK
|
||||
// The "Operation not supported" response will be received
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to remove all stored records from the Continuous Glucose Monitor device.
|
||||
* This feature is not supported by the CGMS sample from the SDK, so monitor will answer with
|
||||
* the Op Code Not Supported error.
|
||||
*/
|
||||
public void deleteAllRecords() {
|
||||
if (mRecordAccessControlPointCharacteristic == null)
|
||||
return;
|
||||
|
||||
clear();
|
||||
mCallbacks.onOperationStarted(getBluetoothDevice());
|
||||
|
||||
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
|
||||
setOpCode(characteristic, OP_CODE_DELETE_STORED_RECORDS, OPERATOR_ALL_RECORDS);
|
||||
writeCharacteristic(characteristic);
|
||||
writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.deleteAllStoredRecords());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,27 +25,24 @@ package no.nordicsemi.android.nrftoolbox.cgms;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import no.nordicsemi.android.ble.BleManagerCallbacks;
|
||||
import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks;
|
||||
|
||||
public interface CGMSManagerCallbacks extends BatteryManagerCallbacks {
|
||||
/**
|
||||
* Called when new CGM value has been obtained from the sensor.
|
||||
*/
|
||||
void onCGMValueReceived(final @NonNull BluetoothDevice device, final CGMSRecord record);
|
||||
|
||||
void onOperationStarted(final @NonNull BluetoothDevice device);
|
||||
void onCGMValueReceived(@NonNull final BluetoothDevice device, final CGMSRecord record);
|
||||
|
||||
void onOperationCompleted(final @NonNull BluetoothDevice device);
|
||||
void onOperationStarted(final @NonNull BluetoothDevice device);
|
||||
|
||||
void onOperationFailed(final @NonNull BluetoothDevice device);
|
||||
void onOperationCompleted(final @NonNull BluetoothDevice device);
|
||||
|
||||
void onOperationAborted(final @NonNull BluetoothDevice device);
|
||||
void onOperationFailed(final @NonNull BluetoothDevice device);
|
||||
|
||||
void onOperationNotSupported(final @NonNull BluetoothDevice device);
|
||||
void onOperationAborted(final @NonNull BluetoothDevice device);
|
||||
|
||||
void onDatasetClear(final @NonNull BluetoothDevice device);
|
||||
void onOperationNotSupported(final @NonNull BluetoothDevice device);
|
||||
|
||||
void onNumberOfRecordsRequested(final @NonNull BluetoothDevice device, final int value);
|
||||
void onDatasetCleared(final @NonNull BluetoothDevice device);
|
||||
|
||||
void onNumberOfRecordsRequested(final @NonNull BluetoothDevice device, final int value);
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package no.nordicsemi.android.nrftoolbox.cgms;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
public class CGMSRecord implements Parcelable{
|
||||
class CGMSRecord implements Parcelable{
|
||||
/** Record sequence number. */
|
||||
protected int sequenceNumber;
|
||||
/** The base time of the measurement (start time + sequenceNumber of minutes). */
|
||||
@@ -11,13 +11,13 @@ public class CGMSRecord implements Parcelable{
|
||||
/** The glucose concentration in mg/dL. */
|
||||
protected float glucoseConcentration;
|
||||
|
||||
protected CGMSRecord(int sequenceNumber, float glucoseConcentration, long timestamp) {
|
||||
CGMSRecord(final int sequenceNumber, final float glucoseConcentration, final long timestamp) {
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
this.glucoseConcentration = glucoseConcentration;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
protected CGMSRecord(Parcel in) {
|
||||
private CGMSRecord(final Parcel in) {
|
||||
this.sequenceNumber = in.readInt();
|
||||
this.glucoseConcentration = in.readFloat();
|
||||
this.timestamp = in.readLong();
|
||||
@@ -25,12 +25,12 @@ public class CGMSRecord implements Parcelable{
|
||||
|
||||
public static final Creator<CGMSRecord> CREATOR = new Creator<CGMSRecord>() {
|
||||
@Override
|
||||
public CGMSRecord createFromParcel(Parcel in) {
|
||||
public CGMSRecord createFromParcel(final Parcel in) {
|
||||
return new CGMSRecord(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CGMSRecord[] newArray(int size) {
|
||||
public CGMSRecord[] newArray(final int size) {
|
||||
return new CGMSRecord[size];
|
||||
}
|
||||
};
|
||||
@@ -41,7 +41,7 @@ public class CGMSRecord implements Parcelable{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int i) {
|
||||
public void writeToParcel(final Parcel parcel, final int flags) {
|
||||
parcel.writeInt(sequenceNumber);
|
||||
parcel.writeFloat(glucoseConcentration);
|
||||
parcel.writeLong(timestamp);
|
||||
|
||||
@@ -9,11 +9,13 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import no.nordicsemi.android.ble.BleManager;
|
||||
import no.nordicsemi.android.ble.common.profile.cgm.CGMTypes;
|
||||
import no.nordicsemi.android.log.Logger;
|
||||
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
|
||||
import no.nordicsemi.android.nrftoolbox.R;
|
||||
@@ -21,267 +23,266 @@ import no.nordicsemi.android.nrftoolbox.ToolboxApplication;
|
||||
import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
|
||||
|
||||
public class CGMService extends BleProfileService implements CGMSManagerCallbacks {
|
||||
private static final String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.cgms.ACTION_DISCONNECT";
|
||||
private static final String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.cgms.ACTION_DISCONNECT";
|
||||
|
||||
public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL";
|
||||
public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL";
|
||||
public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL";
|
||||
public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL";
|
||||
|
||||
public static final String BROADCAST_NEW_CGMS_VALUE = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_NEW_CGMS_VALUE";
|
||||
public static final String BROADCAST_DATA_SET_CLEAR = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_DATA_SET_CLEAR";
|
||||
public static final String OPERATION_STARTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_STARTED";
|
||||
public static final String OPERATION_COMPLETED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_COMPLETED";
|
||||
public static final String OPERATION_SUPPORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_SUPPORTED";
|
||||
public static final String OPERATION_NOT_SUPPORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_NOT_SUPPORTED";
|
||||
public static final String OPERATION_FAILED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_FAILED";
|
||||
public static final String OPERATION_ABORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_ABORTED";
|
||||
public static final String EXTRA_CGMS_RECORD = "no.nordicsemi.android.nrftoolbox.cgms.EXTRA_CGMS_RECORD";
|
||||
public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.cgms.EXTRA_DATA";
|
||||
public static final String BROADCAST_NEW_CGMS_VALUE = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_NEW_CGMS_VALUE";
|
||||
public static final String BROADCAST_DATA_SET_CLEAR = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_DATA_SET_CLEAR";
|
||||
public static final String OPERATION_STARTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_STARTED";
|
||||
public static final String OPERATION_COMPLETED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_COMPLETED";
|
||||
public static final String OPERATION_SUPPORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_SUPPORTED";
|
||||
public static final String OPERATION_NOT_SUPPORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_NOT_SUPPORTED";
|
||||
public static final String OPERATION_FAILED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_FAILED";
|
||||
public static final String OPERATION_ABORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_ABORTED";
|
||||
public static final String EXTRA_CGMS_RECORD = "no.nordicsemi.android.nrftoolbox.cgms.EXTRA_CGMS_RECORD";
|
||||
public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.cgms.EXTRA_DATA";
|
||||
|
||||
private final static int NOTIFICATION_ID = 229;
|
||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||
private final static int DISCONNECT_REQ = 1;
|
||||
private final static int NOTIFICATION_ID = 229;
|
||||
private final static int OPEN_ACTIVITY_REQ = 0;
|
||||
private final static int DISCONNECT_REQ = 1;
|
||||
|
||||
private CGMSManager mManager;
|
||||
private final LocalBinder mBinder = new CGMSBinder();
|
||||
private CGMSManager mManager;
|
||||
private final LocalBinder mBinder = new CGMSBinder();
|
||||
|
||||
/**
|
||||
* This local binder is an interface for the bonded activity to operate with the RSC sensor
|
||||
*/
|
||||
/**
|
||||
* This local binder is an interface for the bonded activity to operate with the RSC sensor
|
||||
*/
|
||||
|
||||
public class CGMSBinder extends LocalBinder {
|
||||
/**
|
||||
* Returns all records as a sparse array where sequence number is the key.
|
||||
*
|
||||
* @return the records list
|
||||
*/
|
||||
public SparseArray<CGMSRecord> getRecords() {
|
||||
return mManager.getRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the records list locally
|
||||
*/
|
||||
public void clear() {
|
||||
if (mManager != null)
|
||||
mManager.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain the first (oldest) record from glucose device.
|
||||
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control
|
||||
* Point indication with status code ({@link CGMSManager# RESPONSE_SUCCESS} or other in case of error.
|
||||
*/
|
||||
public void getFirstRecord() {
|
||||
if(mManager != null)
|
||||
mManager.getFirstRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain the last (most recent) record from glucose device.
|
||||
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access
|
||||
* Control Point indication with status code ({@link CGMSManager#RESPONSE_SUCCESS} or other in case of error.
|
||||
*/
|
||||
public void getLastRecord() {
|
||||
if(mManager != null)
|
||||
mManager.getLastRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain all records from glucose device.
|
||||
* Initially we want to notify user about the number of the records so the {@link CGMSManager#OP_CODE_REPORT_NUMBER_OF_RECORDS} is send.
|
||||
* The data will be returned to Glucose Measurement characteristic as a series of notifications followed by Record Access Control Point
|
||||
* indication with status code ({@link CGMSManager#RESPONSE_SUCCESS} or other in case of error.
|
||||
*/
|
||||
public void getAllRecords() {
|
||||
if(mManager != null)
|
||||
mManager.getAllRecords();
|
||||
}
|
||||
public class CGMSBinder extends LocalBinder {
|
||||
/**
|
||||
* Returns all records as a sparse array where sequence number is the key.
|
||||
*
|
||||
* @return the records list
|
||||
*/
|
||||
public SparseArray<CGMSRecord> getRecords() {
|
||||
return mManager.getRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain all records from glucose device with sequence number greater than the last one already obtained.
|
||||
* The data will be returned to Glucose Measurement characteristic as a series of notifications followed by Record Access Control Point
|
||||
* indication with status code ({@link CGMSManager#RESPONSE_SUCCESS} or other in case of error.
|
||||
*/
|
||||
public void refreshRecords() {
|
||||
if (mManager != null)
|
||||
mManager.refreshRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends abort operation signal to the device
|
||||
*/
|
||||
public void abort() {
|
||||
if(mManager != null)
|
||||
mManager.abort();
|
||||
}
|
||||
* Clears the records list locally
|
||||
*/
|
||||
public void clear() {
|
||||
if (mManager != null)
|
||||
mManager.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends Delete op code with All stored records parameter. This method may not be supported by the SDK sample.
|
||||
*/
|
||||
public void deleteAllRecords() {
|
||||
if(mManager != null)
|
||||
mManager.deleteAllRecords();
|
||||
}
|
||||
}
|
||||
* Sends the request to obtain the first (oldest) record from glucose device.
|
||||
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control
|
||||
* Point indication with status code ({@link CGMSManager# RESPONSE_SUCCESS} or other in case of error.
|
||||
*/
|
||||
public void getFirstRecord() {
|
||||
if (mManager != null)
|
||||
mManager.getFirstRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
/**
|
||||
* Sends the request to obtain the last (most recent) record from glucose device.
|
||||
* The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access
|
||||
* Control Point indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void getLastRecord() {
|
||||
if (mManager != null)
|
||||
mManager.getLastRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BleManager initializeManager() {
|
||||
return mManager = new CGMSManager(this);
|
||||
}
|
||||
/**
|
||||
* Sends the request to obtain all records from glucose device.
|
||||
* Initially we want to notify user about the number of the records so the Report Number of Stored Records is send.
|
||||
* The data will be returned to Glucose Measurement characteristic as a series of notifications followed
|
||||
* by Record Access Control Point indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void getAllRecords() {
|
||||
if (mManager != null)
|
||||
mManager.getAllRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request to obtain all records from glucose device with sequence number greater
|
||||
* than the last one already obtained. The data will be returned to Glucose Measurement
|
||||
* characteristic as a series of notifications followed by Record Access Control Point
|
||||
* indication with status code Success or other in case of error.
|
||||
*/
|
||||
public void refreshRecords() {
|
||||
if (mManager != null)
|
||||
mManager.refreshRecords();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends abort operation signal to the device
|
||||
*/
|
||||
public void abort() {
|
||||
if (mManager != null)
|
||||
mManager.abort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends Delete op code with All stored records parameter. This method may not be supported by the SDK sample.
|
||||
*/
|
||||
public void deleteAllRecords() {
|
||||
if (mManager != null)
|
||||
mManager.deleteAllRecords();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BleManager initializeManager() {
|
||||
return mManager = new CGMSManager(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_DISCONNECT);
|
||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
||||
}
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_DISCONNECT);
|
||||
registerReceiver(mDisconnectActionBroadcastReceiver, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||
cancelNotification();
|
||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
// when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService
|
||||
cancelNotification();
|
||||
unregisterReceiver(mDisconnectActionBroadcastReceiver);
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
// when the activity rebinds to the service, remove the notification
|
||||
cancelNotification();
|
||||
}
|
||||
@Override
|
||||
protected void onRebind() {
|
||||
// when the activity rebinds to the service, remove the notification
|
||||
cancelNotification();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
// when the activity closes we need to show the notification that user is connected to the sensor
|
||||
createNotification(R.string.csc_notification_connected_message, 0);
|
||||
}
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
// when the activity closes we need to show the notification that user is connected to the sensor
|
||||
createNotification(R.string.csc_notification_connected_message, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the notification
|
||||
*
|
||||
* @param messageResId
|
||||
* the message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults
|
||||
* signals that will be used to notify the user
|
||||
*/
|
||||
private void createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, CGMSActivity.class);
|
||||
/**
|
||||
* Creates the notification
|
||||
*
|
||||
* @param messageResId the message resource id. The message must have one String parameter,<br />
|
||||
* f.e. <code><string name="name">%s is connected</string></code>
|
||||
* @param defaults signals that will be used to notify the user
|
||||
*/
|
||||
private void createNotification(final int messageResId, final int defaults) {
|
||||
final Intent parentIntent = new Intent(this, FeaturesActivity.class);
|
||||
parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
final Intent targetIntent = new Intent(this, CGMSActivity.class);
|
||||
|
||||
final Intent disconnect = new Intent(ACTION_DISCONNECT);
|
||||
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final Intent disconnect = new Intent(ACTION_DISCONNECT);
|
||||
final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[] { parentIntent, targetIntent }, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_notify_cgms);
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.csc_notification_action_disconnect), disconnectAction));
|
||||
// both activities above have launchMode="singleTask" in the AndroidManifest.xml file, so if the task is already running, it will be resumed
|
||||
final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[]{parentIntent, targetIntent}, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL);
|
||||
builder.setContentIntent(pendingIntent);
|
||||
builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName()));
|
||||
builder.setSmallIcon(R.drawable.ic_stat_notify_cgms);
|
||||
builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true);
|
||||
builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.csc_notification_action_disconnect), disconnectAction));
|
||||
|
||||
final Notification notification = builder.build();
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
final Notification notification = builder.build();
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
nm.notify(NOTIFICATION_ID, notification);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the existing notification. If there is no active notification this method does nothing
|
||||
*/
|
||||
private void cancelNotification() {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
/**
|
||||
* Cancels the existing notification. If there is no active notification this method does nothing
|
||||
*/
|
||||
private void cancelNotification() {
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
nm.cancel(NOTIFICATION_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
|
||||
*/
|
||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||
if (isConnected())
|
||||
getBinder().disconnect();
|
||||
else
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification.
|
||||
*/
|
||||
private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
Logger.i(getLogSession(), "[Notification] Disconnect action pressed");
|
||||
if (isConnected())
|
||||
getBinder().disconnect();
|
||||
else
|
||||
stopSelf();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCGMValueReceived(@NonNull final BluetoothDevice device, final CGMSRecord record) {
|
||||
final Intent broadcast = new Intent(BROADCAST_NEW_CGMS_VALUE);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_CGMS_RECORD, record);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onCGMValueReceived(@NonNull final BluetoothDevice device, final CGMSRecord record) {
|
||||
final Intent broadcast = new Intent(BROADCAST_NEW_CGMS_VALUE);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_CGMS_RECORD, record);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationStarted(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_STARTED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onOperationStarted(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_STARTED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationCompleted(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_COMPLETED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onOperationCompleted(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_COMPLETED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationFailed(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_FAILED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onOperationFailed(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_FAILED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationAborted(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_ABORTED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onOperationAborted(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_ABORTED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationNotSupported(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_NOT_SUPPORTED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, false);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onOperationNotSupported(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(OPERATION_NOT_SUPPORTED);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
broadcast.putExtra(EXTRA_DATA, false);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDatasetClear(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(BROADCAST_DATA_SET_CLEAR);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onDatasetCleared(@NonNull final BluetoothDevice device) {
|
||||
final Intent broadcast = new Intent(BROADCAST_DATA_SET_CLEAR);
|
||||
broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice());
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNumberOfRecordsRequested(@NonNull final BluetoothDevice device, int value) {
|
||||
showToast(getResources().getQuantityString(R.plurals.gls_progress, value, value));
|
||||
}
|
||||
@Override
|
||||
public void onNumberOfRecordsRequested(@NonNull final BluetoothDevice device, final int value) {
|
||||
showToast(getResources().getQuantityString(R.plurals.gls_progress, value, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
||||
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
||||
broadcast.putExtra(EXTRA_BATTERY_LEVEL, batteryLevel);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
@Override
|
||||
public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) {
|
||||
final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
|
||||
broadcast.putExtra(EXTRA_DEVICE, device);
|
||||
broadcast.putExtra(EXTRA_BATTERY_LEVEL, batteryLevel);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user