mirror of
https://github.com/aljazceru/Android-nRF-Toolbox.git
synced 2026-01-06 00:04:21 +01:00
CGMS profile added, ver 1.18.0
+ minor fixes
This commit is contained in:
@@ -9,6 +9,7 @@ It contains applications demonstrating Bluetooth Smart profiles:
|
||||
* **Blood Pressure Monitor**,
|
||||
* **Health Thermometer Monitor**,
|
||||
* **Glucose Monitor**,
|
||||
* **Continuous Glucose Monitor**,
|
||||
* **Proximity Monitor**.
|
||||
|
||||
Since version 1.10.0 the *nRF Toolbox* also supports the **Nordic UART Service** which may be used for bidirectional text communication between devices.
|
||||
|
||||
@@ -8,8 +8,8 @@ android {
|
||||
applicationId "no.nordicsemi.android.nrftoolbox"
|
||||
minSdkVersion 18
|
||||
targetSdkVersion 24
|
||||
versionCode 46
|
||||
versionName "1.17.0"
|
||||
versionCode 47
|
||||
versionName "1.18.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
~ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
~ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
~ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="no.nordicsemi.android.nrftoolbox"
|
||||
android:installLocation="auto">
|
||||
@@ -201,6 +201,16 @@
|
||||
<category android:name="no.nordicsemi.android.nrftoolbox.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name="no.nordicsemi.android.nrftoolbox.cgms.CGMSActivity"
|
||||
android:icon="@drawable/ic_cgms_feature"
|
||||
android:label="@string/cgms_feature_title"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="no.nordicsemi.android.nrftoolbox.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name="no.nordicsemi.android.nrftoolbox.proximity.ProximityService"
|
||||
@@ -228,6 +238,9 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name="no.nordicsemi.android.nrftoolbox.cgms.CGMService"
|
||||
android:label="@string/cgms_feature_title" />
|
||||
<service
|
||||
android:name="no.nordicsemi.android.nrftoolbox.rsc.RSCService"
|
||||
android:label="@string/rsc_feature_title" />
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Nordic Semiconductor
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package no.nordicsemi.android.nrftoolbox.cgms;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.util.SparseArray;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ListView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import no.nordicsemi.android.nrftoolbox.R;
|
||||
import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
|
||||
import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity;
|
||||
|
||||
public class CGMSActivity extends BleProfileServiceReadyActivity<CGMService.CGMSBinder> implements PopupMenu.OnMenuItemClickListener {
|
||||
|
||||
private View mControlPanelStd;
|
||||
private View mControlPanelAbort;
|
||||
private TextView mUnitView;
|
||||
private ListView mRecordsListView;
|
||||
private CGMSRecordsAdapter mCgmsRecordsAdapter;
|
||||
|
||||
private CGMService.CGMSBinder mBinder;
|
||||
|
||||
@Override
|
||||
protected void onCreateView(Bundle savedInstanceState) {
|
||||
setContentView(R.layout.activity_feature_cgms);
|
||||
setGUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInitialize(Bundle savedInstanceState) {
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter());
|
||||
}
|
||||
|
||||
private void setGUI() {
|
||||
mRecordsListView = (ListView) findViewById(R.id.list);
|
||||
mUnitView = (TextView) findViewById(R.id.unit);
|
||||
mControlPanelStd = findViewById(R.id.cgms_control_std);
|
||||
mControlPanelAbort = findViewById(R.id.cgms_control_abort);
|
||||
|
||||
findViewById(R.id.action_last).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
clearRecords();
|
||||
if(mBinder != null) {
|
||||
mBinder.clear();
|
||||
mBinder.getLastRecord();
|
||||
}
|
||||
}
|
||||
});
|
||||
findViewById(R.id.action_all).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
clearRecords();
|
||||
if(mBinder != null){
|
||||
clearRecords();
|
||||
mBinder.getAllRecords();
|
||||
}
|
||||
}
|
||||
});
|
||||
findViewById(R.id.action_abort).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if(mBinder != null){
|
||||
mBinder.abort();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// create popup menu attached to the button More
|
||||
findViewById(R.id.action_more).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
PopupMenu menu = new PopupMenu(CGMSActivity.this, v);
|
||||
menu.setOnMenuItemClickListener(CGMSActivity.this);
|
||||
MenuInflater inflater = menu.getMenuInflater();
|
||||
inflater.inflate(R.menu.gls_more, menu.getMenu());
|
||||
menu.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void loadAdapter(SparseArray<CGMSRecord> records){
|
||||
for(int i = 0; i < records.size(); i++){
|
||||
mCgmsRecordsAdapter.addItem(records.get(i));
|
||||
}
|
||||
mCgmsRecordsAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onServiceBinded(CGMService.CGMSBinder binder) {
|
||||
mBinder = binder;
|
||||
SparseArray<CGMSRecord> cgmsRecords = binder.getCgmsRecords();
|
||||
if(cgmsRecords != null && cgmsRecords.size() > 0){
|
||||
if(mCgmsRecordsAdapter == null) {
|
||||
mCgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
|
||||
mRecordsListView.setAdapter(mCgmsRecordsAdapter);
|
||||
}
|
||||
loadAdapter(cgmsRecords);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onServiceUnbinded() {
|
||||
mBinder = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<? extends BleProfileService> getServiceClass() {
|
||||
return CGMService.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getLoggerProfileTitle() {
|
||||
return R.string.cgms_feature_title;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getAboutTextId() {
|
||||
return R.string.cgms_about_text;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDefaultDeviceName() {
|
||||
return R.string.cgms_default_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UUID getFilterUUID() {
|
||||
return CGMSManager.CGMS_UUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServicesDiscovered(final boolean optionalServicesFound) {
|
||||
// this may notify user or show some views
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceReady() {
|
||||
|
||||
}
|
||||
|
||||
private void setOperationInProgress(final boolean progress) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// setSupportProgressBarIndeterminateVisibility(progress);
|
||||
mControlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE);
|
||||
mControlPanelAbort.setVisibility(progress ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceDisconnected() {
|
||||
super.onDeviceDisconnected();
|
||||
setOperationInProgress(false);
|
||||
clearRecords();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setDefaultUI() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||
switch (menuItem.getItemId()) {
|
||||
case R.id.action_refresh:
|
||||
/*if(mBinder != null)
|
||||
mBinder.refreshRecords();*/
|
||||
break;
|
||||
case R.id.action_first:
|
||||
clearRecords();
|
||||
if(mBinder != null)
|
||||
mBinder.getFirstRecord();
|
||||
break;
|
||||
case R.id.action_clear:
|
||||
clearRecords();
|
||||
if(mBinder != null)
|
||||
mBinder.clear();
|
||||
break;
|
||||
case R.id.action_delete_all:
|
||||
clearRecords();
|
||||
if(mBinder != null)
|
||||
mBinder.deleteAllRecords();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void clearRecords(){
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(mCgmsRecordsAdapter != null){
|
||||
mCgmsRecordsAdapter.clear();
|
||||
mCgmsRecordsAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
if (CGMService.BROADCAST_CGMS_VALUES.equals(action)) {
|
||||
CGMSRecord cgmsRecord = intent.getExtras().getParcelable(CGMService.EXTRA_CGMS_RECORD);
|
||||
if(mCgmsRecordsAdapter == null){
|
||||
mCgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this);
|
||||
mRecordsListView.setAdapter(mCgmsRecordsAdapter);
|
||||
}
|
||||
mCgmsRecordsAdapter.addItem(cgmsRecord);
|
||||
mCgmsRecordsAdapter.notifyDataSetChanged();
|
||||
|
||||
} else if (CGMService.BROADCAST_DATA_SET_CHANGED.equals(action)) {
|
||||
// Update GUI
|
||||
clearRecords();
|
||||
} else if (CGMService.OPERATION_STARTED.equals(action)) {
|
||||
// Update GUI
|
||||
setOperationInProgress(true);
|
||||
} else if (CGMService.OPERATION_COMPLETED.equals(action)) {
|
||||
// Update GUI
|
||||
setOperationInProgress(false);
|
||||
} else if (CGMService.OPERATION_SUPPORTED.equals(action)) {
|
||||
// Update GUI
|
||||
setOperationInProgress(false);
|
||||
} else if (CGMService.OPERATION_NOT_SUPPORTED.equals(action)) {
|
||||
// Update GUI
|
||||
setOperationInProgress(false);
|
||||
} else if (CGMService.OPERATION_ABORTED.equals(action)) {
|
||||
// Update GUI
|
||||
setOperationInProgress(false);
|
||||
} else if (CGMService.OPERATION_FAILED.equals(action)) {
|
||||
// Update GUI
|
||||
setOperationInProgress(false);
|
||||
showToast(R.string.gls_operation_failed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static IntentFilter makeIntentFilter() {
|
||||
final IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(CGMService.BROADCAST_CGMS_VALUES);
|
||||
intentFilter.addAction(CGMService.BROADCAST_DATA_SET_CHANGED);
|
||||
intentFilter.addAction(CGMService.OPERATION_STARTED);
|
||||
intentFilter.addAction(CGMService.OPERATION_COMPLETED);
|
||||
intentFilter.addAction(CGMService.OPERATION_SUPPORTED);
|
||||
intentFilter.addAction(CGMService.OPERATION_NOT_SUPPORTED);
|
||||
intentFilter.addAction(CGMService.OPERATION_ABORTED);
|
||||
intentFilter.addAction(CGMService.OPERATION_FAILED);
|
||||
return intentFilter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Nordic Semiconductor
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package no.nordicsemi.android.nrftoolbox.cgms;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.bluetooth.BluetoothGattService;
|
||||
import android.content.Context;
|
||||
import android.nfc.Tag;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
|
||||
import no.nordicsemi.android.log.Logger;
|
||||
import no.nordicsemi.android.nrftoolbox.parser.HeartRateMeasurementParser;
|
||||
import no.nordicsemi.android.nrftoolbox.parser.RecordAccessControlPointParser;
|
||||
import no.nordicsemi.android.nrftoolbox.profile.BleManager;
|
||||
import no.nordicsemi.android.nrftoolbox.utility.DebugLogger;
|
||||
|
||||
/**
|
||||
* Created by rora on 10.05.2016.
|
||||
*/
|
||||
public class CGMSManager extends BleManager<CGMSManagerCallbacks> {
|
||||
private static final String TAG = "CGMSManager";
|
||||
|
||||
/** Cycling Speed and Cadence service UUID */
|
||||
public final static UUID CGMS_UUID = UUID.fromString("0000181F-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");
|
||||
/** Record Access Control Point characteristic UUID */
|
||||
private final static UUID RACP_UUID = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb");
|
||||
|
||||
private final static int OP_CODE_REPORT_STORED_RECORDS = 1;
|
||||
private final static int OP_CODE_DELETE_STORED_RECORDS = 2;
|
||||
private final static int OP_CODE_ABORT_OPERATION = 3;
|
||||
private final static int OP_CODE_REPORT_NUMBER_OF_RECORDS = 4;
|
||||
private final static int OP_CODE_NUMBER_OF_STORED_RECORDS_RESPONSE = 5;
|
||||
private final static int OP_CODE_RESPONSE_CODE = 6;
|
||||
|
||||
private final static int OPERATOR_NULL = 0;
|
||||
private final static int OPERATOR_ALL_RECORDS = 1;
|
||||
private final static int OPERATOR_LESS_THEN_OR_EQUAL = 2;
|
||||
private final static int OPERATOR_GREATER_THEN_OR_EQUAL = 3;
|
||||
private final static int OPERATOR_WITHING_RANGE = 4;
|
||||
private final static int OPERATOR_FIRST_RECORD = 5;
|
||||
private final static 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 final static 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 final static int FILTER_TYPE_USER_FACING_TIME = 2;
|
||||
private final static int RESPONSE_SUCCESS = 1;
|
||||
private final static int RESPONSE_OP_CODE_NOT_SUPPORTED = 2;
|
||||
private final static int RESPONSE_INVALID_OPERATOR = 3;
|
||||
private final static int RESPONSE_OPERATOR_NOT_SUPPORTED = 4;
|
||||
private final static int RESPONSE_INVALID_OPERAND = 5;
|
||||
private final static int RESPONSE_NO_RECORDS_FOUND = 6;
|
||||
private final static int RESPONSE_ABORT_UNSUCCESSFUL = 7;
|
||||
private final static int RESPONSE_PROCEDURE_NOT_COMPLETED = 8;
|
||||
private final static int RESPONSE_OPERAND_NOT_SUPPORTED = 9;
|
||||
|
||||
private final static SimpleDateFormat mTimeFormat= new SimpleDateFormat("dd MM YYYY HH:mm:ss");
|
||||
|
||||
private BluetoothGattCharacteristic mCGMMEasurementCharacteristic;
|
||||
private BluetoothGattCharacteristic mCGMOpsControlPointCharacteristic;
|
||||
private BluetoothGattCharacteristic mRecordAccessControlPointCharacteristic;
|
||||
|
||||
private static CGMSManager managerInstance = null;
|
||||
private SparseArray<CGMSRecord> mRecords = new SparseArray<>();
|
||||
private boolean mAbort;
|
||||
private long mSessionStartTime;
|
||||
|
||||
/**
|
||||
* singleton implementation of HRSManager class
|
||||
*/
|
||||
public static synchronized CGMSManager getInstance(final Context context) {
|
||||
if (managerInstance == null) {
|
||||
managerInstance = new CGMSManager(context);
|
||||
}
|
||||
return managerInstance;
|
||||
}
|
||||
public CGMSManager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BleManagerGattCallback getGattCallback() {
|
||||
return mGattCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* BluetoothGatt callbacks for connection/disconnection, service discovery, receiving notification, etc
|
||||
*/
|
||||
private final BleManagerGattCallback mGattCallback = new BleManagerGattCallback() {
|
||||
|
||||
@Override
|
||||
protected Queue<Request> initGatt(final BluetoothGatt gatt) {
|
||||
final LinkedList<Request> requests = new LinkedList<>();
|
||||
requests.push(Request.newEnableNotificationsRequest(mCGMMEasurementCharacteristic));
|
||||
if (mCGMOpsControlPointCharacteristic != null) {
|
||||
mSessionStartTime = System.currentTimeMillis();
|
||||
requests.push(Request.newWriteRequest(mCGMOpsControlPointCharacteristic, new byte[]{26} /*start session value*/));
|
||||
}
|
||||
requests.push(Request.newEnableIndicationsRequest(mRecordAccessControlPointCharacteristic));
|
||||
return requests;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isRequiredServiceSupported(final BluetoothGatt gatt) {
|
||||
final BluetoothGattService service = gatt.getService(CGMS_UUID);
|
||||
if (service != null) {
|
||||
mCGMMEasurementCharacteristic = service.getCharacteristic(CGM_MEASUREMENT_UUID);
|
||||
mCGMOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
|
||||
mRecordAccessControlPointCharacteristic = service.getCharacteristic(RACP_UUID);
|
||||
}
|
||||
return mCGMMEasurementCharacteristic != null && mCGMOpsControlPointCharacteristic != null && mRecordAccessControlPointCharacteristic != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isOptionalServiceSupported(final BluetoothGatt gatt) {
|
||||
final BluetoothGattService service = gatt.getService(CGMS_UUID);
|
||||
if (service != null) {
|
||||
mCGMOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID);
|
||||
}
|
||||
return mCGMOpsControlPointCharacteristic != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDeviceDisconnected() {
|
||||
mCGMOpsControlPointCharacteristic = null;
|
||||
mCGMMEasurementCharacteristic = null;
|
||||
//mRecordAccessControlPointCharacteristic = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCharacteristicNotified(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
|
||||
final UUID uuid = characteristic.getUuid();
|
||||
if(CGM_MEASUREMENT_UUID.equals(uuid)) {
|
||||
if (mLogSession != null)
|
||||
Logger.a(mLogSession, HeartRateMeasurementParser.parse(characteristic));
|
||||
byte [] data = characteristic.getValue();
|
||||
int cgmSize = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0);
|
||||
float cgmValue;
|
||||
int timeOffset;
|
||||
if (cgmSize > 0) {
|
||||
cgmValue = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, 2);
|
||||
timeOffset = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 4);
|
||||
Date date = new Date(mSessionStartTime + (timeOffset * 3600));
|
||||
final String timeStamp = mTimeFormat.format(date);
|
||||
//This will send callback to CGMSActivity when new concentration value is received from CGMS device
|
||||
mCallbacks.onCGMValueReceived(cgmValue, timeStamp);
|
||||
}
|
||||
} else if (CGM_OPS_CONTROL_POINT_UUID.equals(uuid)){
|
||||
Log.v(TAG, "CGM Ops control");
|
||||
} else if (RACP_UUID.equals(uuid)){
|
||||
Log.v(TAG, "RACP Ops control");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCharacteristicIndicated(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
|
||||
if (mLogSession != null)
|
||||
Logger.a(mLogSession, RecordAccessControlPointParser.parse(characteristic));
|
||||
|
||||
// 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(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();
|
||||
}
|
||||
} 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();
|
||||
else
|
||||
mCallbacks.onOperationAborted();
|
||||
break;
|
||||
case RESPONSE_NO_RECORDS_FOUND:
|
||||
mCallbacks.onOperationCompleted();
|
||||
break;
|
||||
case RESPONSE_OP_CODE_NOT_SUPPORTED:
|
||||
mCallbacks.onOperationNotSupported();
|
||||
break;
|
||||
case RESPONSE_PROCEDURE_NOT_COMPLETED:
|
||||
case RESPONSE_ABORT_UNSUCCESSFUL:
|
||||
default:
|
||||
mCallbacks.onOperationFailed();
|
||||
break;
|
||||
}
|
||||
mAbort = false;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void getLastRecord() {
|
||||
if (mRecordAccessControlPointCharacteristic == null)
|
||||
return;
|
||||
|
||||
clear();
|
||||
mCallbacks.onOperationStarted();
|
||||
|
||||
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
|
||||
setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_LAST_RECORD);
|
||||
writeCharacteristic(characteristic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all records as a sparse array where sequence number is the key.
|
||||
*
|
||||
* @return the records list
|
||||
*/
|
||||
public SparseArray<CGMSRecord> getRecords() {
|
||||
return mRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the records list locally
|
||||
*/
|
||||
public void clear() {
|
||||
mRecords.clear();
|
||||
mCallbacks.onDatasetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void getFirstRecord() {
|
||||
if (mRecordAccessControlPointCharacteristic == null)
|
||||
return;
|
||||
|
||||
clear();
|
||||
mCallbacks.onOperationStarted();
|
||||
|
||||
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
|
||||
setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_FIRST_RECORD);
|
||||
final LinkedList<Request> requests = new LinkedList<>();
|
||||
writeCharacteristic(characteristic);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public void getAllRecords() {
|
||||
if (mRecordAccessControlPointCharacteristic == null)
|
||||
return;
|
||||
|
||||
clear();
|
||||
mCallbacks.onOperationStarted();
|
||||
|
||||
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
|
||||
setOpCode(characteristic, OP_CODE_REPORT_NUMBER_OF_RECORDS, OPERATOR_ALL_RECORDS);
|
||||
writeCharacteristic(characteristic);
|
||||
}
|
||||
|
||||
public void deleteAllRecords() {
|
||||
if (mRecordAccessControlPointCharacteristic == null)
|
||||
return;
|
||||
|
||||
clear();
|
||||
mCallbacks.onOperationStarted();
|
||||
|
||||
final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic;
|
||||
setOpCode(characteristic, OP_CODE_DELETE_STORED_RECORDS, OPERATOR_ALL_RECORDS);
|
||||
writeCharacteristic(characteristic);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Nordic Semiconductor
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package no.nordicsemi.android.nrftoolbox.cgms;
|
||||
|
||||
import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks;
|
||||
|
||||
/**
|
||||
* Created by rora on 10.05.2016.
|
||||
*/
|
||||
public interface CGMSManagerCallbacks extends BleManagerCallbacks {
|
||||
/**
|
||||
* Called when new CGM value has been obtained from the sensor
|
||||
*
|
||||
* @param value
|
||||
* the new value
|
||||
*/
|
||||
public void onCGMValueReceived(float value, String timeStamp);
|
||||
|
||||
|
||||
public void onOperationStarted();
|
||||
|
||||
public void onOperationCompleted();
|
||||
|
||||
public void onOperationFailed();
|
||||
|
||||
public void onOperationAborted();
|
||||
|
||||
public void onOperationNotSupported();
|
||||
|
||||
public void onDatasetChanged();
|
||||
|
||||
public void onNumberOfRecordsRequested(final int value);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package no.nordicsemi.android.nrftoolbox.cgms;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* Created by rora on 02.09.2016.
|
||||
*/
|
||||
public class CGMSRecord implements Parcelable{
|
||||
|
||||
/** Record sequence number */
|
||||
protected int sequenceNumber;
|
||||
/** The base time of the measurement */
|
||||
protected Calendar time;
|
||||
/** Time offset of the record */
|
||||
protected String timeStamp;
|
||||
protected float reading;
|
||||
|
||||
protected CGMSRecord(float cgmsValue, String timeStamp) {
|
||||
sequenceNumber = 0;
|
||||
this.timeStamp = timeStamp;
|
||||
this.reading = cgmsValue;
|
||||
}
|
||||
|
||||
protected CGMSRecord(Parcel in) {
|
||||
sequenceNumber = in.readInt();
|
||||
timeStamp = in.readString();
|
||||
reading = in.readFloat();
|
||||
}
|
||||
|
||||
public static final Creator<CGMSRecord> CREATOR = new Creator<CGMSRecord>() {
|
||||
@Override
|
||||
public CGMSRecord createFromParcel(Parcel in) {
|
||||
return new CGMSRecord(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CGMSRecord[] newArray(int size) {
|
||||
return new CGMSRecord[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int i) {
|
||||
parcel.writeInt(sequenceNumber);
|
||||
parcel.writeString(timeStamp);
|
||||
parcel.writeFloat(reading);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package no.nordicsemi.android.nrftoolbox.cgms;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.SparseArray;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import no.nordicsemi.android.nrftoolbox.R;
|
||||
|
||||
/**
|
||||
* Created by rora on 02.09.2016.
|
||||
*/
|
||||
public class CGMSRecordsAdapter extends BaseAdapter {
|
||||
|
||||
private SparseArray<CGMSRecord> mRecords;
|
||||
private LayoutInflater mInflator;
|
||||
private Context context;
|
||||
|
||||
public CGMSRecordsAdapter(Context context) {
|
||||
super();
|
||||
mRecords = new SparseArray<>();
|
||||
this.context = context;
|
||||
mInflator = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mRecords.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int i) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(final int position, View convertView, ViewGroup parent) {
|
||||
|
||||
ViewHolder viewHolder;
|
||||
if (convertView == null) {
|
||||
convertView = mInflator.inflate(R.layout.activity_feature_cgms_item, null);
|
||||
viewHolder = new ViewHolder();
|
||||
viewHolder.concentration = (TextView) convertView.findViewById(R.id.cgms_concentration);
|
||||
viewHolder.time = (TextView) convertView.findViewById(R.id.time);
|
||||
viewHolder.details = (TextView) convertView.findViewById(R.id.details);
|
||||
convertView.setTag(viewHolder);
|
||||
} else {
|
||||
viewHolder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
final CGMSRecord cgmsRecord = mRecords.get(position);
|
||||
final String concentration = String.valueOf(cgmsRecord.reading);
|
||||
|
||||
if (concentration != null && concentration.length() > 0) {
|
||||
viewHolder.concentration.setText(concentration /*+ " " + context.getString(R.string.cgms_value_unit*/);
|
||||
viewHolder.time.setText(cgmsRecord.timeStamp);
|
||||
}
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
public void addItem(CGMSRecord record) {
|
||||
mRecords.put(mRecords.size(), record);
|
||||
}
|
||||
|
||||
public SparseArray<CGMSRecord> getValues() {
|
||||
return mRecords;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mRecords.clear();
|
||||
}
|
||||
|
||||
static class ViewHolder {
|
||||
TextView time;
|
||||
TextView details;
|
||||
TextView concentration;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
package no.nordicsemi.android.nrftoolbox.cgms;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.support.v7.app.NotificationCompat;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import no.nordicsemi.android.log.Logger;
|
||||
import no.nordicsemi.android.nrftoolbox.FeaturesActivity;
|
||||
import no.nordicsemi.android.nrftoolbox.R;
|
||||
import no.nordicsemi.android.nrftoolbox.profile.BleManager;
|
||||
import no.nordicsemi.android.nrftoolbox.profile.BleProfileService;
|
||||
|
||||
/**
|
||||
* Created by rora on 05.09.2016.
|
||||
*/
|
||||
public class CGMService extends BleProfileService implements CGMSManagerCallbacks {
|
||||
private static final String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.cgms.ACTION_DISCONNECT";
|
||||
public static final String BROADCAST_CGMS_VALUES = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_CGMS_VALUES";
|
||||
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 BROADCAST_DATA_SET_CHANGED = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_DATA_SET_CHANGED";
|
||||
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 CGMSManager mManager;
|
||||
private final LocalBinder mBinder = new CGMSBinder();
|
||||
private SparseArray<CGMSRecord> mRecords = new SparseArray<>();
|
||||
|
||||
/**
|
||||
* This local binder is an interface for the bonded activity to operate with the RSC sensor
|
||||
*/
|
||||
|
||||
public class CGMSBinder extends LocalBinder {
|
||||
public SparseArray<CGMSRecord> getCgmsRecords() {
|
||||
return mRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
clear();
|
||||
if(mManager != null)
|
||||
mManager.getLastRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all records as a sparse array where sequence number is the key.
|
||||
*
|
||||
* @return the records list
|
||||
*/
|
||||
public SparseArray<CGMSRecord> getRecords() {
|
||||
return mRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the records list locally
|
||||
*/
|
||||
public void clear() {
|
||||
mRecords.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends abort operation signal to the device
|
||||
*/
|
||||
public void abort() {
|
||||
|
||||
if(mManager != null)
|
||||
mManager.abort();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 all records from glucose device. Initially we want to notify him/her 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 notification followed by Record Access Control Point indication with status code ({@link CGMSManager#RESPONSE_SUCCESS} or other in case of
|
||||
* error.
|
||||
*/
|
||||
public void getAllRecords() {
|
||||
clear();
|
||||
if(mManager != null)
|
||||
mManager.getAllRecords();
|
||||
}
|
||||
|
||||
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 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();
|
||||
}
|
||||
|
||||
@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 onServiceStarted() {
|
||||
// logger is now available. Assign it to the manager
|
||||
mManager.setLogger(getLogSession());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCGMValueReceived(float value, String timeStamp) {
|
||||
final Intent broadcast = new Intent(BROADCAST_CGMS_VALUES);
|
||||
CGMSRecord cgmsRecord = new CGMSRecord(value, timeStamp);
|
||||
broadcast.putExtra(EXTRA_CGMS_RECORD, cgmsRecord);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
mRecords.put(mRecords.size(), cgmsRecord);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationStarted() {
|
||||
final Intent broadcast = new Intent(OPERATION_STARTED);
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationCompleted() {
|
||||
final Intent broadcast = new Intent(OPERATION_COMPLETED);
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationFailed() {
|
||||
final Intent broadcast = new Intent(OPERATION_FAILED);
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationAborted() {
|
||||
final Intent broadcast = new Intent(OPERATION_ABORTED);
|
||||
broadcast.putExtra(EXTRA_DATA, true);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOperationNotSupported() {
|
||||
final Intent broadcast = new Intent(OPERATION_NOT_SUPPORTED);
|
||||
broadcast.putExtra(EXTRA_DATA, false);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDatasetChanged() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNumberOfRecordsRequested(int value) {
|
||||
showToast(getString(R.string.gls_progress, value));
|
||||
}
|
||||
}
|
||||
@@ -265,6 +265,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl
|
||||
mConnectButton.setText(R.string.action_connect);
|
||||
mDeviceNameView.setText(getDefaultDeviceName());
|
||||
mBatteryLevelView.setText(R.string.not_available);
|
||||
mConnectButton.setEnabled(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
BIN
app/src/main/res/drawable-hdpi/ic_cgms_feature.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_cgms_feature.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/drawable-hdpi/ic_stat_notify_cgms.png
Normal file
BIN
app/src/main/res/drawable-hdpi/ic_stat_notify_cgms.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 659 B |
BIN
app/src/main/res/drawable-xhdpi/ic_cgms_feature.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_cgms_feature.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
BIN
app/src/main/res/drawable-xhdpi/ic_hts_feature_black.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_hts_feature_black.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 368 B |
BIN
app/src/main/res/drawable-xhdpi/ic_stat_notify_cgms.png
Normal file
BIN
app/src/main/res/drawable-xhdpi/ic_stat_notify_cgms.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 844 B |
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".BPMActivity">
|
||||
tools:context=".bpm.BPMActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
227
app/src/main/res/layout-land/activity_feature_cgms.xml
Normal file
227
app/src/main/res/layout-land/activity_feature_cgms.xml
Normal file
@@ -0,0 +1,227 @@
|
||||
<!--
|
||||
~ Copyright (c) 2015, Nordic Semiconductor
|
||||
~ All rights reserved.
|
||||
~
|
||||
~ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
~
|
||||
~ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
~
|
||||
~ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||
~ documentation and/or other materials provided with the distribution.
|
||||
~
|
||||
~ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||
~ software without specific prior written permission.
|
||||
~
|
||||
~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
~ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
~ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
~ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
~ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
~ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".cgms.CGMSActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
layout="@layout/toolbar"/>
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.ForegroundRelativeLayout
|
||||
style="@style/HeaderShadow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- The size of text below must be fixed, therefore dp are used instead of sp -->
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.TrebuchetBoldTextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="@dimen/cgms_feature_title_long_margin"
|
||||
android:rotation="270"
|
||||
android:text="@string/cgms_feature_title_long"
|
||||
android:textColor="@color/darkGray"
|
||||
android:textSize="32dp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/battery"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginLeft="@dimen/feature_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/feature_device_name_margin_top"
|
||||
android:background="@drawable/battery"
|
||||
android:freezesText="true"
|
||||
android:gravity="center"
|
||||
android:text="@string/not_available"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.TrebuchetTextView
|
||||
android:id="@+id/device_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginTop="@dimen/feature_device_name_margin_top"
|
||||
android:layout_toRightOf="@+id/battery"
|
||||
android:ellipsize="end"
|
||||
android:freezesText="true"
|
||||
android:maxLines="1"
|
||||
android:text="@string/cgms_default_name"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@+id/action_connect"
|
||||
android:layout_marginLeft="@dimen/feature_horizontal_margin"
|
||||
android:layout_marginRight="@dimen/feature_horizontal_margin"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- Application section -->
|
||||
|
||||
<LinearLayout
|
||||
style="@style/Widget.List"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin_bottom"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginTop="@dimen/feature_vertical_margin_top"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
style="@style/Widget.ListTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.TrebuchetBoldTextView
|
||||
style="@style/Widget.ListTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/gls_section_data"/>
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.TrebuchetTextView
|
||||
android:id="@+id/unit"
|
||||
style="@style/Widget.ListTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="4dp"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
tools:listitem="@layout/activity_feature_cgms_item"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/gls_no_data"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Timestamp section -->
|
||||
|
||||
<LinearLayout
|
||||
style="@style/Widget.List"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin_bottom"
|
||||
android:layout_marginLeft="14dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:layout_marginTop="@dimen/feature_vertical_margin_top"
|
||||
android:orientation="vertical">
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.TrebuchetBoldTextView
|
||||
style="@style/Widget.ListTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/gls_section_actions"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/cgms_control_std"
|
||||
style="?android:attr/buttonBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_all"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="0dp"
|
||||
android:text="@string/gls_action_all"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_last"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="0dp"
|
||||
android:text="@string/gls_action_last"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_more"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minWidth="0dp"
|
||||
android:text="@string/gls_action_more"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/cgms_control_abort"
|
||||
style="?android:attr/buttonBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_abort"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minWidth="0dp"
|
||||
android:text="@string/gls_action_abort"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_connect"
|
||||
style="@style/Widget.Connect"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin_bottom"
|
||||
android:onClick="onConnectClicked"
|
||||
android:text="@string/action_connect"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:src="@drawable/background_title"/>
|
||||
|
||||
</no.nordicsemi.android.nrftoolbox.widget.ForegroundRelativeLayout>
|
||||
</LinearLayout>
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".CSCActivity">
|
||||
tools:context=".csc.CSCActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".DfuActivity">
|
||||
tools:context=".dfu.DfuActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".BPMActivity">
|
||||
tools:context=".hrs.HRSActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".HTSActivity">
|
||||
tools:context=".hts.HTSActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".ProximityActivity">
|
||||
tools:context=".proximity.ProximityActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".RSCActivity">
|
||||
tools:context=".rsc.RSCActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".UARTActivity">
|
||||
tools:context=".uart.UARTActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".BPMActivity">
|
||||
tools:context=".bpm.BPMActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".CSCActivity">
|
||||
tools:context=".csc.CSCActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".DfuActivity">
|
||||
tools:context=".dfu.DfuActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".BPMActivity">
|
||||
tools:context=".hrs.HRSActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".RSCActivity">
|
||||
tools:context=".rsc.RSCActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".BPMActivity">
|
||||
tools:context=".bpm.BPMActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
225
app/src/main/res/layout/activity_feature_cgms.xml
Normal file
225
app/src/main/res/layout/activity_feature_cgms.xml
Normal file
@@ -0,0 +1,225 @@
|
||||
<!--
|
||||
~ Copyright (c) 2015, Nordic Semiconductor
|
||||
~ All rights reserved.
|
||||
~
|
||||
~ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
~
|
||||
~ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
~
|
||||
~ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||
~ documentation and/or other materials provided with the distribution.
|
||||
~
|
||||
~ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||
~ software without specific prior written permission.
|
||||
~
|
||||
~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
~ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
~ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
~ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
~ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
~ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
layout="@layout/toolbar"/>
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.ForegroundRelativeLayout
|
||||
style="@style/HeaderShadow"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- The size of text below must be fixed, therefore dp are used instead of sp -->
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.TrebuchetBoldTextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="@dimen/cgms_feature_title_long_margin"
|
||||
android:rotation="270"
|
||||
android:text="@string/cgms_feature_title_long"
|
||||
android:textColor="@color/darkGray"
|
||||
android:textSize="32dp"
|
||||
android:textStyle="bold"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/battery"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginLeft="@dimen/feature_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/feature_device_name_margin_top"
|
||||
android:background="@drawable/battery"
|
||||
android:freezesText="true"
|
||||
android:gravity="center"
|
||||
android:text="@string/not_available"
|
||||
android:textColor="#FFFFFF"
|
||||
android:textSize="12sp"/>
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.TrebuchetTextView
|
||||
android:id="@+id/device_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginTop="@dimen/feature_device_name_margin_top"
|
||||
android:layout_toRightOf="@+id/battery"
|
||||
android:ellipsize="end"
|
||||
android:freezesText="true"
|
||||
android:maxLines="1"
|
||||
android:text="@string/cgms_default_name"
|
||||
android:textAllCaps="true"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"/>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@+id/action_connect"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- Application section -->
|
||||
|
||||
<LinearLayout
|
||||
style="@style/Widget.List"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginLeft="@dimen/feature_horizontal_margin"
|
||||
android:layout_marginRight="@dimen/feature_horizontal_margin"
|
||||
android:layout_marginTop="@dimen/feature_vertical_margin_top"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<RelativeLayout
|
||||
style="@style/Widget.ListTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.TrebuchetBoldTextView
|
||||
style="@style/Widget.ListTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/gls_section_data"/>
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.TrebuchetTextView
|
||||
android:id="@+id/unit"
|
||||
style="@style/Widget.ListTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="4dp"/>
|
||||
</RelativeLayout>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
tools:listitem="@layout/activity_feature_gls_item"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/gls_no_data"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Timestamp section -->
|
||||
|
||||
<LinearLayout
|
||||
style="@style/Widget.List"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin_bottom"
|
||||
android:layout_marginLeft="@dimen/feature_horizontal_margin"
|
||||
android:layout_marginRight="@dimen/feature_horizontal_margin"
|
||||
android:layout_marginTop="15dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.TrebuchetBoldTextView
|
||||
style="@style/Widget.ListTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/gls_section_actions"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/cgms_control_std"
|
||||
style="?android:attr/buttonBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_all"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minWidth="0dp"
|
||||
android:text="@string/gls_action_all"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_last"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minWidth="0dp"
|
||||
android:text="@string/gls_action_last"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_more"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minWidth="0dp"
|
||||
android:text="@string/gls_action_more"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/cgms_control_abort"
|
||||
style="?android:attr/buttonBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_abort"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:minWidth="0dp"
|
||||
android:text="@string/gls_action_abort"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_connect"
|
||||
style="@style/Widget.Connect"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginBottom="@dimen/activity_vertical_margin_bottom"
|
||||
android:onClick="onConnectClicked"
|
||||
android:text="@string/action_connect"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:src="@drawable/background_title"/>
|
||||
|
||||
</no.nordicsemi.android.nrftoolbox.widget.ForegroundRelativeLayout>
|
||||
</LinearLayout>
|
||||
71
app/src/main/res/layout/activity_feature_cgms_item.xml
Normal file
71
app/src/main/res/layout/activity_feature_cgms_item.xml
Normal file
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2015, Nordic Semiconductor
|
||||
~ All rights reserved.
|
||||
~
|
||||
~ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
~
|
||||
~ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
~
|
||||
~ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||
~ documentation and/or other materials provided with the distribution.
|
||||
~
|
||||
~ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||
~ software without specific prior written permission.
|
||||
~
|
||||
~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
~ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
~ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
~ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
~ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
~ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:attr/listPreferredItemHeightSmall"
|
||||
android:paddingBottom="2dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingLeft"
|
||||
android:paddingTop="2dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/details"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textSize="12sp"
|
||||
android:text="@string/cgms_item_summary"/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cgms_concentration"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:layout_centerVertical="true"
|
||||
android:gravity="right"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingLeft"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cgms_unit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:text="@string/cgms_value_unit"/>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".CSCActivity">
|
||||
tools:context=".csc.CSCActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".DfuActivity">
|
||||
tools:context=".dfu.DfuActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".HRSActivity">
|
||||
tools:context=".hrs.HRSActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".HTSActivity">
|
||||
tools:context=".hts.HTSActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".ProximityActivity">
|
||||
tools:context=".proximity.ProximityActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".RSCActivity">
|
||||
tools:context=".rsc.RSCActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".TemplateActivity">
|
||||
tools:context=".template.TemplateActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".UARTActivity">
|
||||
tools:context=".uart.UARTActivity">
|
||||
|
||||
<include
|
||||
android:id="@+id/toolbar_actionbar"
|
||||
|
||||
@@ -44,6 +44,13 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:src="@drawable/background_title"/>
|
||||
|
||||
<GridView
|
||||
android:id="@+id/grid"
|
||||
android:layout_width="match_parent"
|
||||
@@ -60,13 +67,6 @@
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:stretchMode="columnWidth"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|center"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:src="@drawable/background_title"/>
|
||||
|
||||
<no.nordicsemi.android.nrftoolbox.widget.TrebuchetBoldTextView
|
||||
android:id="@android:id/empty"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
29
app/src/main/res/values-land/strings_cgms.xml
Normal file
29
app/src/main/res/values-land/strings_cgms.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2016, Nordic Semiconductor
|
||||
~ All rights reserved.
|
||||
~
|
||||
~ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
~
|
||||
~ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
~
|
||||
~ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||
~ documentation and/or other materials provided with the distribution.
|
||||
~
|
||||
~ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||
~ software without specific prior written permission.
|
||||
~
|
||||
~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
~ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
~ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
~ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
~ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
~ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="cgms_feature_title_long">CGMS</string>
|
||||
<string name="text_cgms_interval">GCM updates are notified every minute</string>
|
||||
<string name="cgms_item_summary">Glucose concentration level</string>
|
||||
<dimen name="cgms_feature_title_long_margin">-16dp</dimen>
|
||||
</resources>
|
||||
@@ -37,7 +37,7 @@
|
||||
<string name="action_select">SELECT DEVICE</string>
|
||||
<string name="action_connecting">CONNECTING…</string>
|
||||
<string name="action_disconnect">DISCONNECT</string>
|
||||
|
||||
|
||||
<string name="drawer_open">Open</string>
|
||||
<string name="drawer_close">Close</string>
|
||||
<string name="drawer_plugins">PLUGINS</string>
|
||||
|
||||
37
app/src/main/res/values/strings_cgms.xml
Normal file
37
app/src/main/res/values/strings_cgms.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2016, Nordic Semiconductor
|
||||
~ All rights reserved.
|
||||
~
|
||||
~ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
~
|
||||
~ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
~
|
||||
~ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
|
||||
~ documentation and/or other materials provided with the distribution.
|
||||
~
|
||||
~ 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this
|
||||
~ software without specific prior written permission.
|
||||
~
|
||||
~ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
~ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
~ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
~ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
~ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
~ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<string name="cgms_feature_title">CGMS</string>
|
||||
<string name="cgms_feature_title_long">CONT. GLUCOSE MONITOR</string>
|
||||
<dimen name="cgms_feature_title_long_margin">-180dp</dimen>
|
||||
|
||||
<string name="cgms_default_name">DEFAULT CGMS</string>
|
||||
<string name="cgms_value_unit">mg/dL</string>
|
||||
<string name="cgms_position_label">sensor position</string>
|
||||
|
||||
<string name="cgms_about_text">CGMS (Continuous Glucode Monitoring Service) profile allows you to connect to your Continuous Glucose Monitoring sensor.
|
||||
It shows you the continuous glucose measurement on the table.</string>
|
||||
<string name="text_cgms_interval">GCM updates are notified every minute</string>
|
||||
<string name="cgms_item_summary">Glucose concentration level</string>
|
||||
</resources>
|
||||
@@ -9,8 +9,8 @@ android {
|
||||
applicationId "no.nordicsemi.android.nrftoolbox"
|
||||
minSdkVersion 20
|
||||
targetSdkVersion 24
|
||||
versionCode 45
|
||||
versionName "1.17.0"
|
||||
versionCode 47
|
||||
versionName "1.18.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
|
||||
Reference in New Issue
Block a user