diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml
new file mode 100644
index 0000000..7ec0147
--- /dev/null
+++ b/.github/workflows/android.yml
@@ -0,0 +1,21 @@
+name: Android CI
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: set up JDK 1.8
+ uses: actions/setup-java@v1
+ with:
+ java-version: 1.8
+ - name: Build with Gradle
+ run: ./gradlew build
diff --git a/.gitignore b/.gitignore
index 39fb081..ffae0c6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,15 @@
/build
/captures
.externalNativeBuild
+.idea/*
+/.idea
+.idea/modules.xml
+.idea/misc.xml
+.idea/gradle.xml
+.idea/compiler.xml
+/app
+.idea/misc.xml
+.idea/misc.xml
+.idea/modules.xml
+.idea/misc.xml
+.idea/modules.xml
diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
index a946cbe..fc22fce 100644
Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 30aa626..681f41a 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -1,29 +1,116 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..b86273d
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 7ac24c7..af17e69 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -1,17 +1,19 @@
+
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
new file mode 100644
index 0000000..a5f05cd
--- /dev/null
+++ b/.idea/jarRepositories.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index e0d5b93..c59d3df 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,11 +1,18 @@
-
+
+
+
+
+
+
-
+
@@ -13,23 +20,41 @@
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index 66a081c..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
deleted file mode 100644
index 7f68460..0000000
--- a/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Changelog.md b/Changelog.md
new file mode 100644
index 0000000..8aea447
--- /dev/null
+++ b/Changelog.md
@@ -0,0 +1,32 @@
+# Version 2.3.0
+## New Features
+* RAW Data Export: For Debugging purposes RAW Data can be exported to a file in JSON format. The file is stored in the Download folder and contains the Data of the last hours as defined in "Max sync hours"
+
+## Bugfixes
+* Smoothing: Internally switched to float values for more precise smoothing
+* Smoothing: better handling of first values after gaps in measurements (e.g. because the transmitter had no connection to the sensor or has been charged)
+
+# Version 2.3.1
+* Added Code comments
+* Fixed spelling in descriptions
+
+# Version 2.3.2
+## New Features
+* Esel does not send future vaules
+* Values can be shifted (by total days) to the future (usefull if phone time is shifted to a date in the past)
+
+# Version 3.0.1
+## New Features
+* New icon: we are a pirate donkey now!
+* Companion Mode: ESEL can read CGM values from the notifications provided by the Eversense app
+* Access to [eversensedms.com](https://www.eversensedms.com/) to fill missing data
+* Fixes for smoothing and calculation of direction
+
+# Version 3.0.2
+* Changed synchronization of datareader to one common sync
+
+# Version 3.0.3
+* For notification lisener: added support for com.senseonics.eversense365.us and generic "com.senseonics."
+
+# Version 3.0.4
+* Added support for us.eversensedms.com for backfilling data from Eversense server
diff --git a/README.md b/README.md
index 4079783..b7c9414 100644
--- a/README.md
+++ b/README.md
@@ -1,16 +1,35 @@
# Esel
+There are two different methods how to access the readings from Eversense:
+* Companion mode, which reads the data from the Eversense notifications (works with the standard Eversense App, available since ESEL version 3.0.1)
+* Patched mode, which requires a patched version of the Eversense App (works completely offline, including backfilling)
-1. Uninstall the Eversense App (Warning: your local historical data (older than 1 week) will be lost!)
-2. Install the patched Eversense app (mod_com.senseonics.gen12androidapp-release.apk) and use it as described by the vendor
+First of all, you need to install ESEL:
+1. Get the ESEL apk e.g. from https://github.com/BernhardRo/Esel/tree/master/apk
+2. Install the apk on your phone
* You need to enable installation of Apps from unknown sources
- * Start the Eversense App, login, connect to your transmitter and use it just like the normal app.
-3. Build https://github.com/BernhardRo/Esel and install it on your phone.
-4. Configuration:
+3. Configuration:
* Allow ESEL to run in the background (it will ask for it)
+ * Allow ESEL access to the Android Notifications (it will ask for it)
+ * In newer Android versions, these settings may be not directly accessible due to restricted settings. In this case restricted settings must be allowed first, see "Allow restricted settings" in https://support.google.com/android/answer/12623953
* Upload to Nightscout: Activate "Send to NightScout" in the preferences. It needs a configured AndroidAPS with internal NSClient or NSClient itself installed on the same phone
* Inter-App-Broadcasts: Activate "Send to AAPS and xDrip". In xDrip and/or AndroidAPS activate the input method "640g/Eversense".
* "Smooth Data" applies a smoothing algorithm to the raw values and provides these smoothed values instead of the raw readings. Smoothing is per default disabled.
- * For feedback contact @BernhardRo
-4. For the modification of the Eversense App, see: https://github.com/BernhardRo/Esel/wiki/How-to-modify-the-Android-Eversense-App
-If you run esel with a fresh installation of Eversense for the first time, it can take up to 15min until your first values appear in xDrip!
\ No newline at end of file
+## Companion Mode
+1. Install/use the official Eversense App from the Google Play Store
+ * Optional, but required for backfilling: Login to your Eversense account with your login data
+ * In Sync, enable Auto synchronization
+3. Configuration of ESEL:
+ * Disable the setting "Get data from patched Eversense App"
+ * For backfilling: Enable "Fill missing data from eversensedms.com"
+ * Provide as Email address and password your Eversense login data
+
+## Patched Eversense App
+1. Uninstall the Eversense App (Warning: your local historical data (older than 1 week) will be lost!)
+2. Install the patched Eversense app (e.g. get it from https://cr4ck3d3v3r53n53.club) and use it as described by the vendor
+ * You need to enable installation of Apps from unknown sources
+ * Start the Eversense App, login, connect to your transmitter and use it just like the normal app.
+3. Configuration of ESEL:
+ * Enable the setting "Get data from patched Eversense App"
+
+If you run ESEL with a fresh installation of Eversense for the first time, it can take up to 15min until your first values appear in xDrip!
diff --git a/apk/Eversense_CGM_v1.0.410-patched.apk b/apk/Eversense_CGM_v1.0.410-patched.apk
new file mode 100644
index 0000000..01579ee
Binary files /dev/null and b/apk/Eversense_CGM_v1.0.410-patched.apk differ
diff --git a/apk/Eversense_com_us_v2_0_103.senseonics.androidapp-patched.apk b/apk/Eversense_com_us_v2_0_103.senseonics.androidapp-patched.apk
new file mode 100644
index 0000000..8a8caf5
Binary files /dev/null and b/apk/Eversense_com_us_v2_0_103.senseonics.androidapp-patched.apk differ
diff --git a/apk/README.md b/apk/README.md
index 2a29650..96e9a7c 100644
--- a/apk/README.md
+++ b/apk/README.md
@@ -2,16 +2,16 @@
1. Uninstall the Eversense App (Warning: your local historical data (older than 1 week) will be lost!)
2. Install the patched Eversense app (mod_com.senseonics.gen12androidapp-release.apk) and use it as described by the vendor
- * You need to enable installation of Apps from unknown sources
- * Start the Eversense App, login, connect to your transmitter and use it just like the normal app.
+ * You need to enable installation of Apps from unknown sources
+ * Start the Eversense App, login, connect to your transmitter and use it just like the normal app.
3. Install esel.apk on your phone.
4. Configuration:
- * Allow ESEL to run in the background (it will ask for it)
- * Upload to Nightscout: Activate "Send to NightScout" in the preferences. It needs a configured AndroidAPS with internal NSClient or NSClient itself installed on the same phone
- * Inter-App-Broadcasts: Activate "Send to AAPS and xDrip". In xDrip and/or AndroidAPS activate the input method "640g/Eversense".
- * "Smooth Data" applies a smoothing algorithm to the raw values and provides these smoothed values instead of the raw readings. Smoothing is per default disabled.
+ * Allow ESEL to run in the background (it will ask for it)
+ * Upload to Nightscout: Activate "Send to NightScout" in the preferences. It needs a configured AndroidAPS with internal NSClient or NSClient itself installed on the same phone
+ * Inter-App-Broadcasts: Activate "Send to AAPS and xDrip". In xDrip and/or AndroidAPS activate the input method "640g/Eversense".
+ * "Smooth Data" applies a smoothing algorithm to the raw values and provides these smoothed values instead of the raw readings. Smoothing is per default disabled.
5. Install xDrip: https://jamorham.github.io/#xdrip-plus (Download latest APK)
- * Use as Datasource 640G / EverSense
+ * Use as Datasource 640G / EverSense
If you run esel with a fresh installation of Eversense for the first time, it can take up to 15min until your first values appear in xDrip!
diff --git a/apk/esel.apk b/apk/esel.apk
deleted file mode 100644
index 7f61fcd..0000000
Binary files a/apk/esel.apk and /dev/null differ
diff --git a/apk/esel_303_us.apk b/apk/esel_303_us.apk
new file mode 100644
index 0000000..7471a2e
Binary files /dev/null and b/apk/esel_303_us.apk differ
diff --git a/apk/esel_304.apk b/apk/esel_304.apk
new file mode 100644
index 0000000..ceeb9c0
Binary files /dev/null and b/apk/esel_304.apk differ
diff --git a/apk/esel_305.apk b/apk/esel_305.apk
new file mode 100644
index 0000000..d25e642
Binary files /dev/null and b/apk/esel_305.apk differ
diff --git a/apk/esel_306.apk b/apk/esel_306.apk
new file mode 100644
index 0000000..7a8c369
Binary files /dev/null and b/apk/esel_306.apk differ
diff --git a/app/build.gradle b/app/build.gradle
index 9873ab8..018260d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,12 +1,11 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ compileSdk 30
defaultConfig {
applicationId "esel.esel.esel"
- minSdkVersion 22
- targetSdkVersion 25
+ minSdk 26
+ targetSdk 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -17,16 +16,23 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
+ namespace 'esel.esel.esel'
}
dependencies {
- compile fileTree(dir: 'libs', include: ['*.jar'])
- androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+ implementation 'com.squareup.retrofit2:adapter-guava:2.9.0'
+ implementation 'com.google.code.gson:gson:2.10.1'
+ implementation 'com.squareup.retrofit2:retrofit-converters:2.8.1'
+ implementation 'com.squareup.retrofit2:adapter-guava:2.9.0'
+ implementation 'com.squareup.retrofit2:adapter-guava:2.9.0'
+ androidTestImplementation('com.android.support.test.espresso:espresso-core:3.0.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
- compile 'com.android.support:appcompat-v7:25.3.1'
- compile 'com.android.support:support-v4:25.3.1'
- compile 'com.android.support:design:25.3.1'
- compile 'com.android.support.constraint:constraint-layout:1.0.2'
- testCompile 'junit:junit:4.12'
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+ implementation 'com.android.support:support-v4:28.0.0'
+ implementation 'com.android.support:design:28.0.0'
+ implementation 'com.android.support.constraint:constraint-layout:2.0.4'
+ implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
+ testImplementation 'junit:junit:4.13.2'
}
diff --git a/app/debug/app-debug.apk b/app/debug/app-debug.apk
index af0b715..177031d 100644
Binary files a/app/debug/app-debug.apk and b/app/debug/app-debug.apk differ
diff --git a/app/debug/esel.apk b/app/debug/esel.apk
deleted file mode 100644
index 97b7f46..0000000
Binary files a/app/debug/esel.apk and /dev/null differ
diff --git a/app/debug/output-metadata.json b/app/debug/output-metadata.json
new file mode 100644
index 0000000..c1d9d00
--- /dev/null
+++ b/app/debug/output-metadata.json
@@ -0,0 +1,21 @@
+{
+ "version": 3,
+ "artifactType": {
+ "type": "APK",
+ "kind": "Directory"
+ },
+ "applicationId": "esel.esel.esel",
+ "variantName": "debug",
+ "elements": [
+ {
+ "type": "SINGLE",
+ "filters": [],
+ "attributes": [],
+ "versionCode": 1,
+ "versionName": "1.0",
+ "outputFile": "app-debug.apk"
+ }
+ ],
+ "elementType": "File",
+ "minSdkVersionForDexing": 26
+}
\ No newline at end of file
diff --git a/app/debug/output.json b/app/debug/output.json
deleted file mode 100644
index f20a39f..0000000
--- a/app/debug/output.json
+++ /dev/null
@@ -1 +0,0 @@
-[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":1,"versionName":"1.0","enabled":true,"outputFile":"app-debug.apk","fullName":"debug","baseName":"debug"},"path":"app-debug.apk","properties":{}}]
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5f365eb..e538d8b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,11 +1,14 @@
-
+
-
+
+
+
+
+
-
-
-
@@ -39,8 +40,21 @@
-
-
+
+
+
+
+
+
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png
new file mode 100644
index 0000000..3ce16bb
Binary files /dev/null and b/app/src/main/ic_launcher-playstore.png differ
diff --git a/app/src/main/java/esel/esel/esel/ErrorsActivity.java b/app/src/main/java/esel/esel/esel/ErrorsActivity.java
deleted file mode 100644
index 3569937..0000000
--- a/app/src/main/java/esel/esel/esel/ErrorsActivity.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package esel.esel.esel;
-
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.support.v7.app.AlertDialog;
-import android.view.View;
-import android.support.design.widget.NavigationView;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.widget.DrawerLayout;
-import android.support.v7.app.ActionBarDrawerToggle;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import java.io.IOException;
-
-import esel.esel.esel.datareader.Datareader;
-import esel.esel.esel.datareader.SGV;
-import esel.esel.esel.preferences.Preferences;
-import esel.esel.esel.preferences.PrefsFragment;
-import esel.esel.esel.util.LocalBroadcaster;
-import esel.esel.esel.util.ToastUtils;
-
-public class ErrorsActivity extends MenuActivity {
-
- private TextView textViewValue;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setupView(R.layout.activity_errors);
- textViewValue = (TextView) findViewById(R.id.textview_main);
- }
-
-}
diff --git a/app/src/main/java/esel/esel/esel/Esel.java b/app/src/main/java/esel/esel/esel/Esel.java
index 639059e..15c9b95 100644
--- a/app/src/main/java/esel/esel/esel/Esel.java
+++ b/app/src/main/java/esel/esel/esel/Esel.java
@@ -6,6 +6,8 @@
import esel.esel.esel.receivers.KeepAliveReceiver;
import esel.esel.esel.receivers.ReadReceiver;
+import esel.esel.esel.util.SP;
+
/**
* Created by adrian on 04/08/17.
*/
@@ -23,8 +25,12 @@ public void onCreate() {
super.onCreate();
sInstance = this;
sResources = getResources();
- startReadReceiver();
- startKeepAliveService();
+
+ boolean use_patched_es = SP.getBoolean("use_patched_es", false);
+ if (use_patched_es) {
+ startKeepAliveService();
+ startReadReceiver();
+ }
}
public static Esel getsInstance() {
@@ -48,23 +54,27 @@ public synchronized void startReadReceiver() {
public synchronized void stopReadReceiver() {
- if (readReceiver != null)
+ if (readReceiver != null) {
readReceiver.cancelAlarm(this);
readReceiver = null;
+ }
}
- private void startKeepAliveService() {
+ public synchronized void startKeepAliveService() {
if (keepAliveReceiver == null) {
keepAliveReceiver = new KeepAliveReceiver();
keepAliveReceiver.setAlarm(this);
+ } else {
+ keepAliveReceiver.setAlarm(this);
}
}
- public void stopKeepAliveService() {
- if (keepAliveReceiver != null)
+ public synchronized void stopKeepAliveService() {
+ if (keepAliveReceiver != null) {
keepAliveReceiver.cancelAlarm(this);
+ keepAliveReceiver = null;
+ }
}
-
}
diff --git a/app/src/main/java/esel/esel/esel/LogActivity.java b/app/src/main/java/esel/esel/esel/LogActivity.java
new file mode 100644
index 0000000..6a8850a
--- /dev/null
+++ b/app/src/main/java/esel/esel/esel/LogActivity.java
@@ -0,0 +1,47 @@
+package esel.esel.esel;
+
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.TextView;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+import esel.esel.esel.util.SP;
+
+public class LogActivity extends MenuActivity {
+
+ private static TextView textViewValue;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setupView(R.layout.activity_errors);
+ textViewValue = (TextView) findViewById(R.id.textview_main);
+ String msg = SP.getString("logging","");
+ textViewValue.setText(msg);
+ }
+ public static void addLog(String type,String tag, String value){
+ String msg = SP.getString("logging","");
+ int lines_limit = 800;
+ String[] lines = msg.split("\n");
+ if(lines.length>lines_limit){
+ int limit_to = (int)(lines_limit * 0.7);
+ StringBuilder strbuild = new StringBuilder();
+ for (int i = 0; i valueArray = Datareader.readDataFromContentProvider(getBaseContext(), 6, currentTime - syncTime);
+ boolean use_esdms = SP.getBoolean("use_esdms",false);
+ if(use_esdms){
+ class DataHandler implements EsNowDatareader.ProcessResultI{
+ @Override
+ public void ProcessResult(List data) {
+ if (data != null && data.size() > 0) {
+ textViewValue.setText("");
+ for (int i = 0; i < data.size(); i++) {
+ SGV sgv = data.get(i);
+ textViewValue.append(sgv.toString() +" " + sgv.direction + "\n");
+ //LocalBroadcaster.broadcast(sgv);
+ EselLog.LogI(TAG,String.valueOf(sgv.value) + " " + sgv.direction);
+ }
+ } else {
+ EselLog.LogE(TAG,"No access to eversensedms",true);
+ }
+ }
+ }
- if (valueArray != null && valueArray.size() > 0) {
- textViewValue.setText("");
- for (int i = 0; i < valueArray.size(); i++) {
- SGV sgv = valueArray.get(i);
- textViewValue.append(sgv.toString() + "\n");
- //LocalBroadcaster.broadcast(sgv);
+ EsNowDatareader reader = new EsNowDatareader();
+ reader.queryCurrentValue(new DataHandler());
+
+
+
+ }else {
+ List valueArray = Datareader.readDataFromContentProvider(getBaseContext(), 6, currentTime - syncTime);
+
+ if (valueArray != null && valueArray.size() > 0) {
+ textViewValue.setText("");
+ for (int i = 0; i < valueArray.size(); i++) {
+ SGV sgv = valueArray.get(i);
+ textViewValue.append(sgv.toString() +" " + sgv.direction+ "\n");
+ //LocalBroadcaster.broadcast(sgv);
+ EselLog.LogI(TAG,String.valueOf(sgv.value) + " " + sgv.direction);
+ }
+ } else {
+ EselLog.LogE(TAG,"DB not readable!",true);
}
- } else {
- ToastUtils.makeToast("DB not readable!");
}
- }catch (android.database.CursorIndexOutOfBoundsException eb) {
- eb.printStackTrace();
- ToastUtils.makeToast("DB is empty!\nIt can take up to 15min with running Eversense App until values are available!");
+ } catch (android.database.CursorIndexOutOfBoundsException eb) {
+ eb.printStackTrace();
+ EselLog.LogW(TAG,"DB is empty!\nIt can take up to 15min with running Eversense App until values are available!",true);
} catch (Exception e) {
e.printStackTrace();
}
@@ -101,19 +147,102 @@ public void onClick(View view) {
sync = SP.getInt("max-sync-hours", sync);
+
} catch (Exception e) {
e.printStackTrace();
}
+
ReadReceiver receiver = new ReadReceiver();
- int written = receiver.FullSync(getBaseContext(), sync);
- textViewValue.setText("Read " + written + " values from DB\n(last " + sync + " hours)");
+ receiver.FullSync(getBaseContext(), sync);
+ textViewValue.setText("Read values from DB\n(last " + sync + " hours)");
}
});
+ buttonExport.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ int sync = 8;
+
+ try {
+
+ sync = SP.getInt("max-sync-hours", sync);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+
+ String filename = "esel_output_" + System.currentTimeMillis() + ".json";
+ String path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + Environment.DIRECTORY_DOWNLOADS;
+ File file = new File(path, filename);
+
+ ReadReceiver receiver = new ReadReceiver();
+
+ receiver.FullExport(getBaseContext(),file, sync);
+
+ textViewValue.setText("Created file " + file.getAbsoluteFile() + " containing values from DB\n(last " + sync + " hours)");
+
+
+ }
+ });
+
}
+ private void askForNotificationAccess() {
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
+ final String packageName = getPackageName();
+ NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getBaseContext());
+
+ boolean nlenabled = NotificationManagerCompat.getEnabledListenerPackages(getBaseContext()).contains(packageName);
+
+ if (!nlenabled) {
+ final Runnable askNotificationAccessRunnable = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Intent intent = new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS);
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ final String msg = "Device does not appear to support notification access!";
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ ToastUtils.makeToast("Device does not appear to support notification access!");
+ }
+ });
+ }
+ }
+ };
+
+ try {
+ final Intent intent = new Intent();
+ intent.setAction(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS);
+ intent.setData(Uri.parse("package:" + packageName));
+ //startActivity(intent);
+
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("Please Allow Permission")
+ .setMessage("For data access in Companion Mode, ESEL needs access to the System Notifications.\n" +
+ "If the settings are not available due to restricted settings, see 'https://support.google.com/android/answer/12623953'.")
+ .setPositiveButton("OK", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ SystemClock.sleep(100);
+ MainActivity.this.runOnUiThread(askNotificationAccessRunnable);
+ dialog.dismiss();
+ }
+ }).show();
+ } catch (Exception e) {
+ ToastUtils.makeToast("Please whitelist ESEL in the phone settings.");
+ }
+ }
+ }
+
+}
+
private void askForBatteryOptimizationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final String packageName = getPackageName();
diff --git a/app/src/main/java/esel/esel/esel/MenuActivity.java b/app/src/main/java/esel/esel/esel/MenuActivity.java
index 4214c46..e8eb922 100644
--- a/app/src/main/java/esel/esel/esel/MenuActivity.java
+++ b/app/src/main/java/esel/esel/esel/MenuActivity.java
@@ -1,8 +1,6 @@
package esel.esel.esel;
import android.content.Intent;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
import android.support.design.widget.NavigationView;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
@@ -11,16 +9,8 @@
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-import java.io.IOException;
-
-import esel.esel.esel.datareader.Datareader;
-import esel.esel.esel.datareader.SGV;
import esel.esel.esel.preferences.Preferences;
-import esel.esel.esel.util.ToastUtils;
/**
* Created by adrian on 07/08/17.
@@ -54,8 +44,8 @@ public boolean onNavigationItemSelected(MenuItem item) {
} else if (id == R.id.nav_home && !(this instanceof MainActivity)){
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
- } else if (id == R.id.nav_errors && !(this instanceof ErrorsActivity)){
- Intent intent = new Intent(this, ErrorsActivity.class);
+ } else if (id == R.id.nav_errors && !(this instanceof LogActivity)){
+ Intent intent = new Intent(this, LogActivity.class);
startActivity(intent);
}
diff --git a/app/src/main/java/esel/esel/esel/datareader/Datareader.java b/app/src/main/java/esel/esel/esel/datareader/Datareader.java
index d462df1..7e75e2b 100644
--- a/app/src/main/java/esel/esel/esel/datareader/Datareader.java
+++ b/app/src/main/java/esel/esel/esel/datareader/Datareader.java
@@ -1,8 +1,9 @@
-package esel.esel.esel.datareader;
+ package esel.esel.esel.datareader;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.util.Log;
import java.io.BufferedReader;
import java.io.DataOutputStream;
@@ -15,6 +16,8 @@
import esel.esel.esel.R;
import esel.esel.esel.util.SP;
+import static android.content.ContentValues.TAG;
+
/**
* Created by bernhard on 18-11-03.
*/
@@ -58,18 +61,18 @@ public static List readDataFromContentProvider(Context context, int number,
do {
String timestamp_str = item.getString(0);
String glucoseLevel_str = item.getString(1);
-// String groupId = item.getString(2);
-// String recordNumber = item.getString(3);
-// String glucoseRaw1 = item.getString(4);
-// String glucoseRaw2 = item.getString(5);
-// String glucoseRaw3 = item.getString(6);
-// String glucoseRaw4 = item.getString(7);
-// String glucoseRaw5 = item.getString(8);
-// String glucoseRaw6 = item.getString(9);
-// String glucoseRaw7 = item.getString(10);
-// String glucoseRaw8 = item.getString(11);
-
- String line = timestamp_str + "," +glucoseLevel_str;
+ String groupId = item.getString(2);
+ String recordNumber = item.getString(3);
+ // String glucoseRaw1 = item.getString(4);
+ // String glucoseRaw2 = item.getString(5);
+ // String glucoseRaw3 = item.getString(6);
+ // String glucoseRaw4 = item.getString(7);
+ // String glucoseRaw5 = item.getString(8);
+ // String glucoseRaw6 = item.getString(9);
+ // String glucoseRaw7 = item.getString(10);
+ // String glucoseRaw8 = item.getString(11);
+
+ String line = timestamp_str + "," +glucoseLevel_str + "," + recordNumber;
sb.append(timestamp_str + "," +glucoseLevel_str + "\n");
SGV sgv = Datareader.generateSGV(line);
@@ -82,13 +85,13 @@ public static List readDataFromContentProvider(Context context, int number,
-// Cursor transmitter = context.getContentResolver().query(Uri.parse(uriTransmitter), null, null, null, null);
+ // Cursor transmitter = context.getContentResolver().query(Uri.parse(uriTransmitter), null, null, null, null);
//
//
-// transmitter.moveToFirst();
-// String id = transmitter.getString(0);
-// String name = transmitter.getString(1);
-// String address = transmitter.getString(2);
+ // transmitter.moveToFirst();
+ // String id = transmitter.getString(0);
+ // String name = transmitter.getString(1);
+ // String address = transmitter.getString(2);
// String status = transmitter.getString(3);
// do {
// // Do work...
@@ -99,15 +102,20 @@ public static List readDataFromContentProvider(Context context, int number,
valueArray.remove(0);
}
+ Log.d(TAG, "readDataFromContentProvider called, result = " + valueArray);
+
return valueArray;
}
+
public static SGV generateSGV(String dataString){
String[] tokens = dataString.split(",");
long timestamp = Long.parseLong(tokens[0]);
int value = Integer.parseInt(tokens[1]);
- return new SGV(value, timestamp);
+ int record = Integer.parseInt(tokens[2]);
+ return new SGV(value, timestamp,record);
}
+
}
diff --git a/app/src/main/java/esel/esel/esel/datareader/EsNotificationListener.java b/app/src/main/java/esel/esel/esel/datareader/EsNotificationListener.java
new file mode 100644
index 0000000..b3c1977
--- /dev/null
+++ b/app/src/main/java/esel/esel/esel/datareader/EsNotificationListener.java
@@ -0,0 +1,105 @@
+package esel.esel.esel.datareader;
+
+import android.app.Notification;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
+import android.widget.RemoteViews;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import esel.esel.esel.util.SP;
+import esel.esel.esel.receivers.ReadReceiver;
+
+/**
+ * Created by bernhard on 24-01-18.
+ */
+public class EsNotificationListener extends NotificationListenerService {
+
+ private static List lastReadings = new ArrayList();
+ private static final ReadReceiver rr = new ReadReceiver();
+
+ @Override
+ public void onNotificationPosted(StatusBarNotification sbn) {
+
+ boolean use_patched_es = SP.getBoolean("use_patched_es", true);
+ if(use_patched_es){
+ return;
+ }
+
+ if (sbn.getPackageName().equals("com.senseonics.gen12androidapp") ||
+ sbn.getPackageName().equals("com.senseonics.androidapp") ||
+ sbn.getPackageName().equals("com.senseonics.eversense365.us") ||
+ sbn.getPackageName().contains("com.senseonics.")
+ ) {
+ Notification notification = sbn.getNotification();
+ if (notification != null && notification.tickerText != null) {
+ try {
+ SGV sgv = generateSGV(notification,lastReadings.size());
+ if(sgv != null) {
+ lastReadings.add(sgv);
+ rr.CallBroadcast(null);
+ }
+ } catch (NumberFormatException err) {
+ err.printStackTrace();
+ }
+
+
+
+ }
+ }
+
+ }
+
+ public static List getData(int number, long lastReadingTime){
+ List result = new ArrayList();
+ for (SGV reading:lastReadings) {
+ //if(reading.timestamp > lastReadingTime){
+ result.add(reading);
+ //}
+
+ }
+
+ while (result.size() > number){
+ result.remove(0);
+ }
+
+ if(result.size() == number){
+ SGV last = lastReadings.get(lastReadings.size()-1);
+ lastReadings.clear();
+ lastReadings.add(last);
+ }
+
+ return result;
+ }
+
+ public static SGV generateSGV(Notification notification ,int record){
+ long timestamp = notification.when;
+ String tickerText = (String) notification.tickerText;
+ int value;
+ if(tickerText.contains("HI")){
+ value =410;
+ } else if(tickerText.contains(".") || tickerText.contains(",")){ //is mmol/l
+ float valuef = Float.parseFloat(tickerText);
+ value = SGV.Convert(valuef);
+ }else{
+ value =Integer.parseInt(tickerText);
+ }
+
+ if(lastReadings.size()>0) {
+ long five_min = 300000l;
+ SGV oldSgv = lastReadings.get(lastReadings.size() - 1);
+ long lastreadingtime = oldSgv.timestamp; // SP.getLong("lastreadingtime_nl",timestamp);
+ int lastreadingvalue = oldSgv.raw; //SP.getInt("lastreadingvalue_nl",value);
+ if (value == lastreadingvalue && (lastreadingtime + (five_min )) > timestamp ) { // no new value // 5 min 30 secs grace time
+ return null;
+ }
+ }
+
+ // SP.putLong("lastreadingtime_nl",timestamp);
+ // SP.putInt("lastreadingvalue_nl",value);
+
+ return new SGV(value, timestamp,record);
+ }
+
+}
diff --git a/app/src/main/java/esel/esel/esel/datareader/EsNowDatareader.java b/app/src/main/java/esel/esel/esel/datareader/EsNowDatareader.java
new file mode 100644
index 0000000..3bb8e8e
--- /dev/null
+++ b/app/src/main/java/esel/esel/esel/datareader/EsNowDatareader.java
@@ -0,0 +1,338 @@
+package esel.esel.esel.datareader;
+
+import java.io.Reader;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import esel.esel.esel.util.CareService;
+import esel.esel.esel.util.EselLog;
+import esel.esel.esel.util.SP;
+import esel.esel.esel.util.ToastUtils;
+import esel.esel.esel.util.UserLoginService;
+import okhttp3.ResponseBody;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import retrofit2.Retrofit;
+import retrofit2.converter.gson.GsonConverterFactory;
+
+public final class EsNowDatareader {
+
+ private static final String TAG = "EsNowDatareader";
+ private String username;
+ private String password;
+ static final String grant_type = "password";
+ static final String client_id = "eversenseMMAAndroid";
+ static final String client_secret = "6ksPx#]~wQ3U";
+ private String BASE_AUTH_URL = "https://ousiamapialpha.eversensedms.com/connect/";
+ private String BASE_URL = "https://ousalphaapiservices.eversensedms.com/";
+ static final String BASE_AUTH_URL_US = "https://apiservice.eversensedms.com/";
+ static final String BASE_URL_US = "https://apiservice.eversensedms.com/";
+ static final String BASE_AUTH_URL_OUS = "https://ousiamapialpha.eversensedms.com/connect/";
+ static final String BASE_URL_OUS = "https://ousalphaapiservices.eversensedms.com/";
+ private static DateTimeFormatter dateformat = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss");
+ private static ZoneId zoneId = ZoneId.systemDefault();
+
+ private UserLoginService.SenseonicsTokenDto token;
+ private List user;
+ private List values;
+ private List events;
+ private LocalDateTime startDate;
+ private LocalDateTime endDate;
+ private ProcessResultI processor;
+
+
+ private int userId = 0;
+
+ private String bearer_token = "";
+ private long token_expires=0;
+
+ public EsNowDatareader() {
+
+ username = SP.getString("es_username","");
+ password =SP.getString("es_password","");
+
+ BASE_AUTH_URL = BASE_AUTH_URL_OUS;
+ BASE_URL = BASE_URL_OUS;
+
+ if(SP.getBoolean("esdms_us",false)){
+ BASE_AUTH_URL = BASE_AUTH_URL_US;
+ BASE_URL = BASE_URL_US;
+ }
+
+ bearer_token = SP.getString("esnow_token", bearer_token);
+ token_expires = SP.getLong("es_now_token_expire", token_expires);
+ userId = SP.getInt("esnow_userId", userId);
+
+ }
+
+ static public void updateLogin(){
+ EsNowDatareader reader = new EsNowDatareader();
+ if(reader.bearer_token == "" || reader.tokenHasExpired() ) {
+ reader.login();
+ }
+ }
+
+ private void login() {
+ LoginController login = new LoginController();
+ login.start();;
+ }
+
+ private boolean tokenHasExpired(){
+ long currentTime = System.currentTimeMillis();
+ //return true;
+ return currentTime > token_expires;
+ }
+
+ private void currentUser() {
+ UserController data = new UserController();
+ data.start();
+ }
+ public void queryCurrentValue(ProcessResultI processor) {
+
+ this.processor = processor;
+ SgvController data = new SgvController();
+ data.start();
+
+
+ }
+
+ public void queryLastValues(ProcessResultI processor, int hours) {
+
+ LocalDateTime.now();
+ startDate = LocalDateTime.now().minusHours(hours);
+ endDate = LocalDateTime.now();
+ this.processor = processor;
+ SgvHistController data = new SgvHistController();
+ data.start();
+
+ }
+
+
+ private SGV generateSGV(CareService.UserEventDto data, int record){
+ ZonedDateTime date = ZonedDateTime.parse(data.eventDate,dateformat.withZone(ZoneId.of("UTC")));
+ long timestamp = (long)date.toEpochSecond() * 1000;
+ int sgv = data.value;
+
+ return new SGV(sgv,timestamp,record);
+ }
+
+ private SGV generateSGV(CareService.CurrentValuesDto data){
+ ZonedDateTime date = ZonedDateTime.parse(data.timeStamp,dateformat.withZone(ZoneId.of("UTC")));
+ long timestamp = (long)date.toEpochSecond() *1000;
+ int sgv = data.currentGlucose;
+
+ return new SGV(sgv,timestamp,1);
+ }
+
+
+ public class LoginController implements Callback {
+ public void start() {
+ Gson gson = new GsonBuilder()
+ .setLenient()
+ .create();
+
+ Retrofit retrofit = new Retrofit.Builder()
+ .baseUrl(BASE_AUTH_URL)
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .build();
+
+ UserLoginService login = retrofit.create(UserLoginService.class);
+
+ Call call = login.authenticate(grant_type,client_id,client_secret,username,password);
+ call.enqueue(this);
+
+ }
+
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (response.isSuccessful()) {
+ token = response.body();
+ if(token != null) {
+ token.SetExpireDateTime();
+ bearer_token = token.GetBearerToken();
+ token_expires = token.expireDateTime;
+ SP.putString("esnow_token",bearer_token );
+ SP.putLong("es_now_token_expire", token_expires);
+ currentUser();
+ EselLog.LogI(TAG,"Eversensedms: Successfully logged in.");
+ }
+ } else {
+ try {
+ Reader reader = response.errorBody().charStream();
+ char[] charBuffer = new char[500];
+ int amountRead = reader.read(charBuffer);
+ charBuffer[amountRead] = '\0';
+ String msg = new String(charBuffer, 0, amountRead);
+ if(msg.contains("6008")){
+ EselLog.LogW(TAG,"Not authorized. Check username and password. Disabling Eversensedms...",true);
+ SP.putBoolean("use_esdms", false);
+ }else if(msg.contains("5005")) {
+ EselLog.LogW(TAG,"Not authorized. Check username and password. Account is locked. Try again in 30min. Disabling Eversensedms...",true);
+ SP.putBoolean("use_esdms", false);
+ }else{
+ EselLog.LogW(TAG,msg,true);
+ }
+
+
+ }catch(Exception err){
+ EselLog.LogE(TAG,err.getMessage(),true);
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ EselLog.LogE(TAG, t.getStackTrace().toString(), true);
+ }
+ }
+
+ public class UserController implements Callback> {
+ public void start() {
+ Gson gson = new GsonBuilder()
+ .setLenient()
+ .create();
+
+ Retrofit retrofit = new Retrofit.Builder()
+ .baseUrl(BASE_URL)
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .build();
+
+ CareService data = retrofit.create(CareService.class);
+
+ Call> call = data.getUserProfile(bearer_token);
+ call.enqueue(this);
+
+ }
+
+ @Override
+ public void onResponse(Call> call, Response> response) {
+ if (response.isSuccessful()) {
+ user = response.body();
+ if(user != null){
+ userId = user.get(0).userId;
+ SP.putInt("esnow_userId",userId );
+ EselLog.LogI(TAG,"UserId is " + userId);
+ }
+ } else {
+ try {
+ EselLog.LogE(TAG, response.errorBody().string(), true);
+ }catch(Exception err){
+ EselLog.LogE(TAG, err.getMessage(), true);
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(Call> call, Throwable t) {
+ EselLog.LogE(TAG, t.getStackTrace().toString(), true);
+ }
+ }
+
+
+ public class SgvController implements Callback> {
+
+
+ public void start() {
+ Gson gson = new GsonBuilder()
+ .setLenient()
+ .create();
+
+ Retrofit retrofit = new Retrofit.Builder()
+ .baseUrl(BASE_URL)
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .build();
+
+ CareService data = retrofit.create(CareService.class);
+
+ Call> call = data.getCurrentValues(bearer_token,userId);
+ call.enqueue(this);
+
+ }
+
+ @Override
+ public void onResponse(Call> call, Response> response) {
+ if (response.isSuccessful()) {
+ values = response.body();
+ List result = new ArrayList();
+ SGV value = generateSGV(values.get(0));
+ result.add(value);
+ if(processor != null) {
+ processor.ProcessResult(result);
+ }
+ } else {
+ try {
+ EselLog.LogE(TAG, response.errorBody().string(), true);
+ }catch(Exception err){
+ EselLog.LogE(TAG, err.getMessage(), true);
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(Call> call, Throwable t) {
+ EselLog.LogE(TAG, t.getStackTrace().toString(), true);
+ }
+ }
+
+ public class SgvHistController implements Callback> {
+
+ public void start() {
+ Gson gson = new GsonBuilder()
+ .setLenient()
+ .create();
+
+ Retrofit retrofit = new Retrofit.Builder()
+ .baseUrl(BASE_URL)
+ .addConverterFactory(GsonConverterFactory.create(gson))
+ .build();
+
+ CareService data = retrofit.create(CareService.class);
+
+ Call> call = data.getFollowingUserSensorGlucose(bearer_token,userId,startDate.format(dateformat),endDate.format(dateformat));
+ call.enqueue(this);
+
+ }
+
+ @Override
+ public void onResponse(Call> call, Response> response) {
+ if (response.isSuccessful()) {
+ events = response.body();
+ List result = new ArrayList();
+ for (int i = 0; i < events.size(); i++){
+ SGV value = generateSGV(events.get(i),i);
+ result.add(value);
+ }
+ if (processor != null){
+ processor.ProcessResult(result);
+ }
+
+ } else {
+ try {
+ EselLog.LogE(TAG, response.errorBody().string(), true);
+ }catch(Exception err){
+ EselLog.LogE(TAG, err.getMessage(), true);
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(Call> call, Throwable t) {
+ EselLog.LogE(TAG, t.getStackTrace().toString(), true);
+ }
+ }
+
+ public interface ProcessResultI{
+
+ public void ProcessResult(List data);
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/esel/esel/esel/datareader/SGV.java b/app/src/main/java/esel/esel/esel/datareader/SGV.java
index 9af25af..db07dbe 100644
--- a/app/src/main/java/esel/esel/esel/datareader/SGV.java
+++ b/app/src/main/java/esel/esel/esel/datareader/SGV.java
@@ -1,23 +1,32 @@
package esel.esel.esel.datareader;
+import android.util.Log;
+
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import esel.esel.esel.util.SP;
+import static android.content.ContentValues.TAG;
+import static java.lang.Math.min;
+
/**
* Created by adrian on 04/08/17.
*/
public class SGV {
- public int value;
- public long timestamp;
+ public int value; //unit: md/dl (always used internally)
+ public int raw;
+ public long timestamp; // UNIX time in ms
+ public int record;
public String direction;
- SGV(int value, long timestamp){
+ public SGV(int value, long timestamp, int record){
this.value = value;
+ this.raw = value;
this.timestamp = timestamp;
+ this.record = record;
if (this.value < 0) { this.value = 38;}
else if (this.value < 40) { this.value = 39;}
@@ -25,6 +34,11 @@ public class SGV {
else if (this.value > 400) { this.value = 400;}
}
+ static public int Convert(float mmoll){
+ float mgdl = mmoll * 18.0182f;
+ return Math.round(mgdl);
+ }
+
@Override
public String toString(){
DateFormat df = SimpleDateFormat.getDateTimeInstance();
@@ -33,41 +47,77 @@ public String toString(){
public void setDirection(double slope_by_minute) {
direction = "NONE";
- if (slope_by_minute <= (-3.5)) {
+ if (slope_by_minute <= (-3.5d)) {
direction = "DoubleDown";
- } else if (slope_by_minute <= (-2)) {
+ } else if (slope_by_minute <= (-2d)) {
direction = "SingleDown";
- } else if (slope_by_minute <= (-1)) {
+ } else if (slope_by_minute <= (-1d)) {
direction = "FortyFiveDown";
- } else if (slope_by_minute <= (1)) {
+ } else if (slope_by_minute <= (1d)) {
direction = "Flat";
- } else if (slope_by_minute <= (2)) {
+ } else if (slope_by_minute <= (2d)) {
direction = "FortyFiveUp";
- } else if (slope_by_minute <= (3.5)) {
+ } else if (slope_by_minute <= (3.5d)) {
direction = "SingleUp";
- } else if (slope_by_minute <= (40)) {
+ } else if (slope_by_minute <= (40d)) {
direction = "DoubleUp";
}
}
- public void smooth(int last){
- double smooth = this.value;
+ /**
+ * Created by bernhard on 2018-11-18.
+ */
- double lastSmooth = SP.getInt("readingSmooth",last*1000)/1000;
- double factor = SP.getDouble("smooth_factor",0.3);
- double correction = SP.getDouble("correction_factor",0.5);
- int lastRaw = SP.getInt("lastReadingRaw", value);
+ public void smooth(int last,boolean enable_smooth){
+ double value = (double)this.value;
+ double lastSmooth = (double)last;
+
+ if(!enable_smooth){
+ SP.putInt("lastReadingRaw", this.value);
+ SP.putFloat("readingSmooth",(float)this.value);
+ return;
+ }
+
+ try{
+ lastSmooth = SP.getFloat("readingSmooth",(float)lastSmooth);
+ }catch (Exception e){
+ //first time: no value available, fallbacksolution is default value
+ }
+ double factor = SP.getDouble("smooth_factor",0.3,0.0,1.0);
+ double correction = SP.getDouble("correction_factor",0.5,0.0,1.0);
+ double descent_factor = SP.getDouble("descent_factor",0.0,0.0,1.0);
+ float lastRaw = SP.getInt("lastReadingRaw", this.value);
SP.putInt("lastReadingRaw", this.value);
- double a=lastSmooth+(factor*(this.value-lastSmooth));
- smooth=a+correction*((lastRaw-lastSmooth)+(this.value-a))/2;
+ if(last < 39) {//no useful value, e.g. due to pause in transmitter usage
+ lastRaw = this.value;
+ lastSmooth = this.value;
+ }
+
+ // exponential smoothing, see https://en.wikipedia.org/wiki/Exponential_smoothing
+ // y'[t]=y'[t-1] + (a*(y-y'[t-1])) = a*y+(1-a)*y'[t-1]
+ // factor is a, value is y, lastSmooth y'[t-1], smooth y'
+ // factor between 0 and 1, default 0.3
+ // factor = 0: always last smooth (constant)
+ // factor = 1: no smoothing
+ double smooth=lastSmooth+(factor*(value-lastSmooth));
- SP.putInt("readingSmooth",(int)Math.round(smooth*1000));
+ // correction: average of delta between raw and smooth value, added to smooth with correction factor
+ // correction between 0 and 1, default 0.5
+ // correction = 0: no correction, full smoothing
+ // correction > 0: less smoothing
+ smooth=smooth+(correction*((lastRaw-lastSmooth)+(value-smooth))/2.0d);
+
+ smooth = smooth - descent_factor*(smooth-min(value,smooth));
+
+ SP.putFloat("readingSmooth",(float)smooth);
if(this.value > SP.getInt("lower_limit",65)){
this.value = (int)Math.round(smooth);
}
+ Log.d(TAG, "readDataFromContentProvider called, result = " + this.value);
+
}
}
diff --git a/app/src/main/java/esel/esel/esel/receivers/ReadReceiver.java b/app/src/main/java/esel/esel/esel/receivers/ReadReceiver.java
index 9f5ce6c..d501e99 100644
--- a/app/src/main/java/esel/esel/esel/receivers/ReadReceiver.java
+++ b/app/src/main/java/esel/esel/esel/receivers/ReadReceiver.java
@@ -5,22 +5,28 @@
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
-import android.database.Cursor;
-import android.net.Uri;
import android.os.PowerManager;
-import android.util.Log;
+import org.json.JSONArray;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import esel.esel.esel.Esel;
-import esel.esel.esel.R;
+import esel.esel.esel.LogActivity;
import esel.esel.esel.datareader.Datareader;
+import esel.esel.esel.datareader.EsNotificationListener;
+import esel.esel.esel.datareader.EsNowDatareader;
import esel.esel.esel.datareader.SGV;
+import esel.esel.esel.util.EselLog;
import esel.esel.esel.util.LocalBroadcaster;
import esel.esel.esel.util.SP;
import esel.esel.esel.util.ToastUtils;
+import retrofit2.Call;
/**
* Created by adrian on 04/08/17.
@@ -32,16 +38,25 @@ public class ReadReceiver extends BroadcastReceiver {
private static final String TAG = "ReadReceiver";
+ private boolean suppressBroadcast =false;
+ JSONArray output = new JSONArray();
+
@Override
public synchronized void onReceive(Context context, Intent intent) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
- PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "");
+ PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Esel:ReadReceiver:Broadcast");//Broadcast
wl.acquire();
- Log.d(TAG, "onReceive called");
+ EselLog.LogV(TAG, "onReceive called");
setAlarm(Esel.getsInstance());
+ CallBroadcast(context);
+
+ wl.release();
+ }
+
+ public void CallBroadcast(Context context){
int sync = 8;
try {
@@ -56,7 +71,7 @@ public synchronized void onReceive(Context context, Intent intent) {
try {
SP.putLong("readReceiver-called", System.currentTimeMillis());
- //TODO: KeepAlive und ReadReceiver bei App-Beenden stoppen.
+
//String datastring = Datareader.readData();
@@ -71,7 +86,9 @@ public synchronized void onReceive(Context context, Intent intent) {
} catch (Exception e) {
- ToastUtils.makeToast("Exception: " + e.getMessage());
+ String msg = e.getMessage();
+ ToastUtils.makeToast("Exception: " + msg);
+ EselLog.LogE(TAG,msg);
}
@@ -83,95 +100,189 @@ public synchronized void onReceive(Context context, Intent intent) {
FullSync(context,sync);
}
+ boolean use_esdms = SP.getBoolean("use_esdms",false);
+ if(use_esdms){
+ EsNowDatareader.updateLogin();
+ }
+
+ }
+
+ public void FullSync(Context context, int syncHours){
+ long currentTime = System.currentTimeMillis();
+ long syncTime = syncHours * 60 * 60 * 1000L;
+ long lastTimestamp = currentTime - syncTime;
+
+
+ boolean use_esdms = SP.getBoolean("use_esdms", false);
+ if(use_esdms){
+
+ class DataHandler implements EsNowDatareader.ProcessResultI{
+
+ @Override
+ public void ProcessResult(List data) {
+ try {
+ int written = ProcesssValues( false, data);
+ String msg = "Full Sync done: Read " + written + " values from DB\n(last " + syncHours + " hours)";
+ //ToastUtils.makeToast(msg);
+ EselLog.LogI(TAG,msg,true);
+ }
+ catch(Exception e){
+ //ToastUtils.makeToast("No access to eversensedms");
+ EselLog.LogE(TAG,"No access to eversensedms",true);
+ }
+ }
+ }
+
+ EsNowDatareader reader = new EsNowDatareader();
+ reader.queryLastValues(new DataHandler(),syncHours);
+
+
+
+ }else {
+
+ //disable smoothing as historical data will be overwritten
+ int written = broadcastData(context, lastTimestamp, false);
+ String msg = "Full Sync done: Read " + written + " values from DB\n(last " + syncHours + " hours)";
+ //ToastUtils.makeToast(msg);
+ EselLog.LogI(TAG,msg,true);
+ }
+
+ SP.putLong("last_full_sync", currentTime);
+
+
- wl.release();
}
- public int FullSync(Context context, int syncHours){
+ public void FullExport(Context context,File file, int syncHours){
long currentTime = System.currentTimeMillis();
long syncTime = syncHours * 60 * 60 * 1000L;
long lastTimestamp = currentTime - syncTime;
- //disable smoothing as historical data will be overwritten
- int written = broadcastData(context, lastTimestamp, false);
+ int written = 0;
+ suppressBroadcast = true;
+ boolean use_esdms = SP.getBoolean("use_esdms", false);
+
+ if (use_esdms) {
+
+ class DataHandler implements EsNowDatareader.ProcessResultI {
+
+ @Override
+ public void ProcessResult(List data) {
+ int written = ProcesssValues( false,data);
+ String msg = "Full Sync done: Read " + written + " values from DB\n(last " + syncHours + " hours)";
+ //ToastUtils.makeToast(msg);
+ EselLog.LogI(TAG, msg,true);
+ WriteData(file,output.toString());
+ output = new JSONArray();
+ suppressBroadcast = false;
+
+ }
+ }
+
+ EsNowDatareader reader = new EsNowDatareader();
+ reader.queryLastValues(new DataHandler(), syncHours);
+
+ }else {
+
+ written = broadcastData(context, lastTimestamp, false);
+ suppressBroadcast = false;
+ WriteData(file,output.toString());
+ output = new JSONArray();
+ String msg = "Full Sync done: Read " + written + " values from DB\n(last " + syncHours + " hours)";
+ //ToastUtils.makeToast(msg);
+ EselLog.LogI(TAG, msg,true);
+
+ }
+
SP.putLong("last_full_sync", currentTime);
- ToastUtils.makeToast("Full Sync done: Read " + written + " values from DB\n(last " + syncHours + " hours)");
+ }
+
+ private void WriteData(File file,String data){
+
+ if (!file.getParentFile().exists()) {
+ file.getParentFile().mkdir();
+ }
+ if (!file.getParentFile().canWrite()) {
+ String msg = "Error: can not write data. Please enable the storage access permission for Esel.";
+ //ToastUtils.makeToast(msg);
+ EselLog.LogE(TAG, msg,true);
+ }
+ if (!file.exists()) {
+ try {
+ file.createNewFile();
+ FileWriter fileWriter = new FileWriter(file.getAbsoluteFile());
+ BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
+ bufferedWriter.write(data.toString());
+ bufferedWriter.close();
+
+ } catch (IOException err) {
+ String msg = "Error creating file: " + err.toString() + " occured at: " + err.getStackTrace().toString();
+ //ToastUtils.makeToast(msg);
+ EselLog.LogE(TAG, msg,true);
+ }
+ }
- return written;
}
- public int broadcastData(Context context, long lastReadingTime, boolean smoothEnabled) {
+ public int broadcastData(Context context, long lastReadingTime, boolean is_continuous_run) {
int result = 0;
try {
-
+ long currentTime = System.currentTimeMillis();
SP.putLong("readReceiver-called", System.currentTimeMillis());
int size = 2;
long updatedReadingTime = lastReadingTime;
+ boolean use_patched_es = SP.getBoolean("use_patched_es", true);
do {
lastReadingTime = updatedReadingTime;
- List valueArray = Datareader.readDataFromContentProvider(context, size, lastReadingTime);
+ List valueArray = new ArrayList<>();
- if (valueArray == null || valueArray.size() == 0) {
- ToastUtils.makeToast("DB not readable!");
- //wl.release();
- return result;
- }
+ if (SP.getBoolean("overwrite_bg", false)) { //send constant values e.g. for debugging purpose
- if (valueArray.size() != size) {
- //ToastUtils.makeToast("DB not readable!");
- //wl.release();
- return result;
- }
-
- for (int i = 0; i < valueArray.size(); i++) {
- SGV sgv = valueArray.get(i);
-
- long oldTime = SP.getLong("lastReadingTime", -1L);
- int oldValue = SP.getInt("lastReadingValue", -1);
+ //if(currentTime - lastReadingTime > 30000) {
+ int bg = SP.getInt("bg_value", 120);
+ SGV sgv = new SGV(bg, currentTime, 1);
+ valueArray.add(new SGV(bg, lastReadingTime, 1));
+ valueArray.add(new SGV(bg, currentTime, 2));
- if (oldTime != sgv.timestamp) {
-
- double slopeByMinute = 0d;
- if (oldTime != sgv.timestamp) {
- slopeByMinute = (oldValue - sgv.value) * 60000.0d / ((oldTime - sgv.timestamp) * 1.0d);
- }
- sgv.setDirection(slopeByMinute);
+ //}
- if (sgv.value >= 39 && oldValue >= 39) {
- //ToastUtils.makeToast(sgv.toString());
- if(SP.getBoolean("smooth_data",false) && smoothEnabled){
- sgv.smooth(oldValue);
- }
+ }else if (use_patched_es){
+ valueArray = Datareader.readDataFromContentProvider(context, size, lastReadingTime);
- LocalBroadcaster.broadcast(sgv);
- result++;
- } else {
- ToastUtils.makeToast("NOT A READING!");
- }
- SP.putLong("lastReadingTime", sgv.timestamp);
- SP.putInt("lastReadingValue", sgv.value);
+ if (valueArray.size() == 0) {
+ //ToastUtils.makeToast("DB not readable!");
+ EselLog.LogE(TAG,"DB not readable!",true);
+ }
+ }else {
+ boolean read_from_nl = true;
+ if(read_from_nl){
+ valueArray = EsNotificationListener.getData(size,lastReadingTime);
}
}
+ if (valueArray.size() != size) {
+ return result;
+ }
+
+ result += ProcesssValues(is_continuous_run,valueArray);
+
updatedReadingTime = SP.getLong("lastReadingTime", lastReadingTime);
} while (updatedReadingTime != lastReadingTime);
- //} catch (IOException e) {
- // ToastUtils.makeToast("IOException");
- //} catch (InterruptedException e) {
- // ToastUtils.makeToast("InterruptedException");
} catch (android.database.CursorIndexOutOfBoundsException eb) {
eb.printStackTrace();
- ToastUtils.makeToast("DB is empty!\nIt can take up to 15min with running Eversense App until values are available!");
+ //ToastUtils.makeToast("DB is empty!\nIt can take up to 15min with running Eversense App until values are available!");
+ EselLog.LogW(TAG,"DB is empty! It can take up to 15min with running Eversense App until values are available!",true);
} catch (Exception e) {
e.printStackTrace();
+ SP.putInt("lastReadingValue", 120);
}
//wl.release();
@@ -179,7 +290,80 @@ public int broadcastData(Context context, long lastReadingTime, boolean smoothEn
return result;
}
+ private int ProcesssValues( boolean is_continuous_run, List valueArray) {
+ int result = 0;
+
+ long currentTime = System.currentTimeMillis();
+ long fiveMin = 5 * 60 * 1000L;
+ long fourMin = 4 * 60 * 1000L;
+
+ for (int i = 0; i < valueArray.size(); i++) {
+ SGV sgv = valueArray.get(i);
+ long oldTime = SP.getLong("lastReadingTime", -1L);
+ boolean acceptValue = oldTime != sgv.timestamp; //is new value
+
+ if(sgv.timestamp - currentTime > (60 * 1000)){
+ //sgv is from future
+ long shiftValue = sgv.timestamp - currentTime;
+ float sec = shiftValue/1000f;
+ EselLog.LogW(TAG,"broadcastData called, value is in future by [sec] " + sec);
+ acceptValue = false;
+ }
+
+ if(sgv.timestamp - oldTime < fourMin){
+ EselLog.LogW(TAG,"broadcastData called, value ignored as it is not older than 4 min: " + sgv.value + ", timestamp: " + sgv.timestamp);
+ acceptValue = false;
+ }
+
+ if (acceptValue) {
+ //if (!futureValue) {
+ int oldValue = sgv.value;
+
+ oldValue = SP.getInt("lastReadingValue", -1);
+
+ long sgvTime = sgv.timestamp;
+ //check if old value is not older than 12min
+ boolean hasTimeGap = (sgvTime - oldTime) > 12 * 60 *1000L;
+
+ if (sgv.value >= 39 /*&& oldValue >= 39*/) { //check for old value to ignore first 5 min
+ //ToastUtils.makeToast(sgv.toString());
+ if(is_continuous_run) {
+ boolean enable_smooth = SP.getBoolean("smooth_data", false) && !hasTimeGap;
+ sgv.smooth(oldValue, enable_smooth);
+ }
+
+ double slopeByMinute = 0d;
+ if (oldTime != sgvTime) {
+ slopeByMinute = (sgv.value - oldValue ) * 60000.0d / (( sgvTime - oldTime) * 1.0d);
+ }
+ if(!hasTimeGap){
+ sgv.setDirection(slopeByMinute);
+ }
+
+ try {
+ if (!suppressBroadcast) {
+ LocalBroadcaster.broadcast(sgv,is_continuous_run);
+ } else {
+ LocalBroadcaster.addSgvEntry(output, sgv);
+ }
+
+ result++;
+ }
+ catch(Exception e){
+ EselLog.LogE(TAG,"LocalBroadcaster.broadcast exception, result = " + e.getMessage());
+ }
+ } else {
+ ToastUtils.makeToast("NOT A READING!");
+ }
+ SP.putLong("lastReadingTime", sgvTime);
+ SP.putInt("lastReadingValue", sgv.value);
+ //SP.putFloat("lastReadingDirection", slopeByMinute);
+ }
+ }
+
+ return result;
+ }
public void setAlarm(Context context) {
diff --git a/app/src/main/java/esel/esel/esel/util/CareService.java b/app/src/main/java/esel/esel/esel/util/CareService.java
new file mode 100644
index 0000000..bc6e1a6
--- /dev/null
+++ b/app/src/main/java/esel/esel/esel/util/CareService.java
@@ -0,0 +1,142 @@
+package esel.esel.esel.util;
+
+
+import com.google.gson.annotations.SerializedName;
+import java.util.List;
+
+import esel.esel.esel.datareader.SGV;
+import retrofit2.http.Body;
+import retrofit2.http.Field;
+import retrofit2.http.FormUrlEncoded;
+import retrofit2.http.GET;
+import retrofit2.http.POST;
+import retrofit2.http.Query;
+import retrofit2.http.Header;
+import retrofit2.Call;
+
+public interface CareService {
+ //public static final Companion Companion = Companion.$$INSTANCE;
+
+ @GET("api/care/GetCurrentValues")
+ Call> getCurrentValues(@Header("Authorization") String token,@Query("FollowerUserID") int paramInt);
+
+ @GET("api/care/GetFollowingUserSensorGlucose")
+ Call> getFollowingUserSensorGlucose(@Header("Authorization") String token,@Query("UserID") int paramInt, @Query("startDate") String paramString1, @Query("endDate") String paramString2);
+
+
+ @GET("api/care/GetUserProfile")
+ Call> getUserProfile(@Header("Authorization") String token);
+
+ public static final class Companion {
+ static final Companion $$INSTANCE = new Companion();
+
+ private static final String CARE_BASE_PATH = "api/care/";
+ }
+
+
+ public final class CurrentValuesDto {
+ @SerializedName("CurrentGlucose")
+ public final int currentGlucose;
+
+ @SerializedName("GlucoseTrend")
+ public final int glucoseTrend;
+
+ @SerializedName("TimeStamp")
+ public final String timeStamp;
+
+ public CurrentValuesDto(int paramInt1, String paramString, int paramInt2) {
+ this.currentGlucose = paramInt1;
+ this.timeStamp = paramString;
+ this.glucoseTrend = paramInt2;
+ }
+ }
+
+ public final class UserEventDto {
+ @SerializedName("EventDate")
+ public final String eventDate;
+
+ @SerializedName("EventSubTypeID")
+ private final int eventSubTypeId;
+
+ @SerializedName("EventTypeID")
+ private final int eventTypeId;
+
+ @SerializedName("Value")
+ public final int value;
+
+ public UserEventDto(int paramInt1, int paramInt2, int paramInt3, String paramString) {
+ this.eventTypeId = paramInt1;
+ this.eventSubTypeId = paramInt2;
+ this.value = paramInt3;
+ this.eventDate = paramString;
+ }
+ }
+
+ public final class MemberDto {
+ @SerializedName("CurrentGlucose")
+ private final int currentGlucose;
+
+ @SerializedName("FirstName")
+ private final String firstName;
+
+ @SerializedName("GlucoseTrend")
+ private final int glucoseTrend;
+
+ @SerializedName("LastName")
+ private final String lastName;
+
+ @SerializedName("ProfileImage")
+ private final String profileImage;
+
+ @SerializedName("Status")
+ private final int status;
+
+ @SerializedName("CGTime")
+ private final String timestamp;
+
+ @SerializedName("UserName")
+ private final String userEmail;
+
+ @SerializedName("UserID")
+ private final int userId;
+
+ public MemberDto(int paramInt1, String paramString1, String paramString2, String paramString3, int paramInt2, int paramInt3, String paramString4, int paramInt4, String paramString5) {
+ this.userId = paramInt1;
+ this.userEmail = paramString1;
+ this.firstName = paramString2;
+ this.lastName = paramString3;
+ this.currentGlucose = paramInt2;
+ this.glucoseTrend = paramInt3;
+ this.profileImage = paramString4;
+ this.status = paramInt4;
+ this.timestamp = paramString5;
+ }
+ }
+
+ public final class UserProfileDto {
+ @SerializedName("FirstName")
+ private final String firstName;
+
+ @SerializedName("LastName")
+ private final String lastName;
+
+ @SerializedName("ProfileImage")
+ private final String profileImageBase64;
+
+ @SerializedName("UserID")
+ public final int userId;
+
+ @SerializedName("UserName")
+ private final String username;
+
+ public UserProfileDto(int paramInt, String paramString1, String paramString2, String paramString3, String paramString4) {
+ this.userId = paramInt;
+ this.username = paramString1;
+ this.firstName = paramString2;
+ this.lastName = paramString3;
+ this.profileImageBase64 = paramString4;
+ }
+ }
+
+
+}
diff --git a/app/src/main/java/esel/esel/esel/util/EselLog.java b/app/src/main/java/esel/esel/esel/util/EselLog.java
new file mode 100644
index 0000000..317b6b8
--- /dev/null
+++ b/app/src/main/java/esel/esel/esel/util/EselLog.java
@@ -0,0 +1,65 @@
+package esel.esel.esel.util;
+
+import android.util.Log;
+
+import esel.esel.esel.LogActivity;
+
+public class EselLog {
+
+
+ public static void LogI(String tag, String value, boolean toast) {
+ if(toast) {
+ ToastUtils.makeToast("Info: " + value);
+ }
+ LogI(tag,value);
+ }
+ public static void LogI(String tag, String value){
+ String type = "Info: ";
+ Log.v(tag,value);
+ LogActivity.addLog(type,tag,value);
+ }
+
+ public static void LogE(String tag, String value, boolean toast) {
+ if(toast) {
+ ToastUtils.makeToast("Error: " + value);
+ }
+
+ LogE(tag,value);
+ }
+
+ public static void LogE(String tag, String value){
+ String type = "Error: ";
+ Log.v(tag,value);
+ LogActivity.addLog(type,tag,value);
+ }
+
+ public static void LogW(String tag, String value, boolean toast) {
+ if(toast) {
+ ToastUtils.makeToast("Warning: " + value);
+ }
+
+ LogW(tag,value);
+ }
+
+ public static void LogW(String tag, String value){
+ String type = "Warning: ";
+ Log.v(tag,value);
+ LogActivity.addLog(type,tag,value);
+ }
+
+ public static void LogV(String tag, String value, boolean toast) {
+ if(toast) {
+ ToastUtils.makeToast("Message: " + value);
+ }
+
+ LogV(tag,value);
+ }
+
+ public static void LogV(String tag, String value){
+ String type = "Message: ";
+ Log.v(tag,value);
+ //LogActivity.addLog(type,tag,value);
+ }
+
+
+}
diff --git a/app/src/main/java/esel/esel/esel/util/LocalBroadcaster.java b/app/src/main/java/esel/esel/esel/util/LocalBroadcaster.java
index 4a305d3..a215971 100644
--- a/app/src/main/java/esel/esel/esel/util/LocalBroadcaster.java
+++ b/app/src/main/java/esel/esel/esel/util/LocalBroadcaster.java
@@ -3,7 +3,6 @@
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
-import android.util.Log;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -12,6 +11,7 @@
import java.util.List;
import java.util.Locale;
+import esel.esel.esel.LogActivity;
import esel.esel.esel.Esel;
import esel.esel.esel.datareader.SGV;
@@ -25,50 +25,46 @@ public class LocalBroadcaster {
public static final String ACTION_DATABASE = "info.nightscout.client.DBACCESS";
-
private static final String TAG = "LocalBroadcaster";
private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
-
-
- public static void broadcast(SGV sgv){
+ public static void broadcast(SGV sgv, boolean log) {
try {
+ int timeShift = SP.getInt("shift_days",0);
+ if(timeShift > 0){
+ timeShift = timeShift * 24 * 60 * 60 * 1000; //days to ms
+ sgv.timestamp = sgv.timestamp + timeShift;
+ }
- if (SP.getBoolean("send_to_AAPS", true)){
+ if (SP.getBoolean("send_to_AAPS", true)) {
final JSONArray entriesBody = new JSONArray();
addSgvEntry(entriesBody, sgv);
- sendBundle("add", "entries", entriesBody, XDRIP_PLUS_NS_EMULATOR);
+ sendBundle("add", "entries", entriesBody, XDRIP_PLUS_NS_EMULATOR, log);
}
if (SP.getBoolean("send_to_NS", true)) {
- sendBundle("dbAdd", "entries", generateSgvEntry(sgv), ACTION_DATABASE);
+ sendBundle("dbAdd", "entries", generateSgvEntry(sgv), ACTION_DATABASE, log);
}
+ if(log) {
+ EselLog.LogI(TAG, String.valueOf(sgv.value) + " " + sgv.direction);
+ }
} catch (Exception e) {
- Log.e(TAG, "Unable to send bundle: " + e);
+ String msg = "Unable to send bundle: " + e;
+ EselLog.LogE(TAG,msg);
}
}
- private static void addSgvEntry(JSONArray entriesArray, SGV sgv) throws Exception {
- JSONObject json = new JSONObject();
- json.put("sgv", sgv.value);
- if (sgv.direction == null){
- json.put("direction", "NONE");
- } else {
- json.put("direction", sgv.direction);
- }
- json.put("device", "ESEL");
- json.put("type", "sgv");
- json.put("date", sgv.timestamp);
- json.put("dateString", format.format(sgv.timestamp));
-
+ public static void addSgvEntry(JSONArray entriesArray, SGV sgv) throws Exception {
+ JSONObject json = generateSgvEntry(sgv);
entriesArray.put(json);
}
private static JSONObject generateSgvEntry(SGV sgv) throws Exception {
JSONObject json = new JSONObject();
json.put("sgv", sgv.value);
- if (sgv.direction == null){
+ json.put("rawbg", sgv.raw);
+ if (sgv.direction == null) {
json.put("direction", "NONE");
} else {
json.put("direction", sgv.direction);
@@ -77,25 +73,32 @@ private static JSONObject generateSgvEntry(SGV sgv) throws Exception {
json.put("type", "sgv");
json.put("date", sgv.timestamp);
json.put("dateString", format.format(sgv.timestamp));
-
+ json.put("created_at", format.format(sgv.timestamp));
+ json.put("source", "Eversense");
return json;
}
- private static void sendBundle(String action, String collection, Object json, String intentIdAction) {
+ private static void sendBundle(String action, String collection, Object json, String intentIdAction,boolean log) {
final Bundle bundle = new Bundle();
bundle.putString("action", action);
bundle.putString("collection", collection);
bundle.putString("data", json.toString());
final Intent intent = new Intent(intentIdAction);
intent.putExtras(bundle).addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
- Esel.getsInstance().sendBroadcast(intent);
+
List receivers = Esel.getsInstance().getPackageManager().queryBroadcastReceivers(intent, 0);
- if (receivers.size() < 1) {
- Log.w(TAG, "No xDrip receivers found. ");
- } else {
- Log.d(TAG, receivers.size() + " xDrip receivers");
+
+ /* With receiving apps targeting O+ we need to explicitly send broadcasts to the packages
+ for them to wake from the background*/
+ for (ResolveInfo resolveInfo : receivers) {
+ String packageName = resolveInfo.activityInfo.packageName;
+ if (packageName != null) {
+ intent.setPackage(packageName);
+ Esel.getsInstance().sendBroadcast(intent);
+ if(log) {
+ EselLog.LogI(TAG, "send to: " + packageName);
+ }
+ }
}
}
-
-
}
diff --git a/app/src/main/java/esel/esel/esel/util/SP.java b/app/src/main/java/esel/esel/esel/util/SP.java
index 53d490e..2042855 100644
--- a/app/src/main/java/esel/esel/esel/util/SP.java
+++ b/app/src/main/java/esel/esel/esel/util/SP.java
@@ -11,7 +11,7 @@
*/
public class SP {
- static SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(Esel.getsInstance().getApplicationContext());
+ static public SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(Esel.getsInstance().getApplicationContext());
static public boolean contains(String key) {
return sharedPreferences.contains(key);
@@ -46,7 +46,19 @@ static public Double getDouble(int resourceID, Double defaultValue) {
}
static public Double getDouble(String key, Double defaultValue) {
- return SafeParse.stringToDouble(sharedPreferences.getString(key, defaultValue.toString()));
+ Double value = SafeParse.stringToDouble(sharedPreferences.getString(key, defaultValue.toString()));
+ return value;
+ }
+
+ static public Double getDouble(String key, Double defaultValue, Double min, Double max) {
+ Double value = SafeParse.stringToDouble(sharedPreferences.getString(key, defaultValue.toString()));
+ if(valuemax){
+ value = max;
+ }
+ return value;
}
static public int getInt(int resourceID, Integer defaultValue) {
@@ -77,6 +89,14 @@ static public long getLong(String key, Long defaultValue) {
}
}
+ static public float getFloat(String key, Float defaultValue) {
+ try {
+ return sharedPreferences.getFloat(key, defaultValue);
+ } catch (Exception e) {
+ return SafeParse.stringToInt(sharedPreferences.getString(key, defaultValue.toString()));
+ }
+ }
+
static public void putBoolean(String key, boolean value) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(key, value);
@@ -119,6 +139,12 @@ static public void putInt(int resourceID, int value) {
editor.apply();
}
+ static public void putFloat(String key, float value) {
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.putFloat(key, value);
+ editor.apply();
+ }
+
static public void putString(int resourceID, String value) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(Esel.getsResources().getString(resourceID), value);
diff --git a/app/src/main/java/esel/esel/esel/util/UserLoginService.java b/app/src/main/java/esel/esel/esel/util/UserLoginService.java
new file mode 100644
index 0000000..db77e99
--- /dev/null
+++ b/app/src/main/java/esel/esel/esel/util/UserLoginService.java
@@ -0,0 +1,69 @@
+package esel.esel.esel.util;
+
+import android.os.SystemClock;
+
+import com.google.gson.annotations.SerializedName;
+import retrofit2.Call;
+import retrofit2.http.Field;
+import retrofit2.http.FormUrlEncoded;
+import retrofit2.http.POST;
+import java.time.LocalDateTime;
+public interface UserLoginService {
+ @FormUrlEncoded
+ @POST("token")
+ Call authenticate(@Field("grant_type") String paramString1, @Field("client_id") String paramString2, @Field("client_secret") String paramString3, @Field("username") String paramString4, @Field("password") String paramString5);
+
+
+ public final class SenseonicsTokenDto {
+
+ @SerializedName("access_token")
+ private final String accessToken;
+
+ @SerializedName("as:client_id")
+ private final String clientId;
+
+ @SerializedName("expires")
+ private final String expired;
+
+ @SerializedName("expires_in")
+ private final Long expiresIn;
+
+ @SerializedName(".issued")
+ private final String issued;
+
+ @SerializedName("refresh_token")
+ private String refresh_token;
+
+ @SerializedName("token_type")
+ private final String tokenType;
+
+ @SerializedName("userName")
+ private final String userName;
+
+ public SenseonicsTokenDto(String paramString1, String paramString2, Long paramLong, String paramString3, String paramString4, String paramString5, String paramString6, String paramString7) {
+ this.accessToken = paramString1;
+ this.tokenType = paramString2;
+ this.expiresIn = paramLong;
+ this.refresh_token = paramString3;
+ this.clientId = paramString4;
+ this.userName = paramString5;
+ this.issued = paramString6;
+ this.expired = paramString7;
+
+ SetExpireDateTime();
+ }
+
+ public void SetExpireDateTime(){
+ long currentTime = System.currentTimeMillis();
+
+ this.expireDateTime = currentTime + (expiresIn * 1000);
+ }
+
+ public long expireDateTime;
+
+ public String GetBearerToken(){
+ return "Bearer "+ accessToken;
+ }
+
+ }
+}
diff --git a/app/src/main/res/drawable/esel_pic.png b/app/src/main/res/drawable/esel_pic.png
new file mode 100644
index 0000000..c1e7bb8
Binary files /dev/null and b/app/src/main/res/drawable/esel_pic.png differ
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..ca3826a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/side_nav_bar.xml b/app/src/main/res/drawable/side_nav_bar.xml
index 458b4b0..e9af4f9 100644
--- a/app/src/main/res/drawable/side_nav_bar.xml
+++ b/app/src/main/res/drawable/side_nav_bar.xml
@@ -2,8 +2,8 @@
android:shape="rectangle">
\ No newline at end of file
diff --git a/app/src/main/res/layout/app_bar_errors.xml b/app/src/main/res/layout/app_bar_errors.xml
index c8ba2b2..8b3b032 100644
--- a/app/src/main/res/layout/app_bar_errors.xml
+++ b/app/src/main/res/layout/app_bar_errors.xml
@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context="esel.esel.esel.ErrorsActivity">
+ tools:context="esel.esel.esel.LogActivity">
+ layout="@layout/content_errors"
+ />
16dp
16dp
- 16dp
+ 5dp
160dp
16dp
diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000..6d1dc2b
--- /dev/null
+++ b/app/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #00B1B8
+
\ 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 1da6957..0c59a81 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,7 +1,9 @@
Esel
+ Version 3.0.6
Open navigation drawer
Close navigation drawer
Settings
24
+ EsNotificationListener
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 31d787a..75d506f 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -1,5 +1,36 @@
+
+
+
+
+
+
+
+
+
+
-
+ android:key="smooth_factor"
+ android:summary="Exponential smooth Factor.\n(1 = no smoothing, between 0 and 1, default: 0.3)"
+ android:title="Smooth Factor" />
+
+
-
\ No newline at end of file
+
+
+
+
+
+
+
+
diff --git a/build.gradle b/build.gradle
index ae9fbaf..31f360b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,9 +4,10 @@ buildscript {
repositories {
jcenter()
google()
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
+ classpath 'com.android.tools.build:gradle:8.13.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@@ -17,6 +18,7 @@ allprojects {
repositories {
jcenter()
google()
+ mavenCentral()
}
}
diff --git a/gradle.properties b/gradle.properties
index aac7c9b..8450cac 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -9,6 +9,9 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
+android.defaults.buildfeatures.buildconfig=true
+android.nonFinalResIds=false
+android.nonTransitiveRClass=false
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index eb4ef0a..25e9bd9 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sat Nov 03 23:10:45 CET 2018
+#Sun Oct 27 11:46:34 CET 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
diff --git a/mod/Readme.md b/mod/Readme.md
new file mode 100644
index 0000000..27ac9cf
--- /dev/null
+++ b/mod/Readme.md
@@ -0,0 +1,139 @@
+# How to patch ES
+## Prerequisits
+You need to have the following tools available. On your computer:
+* Android debugger [Adb](https://developer.android.com/studio/command-line/adb)
+* A Tool to decompile Apk apps to smali code, e.g. [Apktool](https://ibotpeaches.github.io/Apktool/install)
+
+On your Android smartphone:
+* Enable Developer options on your Android phone, e.g. by following this [User Guide](https://developer.android.com/studio/debug/dev-options)
+* Enable USB-Debugging in the Developer options on your Android phone.
+
+
+## Get the sources
+1. Install the official EversenseApp from the Playstore
+2. find the app with
+
+ adb shell pm list packages
+
+ should be com.senseonics.gen12androidapp
+3. get the full path name:
+
+ adb shell pm path com.senseonics.gen12androidapp
+
+ should give you
+ > package:/data/app/com.senseonics.gen12androidapp-nU4XaDnFpSSira9EH02H9Q==/base.apk
+ > package:/data/app/com.senseonics.gen12androidapp-nU4XaDnFpSSira9EH02H9Q==/split_config.de.apk
+ > package:/data/app/com.senseonics.gen12androidapp-nU4XaDnFpSSira9EH02H9Q==/split_config.xxhdpi.apk
+
+ Of course the language file (the second one) can be different according to your localization.
+4. pull to computer:
+
+ adb pull /data/app/com.senseonics.gen12androidapp-nU4XaDnFpSSira9EH02H9Q==/base.apk .\org\
+ adb pull /data/app/com.senseonics.gen12androidapp-nU4XaDnFpSSira9EH02H9Q==/split_config.de.apk .\org\
+ adb pull /data/app/com.senseonics.gen12androidapp-nU4XaDnFpSSira9EH02H9Q==/split_config.xxhdpi.apk .\org\
+
+## Create the patched files
+1. Decompile the APK to .smali code (e.g. with Apktool)
+
+ apktool.bat d .\org\base.apk
+2. In the decompiled app, navigate to
+ > base\smali_classes2\com\senseonics\db
+3. Copy/duplicate
+ > ConnectedTransmitterContentProvider.smali
+
+ and name the new file to
+ > GlucoseContentProvider.smali
+
+ (see the file GlucoseContentProvider.smali in this repo for references)
+4. Edit
+ > GlucoseContentProvider.smali
+
+ and rename every instance of
+
+ ConnectedTransmitterContentProvider
+
+ to
+
+ GlucoseContentProvider
+
+ and also rename
+
+ connectedTransmitters
+
+ to
+
+ glucosereadings
+
+ (in the SQL statements) - except of line 25: for security reasons, rename the string in
+
+ performDelete
+
+ to something like
+
+ deletenotsupported
+
+5. Modify
+ > com.senseonics.gen12androidapp\AndroidManifest.xml
+
+ Replace line 74
+
+
+
+ and delete the declaration
+
+ android:localeConfig="@xml/locales_config"
+
+ (see the file AndroidManifest.xml in this repo for references). Modify in
+
+ > res\values\strings.xml:630 and 631: © 2016 Senseonics, Inc.
+
+ and add
+ > patched
+
+ delete file
+
+ > \res\xml\locales_config.xml
+
+ open file
+ > \res\values\public.xml
+
+ and delete line
+
+
+
+ (appears 2 times). Instead, insert line
+
+
+
+6. Compile the code according the documentation of your tool you have used to decompile it
+
+ apktool.bat b .\base\
+
+## Install the patched files
+1. Sign the compiled APK (See the Android Documentation for help). First aligne it:
+
+ zipalign.exe -v -p -f 4 .\base\dist\base.apk .\base\dist\base-aligned.apk
+
+ next, sign it. Here an example with an keyfile called my-release-key_123456.jks and pwd 123456:
+
+ apksigner.bat sign --ks my-release-key_123456.jks --out .\base-patched.apk .\base\dist\base-aligned.apk
+ > 123456
+2. Do the same (without any modification) with the other apk files, language file:
+
+ apksigner.bat sign --ks my-release-key_123456.jks --out .\split_config.de.apk .\org\split_config.de.apk
+
+ and common file:
+
+ apksigner.bat sign --ks my-release-key_123456.jks --out .\split_config.xxhdpi.apk .\org\split_config.xxhdpi.apk
+3. Uninstall the original Eversense App on your phone (Warning: the local history of your CGM readings in your Eversense App will get lost) and install your new APK. The new App will behave just like the original one - except of the difference that the CGM reading can be accessed from other Apps e.g. by ESEL
+
+ adb install-multiple base.apk split_config.de.apk split_config.xxhdpi.apk
+
+
+
+There is also a script available following these steps and running on Bitbucket in Docker:
+https://bitbucket.org/norbert_bitbucket1/hackingeversense/src/master/
diff --git a/mod/my-release-key_anon.jks b/mod/my-release-key_123456.jks
similarity index 100%
rename from mod/my-release-key_anon.jks
rename to mod/my-release-key_123456.jks
diff --git a/mod/v1.2.107/apk/base.apk b/mod/v1.2.107/apk/base.apk
new file mode 100644
index 0000000..8268a3d
Binary files /dev/null and b/mod/v1.2.107/apk/base.apk differ
diff --git a/mod/v1.2.107/apk/split_config.de.apk b/mod/v1.2.107/apk/split_config.de.apk
new file mode 100644
index 0000000..f464f7c
Binary files /dev/null and b/mod/v1.2.107/apk/split_config.de.apk differ
diff --git a/mod/v1.2.107/apk/split_config.en.apk b/mod/v1.2.107/apk/split_config.en.apk
new file mode 100644
index 0000000..c86600c
Binary files /dev/null and b/mod/v1.2.107/apk/split_config.en.apk differ
diff --git a/mod/v1.2.107/apk/split_config.xxhdpi.apk b/mod/v1.2.107/apk/split_config.xxhdpi.apk
new file mode 100644
index 0000000..528eb37
Binary files /dev/null and b/mod/v1.2.107/apk/split_config.xxhdpi.apk differ
diff --git a/mod/v1.2.107/changes/AndroidManifest.xml b/mod/v1.2.107/changes/AndroidManifest.xml
new file mode 100644
index 0000000..9a65a76
--- /dev/null
+++ b/mod/v1.2.107/changes/AndroidManifest.xml
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mod/v1.2.107/changes/res/values/public.xml b/mod/v1.2.107/changes/res/values/public.xml
new file mode 100644
index 0000000..bbe87b7
--- /dev/null
+++ b/mod/v1.2.107/changes/res/values/public.xml
@@ -0,0 +1,4786 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mod/v1.2.107/changes/smali_classes2/com/senseonics/db/GlucoseContentProvider.smali b/mod/v1.2.107/changes/smali_classes2/com/senseonics/db/GlucoseContentProvider.smali
new file mode 100644
index 0000000..2ac2567
--- /dev/null
+++ b/mod/v1.2.107/changes/smali_classes2/com/senseonics/db/GlucoseContentProvider.smali
@@ -0,0 +1,194 @@
+.class public Lcom/senseonics/db/GlucoseContentProvider;
+.super Landroid/content/ContentProvider;
+.source "GlucoseContentProvider.java"
+
+
+# instance fields
+.field helper:Lcom/senseonics/db/SenseonicsDBHelper;
+
+
+# direct methods
+.method public constructor ()V
+ .locals 0
+
+ .line 9
+ invoke-direct {p0}, Landroid/content/ContentProvider;->()V
+
+ return-void
+.end method
+
+.method private performDelete(Landroid/database/sqlite/SQLiteDatabase;)I
+ .locals 2
+
+ const/4 v0, 0x0
+
+ const-string v1, "deletenotsupported"
+
+ .line 50
+ invoke-virtual {p1, v1, v0, v0}, Landroid/database/sqlite/SQLiteDatabase;->delete(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)I
+
+ move-result p1
+
+ return p1
+.end method
+
+
+# virtual methods
+.method public delete(Landroid/net/Uri;Ljava/lang/String;[Ljava/lang/String;)I
+ .locals 0
+
+ .line 45
+ iget-object p1, p0, Lcom/senseonics/db/GlucoseContentProvider;->helper:Lcom/senseonics/db/SenseonicsDBHelper;
+
+ invoke-virtual {p1}, Lcom/senseonics/db/SenseonicsDBHelper;->getWritableDatabase()Landroid/database/sqlite/SQLiteDatabase;
+
+ move-result-object p1
+
+ .line 46
+ invoke-direct {p0, p1}, Lcom/senseonics/db/GlucoseContentProvider;->performDelete(Landroid/database/sqlite/SQLiteDatabase;)I
+
+ move-result p1
+
+ return p1
+.end method
+
+.method public getType(Landroid/net/Uri;)Ljava/lang/String;
+ .locals 0
+
+ const/4 p1, 0x0
+
+ return-object p1
+.end method
+
+.method public insert(Landroid/net/Uri;Landroid/content/ContentValues;)Landroid/net/Uri;
+ .locals 4
+
+ .line 31
+ iget-object v0, p0, Lcom/senseonics/db/GlucoseContentProvider;->helper:Lcom/senseonics/db/SenseonicsDBHelper;
+
+ invoke-virtual {v0}, Lcom/senseonics/db/SenseonicsDBHelper;->getWritableDatabase()Landroid/database/sqlite/SQLiteDatabase;
+
+ move-result-object v0
+
+ const/4 v1, 0x0
+
+ const-string v2, "select count(*) from glucosereadings"
+
+ .line 33
+ invoke-virtual {v0, v2, v1}, Landroid/database/sqlite/SQLiteDatabase;->rawQuery(Ljava/lang/String;[Ljava/lang/String;)Landroid/database/Cursor;
+
+ move-result-object v2
+
+ .line 34
+ invoke-interface {v2}, Landroid/database/Cursor;->moveToFirst()Z
+
+ const/4 v3, 0x0
+
+ .line 35
+ invoke-interface {v2, v3}, Landroid/database/Cursor;->getInt(I)I
+
+ move-result v2
+
+ if-lez v2, :cond_0
+
+ .line 36
+ invoke-direct {p0, v0}, Lcom/senseonics/db/GlucoseContentProvider;->performDelete(Landroid/database/sqlite/SQLiteDatabase;)I
+
+ :cond_0
+ const-string v2, "glucosereadings"
+
+ .line 39
+ invoke-virtual {v0, v2, v1, p2}, Landroid/database/sqlite/SQLiteDatabase;->insert(Ljava/lang/String;Ljava/lang/String;Landroid/content/ContentValues;)J
+
+ move-result-wide v0
+
+ .line 40
+ new-instance p2, Ljava/lang/StringBuilder;
+
+ invoke-direct {p2}, Ljava/lang/StringBuilder;->()V
+
+ const-string v2, ""
+
+ invoke-virtual {p2, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
+
+ invoke-virtual {p2, v0, v1}, Ljava/lang/StringBuilder;->append(J)Ljava/lang/StringBuilder;
+
+ invoke-virtual {p2}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
+
+ move-result-object p2
+
+ invoke-static {p1, p2}, Landroid/net/Uri;->withAppendedPath(Landroid/net/Uri;Ljava/lang/String;)Landroid/net/Uri;
+
+ move-result-object p1
+
+ return-object p1
+.end method
+
+.method public onCreate()Z
+ .locals 2
+
+ .line 15
+ new-instance v0, Lcom/senseonics/db/SenseonicsDBHelper;
+
+ invoke-virtual {p0}, Lcom/senseonics/db/GlucoseContentProvider;->getContext()Landroid/content/Context;
+
+ move-result-object v1
+
+ invoke-direct {v0, v1}, Lcom/senseonics/db/SenseonicsDBHelper;->(Landroid/content/Context;)V
+
+ iput-object v0, p0, Lcom/senseonics/db/GlucoseContentProvider;->helper:Lcom/senseonics/db/SenseonicsDBHelper;
+
+ const/4 v0, 0x1
+
+ return v0
+.end method
+
+.method public query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;
+ .locals 8
+
+ .line 21
+ iget-object p1, p0, Lcom/senseonics/db/GlucoseContentProvider;->helper:Lcom/senseonics/db/SenseonicsDBHelper;
+
+ invoke-virtual {p1}, Lcom/senseonics/db/SenseonicsDBHelper;->getReadableDatabase()Landroid/database/sqlite/SQLiteDatabase;
+
+ move-result-object v0
+
+ const-string v1, "glucosereadings"
+
+ const/4 v5, 0x0
+
+ const/4 v6, 0x0
+
+ move-object v2, p2
+
+ move-object v3, p3
+
+ move-object v4, p4
+
+ move-object v7, p5
+
+ invoke-virtual/range {v0 .. v7}, Landroid/database/sqlite/SQLiteDatabase;->query(Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;
+
+ move-result-object p1
+
+ return-object p1
+.end method
+
+.method public update(Landroid/net/Uri;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I
+ .locals 1
+
+ .line 55
+ iget-object p1, p0, Lcom/senseonics/db/GlucoseContentProvider;->helper:Lcom/senseonics/db/SenseonicsDBHelper;
+
+ invoke-virtual {p1}, Lcom/senseonics/db/SenseonicsDBHelper;->getWritableDatabase()Landroid/database/sqlite/SQLiteDatabase;
+
+ move-result-object p1
+
+ const-string v0, "glucosereadings"
+
+ invoke-virtual {p1, v0, p2, p3, p4}, Landroid/database/sqlite/SQLiteDatabase;->update(Ljava/lang/String;Landroid/content/ContentValues;Ljava/lang/String;[Ljava/lang/String;)I
+
+ move-result p1
+
+ return p1
+.end method