diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/cgm/carelinkfollow/client/CountryUtils.java b/app/src/main/java/com/eveningoutpost/dexdrip/cgm/carelinkfollow/client/CountryUtils.java index 87ad34f73e..d7672e175d 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/cgm/carelinkfollow/client/CountryUtils.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/cgm/carelinkfollow/client/CountryUtils.java @@ -5,120 +5,130 @@ public class CountryUtils { public static final String[] supportedCountryCodes = { + "al", "dz", - "ba", - "eg", - "za", - "ca", - "cr", - "mx", - "ma", - "pa", - "pr", - "us", + "ad", "ar", - "br", - "cl", - "co", - "ve", - "hk", - "in", - "id", - "il", - "jp", - "kw", - "lb", - "my", - "ph", - "qa", - "sa", - "sg", - "kr", - "tw", - "th", - "tn", - "tr", - "ae", - "vn", - "at", - "be", - "bg", - "hr", - "cz", - "dk", - "ee", - "fi", - "fr", - "de", - "gr", - "hu", - "is", - "ie", - "it", - "lv", - "lt", - "lu", - "nl", - "no", - "pl", - "pt", - "ro", - "ru", - "rs", - "sk", - "si", - "es", - "se", - "ch", - "ua", - "gb", - "au", - "nz", - "bh", - "om", - "cn", - "cy", - "al", "am", + "aw", + "au", + "at", "az", "bs", + "bh", + "bd", "bb", "by", + "be", "bm", "bo", + "ba", + "bw", + "br", + "bg", "kh", + "ca", + "ky", + "cl", + "cn", + "co", + "cr", + "hr", + "cw", + "cy", + "cz", + "dk", "do", "ec", + "eg", "sv", + "ee", + "fi", + "fr", + "pf", "ge", + "de", + "gr", "gt", "hn", + "hk", + "hu", + "is", + "in", + "id", "ir", "iq", + "ie", + "il", + "it", + "jm", + "jp", "jo", + "kz", + "ke", "xk", + "kw", + "lv", + "lb", "ly", + "li", + "lt", + "lu", "mo", "mk", + "my", "mv", "mt", "mu", "yt", + "mx", "md", "me", + "ma", "na", + "nl", "nc", + "nz", "ni", "ng", + "no", + "om", "pk", + "pa", "py", + "pe", + "ph", + "pl", + "pt", + "pr", + "qa", + "ro", + "ru", + "sa", + "rs", + "sg", + "sk", + "si", + "za", + "kr", + "es", "mf", "sd", + "se", + "ch", + "tw", + "th", + "tt", + "tn", + "tr", + "ua", + "ae", + "gb", + "us", "uy", - "aw", - "ky", - "cw", - "pe" + "uz", + "ve", + "vn" }; public static boolean isSupportedCountry(String countryCode) { diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/models/Treatments.java b/app/src/main/java/com/eveningoutpost/dexdrip/models/Treatments.java index 06ba55f7bf..a328958dae 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/models/Treatments.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/models/Treatments.java @@ -21,6 +21,7 @@ import com.eveningoutpost.dexdrip.models.UserError.Log; import com.eveningoutpost.dexdrip.R; import com.eveningoutpost.dexdrip.services.SyncService; +import com.eveningoutpost.dexdrip.services.UiBasedCollector; import com.eveningoutpost.dexdrip.utilitymodels.Constants; import com.eveningoutpost.dexdrip.utilitymodels.Pref; import com.eveningoutpost.dexdrip.utilitymodels.UndoRedo; @@ -57,6 +58,7 @@ import static com.eveningoutpost.dexdrip.models.JoH.msSince; import static com.eveningoutpost.dexdrip.utilitymodels.Constants.HOUR_IN_MS; import static com.eveningoutpost.dexdrip.utilitymodels.Constants.MINUTE_IN_MS; +import com.eveningoutpost.dexdrip.utilitymodels.Pref; import static java.lang.StrictMath.abs; import static com.eveningoutpost.dexdrip.models.JoH.emptyString; @@ -1292,6 +1294,20 @@ public static List ioBForGraph_old(int number, double startTime) { }*/ public static Double getCurrentIoB() { + if (Pref.getBooleanDefaultFalse("fetch_iob_from_companion_app")) { + return getCurrentIoBFromCompanionApp(); + } else { + return getCurrentIoBFromGraphCalculation(); + } + } + + public static Double getCurrentIoBFromCompanionApp() { + Double iob = UiBasedCollector.getCurrentIoB(); + + return iob; + } + + public static Double getCurrentIoBFromGraphCalculation() { long now = System.currentTimeMillis(); final List iobInfo = Treatments.ioBForGraph_new(now - 1 * Constants.DAY_IN_MS); diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/services/UiBasedCollector.java b/app/src/main/java/com/eveningoutpost/dexdrip/services/UiBasedCollector.java index 171d6f5908..0e560b4e32 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/services/UiBasedCollector.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/services/UiBasedCollector.java @@ -2,6 +2,7 @@ import static com.eveningoutpost.dexdrip.models.JoH.msSince; import static com.eveningoutpost.dexdrip.cgm.dex.ClassifierAction.lastReadingTimestamp; +import static com.eveningoutpost.dexdrip.utilitymodels.Constants.MINUTE_IN_MS; import static com.eveningoutpost.dexdrip.utils.DexCollectionType.UiBased; import static com.eveningoutpost.dexdrip.utils.DexCollectionType.getDexCollectionType; import static com.eveningoutpost.dexdrip.xdrip.gs; @@ -26,20 +27,26 @@ import androidx.annotation.VisibleForTesting; import com.eveningoutpost.dexdrip.BestGlucose; +import com.eveningoutpost.dexdrip.alert.Persist; import com.eveningoutpost.dexdrip.models.BgReading; import com.eveningoutpost.dexdrip.models.JoH; import com.eveningoutpost.dexdrip.models.Sensor; import com.eveningoutpost.dexdrip.models.UserError; import com.eveningoutpost.dexdrip.R; +import com.eveningoutpost.dexdrip.utilitymodels.Constants; import com.eveningoutpost.dexdrip.utilitymodels.PersistentStore; import com.eveningoutpost.dexdrip.utilitymodels.Unitized; import com.eveningoutpost.dexdrip.cgm.dex.BlueTails; import com.eveningoutpost.dexdrip.utils.DexCollectionType; import com.eveningoutpost.dexdrip.xdrip; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.HashSet; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import lombok.val; @@ -53,10 +60,16 @@ public class UiBasedCollector extends NotificationListenerService { private static final String TAG = UiBasedCollector.class.getSimpleName(); private static final String UI_BASED_STORE_LAST_VALUE = "UI_BASED_STORE_LAST_VALUE"; private static final String UI_BASED_STORE_LAST_REPEAT = "UI_BASED_STORE_LAST_REPEAT"; + private static final String COMPANION_APP_IOB_ENABLED_PREFERENCE_KEY = "fetch_iob_from_companion_app"; + private static final Persist.DoubleTimeout iob_store = + new Persist.DoubleTimeout("COMPANION_APP_IOB_VALUE", Constants.MINUTE_IN_MS * 5); private static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners"; private static final String ACTION_NOTIFICATION_LISTENER_SETTINGS = "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"; private static final HashSet coOptedPackages = new HashSet<>(); + private static final HashSet companionAppIoBPackages = new HashSet<>(); + private static final HashSet companionAppIoBRegexes = new HashSet<>(); + private static boolean debug = false; @VisibleForTesting String lastPackage; @@ -74,6 +87,12 @@ public class UiBasedCollector extends NotificationListenerService { coOptedPackages.add("com.medtronic.diabetes.guardian"); coOptedPackages.add("com.medtronic.diabetes.minimedmobile.eu"); coOptedPackages.add("com.medtronic.diabetes.minimedmobile.us"); + + companionAppIoBPackages.add("com.insulet.myblue.pdm"); + + // The IoB value should be captured into the first match group. + // English localization of the Omnipod 5 App + companionAppIoBRegexes.add(Pattern.compile("IOB: ([\\d\\.,]+) U")); } @Override @@ -93,6 +112,68 @@ public void onNotificationPosted(final StatusBarNotification sbn) { } } } + + if (companionAppIoBPackages.contains(fromPackage)) { + processCompanionAppIoBNotification(sbn.getNotification()); + } + } + + private void processCompanionAppIoBNotification(final Notification notification) { + if (notification == null) { + UserError.Log.e(TAG, "Null notification"); + return; + } + if (notification.contentView != null) { + processCompanionAppIoBNotificationCV(notification.contentView); + } else { + UserError.Log.e(TAG, "Content is empty"); + } + } + + private void processCompanionAppIoBNotificationCV(final RemoteViews cview) { + if (cview == null) return; + val applied = cview.apply(this, null); + val root = (ViewGroup) applied.getRootView(); + val texts = new ArrayList(); + getTextViews(texts, root); + if (debug) UserError.Log.d(TAG, "Text views: " + texts.size()); + Double iob = null; + try { + for (val view : texts) { + val tv = (TextView) view; + String text = tv.getText() != null ? tv.getText().toString() : ""; + val desc = tv.getContentDescription() != null ? tv.getContentDescription().toString() : ""; + if (debug) UserError.Log.d(TAG, "Examining: >" + text + "< : >" + desc + "<"); + iob = parseIoB(text); + if (iob != null) { + break; + } + } + + if (iob != null) { + if (debug) UserError.Log.d(TAG, "Inserting new IoB value: " + iob); + iob_store.set(iob); + } + } catch (Exception e) { + UserError.Log.e(TAG, "exception in processCompanionAppIoBNotificationCV: " + e); + } + + texts.clear(); + } + Double parseIoB(final String value) { + for (Pattern pattern : companionAppIoBRegexes) { + Matcher matcher = pattern.matcher(value); + + if (matcher.find()) { + return JoH.tolerantParseDouble(matcher.group(1)); + } + } + + return null; + } + + public static Double getCurrentIoB() { + return iob_store.get(); } @Override @@ -257,12 +338,23 @@ public static SharedPreferences.OnSharedPreferenceChangeListener getListener(fin // } } + if (key.equals(COMPANION_APP_IOB_ENABLED_PREFERENCE_KEY)) { + try { + enableNotificationService(activity); + } catch (Exception e) { + UserError.Log.e(TAG, "Exception when enabling NotificationService: " + e); + } + } }; } public static void switchToAndEnable(final Activity activity) { DexCollectionType.setDexCollectionType(UiBased); Sensor.createDefaultIfMissing(); + enableNotificationService(activity); + } + + private static void enableNotificationService(final Activity activity) { if (!isNotificationServiceEnabled()) { JoH.show_ok_dialog(activity, gs(R.string.please_allow_permission), "Permission is needed to receive data from other applications. xDrip does not do anything beyond this scope. Please enable xDrip on the next screen", diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/webservices/WebServicePebble.java b/app/src/main/java/com/eveningoutpost/dexdrip/webservices/WebServicePebble.java index 560a7e7186..e643277551 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/webservices/WebServicePebble.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/webservices/WebServicePebble.java @@ -1,5 +1,7 @@ package com.eveningoutpost.dexdrip.webservices; +import android.content.Context; +import android.app.Activity; import android.util.Log; import com.eveningoutpost.dexdrip.BestGlucose; @@ -10,6 +12,9 @@ import com.eveningoutpost.dexdrip.models.Treatments; import com.eveningoutpost.dexdrip.dagger.Injectors; import com.eveningoutpost.dexdrip.ui.MicroStatus; +import com.eveningoutpost.dexdrip.utilitymodels.Pref; +import com.eveningoutpost.dexdrip.xdrip; + import org.json.JSONArray; import org.json.JSONException; @@ -83,8 +88,12 @@ public WebResponse request(String query) { } bgs.put("battery", microStatus.gs("bestBridgeBattery")); - Double iob = Treatments.getCurrentIoB(); - bgs.put("iob", (iob == null) ? "unknown" : String.format("%.02f", iob)); + if (!Pref.getBooleanDefaultFalse("enable_iob_in_api_endpoint")) { + bgs.put("iob", 0.0); + } else { + Double iob = Treatments.getCurrentIoB(); + bgs.put("iob", (iob == null) ? "unknown" : String.format("%.02f", iob)); + } // TODO output bwp and bwpo status_array.put(status); diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index b96d367f69..eebf70386d 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -249,6 +249,7 @@ Albania Algeria + Andorra Argentina Armenia Aruba @@ -257,12 +258,14 @@ Azerbaijan Bahamas Bahrain + Bangladesh Barbados Belarus Belgium Bermuda Bolivia Bosnia and Herzegovina + Botswana Brazil Bulgaria Cambodia @@ -284,6 +287,7 @@ Estonia Finland France + French Polynesia Georgia Germany Greece @@ -299,13 +303,17 @@ Ireland Israel Italy + Jamaica Japan Jordan + Kazakhstan + Kenya Kosovo Kuwait Latvia Lebanon Libya + Liechtenstein Lithuania Luxembourg Macau @@ -352,6 +360,7 @@ Switzerland Taiwan Thailand + Trinidad and Tobago Tunisia Turkey Ukraine @@ -359,6 +368,7 @@ United Kingdom United States Uruguay + Uzbekistan Venezuela Vietnam @@ -366,6 +376,7 @@ al dz + ad ar am aw @@ -374,12 +385,14 @@ az bs bh + bd bb by be bm bo ba + bw br bg kh @@ -401,6 +414,7 @@ ee fi fr + pf ge de gr @@ -416,13 +430,17 @@ ie il it + jm jp jo + kz + ke xk kw lv lb ly + pf lt lu mo @@ -469,6 +487,7 @@ ch tw th + tt tn tr ua @@ -476,6 +495,7 @@ gb us uy + uz ve vn diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ff12cb3734..b2d1c88094 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1241,6 +1241,10 @@ Broadcast Service API Enables xDrip communication with third-party applications by using new API + Enable IoB reporting in API + Enable IoB value reporting in Web Service API endpoint used by some smartwatches + Fetch IoB from companion app + Fetch IoB value from companion app running on the same device, such as the Omnipod 5 App MiBand Sync Data with MiBand fitness bands diff --git a/app/src/main/res/xml/pref_advanced_settings.xml b/app/src/main/res/xml/pref_advanced_settings.xml index 93e076d224..4f2480ce36 100644 --- a/app/src/main/res/xml/pref_advanced_settings.xml +++ b/app/src/main/res/xml/pref_advanced_settings.xml @@ -1005,6 +1005,16 @@ android:key="broadcast_service_enabled" android:summary="@string/summary_broadcast_service_api" android:title="@string/title_broadcast_service_api" /> + +