Skip to content
Snippets Groups Projects
Commit 24758c26 authored by jgwashburn@gmail.com's avatar jgwashburn@gmail.com
Browse files

Merge remote-tracking branch 'upstream/master'

Conflicts:
	app/app.iml
	app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java
	app/src/main/res/layout/activity_login.xml
parents 64ad8c07 084cebf7
No related branches found
No related tags found
No related merge requests found
Showing
with 267 additions and 501 deletions
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="640gAndroidUploader" external.system.module.version="0.4.0-SNAPSHOT" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/fabric/res/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/animated-vector-drawable/23.4.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.4.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/23.4.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.4.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.4.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-vector-drawable/23.4.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.bugfender.sdk/android/0.4.4/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.crashlytics.sdk.android/answers/1.3.10/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.crashlytics.sdk.android/beta/1.2.2/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.crashlytics.sdk.android/crashlytics-core/2.3.14/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.crashlytics.sdk.android/crashlytics/2.6.5/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.getkeepsafe.relinker/relinker/1.2.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.github.PhilJay/MPAndroidChart-Realm/v1.1.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.mikepenz/fastadapter/1.5.2/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.mikepenz/google-material-typeface/2.2.0.1.original/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.mikepenz/iconics-core/2.6.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.mikepenz/materialdrawer/5.2.9/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.mikepenz/materialize/0.8.8/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/io.fabric.sdk.android/fabric/1.3.14/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/io.realm/realm-android-library/1.0.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/uk.co.chrisjenx/calligraphy/2.2.0/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
</content>
<orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="okio-1.8.0" level="project" />
<orderEntry type="library" exported="" name="support-annotations-23.4.0" level="project" />
<orderEntry type="library" exported="" name="google-material-typeface-2.2.0.1.original" level="project" />
<orderEntry type="library" exported="" name="okhttp-2.4.0" level="project" />
<orderEntry type="library" exported="" name="relinker-1.2.1" level="project" />
<orderEntry type="library" exported="" name="retrofit-1.9.0" level="project" />
<orderEntry type="library" exported="" name="realm-annotations-1.0.0" level="project" />
<orderEntry type="library" exported="" name="crashlytics-core-2.3.14" level="project" />
<orderEntry type="library" exported="" name="animated-vector-drawable-23.4.0" level="project" />
<orderEntry type="library" exported="" name="commons-lang3-3.4" level="project" />
<orderEntry type="library" exported="" name="support-v4-23.4.0" level="project" />
<orderEntry type="library" exported="" name="recyclerview-v7-23.4.0" level="project" />
<orderEntry type="library" exported="" name="slf4j-api-1.7.2" level="project" />
<orderEntry type="library" exported="" name="support-vector-drawable-23.4.0" level="project" />
<orderEntry type="library" exported="" name="materialize-0.8.8" level="project" />
<orderEntry type="library" exported="" name="realm-android-library-1.0.0" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-23.4.0" level="project" />
<orderEntry type="library" exported="" name="design-23.4.0" level="project" />
<orderEntry type="library" exported="" name="android-0.4.4" level="project" />
<orderEntry type="library" exported="" name="fabric-1.3.14" level="project" />
<orderEntry type="library" exported="" name="MPAndroidChart-v3.0.0-beta1" level="project" />
<orderEntry type="library" exported="" name="crashlytics-2.6.5" level="project" />
<orderEntry type="library" exported="" name="beta-1.2.2" level="project" />
<orderEntry type="library" exported="" name="fastadapter-1.5.2" level="project" />
<orderEntry type="library" exported="" name="gson-2.7" level="project" />
<orderEntry type="library" exported="" name="retrofit-2.1.0" level="project" />
<orderEntry type="library" exported="" name="converter-gson-2.1.0" level="project" />
<orderEntry type="library" exported="" name="answers-1.3.10" level="project" />
<orderEntry type="library" exported="" name="materialdrawer-5.2.9" level="project" />
<orderEntry type="library" exported="" name="MPAndroidChart-Realm-v1.1.0" level="project" />
<orderEntry type="library" exported="" name="calligraphy-2.2.0" level="project" />
<orderEntry type="library" exported="" name="okhttp-3.3.0" level="project" />
<orderEntry type="library" exported="" name="iconics-core-2.6.0" level="project" />
<orderEntry type="library" exported="" name="org.apache.http.legacy-android-23" level="project" />
</component>
</module>
\ No newline at end of file
import org.ajoberstar.grgit.Grgit
buildscript {
repositories {
maven { url 'https://maven.fabric.io/public' }
......@@ -5,7 +7,8 @@ buildscript {
dependencies {
classpath 'io.fabric.tools:gradle:1.21.6'
classpath 'io.realm:realm-gradle-plugin:1.1.0'
classpath 'io.realm:realm-gradle-plugin:1.1.1'
classpath 'org.ajoberstar:grgit:1.5.0'
}
}
plugins {
......@@ -23,8 +26,25 @@ apply plugin: 'io.fabric'
apply plugin: 'realm-android'
def gitVersion() {
def process = ['sh', '-c', 'git tag -l | grep -c ".*" -'].execute().text.trim()
return process.toInteger() + 1
// current dir is <your proj>/app, so it's likely that all your git repo files are in the dir
// above.
ext.repo = Grgit.open(project.file('..'))
// should result in the same value as running
// git tag -l | wc -l or git tag -l | grep -c ".*" -
def numOfTags = ext.repo.tag.list().size()
return numOfTags
}
def gitCommitId() {
//def process = ['sh', '-c', 'git tag -l | grep -c ".*" -'].execute().text.trim()
//return process.toInteger() + 1
//return 42
// current dir is <your proj>/app, so it's likely that all your git repo files are in the dir
// above.
ext.repo = Grgit.open(project.file('..'))
return ext.repo.log().first().id.substring(0, 7)
}
def getBugfenderApiKey() {
......@@ -47,7 +67,7 @@ android {
applicationId "info.nightscout.android"
minSdkVersion 14
targetSdkVersion 23
versionName project.properties['version']
versionName project.properties['version'] + "/" + gitCommitId()
versionCode gitVersion()
buildConfigField "String", "BUGFENDER_API_KEY", getBugfenderApiKey()
}
......@@ -134,7 +154,7 @@ dependencies {
compile 'org.apache.commons:commons-lang3:3.4'
compile 'com.mikepenz:google-material-typeface:2.2.0.1.original@aar'
compile 'uk.co.chrisjenx:calligraphy:2.2.0'
compile 'com.bugfender.sdk:android:0.4.4'
compile 'com.bugfender.sdk:android:0.6.2'
compile 'com.github.PhilJay:MPAndroidChart:v3.0.0-beta1'
compile 'com.github.PhilJay:MPAndroidChart-Realm:v1.1.0@aar'
compile 'com.android.support:support-v4:23.4.0'
......
version=0.4.0-SNAPSHOT
version=0.5.0-SNAPSHOT
......@@ -18,6 +18,9 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.USB_PERMISSION" />
<!-- allow to disable battery optimization -->
<uses-permission-sdk-23 android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<application
android:name=".UploaderApplication"
android:allowBackup="true"
......@@ -26,6 +29,7 @@
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- I have set screenOrientation to "portrait" to avoid the restart of AsyncTasks when you rotate the phone -->
<activity
android:name=".medtronic.MainActivity"
......@@ -64,24 +68,27 @@
android:label="@string/title_activity_login"
android:theme="@style/SettingsTheme" />
<activity android:name=".medtronic.StatusActivity" />
<service
android:name=".upload.nightscout.NightscoutUploadIntentService"
android:icon="@drawable/ic_launcher" />
<service
android:name=".xdrip_plus.XDripPlusUploadIntentService"
android:icon="@drawable/ic_launcher" />
<service
android:name=".medtronic.service.MedtronicCnlIntentService"
android:icon="@drawable/ic_launcher" />
<activity android:name=".medtronic.StatusActivity" />
<receiver android:name=".medtronic.service.MedtronicCnlAlarmReceiver" />
<receiver android:name=".upload.nightscout.NightscoutUploadReceiver" />
<receiver android:name=".xdrip_plus.XDripPlusUploadReceiver" />
<receiver android:name=".medtronic.service.MedtronicCnlAlarmReceiver"></receiver>
<meta-data
android:name="io.fabric.ApiKey"
android:value="FABRIC_API_KEY_VALUE" />
android:value="aa26e770bd4f7480eed7cabb63a84363ecd12009" />
</application>
</manifest>
\ No newline at end of file
......@@ -62,20 +62,8 @@ import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper;
*/
public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCallbacks<Cursor> {
/**
* Keep track of the login task to ensure we can cancel it if requested.
*/
// TODO - Replace with Rx.Java
private GetHmacAndKey mHmacAndKeyTask = null;
// UI references.
private EditText mUsernameView;
private EditText mPasswordView;
private EditText mHostnameView;
private View mProgressView;
private View mLoginFormView;
private TextView mRegisteredStickView;
private MenuItem mLoginMenuItem;
@Override
protected void onCreate(Bundle savedInstanceState) {
......@@ -83,35 +71,8 @@ public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCa
setContentView(R.layout.activity_login);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle("Register USB");
// Set up the login form.
mUsernameView = (EditText) findViewById(R.id.username);
mPasswordView = (EditText) findViewById(R.id.password);
mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
if (id == EditorInfo.IME_ACTION_DONE) {
attemptLogin();
return true;
}
return false;
}
});
mHostnameView = (EditText) findViewById(R.id.hostname);
mHostnameView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
attemptLogin();
return true;
}
});
getSupportActionBar().setTitle("Registered Devices");
mLoginFormView = findViewById(R.id.login_form);
mProgressView = findViewById(R.id.login_progress);
mRegisteredStickView = (TextView) findViewById(R.id.registered_usb_devices);
showRegisteredSticks();
......@@ -119,21 +80,12 @@ public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCa
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_register_usb, menu);
mLoginMenuItem = menu.findItem(R.id.action_menu_login);
mLoginMenuItem.setIcon(new IconicsDrawable(this, GoogleMaterial.Icon.gmd_cloud_download).color(Color.WHITE).actionBar());
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_menu_login:
attemptLogin();
break;
case android.R.id.home:
finish();
break;
......@@ -146,103 +98,13 @@ public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCa
super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase));
}
/**
* Attempts to sign in or register the account specified by the login form.
* If there are form errors (invalid username, missing fields, etc.), the
* errors are presented and no actual login attempt is made.
*/
private void attemptLogin() {
if (mHmacAndKeyTask != null || !checkOnline("Please connect to the Internet", "You must be online to register your USB stick.")) {
return;
}
// Reset errors.
mUsernameView.setError(null);
mPasswordView.setError(null);
mHostnameView.setError(null);
// Store values at the time of the login attempt.
String username = mUsernameView.getText().toString();
String password = mPasswordView.getText().toString();
String hostname = mHostnameView.getText().toString();
boolean cancel = false;
View focusView = null;
// Check for a valid password, if the user entered one.
if (TextUtils.isEmpty(password)) {
mPasswordView.setError(getString(R.string.error_invalid_password));
focusView = mPasswordView;
cancel = true;
}
// Check for a valid username address.
if (TextUtils.isEmpty(username)) {
mUsernameView.setError(getString(R.string.error_field_required));
focusView = mUsernameView;
cancel = true;
}
// Check for a carelink server hostname (this is optional for a user to define)
if (TextUtils.isEmpty(hostname)) {
hostname = getString(R.string.server_hostname); // default
}
if (cancel) {
// There was an error; don't attempt login and focus the first
// form field with an error.
focusView.requestFocus();
} else {
// Show a progress spinner, and kick off a background task to
// perform the user login attempt.
showProgress(true);
mHmacAndKeyTask = new GetHmacAndKey(username, password, hostname);
mHmacAndKeyTask.execute((Void) null);
}
}
/**
* Shows the progress UI and hides the login form.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
private void showProgress(final boolean show) {
// On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
// for very easy animations. If available, use these APIs to fade-in
// the progress spinner.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
mLoginFormView.animate().setDuration(shortAnimTime).alpha(
show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
});
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mProgressView.animate().setDuration(shortAnimTime).alpha(
show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
}
});
} else {
// The ViewPropertyAnimator APIs are not available, so simply show
// and hide the relevant UI components.
mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
}
}
private void showRegisteredSticks() {
Realm realm = Realm.getDefaultInstance();
RealmResults<ContourNextLinkInfo> results = realm.where(ContourNextLinkInfo.class).findAll();
String deviceTableHtml = "<big><b>Registered Devices</b></big><br/>";
String deviceTableHtml = "";
for (ContourNextLinkInfo info : results) {
String longSerial = info.getSerialNumber();
......@@ -254,29 +116,6 @@ public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCa
mRegisteredStickView.setText(Html.fromHtml(deviceTableHtml));
}
private boolean checkOnline(String title, String message) {
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo netInfo = cm.getActiveNetworkInfo();
boolean isOnline = (netInfo != null && netInfo.isConnectedOrConnecting());
if (!isOnline) {
new AlertDialog.Builder(this, R.style.AppTheme)
.setTitle(title)
.setMessage(message)
.setCancelable(false)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
return isOnline;
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return null;
......@@ -290,129 +129,5 @@ public class GetHmacAndKeyActivity extends AppCompatActivity implements LoaderCa
public void onLoaderReset(Loader<Cursor> loader) {
}
/**
* Represents an asynchronous login/registration task used to authenticate
* the user.
*/
public class GetHmacAndKey extends AsyncTask<Void, Void, Boolean> {
private final String mUsername;
private final String mPassword;
private final String mHostname;
// Note: if AsyncTask declaration can be located and changed,
// then we can pass status to onPostExecute() in return value
// from doInBackground()
// and not have to store it this way.
private String mStatus = "success";
GetHmacAndKey(String username, String password, String hostname) {
mUsername = username;
mPassword = password;
mHostname = hostname;
}
@Override
protected Boolean doInBackground(final Void... params) {
HttpResponse response;
try {
DefaultHttpClient client = new DefaultHttpClient();
HttpPost loginPost = new HttpPost(mHostname + "/patient/j_security_check");
List<NameValuePair> nameValuePairs = new ArrayList<>();
nameValuePairs.add(new BasicNameValuePair("j_username", mUsername));
nameValuePairs.add(new BasicNameValuePair("j_password", mPassword));
nameValuePairs.add(new BasicNameValuePair("j_character_encoding", "UTF-8"));
loginPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
response = client.execute(loginPost);
if (response.getStatusLine().getStatusCode() == 200) {
// Get the HMAC/keys for every serial we have seen
Realm realm = Realm.getDefaultInstance();
RealmResults<ContourNextLinkInfo> results = realm.where(ContourNextLinkInfo.class).findAll();
for (ContourNextLinkInfo info : results) {
String longSerial = info.getSerialNumber();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ObjectOutputStream hmacRequest = new ObjectOutputStream(buffer);
hmacRequest.writeInt(0x1c);
hmacRequest.writeObject(longSerial.replaceAll("\\d+-", ""));
HttpPost hmacPost = new HttpPost(mHostname + "/patient/secure/SnapshotServer/");
hmacPost.setEntity(new ByteArrayEntity(buffer.toByteArray()));
hmacPost.setHeader("Content-type", "application/octet-stream");
response = client.execute(hmacPost);
ByteArrayInputStream inputBuffer = new ByteArrayInputStream(EntityUtils.toByteArray(response.getEntity()));
ObjectInputStream hmacResponse = new ObjectInputStream(inputBuffer);
byte[] hmacBytes = (byte[]) hmacResponse.readObject();
ArrayUtils.reverse(hmacBytes);
String hmac = MessageUtils.byteArrayToHexString(hmacBytes);
buffer.reset();
inputBuffer.reset();
ObjectOutputStream keyRequest = new ObjectOutputStream(buffer);
keyRequest.writeInt(0x1f);
keyRequest.writeObject(longSerial);
HttpPost keyPost = new HttpPost(mHostname + "/patient/secure/SnapshotServer/");
keyPost.setEntity(new ByteArrayEntity(buffer.toByteArray()));
keyPost.setHeader("Content-type", "application/octet-stream");
response = client.execute(keyPost);
inputBuffer = new ByteArrayInputStream(EntityUtils.toByteArray(response.getEntity()));
ObjectInputStream keyResponse = new ObjectInputStream(inputBuffer);
keyResponse.readInt(); // Throw away the first int. Not sure what it does
String key = MessageUtils.byteArrayToHexString((byte[]) keyResponse.readObject());
realm.beginTransaction();
info.setHmac(hmac);
info.setKey(key);
realm.commitTransaction();
}
return true;
}
} catch (ClientProtocolException e) {
mStatus = getString(R.string.error_client_protocol_exception);
return false;
} catch (IOException e) {
mStatus = getString(R.string.error_io_exception);
return false;
} catch (ClassNotFoundException e) {
mStatus = getString(R.string.error_class_not_found_exception);
return false;
}
mStatus = getString(R.string.error_http_response) + "http response: " + response.getStatusLine();
return false;
}
@Override
protected void onPostExecute(final Boolean success) {
mHmacAndKeyTask = null;
if (success) {
showRegisteredSticks();
mLoginMenuItem.setVisible(false);
mLoginFormView.setVisibility(View.GONE);
mProgressView.setVisibility(View.GONE);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mLoginFormView.getWindowToken(), 0);
} else {
showProgress(false);
mPasswordView.setError(mStatus);
mPasswordView.requestFocus();
}
}
@Override
protected void onCancelled() {
mHmacAndKeyTask = null;
showProgress(false);
}
}
}
......@@ -3,6 +3,7 @@ package info.nightscout.android.medtronic;
import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
......@@ -12,11 +13,14 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.support.v4.app.TaskStackBuilder;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AlertDialog;
......@@ -107,6 +111,28 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
stopCgmService();
}
// Disable battery optimization to avoid missing values on 6.0+
// taken from https://github.com/NightscoutFoundation/xDrip/blob/master/app/src/main/java/com/eveningoutpost/dexdrip/Home.java#L277L298
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final String packageName = getPackageName();
//Log.d(TAG, "Maybe ignoring battery optimization");
final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
Log.d(TAG, "Requesting ignore battery optimization");
try {
// ignoring battery optimizations required for constant connection
// to peripheral device - eg CGM transmitter.
final Intent intent = new Intent();
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.d(TAG, "Device does not appear to support battery optimization whitelisting!");
}
}
}
LocalBroadcastManager.getInstance(this).registerReceiver(
statusMessageReceiver,
new IntentFilter(MedtronicCnlIntentService.Constants.ACTION_STATUS_MESSAGE));
......@@ -149,7 +175,7 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
.withIcon(GoogleMaterial.Icon.gmd_settings)
.withSelectable(false);
final PrimaryDrawerItem itemRegisterUsb = new PrimaryDrawerItem()
.withName("Register Contour Next Link")
.withName("Registered Devices")
.withIcon(GoogleMaterial.Icon.gmd_usb)
.withSelectable(false);
final PrimaryDrawerItem itemStopCollecting = new PrimaryDrawerItem()
......@@ -246,8 +272,8 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
private boolean hasDetectedCnl() {
if (mRealm.where(ContourNextLinkInfo.class).count() == 0) {
new AlertDialog.Builder(this, R.style.AppTheme)
.setTitle("Contour Next Link not detected")
.setMessage("To register a Contour Next Link you must first plug it in.")
.setTitle("No registered Contour Next Link devices")
.setMessage("To register a Contour Next Link you must first plug it in, and get a reading from the pump.")
.setCancelable(false)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
......@@ -266,7 +292,6 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
UsbDevice cnlDevice = UsbHidDriver.getUsbDevice(usbManager, MedtronicCnlIntentService.USB_VID, MedtronicCnlIntentService.USB_PID);
return !(usbManager != null && cnlDevice != null && !usbManager.hasPermission(cnlDevice));
}
private void waitForUsbPermission() {
......@@ -305,7 +330,7 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
}
private void startCgmService() {
startCgmService(System.currentTimeMillis());
startCgmService(System.currentTimeMillis() + 1000);
}
private void startCgmService(long initialPoll) {
......@@ -524,8 +549,6 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
private class RefreshDisplayRunnable implements Runnable {
@Override
public void run() {
Log.d(TAG, "NOW " + new Date(System.currentTimeMillis()).toString());
// UI elements - TODO do these need to be members?
TextView textViewBg = (TextView) findViewById(R.id.textview_bg);
TextView textViewBgTime = (TextView) findViewById(R.id.textview_bg_time);
......@@ -630,11 +653,9 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
return;
}
long nextPoll = pumpStatusData.getEventDate().getTime() + MedtronicCnlIntentService.POLL_GRACE_PERIOD_MS + MedtronicCnlIntentService.POLL_PERIOD_MS;
long nextPoll = pumpStatusData.getEventDate().getTime() + pumpStatusData.getPumpTimeOffset()
+ MedtronicCnlIntentService.POLL_GRACE_PERIOD_MS + MedtronicCnlIntentService.POLL_PERIOD_MS;
startCgmService(nextPoll);
Log.d(TAG, "Local time " + new Date());
Log.d(TAG, "Last event was " + new Date(pumpStatusData.getEventDate().getTime()));
Log.d(TAG, "Next Poll at " + new Date(nextPoll).toString());
// Delete invalid or old records from Realm
// TODO - show an error message if the valid records haven't been uploaded
......
......@@ -9,6 +9,7 @@ import java.io.IOException;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
......@@ -36,6 +37,7 @@ import info.nightscout.android.medtronic.message.PumpStatusResponseMessage;
import info.nightscout.android.medtronic.message.PumpTimeRequestMessage;
import info.nightscout.android.medtronic.message.PumpTimeResponseMessage;
import info.nightscout.android.medtronic.message.ReadInfoResponseMessage;
import info.nightscout.android.medtronic.message.RequestLinkKeyResponseMessage;
import info.nightscout.android.medtronic.message.UnexpectedMessageException;
import info.nightscout.android.model.medtronicNg.PumpStatusEvent;
import info.nightscout.android.utils.HexDump;
......@@ -43,9 +45,9 @@ import info.nightscout.android.utils.HexDump;
/**
* Created by lgoedhart on 24/03/2016.
*/
public class MedtronicCNLReader implements ContourNextLinkMessageHandler {
public class MedtronicCnlReader implements ContourNextLinkMessageHandler {
private static final String TAG = MedtronicCNLReader.class.getSimpleName();
private static final String TAG = MedtronicCnlReader.class.getSimpleName();
private static final int USB_BLOCKSIZE = 64;
private static final int READ_TIMEOUT_MS = 5000;
......@@ -54,11 +56,11 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler {
private static final byte[] RADIO_CHANNELS = {0x14, 0x11, 0x0e, 0x17, 0x1a};
private UsbHidDriver mDevice;
private MedtronicCNLSession mPumpSession = new MedtronicCNLSession();
private MedtronicCnlSession mPumpSession = new MedtronicCnlSession();
private String mStickSerial = null;
public MedtronicCNLReader(UsbHidDriver device) {
public MedtronicCnlReader(UsbHidDriver device) {
mDevice = device;
}
......@@ -87,7 +89,7 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler {
return mStickSerial;
}
public MedtronicCNLSession getPumpSession() {
public MedtronicCnlSession getPumpSession() {
return mPumpSession;
}
......@@ -238,7 +240,7 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler {
Log.d(TAG, "Finished enterPasshtroughMode");
}
public void openConnection() throws IOException, TimeoutException {
public void openConnection() throws IOException, TimeoutException, NoSuchAlgorithmException {
Log.d(TAG, "Begin openConnection");
new ContourNextLinkBinaryMessage(ContourNextLinkBinaryMessage.CommandType.OPEN_CONNECTION, mPumpSession, mPumpSession.getHMAC()).send(this);
// FIXME - We need to care what the response message is - wrong MAC and all that
......@@ -264,6 +266,24 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler {
Log.d(TAG, String.format("Finished requestReadInfo. linkMAC = '%d', pumpMAC = '%d", linkMAC, pumpMAC));
}
public void requestLinkKey() throws IOException, TimeoutException, EncryptionException, ChecksumException {
Log.d(TAG, "Begin requestLinkKey");
new ContourNextLinkBinaryMessage(ContourNextLinkBinaryMessage.CommandType.REQUEST_LINK_KEY, mPumpSession, null).send(this);
ContourNextLinkMessage response = RequestLinkKeyResponseMessage.fromBytes(mPumpSession, readMessage());
// FIXME - this needs to go into RequestLinkKeyResponseMessage
ByteBuffer infoBuffer = ByteBuffer.allocate(55);
infoBuffer.order(ByteOrder.BIG_ENDIAN);
infoBuffer.put(response.encode(), 0x21, 55);
byte[] packedLinkKey = infoBuffer.array();
this.getPumpSession().setPackedLinkKey(packedLinkKey);
Log.d(TAG, String.format("Finished requestLinkKey. linkKey = '%s'", this.getPumpSession().getKey()));
}
public byte negotiateChannel(byte lastRadioChannel) throws IOException, ChecksumException, TimeoutException {
ArrayList<Byte> radioChannels = new ArrayList<>(Arrays.asList(ArrayUtils.toObject(RADIO_CHANNELS)));
......
package info.nightscout.android.medtronic;
import org.apache.commons.lang3.ArrayUtils;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Created by lgoedhart on 26/03/2016.
*/
public class MedtronicCNLSession {
public class MedtronicCnlSession {
private static final String HMAC_PADDING = "A4BD6CED9A42602564F413123";
private byte[] HMAC;
private byte[] key;
private String stickSerial;
private long linkMAC;
private long pumpMAC;
......@@ -14,16 +23,31 @@ public class MedtronicCNLSession {
private int bayerSequenceNumber = 1;
private int medtronicSequenceNumber = 1;
public byte[] getHMAC() {
/*public byte[] getHMAC() {
return HMAC;
}*/
public byte[] getHMAC() throws NoSuchAlgorithmException {
String shortSerial = this.stickSerial.replaceAll("\\d+-", "");
byte[] message = (shortSerial + HMAC_PADDING).getBytes();
byte[] numArray;
MessageDigest instance = MessageDigest.getInstance("SHA-256");
instance.update(message);
numArray = instance.digest();
ArrayUtils.reverse(numArray);
return numArray;
}
public byte[] getKey() {
return key;
}
public byte[] getIV() {
byte[] iv = new byte[key.length];
System.arraycopy(key,0,iv,0,key.length);
System.arraycopy(key, 0, iv, 0, key.length);
iv[0] = radioChannel;
return iv;
}
......@@ -32,7 +56,7 @@ public class MedtronicCNLSession {
return linkMAC;
}
public void setLinkMAC( long linkMAC ) {
public void setLinkMAC(long linkMAC) {
this.linkMAC = linkMAC;
}
......@@ -40,7 +64,7 @@ public class MedtronicCNLSession {
return pumpMAC;
}
public void setPumpMAC( long pumpMAC ) {
public void setPumpMAC(long pumpMAC) {
this.pumpMAC = pumpMAC;
}
......@@ -68,11 +92,39 @@ public class MedtronicCNLSession {
this.radioChannel = radioChannel;
}
public void setHMAC( byte[] hmac ) {
public void setHMAC(byte[] hmac) {
this.HMAC = hmac;
}
public void setKey( byte[] key ) {
public void setKey(byte[] key) {
this.key = key;
}
public void setPackedLinkKey(byte[] packedLinkKey) {
this.key = new byte[16];
int pos = this.stickSerial.charAt(this.stickSerial.length() - 1) & 7;
for (int i = 0; i < this.key.length; i++) {
if ((packedLinkKey[pos + 1] & 1) == 1) {
this.key[i] = (byte) ~packedLinkKey[pos];
} else {
this.key[i] = packedLinkKey[pos];
}
if (((packedLinkKey[pos + 1] >> 1) & 1) == 0) {
pos += 3;
} else {
pos += 2;
}
}
}
public String getStickSerial() {
return stickSerial;
}
public void setStickSerial(String stickSerial) {
this.stickSerial = stickSerial;
}
}
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCNLSession;
import info.nightscout.android.medtronic.MedtronicCnlSession;
/**
* Created by lgoedhart on 26/03/2016.
*/
public class BeginEHSMMessage extends MedtronicSendMessage {
public BeginEHSMMessage(MedtronicCNLSession pumpSession) throws EncryptionException {
public BeginEHSMMessage(MedtronicCnlSession pumpSession) throws EncryptionException {
super(SendMessageType.BEGIN_EHSM_SESSION, pumpSession, buildPayload());
}
......
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCNLSession;
import info.nightscout.android.medtronic.MedtronicCnlSession;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
......@@ -9,11 +9,11 @@ import java.nio.ByteOrder;
* Created by lgoedhart on 26/03/2016.
*/
public class ChannelNegotiateMessage extends MedtronicMessage {
public ChannelNegotiateMessage(MedtronicCNLSession pumpSession) {
public ChannelNegotiateMessage(MedtronicCnlSession pumpSession) {
super(CommandType.SEND_MESSAGE, CommandAction.CHANNEL_NEGOTIATE, pumpSession, buildPayload(pumpSession));
}
protected static byte[] buildPayload( MedtronicCNLSession pumpSession ) {
protected static byte[] buildPayload( MedtronicCnlSession pumpSession ) {
ByteBuffer payload = ByteBuffer.allocate(26);
payload.order(ByteOrder.LITTLE_ENDIAN);
// The MedtronicMessage sequence number is always sent as 1 for this message,
......
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCNLSession;
import info.nightscout.android.medtronic.MedtronicCnlSession;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
......@@ -34,13 +34,17 @@ public class ContourNextLinkBinaryMessage extends ContourNextLinkMessage{
CommandType(int commandType) {
value = (byte) commandType;
}
public int getValue() {
return value;
}
}
public ContourNextLinkBinaryMessage(CommandType commandType, MedtronicCNLSession pumpSession, byte[] payload) {
public ContourNextLinkBinaryMessage(CommandType commandType, MedtronicCnlSession pumpSession, byte[] payload) {
super(buildPayload(commandType, pumpSession, payload));
}
protected static byte[] buildPayload(CommandType commandType, MedtronicCNLSession pumpSession, byte[] payload) {
protected static byte[] buildPayload(CommandType commandType, MedtronicCnlSession pumpSession, byte[] payload) {
int payloadLength = payload == null ? 0 : payload.length;
ByteBuffer payloadBuffer = ByteBuffer.allocate( ENVELOPE_SIZE + payloadLength );
......
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCNLSession;
import info.nightscout.android.medtronic.MedtronicCnlSession;
/**
* Created by lgoedhart on 26/03/2016.
*/
public class EndEHSMMessage extends MedtronicSendMessage {
public EndEHSMMessage(MedtronicCNLSession pumpSession) throws EncryptionException {
public EndEHSMMessage(MedtronicCnlSession pumpSession) throws EncryptionException {
super(SendMessageType.END_EHSM_SESSION, pumpSession, buildPayload());
}
......
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCNLSession;
import info.nightscout.android.medtronic.MedtronicCnlSession;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
......@@ -29,7 +29,7 @@ public class MedtronicMessage extends ContourNextLinkBinaryMessage {
}
}
protected MedtronicMessage(CommandType commandType, CommandAction commandAction, MedtronicCNLSession pumpSession, byte[] payload) {
protected MedtronicMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) {
super(commandType, pumpSession, buildPayload(commandAction, payload));
}
......
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCNLSession;
import info.nightscout.android.medtronic.MedtronicCnlSession;
import java.nio.ByteBuffer;
......@@ -12,7 +12,7 @@ public class MedtronicReceiveMessage extends MedtronicMessage {
static int ENCRYPTED_ENVELOPE_SIZE = 3;
static int CRC_SIZE = 2;
protected MedtronicReceiveMessage(CommandType commandType, CommandAction commandAction, MedtronicCNLSession pumpSession, byte[] payload) {
protected MedtronicReceiveMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) {
super(commandType, commandAction, pumpSession, payload);
}
......@@ -38,14 +38,17 @@ public class MedtronicReceiveMessage extends MedtronicMessage {
* | byte receiveSequenceNumber | BE short receiveMessageType | byte[] Payload bytes | BE short CCITT CRC |
* +----------------------------+-----------------------------+----------------------+--------------------+
*/
public static ContourNextLinkMessage fromBytes(MedtronicCNLSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
// TODO - turn this into a factory
ContourNextLinkMessage message = MedtronicMessage.fromBytes(bytes);
// TODO - Validate the message, inner CCITT, serial numbers, etc
// If there's not 57 bytes, then we got back a bad message. Not sure how to process these yet.
if( bytes.length >= 57 ) {
// Also, READ_INFO and REQUEST_LINK_KEY are not encrypted
if (bytes.length >= 57 &&
(bytes[18] != CommandType.READ_INFO.getValue()) &&
(bytes[18] != CommandType.REQUEST_LINK_KEY_RESPONSE.getValue())) {
// Replace the encrypted bytes by their decrypted equivalent (same block size)
byte encryptedPayloadSize = bytes[56];
......
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCNLSession;
import info.nightscout.android.medtronic.MedtronicCnlSession;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
......@@ -28,7 +28,7 @@ public class MedtronicSendMessage extends MedtronicMessage {
}
}
protected MedtronicSendMessage(SendMessageType sendMessageType, MedtronicCNLSession pumpSession, byte[] payload) throws EncryptionException {
protected MedtronicSendMessage(SendMessageType sendMessageType, MedtronicCnlSession pumpSession, byte[] payload) throws EncryptionException {
super(CommandType.SEND_MESSAGE, CommandAction.PUMP_REQUEST, pumpSession, buildPayload(sendMessageType, pumpSession, payload));
}
......@@ -43,7 +43,7 @@ public class MedtronicSendMessage extends MedtronicMessage {
* | byte sendSequenceNumber | BE short sendMessageType | byte[] Payload bytes | BE short CCITT CRC |
* +-------------------------+----------------------+----------------------+--------------------+
*/
protected static byte[] buildPayload(SendMessageType sendMessageType, MedtronicCNLSession pumpSession, byte[] payload) throws EncryptionException {
protected static byte[] buildPayload(SendMessageType sendMessageType, MedtronicCnlSession pumpSession, byte[] payload) throws EncryptionException {
byte payloadLength = (byte) (payload == null ? 0 : payload.length);
ByteBuffer sendPayloadBuffer = ByteBuffer.allocate(ENCRYPTED_ENVELOPE_SIZE + payloadLength + CRC_SIZE);
......
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCNLSession;
import info.nightscout.android.medtronic.MedtronicCnlSession;
/**
* Created by lgoedhart on 26/03/2016.
*/
public class PumpBasalPatternRequestMessage extends MedtronicSendMessage {
public PumpBasalPatternRequestMessage(MedtronicCNLSession pumpSession) throws EncryptionException {
public PumpBasalPatternRequestMessage(MedtronicCnlSession pumpSession) throws EncryptionException {
super(SendMessageType.READ_BASAL_PATTERN_REQUEST, pumpSession, null);
}
}
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCNLSession;
import info.nightscout.android.medtronic.MedtronicCnlSession;
/**
* Created by lgoedhart on 27/03/2016.
*/
public class PumpBasalPatternResponseMessage extends MedtronicReceiveMessage {
protected PumpBasalPatternResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCNLSession pumpSession, byte[] payload) {
protected PumpBasalPatternResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) {
super(commandType, commandAction, pumpSession, payload);
}
public static ContourNextLinkMessage fromBytes(MedtronicCNLSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
// TODO - turn this into a factory
ContourNextLinkMessage message = MedtronicReceiveMessage.fromBytes(pumpSession, bytes);
......
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCNLSession;
import info.nightscout.android.medtronic.MedtronicCnlSession;
/**
* Created by lgoedhart on 26/03/2016.
*/
public class PumpStatusRequestMessage extends MedtronicSendMessage {
public PumpStatusRequestMessage(MedtronicCNLSession pumpSession) throws EncryptionException {
public PumpStatusRequestMessage(MedtronicCnlSession pumpSession) throws EncryptionException {
super(SendMessageType.READ_PUMP_STATUS_REQUEST, pumpSession, null);
}
}
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCNLSession;
import info.nightscout.android.medtronic.MedtronicCnlSession;
/**
* Created by lgoedhart on 27/03/2016.
*/
public class PumpStatusResponseMessage extends MedtronicReceiveMessage {
protected PumpStatusResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCNLSession pumpSession, byte[] payload) {
protected PumpStatusResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) {
super(commandType, commandAction, pumpSession, payload);
}
public static ContourNextLinkMessage fromBytes(MedtronicCNLSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException {
// TODO - turn this into a factory
ContourNextLinkMessage message = MedtronicReceiveMessage.fromBytes(pumpSession, bytes);
......
package info.nightscout.android.medtronic.message;
import info.nightscout.android.medtronic.MedtronicCNLSession;
import info.nightscout.android.medtronic.MedtronicCnlSession;
/**
* Created by lgoedhart on 26/03/2016.
*/
public class PumpTimeRequestMessage extends MedtronicSendMessage {
public PumpTimeRequestMessage(MedtronicCNLSession pumpSession) throws EncryptionException {
public PumpTimeRequestMessage(MedtronicCnlSession pumpSession) throws EncryptionException {
super(SendMessageType.TIME_REQUEST, pumpSession, null);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment