diff --git a/app/app.iml b/app/app.iml deleted file mode 100644 index f36de1906719a71a357c1f627683fe377dc6f4ae..0000000000000000000000000000000000000000 --- a/app/app.iml +++ /dev/null @@ -1,154 +0,0 @@ -<?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 diff --git a/app/build.gradle b/app/build.gradle index c7dfac638564444c54e3883d8761adceb53b9263..321863d615cb36775b630d58e4edd1721a5f7a06 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,3 +1,5 @@ +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' diff --git a/app/gradle.properties b/app/gradle.properties index 0db303f3a5e5d10435a82acd862bec04bc146452..1dd0e26d2b59d84aa9b32ab72e3c5b99065efabe 100644 --- a/app/gradle.properties +++ b/app/gradle.properties @@ -1 +1 @@ -version=0.4.0-SNAPSHOT +version=0.5.0-SNAPSHOT diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 398c27edf0eb1986f7012659700f3f14e2f49a61..80e56888d3b01828035953934ed4cb6cb4d761ef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -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 diff --git a/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java b/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java index d2f50fa2b184934da6ae12a9cfbda2351113a9f9..c487d9382984b303e6292afeb7f05fec42790870 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java +++ b/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java @@ -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); - } - } } + diff --git a/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java b/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java index 6905665497f5f23e3f18498ffd4eff166fbbf795..d1249934460aebef1968d8ab832c1dcdbb04f5f3 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java +++ b/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java @@ -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 diff --git a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLSession.java b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLSession.java deleted file mode 100644 index 6c1ac2f55a6295cb70d7ada74b9825bd6755926f..0000000000000000000000000000000000000000 --- a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLSession.java +++ /dev/null @@ -1,78 +0,0 @@ -package info.nightscout.android.medtronic; - -/** - * Created by lgoedhart on 26/03/2016. - */ -public class MedtronicCNLSession { - private byte[] HMAC; - private byte[] key; - - private long linkMAC; - private long pumpMAC; - - private byte radioChannel; - private int bayerSequenceNumber = 1; - private int medtronicSequenceNumber = 1; - - public byte[] getHMAC() { - return HMAC; - } - - public byte[] getKey() { - return key; - } - public byte[] getIV() { - byte[] iv = new byte[key.length]; - System.arraycopy(key,0,iv,0,key.length); - iv[0] = radioChannel; - return iv; - } - - public long getLinkMAC() { - return linkMAC; - } - - public void setLinkMAC( long linkMAC ) { - this.linkMAC = linkMAC; - } - - public long getPumpMAC() { - return pumpMAC; - } - - public void setPumpMAC( long pumpMAC ) { - this.pumpMAC = pumpMAC; - } - - public int getBayerSequenceNumber() { - return bayerSequenceNumber; - } - - public int getMedtronicSequenceNumber() { - return medtronicSequenceNumber; - } - - public byte getRadioChannel() { - return radioChannel; - } - - public void incrBayerSequenceNumber() { - bayerSequenceNumber++; - } - - public void incrMedtronicSequenceNumber() { - medtronicSequenceNumber++; - } - - public void setRadioChannel(byte radioChannel) { - this.radioChannel = radioChannel; - } - - public void setHMAC( byte[] hmac ) { - this.HMAC = hmac; - } - - public void setKey( byte[] key ) { - this.key = key; - } -} diff --git a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLReader.java b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java similarity index 94% rename from app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLReader.java rename to app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java index 505f6414814beaee557686a4cb9d194848767da7..6dd908f0dd3f57b8d8c585d51690eaee4b82df5b 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLReader.java +++ b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlReader.java @@ -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))); diff --git a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java new file mode 100644 index 0000000000000000000000000000000000000000..215e7f3e6174163da35db8824c928d87f5d454bb --- /dev/null +++ b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCnlSession.java @@ -0,0 +1,130 @@ +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 { + private static final String HMAC_PADDING = "A4BD6CED9A42602564F413123"; + + private byte[] HMAC; + private byte[] key; + + private String stickSerial; + + private long linkMAC; + private long pumpMAC; + + private byte radioChannel; + private int bayerSequenceNumber = 1; + private int medtronicSequenceNumber = 1; + + /*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); + iv[0] = radioChannel; + return iv; + } + + public long getLinkMAC() { + return linkMAC; + } + + public void setLinkMAC(long linkMAC) { + this.linkMAC = linkMAC; + } + + public long getPumpMAC() { + return pumpMAC; + } + + public void setPumpMAC(long pumpMAC) { + this.pumpMAC = pumpMAC; + } + + public int getBayerSequenceNumber() { + return bayerSequenceNumber; + } + + public int getMedtronicSequenceNumber() { + return medtronicSequenceNumber; + } + + public byte getRadioChannel() { + return radioChannel; + } + + public void incrBayerSequenceNumber() { + bayerSequenceNumber++; + } + + public void incrMedtronicSequenceNumber() { + medtronicSequenceNumber++; + } + + public void setRadioChannel(byte radioChannel) { + this.radioChannel = radioChannel; + } + + public void setHMAC(byte[] hmac) { + this.HMAC = hmac; + } + + 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; + } +} diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/BeginEHSMMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/BeginEHSMMessage.java index ed1c7d8f18c7cc61920428de4ec47ed5f6a1dc91..e2ee643a1a0d9f7de0a0c566c6d2d147ad6e3e19 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/BeginEHSMMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/BeginEHSMMessage.java @@ -1,12 +1,12 @@ 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()); } diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ChannelNegotiateMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ChannelNegotiateMessage.java index cce33d28ea977c9f978269c0d1938bb189e0cff2..eda3ce6f6f514f3045396216dc658b65e825e5fc 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/ChannelNegotiateMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/ChannelNegotiateMessage.java @@ -1,6 +1,6 @@ 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, diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryMessage.java index 33eda925bd298ff4079372cf0189bfc82c1e1d83..95e94baa56ef73718e3db0d2d13e272f8b48a058 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/ContourNextLinkBinaryMessage.java @@ -1,6 +1,6 @@ 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 ); diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/EndEHSMMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/EndEHSMMessage.java index fe1adae580d34b37306f8a7ed30d536bff49448b..0364110375aec3d9c5f6b9c940f500d363758e4f 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/EndEHSMMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/EndEHSMMessage.java @@ -1,12 +1,12 @@ 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()); } diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicMessage.java index aed8d129f378cd16c779c13f83b3d0c857ccce81..25588505ab2e817307d0428108a0e2bb98ef4eb7 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicMessage.java @@ -1,6 +1,6 @@ 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)); } diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicReceiveMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicReceiveMessage.java index 63d854a6e12871c1a6fae098011f5ecfb120dbb3..c2f4a7d58cf10d70925e3d2ab15e3358a4ff3a3f 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicReceiveMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicReceiveMessage.java @@ -1,6 +1,6 @@ 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]; diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicSendMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicSendMessage.java index 4d099d8e59d831d04bf6d50789813d2cc6118393..7bba4ded16da96428fd056f5b985ce821ee9e63e 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicSendMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/MedtronicSendMessage.java @@ -1,6 +1,6 @@ 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); diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternRequestMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternRequestMessage.java index c1aefefde92979edb4dcd3df29c91d14855a1131..d31eb36a229654efedd6b9849fac749c1b748254 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternRequestMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternRequestMessage.java @@ -1,12 +1,12 @@ 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); } } diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternResponseMessage.java index 7aee86799f4e3bb61c72c492820472971ac78267..d4b4ef97d55422a5d5be2a5179879569a59cfcad 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternResponseMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpBasalPatternResponseMessage.java @@ -1,16 +1,16 @@ 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); diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusRequestMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusRequestMessage.java index aba4dc62d0db5aea298fa4fcc8160b3e7162185a..1162bfe139ca65e06fe1eb95571f1ff67520f78c 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusRequestMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusRequestMessage.java @@ -1,12 +1,12 @@ 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); } } diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java index bbd3c3b63c916c6ee20439a83dbc70223d54bf8a..06e9a0f3357d2456f64a5eb7c84ac3218d1e35ee 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpStatusResponseMessage.java @@ -1,16 +1,16 @@ 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); diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeRequestMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeRequestMessage.java index 97fb82065755fe04806bb1862ea38940c8f1c40d..89305b0a9b3873d3ec4079eeacebf8d740443ffe 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeRequestMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeRequestMessage.java @@ -1,12 +1,12 @@ 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); } } diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeResponseMessage.java index 940f9afa38015f6bb9dc185fdd84a28baf4d1a8e..3437dd69c65e9adfe188966ea14cbc1a6f8afb18 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeResponseMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/PumpTimeResponseMessage.java @@ -1,16 +1,16 @@ 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 PumpTimeResponseMessage extends MedtronicReceiveMessage { - protected PumpTimeResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCNLSession pumpSession, byte[] payload) { + protected PumpTimeResponseMessage(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); diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/ReadInfoResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/ReadInfoResponseMessage.java index 980392929a454a5cd841d74de46f5e46b7669aef..68aab2df7977d4235e1c445b4b8ac0692d16e88b 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/message/ReadInfoResponseMessage.java +++ b/app/src/main/java/info/nightscout/android/medtronic/message/ReadInfoResponseMessage.java @@ -1,16 +1,16 @@ package info.nightscout.android.medtronic.message; -import info.nightscout.android.medtronic.MedtronicCNLSession; +import info.nightscout.android.medtronic.MedtronicCnlSession; /** * Created by lgoedhart on 10/05/2016. */ public class ReadInfoResponseMessage extends MedtronicReceiveMessage { - protected ReadInfoResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCNLSession pumpSession, byte[] payload) { + protected ReadInfoResponseMessage(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); diff --git a/app/src/main/java/info/nightscout/android/medtronic/message/RequestLinkKeyResponseMessage.java b/app/src/main/java/info/nightscout/android/medtronic/message/RequestLinkKeyResponseMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..423e40fb8ab61296fc9c26995837a56932715a7e --- /dev/null +++ b/app/src/main/java/info/nightscout/android/medtronic/message/RequestLinkKeyResponseMessage.java @@ -0,0 +1,21 @@ +package info.nightscout.android.medtronic.message; + +import info.nightscout.android.medtronic.MedtronicCnlSession; + +/** + * Created by lgoedhart on 10/05/2016. + */ +public class RequestLinkKeyResponseMessage extends MedtronicReceiveMessage { + protected RequestLinkKeyResponseMessage(CommandType commandType, CommandAction commandAction, MedtronicCnlSession pumpSession, byte[] payload) { + super(commandType, commandAction, pumpSession, payload); + } + + public static ContourNextLinkMessage fromBytes(MedtronicCnlSession pumpSession, byte[] bytes) throws ChecksumException, EncryptionException { + // TODO - turn this into a factory + ContourNextLinkMessage message = MedtronicReceiveMessage.fromBytes(pumpSession, bytes); + + // TODO - Validate the MessageType + + return message; + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmReceiver.java b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmReceiver.java index a0af992a915f00cd4c9ca02e5d240b3371f5ba2a..49e648c68cc37df7ca643e632c9c76b1457b32f0 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmReceiver.java +++ b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlAlarmReceiver.java @@ -4,6 +4,7 @@ import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.os.Build; import android.support.v4.content.WakefulBroadcastReceiver; import android.util.Log; @@ -16,8 +17,8 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver { private static final String TAG = MedtronicCnlAlarmReceiver.class.getSimpleName(); private static final int ALARM_ID = 102; // Alarm id - private static PendingIntent pi = null; - private static AlarmManager am = null; + private static PendingIntent pendingIntent = null; + private static AlarmManager alarmManager = null; @Override public void onReceive(final Context context, Intent intent) { @@ -31,9 +32,9 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver { public void setContext(Context context) { cancelAlarm(); - am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, MedtronicCnlAlarmReceiver.class); - pi = PendingIntent.getBroadcast(context, ALARM_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT); + pendingIntent = PendingIntent.getBroadcast(context, ALARM_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT); } // Setting the alarm in 15 seconds from now @@ -43,7 +44,7 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver { // Setting the alarm to call onRecieve public void setAlarm(long millis) { - if (am == null || pi == null) + if (alarmManager == null || pendingIntent == null) return; cancelAlarm(); @@ -53,7 +54,12 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver { millis = System.currentTimeMillis(); Log.d(TAG, "AlarmManager set to fire at " + new Date(millis)); - am.setExact(AlarmManager.RTC_WAKEUP, millis, pi); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(millis, null), pendingIntent); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + alarmManager.setExact(AlarmManager.RTC_WAKEUP, millis, pendingIntent); + } else + alarmManager.set(AlarmManager.RTC_WAKEUP, millis, pendingIntent); } // restarting the alarm after MedtronicCnlIntentService.POLL_PERIOD_MS from now @@ -63,10 +69,10 @@ public class MedtronicCnlAlarmReceiver extends WakefulBroadcastReceiver { // Cancel the alarm. public void cancelAlarm() { - if (am == null || pi == null) + if (alarmManager == null || pendingIntent == null) return; - am.cancel(pi); + alarmManager.cancel(pendingIntent); } } diff --git a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java index 1a1f246f4f3e4cd643b14ee0c4cf1b3e9484f6e7..b958a2c3ac004079815a46121313dc9e74cf097a 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java +++ b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java @@ -5,21 +5,26 @@ import android.app.IntentService; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; +import android.os.Build; +import android.preference.PreferenceManager; import android.support.v4.app.NotificationManagerCompat; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import java.io.IOException; +import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.Locale; import java.util.concurrent.TimeoutException; +import info.nightscout.android.R; import info.nightscout.android.USB.UsbHidDriver; import info.nightscout.android.medtronic.MainActivity; -import info.nightscout.android.medtronic.MedtronicCNLReader; +import info.nightscout.android.medtronic.MedtronicCnlReader; import info.nightscout.android.medtronic.message.ChecksumException; import info.nightscout.android.medtronic.message.EncryptionException; import info.nightscout.android.medtronic.message.MessageUtils; @@ -28,6 +33,7 @@ import info.nightscout.android.model.medtronicNg.ContourNextLinkInfo; import info.nightscout.android.model.medtronicNg.PumpInfo; import info.nightscout.android.model.medtronicNg.PumpStatusEvent; import info.nightscout.android.upload.nightscout.NightscoutUploadReceiver; +import info.nightscout.android.xdrip_plus.XDripPlusUploadReceiver; import io.realm.Realm; import io.realm.RealmResults; @@ -128,7 +134,7 @@ public class MedtronicCnlIntentService extends IntentService { return; } - MedtronicCNLReader cnlReader = new MedtronicCNLReader(mHidDevice); + MedtronicCnlReader cnlReader = new MedtronicCnlReader(mHidDevice); Realm realm = Realm.getDefaultInstance(); realm.beginTransaction(); @@ -152,22 +158,7 @@ public class MedtronicCnlIntentService extends IntentService { info = realm.copyToRealm(info); } - String hmac = info.getHmac(); - String key = info.getKey(); - - if (hmac == null || key == null) { - // Must commit the transaction before we send the Registration activation message - realm.commitTransaction(); - - sendMessage(Constants.ACTION_USB_REGISTER); - realm.close(); - MedtronicCnlAlarmReceiver.completeWakefulIntent(intent); - // TODO - throw, don't return - return; - } - - cnlReader.getPumpSession().setHMAC(MessageUtils.hexStringToByteArray(hmac)); - cnlReader.getPumpSession().setKey(MessageUtils.hexStringToByteArray(key)); + cnlReader.getPumpSession().setStickSerial(info.getSerialNumber()); cnlReader.enterControlMode(); @@ -176,6 +167,17 @@ public class MedtronicCnlIntentService extends IntentService { cnlReader.openConnection(); cnlReader.requestReadInfo(); + String key = info.getKey(); + + if (key == null) { + cnlReader.requestLinkKey(); + + info.setKey(MessageUtils.byteArrayToHexString(cnlReader.getPumpSession().getKey())); + key = info.getKey(); + } + + cnlReader.getPumpSession().setKey(MessageUtils.hexStringToByteArray(key)); + long pumpMAC = cnlReader.getPumpSession().getPumpMAC(); Log.i(TAG, "PumpInfo MAC: " + (pumpMAC & 0xffffff)); MainActivity.setActivePumpMac(pumpMAC); @@ -209,8 +211,10 @@ public class MedtronicCnlIntentService extends IntentService { long pumpTime = cnlReader.getPumpTime().getTime(); long pumpOffset = pumpTime - System.currentTimeMillis(); + Log.d(TAG, "Time offset between pump and device: " + pumpOffset + " millis."); // TODO - send ACTION to MainActivity to show offset between pump and uploader. + pumpRecord.setPumpTimeOffset(pumpOffset); pumpRecord.setPumpDate(new Date(pumpTime - pumpOffset)); cnlReader.getPumpStatus(pumpRecord, pumpOffset); activePump.getPumpHistory().add(pumpRecord); @@ -243,6 +247,9 @@ public class MedtronicCnlIntentService extends IntentService { } catch (UnexpectedMessageException e) { Log.e(TAG, "Unexpected Message", e); sendStatus("Communication Error: " + e.getMessage()); + } catch (NoSuchAlgorithmException e) { + Log.e(TAG, "Could not determine CNL HMAC", e); + sendStatus("Error connecting to Contour Next Link: Hashing error."); } finally { //TODO : 05.11.2016 has the close to be here? cnlReader.closeConnection(); @@ -274,17 +281,39 @@ public class MedtronicCnlIntentService extends IntentService { } // TODO - set status if offline or Nightscout not reachable + sendToXDrip(); uploadToNightscout(); MedtronicCnlAlarmReceiver.completeWakefulIntent(intent); } } + // reliable wake alarm manager wake up for all android versions + public static void wakeUpIntent(Context context, long wakeTime, PendingIntent pendingIntent) { + final AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, wakeTime, pendingIntent); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + alarm.setExact(AlarmManager.RTC_WAKEUP, wakeTime, pendingIntent); + } else + alarm.set(AlarmManager.RTC_WAKEUP, wakeTime, pendingIntent); + } + + private void sendToXDrip() { + final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + if (prefs.getBoolean(getString(R.string.preference_enable_xdrip_plus), false)) { + final Intent receiverIntent = new Intent(this, XDripPlusUploadReceiver.class); + final long timestamp = System.currentTimeMillis() + 500L; + final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, (int) timestamp, receiverIntent, PendingIntent.FLAG_ONE_SHOT); + Log.d(TAG, "Scheduling xDrip+ send"); + wakeUpIntent(getApplicationContext(), timestamp, pendingIntent); + } + } + private void uploadToNightscout() { - AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent receiverIntent = new Intent(this, NightscoutUploadReceiver.class); final long timestamp = System.currentTimeMillis() + 1000L; - PendingIntent pendingIntent = PendingIntent.getBroadcast(this, (int)timestamp, receiverIntent, PendingIntent.FLAG_ONE_SHOT); - alarmManager.set(AlarmManager.RTC_WAKEUP, timestamp, pendingIntent); + final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, (int) timestamp, receiverIntent, PendingIntent.FLAG_ONE_SHOT); + wakeUpIntent(getApplicationContext(), timestamp, pendingIntent); } private boolean hasUsbHostFeature() { diff --git a/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java b/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java index 404d801c8250aaa33c13ca53e58b0d9f0e852a05..9b054671a3580a5c5e142405e89d8ea52147e100 100644 --- a/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java +++ b/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java @@ -9,7 +9,6 @@ import io.realm.annotations.PrimaryKey; public class ContourNextLinkInfo extends RealmObject { @PrimaryKey private String serialNumber; - private String hmac; private String key; public String getSerialNumber() { @@ -20,14 +19,6 @@ public class ContourNextLinkInfo extends RealmObject { this.serialNumber = serialNumber; } - public String getHmac() { - return hmac; - } - - public void setHmac(String hmac) { - this.hmac = hmac; - } - public String getKey() { return key; } diff --git a/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java b/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java index 496a85bacbf51966917c3c7463feed8a2d99ab43..ab95d50f6d346d506d3a6f03a992e53cfaa00804 100644 --- a/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java +++ b/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java @@ -3,6 +3,7 @@ package info.nightscout.android.model.medtronicNg; import java.util.Date; import io.realm.RealmObject; +import io.realm.annotations.Ignore; import io.realm.annotations.Index; /** @@ -38,6 +39,9 @@ public class PumpStatusEvent extends RealmObject { private boolean recentBolusWizard; // Whether a bolus wizard has been run recently private int bolusWizardBGL; // in mg/dL. 0 means no recent bolus wizard reading. + @Ignore + private long pumpTimeOffset; // millis the pump is ahead + @Index private boolean uploaded = false; @@ -249,6 +253,14 @@ public class PumpStatusEvent extends RealmObject { this.recentBolusWizard = recentBolusWizard; } + public long getPumpTimeOffset() { + return pumpTimeOffset; + } + + public void setPumpTimeOffset(long pumpTimeOffset) { + this.pumpTimeOffset = pumpTimeOffset; + } + public enum CGM_TREND { NONE, DOUBLE_UP, diff --git a/app/src/main/java/info/nightscout/android/settings/SettingsFragment.java b/app/src/main/java/info/nightscout/android/settings/SettingsFragment.java index e070ac229cd308a3e7f82ae50528aa789bfcbb21..7519a5c7f75cc4e177012ca37b2ec08d272d0b8a 100644 --- a/app/src/main/java/info/nightscout/android/settings/SettingsFragment.java +++ b/app/src/main/java/info/nightscout/android/settings/SettingsFragment.java @@ -10,13 +10,7 @@ import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; -import java.io.IOException; - import info.nightscout.android.R; -import info.nightscout.android.upload.nightscout.NightscoutApi; -import retrofit2.Call; -import retrofit2.Retrofit; -import retrofit2.converter.gson.GsonConverterFactory; public class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener { diff --git a/app/src/main/java/info/nightscout/android/upload/nightscout/NightScoutApi.java b/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutApi.java similarity index 100% rename from app/src/main/java/info/nightscout/android/upload/nightscout/NightScoutApi.java rename to app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutApi.java diff --git a/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java b/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java index 3fcefde12a486c2e2b5d71f48634cd60d1058fac..6ac7129878dfdcf45118b3f1f4cf83538766de24 100644 --- a/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java +++ b/app/src/main/java/info/nightscout/android/upload/nightscout/NightscoutUploadIntentService.java @@ -10,6 +10,8 @@ import android.preference.PreferenceManager; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; +import org.apache.http.HttpResponse; +import org.apache.http.StatusLine; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; @@ -31,7 +33,6 @@ import java.util.regex.Pattern; import info.nightscout.android.R; import info.nightscout.android.medtronic.MainActivity; -import info.nightscout.android.medtronic.service.MedtronicCnlIntentService; import info.nightscout.android.model.medtronicNg.PumpStatusEvent; import info.nightscout.android.upload.nightscout.serializer.EntriesSerializer; import io.realm.Realm; @@ -170,22 +171,22 @@ public class NightscoutUploadIntentService extends IntentService { addMbgEntry(entriesBody, record); } - uploadToNightscout(new URL(baseURL + "/entries"), secret, entriesBody); + boolean isUploaded = uploadToNightscout(new URL(baseURL + "/entries"), secret, entriesBody); - for(int i = 0; i < devicestatusBody.length(); i++) { - uploadToNightscout(new URL(baseURL + "/devicestatus"), secret, devicestatusBody.getJSONObject(i)); + for(int i = 0; isUploaded && i < devicestatusBody.length(); i++) { + isUploaded &= uploadToNightscout(new URL(baseURL + "/devicestatus"), secret, devicestatusBody.getJSONObject(i)); } - // Yay! We uploaded. Tell Realm - // FIXME - check the upload succeeded! - mRealm.beginTransaction(); - - for (PumpStatusEvent updateRecord : records) { - updateRecord.setUploaded(true); + if (isUploaded) { + // Yay! We uploaded. Tell Realm + // FIXME - check the upload succeeded! + mRealm.beginTransaction(); + for (PumpStatusEvent updateRecord : records) { + updateRecord.setUploaded(true); + } + mRealm.commitTransaction(); } - mRealm.commitTransaction(); - } catch (Exception e) { Log.e(TAG, "Unable to post data", e); } @@ -237,6 +238,7 @@ public class NightscoutUploadIntentService extends IntentService { httpclient.execute(post, responseHandler); } catch (Exception e) { Log.w(TAG, "Unable to post data to: '" + post.getURI().toString() + "'", e); + return false; } return true; @@ -256,11 +258,22 @@ public class NightscoutUploadIntentService extends IntentService { iob.put("timestamp", record.getPumpDate()); iob.put("bolusiob", record.getActiveInsulin()); + JSONObject status = new JSONObject(); + if (record.isBolusing()) { + status.put("bolusing", true); + } else if (record.isSuspended()) { + status.put("suspended", true); + } else { + status.put("status", "normal"); + } + JSONObject battery = new JSONObject(); battery.put("percent", record.getBatteryPercentage()); pumpInfo.put("iob", iob); pumpInfo.put("battery", battery); + pumpInfo.put("status", status); + json.put("pump", pumpInfo); String jsonString = json.toString(); Log.i(TAG, "Device Status JSON: " + jsonString); diff --git a/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadIntentService.java b/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadIntentService.java new file mode 100644 index 0000000000000000000000000000000000000000..6cc1a6f91b54362685926b06cb6f9072b78704bd --- /dev/null +++ b/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadIntentService.java @@ -0,0 +1,171 @@ +package info.nightscout.android.xdrip_plus; + +import android.app.IntentService; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ResolveInfo; +import android.os.Bundle; +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.math.BigDecimal; +import java.text.SimpleDateFormat; +import java.util.List; +import java.util.Locale; + +import info.nightscout.android.medtronic.MainActivity; +import info.nightscout.android.model.medtronicNg.PumpStatusEvent; +import info.nightscout.android.upload.nightscout.serializer.EntriesSerializer; +import io.realm.Realm; +import io.realm.RealmResults; +import io.realm.Sort; + +/** + * Created by jamorham on 17/11/2016. + */ + + +public class XDripPlusUploadIntentService extends IntentService { + + private static final String TAG = XDripPlusUploadIntentService.class.getSimpleName(); + private static final SimpleDateFormat ISO8601_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault()); + Context mContext; + private Realm mRealm; + + public XDripPlusUploadIntentService() { + super(XDripPlusUploadIntentService.class.getName()); + } + + // status unused + protected void sendStatus(String message) { + Intent localIntent = + new Intent(info.nightscout.android.xdrip_plus.XDripPlusUploadIntentService.Constants.ACTION_STATUS_MESSAGE) + .putExtra(info.nightscout.android.xdrip_plus.XDripPlusUploadIntentService.Constants.EXTENDED_DATA, message); + LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); + } + + @Override + public void onCreate() { + super.onCreate(); + + Log.i(TAG, "onCreate called"); + mContext = this.getBaseContext(); + } + + @Override + protected void onHandleIntent(Intent intent) { + Log.d(TAG, "onHandleIntent called"); + mRealm = Realm.getDefaultInstance(); + + RealmResults<PumpStatusEvent> all_records = mRealm + .where(PumpStatusEvent.class) + .notEqualTo("sgv", 0) + .findAllSorted("eventDate", Sort.DESCENDING); + + // get the most recent record and send that + if (all_records.size() > 0) { + List<PumpStatusEvent> records = all_records.subList(0, 1); + doXDripUpload(records); + } + XDripPlusUploadReceiver.completeWakefulIntent(intent); + } + + private void doXDripUpload(List<PumpStatusEvent> records) { + try { + + final JSONArray devicestatusBody = new JSONArray(); + final JSONArray entriesBody = new JSONArray(); + + for (PumpStatusEvent record : records) { + addDeviceStatus(devicestatusBody, record); + addSgvEntry(entriesBody, record); + addMbgEntry(entriesBody, record); + } + + if (entriesBody.length() > 0) sendBundle(mContext, "add", "entries", entriesBody); + if (devicestatusBody.length() > 0) + sendBundle(mContext, "add", "devicestatus", devicestatusBody); + + } catch (Exception e) { + Log.e(TAG, "Unable to send bundle: " + e); + } + } + + private void sendBundle(Context context, String action, String collection, JSONArray json) { + final Bundle bundle = new Bundle(); + bundle.putString("action", action); + bundle.putString("collection", collection); + bundle.putString("data", json.toString()); + final Intent intent = new Intent(Constants.XDRIP_PLUS_NS_EMULATOR); + intent.putExtras(bundle).addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + context.sendBroadcast(intent); + List<ResolveInfo> receivers = context.getPackageManager().queryBroadcastReceivers(intent, 0); + if (receivers.size() < 1) { + Log.e(TAG, "No receivers"); + } else Log.e(TAG, receivers.size() + " receivers"); + } + + + private void addDeviceStatus(JSONArray devicestatusArray, PumpStatusEvent record) throws Exception { + JSONObject json = new JSONObject(); + json.put("uploaderBattery", MainActivity.batLevel); + json.put("device", record.getDeviceName()); + json.put("created_at", ISO8601_DATE_FORMAT.format(record.getPumpDate())); + + JSONObject pumpInfo = new JSONObject(); + pumpInfo.put("clock", ISO8601_DATE_FORMAT.format(record.getPumpDate())); + pumpInfo.put("reservoir", new BigDecimal(record.getReservoirAmount()).setScale(3, BigDecimal.ROUND_HALF_UP)); + + JSONObject iob = new JSONObject(); + iob.put("timestamp", record.getPumpDate()); + iob.put("bolusiob", record.getActiveInsulin()); + + JSONObject battery = new JSONObject(); + battery.put("percent", record.getBatteryPercentage()); + + pumpInfo.put("iob", iob); + pumpInfo.put("battery", battery); + json.put("pump", pumpInfo); + //String jsonString = json.toString(); + + devicestatusArray.put(json); + } + + private void addSgvEntry(JSONArray entriesArray, PumpStatusEvent pumpRecord) throws Exception { + JSONObject json = new JSONObject(); + // TODO replace with Retrofit/EntriesSerializer + json.put("sgv", pumpRecord.getSgv()); + json.put("direction", EntriesSerializer.getDirectionString(pumpRecord.getCgmTrend())); + json.put("device", pumpRecord.getDeviceName()); + json.put("type", "sgv"); + json.put("date", pumpRecord.getEventDate().getTime()); + json.put("dateString", pumpRecord.getEventDate()); + + entriesArray.put(json); + } + + private void addMbgEntry(JSONArray entriesArray, PumpStatusEvent pumpRecord) throws Exception { + if (pumpRecord.hasRecentBolusWizard()) { + JSONObject json = new JSONObject(); + + // TODO replace with Retrofit/EntriesSerializer + json.put("type", "mbg"); + json.put("mbg", pumpRecord.getBolusWizardBGL()); + json.put("device", pumpRecord.getDeviceName()); + json.put("date", pumpRecord.getEventDate().getTime()); + json.put("dateString", pumpRecord.getEventDate()); + + entriesArray.put(json); + } + } + + + public final class Constants { + public static final String ACTION_STATUS_MESSAGE = "info.nightscout.android.xdrip_plus.STATUS_MESSAGE"; + public static final String EXTENDED_DATA = "info.nightscout.android.xdrip_plus.DATA"; + private static final String XDRIP_PLUS_NS_EMULATOR = "com.eveningoutpost.dexdrip.NS_EMULATOR"; + } +} diff --git a/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadReceiver.java b/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadReceiver.java new file mode 100644 index 0000000000000000000000000000000000000000..734cd34d65542d827f26d5b81290ccb42023db47 --- /dev/null +++ b/app/src/main/java/info/nightscout/android/xdrip_plus/XDripPlusUploadReceiver.java @@ -0,0 +1,22 @@ +package info.nightscout.android.xdrip_plus; + +import android.content.Context; +import android.content.Intent; +import android.support.v4.content.WakefulBroadcastReceiver; +import android.util.Log; + + +/** + * Created by jamorham on 17/11/2016. + */ +public class XDripPlusUploadReceiver extends WakefulBroadcastReceiver { + private static final String TAG = XDripPlusUploadReceiver.class.getSimpleName(); + + @Override + public void onReceive(final Context context, Intent intent) { + // Start the IntentService + Log.d(TAG, "Received broadcast message"); + Intent service = new Intent(context, XDripPlusUploadIntentService.class); + startWakefulService(context, service); + } +} diff --git a/app/src/main/res/drawable/drawer_header.jpg b/app/src/main/res/drawable/drawer_header.jpg index e3f8ab881ebc761afbfdad7ae6b554adb658d83a..251abd5c8a8ee193ef484393a966c891c8f5478a 100644 Binary files a/app/src/main/res/drawable/drawer_header.jpg and b/app/src/main/res/drawable/drawer_header.jpg differ diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 462badee54883bc0f801bacf05107482d57e99b6..84cc07b2b8603da6a558869fe53fa029ae140bcd 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -11,13 +11,6 @@ tools:context=".medtronic.GetHmacAndKeyActivity"> <!-- Login progress --> - <ProgressBar - android:id="@+id/login_progress" - style="?android:attr/progressBarStyleLarge" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginBottom="8dp" - android:visibility="gone"/> <ScrollView android:layout_width="match_parent" @@ -28,62 +21,10 @@ android:layout_width="match_parent" android:layout_height="wrap_content"> - <LinearLayout - android:id="@+id/login_form" + <TextView android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="vertical"> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceMedium" - android:text="@string/prompt_carelink_username_password" /> - - <AutoCompleteTextView - android:id="@+id/username" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:hint="@string/prompt_username" - android:inputType="text" - android:imeOptions="actionNext" - android:maxLines="1" - android:singleLine="true"/> - - <EditText - android:id="@+id/password" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:hint="@string/prompt_password" - android:imeActionId="@+id/login" - android:imeActionLabel="@string/action_sign_in_short" - android:imeOptions="actionDone|actionUnspecified" - android:inputType="textPassword" - android:maxLines="1" - android:singleLine="true"/> - - <AutoCompleteTextView - android:id="@+id/hostname" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:hint="Carelink hostname (optional)" - android:imeOptions="actionDone" - android:inputType="text" - android:maxLines="1"/> - - - </LinearLayout> - - <LinearLayout - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="match_parent"> - - <TextView - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:id="@+id/registered_usb_devices" /> - </LinearLayout> + android:id="@+id/registered_usb_devices" /> </LinearLayout> </ScrollView> diff --git a/app/src/main/res/menu/menu_register_usb.xml b/app/src/main/res/menu/menu_register_usb.xml deleted file mode 100644 index 81a6c5646903e8d5f192edbd9d651e4b025c70dc..0000000000000000000000000000000000000000 --- a/app/src/main/res/menu/menu_register_usb.xml +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> - <item android:id="@+id/action_menu_login" - android:title="Login" - android:orderInCategory="100" - app:showAsAction="always" - /> -</menu> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 00a255b85ec633800300f0bd6f93fbc4b81ae25c..89751b6c042dc6aca1482597467d1d6cfffab63f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -35,7 +35,7 @@ <string name="preference_api_secret">API SECRET</string> <string name="prompt_carelink_username_password">Please enter your CareLink details.\nThey will not be stored.</string> <string name="close">Close</string> - <string name="register_contour_next_link">Register Contour Next Link</string> + <string name="register_contour_next_link">Registered Devices</string> <string name="preferences_enable_crashlytics">prefs_enable_crashlytics</string> <string name="preferences_enable_answers">prefs_enable_answers</string> <string name="preferences_enable_remote_logcat">prefs_enable_remote_logcat</string> @@ -46,6 +46,7 @@ <string name="button_text_start_uploading_data">Start Uploading CGM Data</string> <string name="preference_eula_accepted">IUNDERSTAND</string> <string name="preference_enable_rest_upload">EnableRESTUpload</string> + <string name="preference_enable_xdrip_plus">EnablexDripPlusUpload</string> <string name="error_msg_api_secret_length">API Secret must be 12 characters or longer.</string> <string name="text_unit_mmolxl">mmol/L</string> <string name="text_unit_mgxdl">mg/dL</string> diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 8a8fb08d3852284649d8428d84e72fac42c4d557..9e6793c85ec60101ef37b053d3af5d9caefd74b1 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -39,6 +39,10 @@ android:dialogTitle="Enter your Nightscout API secret" android:key="@string/preference_api_secret" android:title="API Secret"/> + <CheckBoxPreference + android:key="@string/preference_enable_xdrip_plus" + android:summary="Enable local broadcast of data to xDrip+" + android:title="Send to xDrip+"/> </PreferenceCategory> <PreferenceCategory android:title="Disclaimer"> <SwitchPreference diff --git a/build.gradle b/build.gradle index 04964d2ceed4f5f07ac9cb13fce761e51603eaeb..9da42b0b994170c75de5ee547bfabc0007cf8dd7 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.2.2' + classpath 'com.android.tools.build:gradle:2.2.3' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files classpath "io.realm:realm-gradle-plugin:1.0.0"