diff --git a/app/app.iml b/app/app.iml index 4a7d5c4eed469e88116b7cfeb0acf539e0cb5889..e21e32e18a1d39dd95c1e160e391b59f001dde94 100644 --- a/app/app.iml +++ b/app/app.iml @@ -28,6 +28,7 @@ <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" /> @@ -35,6 +36,7 @@ <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" /> @@ -65,14 +67,6 @@ <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" /> @@ -81,6 +75,14 @@ <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" /> + <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" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" /> @@ -88,48 +90,65 @@ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" /> <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.3.5/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.crashlytics.sdk.android/answers/1.3.6/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.crashlytics.sdk.android/beta/1.1.4/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.crashlytics.sdk.android/crashlytics-core/2.3.8/jars" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.crashlytics.sdk.android/crashlytics/2.5.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.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.10/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/incremental-classes" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-runtime-classes" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-safeguard" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental-verifier" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant-run-support" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" /> <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/restart-dex" /> <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/intermediates/transforms" /> <excludeFolder url="file://$MODULE_DIR$/build/outputs" /> <excludeFolder url="file://$MODULE_DIR$/build/tmp" /> </content> <orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" /> <orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="library" exported="" name="support-annotations-23.4.0" level="project" /> - <orderEntry type="library" exported="" name="crashlytics-2.5.5" level="project" /> - <orderEntry type="library" exported="" name="crashlytics-core-2.3.8" level="project" /> - <orderEntry type="library" exported="" name="beta-1.1.4" level="project" /> - <orderEntry type="library" exported="" name="logback-android-1.1.1-3" 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="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="answers-1.3.6" 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="okio-1.4.0" 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="fabric-1.3.10" level="project" /> + <orderEntry type="library" exported="" name="design-23.4.0" level="project" /> + <orderEntry type="library" exported="" name="android-0.3.5" level="project" /> + <orderEntry type="library" exported="" name="gson-2.4" level="project" /> + <orderEntry type="library" exported="" name="crashlytics-2.5.5" level="project" /> + <orderEntry type="library" exported="" name="crashlytics-core-2.3.8" level="project" /> + <orderEntry type="library" exported="" name="beta-1.1.4" level="project" /> + <orderEntry type="library" exported="" name="fastadapter-1.5.2" level="project" /> + <orderEntry type="library" exported="" name="logback-android-1.1.1-3" level="project" /> + <orderEntry type="library" exported="" name="materialdrawer-5.2.9" level="project" /> + <orderEntry type="library" exported="" name="calligraphy-2.2.0" level="project" /> + <orderEntry type="library" exported="" name="answers-1.3.6" 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 45fe30164faabb3156f08b49dd5aa7dcbd3e3fe3..c767a6020438f130ef40e37285812e9b075fbf3a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,6 +13,7 @@ plugins { apply plugin: 'com.android.application' apply plugin: 'io.fabric' +apply plugin: 'realm-android' repositories { maven { url 'https://maven.fabric.io/public' } @@ -36,7 +37,7 @@ android { defaultConfig { applicationId "info.nightscout.android" - minSdkVersion 15 + minSdkVersion 14 targetSdkVersion 23 versionName project.properties['version'] versionCode gitVersion() @@ -119,4 +120,10 @@ dependencies { compile('com.crashlytics.sdk.android:crashlytics:2.5.5@aar') { transitive = true; } + compile('com.mikepenz:materialdrawer:5.2.9@aar') { + transitive = true + } + 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.3.5' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 47d94a65882f9993945395ab18a71a3531dbbe26..c067681495750701d9a78af923eceb2d77fca1a0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,10 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="info.nightscout.android" - > + package="info.nightscout.android"> - <uses-sdk - android:maxSdkVersion="23" /> + <uses-sdk android:maxSdkVersion="23" /> <uses-feature android:name="android.hardware.usb.host" /> @@ -16,28 +14,30 @@ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> + <uses-permission android:name="android.permission.USB_PERMISSION" /> <application + android:name=".UploaderApplication" android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" - android:theme="@style/AppBaseTheme" > + 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.Medtronic640gActivity" + android:name=".medtronic.MainActivity" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:launchMode="singleTask" - android:screenOrientation="portrait" > - <intent-filter android:icon="@drawable/ic_launcher" > + android:screenOrientation="portrait"> + <intent-filter android:icon="@drawable/ic_launcher"> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> - <intent-filter android:icon="@drawable/ic_launcher" > + <intent-filter android:icon="@drawable/ic_launcher"> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter> @@ -48,17 +48,18 @@ <activity android:name=".settings.SettingsActivity" android:icon="@drawable/ic_launcher" - android:label="Settings" /> - - <service - android:name=".medtronic.service.MedtronicCNLService" - android:icon="@drawable/ic_launcher" > - </service> + android:label="Settings" + android:theme="@style/SettingsTheme"/> <activity android:name=".medtronic.GetHmacAndKeyActivity" - android:label="@string/title_activity_login" > - </activity> + android:label="@string/title_activity_login" + android:theme="@style/SettingsTheme" /> + + <service + android:name=".medtronic.service.MedtronicCnlIntentService" + android:icon="@drawable/ic_launcher"></service> + </application> </manifest> \ No newline at end of file diff --git a/app/src/main/assets/fonts/OpenSans-Regular.ttf b/app/src/main/assets/fonts/OpenSans-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..db433349b7047f72f40072630c1bc110620bf09e Binary files /dev/null and b/app/src/main/assets/fonts/OpenSans-Regular.ttf differ diff --git a/app/src/main/java/info/nightscout/android/UploaderApplication.java b/app/src/main/java/info/nightscout/android/UploaderApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..384ab6f2f39319ba3fcbeebf4b3232d9e266d141 --- /dev/null +++ b/app/src/main/java/info/nightscout/android/UploaderApplication.java @@ -0,0 +1,30 @@ +package info.nightscout.android; + +import android.app.Application; + +import com.bugfender.sdk.Bugfender; + +import io.realm.Realm; +import io.realm.RealmConfiguration; +import uk.co.chrisjenx.calligraphy.CalligraphyConfig; + +/** + * Created by lgoedhart on 9/06/2016. + */ +public class UploaderApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + CalligraphyConfig.initDefault(new CalligraphyConfig.Builder() + .setDefaultFontPath("fonts/OpenSans-Regular.ttf") + .setFontAttrId(R.attr.fontPath) + .build() + ); + + //Bugfender.init(this, "TSwASSlwqOGXFb86RadI7EEJZSr2jGeT", BuildConfig.DEBUG); + //Bugfender.enableLogcatLogging(); + + RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(this).build(); + Realm.setDefaultConfiguration(realmConfiguration); + } +} 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 6351a83bd1b04d7c81bd5c4a8a736e86325a4311..e96266b00e2f6b9b9225ff02dc8f3262462070ca 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java +++ b/app/src/main/java/info/nightscout/android/medtronic/GetHmacAndKeyActivity.java @@ -3,29 +3,29 @@ package info.nightscout.android.medtronic; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.annotation.TargetApi; -import android.app.Activity; import android.app.LoaderManager.LoaderCallbacks; import android.content.Context; import android.content.Loader; import android.database.Cursor; +import android.graphics.Color; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; import android.text.Html; import android.text.TextUtils; import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; -import android.view.View.OnClickListener; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; -import android.widget.Button; import android.widget.EditText; import android.widget.TextView; -import info.nightscout.android.R; -import info.nightscout.android.medtronic.data.CNLConfigContract; -import info.nightscout.android.medtronic.data.CNLConfigDbHelper; -import info.nightscout.android.medtronic.message.MessageUtils; +import com.mikepenz.google_material_typeface_library.GoogleMaterial; +import com.mikepenz.iconics.IconicsDrawable; import org.apache.commons.lang3.ArrayUtils; import org.apache.http.HttpResponse; @@ -46,14 +46,22 @@ import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List; +import info.nightscout.android.R; +import info.nightscout.android.medtronic.message.MessageUtils; +import info.nightscout.android.model.medtronicNg.ContourNextLinkInfo; +import io.realm.Realm; +import io.realm.RealmResults; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; + /** * A login screen that offers login via username/password. */ -public class GetHmacAndKeyActivity extends Activity implements LoaderCallbacks<Cursor> { +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. @@ -62,12 +70,16 @@ public class GetHmacAndKeyActivity extends Activity implements LoaderCallbacks<C private View mProgressView; private View mLoginFormView; private TextView mRegisteredStickView; - private Button mCloseButton; + private MenuItem mLoginMenuItem; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setTitle("Register USB"); + // Set up the login form. mUsernameView = (EditText) findViewById(R.id.username); @@ -83,28 +95,42 @@ public class GetHmacAndKeyActivity extends Activity implements LoaderCallbacks<C } }); - Button usernameSignInButton = (Button) findViewById(R.id.username_sign_in_button); - usernameSignInButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - attemptLogin(); - } - }); - mLoginFormView = findViewById(R.id.login_form); mProgressView = findViewById(R.id.login_progress); - mRegisteredStickView = (TextView)findViewById(R.id.registered_usb_devices); - mCloseButton = (Button)findViewById(R.id.close_button); - mCloseButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - finish(); - } - }); + mRegisteredStickView = (TextView) findViewById(R.id.registered_usb_devices); showRegisteredSticks(); } + @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; + } + return true; + } + + @Override + protected void attachBaseContext(Context newBase) { + 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 @@ -190,21 +216,20 @@ public class GetHmacAndKeyActivity extends Activity implements LoaderCallbacks<C } private void showRegisteredSticks() { - CNLConfigDbHelper configDbHelper = new CNLConfigDbHelper(getBaseContext()); - Cursor cursor = configDbHelper.getAllRows(); + Realm realm = Realm.getDefaultInstance(); - String deviceTableHtml = "<big><b>Registered Devices</b></big><br/>"; + RealmResults<ContourNextLinkInfo> results = realm.where(ContourNextLinkInfo.class).findAll(); - while( !cursor.isAfterLast() ) { - String longSerial = cursor.getString(cursor.getColumnIndex(CNLConfigContract.ConfigEntry.COLUMN_NAME_STICK_SERIAL)); - String key = cursor.getString(cursor.getColumnIndex(CNLConfigContract.ConfigEntry.COLUMN_NAME_KEY)); + String deviceTableHtml = "<big><b>Registered Devices</b></big><br/>"; - deviceTableHtml += String.format("<b>Serial Number:</b> %s %s<br/>", longSerial, key.equals("") ? "✘" : "✔" ); + for (ContourNextLinkInfo info : results) { + String longSerial = info.getSerialNumber(); + String key = info.getKey(); - cursor.moveToNext(); + deviceTableHtml += String.format("<b>Serial Number:</b> %s %s<br/>", longSerial, key == null ? "✘" : "✔"); } - mRegisteredStickView.setText(Html.fromHtml( deviceTableHtml )); + mRegisteredStickView.setText(Html.fromHtml(deviceTableHtml)); } @Override @@ -229,7 +254,7 @@ public class GetHmacAndKeyActivity extends Activity implements LoaderCallbacks<C private final String mUsername; private final String mPassword; - GetHmacAndKey(String username, String password ) { + GetHmacAndKey(String username, String password) { mUsername = username; mPassword = password; } @@ -247,12 +272,12 @@ public class GetHmacAndKeyActivity extends Activity implements LoaderCallbacks<C HttpResponse response = client.execute(loginPost); if (response.getStatusLine().getStatusCode() == 200) { - // Get the HMAC/keys for every serial in the Config database - CNLConfigDbHelper configDbHelper = new CNLConfigDbHelper(getBaseContext()); - Cursor cursor = configDbHelper.getAllRows(); + // Get the HMAC/keys for every serial we have seen + Realm realm = Realm.getDefaultInstance(); - while( !cursor.isAfterLast() ) { - String longSerial = cursor.getString(cursor.getColumnIndex(CNLConfigContract.ConfigEntry.COLUMN_NAME_STICK_SERIAL)); + 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); @@ -287,10 +312,10 @@ public class GetHmacAndKeyActivity extends Activity implements LoaderCallbacks<C keyResponse.readInt(); // Throw away the first int. Not sure what it does String key = MessageUtils.byteArrayToHexString((byte[]) keyResponse.readObject()); - // TODO - return false if this returns 0? What would we do anyway? - configDbHelper.setHmacAndKey(longSerial, hmac, key); - - cursor.moveToNext(); + realm.beginTransaction(); + info.setHmac(hmac); + info.setKey(key); + realm.commitTransaction(); } return true; @@ -313,10 +338,10 @@ public class GetHmacAndKeyActivity extends Activity implements LoaderCallbacks<C if (success) { showRegisteredSticks(); - mCloseButton.setVisibility(View.VISIBLE); + mLoginMenuItem.setVisible(false); mLoginFormView.setVisibility(View.GONE); mProgressView.setVisibility(View.GONE); - InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(mLoginFormView.getWindowToken(), 0); } else { 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 new file mode 100644 index 0000000000000000000000000000000000000000..887ab956f4f73d4615bb8e599afaa6bc5037ac20 --- /dev/null +++ b/app/src/main/java/info/nightscout/android/medtronic/MainActivity.java @@ -0,0 +1,460 @@ +package info.nightscout.android.medtronic; + +import android.app.ActivityManager; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.hardware.usb.UsbManager; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.BatteryManager; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v4.content.LocalBroadcastManager; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.text.Html; +import android.text.format.DateUtils; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.TextView; +import android.widget.TextView.BufferType; + +import com.crashlytics.android.Crashlytics; +import com.crashlytics.android.answers.Answers; +import com.mikepenz.google_material_typeface_library.GoogleMaterial; +import com.mikepenz.materialdrawer.AccountHeaderBuilder; +import com.mikepenz.materialdrawer.Drawer; +import com.mikepenz.materialdrawer.DrawerBuilder; +import com.mikepenz.materialdrawer.model.PrimaryDrawerItem; +import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.DecimalFormat; +import java.util.Locale; + +import info.nightscout.android.R; +import info.nightscout.android.eula.Eula; +import info.nightscout.android.eula.Eula.OnEulaAgreedTo; +import info.nightscout.android.medtronic.service.MedtronicCnlIntentService; +import info.nightscout.android.settings.SettingsActivity; +import info.nightscout.android.upload.MedtronicNG.CGMRecord; +import info.nightscout.android.upload.MedtronicNG.PumpStatusRecord; +import io.fabric.sdk.android.Fabric; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; + +/* Main activity for the MainActivity program */ +public class MainActivity extends AppCompatActivity implements OnSharedPreferenceChangeListener, OnEulaAgreedTo { + private static final String TAG = MainActivity.class.getSimpleName(); + public static int batLevel = 0; + public static PumpStatusRecord pumpStatusRecord = new PumpStatusRecord(); + final Object mHandlerActiveLock = new Object(); + boolean keepServiceAlive = true; + Boolean mHandlerActive = false; + ActivityManager manager = null; + SharedPreferences prefs = null; + private Logger log = (Logger) LoggerFactory.getLogger(MainActivity.class.getName()); + private Toolbar toolbar; + private TextView mTextViewBg; + private TextView mTextViewBgTime; + private TextView mTextViewLog; + private TextView mTextViewUnits; + private TextView mTextViewTrend; + private TextView mTextViewIOB; + private Button buttonStopService; + private Intent mCnlIntentService; + + //Look for and launch the service, mTextViewLog status to user + @Override + public void onCreate(Bundle savedInstanceState) { + Log.i(TAG, "onCreate called"); + super.onCreate(savedInstanceState); + + mCnlIntentService = new Intent(this, MedtronicCnlIntentService.class); + + setContentView(R.layout.activity_main); + + PreferenceManager.getDefaultSharedPreferences(getBaseContext()).registerOnSharedPreferenceChangeListener(this); + prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); + + if (prefs.getBoolean(getString(R.string.preferences_enable_crashlytics), true)) { + Fabric.with(this, new Crashlytics()); + } + if (prefs.getBoolean(getString(R.string.preferences_enable_answers), true)) { + Fabric.with(this, new Answers()); + } + + if (!prefs.getBoolean("IUNDERSTAND", false)) { + stopCgmService(); + } else { + mHandlerActive = true; + } + + // Registers the DownloadStateReceiver and its intent filters + LocalBroadcastManager.getInstance(this).registerReceiver( + new StatusMessageReceiver(), + new IntentFilter(MedtronicCnlIntentService.Constants.ACTION_STATUS_MESSAGE)); + LocalBroadcastManager.getInstance(this).registerReceiver( + new CgmRecordReceiver(), + new IntentFilter(MedtronicCnlIntentService.Constants.ACTION_CGM_DATA)); + + keepServiceAlive = Eula.show(this, prefs); + + IntentFilter batteryIntentFilter = new IntentFilter(); + batteryIntentFilter.addAction(Intent.ACTION_BATTERY_LOW); + batteryIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); + batteryIntentFilter.addAction(Intent.ACTION_BATTERY_OKAY); + registerReceiver(new BatteryReceiver(), batteryIntentFilter); + + IntentFilter usbIntentFilter = new IntentFilter(); + usbIntentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED); + usbIntentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED); + registerReceiver(new UsbReceiver(), usbIntentFilter); + + manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + toolbar = (Toolbar) findViewById(R.id.toolbar); + + if (toolbar != null) { + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(false); + getSupportActionBar().setElevation(0); + getSupportActionBar().setTitle("Nightscout"); + } + + + final PrimaryDrawerItem itemHome = new PrimaryDrawerItem().withName("Home").withIcon(GoogleMaterial.Icon.gmd_home).withSelectable(false); + final PrimaryDrawerItem itemSettings = new PrimaryDrawerItem().withName("Settings").withIcon(GoogleMaterial.Icon.gmd_settings).withSelectable(false); + final PrimaryDrawerItem itemRegisterUsb = new PrimaryDrawerItem().withName("Register Contour Next Link").withIcon(GoogleMaterial.Icon.gmd_usb).withSelectable(false); + + Drawer drawer = new DrawerBuilder() + .withActivity(this) + .withAccountHeader(new AccountHeaderBuilder() + .withActivity(this) + .withHeaderBackground(R.drawable.drawer_header) + .build() + ) + .withTranslucentStatusBar(false) + .withToolbar(toolbar) + .withActionBarDrawerToggle(true) + .withSelectedItem(-1) + .addDrawerItems( + itemHome, + itemSettings, + itemRegisterUsb + ) + .withOnDrawerItemClickListener(new Drawer.OnDrawerItemClickListener() { + @Override + public boolean onItemClick(View view, int position, IDrawerItem drawerItem) { + if (drawerItem.equals(itemSettings)) { + openSettings(); + } else if (drawerItem.equals(itemRegisterUsb)) { + openUsbRegistration(); + } + return false; + } + }) + .build(); + + // UI elements - TODO do these need to be members? + mTextViewBg = (TextView) findViewById(R.id.textview_bg); + mTextViewBgTime = (TextView) findViewById(R.id.textview_bg_time); + mTextViewLog = (TextView) findViewById(R.id.textview_log); + mTextViewUnits = (TextView) findViewById(R.id.textview_units); + if (prefs.getBoolean("mmolxl", false)) { + mTextViewUnits.setText(R.string.text_unit_mmolxl); + } else { + mTextViewUnits.setText(R.string.text_unit_mgxdl); + } + mTextViewTrend = (TextView) findViewById(R.id.textview_trend); + mTextViewIOB = (TextView) findViewById(R.id.textview_iob); + + buttonStopService = (Button) findViewById(R.id.button_stop_service); + + Button buttonClearLog = (Button) findViewById(R.id.button_clear_log); + Button buttonStartService = (Button) findViewById(R.id.button_start_service); + + buttonClearLog.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + mTextViewLog.setText("", BufferType.EDITABLE); + } + }); + + buttonStartService.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + // Get an immediate reading. + startCgmService(); + } + }); + + buttonStopService.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + synchronized (mHandlerActiveLock) { + mHandlerActive = false; + keepServiceAlive = false; + stopCgmService(); + finish(); + } + } + }); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + startCgmService(); + } + + @Override + protected void onPause() { + log.info("ON PAUSE!"); + super.onPause(); + } + + @Override + protected void onResume() { + log.info("ON RESUME!"); + super.onResume(); + } + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + //MenuInflater inflater = getMenuInflater(); + //inflater.inflate(R.menu.menu, menu); + + return true; + } + + 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 boolean onOptionsItemSelected(MenuItem item) { + + switch (item.getItemId()) { + case R.id.menu_settings: + Intent settingsIntent = new Intent(this, SettingsActivity.class); + startActivity(settingsIntent); + break; + case R.id.registerCNL: + if (checkOnline("Please connect to the Internet", "You must be online to register your USB stick.")) { + Intent loginIntent = new Intent(this, GetHmacAndKeyActivity.class); + startActivity(loginIntent); + } + break; + default: + break; + } + return super.onOptionsItemSelected(item); + } + + private void startCgmService() { + Log.i(TAG, "startCgmService called"); + startService(mCnlIntentService); + } + + private void startCgmServicePolling(long initialPoll) { + Log.i(TAG, "startCgmServicePolling called"); + AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); + PendingIntent pending = PendingIntent.getService(this, 0, mCnlIntentService, 0); + + alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, + initialPoll, MedtronicCnlIntentService.POLL_PERIOD_MS, pending); + } + + private void stopCgmService() { + Log.i(TAG, "stopCgmService called"); + + AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); + PendingIntent pending = PendingIntent.getService(this, 0, mCnlIntentService, 0); + + alarmManager.cancel(pending); + } + + @Override + protected void onDestroy() { + Log.i(TAG, "onDestroy called"); + log.info("onDestroy called"); + PreferenceManager.getDefaultSharedPreferences(getBaseContext()).unregisterOnSharedPreferenceChangeListener(this); + synchronized (mHandlerActiveLock) { + if (!keepServiceAlive) { + stopCgmService(); + } + mHandlerActive = false; + SharedPreferences.Editor editor = getBaseContext().getSharedPreferences(MedtronicConstants.PREFS_NAME, 0).edit(); + editor.putLong("lastDestroy", System.currentTimeMillis()); + editor.apply(); + super.onDestroy(); + } + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + if (key.equals(getString(R.string.preference_eula_accepted))) { + if (!sharedPreferences.getBoolean(getString(R.string.preference_eula_accepted), false)) { + synchronized (mHandlerActiveLock) { + mHandlerActive = false; + } + stopCgmService(); + } else { + startCgmService(); + mHandlerActive = true; + } + } + } + + @Override + public void onEulaAgreedTo() { + keepServiceAlive = true; + } + + @Override + public void onEulaRefusedTo() { + keepServiceAlive = false; + } + + public void openSettings() { + Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + } + + public void openUsbRegistration() { + if (checkOnline("Please connect to the Internet", "You must be online to register your USB stick.")) { + Intent loginIntent = new Intent(this, GetHmacAndKeyActivity.class); + startActivity(loginIntent); + } + } + + private String renderTrendHtml(CGMRecord.TREND trend) { + switch (trend) { + case DOUBLE_UP: + return "⇈"; + case SINGLE_UP: + return "↑"; + case FOURTY_FIVE_UP: + return "↗"; + case FLAT: + return "→"; + case FOURTY_FIVE_DOWN: + return "↘"; + case SINGLE_DOWN: + return "↓"; + case DOUBLE_DOWN: + return "⇊"; + default: + return "—"; + } + } + + private class StatusMessageReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String message = intent.getStringExtra(MedtronicCnlIntentService.Constants.EXTENDED_DATA); + + mTextViewLog.setText(mTextViewLog.getText() + "\n" + message, BufferType.EDITABLE); + } + } + + private class CgmRecordReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + CGMRecord cgmRecord = (CGMRecord) intent.getSerializableExtra(MedtronicCnlIntentService.Constants.EXTENDED_DATA); + + // FIXME - replace initial polling time with the next expected polling period + // i.e. Next 5 minute CGM polling increment to occur after now, + POLL_GRACE_PERIOD_MS + startCgmServicePolling(System.currentTimeMillis() + MedtronicCnlIntentService.POLL_PERIOD_MS); + + DecimalFormat df; + if (prefs.getBoolean("mmolDecimals", false)) + df = new DecimalFormat("0.00"); + else + df = new DecimalFormat("0.0"); + + String sgvString, units; + if (prefs.getBoolean("mmolxl", false)) { + float fBgValue = (float) cgmRecord.sgv; + sgvString = df.format(fBgValue / 18.016f); + units = "mmol/L"; + log.info("mmolxl true --> " + sgvString); + + } else { + sgvString = String.valueOf(cgmRecord.sgv); + units = "mg/dL"; + log.info("mmolxl false --> " + sgvString); + } + + mTextViewBg.setText(sgvString); + mTextViewUnits.setText(units); + mTextViewBgTime.setText(DateUtils.formatDateTime(getBaseContext(), cgmRecord.sgvDate.getTime(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME)); + mTextViewTrend.setText(Html.fromHtml(renderTrendHtml(cgmRecord.getTrend()))); + mTextViewIOB.setText(String.format(Locale.getDefault(), "%.2f", pumpStatusRecord.activeInsulin)); + } + } + + private class UsbReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) { + mTextViewLog.setText(mTextViewLog.getText() + "\nUSB plugged in", BufferType.EDITABLE); + startCgmService(); + } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { + mTextViewLog.setText(mTextViewLog.getText() + "\nUSB unplugged", BufferType.EDITABLE); + } + + } + } + + private class BatteryReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context arg0, Intent arg1) { + if (arg1.getAction().equalsIgnoreCase(Intent.ACTION_BATTERY_LOW) + || arg1.getAction().equalsIgnoreCase(Intent.ACTION_BATTERY_CHANGED) + || arg1.getAction().equalsIgnoreCase(Intent.ACTION_BATTERY_OKAY)) { + Log.i("BatteryReceived", "BatteryReceived"); + batLevel = arg1.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); + } + } + } +} diff --git a/app/src/main/java/info/nightscout/android/medtronic/Medtronic640gActivity.java b/app/src/main/java/info/nightscout/android/medtronic/Medtronic640gActivity.java deleted file mode 100644 index d325fa654d55e14714eb357a7a79d42a4ecd7b71..0000000000000000000000000000000000000000 --- a/app/src/main/java/info/nightscout/android/medtronic/Medtronic640gActivity.java +++ /dev/null @@ -1,457 +0,0 @@ -package info.nightscout.android.medtronic; - -import android.app.Activity; -import android.app.ActivityManager; -import android.app.AlertDialog; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.graphics.Color; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.os.BatteryManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.StrictMode; -import android.preference.PreferenceManager; -import android.text.Html; -import android.text.format.DateUtils; -import android.text.method.ScrollingMovementMethod; -import android.util.Log; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup.LayoutParams; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.TextView; -import android.widget.TextView.BufferType; - -import com.crashlytics.android.Crashlytics; -import com.crashlytics.android.answers.Answers; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.text.DecimalFormat; -import java.util.Locale; - -import info.nightscout.android.R; -import info.nightscout.android.eula.Eula; -import info.nightscout.android.eula.Eula.OnEulaAgreedTo; -import info.nightscout.android.medtronic.service.MedtronicCNLService; -import info.nightscout.android.service.ServiceManager; -import info.nightscout.android.settings.SettingsActivity; -import info.nightscout.android.upload.MedtronicNG.CGMRecord; -import info.nightscout.android.upload.MedtronicNG.PumpStatusRecord; -import io.fabric.sdk.android.Fabric; - -/* Main activity for the Medtronic640gActivity program */ -public class Medtronic640gActivity extends Activity implements OnSharedPreferenceChangeListener, OnEulaAgreedTo { - //CGMs supported - public static final int CNL_24 = 2; - private static final String TAG = Medtronic640gActivity.class.getSimpleName(); - private static final boolean ISDEBUG = true; - public static int batLevel = 0; - public static PumpStatusRecord pumpStatusRecord = new PumpStatusRecord(); - BatteryReceiver mArrow; - Intent batteryReceiver; - boolean keepServiceAlive = true; - Boolean mHandlerActive = false; - final Object mHandlerActiveLock = new Object(); - ActivityManager manager = null; - SharedPreferences settings = null; - SharedPreferences prefs = null; - private Logger log = (Logger) LoggerFactory.getLogger(Medtronic640gActivity.class.getName()); - private int cgmSelected = CNL_24; - private Handler mHandler = new Medtronic640gActivityHandler(); - private TextView mTitleTextView; - private TextView mDumpTextView; - private Button b1; - private TextView display; - private ServiceManager cgmService; // > service - - //Look for and launch the service, display status to user - @Override - public void onCreate(Bundle savedInstanceState) { - Log.i(TAG, "onCreate called"); - super.onCreate(savedInstanceState); - - if (android.os.Build.VERSION.SDK_INT > 9) { - StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); - StrictMode.setThreadPolicy(policy); - } - - this.settings = getBaseContext().getSharedPreferences( - MedtronicConstants.PREFS_NAME, 0); - PreferenceManager.getDefaultSharedPreferences(getBaseContext()).registerOnSharedPreferenceChangeListener(this); - prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); - - if (prefs.getBoolean(getString(R.string.preferences_enable_crashlytics), true)) { - Fabric.with(this, new Crashlytics()); - } - if (prefs.getBoolean(getString(R.string.preferences_enable_answers), true)) { - Fabric.with(this, new Answers()); - } - - keepServiceAlive = Eula.show(this, prefs); - - mArrow = new BatteryReceiver(); - IntentFilter mIntentFilter = new IntentFilter(); - mIntentFilter.addAction(Intent.ACTION_BATTERY_LOW); - mIntentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); - mIntentFilter.addAction(Intent.ACTION_BATTERY_OKAY); - batteryReceiver = registerReceiver(mArrow, mIntentFilter); - setContentView(R.layout.adb); - manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); - mTitleTextView = (TextView) findViewById(R.id.demoTitle); - mDumpTextView = (TextView) findViewById(R.id.demoText); - - LinearLayout lnr = (LinearLayout) findViewById(R.id.container); - LinearLayout lnr2 = new LinearLayout(this); - LinearLayout lnr3 = new LinearLayout(this); - lnr3.setOrientation(LinearLayout.HORIZONTAL); - b1 = new Button(this); - - if (!prefs.getBoolean("IUNDERSTAND", false)) { - stopCGMServices(); - } else { - mHandlerActive = true; - } - - b1.setText(R.string.button_text_stop_uploading_data); - lnr.addView(b1); - lnr2.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - lnr3.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); - Button b2 = new Button(this); - b2.setText(R.string.button_text_clear_log); - b2.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, 1.0f)); - Button b4 = new Button(this); - b4.setText(R.string.button_text_get_now); - b4.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT, 1.0f)); - lnr3.addView(b4); - - if (ISDEBUG) { - lnr3.addView(b2); - } - lnr.addView(lnr3); - lnr.addView(lnr2); - display = new TextView(this); - if (ISDEBUG) { - display.setText("", BufferType.EDITABLE); - display.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - display.setKeyListener(null); - display.setBackgroundColor(Color.BLACK); - display.setTextColor(Color.WHITE); - display.setMovementMethod(new ScrollingMovementMethod()); - display.setMaxLines(10); - - lnr2.addView(display); - } - b2.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - display.setText("", BufferType.EDITABLE); - display.setKeyListener(null); - } - }); - - b4.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - display.setKeyListener(null); - if (cgmService != null) { - if (!cgmService.isRunning()) { - cgmService.start(); - } else { - cgmService.stop(); - cgmService.start(); - } - } - } - }); - - b1.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - synchronized (mHandlerActiveLock) { - if (b1.getText() == "Stop Uploading CGM Data") { - mHandlerActive = false; - //mHandler.removeCallbacks(updateDataView); - keepServiceAlive = false; - stopCGMServices(); - b1.setText(R.string.button_text_start_uploading_data); - finish(); - } else { - startCGMServices(); - - mHandlerActive = true; - b1.setText(R.string.button_text_stop_uploading_data); - } - } - - } - }); - } - - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - startCGMServices(); - if (cgmService != null) { - Log.d(TAG, "onPostCreate: Starting the service"); - cgmService.start(); - } - } - - @Override - protected void onPause() { - log.info("ON PAUSE!"); - super.onPause(); - - } - - @Override - protected void onResume() { - log.info("ON RESUME!"); - super.onResume(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.menu, menu); - - return true; - } - - 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) - .setTitle(title) - .setMessage(message) - .setCancelable(false) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - // continue with delete - dialog.dismiss(); - } - }) - .setIcon(android.R.drawable.ic_dialog_alert) - .show(); - } - - return isOnline; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - switch (item.getItemId()) { - case R.id.menu_settings: - Intent settingsIntent = new Intent(this, SettingsActivity.class); - startActivity(settingsIntent); - break; - case R.id.registerCNL: - if (checkOnline("Please connect to the Internet", "You must be online to register your USB stick.")) { - Intent loginIntent = new Intent(this, GetHmacAndKeyActivity.class); - startActivity(loginIntent); - } - break; - default: - break; - } - return super.onOptionsItemSelected(item); - } - - private void startCGMServices() { - Log.d("DexcomActivity", "Starting service for CGM: " + cgmSelected); - switch (cgmSelected) { - default: - Log.d("DexcomActivity", "Starting Medtronic CNL service"); - cgmService = new ServiceManager(this, MedtronicCNLService.class, mHandler); - break; - } - } - - private void stopCGMServices() { - switch (cgmSelected) { - default: - if (cgmService != null) { - cgmService.stop(); - } - break; - } - } - - @Override - protected void onDestroy() { - Log.i(TAG, "onDestroy called"); - log.info("onDestroy called"); - PreferenceManager.getDefaultSharedPreferences(getBaseContext()).unregisterOnSharedPreferenceChangeListener(this); - unregisterReceiver(mArrow); - synchronized (mHandlerActiveLock) { - //mHandler.removeCallbacks(updateDataView); - - stopCGMServices(); - if (keepServiceAlive) { - startCGMServices(); - } - mHandlerActive = false; - SharedPreferences.Editor editor = getBaseContext().getSharedPreferences(MedtronicConstants.PREFS_NAME, 0).edit(); - editor.putLong("lastDestroy", System.currentTimeMillis()); - editor.apply(); - super.onDestroy(); - } - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, - String key) { - try { - //If i do not - if (key.equals("IUNDERSTAND")) { - if (!sharedPreferences.getBoolean("IUNDERSTAND", false)) { - synchronized (mHandlerActiveLock) { - //mHandler.removeCallbacks(updateDataView); - mHandlerActive = false; - } - b1.setText(R.string.button_text_start_uploading_data); - stopCGMServices(); - } else { - startCGMServices(); - //mHandler.post(updateDataView); - mHandlerActive = true; - } - } - } catch (Exception e) { - StringBuilder sb1 = new StringBuilder(""); - sb1.append("EXCEPTION!!!!!! ").append(e.getMessage()).append(" ").append(e.getCause()); - for (StackTraceElement st : e.getStackTrace()) { - sb1.append(st.toString()).append("\n"); - } - Log.e("CGM_onSharedPrefChanged", sb1.toString()); - if (ISDEBUG) { - display.append(sb1.toString()); - } - } - } - - @Override - public void onEulaAgreedTo() { - keepServiceAlive = true; - } - - @Override - public void onEulaRefusedTo() { - keepServiceAlive = false; - - } - - private String renderTrendHtml(CGMRecord.TREND trend) { - switch (trend) { - case DOUBLE_UP: - return "⇈"; - case SINGLE_UP: - return "↑"; - case FOURTY_FIVE_UP: - return "↗"; - case FLAT: - return "→"; - case FOURTY_FIVE_DOWN: - return "↘"; - case SINGLE_DOWN: - return "↓"; - case DOUBLE_DOWN: - return "⇊"; - default: - return "—"; - } - } - - public class Medtronic640gActivityHandler extends Handler { - public static final int MSG_ERROR = 1; - public static final int MSG_STATUS = 2; - public static final int MSG_DATA = 3; - - @Override - public void handleMessage(Message msg) { - Log.d(TAG, "Got message from Service."); - switch (cgmSelected) { - case CNL_24: - switch (msg.what) { - case MSG_ERROR: - display.setText(msg.obj.toString(), BufferType.EDITABLE); - break; - case MSG_STATUS: - display.setText(msg.obj.toString(), BufferType.EDITABLE); - break; - case MSG_DATA: - CGMRecord record = (CGMRecord) msg.obj; - - DecimalFormat df; - if (prefs.getBoolean("mmolDecimals", false)) - df = new DecimalFormat("#.00"); - else - df = new DecimalFormat("#.0"); - String sgvString; - String unitsString = "mg/dL"; - if (prefs.getBoolean("mmolxl", false)) { - - float fBgValue = (float) record.sgv; - sgvString = df.format(fBgValue / 18.016f); - unitsString = "mmol/L"; - log.info("mmolxl true --> " + sgvString); - - } else { - sgvString = String.valueOf(record.sgv); - log.info("mmolxl false --> " + sgvString); - } - - //mTitleTextView.setTextColor(Color.YELLOW); - mTitleTextView.setText(Html.fromHtml( - String.format("<big><b>%s</b></big> <small>%s %s</small>", - sgvString, unitsString, renderTrendHtml(record.getTrend())))); - - mDumpTextView.setTextColor(Color.WHITE); - mDumpTextView.setText(Html.fromHtml( - String.format( Locale.getDefault(), "<b>SG at:</b> %s<br/><b>Pump Time:</b> %s<br/><b>Active Insulin: </b>%.3f<br/><b>Rate of Change: </b>%s", - DateUtils.formatDateTime(getBaseContext(), record.sgvDate.getTime(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME), - DateUtils.formatDateTime(getBaseContext(), pumpStatusRecord.pumpDate.getTime(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME), - pumpStatusRecord.activeInsulin, - record.direction - ) - )); - - break; - } - default: - super.handleMessage(msg); - } - } - } - - private class BatteryReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context arg0, Intent arg1) { - if (arg1.getAction().equalsIgnoreCase(Intent.ACTION_BATTERY_LOW) - || arg1.getAction().equalsIgnoreCase(Intent.ACTION_BATTERY_CHANGED) - || arg1.getAction().equalsIgnoreCase(Intent.ACTION_BATTERY_OKAY)) { - Log.i("BatteryReceived", "BatteryReceived"); - batLevel = arg1.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); - } - } - } -} diff --git a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLReader.java b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLReader.java index 763e9171f30322803fe728b48f7aa847800a4fb3..94658af861e75b153215d42d197e9ff1ca1fab26 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLReader.java +++ b/app/src/main/java/info/nightscout/android/medtronic/MedtronicCNLReader.java @@ -7,11 +7,8 @@ import java.io.IOException; import java.math.BigDecimal; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -import java.util.TimeZone; import java.util.concurrent.TimeoutException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -34,9 +31,8 @@ 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.UnexpectedMessageException; -import info.nightscout.android.medtronic.service.MedtronicCNLService; +import info.nightscout.android.medtronic.service.MedtronicCnlIntentService; import info.nightscout.android.upload.MedtronicNG.CGMRecord; -import info.nightscout.android.upload.MedtronicNG.PumpStatusRecord; import info.nightscout.android.utils.HexDump; /** @@ -44,7 +40,7 @@ import info.nightscout.android.utils.HexDump; */ public class MedtronicCNLReader implements ContourNextLinkMessageHandler { - private static final String TAG = MedtronicCNLService.class.getSimpleName(); + private static final String TAG = MedtronicCnlIntentService.class.getSimpleName(); private static final int USB_BLOCKSIZE = 64; private static final int READ_TIMEOUT_MS = 5000; @@ -141,7 +137,7 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler { // TODO - get rid of this - it should be in a message decoder private void checkControlMessage(byte[] msg, byte controlCharacter) throws IOException, TimeoutException, UnexpectedMessageException { if (msg.length != 1 || msg[0] != controlCharacter) { - throw new UnexpectedMessageException(String.format( Locale.getDefault(), "Expected to get control character '%d' Got '%d'.", + throw new UnexpectedMessageException(String.format(Locale.getDefault(), "Expected to get control character '%d' Got '%d'.", (int) controlCharacter, (int) msg[0])); } } @@ -252,7 +248,7 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler { if (responseBytes[76] == mPumpSession.getRadioChannel()) { break; } else { - throw new IOException(String.format( Locale.getDefault(), "Expected to get a message for channel %d. Got %d", mPumpSession.getRadioChannel(), responseBytes[76])); + throw new IOException(String.format(Locale.getDefault(), "Expected to get a message for channel %d. Got %d", mPumpSession.getRadioChannel(), responseBytes[76])); } } else { mPumpSession.setRadioChannel((byte) 0); @@ -268,8 +264,9 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler { readMessage(); } - public void getPumpTime(PumpStatusRecord pumpRecord) throws EncryptionException, IOException, ChecksumException, TimeoutException { + public Date getPumpTime() throws EncryptionException, IOException, ChecksumException, TimeoutException { // FIXME - throw if not in EHSM mode (add a state machine) + Date timeAtCapture = new Date(); new PumpTimeRequestMessage(mPumpSession).send(this); // Read the 0x81 @@ -279,23 +276,18 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler { ContourNextLinkMessage response = PumpTimeResponseMessage.fromBytes(mPumpSession, readMessage()); if (response.encode().length < 57) { - // Invalid message. Don't try and parse it - return; + // Invalid message. Return an invalid date. + return new Date(); } // FIXME - this needs to go into PumpTimeResponseMessage ByteBuffer dateBuffer = ByteBuffer.allocate(8); dateBuffer.order(ByteOrder.BIG_ENDIAN); - dateBuffer.put(response.encode(), 61, 8); + dateBuffer.put(response.encode(), 0x3d, 8); long rtc = dateBuffer.getInt(0) & 0x00000000ffffffffL; long offset = dateBuffer.getInt(4); - Date pumpDate = MessageUtils.decodeDateTime(rtc, offset); - - // Set displayTime to be an ISO 8601 date (so that it's parsable). - DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - pumpRecord.displayTime = dateFormat.format(pumpDate); + return MessageUtils.decodeDateTime(rtc, offset); } public void getPumpStatus(CGMRecord cgmRecord) throws IOException, EncryptionException, ChecksumException, TimeoutException { @@ -320,7 +312,7 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler { // Read the data into the record long rawActiveInsulin = statusBuffer.getShort(0x33) & 0x0000ffff; - Medtronic640gActivity.pumpStatusRecord.activeInsulin = new BigDecimal(rawActiveInsulin / 10000f).setScale(3, BigDecimal.ROUND_HALF_UP); + MainActivity.pumpStatusRecord.activeInsulin = new BigDecimal(rawActiveInsulin / 10000f).setScale(3, BigDecimal.ROUND_HALF_UP); cgmRecord.sgv = statusBuffer.getShort(0x35) & 0x0000ffff; // In mg/DL. 0 means no CGM reading long rtc; long offset; @@ -336,11 +328,11 @@ public class MedtronicCNLReader implements ContourNextLinkMessageHandler { cgmRecord.setTrend(CGMRecord.fromMessageByte(statusBuffer.get(0x40))); } cgmRecord.sgvDate = MessageUtils.decodeDateTime(rtc, offset); - Medtronic640gActivity.pumpStatusRecord.recentBolusWizard = statusBuffer.get(0x48) != 0; - Medtronic640gActivity.pumpStatusRecord.bolusWizardBGL = statusBuffer.getShort(0x49); // In mg/DL + MainActivity.pumpStatusRecord.recentBolusWizard = statusBuffer.get(0x48) != 0; + MainActivity.pumpStatusRecord.bolusWizardBGL = statusBuffer.getShort(0x49); // In mg/DL long rawReservoirAmount = statusBuffer.getInt(0x2b); - Medtronic640gActivity.pumpStatusRecord.reservoirAmount = new BigDecimal(rawReservoirAmount / 10000f).setScale(3, BigDecimal.ROUND_HALF_UP); - Medtronic640gActivity.pumpStatusRecord.batteryPercentage = (statusBuffer.get(0x2a)); + MainActivity.pumpStatusRecord.reservoirAmount = new BigDecimal(rawReservoirAmount / 10000f).setScale(3, BigDecimal.ROUND_HALF_UP); + MainActivity.pumpStatusRecord.batteryPercentage = (statusBuffer.get(0x2a)); } public void endEHSMSession() throws EncryptionException, IOException, TimeoutException { diff --git a/app/src/main/java/info/nightscout/android/medtronic/data/CNLConfigContract.java b/app/src/main/java/info/nightscout/android/medtronic/data/CNLConfigContract.java deleted file mode 100644 index 49250a772bb4c068598d29d6cf8a9cbaca471ff5..0000000000000000000000000000000000000000 --- a/app/src/main/java/info/nightscout/android/medtronic/data/CNLConfigContract.java +++ /dev/null @@ -1,21 +0,0 @@ -package info.nightscout.android.medtronic.data; - -import android.provider.BaseColumns; - -/** - * Created by lgoedhart on 9/05/2016. - */ -public class CNLConfigContract { - // To prevent someone from accidentally instantiating the contract class, - // give it an empty constructor. - public CNLConfigContract() {} - - /* Inner class that defines the table contents */ - public static abstract class ConfigEntry implements BaseColumns { - public static final String TABLE_NAME = "config"; - public static final String COLUMN_NAME_STICK_SERIAL = "stick_serial"; - public static final String COLUMN_NAME_HMAC = "hmac"; - public static final String COLUMN_NAME_KEY = "key"; - public static final String COLUMN_NAME_LAST_RADIO_CHANNEL = "last_radio_channel"; - } -} diff --git a/app/src/main/java/info/nightscout/android/medtronic/data/CNLConfigDbHelper.java b/app/src/main/java/info/nightscout/android/medtronic/data/CNLConfigDbHelper.java deleted file mode 100644 index 22ecae852a02d254a0d43df0e5a6355005ea6951..0000000000000000000000000000000000000000 --- a/app/src/main/java/info/nightscout/android/medtronic/data/CNLConfigDbHelper.java +++ /dev/null @@ -1,141 +0,0 @@ -package info.nightscout.android.medtronic.data; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; - -/** - * Created by lgoedhart on 9/05/2016. - */ -public class CNLConfigDbHelper extends SQLiteOpenHelper { - // Database Specific Details - - // If you change the database schema, you must increment the database version. - private static final int DATABASE_VERSION = 1; - // DB Name, same is used to name the sqlite DB file - private static final String DATABASE_NAME = "cnl_config.db"; - - private static final String SQL_CREATE_CONFIG = - "CREATE TABLE " + CNLConfigContract.ConfigEntry.TABLE_NAME + " (" + - CNLConfigContract.ConfigEntry._ID + " INTEGER PRIMARY KEY," + - CNLConfigContract.ConfigEntry.COLUMN_NAME_STICK_SERIAL + " TEXT UNIQUE, " + - CNLConfigContract.ConfigEntry.COLUMN_NAME_HMAC + " TEXT, "+ - CNLConfigContract.ConfigEntry.COLUMN_NAME_KEY + " TEXT, " + - CNLConfigContract.ConfigEntry.COLUMN_NAME_LAST_RADIO_CHANNEL + " INTEGER " + - ")"; - - private static final String SQL_DROP_CONFIG = - "DROP TABLE IF EXISTS " + CNLConfigContract.ConfigEntry.TABLE_NAME; - - public CNLConfigDbHelper(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL(SQL_CREATE_CONFIG); - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - // No upgrades yet, so drop and rebuild - db.execSQL(SQL_DROP_CONFIG); - onCreate(db); - } - - @Override - public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { - onUpgrade(db, oldVersion, newVersion); - } - - public void insertStickSerial( String stickSerial ) { - SQLiteDatabase configDb = this.getWritableDatabase(); - ContentValues insertValues = new ContentValues(); - insertValues.put(CNLConfigContract.ConfigEntry.COLUMN_NAME_STICK_SERIAL, stickSerial ); - insertValues.put(CNLConfigContract.ConfigEntry.COLUMN_NAME_HMAC, ""); - insertValues.put(CNLConfigContract.ConfigEntry.COLUMN_NAME_KEY, ""); - insertValues.put(CNLConfigContract.ConfigEntry.COLUMN_NAME_LAST_RADIO_CHANNEL, 0x14 ); - configDb.insertWithOnConflict(CNLConfigContract.ConfigEntry.TABLE_NAME, null, insertValues, SQLiteDatabase.CONFLICT_IGNORE); - configDb.close(); - } - - public String getHmac( String stickSerial ){ - SQLiteDatabase configDb = this.getWritableDatabase(); - - Cursor cursor = configDb.query( CNLConfigContract.ConfigEntry.TABLE_NAME, - new String[] { CNLConfigContract.ConfigEntry.COLUMN_NAME_HMAC }, - CNLConfigContract.ConfigEntry.COLUMN_NAME_STICK_SERIAL + " = ?", new String[]{ stickSerial }, null, null, null); - - String hmac = null; - - if (cursor != null && cursor.moveToFirst()) { - hmac = cursor.getString(cursor.getColumnIndex(CNLConfigContract.ConfigEntry.COLUMN_NAME_HMAC)); - cursor.close(); - } - - configDb.close(); - - return hmac; - } - - public String getKey( String stickSerial ){ - SQLiteDatabase configDb = this.getWritableDatabase(); - - Cursor cursor = configDb.query( CNLConfigContract.ConfigEntry.TABLE_NAME, - new String[] { CNLConfigContract.ConfigEntry.COLUMN_NAME_KEY }, - CNLConfigContract.ConfigEntry.COLUMN_NAME_STICK_SERIAL + " = ?", new String[]{ stickSerial }, null, null, null); - - String key = null; - - if (cursor != null && cursor.moveToFirst()) { - key = cursor.getString(cursor.getColumnIndex(CNLConfigContract.ConfigEntry.COLUMN_NAME_KEY)); - cursor.close(); - } - - configDb.close(); - - return key; - } - - public int setHmacAndKey( String stickSerial, String hmac, String key ) { - SQLiteDatabase configDb = this.getWritableDatabase(); - - ContentValues values = new ContentValues(); - values.put(CNLConfigContract.ConfigEntry.COLUMN_NAME_HMAC, hmac); - values.put(CNLConfigContract.ConfigEntry.COLUMN_NAME_KEY, key); - - // Which row to update, based on the ID - String whereClause = CNLConfigContract.ConfigEntry.COLUMN_NAME_STICK_SERIAL + " = ?"; - String[] whereArgs = { stickSerial }; - - int affectedRows = configDb.update( - CNLConfigContract.ConfigEntry.TABLE_NAME, - values, - whereClause, - whereArgs - ); - - configDb.close(); - return affectedRows; - } - - public Cursor getAllRows(){ - SQLiteDatabase configDb = this.getReadableDatabase(); - - String where = null; - String whereArgs[] = null; - String groupBy = null; - String having = null; - String order = null; - String limit = null; - - Cursor cursor = configDb.query(CNLConfigContract.ConfigEntry.TABLE_NAME, null, where, whereArgs, groupBy, having, order, limit); - if (cursor != null){ - cursor.moveToFirst(); - } - return cursor; - } - -} diff --git a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCNLService.java b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java similarity index 59% rename from app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCNLService.java rename to app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java index 2f1ca0b145438db9870b4102af28349a5ee26a0e..bdab9b3c1c0124f55f182e7568da1f2209217da1 100644 --- a/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCNLService.java +++ b/app/src/main/java/info/nightscout/android/medtronic/service/MedtronicCnlIntentService.java @@ -1,16 +1,14 @@ package info.nightscout.android.medtronic.service; -import android.app.PendingIntent; +import android.app.IntentService; import android.content.Context; import android.content.Intent; -import android.graphics.BitmapFactory; +import android.content.pm.PackageManager; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.os.Handler; -import android.os.Message; -import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; +import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import java.io.File; @@ -19,78 +17,74 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.Serializable; import java.util.Locale; -import java.util.Timer; -import java.util.TimerTask; import java.util.concurrent.TimeoutException; import info.nightscout.android.R; import info.nightscout.android.USB.UsbHidDriver; -import info.nightscout.android.medtronic.Medtronic640gActivity; +import info.nightscout.android.medtronic.MainActivity; import info.nightscout.android.medtronic.MedtronicCNLReader; -import info.nightscout.android.medtronic.data.CNLConfigDbHelper; import info.nightscout.android.medtronic.message.ChecksumException; import info.nightscout.android.medtronic.message.EncryptionException; import info.nightscout.android.medtronic.message.MessageUtils; import info.nightscout.android.medtronic.message.UnexpectedMessageException; -import info.nightscout.android.service.AbstractService; +import info.nightscout.android.model.medtronicNg.ContourNextLinkInfo; import info.nightscout.android.upload.MedtronicNG.CGMRecord; import info.nightscout.android.upload.MedtronicNG.PumpStatusRecord; import info.nightscout.android.upload.UploadHelper; +import io.realm.Realm; -public class MedtronicCNLService extends AbstractService { +public class MedtronicCnlIntentService extends IntentService { public final static int USB_VID = 0x1a79; public final static int USB_PID = 0x6210; - + public final static long POLL_PERIOD_MS = 300000L; + // Number of additional seconds to wait after the next expected CGM poll, so that we don't interfere with CGM radio comms. + public final static long POLL_GRACE_PERIOD_MS = 30000L; + private static final String TAG = MedtronicCnlIntentService.class.getSimpleName(); private UsbHidDriver mHidDevice; - private Timer mTimer = new Timer(); - private static final String TAG = MedtronicCNLService.class.getSimpleName(); private Context mContext; private NotificationManagerCompat nm; - private final static long POLL_PERIOD_MS = 300000L; - private final static long POLL_DELAY_MS = 30000L; - // If the polling is within this many milliseconds (either side), then we don't reset the timer - private final static long POLL_MARGIN_MS = 10000L; private UsbManager mUsbManager; - private Handler handler; - @Override - public void onCreate() { - this.handler = new Handler(); - super.onCreate(); + public MedtronicCnlIntentService() { + super(MedtronicCnlIntentService.class.getName()); } - @Override - public void onStartService() { - Log.i(TAG, "onStartService called"); - mContext = this.getBaseContext(); - mUsbManager = (UsbManager) this.getSystemService(Context.USB_SERVICE); + public final class Constants { + public static final String ACTION_STATUS_MESSAGE = "info.nightscout.android.medtronic.service.STATUS_MESSAGE"; + public static final String ACTION_CGM_DATA = "info.nightscout.android.medtronic.service.CGM_DATA"; + public static final String EXTENDED_DATA = "info.nightscout.android.medtronic.service.DATA"; + } - // Add a small start delay - for some reason, having no start delay causes initial - // binding/rendering issues - startPollingLoop(250L); + protected void sendStatus(String message) { + Intent localIntent = + new Intent(Constants.ACTION_STATUS_MESSAGE) + .putExtra(Constants.EXTENDED_DATA, message); + LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); } - private void startPollingLoop(long delay) { - mTimer.scheduleAtFixedRate(new TimerTask() { - public void run() { - handler.post(new Runnable() { - public void run() { - doReadAndUpload(); - } - }); - } - }, delay, POLL_PERIOD_MS); + protected void sendCgmRecord(Serializable cgmRecord) { + Intent localIntent = + new Intent(Constants.ACTION_CGM_DATA) + .putExtra(Constants.EXTENDED_DATA, cgmRecord); + LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent); } @Override - public void onStopService() { - Log.d(TAG, "onStopService called"); + public void onCreate() { + super.onCreate(); - if (mTimer != null) { - mTimer.cancel(); - mTimer = null; - } + Log.i(TAG, "onCreate called"); + mContext = this.getBaseContext(); + mUsbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE); + } + + @Override + public void onDestroy() { + super.onDestroy(); + + Log.d(TAG, "onDestroy called"); if (nm != null) { nm.cancelAll(); @@ -104,25 +98,29 @@ public class MedtronicCNLService extends AbstractService { } } - @Override - public void onReceiveMessage(Message msg) { - } + protected void onHandleIntent(Intent intent) { + Log.i(TAG, "onHandleIntent called"); + + if (!hasUsbHostFeature()) { + sendStatus("It appears that this device doesn't support USB OTG."); + return; + } - protected void doReadAndUpload() { UploadHelper mUploader = new UploadHelper(getBaseContext()); mHidDevice = UsbHidDriver.acquire(mUsbManager, USB_VID, USB_PID); + Realm realm = Realm.getDefaultInstance(); // Load the initial data to the display CGMRecord cgmRecord = loadData(); - PumpStatusRecord pumpRecord = Medtronic640gActivity.pumpStatusRecord; + PumpStatusRecord pumpRecord = MainActivity.pumpStatusRecord; - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_DATA, cgmRecord)); + sendCgmRecord(cgmRecord); if (mHidDevice == null) { String title = "USB connection error"; String msg = "Is the Bayer Contour NextLink plugged in?"; //showNotification(title, msg); - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_ERROR, title + "\n" + msg)); + sendStatus(title + "\n" + msg); } else { try { mHidDevice.open(); @@ -135,20 +133,32 @@ public class MedtronicCNLService extends AbstractService { MedtronicCNLReader cnlReader = new MedtronicCNLReader(mHidDevice); try { - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_STATUS, "Connecting to the Contour Next Link...")); + sendStatus("Connecting to the Contour Next Link..."); cnlReader.requestDeviceInfo(); // Is the device already configured? - CNLConfigDbHelper configDbHelper = new CNLConfigDbHelper(mContext); - configDbHelper.insertStickSerial(cnlReader.getStickSerial()); - String hmac = configDbHelper.getHmac(cnlReader.getStickSerial()); - String key = configDbHelper.getKey(cnlReader.getStickSerial()); + ContourNextLinkInfo info = realm + .where(ContourNextLinkInfo.class).equalTo("serialNumber", cnlReader.getStickSerial()) + .findFirst(); + + if (info == null) { + info = new ContourNextLinkInfo(); + info.setSerialNumber(cnlReader.getStickSerial()); + + realm.beginTransaction(); + info = realm.copyToRealm(info); + realm.commitTransaction(); + } + + String hmac = info.getHmac(); + String key = info.getKey(); + String deviceName = String.format("medtronic-640g://%s", cnlReader.getStickSerial()); cgmRecord.setDeviceName(deviceName); - Medtronic640gActivity.pumpStatusRecord.setDeviceName(deviceName); + pumpRecord.setDeviceName(deviceName); - if (hmac.equals("") || key.equals("")) { - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_ERROR, String.format("Before you can use the Contour Next Link, you need to register it with the app. Select '%s' from the menu.", getString(R.string.register_contour_next_link)))); + if (hmac == null || key == null) { + sendStatus(String.format("Before you can use the Contour Next Link, you need to register it with the app. Select '%s' from the menu.", getString(R.string.register_contour_next_link))); return; } @@ -162,45 +172,44 @@ public class MedtronicCNLService extends AbstractService { cnlReader.requestReadInfo(); byte radioChannel = cnlReader.negotiateChannel(); if (radioChannel == 0) { - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_ERROR, "Could not communicate with the 640g. Are you near the pump?")); + sendStatus("Could not communicate with the 640g. Are you near the pump?"); Log.i(TAG, "Could not communicate with the 640g. Are you near the pump?"); } else { - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_STATUS, String.format( Locale.getDefault(), "Connected to Contour Next Link on channel %d.", (int) radioChannel))); + sendStatus(String.format(Locale.getDefault(), "Connected to Contour Next Link on channel %d.", (int) radioChannel)); Log.d(TAG, String.format("Connected to Contour Next Link on channel %d.", (int) radioChannel)); cnlReader.beginEHSMSession(); - cnlReader.getPumpTime(pumpRecord); + pumpRecord.pumpDate = cnlReader.getPumpTime(); cnlReader.getPumpStatus(cgmRecord); - long pumpToUploaderTimeOffset = (new java.util.Date()).getTime() - Medtronic640gActivity.pumpStatusRecord.pumpDate.getTime(); - writeData(cgmRecord); - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_DATA, cgmRecord)); + sendCgmRecord(cgmRecord); cnlReader.endEHSMSession(); } cnlReader.closeConnection(); } catch (UnexpectedMessageException e) { Log.e(TAG, "Unexpected Message", e); - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_ERROR, "Communication Error: " + e.getMessage())); + sendStatus("Communication Error: " + e.getMessage()); + } finally { cnlReader.endPassthroughMode(); cnlReader.endControlMode(); } } catch (IOException e) { Log.e(TAG, "Error getting SGVs", e); - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_ERROR, "Error connecting to Contour Next Link.")); + sendStatus("Error connecting to Contour Next Link."); } catch (ChecksumException e) { Log.e(TAG, "Checksum error", e); - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_ERROR, "Checksum error getting message from the Contour Next Link.")); + sendStatus("Checksum error getting message from the Contour Next Link."); } catch (EncryptionException e) { Log.e(TAG, "Encryption exception", e); - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_ERROR, "Error decrypting messages from Contour Next Link.")); + sendStatus("Error decrypting messages from Contour Next Link."); } catch (TimeoutException e) { Log.e(TAG, "Timeout communicating with Contour", e); - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_ERROR, "Timeout communicating with the Contour Next Link.")); + sendStatus("Timeout communicating with the Contour Next Link."); } catch (UnexpectedMessageException e) { Log.e(TAG, "Unexpected Message", e); - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_ERROR, "Could not close connection: " + e.getMessage())); + sendStatus("Could not close connection: " + e.getMessage()); } // TODO - add retries. @@ -208,19 +217,40 @@ public class MedtronicCNLService extends AbstractService { String title = "Cannot upload data"; String msg = "Please check that you're connected to the Internet"; //showNotification(title, msg); - send(Message.obtain(null, Medtronic640gActivity.Medtronic640gActivityHandler.MSG_ERROR, title + "\n" + msg)); + sendStatus(title + "\n" + msg); } else { - mUploader.execute(cgmRecord); + // FIXME - DO THE UPLOAD! + //mUploader.execute(cgmRecord); } + + realm.close(); } } private boolean isOnline() { - ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); + ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo netInfo = cm.getActiveNetworkInfo(); return netInfo != null && netInfo.isConnectedOrConnecting(); } + private boolean hasUsbHostFeature() { + return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_USB_HOST); + } + + // FIXME - replace this with writing to the SQLite DB. + private void writeData(CGMRecord cgmRecord) { + //Write most recent data + try { + Context context = getBaseContext(); + ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(context.getFilesDir(), "save.bin"))); //Select where you wish to save the file... + oos.writeObject(cgmRecord); // write the class as an 'object' + oos.flush(); // flush the stream to insure all of the information was written to 'save.bin' + oos.close();// close the stream + } catch (Exception e) { + Log.e(TAG, "write to OutputStream failed", e); + } + } + /* // FIXME - when we want to enable notifications, start with this. We'll need to fix the icon to match // the Android standards (linter will fail anyway) @@ -228,7 +258,7 @@ public class MedtronicCNLService extends AbstractService { NotificationManagerCompat nm = NotificationManagerCompat.from(mContext); // The PendingIntent to launch our activity if the user selects this notification - PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Medtronic640gActivity.class), 0); + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0); nm.notify(R.string.app_name, new NotificationCompat.Builder(mContext) .setDefaults(NotificationCompat.DEFAULT_ALL) .setContentTitle(title) @@ -244,20 +274,6 @@ public class MedtronicCNLService extends AbstractService { } */ - // FIXME - replace this with writing to the SQLite DB. - private void writeData(CGMRecord mostRecentData) { - //Write most recent data - try { - Context context = getBaseContext(); - ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(context.getFilesDir(), "save.bin"))); //Select where you wish to save the file... - oos.writeObject(mostRecentData); // write the class as an 'object' - oos.flush(); // flush the stream to insure all of the information was written to 'save.bin' - oos.close();// close the stream - } catch (Exception e) { - Log.e(TAG, "write to OutputStream failed", e); - } - } - private CGMRecord loadData() { ObjectInputStream ois = null; try { diff --git a/app/src/main/java/info/nightscout/android/model/CgmStatusEvent.java b/app/src/main/java/info/nightscout/android/model/CgmStatusEvent.java new file mode 100644 index 0000000000000000000000000000000000000000..c8759eeb61102ddd8c9b0dc5d24c04050d6b7a56 --- /dev/null +++ b/app/src/main/java/info/nightscout/android/model/CgmStatusEvent.java @@ -0,0 +1,63 @@ +package info.nightscout.android.model; + +import java.util.Date; + +import io.realm.RealmObject; +import io.realm.annotations.Index; + +/** + * Created by lgoedhart on 4/06/2016. + */ +public class CgmStatusEvent extends RealmObject { + public enum TREND { + NONE, + DOUBLE_UP, + SINGLE_UP, + FOURTY_FIVE_UP, + FLAT, + FOURTY_FIVE_DOWN, + SINGLE_DOWN, + DOUBLE_DOWN, + NOT_COMPUTABLE, + RATE_OUT_OF_RANGE, + NOT_SET + } + + @Index + private Date eventDate; // The actual time of the event (assume the capture device eventDate/time is accurate) + private Date pumpDate; // The eventDate/time on the pump at the time of the event + private int sgv; + private String trend; + + public Date getEventDate() { + return eventDate; + } + + public void setEventDate(Date eventDate) { + this.eventDate = eventDate; + } + + public Date getPumpDate() { + return pumpDate; + } + + public void setPumpDate(Date pumpDate) { + this.pumpDate = pumpDate; + } + + public int getSgv() { + return sgv; + } + + public void setSgv(int sgv) { + this.sgv = sgv; + } + + public TREND getTrend() { + return TREND.valueOf(trend); + } + + public void setTrend(TREND trend) { + this.trend = trend.name(); + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..404d801c8250aaa33c13ca53e58b0d9f0e852a05 --- /dev/null +++ b/app/src/main/java/info/nightscout/android/model/medtronicNg/ContourNextLinkInfo.java @@ -0,0 +1,38 @@ +package info.nightscout.android.model.medtronicNg; + +import io.realm.RealmObject; +import io.realm.annotations.PrimaryKey; + +/** + * Created by lgoedhart on 4/06/2016. + */ +public class ContourNextLinkInfo extends RealmObject { + @PrimaryKey + private String serialNumber; + private String hmac; + private String key; + + public String getSerialNumber() { + return serialNumber; + } + + public void setSerialNumber(String serialNumber) { + this.serialNumber = serialNumber; + } + + public String getHmac() { + return hmac; + } + + public void setHmac(String hmac) { + this.hmac = hmac; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } +} diff --git a/app/src/main/java/info/nightscout/android/model/medtronicNg/Pump.java b/app/src/main/java/info/nightscout/android/model/medtronicNg/Pump.java new file mode 100644 index 0000000000000000000000000000000000000000..3d34bef3dceece251d193f1f9b60b6fb4c022d3b --- /dev/null +++ b/app/src/main/java/info/nightscout/android/model/medtronicNg/Pump.java @@ -0,0 +1,58 @@ +package info.nightscout.android.model.medtronicNg; + +import info.nightscout.android.model.CgmStatusEvent; +import io.realm.RealmList; +import io.realm.RealmObject; +import io.realm.annotations.PrimaryKey; + +/** + * Created by lgoedhart on 4/06/2016. + */ +public class Pump extends RealmObject { + @PrimaryKey + private String serialNumber; + private int lastRadioChannel; + private RealmList<ContourNextLinkInfo> associatedCnls; + private RealmList<CgmStatusEvent> cgmHistory; + private RealmList<PumpStatusEvent> pumpHistory; + + public String getSerialNumber() { + return serialNumber; + } + + public void setSerialNumber(String serialNumber) { + this.serialNumber = serialNumber; + } + + public int getLastRadioChannel() { + return lastRadioChannel; + } + + public void setLastRadioChannel(int lastRadioChannel) { + this.lastRadioChannel = lastRadioChannel; + } + + public RealmList<ContourNextLinkInfo> getAssociatedCnls() { + return associatedCnls; + } + + public void setAssociatedCnls(RealmList<ContourNextLinkInfo> associatedCnls) { + this.associatedCnls = associatedCnls; + } + + public RealmList<CgmStatusEvent> getCgmHistory() { + return cgmHistory; + } + + public void setCgmHistory(RealmList<CgmStatusEvent> cgmHistory) { + this.cgmHistory = cgmHistory; + } + + public RealmList<PumpStatusEvent> getPumpHistory() { + return pumpHistory; + } + + public void setPumpHistory(RealmList<PumpStatusEvent> pumpHistory) { + this.pumpHistory = pumpHistory; + } +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..741f1a68891a94ba73e1a374bfff69e2a953c3c6 --- /dev/null +++ b/app/src/main/java/info/nightscout/android/model/medtronicNg/PumpStatusEvent.java @@ -0,0 +1,19 @@ +package info.nightscout.android.model.medtronicNg; + +import java.util.Date; + +import io.realm.RealmObject; +import io.realm.annotations.Index; + +/** + * Created by lgoedhart on 4/06/2016. + */ +public class PumpStatusEvent extends RealmObject { + @Index + private Date eventDate; // The actual time of the event (assume the capture device eventDate/time is accurate) + private Date pumpDate; // The eventDate/time on the pump at the time of the event + private float activeInsulin; + private float reservoirAmount; + private boolean recentBolusWizard; // Whether a bolus wizard has been run recently + private int bolusWizardBGL; // in mg/dL. 0 means no recent bolus wizard reading. +} diff --git a/app/src/main/java/info/nightscout/android/service/AbstractService.java b/app/src/main/java/info/nightscout/android/service/AbstractService.java deleted file mode 100644 index d7f615641f1136a34561c0154c0759ab865ae3ca..0000000000000000000000000000000000000000 --- a/app/src/main/java/info/nightscout/android/service/AbstractService.java +++ /dev/null @@ -1,103 +0,0 @@ -package info.nightscout.android.service; -/* - * This example demonstrates a good way to communicate between Activity and Service. - * - * 1. Implement a service by inheriting from AbstractService - * 2. Add a ServiceManager to your activity - * - Control the service with ServiceManager.start() and .stop() - * - Send messages to the service via ServiceManager.send() - * - Receive messages with by passing a Handler in the constructor - * 3. Send and receive messages on the service-side using send() and onReceiveMessage() - * - * Author: Philipp C. Heckel; based on code by Lance Lefebure from - * http://stackoverflow.com/questions/4300291/example-communication-between-activity-and-service-using-messaging - * Source: https://code.launchpad.net/~binwiederhier/+junk/android-service-example - * Date: 6 Jun 2012 - */ - -import java.util.ArrayList; - -import android.app.Service; -import android.content.Intent; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.util.Log; - -public abstract class AbstractService extends Service { - static final int MSG_REGISTER_CLIENT = 9991; - static final int MSG_UNREGISTER_CLIENT = 9992; - - ArrayList<Messenger> mClients = new ArrayList<Messenger>(); // Keeps track of all current registered clients. - final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler. - - private class IncomingHandler extends Handler { // Handler of incoming messages from clients. - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_REGISTER_CLIENT: - Log.i("MyService", "Client registered: "+msg.replyTo); - mClients.add(msg.replyTo); - break; - case MSG_UNREGISTER_CLIENT: - Log.i("MyService", "Client un-registered: "+msg.replyTo); - mClients.remove(msg.replyTo); - break; - default: - //super.handleMessage(msg); - onReceiveMessage(msg); - } - } - } - - @Override - public void onCreate() { - super.onCreate(); - - onStartService(); - - Log.i("MyService", "Service Started."); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - Log.i("MyService", "Received start id " + startId + ": " + intent); - return START_STICKY; // run until explicitly stopped. - } - - @Override - public IBinder onBind(Intent intent) { - return mMessenger.getBinder(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - - onStopService(); - - Log.i("MyService", "Service Stopped."); - } - - protected void send(Message msg) { - for (int i=mClients.size()-1; i>=0; i--) { - try { - Log.i("MyService", "Sending message to clients: "+msg); - mClients.get(i).send(msg); - } - catch (RemoteException e) { - // The client is dead. Remove it from the list; we are going through the list from back to front so this is safe to do inside the loop. - Log.e("MyService", "Client is dead. Removing from list: "+i); - mClients.remove(i); - } - } - } - - - public abstract void onStartService(); - public abstract void onStopService(); - public abstract void onReceiveMessage(Message msg); - -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/android/service/ServiceManager.java b/app/src/main/java/info/nightscout/android/service/ServiceManager.java deleted file mode 100644 index f87dc5b708db0035ef907fd21f4d3ea80d195ad7..0000000000000000000000000000000000000000 --- a/app/src/main/java/info/nightscout/android/service/ServiceManager.java +++ /dev/null @@ -1,152 +0,0 @@ -package info.nightscout.android.service; - -/* - * This example demonstrates a good way to communicate between Activity and Service. - * - * 1. Implement a service by inheriting from AbstractService - * 2. Add a ServiceManager to your activity - * - Control the service with ServiceManager.start() and .stop() - * - Send messages to the service via ServiceManager.send() - * - Receive messages with by passing a Handler in the constructor - * 3. Send and receive messages on the service-side using send() and onReceiveMessage() - * - * Author: Philipp C. Heckel; based on code by Lance Lefebure from - * http://stackoverflow.com/questions/4300291/example-communication-between-activity-and-service-using-messaging - * Source: https://code.launchpad.net/~binwiederhier/+junk/android-service-example - * Date: 6 Jun 2012 - */ - -import android.app.ActivityManager; -import android.app.ActivityManager.RunningServiceInfo; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.util.Log; - -public class ServiceManager { - private Class<? extends AbstractService> mServiceClass; - private Context mActivity; - private boolean mIsBound; - private Messenger mService = null; - private Handler mIncomingHandler = null; - private final Messenger mMessenger = new Messenger(new IncomingHandler()); - - private class IncomingHandler extends Handler { - @Override - public void handleMessage(Message msg) { - if (mIncomingHandler != null) { - Log.i("ServiceHandler", "Incoming message. Passing to handler: "+msg); - mIncomingHandler.handleMessage(msg); - } - } - } - - private ServiceConnection mConnection = new ServiceConnection() { - public void onServiceConnected(ComponentName className, IBinder service) { - mService = new Messenger(service); - //textStatus.setText("Attached."); - Log.i("ServiceHandler", "Attached."); - try { - Message msg = Message.obtain(null, AbstractService.MSG_REGISTER_CLIENT); - msg.replyTo = mMessenger; - mService.send(msg); - } catch (RemoteException e) { - // In this case the service has crashed before we could even do anything with it - } - } - - public void onServiceDisconnected(ComponentName className) { - // This is called when the connection with the service has been unexpectedly disconnected - process crashed. - mService = null; - //textStatus.setText("Disconnected."); - Log.i("ServiceHandler", "Disconnected."); - } - }; - - public ServiceManager(Context context, Class<? extends AbstractService> serviceClass, Handler incomingHandler) { - this.mActivity = context; - this.mServiceClass = serviceClass; - this.mIncomingHandler = incomingHandler; - - if (isRunning()) { - doBindService(); - } - } - - public void start() { - doStartService(); - doBindService(); - } - - public void stop() { - doUnbindService(); - doStopService(); - } - - /** - * Use with caution (only in Activity.onDestroy())! - */ - public void unbind() { - doUnbindService(); - } - - public boolean isRunning() { - ActivityManager manager = (ActivityManager) mActivity.getSystemService(Context.ACTIVITY_SERVICE); - - for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { - if (mServiceClass.getName().equals(service.service.getClassName())) { - return true; - } - } - - return false; - } - - public void send(Message msg) throws RemoteException { - if (mIsBound) { - if (mService != null) { - mService.send(msg); - } - } - } - - private void doStartService() { - mActivity.startService(new Intent(mActivity, mServiceClass)); - } - - private void doStopService() { - mActivity.stopService(new Intent(mActivity, mServiceClass)); - } - - private void doBindService() { - mActivity.bindService(new Intent(mActivity, mServiceClass), mConnection, Context.BIND_AUTO_CREATE); - mIsBound = true; - } - - private void doUnbindService() { - if (mIsBound) { - // If we have received the service, and hence registered with it, then now is the time to unregister. - if (mService != null) { - try { - Message msg = Message.obtain(null, AbstractService.MSG_UNREGISTER_CLIENT); - msg.replyTo = mMessenger; - mService.send(msg); - } catch (RemoteException e) { - // There is nothing special we need to do if the service has crashed. - } - } - - // Detach our existing connection. - mActivity.unbindService(mConnection); - mIsBound = false; - //textStatus.setText("Unbinding."); - Log.i("ServiceHandler", "Unbinding."); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/android/settings/SettingsActivity.java b/app/src/main/java/info/nightscout/android/settings/SettingsActivity.java index 0110a50e4ed7cb47721c12752ab591dea22f8950..e004f7b6284ae5dd3b1791d94ebe983d900e5908 100644 --- a/app/src/main/java/info/nightscout/android/settings/SettingsActivity.java +++ b/app/src/main/java/info/nightscout/android/settings/SettingsActivity.java @@ -1,14 +1,39 @@ package info.nightscout.android.settings; +import android.content.Context; import android.os.Bundle; -import android.preference.PreferenceActivity; +import android.support.v7.app.AppCompatActivity; +import android.view.MenuItem; + +import info.nightscout.android.R; +import uk.co.chrisjenx.calligraphy.CalligraphyContextWrapper; + +public class SettingsActivity extends AppCompatActivity { -public class SettingsActivity extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setContentView(R.layout.activity_settings); /* set fragment */ - getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit(); + getFragmentManager().beginTransaction().replace(R.id.settings_frame, new SettingsFragment()).commit(); + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setTitle("Settings"); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + break; + } + return true; + } + + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CalligraphyContextWrapper.wrap(newBase)); } } \ No newline at end of file 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 dea60c93080fce7b89c2babebef87d564f67eef4..7519a5c7f75cc4e177012ca37b2ec08d272d0b8a 100644 --- a/app/src/main/java/info/nightscout/android/settings/SettingsFragment.java +++ b/app/src/main/java/info/nightscout/android/settings/SettingsFragment.java @@ -9,7 +9,6 @@ import android.preference.MultiSelectListPreference; import android.preference.Preference; import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; -import android.preference.SwitchPreference; import info.nightscout.android.R; @@ -21,9 +20,7 @@ public class SettingsFragment extends PreferenceFragment implements OnSharedPref /* set preferences */ addPreferencesFromResource(R.xml.preferences); - - addMedtronicOptionsListener(); - + // iterate through all preferences and update to saved value for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) { initSummary(getPreferenceScreen().getPreference(i)); @@ -74,14 +71,4 @@ public class SettingsFragment extends PreferenceFragment implements OnSharedPref p.setSummary(editTextPref.getText()); } } - - private void addMedtronicOptionsListener(){ - final SwitchPreference enableRest = (SwitchPreference)findPreference("EnableRESTUpload"); - enableRest.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - final Boolean val = (Boolean)newValue; - return true; - } - }); - } } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/android/upload/MedtronicNG/PumpStatusRecord.java b/app/src/main/java/info/nightscout/android/upload/MedtronicNG/PumpStatusRecord.java index b4ad000bf45b49a07b8bb57314a78436bd9bfff0..8f0c5c239ea3c17f131b2e2088f2bf567dad9f1f 100644 --- a/app/src/main/java/info/nightscout/android/upload/MedtronicNG/PumpStatusRecord.java +++ b/app/src/main/java/info/nightscout/android/upload/MedtronicNG/PumpStatusRecord.java @@ -10,11 +10,6 @@ import java.util.Date; * Created by lgoedhart on 27/03/2016. */ public class PumpStatusRecord extends DeviceRecord implements Serializable { - - public String alarm = "---"; // Not sure where this is yet - public String temporaryBasal = "---"; // Not sure where this is yet - public String model = "---"; // Available? - public int batteryPercentage; public Date pumpDate = new Date(); public BigDecimal activeInsulin = new BigDecimal(0); diff --git a/app/src/main/java/info/nightscout/android/upload/UploadHelper.java b/app/src/main/java/info/nightscout/android/upload/UploadHelper.java index 065a28afaeb1c35d361e35e5764e1b011002a160..d6c06f609a458b297eb2df36aeb33c29fed4ee2a 100644 --- a/app/src/main/java/info/nightscout/android/upload/UploadHelper.java +++ b/app/src/main/java/info/nightscout/android/upload/UploadHelper.java @@ -33,7 +33,7 @@ import java.util.regex.Pattern; import ch.qos.logback.classic.Logger; import info.nightscout.android.R; -import info.nightscout.android.medtronic.Medtronic640gActivity; +import info.nightscout.android.medtronic.MainActivity; import info.nightscout.android.medtronic.MedtronicConstants; import info.nightscout.android.upload.MedtronicNG.CGMRecord; @@ -53,10 +53,6 @@ public class UploadHelper extends AsyncTask<Record, Integer, Long> { public static final Object isModifyingRecordsLock = new Object(); public UploadHelper(Context context) { - this(context, Medtronic640gActivity.CNL_24); - } - - public UploadHelper(Context context, int cgmSelected) { this.context = context; settings = context.getSharedPreferences(MedtronicConstants.PREFS_NAME, 0); synchronized (isModifyingRecordsLock) { @@ -411,19 +407,19 @@ public class UploadHelper extends AsyncTask<Record, Integer, Long> { log.info("devicestatusURL: " + devicestatusURL); JSONObject json = new JSONObject(); - json.put("uploaderBattery", Medtronic640gActivity.batLevel); - json.put("device", Medtronic640gActivity.pumpStatusRecord.getDeviceName() ); + json.put("uploaderBattery", MainActivity.batLevel); + json.put("device", MainActivity.pumpStatusRecord.getDeviceName() ); JSONObject pumpInfo = new JSONObject(); - pumpInfo.put( "clock", Medtronic640gActivity.pumpStatusRecord.pumpDate ); - pumpInfo.put( "reservoir", Medtronic640gActivity.pumpStatusRecord.reservoirAmount); + pumpInfo.put( "clock", MainActivity.pumpStatusRecord.pumpDate ); + pumpInfo.put( "reservoir", MainActivity.pumpStatusRecord.reservoirAmount); JSONObject iob = new JSONObject(); - iob.put( "timestamp", Medtronic640gActivity.pumpStatusRecord.pumpDate ); - iob.put( "bolusiob", Medtronic640gActivity.pumpStatusRecord.activeInsulin ); + iob.put( "timestamp", MainActivity.pumpStatusRecord.pumpDate ); + iob.put( "bolusiob", MainActivity.pumpStatusRecord.activeInsulin ); JSONObject battery = new JSONObject(); - battery.put( "percent", Medtronic640gActivity.pumpStatusRecord.batteryPercentage ); + battery.put( "percent", MainActivity.pumpStatusRecord.batteryPercentage ); pumpInfo.put( "iob", iob ); pumpInfo.put( "battery", battery ); @@ -444,20 +440,17 @@ public class UploadHelper extends AsyncTask<Record, Integer, Long> { private void populateV1APIEntry(JSONObject json, Record oRecord) throws Exception { if (oRecord instanceof CGMRecord) { - json.put("date", ((CGMRecord) oRecord).sgvDate.getTime()); - json.put("dateString", oRecord.displayTime); + CGMRecord pumpRecord = (CGMRecord) oRecord; + json.put("sgv", pumpRecord.sgv); + json.put("direction", pumpRecord.direction); + json.put("device", pumpRecord.getDeviceName()); + json.put("type", "sgv"); + json.put("date", pumpRecord.sgvDate.getTime()); + json.put("dateString", pumpRecord.sgvDate); } else { Date date = DATE_FORMAT.parse(oRecord.displayTime); json.put("date", date.getTime()); } - - if (oRecord instanceof CGMRecord){ - CGMRecord pumpRecord = (CGMRecord) oRecord; - json.put("sgv", pumpRecord.sgv); - json.put("direction", pumpRecord.direction); - json.put("device", pumpRecord.getDeviceName()); - json.put("type", "sgv"); - } } private static String convertStreamToString(InputStream is) { diff --git a/app/src/main/res/drawable/drawer_header.jpg b/app/src/main/res/drawable/drawer_header.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e3f8ab881ebc761afbfdad7ae6b554adb658d83a Binary files /dev/null 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 d1f5cfe4ff088813d271a15840080fc40275bee8..f8dec0427c4c8487c39cce4a993fa624cf926080 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -2,6 +2,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:app="http://schemas.android.com/apk/res-auto" android:gravity="center_horizontal" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" @@ -61,15 +62,6 @@ android:maxLines="1" android:singleLine="true"/> - <Button - android:id="@+id/username_sign_in_button" - style="?android:textAppearanceSmall" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="16dp" - android:text="@string/action_sign_in" - android:textStyle="bold"/> - </LinearLayout> <LinearLayout @@ -83,14 +75,6 @@ android:id="@+id/registered_usb_devices" /> </LinearLayout> - <Button - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/close" - android:id="@+id/close_button" - android:layout_gravity="center_horizontal" - android:visibility="invisible" /> - </LinearLayout> </ScrollView> diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000000000000000000000000000000000000..5ecb12545edb96666e30bb41f1e8810666aa2480 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,175 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <android.support.design.widget.AppBarLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> + + <android.support.v7.widget.Toolbar + android:id="@+id/toolbar" + android:layout_width="match_parent" + android:layout_height="wrap_content" + app:layout_scrollFlags="scroll|enterAlways" + app:popupTheme="@style/ThemeOverlay.AppCompat.Light" + app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> + + </android.support.v7.widget.Toolbar> + + </android.support.design.widget.AppBarLayout> + + <LinearLayout + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_marginBottom="10sp" + android:layout_marginTop="10sp" + android:baselineAligned="true" + android:gravity="bottom" + android:orientation="vertical"> + + <TextView + android:id="@+id/textview_bg_time" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:layout_marginTop="5sp" + android:text="3 minutes ago" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom|center_horizontal" + android:baselineAligned="false"> + + <TextView + android:id="@+id/textview_bg" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="bottom" + android:layout_weight="1" + android:singleLine="true" + android:text="-" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textSize="70sp" /> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="fill_parent" + android:layout_gravity="bottom" + android:layout_weight="1" + android:gravity="bottom|center_horizontal" + android:orientation="vertical"> + + <TextView + android:id="@+id/textview_trend" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center|top" + android:singleLine="true" + android:text="-" + android:textAppearance="?android:attr/textAppearanceLarge" + android:textSize="40sp" /> + + <TextView + android:id="@+id/textview_units" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:singleLine="true" + android:text="mmol/L" + android:textAppearance="?android:attr/textAppearanceSmall" /> + + </LinearLayout> + + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="center_horizontal" + android:orientation="horizontal" + android:paddingTop="10sp"> + + <TextView + android:id="@+id/label_iob" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Active Insulin: " + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <TextView + android:id="@+id/textview_iob" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="-" + android:textAppearance="?android:attr/textAppearanceMedium" /> + + <TextView + android:id="@+id/label_units" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text=" U" + android:textAppearance="?android:attr/textAppearanceMedium" /> + </LinearLayout> + + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:orientation="horizontal"> + + <Button + android:id="@+id/button_stop_service" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_text_stop_uploading_data" /> + + </LinearLayout> + + <LinearLayout + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:orientation="horizontal"> + + <Button + android:id="@+id/button_start_service" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_text_get_now" /> + + <Button + android:id="@+id/button_clear_log" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/button_text_clear_log" /> + </LinearLayout> + + <ScrollView + android:id="@+id/scrollView" + android:layout_width="match_parent" + android:layout_height="fill_parent"> + + <LinearLayout + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + <TextView + android:id="@+id/textview_log" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_margin="10sp" + android:maxLines="20" + android:text="" /> + </LinearLayout> + </ScrollView> + +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..d8309fd9621fe9f1120c4e1be6b01713a04b4668 --- /dev/null +++ b/app/src/main/res/layout/activity_settings.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/settings_frame" + android:layout_width="fill_parent" + android:layout_height="fill_parent" /> \ No newline at end of file diff --git a/app/src/main/res/layout/adb.xml b/app/src/main/res/layout/adb.xml deleted file mode 100644 index 9e1dba225c4528214e90e9b98d55dcbe0c5b3833..0000000000000000000000000000000000000000 --- a/app/src/main/res/layout/adb.xml +++ /dev/null @@ -1,41 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:orientation="vertical" - android:paddingTop="15dp"> - - <TextView - android:id="@+id/demoTitle" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textSize="50sp" - android:gravity="center" - android:textStyle="bold" - - android:text="@string/hello" /> - - <TextView - android:id="@+id/demoText" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textSize="20sp" - - android:gravity="start" /> - - <ScrollView - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:padding="10dp"> - - <LinearLayout android:id="@+id/container" - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="wrap_content"> - </LinearLayout> - </ScrollView> - - -</LinearLayout> - - diff --git a/app/src/main/res/menu/menu.xml b/app/src/main/res/menu/menu.xml index 66a845035a8bc1a2b96c08db01ed3a528cf30ff0..ed398f07134bc58c192bc0139912bb2c2ac27c2d 100644 --- a/app/src/main/res/menu/menu.xml +++ b/app/src/main/res/menu/menu.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<menu xmlns:android="http://schemas.android.com/apk/res/android"> +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menu_settings" android:orderInCategory="100" diff --git a/app/src/main/res/menu/menu_register_usb.xml b/app/src/main/res/menu/menu_register_usb.xml new file mode 100644 index 0000000000000000000000000000000000000000..81a6c5646903e8d5f192edbd9d651e4b025c70dc --- /dev/null +++ b/app/src/main/res/menu/menu_register_usb.xml @@ -0,0 +1,9 @@ +<?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-v11/styles.xml b/app/src/main/res/values-v11/styles.xml deleted file mode 100644 index d4787af956a669791afa0ff3cb5cf1164771aede..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-v11/styles.xml +++ /dev/null @@ -1,11 +0,0 @@ -<resources> - - <!-- - Base application theme for API 11+. This theme completely replaces - AppBaseTheme from res/values/styles.xml on API 11+ devices. - --> - <style name="AppBaseTheme" parent="android:Theme.DeviceDefault"> - <!-- API 11 theme customizations can go here. --> - </style> - -</resources> diff --git a/app/src/main/res/values-v14/styles.xml b/app/src/main/res/values-v14/styles.xml deleted file mode 100644 index 9baa6e219d568d68c95b88bdbe697cc0322e8f3e..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-v14/styles.xml +++ /dev/null @@ -1,12 +0,0 @@ -<resources> - - <!-- - Base application theme for API 14+. This theme completely replaces - AppBaseTheme from BOTH res/values/styles.xml and - res/values-v11/styles.xml on API 14+ devices. - --> - <style name="AppBaseTheme" parent="android:Theme.DeviceDefault"> - <!-- API 14 theme customizations can go here. --> - </style> - -</resources> diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml deleted file mode 100644 index 5f2c7258abfce1dad6b97ac6d6c11006dcb2fcce..0000000000000000000000000000000000000000 --- a/app/src/main/res/values-v21/styles.xml +++ /dev/null @@ -1,7 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - - <style name="AppBaseTheme" parent="android:Theme.DeviceDefault"> - <!-- API 11 theme customizations can go here. --> - </style> -</resources> \ 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 f0a3a09f14d46179f1126366e4e08d38b0cd5804..4622e91ea33e751de165b7f071d94a5aa9efb7ea 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -41,4 +41,6 @@ <string name="preference_eula_accepted">IUNDERSTAND</string> <string name="preference_enable_rest_upload">EnableRESTUpload</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> </resources> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml new file mode 100644 index 0000000000000000000000000000000000000000..d5d511766e2bf455a639fbe087a72025766bf3e2 --- /dev/null +++ b/app/src/main/res/values/styles.xml @@ -0,0 +1,23 @@ +<resources> + + <!-- Base application theme. --> + <style name="AppTheme" parent="Theme.AppCompat.NoActionBar"> + <!-- Customize your theme here. --> + <!-- MaterialDrawer specific values --> + <item name="material_drawer_background">@color/material_drawer_dark_background</item> + <item name="material_drawer_primary_text">@color/material_drawer_dark_primary_text</item> + <item name="material_drawer_primary_icon">@color/material_drawer_dark_primary_icon</item> + <item name="material_drawer_secondary_text">@color/material_drawer_dark_secondary_text</item> + <item name="material_drawer_hint_text">@color/material_drawer_dark_hint_text</item> + <item name="material_drawer_divider">@color/material_drawer_dark_divider</item> + <item name="material_drawer_selected">@color/material_drawer_dark_selected</item> + <item name="material_drawer_selected_text">@color/material_drawer_dark_selected_text</item> + <item name="material_drawer_header_selection_text">@color/material_drawer_dark_header_selection_text</item> + </style> + + <!-- Settings theme. Has an action bar. --> + <style name="SettingsTheme" parent="@style/Theme.AppCompat"> + + </style> + +</resources> diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 96bddb3ddfeccca76ac69efb6f74abe9890175a9..3a039ba36f60428eed118a73ba7734eac5e66c59 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -4,51 +4,51 @@ <info.nightscout.android.utils.CustomSwitchPreference android:disableDependentsState="false" android:key="mmolxl" - android:summaryOff="mg/dl. Values are shown and set in mg/dl" - android:summaryOn="mmol/l. Values are shown and set in mmol/l" - android:switchTextOff="mg/dl" - android:switchTextOn="mmol/l" - android:title="mmol/l"></info.nightscout.android.utils.CustomSwitchPreference> + android:summaryOff="Values are shown and set in mg/dL" + android:summaryOn="Values are shown and set in mmol/L" + android:switchTextOff="mg/dL" + android:switchTextOn="mmol/L" + android:title="BG Unit"/> <info.nightscout.android.utils.CustomSwitchPreference android:defaultValue="false" android:dependency="mmolxl" android:key="mmolDecimals" - android:summaryOff="Deactivated. 1 Decimal value will be shown ." - android:summaryOn="Activated. 2 Decimal values will be shown ." + android:summaryOff="1 decimal value will be shown" + android:summaryOn="2 decimal values will be shown" android:switchTextOff="1" android:switchTextOn="2" - android:title="mmol/l decimals"></info.nightscout.android.utils.CustomSwitchPreference> + android:title="Decimals"/> </PreferenceCategory> <PreferenceCategory android:title="Sharing"> - <info.nightscout.android.utils.CustomSwitchPreference + <CheckBoxPreference android:disableDependentsState="false" android:key="@string/preference_enable_rest_upload" android:summary="Enable upload of data to Nightscout" - android:title="REST API Upload"></info.nightscout.android.utils.CustomSwitchPreference> + android:title="REST API Upload"/> <EditTextPreference android:defaultValue="https://YOUR.NIGHTSCOUT.SITE" android:dependency="@string/preference_enable_rest_upload" android:dialogMessage="The hostname of your Nightscout site" android:dialogTitle="Enter Nightscout URL" android:key="@string/preference_nightscout_url" - android:title="Nightscout URL"></EditTextPreference> + android:title="Nightscout URL"/> <info.nightscout.android.utils.ValidatingEditTextPreference android:defaultValue="YOURAPISECRET" android:dependency="@string/preference_enable_rest_upload" android:dialogMessage="Your Nightscout API secret" android:dialogTitle="Enter your Nightscout API secret" android:key="@string/preference_api_secret" - android:title="API Secret"></info.nightscout.android.utils.ValidatingEditTextPreference> + android:title="API Secret"/> </PreferenceCategory> <PreferenceCategory android:title="Disclaimer"> - <info.nightscout.android.utils.CustomSwitchPreference + <SwitchPreference android:disableDependentsState="false" android:key="@string/preference_eula_accepted" - android:summaryOff="Deactivated. Nightscout should not be used to make medical decisions. There is no support or any warranty of any kind. The quality and performance of the project is with you. This is a project that was created and is supported completely by volunteers" - android:summaryOn="Activated. Nightscout should not be used to make medical decisions. There is no support or any warranty of any kind. The quality and performance of the project is with you. This is a project that was created and is supported completely by volunteers" + android:summaryOff="Nightscout should not be used to make medical decisions. There is no support or any warranty of any kind. The quality and performance of the project is with you. This is a project that was created and is supported completely by volunteers" + android:summaryOn="Nightscout should not be used to make medical decisions. There is no support or any warranty of any kind. The quality and performance of the project is with you. This is a project that was created and is supported completely by volunteers" android:switchTextOff="NO" android:switchTextOn="YES" - android:title="I UNDERSTAND"></info.nightscout.android.utils.CustomSwitchPreference> + android:title="I UNDERSTAND"/> </PreferenceCategory> <PreferenceCategory android:title="App Version"> <Preference @@ -56,12 +56,12 @@ android:title="@string/versionName" /> </PreferenceCategory> <PreferenceCategory android:title="Debug"> - <info.nightscout.android.utils.CustomSwitchPreference + <SwitchPreference android:defaultValue="true" android:key="@string/preferences_enable_crashlytics" android:summary="Send crash errors to developer" - android:title="Automatic Crash Reporting" /> - <info.nightscout.android.utils.CustomSwitchPreference + android:title="Crash Reporting" /> + <SwitchPreference android:defaultValue="true" android:key="@string/preferences_enable_answers" android:summary="Sends usage data to the developer to help develop a better app." diff --git a/build.gradle b/build.gradle index f349d7384acb1a761ddbb0f7b2b7702f25892d42..c08cd482b77a2b4b7463d7023f54a0d5f4adb69f 100644 --- a/build.gradle +++ b/build.gradle @@ -8,6 +8,7 @@ buildscript { classpath 'com.android.tools.build:gradle:2.1.0' // 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" } }