diff --git a/.idea/compiler.xml b/.idea/compiler.xml index fb7f4a8..b589d56 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml deleted file mode 100644 index 12557ce..0000000 --- a/.idea/deploymentTargetDropDown.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 93512f7..5b230c0 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -5,16 +5,15 @@ diff --git a/.idea/misc.xml b/.idea/misc.xml index a936f67..205cd15 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - - + diff --git a/README.md b/README.md index 412540c..85fbe7d 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,34 @@ # 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) +* Patched mode, which requires a patched version of the Eversense App (works completely offline, including backfilling) +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 +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) + * 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. + +## 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 (mod_com.senseonics.gen12androidapp-release.apk) and use it as described by the vendor +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. Build https://github.com/BernhardRo/Esel and install it 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. - * 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 +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! \ No newline at end of file diff --git a/apk/esel_241.apk b/apk/esel_241.apk new file mode 100644 index 0000000..60322fd Binary files /dev/null and b/apk/esel_241.apk differ diff --git a/apk/esel_301.apk b/apk/esel_301.apk new file mode 100644 index 0000000..2c9fcad Binary files /dev/null and b/apk/esel_301.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..2c9fcad 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..aa6326a --- /dev/null +++ b/app/debug/output-metadata.json @@ -0,0 +1,20 @@ +{ + "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" +} \ 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 d2b9833..e538d8b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,13 +1,14 @@ - + - + + + - - - @@ -41,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/LogActivity.java b/app/src/main/java/esel/esel/esel/LogActivity.java new file mode 100644 index 0000000..ad9dd34 --- /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 = 500; + 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); + } + } + } + + 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() + "\n"); - //LocalBroadcaster.broadcast(sgv); + 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(); } @@ -107,13 +123,15 @@ 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)"); } }); @@ -122,6 +140,7 @@ public void onClick(View view) { @Override public void onClick(View view) { int sync = 8; + try { sync = SP.getInt("max-sync-hours", sync); @@ -130,34 +149,75 @@ public void onClick(View view) { e.printStackTrace(); } - ReadReceiver receiver = new ReadReceiver(); - String output = receiver.FullExport(getBaseContext(), sync); - String filename = "esel_output_" + System.currentTimeMillis() + ".json"; - String path = Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator + Environment.DIRECTORY_DOWNLOADS; - File file = new File(path,filename); - if(!file.getParentFile().exists()){ - file.getParentFile().mkdir(); - } - if(!file.getParentFile().canWrite()){ - ToastUtils.makeToast("Error: can not write data. Please enable the storage access permission for Esel."); + 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)"); + + } - if(!file.exists()){ - try{ - file.createNewFile(); - FileWriter fileWriter = new FileWriter(file.getAbsoluteFile()); - BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); - bufferedWriter.write(output.toString()); - bufferedWriter.close(); - textViewValue.setText("Created file " + file.getAbsoluteFile() + " containing values from DB\n(last " + sync + " hours)"); - }catch(IOException err){ - ToastUtils.makeToast("Error creating file: " + err.toString() + " occured at: "+ err.getStackTrace().toString()); + }); + + } + + 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) { 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 92508b1..7e75e2b 100644 --- a/app/src/main/java/esel/esel/esel/datareader/Datareader.java +++ b/app/src/main/java/esel/esel/esel/datareader/Datareader.java @@ -107,6 +107,7 @@ public static List readDataFromContentProvider(Context context, int number, return valueArray; } + public static SGV generateSGV(String dataString){ String[] tokens = dataString.split(","); long timestamp = Long.parseLong(tokens[0]); @@ -115,10 +116,6 @@ int record = Integer.parseInt(tokens[2]); return new SGV(value, timestamp,record); } - public static SGV generateSGV(int value, long timestamp, int record){ - 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..18af204 --- /dev/null +++ b/app/src/main/java/esel/esel/esel/datareader/EsNotificationListener.java @@ -0,0 +1,94 @@ +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; + +/** + * Created by bernhard on 24-01-18. + */ +public class EsNotificationListener extends NotificationListenerService { + + private static List lastReadings = new ArrayList(); + + @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")) { + Notification notification = sbn.getNotification(); + if (notification != null && notification.tickerText != null) { + try { + SGV sgv = generateSGV(notification,lastReadings.size()); + if(sgv != null) { + lastReadings.add(sgv); + } + } 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(".") || 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 * 1.05)) > timestamp ) { // no new value + 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..c965203 --- /dev/null +++ b/app/src/main/java/esel/esel/esel/datareader/EsNowDatareader.java @@ -0,0 +1,329 @@ +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"; + static final String BASE_AUTH_URL = "https://ousiamapialpha.eversensedms.com/connect/"; + static final String BASE_URL = "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",""); + + 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(); + } + if(reader.userId == 0 ){ + reader.currentUser(); + } + } + + private void login() { + LoginController login = new LoginController(); + login.start();; + } + + private boolean tokenHasExpired(){ + long currentTime = System.currentTimeMillis(); + 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 fc5388e..db07dbe 100644 --- a/app/src/main/java/esel/esel/esel/datareader/SGV.java +++ b/app/src/main/java/esel/esel/esel/datareader/SGV.java @@ -16,9 +16,9 @@ */ public class SGV { - public int value; + public int value; //unit: md/dl (always used internally) public int raw; - public long timestamp; + public long timestamp; // UNIX time in ms public int record; public String direction; @@ -34,6 +34,11 @@ public SGV(int value, long timestamp, int record){ 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(); @@ -42,28 +47,32 @@ 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,boolean onlyDummyRun){ - double value = this.value; + /** + * Created by bernhard on 2018-11-18. + */ + + public void smooth(int last,boolean enable_smooth){ + double value = (double)this.value; double lastSmooth = (double)last; - if(onlyDummyRun){ + if(!enable_smooth){ SP.putInt("lastReadingRaw", this.value); SP.putFloat("readingSmooth",(float)this.value); return; @@ -77,7 +86,7 @@ public void smooth(int last,boolean onlyDummyRun){ 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); - int lastRaw = SP.getInt("lastReadingRaw", this.value); + float lastRaw = SP.getInt("lastReadingRaw", this.value); SP.putInt("lastReadingRaw", 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 45f2d8c..bf824bd 100644 --- a/app/src/main/java/esel/esel/esel/receivers/ReadReceiver.java +++ b/app/src/main/java/esel/esel/esel/receivers/ReadReceiver.java @@ -5,13 +5,9 @@ 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 org.json.JSONObject; import java.io.BufferedWriter; import java.io.File; @@ -21,15 +17,16 @@ 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 static android.content.ContentValues.TAG; - /** * Created by adrian on 04/08/17. */ @@ -46,10 +43,10 @@ public class ReadReceiver extends BroadcastReceiver { @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, "Esel:ReadReceiver:Boradcast"); + PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Esel:ReadReceiver:Broadcast");//Boradcast wl.acquire(); - Log.d(TAG, "onReceive called"); + EselLog.LogV(TAG,"onReceive called"); setAlarm(Esel.getsInstance()); @@ -67,7 +64,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(); @@ -82,7 +79,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); } @@ -98,38 +97,123 @@ public synchronized void onReceive(Context context, Intent intent) { wl.release(); } - public int FullSync(Context context, int syncHours){ + public void FullSync(Context context, 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); + + 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); - ToastUtils.makeToast("Full Sync done: Read " + written + " values from DB\n(last " + syncHours + " hours)"); - return written; + } - public String FullExport(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; + int written = 0; suppressBroadcast = true; - int written = broadcastData(context, lastTimestamp, false); - suppressBroadcast = false; + 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)"); + } - String result = output.toString(); - output = new JSONArray(); + 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 result; } public int broadcastData(Context context, long lastReadingTime, boolean smoothEnabled) { @@ -142,6 +226,9 @@ public int broadcastData(Context context, long lastReadingTime, boolean smoothEn int size = 2; long updatedReadingTime = lastReadingTime; + boolean use_patched_es = SP.getBoolean("use_patched_es", true); + boolean use_esdms = SP.getBoolean("use_esdms",false); + do { lastReadingTime = updatedReadingTime; @@ -158,89 +245,39 @@ public int broadcastData(Context context, long lastReadingTime, boolean smoothEn //} - }else{ + }else if (use_patched_es){ valueArray = Datareader.readDataFromContentProvider(context, size, lastReadingTime); - } - - if (valueArray.size() == 0) { - ToastUtils.makeToast("DB not readable!"); - //wl.release(); - return result; + if (valueArray.size() == 0) { + //ToastUtils.makeToast("DB not readable!"); + EselLog.LogE(TAG,"DB not readable!",true); + } + }else { + boolean read_from_nl = true; + if(use_esdms){ + EsNowDatareader.updateLogin(); + } + if(read_from_nl){ + valueArray = EsNotificationListener.getData(size,lastReadingTime); + } } - 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); - - boolean newValue = oldTime != sgv.timestamp; - boolean futureValue = false; - - if(sgv.timestamp - currentTime > (60 * 1000)){ - //sgv is from future - long shiftValue = sgv.timestamp - currentTime; - float sec = shiftValue/1000f; - Log.d(TAG, "broadcastData called, value is in future by [sec] " + sec); - futureValue = true; - } - - if (newValue && !futureValue) { - //if (!futureValue) { - int oldValue = SP.getInt("lastReadingValue", -1); - long sgvTime = sgv.timestamp; - //check if old value is not older than 17min - boolean hasTimeGap = (sgvTime - oldTime) > 12 * 60 *1000L; - - float slopeByMinute = 0f; - if (oldTime != sgvTime) { - slopeByMinute = (oldValue - sgv.value) * 60000.0f / ((oldTime - sgvTime) * 1.0f); - } - if(!hasTimeGap){ - sgv.setDirection(slopeByMinute); - } - - if (sgv.value >= 39 /*&& oldValue >= 39*/) { //check for old value to ignore first 5 min - //ToastUtils.makeToast(sgv.toString()); - if(SP.getBoolean("smooth_data",false) && smoothEnabled){ - sgv.smooth(oldValue,hasTimeGap); - } - - if(!suppressBroadcast) { - LocalBroadcaster.broadcast(sgv); - }else{ - LocalBroadcaster.addSgvEntry(output,sgv); - } - result++; - Log.d(TAG, "LocalBroadcaster.broadcast called, result = " + sgv.toString()); - } else { - ToastUtils.makeToast("NOT A READING!"); - } - SP.putLong("lastReadingTime", sgvTime); - SP.putInt("lastReadingValue", sgv.value); - //SP.putFloat("lastReadingDirection", slopeByMinute); - } - } + result += ProcesssValues(smoothEnabled,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(); @@ -248,7 +285,80 @@ public int broadcastData(Context context, long lastReadingTime, boolean smoothEn return result; } + private int ProcesssValues( boolean smoothEnabled, List valueArray) { + int result = 0; + + long currentTime = System.currentTimeMillis(); + + for (int i = 0; i < valueArray.size(); i++) { + SGV sgv = valueArray.get(i); + long oldTime = SP.getLong("lastReadingTime", -1L); + + boolean newValue = oldTime != sgv.timestamp; + boolean futureValue = false; + + 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); + futureValue = true; + } + if (newValue && !futureValue) { + //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(smoothEnabled) { + boolean enable_smooth = SP.getBoolean("smooth_data", false) && !hasTimeGap; + sgv.smooth(oldValue, enable_smooth); + } + +// if(SP.getBoolean("smooth_data",false) && smoothEnabled){ +// sgv.smooth(oldValue,hasTimeGap); +// }else { +// sgv.smooth(oldValue,true); // +// } + + 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); + } 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 d75360f..a649fef 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,11 +11,10 @@ import java.util.List; import java.util.Locale; +import esel.esel.esel.LogActivity; import esel.esel.esel.Esel; import esel.esel.esel.datareader.SGV; -import static android.content.ContentValues.TAG; - /** * Created by adrian on 04/08/17. */ @@ -49,8 +47,11 @@ public static void broadcast(SGV sgv) { sendBundle("dbAdd", "entries", generateSgvEntry(sgv), ACTION_DATABASE); } + 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); } } @@ -93,7 +94,7 @@ private static void sendBundle(String action, String collection, Object json, St if (packageName != null) { intent.setPackage(packageName); Esel.getsInstance().sendBroadcast(intent); - Log.d(TAG, "sent to: " + packageName); + EselLog.LogI(TAG,"send to: " + packageName); } } } 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/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" + />