diff --git a/icons/battery-burnin/battery-charging-wireless-10-burnin.svg b/icons/battery-burnin/battery-charging-wireless-10-burnin.svg
new file mode 100644
index 0000000000..2888abf209
--- /dev/null
+++ b/icons/battery-burnin/battery-charging-wireless-10-burnin.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/icons/battery-burnin/battery-charging-wireless-20-burnin.svg b/icons/battery-burnin/battery-charging-wireless-20-burnin.svg
new file mode 100644
index 0000000000..77d52751d7
--- /dev/null
+++ b/icons/battery-burnin/battery-charging-wireless-20-burnin.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/icons/battery-burnin/battery-charging-wireless-30-burnin.svg b/icons/battery-burnin/battery-charging-wireless-30-burnin.svg
new file mode 100644
index 0000000000..9ffa356436
--- /dev/null
+++ b/icons/battery-burnin/battery-charging-wireless-30-burnin.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/icons/battery-burnin/battery-charging-wireless-40-burnin.svg b/icons/battery-burnin/battery-charging-wireless-40-burnin.svg
new file mode 100644
index 0000000000..d9ccc46027
--- /dev/null
+++ b/icons/battery-burnin/battery-charging-wireless-40-burnin.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/icons/battery-burnin/battery-charging-wireless-50-burnin.svg b/icons/battery-burnin/battery-charging-wireless-50-burnin.svg
new file mode 100644
index 0000000000..4d4905046c
--- /dev/null
+++ b/icons/battery-burnin/battery-charging-wireless-50-burnin.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/icons/battery-burnin/battery-charging-wireless-60-burnin.svg b/icons/battery-burnin/battery-charging-wireless-60-burnin.svg
new file mode 100644
index 0000000000..e3c4ba5c44
--- /dev/null
+++ b/icons/battery-burnin/battery-charging-wireless-60-burnin.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/icons/battery-burnin/battery-charging-wireless-70-burnin.svg b/icons/battery-burnin/battery-charging-wireless-70-burnin.svg
new file mode 100644
index 0000000000..fe26b5e93d
--- /dev/null
+++ b/icons/battery-burnin/battery-charging-wireless-70-burnin.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/icons/battery-burnin/battery-charging-wireless-80-burnin.svg b/icons/battery-burnin/battery-charging-wireless-80-burnin.svg
new file mode 100644
index 0000000000..c949afb1c8
--- /dev/null
+++ b/icons/battery-burnin/battery-charging-wireless-80-burnin.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/icons/battery-burnin/battery-charging-wireless-90-burnin.svg b/icons/battery-burnin/battery-charging-wireless-90-burnin.svg
new file mode 100644
index 0000000000..13677dc328
--- /dev/null
+++ b/icons/battery-burnin/battery-charging-wireless-90-burnin.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/icons/battery-burnin/battery-charging-wireless-burnin.svg b/icons/battery-burnin/battery-charging-wireless-burnin.svg
new file mode 100644
index 0000000000..f074b89d34
--- /dev/null
+++ b/icons/battery-burnin/battery-charging-wireless-burnin.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/icons/battery-burnin/battery-unknown-burnin.svg b/icons/battery-burnin/battery-unknown-burnin.svg
new file mode 100644
index 0000000000..b0cc3bba40
--- /dev/null
+++ b/icons/battery-burnin/battery-unknown-burnin.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/icons/battery-source/mask-burnin-battery-raw.svg b/icons/battery-source/mask-burnin-battery-raw.svg
new file mode 100644
index 0000000000..e2ab79f2a1
--- /dev/null
+++ b/icons/battery-source/mask-burnin-battery-raw.svg
@@ -0,0 +1,55 @@
+
+
diff --git a/icons/battery-source/mask-burnin-battery.svg b/icons/battery-source/mask-burnin-battery.svg
new file mode 100644
index 0000000000..09be5da8a9
--- /dev/null
+++ b/icons/battery-source/mask-burnin-battery.svg
@@ -0,0 +1,223 @@
+
+
diff --git a/icons/battery/battery-charging-wireless-10.svg b/icons/battery/battery-charging-wireless-10.svg
new file mode 100644
index 0000000000..d6dbd7febc
--- /dev/null
+++ b/icons/battery/battery-charging-wireless-10.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/battery/battery-charging-wireless-20.svg b/icons/battery/battery-charging-wireless-20.svg
new file mode 100644
index 0000000000..9e4badedc9
--- /dev/null
+++ b/icons/battery/battery-charging-wireless-20.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/battery/battery-charging-wireless-30.svg b/icons/battery/battery-charging-wireless-30.svg
new file mode 100644
index 0000000000..7da87ce966
--- /dev/null
+++ b/icons/battery/battery-charging-wireless-30.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/battery/battery-charging-wireless-40.svg b/icons/battery/battery-charging-wireless-40.svg
new file mode 100644
index 0000000000..b9aaad2b0f
--- /dev/null
+++ b/icons/battery/battery-charging-wireless-40.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/battery/battery-charging-wireless-50.svg b/icons/battery/battery-charging-wireless-50.svg
new file mode 100644
index 0000000000..705a61c55b
--- /dev/null
+++ b/icons/battery/battery-charging-wireless-50.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/battery/battery-charging-wireless-60.svg b/icons/battery/battery-charging-wireless-60.svg
new file mode 100644
index 0000000000..b2cd9f7734
--- /dev/null
+++ b/icons/battery/battery-charging-wireless-60.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/battery/battery-charging-wireless-70.svg b/icons/battery/battery-charging-wireless-70.svg
new file mode 100644
index 0000000000..608a404882
--- /dev/null
+++ b/icons/battery/battery-charging-wireless-70.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/battery/battery-charging-wireless-80.svg b/icons/battery/battery-charging-wireless-80.svg
new file mode 100644
index 0000000000..c604743cc3
--- /dev/null
+++ b/icons/battery/battery-charging-wireless-80.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/battery/battery-charging-wireless-90.svg b/icons/battery/battery-charging-wireless-90.svg
new file mode 100644
index 0000000000..246886ad08
--- /dev/null
+++ b/icons/battery/battery-charging-wireless-90.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/battery/battery-charging-wireless.svg b/icons/battery/battery-charging-wireless.svg
new file mode 100644
index 0000000000..b36143c4c2
--- /dev/null
+++ b/icons/battery/battery-charging-wireless.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/battery/battery-outline.svg b/icons/battery/battery-outline.svg
new file mode 100644
index 0000000000..e05e71b288
--- /dev/null
+++ b/icons/battery/battery-outline.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/battery/battery-unknown.svg b/icons/battery/battery-unknown.svg
new file mode 100644
index 0000000000..8e117be5cb
--- /dev/null
+++ b/icons/battery/battery-unknown.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/icons/complications-source/ic_br_cob_iob_orig.svg b/icons/complications-source/ic_br_cob_iob_orig.svg
new file mode 100644
index 0000000000..f650e12d99
--- /dev/null
+++ b/icons/complications-source/ic_br_cob_iob_orig.svg
@@ -0,0 +1,93 @@
+
+
+
+
diff --git a/icons/complications-source/ic_cob_detailed_orig.svg b/icons/complications-source/ic_cob_detailed_orig.svg
new file mode 100644
index 0000000000..e599774c5d
--- /dev/null
+++ b/icons/complications-source/ic_cob_detailed_orig.svg
@@ -0,0 +1,83 @@
+
+
+
+
diff --git a/icons/complications-source/ic_cob_iob_orig.svg b/icons/complications-source/ic_cob_iob_orig.svg
new file mode 100644
index 0000000000..98c1764554
--- /dev/null
+++ b/icons/complications-source/ic_cob_iob_orig.svg
@@ -0,0 +1,83 @@
+
+
+
+
diff --git a/icons/complications-source/ic_ins_burnin_orig.svg b/icons/complications-source/ic_ins_burnin_orig.svg
new file mode 100644
index 0000000000..c5bcdfe0ff
--- /dev/null
+++ b/icons/complications-source/ic_ins_burnin_orig.svg
@@ -0,0 +1,57 @@
+
+
diff --git a/icons/complications-source/ic_ins_orig.svg b/icons/complications-source/ic_ins_orig.svg
new file mode 100644
index 0000000000..7601867f58
--- /dev/null
+++ b/icons/complications-source/ic_ins_orig.svg
@@ -0,0 +1,56 @@
+
+
diff --git a/icons/complications-source/ic_iob_detailed_orig.svg b/icons/complications-source/ic_iob_detailed_orig.svg
new file mode 100644
index 0000000000..3479a78565
--- /dev/null
+++ b/icons/complications-source/ic_iob_detailed_orig.svg
@@ -0,0 +1,88 @@
+
+
+
+
diff --git a/icons/complications/ic_aaps_full.svg b/icons/complications/ic_aaps_full.svg
new file mode 100644
index 0000000000..4e005a8228
--- /dev/null
+++ b/icons/complications/ic_aaps_full.svg
@@ -0,0 +1,36 @@
+
+
diff --git a/icons/complications/ic_basal.svg b/icons/complications/ic_basal.svg
new file mode 100644
index 0000000000..0491265177
--- /dev/null
+++ b/icons/complications/ic_basal.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/icons/complications/ic_br_cob_iob.svg b/icons/complications/ic_br_cob_iob.svg
new file mode 100644
index 0000000000..b340c42187
--- /dev/null
+++ b/icons/complications/ic_br_cob_iob.svg
@@ -0,0 +1,40 @@
+
+
diff --git a/icons/complications/ic_carbs.svg b/icons/complications/ic_carbs.svg
new file mode 100644
index 0000000000..0785741d47
--- /dev/null
+++ b/icons/complications/ic_carbs.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/icons/complications/ic_cob_detailed.svg b/icons/complications/ic_cob_detailed.svg
new file mode 100644
index 0000000000..5132260c3c
--- /dev/null
+++ b/icons/complications/ic_cob_detailed.svg
@@ -0,0 +1,36 @@
+
+
diff --git a/icons/complications/ic_cob_iob.svg b/icons/complications/ic_cob_iob.svg
new file mode 100644
index 0000000000..81a2e9250f
--- /dev/null
+++ b/icons/complications/ic_cob_iob.svg
@@ -0,0 +1,36 @@
+
+
diff --git a/icons/complications/ic_ins.svg b/icons/complications/ic_ins.svg
new file mode 100644
index 0000000000..e5d1b3e147
--- /dev/null
+++ b/icons/complications/ic_ins.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/icons/complications/ic_ins_burnin.svg b/icons/complications/ic_ins_burnin.svg
new file mode 100644
index 0000000000..623db41e5b
--- /dev/null
+++ b/icons/complications/ic_ins_burnin.svg
@@ -0,0 +1,31 @@
+
+
diff --git a/icons/complications/ic_iob_detailed.svg b/icons/complications/ic_iob_detailed.svg
new file mode 100644
index 0000000000..8bd9aabc0e
--- /dev/null
+++ b/icons/complications/ic_iob_detailed.svg
@@ -0,0 +1,36 @@
+
+
diff --git a/icons/complications/ic_sgv.svg b/icons/complications/ic_sgv.svg
new file mode 100644
index 0000000000..1dc46d403b
--- /dev/null
+++ b/icons/complications/ic_sgv.svg
@@ -0,0 +1,35 @@
+
+
diff --git a/wear/build.gradle b/wear/build.gradle
index 7e6500fe56..8d4dd71af3 100644
--- a/wear/build.gradle
+++ b/wear/build.gradle
@@ -92,6 +92,10 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
//implementation files("libs/hellocharts-library-1.5.5.jar")
//compile "com.ustwo.android:clockwise-wearable:1.0.2"
+
+ implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation 'androidx.legacy:legacy-support-v13:1.0.0'
+
compileOnly "com.google.android.wearable:wearable:${wearableVersion}"
implementation "com.google.android.support:wearable:${wearableVersion}"
implementation "com.google.android.gms:play-services-wearable:${playServicesWearable}"
diff --git a/wear/src/main/AndroidManifest.xml b/wear/src/main/AndroidManifest.xml
index 874a9c8763..2f89781293 100644
--- a/wear/src/main/AndroidManifest.xml
+++ b/wear/src/main/AndroidManifest.xml
@@ -10,6 +10,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wear/src/main/assets/watch_dark.jpg b/wear/src/main/assets/watch_dark.jpg
new file mode 100644
index 0000000000..54cd4dc1dc
Binary files /dev/null and b/wear/src/main/assets/watch_dark.jpg differ
diff --git a/wear/src/main/assets/watch_gray.jpg b/wear/src/main/assets/watch_gray.jpg
new file mode 100644
index 0000000000..2cb3778b6b
Binary files /dev/null and b/wear/src/main/assets/watch_gray.jpg differ
diff --git a/wear/src/main/assets/watch_light.jpg b/wear/src/main/assets/watch_light.jpg
new file mode 100644
index 0000000000..a8183304d6
Binary files /dev/null and b/wear/src/main/assets/watch_light.jpg differ
diff --git a/wear/src/main/java/info/nightscout/androidaps/aaps.java b/wear/src/main/java/info/nightscout/androidaps/aaps.java
new file mode 100644
index 0000000000..f05f032f2e
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/aaps.java
@@ -0,0 +1,75 @@
+package info.nightscout.androidaps;
+
+import android.annotation.SuppressLint;
+import android.app.Application;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.preference.PreferenceManager;
+
+import androidx.annotation.StringRes;
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import info.nightscout.androidaps.interaction.utils.Persistence;
+
+/**
+ * Created for xDrip+ by Emma Black on 3/21/15.
+ * Adapted for AAPS by dlvoy 2019-11-06.
+ */
+
+public class aaps extends Application implements SharedPreferences.OnSharedPreferenceChangeListener {
+
+ @SuppressLint("StaticFieldLeak")
+ private static Context context;
+ private static Boolean unicodeComplications = true;
+ private static String complicationTapAction = "default";
+
+ @Override
+ public void onCreate() {
+ aaps.context = getApplicationContext();
+ SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ sharedPrefs.registerOnSharedPreferenceChangeListener(this);
+ updatePrefs(sharedPrefs);
+ super.onCreate();
+ }
+
+ private void updatePrefs(SharedPreferences sharedPrefs) {
+ unicodeComplications = sharedPrefs.getBoolean("complication_unicode", true);
+ complicationTapAction = sharedPrefs.getString("complication_tap_action", "default");
+ }
+
+ public static Context getAppContext() {
+ return aaps.context;
+ }
+
+ private static boolean isWear2OrAbove() {
+ return Build.VERSION.SDK_INT > 23;
+ }
+
+ public static String gs(@StringRes final int id) {
+ return getAppContext().getString(id);
+ }
+
+ public static String gs(@StringRes final int id, String... args) {
+ return getAppContext().getString(id, (Object[]) args);
+ }
+
+ public static Boolean areComplicationsUnicode() {
+ return unicodeComplications;
+ }
+
+ public static String getComplicationTapAction() {
+ return complicationTapAction;
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ updatePrefs(sharedPrefs);
+
+ // we trigger update on Complications
+ Intent messageIntent = new Intent();
+ messageIntent.setAction(Intent.ACTION_SEND);
+ LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/BaseComplicationProviderService.java b/wear/src/main/java/info/nightscout/androidaps/complications/BaseComplicationProviderService.java
new file mode 100644
index 0000000000..c1f33e41c5
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/BaseComplicationProviderService.java
@@ -0,0 +1,415 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.drawable.Icon;
+import android.support.wearable.complications.ComplicationData;
+import android.support.wearable.complications.ComplicationManager;
+import android.support.wearable.complications.ComplicationProviderService;
+import android.support.wearable.complications.ComplicationText;
+import android.support.wearable.complications.ProviderUpdateRequester;
+import android.util.Log;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.aaps;
+import info.nightscout.androidaps.data.DisplayRawData;
+import info.nightscout.androidaps.data.ListenerService;
+import info.nightscout.androidaps.interaction.utils.Constants;
+import info.nightscout.androidaps.interaction.utils.DisplayFormat;
+import info.nightscout.androidaps.interaction.utils.Inevitable;
+import info.nightscout.androidaps.interaction.utils.Persistence;
+import info.nightscout.androidaps.interaction.utils.WearUtil;
+
+/**
+ * Base class for all complications
+ *
+ * Created by dlvoy on 2019-11-12
+ */
+public abstract class BaseComplicationProviderService extends ComplicationProviderService {
+
+ private static final String TAG = BaseComplicationProviderService.class.getSimpleName();
+
+ private static final String KEY_COMPLICATIONS = "complications";
+ private static final String KEY_LAST_SINCE = "lastSince";
+ private static final String KEY_STALE_REPORTED = "staleReported";
+ private static final String TASK_ID_REFRESH_COMPLICATION = "refresh-complication";
+
+
+ private LocalBroadcastManager localBroadcastManager;
+ private MessageReceiver messageReceiver;
+
+ public static void turnOff() {
+ Log.d(TAG, "TURNING OFF all active complications");
+ final Persistence persistence = new Persistence();
+ persistence.putString(KEY_COMPLICATIONS, "");
+ }
+
+ //==============================================================================================
+ // ABSTRACT COMPLICATION INTERFACE
+ //==============================================================================================
+
+ public abstract ComplicationData buildComplicationData(int dataType, DisplayRawData raw, PendingIntent complicationPendingIntent);
+ public abstract String getProviderCanonicalName();
+
+ public ComplicationAction getComplicationAction() { return ComplicationAction.MENU; };
+
+ //----------------------------------------------------------------------------------------------
+ // DEFAULT BEHAVIOURS
+ //----------------------------------------------------------------------------------------------
+
+ public ComplicationData buildNoSyncComplicationData(int dataType,
+ DisplayRawData raw,
+ PendingIntent complicationPendingIntent,
+ PendingIntent exceptionalPendingIntent,
+ long since) {
+ ComplicationData complicationData = null;
+
+ final ComplicationData.Builder builder = new ComplicationData.Builder(dataType);
+ if (dataType != ComplicationData.TYPE_LARGE_IMAGE) {
+ builder.setIcon(Icon.createWithResource(this, R.drawable.ic_sync_alert));
+ }
+
+ if (dataType == ComplicationData.TYPE_RANGED_VALUE) {
+ builder.setMinValue(0);
+ builder.setMaxValue(100);
+ builder.setValue(0);
+ }
+
+ switch (dataType) {
+ case ComplicationData.TYPE_ICON:
+ case ComplicationData.TYPE_SHORT_TEXT:
+ case ComplicationData.TYPE_RANGED_VALUE:
+ if (since > 0) {
+ builder.setShortText(ComplicationText.plainText(DisplayFormat.shortTimeSince(since) + " old"));
+ } else {
+ builder.setShortText(ComplicationText.plainText("!err!"));
+ }
+ break;
+ case ComplicationData.TYPE_LONG_TEXT:
+ builder.setLongTitle(ComplicationText.plainText(aaps.gs(R.string.label_warning_sync)));
+ if (since > 0) {
+ builder.setLongText(ComplicationText.plainText(String.format(aaps.gs(R.string.label_warning_since), DisplayFormat.shortTimeSince(since))));
+ } else {
+ builder.setLongText(ComplicationText.plainText(aaps.gs(R.string.label_warning_sync_aaps)));
+ }
+ break;
+ case ComplicationData.TYPE_LARGE_IMAGE:
+ return buildComplicationData(dataType, raw, complicationPendingIntent);
+ default:
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ break;
+ }
+
+ builder.setTapAction(exceptionalPendingIntent);
+ complicationData = builder.build();
+ return complicationData;
+ }
+
+ public ComplicationData buildOutdatedComplicationData(int dataType,
+ DisplayRawData raw,
+ PendingIntent complicationPendingIntent,
+ PendingIntent exceptionalPendingIntent,
+ long since) {
+ ComplicationData complicationData = null;
+
+ final ComplicationData.Builder builder = new ComplicationData.Builder(dataType);
+ if (dataType != ComplicationData.TYPE_LARGE_IMAGE) {
+ builder.setIcon(Icon.createWithResource(this, R.drawable.ic_alert));
+ builder.setBurnInProtectionIcon(Icon.createWithResource(this, R.drawable.ic_alert_burnin));
+ }
+
+ if (dataType == ComplicationData.TYPE_RANGED_VALUE) {
+ builder.setMinValue(0);
+ builder.setMaxValue(100);
+ builder.setValue(0);
+ }
+
+ switch (dataType) {
+ case ComplicationData.TYPE_ICON:
+ case ComplicationData.TYPE_SHORT_TEXT:
+ case ComplicationData.TYPE_RANGED_VALUE:
+ if (since > 0) {
+ builder.setShortText(ComplicationText.plainText(DisplayFormat.shortTimeSince(since) + " old"));
+ } else {
+ builder.setShortText(ComplicationText.plainText("!old!"));
+ }
+ break;
+ case ComplicationData.TYPE_LONG_TEXT:
+ builder.setLongTitle(ComplicationText.plainText(aaps.gs(R.string.label_warning_old)));
+ if (since > 0) {
+ builder.setLongText(ComplicationText.plainText(String.format(aaps.gs(R.string.label_warning_since), DisplayFormat.shortTimeSince(since))));
+ } else {
+ builder.setLongText(ComplicationText.plainText(aaps.gs(R.string.label_warning_sync_aaps)));
+ }
+ break;
+ case ComplicationData.TYPE_LARGE_IMAGE:
+ return buildComplicationData(dataType, raw, complicationPendingIntent);
+ default:
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ break;
+ }
+
+ builder.setTapAction(exceptionalPendingIntent);
+ complicationData = builder.build();
+ return complicationData;
+ }
+
+ /**
+ * If Complication depend on "since" field and need to be updated every minute or not
+ * and need only update when new DisplayRawData arrive
+ */
+ protected boolean usesSinceField() {
+ return false;
+ }
+
+ //==============================================================================================
+ // COMPLICATION LIFECYCLE
+ //==============================================================================================
+
+ /*
+ * Called when a complication has been activated. The method is for any one-time
+ * (per complication) set-up.
+ *
+ * You can continue sending data for the active complicationId until onComplicationDeactivated()
+ * is called.
+ */
+ @Override
+ public void onComplicationActivated(
+ int complicationId, int dataType, ComplicationManager complicationManager) {
+ Log.d(TAG, "onComplicationActivated(): " + complicationId + " of kind: "+getProviderCanonicalName());
+
+ Persistence persistence = new Persistence();
+ persistence.putString("complication_"+complicationId, getProviderCanonicalName());
+ persistence.putBoolean("complication_"+complicationId+"_since", usesSinceField());
+ persistence.addToSet(KEY_COMPLICATIONS, "complication_"+complicationId);
+
+ IntentFilter messageFilter = new IntentFilter(Intent.ACTION_SEND);
+
+ messageReceiver = new BaseComplicationProviderService.MessageReceiver();
+ localBroadcastManager = LocalBroadcastManager.getInstance(this);
+ localBroadcastManager.registerReceiver(messageReceiver, messageFilter);
+
+ ListenerService.requestData(this);
+ checkIfUpdateNeeded();
+ }
+
+ /*
+ * Called when the complication needs updated data from your provider. There are four scenarios
+ * when this will happen:
+ *
+ * 1. An active watch face complication is changed to use this provider
+ * 2. A complication using this provider becomes active
+ * 3. The period of time you specified in the manifest has elapsed (UPDATE_PERIOD_SECONDS)
+ * 4. You triggered an update from your own class via the
+ * ProviderUpdateRequester.requestUpdate() method.
+ */
+ @Override
+ public void onComplicationUpdate(
+ int complicationId, int dataType, ComplicationManager complicationManager) {
+ Log.d(TAG, "onComplicationUpdate() id: " + complicationId + " of class: "+getProviderCanonicalName());
+
+ // Create Tap Action so that the user can checkIfUpdateNeeded an update by tapping the complication.
+ final ComponentName thisProvider = new ComponentName(this, getProviderCanonicalName());
+
+ // We pass the complication id, so we can only update the specific complication tapped.
+ final PendingIntent complicationPendingIntent =
+ ComplicationTapBroadcastReceiver.getTapActionIntent(
+ aaps.getAppContext(), thisProvider, complicationId, getComplicationAction());
+
+ final Persistence persistence = new Persistence();
+
+ final DisplayRawData raw = new DisplayRawData();
+ raw.partialUpdateFromPersistence(persistence);
+ Log.d(TAG, "Complication data: " + raw.toDebugString());
+
+ // store what is currently rendered since field, to detect it need update
+ persistence.putString(KEY_LAST_SINCE, DisplayFormat.shortTimeSince(raw.datetime));
+
+ // by each render we clear stale flag to ensure it is re-rendered at next refresh detection round
+ persistence.putBoolean(KEY_STALE_REPORTED, false);
+
+ ComplicationData complicationData;
+
+ if (WearUtil.msSince(persistence.whenDataUpdated()) > Constants.STALE_MS) {
+ // no new data arrived - probably configuration or connection error
+ final PendingIntent infoToast = ComplicationTapBroadcastReceiver.getTapWarningSinceIntent(
+ aaps.getAppContext(), thisProvider, complicationId, ComplicationAction.WARNING_SYNC, persistence.whenDataUpdated());
+ complicationData = buildNoSyncComplicationData(dataType, raw, complicationPendingIntent, infoToast, persistence.whenDataUpdated());
+ } else if (WearUtil.msSince(raw.datetime) > Constants.STALE_MS) {
+ // data arriving from phone AAPS, but it is outdated (uploader/NS/xDrip/Sensor error)
+ final PendingIntent infoToast = ComplicationTapBroadcastReceiver.getTapWarningSinceIntent(
+ aaps.getAppContext(), thisProvider, complicationId, ComplicationAction.WARNING_OLD, raw.datetime);
+ complicationData = buildOutdatedComplicationData(dataType, raw, complicationPendingIntent, infoToast, raw.datetime);
+ } else {
+ // data is up-to-date, we can render standard complication
+ complicationData = buildComplicationData(dataType, raw, complicationPendingIntent);
+ }
+
+ if (complicationData != null) {
+ complicationManager.updateComplicationData(complicationId, complicationData);
+
+ } else {
+ // If no data is sent, we still need to inform the ComplicationManager, so the update
+ // job can finish and the wake lock isn't held any longer than necessary.
+ complicationManager.noUpdateRequired(complicationId);
+ }
+ }
+
+ /*
+ * Called when the complication has been deactivated.
+ */
+ @Override
+ public void onComplicationDeactivated(int complicationId) {
+ Log.d(TAG, "onComplicationDeactivated(): " + complicationId);
+
+ Persistence persistence = new Persistence();
+ persistence.removeFromSet(KEY_COMPLICATIONS, "complication_"+complicationId);
+
+ if (localBroadcastManager != null && messageReceiver != null) {
+ localBroadcastManager.unregisterReceiver(messageReceiver);
+ }
+ Inevitable.kill(TASK_ID_REFRESH_COMPLICATION);
+ }
+
+ //==============================================================================================
+ // UPDATE AND REFRESH LOGIC
+ //==============================================================================================
+
+ /*
+ * Schedule check for field update
+ */
+ public static void checkIfUpdateNeeded() {
+
+ Persistence p = new Persistence();
+
+ Log.d(TAG, "Pending check if update needed - "+p.getString(KEY_COMPLICATIONS, ""));
+
+ Inevitable.task(TASK_ID_REFRESH_COMPLICATION, 15 * Constants.SECOND_IN_MS, () -> {
+ if (WearUtil.rateLimit("complication-checkIfUpdateNeeded", 5)) {
+ Log.d(TAG, "Checking if update needed");
+ requestUpdateIfSinceChanged();
+ // We reschedule need for check - to make sure next check will Inevitable go in next 15s
+ checkIfUpdateNeeded();
+ }
+ });
+
+ }
+
+ /*
+ * Check if displayed since field (field that shows how old, in minutes, is reading)
+ * is up-to-date or need to be changed (a minute or more elapsed)
+ */
+ private static void requestUpdateIfSinceChanged() {
+ final Persistence persistence = new Persistence();
+
+ final DisplayRawData raw = new DisplayRawData();
+ raw.partialUpdateFromPersistence(persistence);
+
+ final String lastSince = persistence.getString(KEY_LAST_SINCE, "-");
+ final String calcSince = DisplayFormat.shortTimeSince(raw.datetime);
+ final boolean isStale = (WearUtil.msSince(persistence.whenDataUpdated()) > Constants.STALE_MS)
+ ||(WearUtil.msSince(raw.datetime) > Constants.STALE_MS);
+
+ final boolean staleWasRefreshed = persistence.getBoolean(KEY_STALE_REPORTED, false);
+ final boolean sinceWasChanged = !lastSince.equals(calcSince);
+
+ if (sinceWasChanged|| (isStale && !staleWasRefreshed)) {
+ persistence.putString(KEY_LAST_SINCE, calcSince);
+ persistence.putBoolean(KEY_STALE_REPORTED, isStale);
+
+ Log.d(TAG, "Detected refresh of time needed! Reason: "
+ + (isStale ? "- stale detected": "")
+ + (sinceWasChanged ? "- since changed from: "+lastSince+" to: "+calcSince : ""));
+
+ if (isStale) {
+ // all complications should update to show offline/old warning
+ requestUpdate(getActiveProviderClasses());
+ } else {
+ // ... but only some require update due to 'since' field change
+ requestUpdate(getSinceDependingProviderClasses());
+ }
+ }
+ }
+
+ /*
+ * Request update for specified list of providers
+ */
+ private static void requestUpdate(Set providers) {
+ for (String provider: providers) {
+ Log.d(TAG, "Pending update of "+provider);
+ // We wait with updating allowing all request, from various sources, to arrive
+ Inevitable.task("update-req-"+provider, 700, () -> {
+ if (WearUtil.rateLimit("update-req-"+provider, 2)) {
+ Log.d(TAG, "Requesting update of "+provider);
+ final ComponentName componentName = new ComponentName(aaps.getAppContext(), provider);
+ final ProviderUpdateRequester providerUpdateRequester = new ProviderUpdateRequester(aaps.getAppContext(), componentName);
+ providerUpdateRequester.requestUpdateAll();
+ }
+ });
+ }
+ }
+
+ /*
+ * List all Complication providing classes that have active (registered) providers
+ */
+ private static Set getActiveProviderClasses() {
+ Persistence persistence = new Persistence();
+ Set providers = new HashSet<>();
+ Set complications = persistence.getSetOf(KEY_COMPLICATIONS);
+ for (String complication: complications) {
+ final String providerClass = persistence.getString(complication, "");
+ if (providerClass.length() > 0) {
+ providers.add(providerClass);
+ }
+ }
+ return providers;
+ }
+
+ /*
+ * List all Complication providing classes that have active (registered) providers
+ * and additionally they depend on "since" field
+ * == they need to be updated not only on data broadcasts, but every minute or so
+ */
+ private static Set getSinceDependingProviderClasses() {
+ Persistence persistence = new Persistence();
+ Set providers = new HashSet<>();
+ Set complications = persistence.getSetOf(KEY_COMPLICATIONS);
+ for (String complication: complications) {
+ final String providerClass = persistence.getString(complication, "");
+ final boolean dependOnSince = persistence.getBoolean(complication+"_since", false);
+ if ((providerClass.length() > 0)&&(dependOnSince)) {
+ providers.add(providerClass);
+ }
+ }
+ return providers;
+ }
+
+ /*
+ * Listen to broadcast --> new data was stored by ListenerService to Persistence
+ */
+ public class MessageReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Set complications = Persistence.setOf(KEY_COMPLICATIONS);
+ if (complications.size() > 0) {
+ checkIfUpdateNeeded();
+ // We request all active providers
+ requestUpdate(getActiveProviderClasses());
+ }
+ }
+ }
+
+
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/BrCobIobComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/BrCobIobComplication.java
new file mode 100644
index 0000000000..e9f05c5f79
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/BrCobIobComplication.java
@@ -0,0 +1,49 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.support.wearable.complications.ComplicationData;
+import android.support.wearable.complications.ComplicationText;
+import android.util.Log;
+
+import info.nightscout.androidaps.data.DisplayRawData;
+import info.nightscout.androidaps.interaction.utils.DisplayFormat;
+import info.nightscout.androidaps.interaction.utils.SmallestDoubleString;
+
+import static info.nightscout.androidaps.interaction.utils.DisplayFormat.MAX_SHORT_FIELD;
+import static info.nightscout.androidaps.interaction.utils.DisplayFormat.MIN_COB_FIELD;
+import static info.nightscout.androidaps.interaction.utils.DisplayFormat.MIN_IOB_FIELD;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class BrCobIobComplication extends BaseComplicationProviderService {
+
+ private static final String TAG = BrCobIobComplication.class.getSimpleName();
+
+ public ComplicationData buildComplicationData(int dataType, DisplayRawData raw, PendingIntent complicationPendingIntent) {
+
+ ComplicationData complicationData = null;
+
+ if (dataType == ComplicationData.TYPE_SHORT_TEXT) {
+ final String cob = new SmallestDoubleString(raw.sCOB2, SmallestDoubleString.Units.USE).minimise(MIN_COB_FIELD);
+ final String iob = new SmallestDoubleString(raw.sIOB1, SmallestDoubleString.Units.USE).minimise(Math.max(MIN_IOB_FIELD, (MAX_SHORT_FIELD-1) - cob.length()));
+
+ final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
+ .setShortText(ComplicationText.plainText(DisplayFormat.basalRateSymbol()+raw.sBasalRate))
+ .setShortTitle(ComplicationText.plainText(cob + " " + iob))
+ .setTapAction(complicationPendingIntent);
+
+ complicationData = builder.build();
+ } else {
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ }
+ return complicationData;
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return BrCobIobComplication.class.getCanonicalName();
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/CobDetailedComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/CobDetailedComplication.java
new file mode 100644
index 0000000000..48341b53ef
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/CobDetailedComplication.java
@@ -0,0 +1,52 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.support.wearable.complications.ComplicationData;
+import android.support.wearable.complications.ComplicationText;
+import android.util.Log;
+import android.util.Pair;
+
+import info.nightscout.androidaps.data.DisplayRawData;
+import info.nightscout.androidaps.interaction.utils.DisplayFormat;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class CobDetailedComplication extends BaseComplicationProviderService {
+
+ private static final String TAG = CobDetailedComplication.class.getSimpleName();
+
+ public ComplicationData buildComplicationData(int dataType, DisplayRawData raw, PendingIntent complicationPendingIntent) {
+
+ ComplicationData complicationData = null;
+
+ if (dataType == ComplicationData.TYPE_SHORT_TEXT) {
+
+ Pair cob = DisplayFormat.detailedCob(raw);
+ final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
+ .setShortText(ComplicationText.plainText(cob.first))
+ .setTapAction(complicationPendingIntent);
+
+ if (cob.second.length() > 0) {
+ builder.setShortTitle(ComplicationText.plainText(cob.second));
+ }
+
+ complicationData = builder.build();
+ } else {
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ }
+ return complicationData;
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return CobDetailedComplication.class.getCanonicalName();
+ }
+
+ @Override
+ public ComplicationAction getComplicationAction() {
+ return ComplicationAction.WIZARD;
+ };
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/CobIconComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/CobIconComplication.java
new file mode 100644
index 0000000000..40824fd313
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/CobIconComplication.java
@@ -0,0 +1,51 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+import android.support.wearable.complications.ComplicationData;
+import android.support.wearable.complications.ComplicationText;
+import android.util.Log;
+
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.DisplayRawData;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class CobIconComplication extends BaseComplicationProviderService {
+
+ private static final String TAG = CobIconComplication.class.getSimpleName();
+
+ public ComplicationData buildComplicationData(int dataType, DisplayRawData raw, PendingIntent complicationPendingIntent) {
+
+ ComplicationData complicationData = null;
+
+ if (dataType == ComplicationData.TYPE_SHORT_TEXT) {
+ final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
+ .setShortText(ComplicationText.plainText(raw.sCOB2))
+ .setIcon(
+ Icon.createWithResource(
+ this, R.drawable.ic_carbs))
+ .setBurnInProtectionIcon(
+ Icon.createWithResource(
+ this, R.drawable.ic_carbs))
+ .setTapAction(complicationPendingIntent);
+
+ complicationData = builder.build();
+ } else {
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ }
+ return complicationData;
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return CobIconComplication.class.getCanonicalName();
+ }
+
+ public ComplicationAction getComplicationAction() {
+ return ComplicationAction.WIZARD;
+ };
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/CobIobComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/CobIobComplication.java
new file mode 100644
index 0000000000..1f7dff7ceb
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/CobIobComplication.java
@@ -0,0 +1,46 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.support.wearable.complications.ComplicationData;
+import android.support.wearable.complications.ComplicationText;
+import android.util.Log;
+
+import info.nightscout.androidaps.data.DisplayRawData;
+import info.nightscout.androidaps.interaction.utils.SmallestDoubleString;
+
+import static info.nightscout.androidaps.interaction.utils.DisplayFormat.MAX_SHORT_FIELD;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class CobIobComplication extends BaseComplicationProviderService {
+
+ private static final String TAG = CobIobComplication.class.getSimpleName();
+
+ public ComplicationData buildComplicationData(int dataType, DisplayRawData raw, PendingIntent complicationPendingIntent) {
+
+ ComplicationData complicationData = null;
+
+ if (dataType == ComplicationData.TYPE_SHORT_TEXT) {
+ final String cob = raw.sCOB2;
+ final String iob = new SmallestDoubleString(raw.sIOB1, SmallestDoubleString.Units.USE).minimise(MAX_SHORT_FIELD);
+
+ final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
+ .setShortText(ComplicationText.plainText(cob))
+ .setShortTitle(ComplicationText.plainText(iob))
+ .setTapAction(complicationPendingIntent);
+
+ complicationData = builder.build();
+ } else {
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ }
+ return complicationData;
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return CobIobComplication.class.getCanonicalName();
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/ComplicationAction.java b/wear/src/main/java/info/nightscout/androidaps/complications/ComplicationAction.java
new file mode 100644
index 0000000000..9ca1e9c456
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/ComplicationAction.java
@@ -0,0 +1,12 @@
+package info.nightscout.androidaps.complications;
+
+public enum ComplicationAction {
+ NONE,
+ MENU,
+ WIZARD,
+ BOLUS,
+ ECARB,
+ STATUS,
+ WARNING_SYNC,
+ WARNING_OLD
+}
\ No newline at end of file
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/ComplicationTapBroadcastReceiver.java b/wear/src/main/java/info/nightscout/androidaps/complications/ComplicationTapBroadcastReceiver.java
new file mode 100644
index 0000000000..61dc8d4dde
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/ComplicationTapBroadcastReceiver.java
@@ -0,0 +1,167 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.wearable.complications.ProviderUpdateRequester;
+import android.util.Log;
+import android.widget.Toast;
+
+import androidx.annotation.StringRes;
+
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.aaps;
+import info.nightscout.androidaps.interaction.actions.BolusActivity;
+import info.nightscout.androidaps.interaction.actions.ECarbActivity;
+import info.nightscout.androidaps.interaction.actions.WizardActivity;
+import info.nightscout.androidaps.interaction.menus.MainMenuActivity;
+import info.nightscout.androidaps.interaction.menus.StatusMenuActivity;
+import info.nightscout.androidaps.interaction.utils.Constants;
+import info.nightscout.androidaps.interaction.utils.DisplayFormat;
+import info.nightscout.androidaps.interaction.utils.WearUtil;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class ComplicationTapBroadcastReceiver extends BroadcastReceiver {
+
+ private static final String TAG = ComplicationTapBroadcastReceiver.class.getSimpleName();
+
+ private static final String EXTRA_PROVIDER_COMPONENT =
+ "info.nightscout.androidaps.complications.action.PROVIDER_COMPONENT";
+ private static final String EXTRA_COMPLICATION_ID =
+ "info.nightscout.androidaps.complications.action.COMPLICATION_ID";
+ private static final String EXTRA_COMPLICATION_ACTION =
+ "info.nightscout.androidaps.complications.action.COMPLICATION_ACTION";
+ private static final String EXTRA_COMPLICATION_SINCE =
+ "info.nightscout.androidaps.complications.action.COMPLICATION_SINCE";
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Bundle extras = intent.getExtras();
+ ComponentName provider = extras.getParcelable(EXTRA_PROVIDER_COMPONENT);
+ int complicationId = extras.getInt(EXTRA_COMPLICATION_ID);
+ String complicationAction = extras.getString(EXTRA_COMPLICATION_ACTION, ComplicationAction.MENU.toString());
+
+ ComplicationAction action = ComplicationAction.MENU;
+ try {
+ action = ComplicationAction.valueOf(ComplicationAction.class, complicationAction);
+ } catch (IllegalArgumentException | NullPointerException ex) {
+ // but how?
+ Log.e(TAG, "Cannot interpret complication action: "+complicationAction);
+ }
+
+ action = remapActionWithUserPreferences(action);
+
+ // Request an update for the complication that has just been tapped.
+ ProviderUpdateRequester requester = new ProviderUpdateRequester(context, provider);
+ requester.requestUpdate(complicationId);
+
+ Intent intentOpen = null;
+
+ switch (action) {
+ case NONE:
+ // do nothing
+ return;
+ case WIZARD:
+ intentOpen = new Intent(aaps.getAppContext(), WizardActivity.class);
+ break;
+ case BOLUS:
+ intentOpen = new Intent(aaps.getAppContext(), BolusActivity.class);
+ break;
+ case ECARB:
+ intentOpen = new Intent(aaps.getAppContext(), ECarbActivity.class);
+ break;
+ case STATUS:
+ intentOpen = new Intent(aaps.getAppContext(), StatusMenuActivity.class);
+ break;
+ case WARNING_OLD:
+ case WARNING_SYNC:
+ long oneAndHalfMinuteAgo = WearUtil.timestamp() - (Constants.MINUTE_IN_MS+Constants.SECOND_IN_MS * 30);
+ long since = extras.getLong(EXTRA_COMPLICATION_SINCE, oneAndHalfMinuteAgo);
+ @StringRes int labelId = (action == ComplicationAction.WARNING_SYNC) ?
+ R.string.msg_warning_sync : R.string.msg_warning_old;
+ String msg = String.format(aaps.gs(labelId), DisplayFormat.shortTimeSince(since));
+ Toast.makeText(aaps.getAppContext(), msg, Toast.LENGTH_LONG).show();
+ break;
+ case MENU:
+ default:
+ intentOpen = new Intent(aaps.getAppContext(), MainMenuActivity.class);
+ }
+
+ if (intentOpen != null) {
+ // Perform intent - open dialog
+ intentOpen.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ aaps.getAppContext().startActivity(intentOpen);
+ }
+ }
+
+ private ComplicationAction remapActionWithUserPreferences(ComplicationAction originalAction) {
+ final String userPrefAction = aaps.getComplicationTapAction();
+ switch (originalAction) {
+ case WARNING_OLD:
+ case WARNING_SYNC:
+ // warnings cannot be reconfigured by user
+ return originalAction;
+ default:
+ switch (userPrefAction) {
+ case "menu":
+ return ComplicationAction.MENU;
+ case "wizard":
+ return ComplicationAction.WIZARD;
+ case "bolus":
+ return ComplicationAction.BOLUS;
+ case "ecarb":
+ return ComplicationAction.ECARB;
+ case "status":
+ return ComplicationAction.STATUS;
+ case "none":
+ return ComplicationAction.NONE;
+ case "default":
+ default:
+ return originalAction;
+ }
+ }
+ }
+
+ /**
+ * Returns a pending intent, suitable for use as a tap intent, that causes a complication to be
+ * toggled and updated.
+ */
+ static PendingIntent getTapActionIntent(
+ Context context, ComponentName provider, int complicationId, ComplicationAction action) {
+ Intent intent = new Intent(context, ComplicationTapBroadcastReceiver.class);
+ intent.putExtra(EXTRA_PROVIDER_COMPONENT, provider);
+ intent.putExtra(EXTRA_COMPLICATION_ID, complicationId);
+ intent.putExtra(EXTRA_COMPLICATION_ACTION, action.toString());
+
+
+ // Pass complicationId as the requestCode to ensure that different complications get
+ // different intents.
+ return PendingIntent.getBroadcast(
+ context, complicationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+ /**
+ * Returns a pending intent, suitable for use as a tap intent, that causes a complication to be
+ * toggled and updated.
+ */
+ static PendingIntent getTapWarningSinceIntent(
+ Context context, ComponentName provider, int complicationId, ComplicationAction action, long since) {
+ Intent intent = new Intent(context, ComplicationTapBroadcastReceiver.class);
+ intent.putExtra(EXTRA_PROVIDER_COMPONENT, provider);
+ intent.putExtra(EXTRA_COMPLICATION_ID, complicationId);
+ intent.putExtra(EXTRA_COMPLICATION_ACTION, action.toString());
+ intent.putExtra(EXTRA_COMPLICATION_SINCE, since);
+
+
+ // Pass complicationId as the requestCode to ensure that different complications get
+ // different intents.
+ return PendingIntent.getBroadcast(
+ context, complicationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/IobDetailedComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/IobDetailedComplication.java
new file mode 100644
index 0000000000..d9ee729874
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/IobDetailedComplication.java
@@ -0,0 +1,52 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.support.wearable.complications.ComplicationData;
+import android.support.wearable.complications.ComplicationText;
+import android.util.Log;
+import android.util.Pair;
+
+import info.nightscout.androidaps.data.DisplayRawData;
+import info.nightscout.androidaps.interaction.utils.DisplayFormat;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class IobDetailedComplication extends BaseComplicationProviderService {
+
+ private static final String TAG = IobDetailedComplication.class.getSimpleName();
+
+ public ComplicationData buildComplicationData(int dataType, DisplayRawData raw, PendingIntent complicationPendingIntent) {
+
+ ComplicationData complicationData = null;
+
+ if (dataType == ComplicationData.TYPE_SHORT_TEXT) {
+
+ Pair iob = DisplayFormat.detailedIob(raw);
+ final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
+ .setShortText(ComplicationText.plainText(iob.first))
+ .setTapAction(complicationPendingIntent);
+
+ if (iob.second.length() > 0) {
+ builder.setShortTitle(ComplicationText.plainText(iob.second));
+ }
+
+ complicationData = builder.build();
+ } else {
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ }
+ return complicationData;
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return IobDetailedComplication.class.getCanonicalName();
+ }
+
+ @Override
+ public ComplicationAction getComplicationAction() {
+ return ComplicationAction.BOLUS;
+ };
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/IobIconComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/IobIconComplication.java
new file mode 100644
index 0000000000..ba253a048d
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/IobIconComplication.java
@@ -0,0 +1,56 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+import android.support.wearable.complications.ComplicationData;
+import android.support.wearable.complications.ComplicationText;
+import android.util.Log;
+
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.DisplayRawData;
+import info.nightscout.androidaps.interaction.utils.SmallestDoubleString;
+
+import static info.nightscout.androidaps.interaction.utils.DisplayFormat.MAX_SHORT_FIELD;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class IobIconComplication extends BaseComplicationProviderService {
+
+ private static final String TAG = IobIconComplication.class.getSimpleName();
+
+ public ComplicationData buildComplicationData(int dataType, DisplayRawData raw, PendingIntent complicationPendingIntent) {
+
+ ComplicationData complicationData = null;
+
+ if (dataType == ComplicationData.TYPE_SHORT_TEXT) {
+ final String iob = new SmallestDoubleString(raw.sIOB1, SmallestDoubleString.Units.USE).minimise(MAX_SHORT_FIELD);
+
+ final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
+ .setShortText(ComplicationText.plainText(iob))
+ .setIcon(Icon.createWithResource(
+ this, R.drawable.ic_ins))
+ .setBurnInProtectionIcon(
+ Icon.createWithResource(
+ this, R.drawable.ic_ins_burnin))
+ .setTapAction(complicationPendingIntent);
+
+ complicationData = builder.build();
+ } else {
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ }
+ return complicationData;
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return IobIconComplication.class.getCanonicalName();
+ }
+
+ @Override
+ public ComplicationAction getComplicationAction() {
+ return ComplicationAction.BOLUS;
+ };
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/LongStatusComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/LongStatusComplication.java
new file mode 100644
index 0000000000..834f40b0a7
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/LongStatusComplication.java
@@ -0,0 +1,52 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.support.wearable.complications.ComplicationData;
+import android.support.wearable.complications.ComplicationText;
+import android.util.Log;
+
+import info.nightscout.androidaps.data.DisplayRawData;
+import info.nightscout.androidaps.interaction.utils.DisplayFormat;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class LongStatusComplication extends BaseComplicationProviderService {
+
+ private static final String TAG = LongStatusComplication.class.getSimpleName();
+
+ public ComplicationData buildComplicationData(int dataType, DisplayRawData raw, PendingIntent complicationPendingIntent) {
+
+ ComplicationData complicationData = null;
+
+ switch (dataType) {
+ case ComplicationData.TYPE_LONG_TEXT:
+
+ final String glucoseLine = DisplayFormat.longGlucoseLine(raw);
+ final String detailsLine = DisplayFormat.longDetailsLine(raw);
+
+ final ComplicationData.Builder builderLong = new ComplicationData.Builder(ComplicationData.TYPE_LONG_TEXT)
+ .setLongTitle(ComplicationText.plainText(glucoseLine))
+ .setLongText(ComplicationText.plainText(detailsLine))
+ .setTapAction(complicationPendingIntent);
+ complicationData = builderLong.build();
+
+ break;
+ default:
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ }
+ return complicationData;
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return LongStatusComplication.class.getCanonicalName();
+ }
+
+ @Override
+ protected boolean usesSinceField() {
+ return true;
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/LongStatusFlippedComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/LongStatusFlippedComplication.java
new file mode 100644
index 0000000000..da3384d358
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/LongStatusFlippedComplication.java
@@ -0,0 +1,53 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.support.wearable.complications.ComplicationData;
+import android.support.wearable.complications.ComplicationText;
+import android.util.Log;
+
+import info.nightscout.androidaps.data.DisplayRawData;
+import info.nightscout.androidaps.interaction.utils.DisplayFormat;
+import info.nightscout.androidaps.interaction.utils.SmallestDoubleString;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class LongStatusFlippedComplication extends BaseComplicationProviderService {
+
+ private static final String TAG = LongStatusFlippedComplication.class.getSimpleName();
+
+ public ComplicationData buildComplicationData(int dataType, DisplayRawData raw, PendingIntent complicationPendingIntent) {
+
+ ComplicationData complicationData = null;
+
+ switch (dataType) {
+ case ComplicationData.TYPE_LONG_TEXT:
+
+ final String glucoseLine = DisplayFormat.longGlucoseLine(raw);
+ final String detailsLine = DisplayFormat.longDetailsLine(raw);
+
+ final ComplicationData.Builder builderLong = new ComplicationData.Builder(ComplicationData.TYPE_LONG_TEXT)
+ .setLongTitle(ComplicationText.plainText(detailsLine))
+ .setLongText(ComplicationText.plainText(glucoseLine))
+ .setTapAction(complicationPendingIntent);
+ complicationData = builderLong.build();
+
+ break;
+ default:
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ }
+ return complicationData;
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return LongStatusFlippedComplication.class.getCanonicalName();
+ }
+
+ @Override
+ protected boolean usesSinceField() {
+ return true;
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/SgvComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/SgvComplication.java
new file mode 100644
index 0000000000..b6f9e94946
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/SgvComplication.java
@@ -0,0 +1,48 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.support.wearable.complications.ComplicationData;
+import android.support.wearable.complications.ComplicationText;
+import android.util.Log;
+
+import info.nightscout.androidaps.data.DisplayRawData;
+import info.nightscout.androidaps.interaction.utils.DisplayFormat;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class SgvComplication extends BaseComplicationProviderService {
+
+ private static final String TAG = SgvComplication.class.getSimpleName();
+
+ public ComplicationData buildComplicationData(int dataType, DisplayRawData raw, PendingIntent complicationPendingIntent) {
+
+ ComplicationData complicationData = null;
+
+ switch (dataType) {
+ case ComplicationData.TYPE_SHORT_TEXT:
+ final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
+ .setShortText(ComplicationText.plainText(raw.sSgv + raw.sDirection))
+ .setShortTitle(ComplicationText.plainText(DisplayFormat.shortTrend(raw)))
+ .setTapAction(complicationPendingIntent);
+
+ complicationData = builder.build();
+ break;
+ default:
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ }
+ return complicationData;
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return SgvComplication.class.getCanonicalName();
+ }
+
+ @Override
+ protected boolean usesSinceField() {
+ return true;
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/UploaderBattery.java b/wear/src/main/java/info/nightscout/androidaps/complications/UploaderBattery.java
new file mode 100644
index 0000000000..4b268ef9c7
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/UploaderBattery.java
@@ -0,0 +1,114 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+import android.support.wearable.complications.ComplicationData;
+import android.support.wearable.complications.ComplicationText;
+import android.util.Log;
+
+import androidx.annotation.DrawableRes;
+import info.nightscout.androidaps.R;
+import info.nightscout.androidaps.data.DisplayRawData;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class UploaderBattery extends BaseComplicationProviderService {
+
+ private static final String TAG = UploaderBattery.class.getSimpleName();
+
+ public ComplicationData buildComplicationData(int dataType, DisplayRawData raw, PendingIntent complicationPendingIntent) {
+
+ ComplicationData complicationData = null;
+
+ @DrawableRes int batteryIcon = R.drawable.ic_battery_unknown;
+ @DrawableRes int burnInBatteryIcon = R.drawable.ic_battery_unknown_burnin;
+ int level = 0;
+ String levelStr = "???";
+
+ if (raw.sUploaderBattery.matches("^[0-9]+$")) {
+ try {
+ level = Integer.parseInt(raw.sUploaderBattery);
+ level = Math.max(Math.min(level, 100), 0);
+ levelStr = level + "%";
+ int iconNo = (int)Math.floor(level / 10.0);
+ if (level > 95) {
+ iconNo = 10;
+ }
+ switch (iconNo) {
+ case 10: batteryIcon = R.drawable.ic_battery_charging_wireless; break;
+ case 9: batteryIcon = R.drawable.ic_battery_charging_wireless_90; break;
+ case 8: batteryIcon = R.drawable.ic_battery_charging_wireless_80; break;
+ case 7: batteryIcon = R.drawable.ic_battery_charging_wireless_70; break;
+ case 6: batteryIcon = R.drawable.ic_battery_charging_wireless_60; break;
+ case 5: batteryIcon = R.drawable.ic_battery_charging_wireless_50; break;
+ case 4: batteryIcon = R.drawable.ic_battery_charging_wireless_40; break;
+ case 3: batteryIcon = R.drawable.ic_battery_charging_wireless_30; break;
+ case 2: batteryIcon = R.drawable.ic_battery_charging_wireless_20; break;
+ case 1: batteryIcon = R.drawable.ic_battery_charging_wireless_10; break;
+ case 0: batteryIcon = R.drawable.ic_battery_alert_variant_outline; break;
+ default: batteryIcon = R.drawable.ic_battery_charging_wireless_outline;
+ }
+
+ switch (iconNo) {
+ case 10: burnInBatteryIcon = R.drawable.ic_battery_charging_wireless_burnin; break;
+ case 9: burnInBatteryIcon = R.drawable.ic_battery_charging_wireless_90_burnin; break;
+ case 8: burnInBatteryIcon = R.drawable.ic_battery_charging_wireless_80_burnin; break;
+ case 7: burnInBatteryIcon = R.drawable.ic_battery_charging_wireless_70_burnin; break;
+ case 6: burnInBatteryIcon = R.drawable.ic_battery_charging_wireless_60_burnin; break;
+ case 5: burnInBatteryIcon = R.drawable.ic_battery_charging_wireless_50_burnin; break;
+ case 4: burnInBatteryIcon = R.drawable.ic_battery_charging_wireless_40_burnin; break;
+ case 3: burnInBatteryIcon = R.drawable.ic_battery_charging_wireless_30_burnin; break;
+ case 2: burnInBatteryIcon = R.drawable.ic_battery_charging_wireless_20_burnin; break;
+ case 1: burnInBatteryIcon = R.drawable.ic_battery_charging_wireless_10_burnin; break;
+ case 0: burnInBatteryIcon = R.drawable.ic_battery_alert_variant_outline; break;
+ default: burnInBatteryIcon = R.drawable.ic_battery_charging_wireless_outline;
+ }
+
+
+ } catch (NumberFormatException ex){
+ Log.e(TAG, "Cannot parse battery level of: " + raw.sUploaderBattery);
+ }
+ }
+
+ if (dataType == ComplicationData.TYPE_RANGED_VALUE) {
+ final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_RANGED_VALUE)
+ .setMinValue(0)
+ .setMaxValue(100)
+ .setValue(level)
+ .setShortText(ComplicationText.plainText(levelStr))
+ .setIcon(Icon.createWithResource(this, batteryIcon))
+ .setBurnInProtectionIcon(Icon.createWithResource(this, burnInBatteryIcon))
+ .setTapAction(complicationPendingIntent);
+ complicationData = builder.build();
+ } else if (dataType == ComplicationData.TYPE_SHORT_TEXT) {
+ final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
+ .setShortText(ComplicationText.plainText(levelStr))
+ .setIcon(Icon.createWithResource(this, batteryIcon))
+ .setBurnInProtectionIcon(Icon.createWithResource(this, burnInBatteryIcon))
+ .setTapAction(complicationPendingIntent);
+ complicationData = builder.build();
+ } else if (dataType == ComplicationData.TYPE_ICON) {
+ final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_ICON)
+ .setIcon(Icon.createWithResource(this, batteryIcon))
+ .setBurnInProtectionIcon(Icon.createWithResource(this, burnInBatteryIcon))
+ .setTapAction(complicationPendingIntent);
+ complicationData = builder.build();
+ } else {
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ }
+ return complicationData;
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return UploaderBattery.class.getCanonicalName();
+ }
+
+ @Override
+ public ComplicationAction getComplicationAction() {
+ return ComplicationAction.STATUS;
+ };
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/WallpaperComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/WallpaperComplication.java
new file mode 100644
index 0000000000..2448bebee0
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/WallpaperComplication.java
@@ -0,0 +1,62 @@
+package info.nightscout.androidaps.complications;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Icon;
+import android.support.wearable.complications.ComplicationData;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.WindowManager;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import info.nightscout.androidaps.aaps;
+import info.nightscout.androidaps.data.DisplayRawData;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public abstract class WallpaperComplication extends BaseComplicationProviderService {
+
+ public abstract String getWallpaperAssetsFileName();
+
+ private static final String TAG = WallpaperComplication.class.getSimpleName();
+
+ public ComplicationData buildComplicationData(int dataType, DisplayRawData raw, PendingIntent complicationPendingIntent) {
+
+ ComplicationData complicationData = null;
+
+ if (dataType == ComplicationData.TYPE_LARGE_IMAGE) {
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ WindowManager windowManager = (WindowManager) aaps.getAppContext()
+ .getSystemService(Context.WINDOW_SERVICE);
+ windowManager.getDefaultDisplay().getMetrics(metrics);
+ int width = metrics.widthPixels;
+ int height = metrics.heightPixels;
+
+ final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_LARGE_IMAGE);
+
+ AssetManager assetManager = getAssets();
+ try (InputStream istr = assetManager.open(getWallpaperAssetsFileName())) {
+ Bitmap bitmap = BitmapFactory.decodeStream(istr);
+ Bitmap scaled = Bitmap.createScaledBitmap(bitmap, width, height, true);
+ builder.setLargeImage(Icon.createWithBitmap(scaled));
+ } catch (IOException e) {
+ Log.e(TAG, "Cannot read wallpaper asset: "+e.getMessage(), e);
+ e.printStackTrace();
+ }
+
+ complicationData = builder.build();
+ } else {
+ if (Log.isLoggable(TAG, Log.WARN)) {
+ Log.w(TAG, "Unexpected complication type " + dataType);
+ }
+ }
+ return complicationData;
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/WallpaperDarkComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/WallpaperDarkComplication.java
new file mode 100644
index 0000000000..8c84e1d8c3
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/WallpaperDarkComplication.java
@@ -0,0 +1,22 @@
+package info.nightscout.androidaps.complications;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class WallpaperDarkComplication extends WallpaperComplication {
+
+ @Override
+ public String getWallpaperAssetsFileName() {
+ return "watch_dark.jpg";
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return WallpaperDarkComplication.class.getCanonicalName();
+ }
+
+ @Override
+ public ComplicationAction getComplicationAction() {
+ return ComplicationAction.NONE;
+ };
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/WallpaperGrayComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/WallpaperGrayComplication.java
new file mode 100644
index 0000000000..bec047f323
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/WallpaperGrayComplication.java
@@ -0,0 +1,22 @@
+package info.nightscout.androidaps.complications;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class WallpaperGrayComplication extends WallpaperComplication {
+
+ @Override
+ public String getWallpaperAssetsFileName() {
+ return "watch_gray.jpg";
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return WallpaperGrayComplication.class.getCanonicalName();
+ }
+
+ @Override
+ public ComplicationAction getComplicationAction() {
+ return ComplicationAction.NONE;
+ };
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/complications/WallpaperLightComplication.java b/wear/src/main/java/info/nightscout/androidaps/complications/WallpaperLightComplication.java
new file mode 100644
index 0000000000..2d2bbf6f14
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/complications/WallpaperLightComplication.java
@@ -0,0 +1,22 @@
+package info.nightscout.androidaps.complications;
+
+/*
+ * Created by dlvoy on 2019-11-12
+ */
+public class WallpaperLightComplication extends WallpaperComplication {
+
+ @Override
+ public String getWallpaperAssetsFileName() {
+ return "watch_light.jpg";
+ }
+
+ @Override
+ public String getProviderCanonicalName() {
+ return WallpaperLightComplication.class.getCanonicalName();
+ }
+
+ @Override
+ public ComplicationAction getComplicationAction() {
+ return ComplicationAction.NONE;
+ };
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/data/DisplayRawData.java b/wear/src/main/java/info/nightscout/androidaps/data/DisplayRawData.java
new file mode 100644
index 0000000000..e9cf997db8
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/data/DisplayRawData.java
@@ -0,0 +1,269 @@
+package info.nightscout.androidaps.data;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.PowerManager;
+
+import com.google.android.gms.wearable.DataMap;
+
+import java.util.ArrayList;
+
+import info.nightscout.androidaps.interaction.utils.Constants;
+import info.nightscout.androidaps.interaction.utils.Persistence;
+import info.nightscout.androidaps.interaction.utils.WearUtil;
+
+/**
+ * Holds bunch of data model variables and lists that arrive from phone app and are due to be
+ * displayed on watchface and complications. Keeping them together makes code cleaner and allows
+ * passing it to complications via persistence layer.
+ *
+ * Created by dlvoy on 2019-11-12
+ */
+public class DisplayRawData {
+
+ static final String DATA_PERSISTENCE_KEY = "raw_data";
+ static final String BASALS_PERSISTENCE_KEY = "raw_basals";
+ static final String STATUS_PERSISTENCE_KEY = "raw_status";
+
+ // data bundle
+ public long sgvLevel = 0;
+ public long datetime;
+ public String sSgv = "---";
+ public String sDirection = "--";
+ public String sDelta = "--";
+ public String sAvgDelta = "--";
+ public String sUnits = "-";
+
+ // status bundle
+ public String sBasalRate = "-.--U/h";
+ public String sUploaderBattery = "--";
+ public String sRigBattery = "--";
+ public boolean detailedIOB = false;
+ public String sIOB1 = "IOB";
+ public String sIOB2 = "-.--";
+ public String sCOB1 = "Carb";
+ public String sCOB2= "--g";
+ public String sBgi = "--";
+ public boolean showBGI = false;
+ public String externalStatusString = "no status";
+ public int batteryLevel = 1;
+ public long openApsStatus = -1;
+
+ // basals bundle
+ public ArrayList bgDataList = new ArrayList<>();
+ public ArrayList tempWatchDataList = new ArrayList<>();
+ public ArrayList basalWatchDataList = new ArrayList<>();
+ public ArrayList bolusWatchDataList = new ArrayList<>();
+ public ArrayList predictionList = new ArrayList<>();
+
+ public String toDebugString() {
+ return "DisplayRawData{" +
+ "sgvLevel=" + sgvLevel +
+ ", datetime=" + datetime +
+ ", sSgv='" + sSgv + '\'' +
+ ", sDirection='" + sDirection + '\'' +
+ ", sDelta='" + sDelta + '\'' +
+ ", sAvgDelta='" + sAvgDelta + '\'' +
+ ", sUnits='" + sUnits + '\'' +
+ ", sBasalRate='" + sBasalRate + '\'' +
+ ", sUploaderBattery='" + sUploaderBattery + '\'' +
+ ", sRigBattery='" + sRigBattery + '\'' +
+ ", detailedIOB=" + detailedIOB +
+ ", sIOB1='" + sIOB1 + '\'' +
+ ", sIOB2='" + sIOB2 + '\'' +
+ ", sCOB1='" + sCOB1 + '\'' +
+ ", sCOB2='" + sCOB2 + '\'' +
+ ", sBgi='" + sBgi + '\'' +
+ ", showBGI=" + showBGI +
+ ", externalStatusString='" + externalStatusString + '\'' +
+ ", batteryLevel=" + batteryLevel +
+ ", openApsStatus=" + openApsStatus +
+ ", bgDataList size=" + bgDataList.size() +
+ ", tempWatchDataList size=" + tempWatchDataList.size() +
+ ", basalWatchDataList size=" + basalWatchDataList.size() +
+ ", bolusWatchDataLis size=" + bolusWatchDataList.size() +
+ ", predictionList size=" + predictionList.size() +
+ '}';
+ }
+
+ public void updateFromPersistence(Persistence persistence) {
+
+ DataMap dataMapData = persistence.getDataMap(DATA_PERSISTENCE_KEY);
+ if (dataMapData != null) {
+ updateData(dataMapData);
+ }
+ DataMap dataMapStatus = persistence.getDataMap(STATUS_PERSISTENCE_KEY);
+ if (dataMapStatus != null) {
+ updateStatus(dataMapStatus);
+ }
+ DataMap dataMapBasals = persistence.getDataMap(BASALS_PERSISTENCE_KEY);
+ if (dataMapBasals != null) {
+ updateBasals(dataMapBasals);
+ }
+ }
+
+ /*
+ * Since complications do not need Basals, we skip them for performance
+ */
+ public void partialUpdateFromPersistence(Persistence persistence) {
+
+ DataMap dataMapData = persistence.getDataMap(DATA_PERSISTENCE_KEY);
+ if (dataMapData != null) {
+ updateData(dataMapData);
+ }
+ DataMap dataMapStatus = persistence.getDataMap(STATUS_PERSISTENCE_KEY);
+ if (dataMapStatus != null) {
+ updateStatus(dataMapStatus);
+ }
+ }
+
+ public DataMap updateDataFromMessage(Intent intent, PowerManager.WakeLock wakeLock) {
+ Bundle bundle = intent.getBundleExtra("data");
+ if (bundle != null) {
+ DataMap dataMap = DataMap.fromBundle(bundle);
+ updateData(dataMap);
+ return dataMap;
+ }
+ return null;
+ }
+
+ private void updateData(DataMap dataMap) {
+ WearUtil.getWakeLock("readingPrefs", 50);
+ sgvLevel = dataMap.getLong("sgvLevel");
+ datetime = dataMap.getLong("timestamp");
+ sSgv = dataMap.getString("sgvString");
+ sDirection = dataMap.getString("slopeArrow");
+ sDelta = dataMap.getString("delta");
+ sAvgDelta = dataMap.getString("avgDelta");
+ sUnits = dataMap.getString("glucoseUnits");
+ }
+
+ public DataMap updateStatusFromMessage(Intent intent, PowerManager.WakeLock wakeLock) {
+ Bundle bundle = intent.getBundleExtra("status");
+ if (bundle != null) {
+ DataMap dataMap = DataMap.fromBundle(bundle);
+ updateStatus(dataMap);
+ return dataMap;
+ }
+ return null;
+ }
+
+ private void updateStatus(DataMap dataMap) {
+ WearUtil.getWakeLock("readingPrefs", 50);
+ sBasalRate = dataMap.getString("currentBasal");
+ sUploaderBattery = dataMap.getString("battery");
+ sRigBattery = dataMap.getString("rigBattery");
+ detailedIOB = dataMap.getBoolean("detailedIob");
+ sIOB1 = dataMap.getString("iobSum") + "U";
+ sIOB2 = dataMap.getString("iobDetail");
+ sCOB1 = "Carb";
+ sCOB2 = dataMap.getString("cob");
+ sBgi = dataMap.getString("bgi");
+ showBGI = dataMap.getBoolean("showBgi");
+ externalStatusString = dataMap.getString("externalStatusString");
+ batteryLevel = dataMap.getInt("batteryLevel");
+ openApsStatus = dataMap.getLong("openApsStatus");
+ }
+
+ public DataMap updateBasalsFromMessage(Intent intent, PowerManager.WakeLock wakeLock) {
+ Bundle bundle = intent.getBundleExtra("basals");
+ if (bundle != null) {
+ DataMap dataMap = DataMap.fromBundle(bundle);
+ updateBasals(dataMap);
+ return dataMap;
+ }
+ return null;
+ }
+
+ private void updateBasals(DataMap dataMap) {
+ WearUtil.getWakeLock("readingPrefs", 500);
+ loadBasalsAndTemps(dataMap);
+ }
+
+ private void loadBasalsAndTemps(DataMap dataMap) {
+ ArrayList temps = dataMap.getDataMapArrayList("temps");
+ if (temps != null) {
+ tempWatchDataList = new ArrayList<>();
+ for (DataMap temp : temps) {
+ TempWatchData twd = new TempWatchData();
+ twd.startTime = temp.getLong("starttime");
+ twd.startBasal = temp.getDouble("startBasal");
+ twd.endTime = temp.getLong("endtime");
+ twd.endBasal = temp.getDouble("endbasal");
+ twd.amount = temp.getDouble("amount");
+ tempWatchDataList.add(twd);
+ }
+ }
+ ArrayList basals = dataMap.getDataMapArrayList("basals");
+ if (basals != null) {
+ basalWatchDataList = new ArrayList<>();
+ for (DataMap basal : basals) {
+ BasalWatchData bwd = new BasalWatchData();
+ bwd.startTime = basal.getLong("starttime");
+ bwd.endTime = basal.getLong("endtime");
+ bwd.amount = basal.getDouble("amount");
+ basalWatchDataList.add(bwd);
+ }
+ }
+ ArrayList boluses = dataMap.getDataMapArrayList("boluses");
+ if (boluses != null) {
+ bolusWatchDataList = new ArrayList<>();
+ for (DataMap bolus : boluses) {
+ BolusWatchData bwd = new BolusWatchData();
+ bwd.date = bolus.getLong("date");
+ bwd.bolus = bolus.getDouble("bolus");
+ bwd.carbs = bolus.getDouble("carbs");
+ bwd.isSMB = bolus.getBoolean("isSMB");
+ bwd.isValid = bolus.getBoolean("isValid");
+ bolusWatchDataList.add(bwd);
+ }
+ }
+ ArrayList predictions = dataMap.getDataMapArrayList("predictions");
+ if (boluses != null) {
+ predictionList = new ArrayList<>();
+ for (DataMap prediction : predictions) {
+ BgWatchData bwd = new BgWatchData();
+ bwd.timestamp = prediction.getLong("timestamp");
+ bwd.sgv = prediction.getDouble("sgv");
+ bwd.color = prediction.getInt("color");
+ predictionList.add(bwd);
+ }
+ }
+ }
+
+ public void addToWatchSet(DataMap dataMap) {
+ ArrayList entries = dataMap.getDataMapArrayList("entries");
+ if (entries != null) {
+ bgDataList = new ArrayList<>();
+ for (DataMap entry : entries) {
+ double sgv = entry.getDouble("sgvDouble");
+ double high = entry.getDouble("high");
+ double low = entry.getDouble("low");
+ long timestamp = entry.getLong("timestamp");
+ int color = entry.getInt("color", 0);
+ bgDataList.add(new BgWatchData(sgv, high, low, timestamp, color));
+ }
+ } else {
+ double sgv = dataMap.getDouble("sgvDouble");
+ double high = dataMap.getDouble("high");
+ double low = dataMap.getDouble("low");
+ long timestamp = dataMap.getLong("timestamp");
+ int color = dataMap.getInt("color", 0);
+
+ final int size = bgDataList.size();
+ if (size > 0) {
+ if (bgDataList.get(size - 1).timestamp == timestamp)
+ return; // Ignore duplicates.
+ }
+
+ bgDataList.add(new BgWatchData(sgv, high, low, timestamp, color));
+ }
+
+ for (int i = 0; i < bgDataList.size(); i++) {
+ if (bgDataList.get(i).timestamp < (System.currentTimeMillis() - (Constants.HOUR_IN_MS * 5))) {
+ bgDataList.remove(i); //Get rid of anything more than 5 hours old
+ break;
+ }
+ }
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/data/ListenerService.java b/wear/src/main/java/info/nightscout/androidaps/data/ListenerService.java
index 83c9ad58b3..7bd43a79e1 100644
--- a/wear/src/main/java/info/nightscout/androidaps/data/ListenerService.java
+++ b/wear/src/main/java/info/nightscout/androidaps/data/ListenerService.java
@@ -40,6 +40,7 @@ import info.nightscout.androidaps.interaction.AAPSPreferences;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interaction.actions.AcceptActivity;
import info.nightscout.androidaps.interaction.actions.CPPActivity;
+import info.nightscout.androidaps.interaction.utils.Persistence;
import info.nightscout.androidaps.interaction.utils.SafeParse;
import info.nightscout.androidaps.interaction.utils.WearUtil;
@@ -512,12 +513,14 @@ public class ListenerService extends WearableListenerService implements GoogleAp
Intent messageIntent = new Intent();
messageIntent.setAction(Intent.ACTION_SEND);
messageIntent.putExtra("status", dataMap.toBundle());
+ Persistence.storeDataMap(DisplayRawData.STATUS_PERSISTENCE_KEY, dataMap);
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
} else if (path.equals(BASAL_DATA_PATH)){
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
Intent messageIntent = new Intent();
messageIntent.setAction(Intent.ACTION_SEND);
messageIntent.putExtra("basals", dataMap.toBundle());
+ Persistence.storeDataMap(DisplayRawData.BASALS_PERSISTENCE_KEY, dataMap);
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
} else if (path.equals(NEW_PREFERENCES_PATH)){
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
@@ -541,6 +544,7 @@ public class ListenerService extends WearableListenerService implements GoogleAp
Intent messageIntent = new Intent();
messageIntent.setAction(Intent.ACTION_SEND);
messageIntent.putExtra("data", dataMap.toBundle());
+ Persistence.storeDataMap(DisplayRawData.DATA_PERSISTENCE_KEY, dataMap);
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
}
}
diff --git a/wear/src/main/java/info/nightscout/androidaps/interaction/utils/Constants.java b/wear/src/main/java/info/nightscout/androidaps/interaction/utils/Constants.java
new file mode 100644
index 0000000000..2af3ef34b6
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/interaction/utils/Constants.java
@@ -0,0 +1,14 @@
+package info.nightscout.androidaps.interaction.utils;
+
+public class Constants {
+
+ public static final long SECOND_IN_MS = 1000;
+ public static final long MINUTE_IN_MS = 60000;
+ public static final long HOUR_IN_MS = 3600000;
+ public static final long DAY_IN_MS = 86400000;
+ public static final long WEEK_IN_MS = DAY_IN_MS * 7;
+ public static final long MONTH_IN_MS = DAY_IN_MS * 30;
+
+ public static final long STALE_MS = Constants.MINUTE_IN_MS * 12;
+
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/interaction/utils/DisplayFormat.java b/wear/src/main/java/info/nightscout/androidaps/interaction/utils/DisplayFormat.java
new file mode 100644
index 0000000000..366ca28eed
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/interaction/utils/DisplayFormat.java
@@ -0,0 +1,129 @@
+package info.nightscout.androidaps.interaction.utils;
+
+import android.util.Pair;
+
+import info.nightscout.androidaps.aaps;
+import info.nightscout.androidaps.data.DisplayRawData;
+
+public class DisplayFormat {
+
+ /**
+ * Maximal lengths of fields/labels shown in complications
+ */
+ public static final int MAX_LONG_FIELD = 22; // this is empirical, above that many watch faces start to ellipsize
+ public static final int MAX_SHORT_FIELD = 7; // according to Wear OS docs for TYPE_SHORT_TEXT
+ public static final int MIN_COB_FIELD = 3; // since carbs are 0..99g
+ public static final int MIN_IOB_FIELD = 3; // IoB can range from like .1U to 99U
+
+ public static String deltaSymbol() {
+ return aaps.areComplicationsUnicode() ? "\u0394" : "";
+ }
+
+ public static String verticalSeparatorSymbol() {
+ return aaps.areComplicationsUnicode() ? "\u205E" : "|";
+ }
+
+ public static String basalRateSymbol() {
+ return aaps.areComplicationsUnicode() ? "\u238D\u2006" : "";
+ }
+
+ public static String shortTimeSince(final long refTime) {
+
+ long deltaTimeMs = WearUtil.msSince(refTime);
+
+ if (deltaTimeMs < Constants.MINUTE_IN_MS) {
+ return "0'";
+ } else if (deltaTimeMs < Constants.HOUR_IN_MS) {
+ int minutes = (int) (deltaTimeMs / Constants.MINUTE_IN_MS);
+ return minutes + "'";
+ } else if (deltaTimeMs < Constants.DAY_IN_MS) {
+ int hours = (int) (deltaTimeMs / Constants.HOUR_IN_MS);
+ return hours + "h";
+ } else {
+ int days = (int) (deltaTimeMs / Constants.DAY_IN_MS);
+ if (days < 7) {
+ return days + "d";
+ } else {
+ int weeks = days / 7;
+ return weeks + "d";
+ }
+ }
+ }
+
+ public static String shortTrend(final DisplayRawData raw) {
+ String minutes = shortTimeSince(raw.datetime);
+ String delta = (new SmallestDoubleString(raw.sDelta)).minimise(MAX_SHORT_FIELD-1);
+
+ if (minutes.length() + delta.length() + 1 < MAX_SHORT_FIELD) {
+ delta = deltaSymbol() + delta;
+ }
+
+ return minutes + " " + delta;
+ }
+
+ public static String longGlucoseLine(final DisplayRawData raw) {
+ return raw.sSgv + raw.sDirection + " " + deltaSymbol() + (new SmallestDoubleString(raw.sDelta)).minimise(8) + " (" + shortTimeSince(raw.datetime) + ")";
+ }
+
+ public static String longDetailsLine(final DisplayRawData raw) {
+
+ final String SEP_LONG = " " + verticalSeparatorSymbol() + " ";
+ final String SEP_SHORT = " " + verticalSeparatorSymbol() + " ";
+ final int SEP_SHORT_LEN = SEP_SHORT.length();
+ final String SEP_MIN = " ";
+
+ String line = raw.sCOB2 + SEP_LONG + raw.sIOB1 + SEP_LONG + basalRateSymbol()+raw.sBasalRate;
+ if (line.length() <= MAX_LONG_FIELD) {
+ return line;
+ }
+ line = raw.sCOB2 + SEP_SHORT + raw.sIOB1 + SEP_SHORT + raw.sBasalRate;
+ if (line.length() <= MAX_LONG_FIELD) {
+ return line;
+ }
+
+ int remainingMax = MAX_LONG_FIELD - (raw.sCOB2.length() + raw.sBasalRate.length() + SEP_SHORT_LEN*2);
+ final String smallestIoB = new SmallestDoubleString(raw.sIOB1, SmallestDoubleString.Units.USE).minimise(Math.max(MIN_IOB_FIELD, remainingMax));
+ line = raw.sCOB2 + SEP_SHORT + smallestIoB + SEP_SHORT + raw.sBasalRate;
+ if (line.length() <= MAX_LONG_FIELD) {
+ return line;
+ }
+
+ remainingMax = MAX_LONG_FIELD - (smallestIoB.length() + raw.sBasalRate.length() + SEP_SHORT_LEN*2);
+ final String simplifiedCob = new SmallestDoubleString(raw.sCOB2, SmallestDoubleString.Units.USE).minimise(Math.max(MIN_COB_FIELD, remainingMax));
+
+ line = simplifiedCob + SEP_SHORT + smallestIoB + SEP_SHORT + raw.sBasalRate;
+ if (line.length() <= MAX_LONG_FIELD) {
+ return line;
+ }
+
+ line = simplifiedCob + SEP_MIN + smallestIoB + SEP_MIN + raw.sBasalRate;
+
+ return line;
+ }
+
+ public static Pair detailedIob(DisplayRawData raw) {
+ final String iob1 = new SmallestDoubleString(raw.sIOB1, SmallestDoubleString.Units.USE).minimise(MAX_SHORT_FIELD);
+ String iob2 = "";
+ if (raw.sIOB2.contains("|")) {
+
+ String[] iobs = raw.sIOB2.replace("(", "").replace(")", "").split("\\|");
+ if (iobs.length == 2) {
+ final String iobBolus = new SmallestDoubleString(iobs[0]).minimise(MIN_IOB_FIELD);
+ final String iobBasal = new SmallestDoubleString(iobs[1]).minimise((MAX_SHORT_FIELD-1) - Math.max(MIN_IOB_FIELD, iobBolus.length()));
+ iob2 = iobBolus+" "+iobBasal;
+ }
+ }
+ return Pair.create(iob1, iob2);
+ }
+
+ public static Pair detailedCob(final DisplayRawData raw) {
+ SmallestDoubleString cobMini = new SmallestDoubleString(raw.sCOB2, SmallestDoubleString.Units.USE);
+
+ String cob2 = "";
+ if (cobMini.getExtra().length() > 0) {
+ cob2 = cobMini.getExtra() + cobMini.getUnits();
+ }
+ final String cob1 = cobMini.minimise(MAX_SHORT_FIELD);
+ return Pair.create(cob1, cob2);
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/interaction/utils/Inevitable.java b/wear/src/main/java/info/nightscout/androidaps/interaction/utils/Inevitable.java
new file mode 100644
index 0000000000..21944da9c7
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/interaction/utils/Inevitable.java
@@ -0,0 +1,117 @@
+package info.nightscout.androidaps.interaction.utils;
+
+import android.os.PowerManager;
+import android.util.Log;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Created for xDrip by jamorham on 07/03/2018
+ * Adapted for AAPS by dlvoy on 2019-11-11
+ *
+ * Tasks which are fired from events can be scheduled here and only execute when they become idle
+ * and are not being rescheduled within their wait window.
+ *
+ */
+
+public class Inevitable {
+
+ private static final String TAG = Inevitable.class.getSimpleName();
+ private static final int MAX_QUEUE_TIME = (int) Constants.MINUTE_IN_MS * 6;
+ private static final boolean d = true;
+
+ private static final ConcurrentHashMap tasks = new ConcurrentHashMap<>();
+
+ public static synchronized void task(final String id, long idle_for, Runnable runnable) {
+ if (idle_for > MAX_QUEUE_TIME) {
+ throw new RuntimeException(id + " Requested time: " + idle_for + " beyond max queue time");
+ }
+ final Task task = tasks.get(id);
+ if (task != null) {
+ // if it already exists then extend the time
+ task.extendTime(idle_for);
+
+ if (d)
+ Log.d(TAG, "Extending time for: " + id + " to " + WearUtil.dateTimeText(task.when));
+ } else {
+ // otherwise create new task
+ if (runnable == null) return; // extension only if already exists
+ tasks.put(id, new Task(id, idle_for, runnable));
+
+ if (d) {
+ Log.d(TAG, "Creating task: " + id + " due: " + WearUtil.dateTimeText(tasks.get(id).when));
+ }
+
+ // create a thread to wait and execute in background
+ final Thread t = new Thread(() -> {
+ final PowerManager.WakeLock wl = WearUtil.getWakeLock(id, MAX_QUEUE_TIME + 5000);
+ try {
+ boolean running = true;
+ // wait for task to be due or killed
+ while (running) {
+ WearUtil.threadSleep(500);
+ final Task thisTask = tasks.get(id);
+ running = thisTask != null && !thisTask.poll();
+ }
+ } finally {
+ WearUtil.releaseWakeLock(wl);
+ }
+ });
+ t.setPriority(Thread.MIN_PRIORITY);
+ //t.setDaemon(true);
+ t.start();
+ }
+ }
+
+ public static synchronized void stackableTask(String id, long idle_for, Runnable runnable) {
+ int stack = 0;
+ while (tasks.get(id = id + "-" + stack) != null) {
+ stack++;
+ }
+ if (stack > 0) {
+ Log.d(TAG, "Task stacked to: " + id);
+ }
+ task(id, idle_for, runnable);
+ }
+
+ public static void kill(final String id) {
+ tasks.remove(id);
+ }
+
+ public static boolean waiting(final String id) {
+ return tasks.containsKey(id);
+ }
+
+ private static class Task {
+ private long when;
+ private final Runnable what;
+ private final String id;
+
+ Task(String id, long offset, Runnable what) {
+ this.what = what;
+ this.id = id;
+ extendTime(offset);
+ }
+
+ public void extendTime(long offset) {
+ this.when = WearUtil.timestamp() + offset;
+ }
+
+ public boolean poll() {
+ final long till = WearUtil.msTill(when);
+ if (till < 1) {
+ if (d) Log.d(TAG, "Executing task! " + this.id);
+ tasks.remove(this.id); // early remove to allow overlapping scheduling
+ what.run();
+ return true;
+ } else if (till > MAX_QUEUE_TIME) {
+ Log.wtf(TAG, "Task: " + this.id + " In queue too long: " + till);
+ tasks.remove(this.id);
+ return true;
+ }
+ return false;
+ }
+
+ }
+
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/interaction/utils/Persistence.java b/wear/src/main/java/info/nightscout/androidaps/interaction/utils/Persistence.java
new file mode 100644
index 0000000000..805aa5aafa
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/interaction/utils/Persistence.java
@@ -0,0 +1,94 @@
+package info.nightscout.androidaps.interaction.utils;
+
+import android.content.SharedPreferences;
+import android.util.Base64;
+
+import com.google.android.gms.wearable.DataMap;
+
+import java.util.Set;
+
+import info.nightscout.androidaps.aaps;
+
+/**
+ * Created by dlvoy on 2019-11-12
+ */
+public class Persistence {
+
+ final SharedPreferences preferences;
+ public static final String COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY =
+ "info.nightscout.androidaps.complications.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY";
+
+ public Persistence() {
+ preferences = aaps.getAppContext().getSharedPreferences(COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0);
+ }
+
+ public DataMap getDataMap(String key) {
+ if (preferences.contains("raw_data")) {
+ final String rawB64Data = preferences.getString(key, null);
+ byte[] rawData = Base64.decode(rawB64Data, Base64.DEFAULT);
+ try {
+ DataMap dataMap = DataMap.fromByteArray(rawData);
+ return dataMap;
+ } catch (IllegalArgumentException ex) {
+
+ }
+ }
+ return null;
+ }
+
+ public void putDataMap(String key, DataMap dataMap) {
+ preferences.edit().putString(key, Base64.encodeToString(dataMap.toByteArray(), Base64.DEFAULT)).apply();
+ }
+
+ public String getString(String key, String defaultValue) {
+ return preferences.getString(key, defaultValue);
+ }
+
+ public void putString(String key, String value) {
+ preferences.edit().putString(key, value).apply();
+ }
+
+ public boolean getBoolean(String key, boolean defaultValue) {
+ return preferences.getBoolean(key, defaultValue);
+ }
+
+ public void putBoolean(String key, boolean value) {
+ preferences.edit().putBoolean(key, value).apply();
+ }
+
+ public long whenDataUpdated() {
+ return preferences.getLong("data_updated_at", 0);
+ }
+
+ private void markDataUpdated() {
+ preferences.edit().putLong("data_updated_at", WearUtil.timestamp()).apply();
+ }
+
+ public Set getSetOf(String key) {
+ return WearUtil.explodeSet(getString(key, ""), "|");
+ }
+
+ public void addToSet(String key, String value) {
+ final Set set = WearUtil.explodeSet(getString(key, ""), "|");
+ set.add(value);
+ putString(key, WearUtil.joinSet(set, "|"));
+ }
+
+ public void removeFromSet(String key, String value) {
+ final Set set = WearUtil.explodeSet(getString(key, ""), "|");
+ set.remove(value);
+ putString(key, WearUtil.joinSet(set, "|"));
+ }
+
+ public static void storeDataMap(String key, DataMap dataMap) {
+ Persistence p = new Persistence();
+ p.putDataMap(key, dataMap);
+ p.markDataUpdated();
+ }
+
+ public static Set setOf(String key) {
+ Persistence p = new Persistence();
+ return p.getSetOf(key);
+ }
+
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/interaction/utils/SmallestDoubleString.java b/wear/src/main/java/info/nightscout/androidaps/interaction/utils/SmallestDoubleString.java
new file mode 100644
index 0000000000..5202daf8e4
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/interaction/utils/SmallestDoubleString.java
@@ -0,0 +1,130 @@
+package info.nightscout.androidaps.interaction.utils;
+
+import java.math.RoundingMode;
+import java.text.DecimalFormat;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Helper to minimise various floating point values, with or without unit, to fit into specified
+ * and limited size, scarifying precision (rounding up) and extra characters like leading zero,
+ * following zero(s) in fractional part, extra plus sign etc.
+ *
+ * Created by dlvoy on 2019-11-12
+ */
+public class SmallestDoubleString {
+
+ private String sign = "";
+ private String decimal = "";
+ private String separator = "";
+ private String fractional = "";
+ private String extra = "";
+ private String units = "";
+
+ private final Units withUnits;
+
+ public enum Units {
+ SKIP,
+ USE
+ }
+
+ private static Pattern pattern = Pattern.compile("^([+-]?)([0-9]*)([,.]?)([0-9]*)(\\([^)]*\\))?(.*?)$", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE );
+
+ public SmallestDoubleString(String inputString) {
+ this(inputString, Units.SKIP);
+ }
+
+ public SmallestDoubleString(String inputString, Units withUnits) {
+ Matcher matcher = pattern.matcher(inputString);
+ matcher.matches();
+
+ sign = matcher.group(1);
+ decimal = matcher.group(2);
+ separator = matcher.group(3);
+ fractional = matcher.group(4);
+ units = matcher.group(6);
+
+ if (fractional == null || fractional.length() == 0) {
+ separator = "";
+ fractional = "";
+ }
+ if (decimal == null || decimal.length() == 0) {
+ decimal = "";
+ }
+ if (separator == null || separator.length() == 0) {
+ separator = "";
+ }
+ if (sign == null || sign.length() == 0) {
+ sign = "";
+ }
+
+ final String extraCandidate = matcher.group(5);
+ if (extraCandidate != null && extraCandidate.length() > 2) {
+ extra = extraCandidate.substring(1, extraCandidate.length()-1);
+ }
+
+ if (units != null) {
+ units = units.trim();
+ }
+
+ this.withUnits = withUnits;
+ }
+
+ public String minimise(int maxSize) {
+ if (Integer.parseInt("0"+fractional) == 0) {
+ separator = "";
+ fractional = "";
+ }
+ if (Integer.parseInt("0"+decimal) == 0 && (fractional.length() >0)) {
+ decimal = "";
+ }
+ if (currentLen() <= maxSize)
+ return toString();
+
+ if (sign.equals("+")) {
+ sign = "";
+ }
+ if (currentLen() <= maxSize) {
+ return toString();
+ }
+
+ while ((fractional.length() > 1)&&(fractional.charAt(fractional.length()-1) == '0')) {
+ fractional = fractional.substring(0, fractional.length()-1);
+ }
+ if (currentLen() <= maxSize) {
+ return toString();
+ }
+
+ if ((fractional.length() > 0)&&(decimal.length() > 0)) {
+ int remainingForFraction = maxSize-currentLen()+fractional.length();
+ String formatCandidate = "#";
+ if (remainingForFraction>=1) {
+ formatCandidate = "#."+("#######".substring(0, remainingForFraction));
+ }
+ DecimalFormat df = new DecimalFormat(formatCandidate);
+ df.setRoundingMode(RoundingMode.HALF_UP);
+
+ return sign + df.format(Double.parseDouble(decimal+"."+fractional)).replace(".", separator) +
+ ((withUnits == Units.USE) ? units : "");
+ }
+ return toString();
+ }
+
+ private int currentLen() {
+ return sign.length() + decimal.length() + separator.length() + fractional.length() +
+ ((withUnits == Units.USE) ? units.length() : 0);
+ }
+
+ public String toString() {
+ return sign+decimal+separator+fractional +
+ ((withUnits == Units.USE) ? units : "");
+ }
+
+ public String getExtra() {
+ return extra;
+ }
+
+ public String getUnits() { return units; }
+
+
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/interaction/utils/WearUtil.java b/wear/src/main/java/info/nightscout/androidaps/interaction/utils/WearUtil.java
index ca63749888..2a400b4fa0 100644
--- a/wear/src/main/java/info/nightscout/androidaps/interaction/utils/WearUtil.java
+++ b/wear/src/main/java/info/nightscout/androidaps/interaction/utils/WearUtil.java
@@ -1,19 +1,127 @@
package info.nightscout.androidaps.interaction.utils;
-import java.time.LocalDateTime;
+import android.content.Context;
+import android.content.Intent;
+import android.os.PowerManager;
+import android.util.Log;
+
import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import info.nightscout.androidaps.aaps;
+import info.nightscout.androidaps.data.DisplayRawData;
/**
* Created by andy on 3/5/19.
+ * Adapted by dlvoy on 2019-11-06 using code from jamorham JoH class
*/
public class WearUtil {
+ private final static boolean debug_wakelocks = false;
+ private static final Map rateLimits = new HashMap();
+ private static final String TAG = WearUtil.class.getName();
+
+ //==============================================================================================
+ // Time related util methods
+ //==============================================================================================
public static String dateTimeText(long timeInMs) {
Date d = new Date(timeInMs);
return "" + d.getDay() + "." + d.getMonth() + "." + d.getYear() + " " + d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds();
}
+ public static long timestamp() {
+ return System.currentTimeMillis();
+ }
+ public static long msSince(long when) {
+ return (timestamp() - when);
+ }
+
+ public static long msTill(long when) {
+ return (when - timestamp());
+ }
+
+ //==============================================================================================
+ // Thread and power management utils
+ //==============================================================================================
+
+ // return true if below rate limit
+ public static synchronized boolean rateLimit(String name, int seconds) {
+ // check if over limit
+ if ((rateLimits.containsKey(name)) && (timestamp() - rateLimits.get(name) < (seconds * 1000))) {
+ Log.d(TAG, name + " rate limited: " + seconds + " seconds");
+ return false;
+ }
+ // not over limit
+ rateLimits.put(name, timestamp());
+ return true;
+ }
+
+ public static PowerManager.WakeLock getWakeLock(final String name, int millis) {
+ final PowerManager pm = (PowerManager) aaps.getAppContext().getSystemService(Context.POWER_SERVICE);
+ PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AAPS::"+name);
+ wl.acquire(millis);
+ if (debug_wakelocks) Log.d(TAG, "getWakeLock: " + name + " " + wl.toString());
+ return wl;
+ }
+
+ public static void releaseWakeLock(PowerManager.WakeLock wl) {
+ if (debug_wakelocks) Log.d(TAG, "releaseWakeLock: " + wl.toString());
+ if (wl == null) return;
+ if (wl.isHeld()) wl.release();
+ }
+
+ public static void startActivity(Class c) {
+ aaps.getAppContext().startActivity(getStartActivityIntent(c));
+ }
+
+
+ public static Intent getStartActivityIntent(Class c) {
+ return new Intent(aaps.getAppContext(), c).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+
+
+
+ public static void threadSleep(long millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ //
+ }
+ }
+
+ public static String joinSet(Set set, String separator) {
+ StringBuilder sb = new StringBuilder();
+ int i = 0;
+ for (String item : set) {
+ final String itemToAdd = item.trim();
+ if (itemToAdd.length() > 0) {
+ if (i > 0) {
+ sb.append(separator);
+ }
+ i++;
+ sb.append(itemToAdd);
+ }
+ }
+ return sb.toString();
+ }
+
+ public static Set explodeSet(String joined, String separator) {
+ // special RegEx literal \\Q starts sequence we escape, \\E ends is
+ // we use it to escape separator for use in RegEx
+ String[] items = joined.split("\\Q"+separator+"\\E");
+ Set set = new HashSet<>();
+ for (String item : items) {
+ final String itemToAdd = item.trim();
+ if (itemToAdd.length() > 0) {
+ set.add(itemToAdd);
+ }
+ }
+ return set;
+ }
}
diff --git a/wear/src/main/java/info/nightscout/androidaps/watchfaces/BaseWatchFace.java b/wear/src/main/java/info/nightscout/androidaps/watchfaces/BaseWatchFace.java
index 229eb64f1b..222f1eda6e 100644
--- a/wear/src/main/java/info/nightscout/androidaps/watchfaces/BaseWatchFace.java
+++ b/wear/src/main/java/info/nightscout/androidaps/watchfaces/BaseWatchFace.java
@@ -10,7 +10,6 @@ import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
-import android.os.Bundle;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
@@ -33,20 +32,18 @@ import com.ustwo.clockwise.common.WatchFaceTime;
import com.ustwo.clockwise.common.WatchShape;
import java.text.SimpleDateFormat;
-import java.util.ArrayList;
import java.util.Date;
-import info.nightscout.androidaps.data.BasalWatchData;
-import info.nightscout.androidaps.data.BgWatchData;
-import info.nightscout.androidaps.data.BolusWatchData;
+import info.nightscout.androidaps.complications.BaseComplicationProviderService;
+import info.nightscout.androidaps.data.DisplayRawData;
import info.nightscout.androidaps.data.ListenerService;
import info.nightscout.androidaps.R;
-import info.nightscout.androidaps.data.TempWatchData;
import lecho.lib.hellocharts.view.LineChartView;
/**
* Created by emmablack on 12/29/14.
* Updated by andrew-warrington on 02-Jan-2018.
+ * Refactored by dlvoy on 2019-11-2019
*/
public abstract class BaseWatchFace extends WatchFace implements SharedPreferences.OnSharedPreferenceChangeListener {
@@ -54,13 +51,10 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
public static final long[] vibratePattern = {0,400,300,400,300,400};
public TextView mTime, mSgv, mDirection, mTimestamp, mUploaderBattery, mRigBattery, mDelta, mAvgDelta, mStatus, mBasalRate, mIOB1, mIOB2, mCOB1, mCOB2, mBgi, mLoop, mDay, mMonth, isAAPSv2, mHighLight, mLowLight;
public ImageView mGlucoseDial, mDeltaGauge, mHourHand, mMinuteHand;
- public long datetime;
public RelativeLayout mRelativeLayout;
public LinearLayout mLinearLayout, mLinearLayout2, mDate, mChartTap, mMainMenuTap;
- public long sgvLevel = 0;
public int ageLevel = 1;
public int loopLevel = 1;
- public int batteryLevel = 1;
public int highColor = Color.YELLOW;
public int lowColor = Color.RED;
public int midColor = Color.WHITE;
@@ -74,11 +68,9 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
public int pointSize = 2;
public BgGraphBuilder bgGraphBuilder;
public LineChartView chart;
- public ArrayList bgDataList = new ArrayList<>();
- public ArrayList tempWatchDataList = new ArrayList<>();
- public ArrayList basalWatchDataList = new ArrayList<>();
- public ArrayList bolusWatchDataList = new ArrayList<>();
- public ArrayList predictionList = new ArrayList<>();
+
+
+ public DisplayRawData rawData = new DisplayRawData();
public PowerManager.WakeLock wakeLock;
// related endTime manual layout
@@ -90,26 +82,9 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
protected SharedPreferences sharedPrefs;
- public boolean detailedIOB = false;
- public boolean showBGI = false;
public boolean forceSquareCanvas = false; //set to true by the Steampunk watch face.
- public long openApsStatus;
- public String externalStatusString = "no status";
- public String sSgv = "---";
- public String sDirection = "--";
- public String sUploaderBattery = "--";
- public String sRigBattery = "--";
- public String sDelta = "--";
- public String sAvgDelta = "--";
- public String sBasalRate = "-.--U/h";
- public String sIOB1 = "IOB";
- public String sIOB2 = "-.--";
- public String sCOB1 = "Carb";
- public String sCOB2 = "--g";
- public String sBgi = "--";
public String sMinute = "0";
public String sHour = "0";
- public String sUnits = "-";
@Override
public void onCreate() {
@@ -126,6 +101,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
}
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
sharedPrefs.registerOnSharedPreferenceChangeListener(this);
+
+ BaseComplicationProviderService.turnOff();
}
@Override
@@ -197,11 +174,11 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
}
public double timeSince() {
- return System.currentTimeMillis() - datetime;
+ return System.currentTimeMillis() - rawData.datetime;
}
public String readingAge(boolean shortString) {
- if (datetime == 0) { return shortString?"--'":"-- Minute ago"; }
+ if (rawData.datetime == 0) { return shortString?"--'":"-- Minute ago"; }
int minutesAgo = (int) Math.floor(timeSince()/(1000*60));
if (minutesAgo == 1) {
return minutesAgo + (shortString?"'":" Minute ago");
@@ -266,50 +243,20 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
@Override
public void onReceive(Context context, Intent intent) {
- Bundle bundle = intent.getBundleExtra("data");
- if (layoutSet && bundle != null) {
- DataMap dataMap = DataMap.fromBundle(bundle);
- wakeLock.acquire(50);
- sgvLevel = dataMap.getLong("sgvLevel");
- datetime = dataMap.getLong("timestamp");
- sSgv = dataMap.getString("sgvString");
- sDirection = dataMap.getString("slopeArrow");
- sDelta = dataMap.getString("delta");
- sAvgDelta = dataMap.getString("avgDelta");
- sUnits = dataMap.getString("glucoseUnits");
- if (chart != null) {
- addToWatchSet(dataMap);
+ if (layoutSet) {
+ final DataMap dataMap = rawData.updateDataFromMessage(intent, wakeLock);
+ if (chart != null && dataMap != null) {
+ rawData.addToWatchSet(dataMap);
setupCharts();
}
- }
-
- bundle = intent.getBundleExtra("status");
- if (layoutSet && bundle != null) {
- DataMap dataMap = DataMap.fromBundle(bundle);
- wakeLock.acquire(50);
- sBasalRate = dataMap.getString("currentBasal");
- sUploaderBattery = dataMap.getString("battery");
- sRigBattery = dataMap.getString("rigBattery");
- detailedIOB = dataMap.getBoolean("detailedIob");
- sIOB1 = dataMap.getString("iobSum") + "U";
- sIOB2 = dataMap.getString("iobDetail");
- sCOB1 = "Carb";
- sCOB2 = dataMap.getString("cob");
- sBgi = dataMap.getString("bgi");
- showBGI = dataMap.getBoolean("showBgi");
- externalStatusString = dataMap.getString("externalStatusString");
- batteryLevel = dataMap.getInt("batteryLevel");
- openApsStatus = dataMap.getLong("openApsStatus");
+ rawData.updateStatusFromMessage(intent, wakeLock);
}
setDataFields();
setColor();
- bundle = intent.getBundleExtra("basals");
- if (layoutSet && bundle != null) {
- DataMap dataMap = DataMap.fromBundle(bundle);
- wakeLock.acquire(500);
- loadBasalsAndTemps(dataMap);
+ if (layoutSet) {
+ rawData.updateBasalsFromMessage(intent, wakeLock);
}
mRelativeLayout.measure(specW, specH);
@@ -328,7 +275,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
if (mSgv != null) {
if (sharedPrefs.getBoolean("showBG", true)) {
- mSgv.setText(sSgv);
+ mSgv.setText(rawData.sSgv);
mSgv.setVisibility(View.VISIBLE);
} else {
//leave the textview there but invisible, as a height holder for the empty space above the white line
@@ -341,7 +288,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
if (mDirection != null) {
if (sharedPrefs.getBoolean("show_direction", true)) {
- mDirection.setText(sDirection);
+ mDirection.setText(rawData.sDirection);
mDirection.setVisibility(View.VISIBLE);
} else {
mDirection.setVisibility(View.GONE);
@@ -350,7 +297,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
if (mDelta != null) {
if (sharedPrefs.getBoolean("showDelta", true)) {
- mDelta.setText(sDelta);
+ mDelta.setText(rawData.sDelta);
mDelta.setVisibility(View.VISIBLE);
} else {
mDelta.setVisibility(View.GONE);
@@ -359,7 +306,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
if (mAvgDelta != null) {
if (sharedPrefs.getBoolean("showAvgDelta", true)) {
- mAvgDelta.setText(sAvgDelta);
+ mAvgDelta.setText(rawData.sAvgDelta);
mAvgDelta.setVisibility(View.VISIBLE);
} else {
mAvgDelta.setVisibility(View.GONE);
@@ -367,7 +314,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
}
if (mCOB1 != null && mCOB2 != null) {
- mCOB2.setText(sCOB2);
+ mCOB2.setText(rawData.sCOB2);
if (sharedPrefs.getBoolean("show_cob", true)) {
mCOB1.setVisibility(View.VISIBLE);
mCOB2.setVisibility(View.VISIBLE);
@@ -377,7 +324,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
}
//deal with cases where there is only the value shown for COB, and not the label
} else if (mCOB2 != null) {
- mCOB2.setText(sCOB2);
+ mCOB2.setText(rawData.sCOB2);
if (sharedPrefs.getBoolean("show_cob", true)) {
mCOB2.setVisibility(View.VISIBLE);
} else {
@@ -389,12 +336,12 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
if (sharedPrefs.getBoolean("show_iob", true)) {
mIOB1.setVisibility(View.VISIBLE);
mIOB2.setVisibility(View.VISIBLE);
- if (detailedIOB) {
- mIOB1.setText(sIOB1);
- mIOB2.setText(sIOB2);
+ if (rawData.detailedIOB) {
+ mIOB1.setText(rawData.sIOB1);
+ mIOB2.setText(rawData.sIOB2);
} else {
mIOB1.setText("IOB");
- mIOB2.setText(sIOB1);
+ mIOB2.setText(rawData.sIOB1);
}
} else {
mIOB1.setVisibility(View.GONE);
@@ -404,10 +351,10 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
} else if (mIOB2 != null) {
if (sharedPrefs.getBoolean("show_iob", true)) {
mIOB2.setVisibility(View.VISIBLE);
- if (detailedIOB) {
- mIOB2.setText(sIOB2);
+ if (rawData.detailedIOB) {
+ mIOB2.setText(rawData.sIOB2);
} else {
- mIOB2.setText(sIOB1);
+ mIOB2.setText(rawData.sIOB1);
}
} else {
mIOB2.setText("");
@@ -434,13 +381,13 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
if (mUploaderBattery != null) {
if (sharedPrefs.getBoolean("show_uploader_battery", true)) {
if (isAAPSv2 != null) {
- mUploaderBattery.setText(sUploaderBattery + "%");
+ mUploaderBattery.setText(rawData.sUploaderBattery + "%");
mUploaderBattery.setVisibility(View.VISIBLE);
} else {
if (sharedPrefs.getBoolean("showExternalStatus", true)) {
- mUploaderBattery.setText("U: " + sUploaderBattery + "%");
+ mUploaderBattery.setText("U: " + rawData.sUploaderBattery + "%");
} else {
- mUploaderBattery.setText("Uploader: " + sUploaderBattery + "%");
+ mUploaderBattery.setText("Uploader: " + rawData.sUploaderBattery + "%");
}
}
} else {
@@ -450,7 +397,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
if (mRigBattery != null) {
if (sharedPrefs.getBoolean("show_rig_battery", false)) {
- mRigBattery.setText(sRigBattery);
+ mRigBattery.setText(rawData.sRigBattery);
mRigBattery.setVisibility(View.VISIBLE);
} else {
mRigBattery.setVisibility(View.GONE);
@@ -459,7 +406,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
if (mBasalRate != null) {
if (sharedPrefs.getBoolean("show_temp_basal", true)) {
- mBasalRate.setText(sBasalRate);
+ mBasalRate.setText(rawData.sBasalRate);
mBasalRate.setVisibility(View.VISIBLE);
} else {
mBasalRate.setVisibility(View.GONE);
@@ -467,8 +414,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
}
if (mBgi != null) {
- if (showBGI) {
- mBgi.setText(sBgi);
+ if (rawData.showBGI) {
+ mBgi.setText(rawData.sBgi);
mBgi.setVisibility(View.VISIBLE);
} else {
mBgi.setVisibility(View.GONE);
@@ -477,7 +424,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
if (mStatus != null) {
if (sharedPrefs.getBoolean("showExternalStatus", true)) {
- mStatus.setText(externalStatusString);
+ mStatus.setText(rawData.externalStatusString);
mStatus.setVisibility(View.VISIBLE);
} else {
mStatus.setVisibility(View.GONE);
@@ -487,8 +434,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
if (mLoop != null) {
if (sharedPrefs.getBoolean("showExternalStatus", true)) {
mLoop.setVisibility(View.VISIBLE);
- if (openApsStatus != -1) {
- int mins = (int) ((System.currentTimeMillis() - openApsStatus) / 1000 / 60);
+ if (rawData.openApsStatus != -1) {
+ int mins = (int) ((System.currentTimeMillis() - rawData.openApsStatus) / 1000 / 60);
mLoop.setText(mins + "'");
if (mins > 14) {
loopLevel = 0;
@@ -594,50 +541,13 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
}
}
- public void addToWatchSet(DataMap dataMap) {
-
- ArrayList entries = dataMap.getDataMapArrayList("entries");
- if (entries != null) {
- bgDataList = new ArrayList();
- for (DataMap entry : entries) {
- double sgv = entry.getDouble("sgvDouble");
- double high = entry.getDouble("high");
- double low = entry.getDouble("low");
- long timestamp = entry.getLong("timestamp");
- int color = entry.getInt("color", 0);
- bgDataList.add(new BgWatchData(sgv, high, low, timestamp, color));
- }
- } else {
- double sgv = dataMap.getDouble("sgvDouble");
- double high = dataMap.getDouble("high");
- double low = dataMap.getDouble("low");
- long timestamp = dataMap.getLong("timestamp");
- int color = dataMap.getInt("color", 0);
-
- final int size = bgDataList.size();
- if (size > 0) {
- if (bgDataList.get(size - 1).timestamp == timestamp)
- return; // Ignore duplicates.
- }
-
- bgDataList.add(new BgWatchData(sgv, high, low, timestamp, color));
- }
-
- for (int i = 0; i < bgDataList.size(); i++) {
- if (bgDataList.get(i).timestamp < (System.currentTimeMillis() - (1000 * 60 * 60 * 5))) {
- bgDataList.remove(i); //Get rid of anything more than 5 hours old
- break;
- }
- }
- }
-
public void setupCharts() {
- if(bgDataList.size() > 0) { //Dont crash things just because we dont have values, people dont like crashy things
+ if(rawData.bgDataList.size() > 0) { //Dont crash things just because we dont have values, people dont like crashy things
int timeframe = Integer.parseInt(sharedPrefs.getString("chart_timeframe", "3"));
if (lowResMode) {
- bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), bgDataList, predictionList, tempWatchDataList, basalWatchDataList, bolusWatchDataList, pointSize, midColor, gridColor, basalBackgroundColor, basalCenterColor, bolusColor, Color.GREEN, timeframe);
+ bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), rawData, pointSize, midColor, gridColor, basalBackgroundColor, basalCenterColor, bolusColor, Color.GREEN, timeframe);
} else {
- bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), bgDataList,predictionList, tempWatchDataList, basalWatchDataList, bolusWatchDataList, pointSize, highColor, lowColor, midColor, gridColor, basalBackgroundColor, basalCenterColor, bolusColor, Color.GREEN, timeframe);
+ bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), rawData, pointSize, highColor, lowColor, midColor, gridColor, basalBackgroundColor, basalCenterColor, bolusColor, Color.GREEN, timeframe);
}
chart.setLineChartData(bgGraphBuilder.lineData());
@@ -646,54 +556,4 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferen
}
}
- private void loadBasalsAndTemps(DataMap dataMap) {
- ArrayList temps = dataMap.getDataMapArrayList("temps");
- if (temps != null) {
- tempWatchDataList = new ArrayList<>();
- for (DataMap temp : temps) {
- TempWatchData twd = new TempWatchData();
- twd.startTime = temp.getLong("starttime");
- twd.startBasal = temp.getDouble("startBasal");
- twd.endTime = temp.getLong("endtime");
- twd.endBasal = temp.getDouble("endbasal");
- twd.amount = temp.getDouble("amount");
- tempWatchDataList.add(twd);
- }
- }
- ArrayList basals = dataMap.getDataMapArrayList("basals");
- if (basals != null) {
- basalWatchDataList = new ArrayList<>();
- for (DataMap basal : basals) {
- BasalWatchData bwd = new BasalWatchData();
- bwd.startTime = basal.getLong("starttime");
- bwd.endTime = basal.getLong("endtime");
- bwd.amount = basal.getDouble("amount");
- basalWatchDataList.add(bwd);
- }
- }
- ArrayList boluses = dataMap.getDataMapArrayList("boluses");
- if (boluses != null) {
- bolusWatchDataList = new ArrayList<>();
- for (DataMap bolus : boluses) {
- BolusWatchData bwd = new BolusWatchData();
- bwd.date = bolus.getLong("date");
- bwd.bolus = bolus.getDouble("bolus");
- bwd.carbs = bolus.getDouble("carbs");
- bwd.isSMB = bolus.getBoolean("isSMB");
- bwd.isValid = bolus.getBoolean("isValid");
- bolusWatchDataList.add(bwd);
- }
- }
- ArrayList predictions = dataMap.getDataMapArrayList("predictions");
- if (boluses != null) {
- predictionList = new ArrayList<>();
- for (DataMap prediction : predictions) {
- BgWatchData bwd = new BgWatchData();
- bwd.timestamp = prediction.getLong("timestamp");
- bwd.sgv = prediction.getDouble("sgv");
- bwd.color = prediction.getInt("color");
- predictionList.add(bwd);
- }
- }
- }
}
diff --git a/wear/src/main/java/info/nightscout/androidaps/watchfaces/BgGraphBuilder.java b/wear/src/main/java/info/nightscout/androidaps/watchfaces/BgGraphBuilder.java
index 4a401489d9..b40e15cfd4 100644
--- a/wear/src/main/java/info/nightscout/androidaps/watchfaces/BgGraphBuilder.java
+++ b/wear/src/main/java/info/nightscout/androidaps/watchfaces/BgGraphBuilder.java
@@ -18,6 +18,7 @@ import java.util.TimeZone;
import info.nightscout.androidaps.data.BasalWatchData;
import info.nightscout.androidaps.data.BgWatchData;
import info.nightscout.androidaps.data.BolusWatchData;
+import info.nightscout.androidaps.data.DisplayRawData;
import info.nightscout.androidaps.data.TempWatchData;
import lecho.lib.hellocharts.model.Axis;
import lecho.lib.hellocharts.model.AxisValue;
@@ -115,6 +116,42 @@ public class BgGraphBuilder {
this.end_time = (predictionEndTime>end_time)?predictionEndTime:end_time;
}
+ public BgGraphBuilder(Context context, DisplayRawData raw, int aPointSize, int aHighColor, int aLowColor, int aMidColor, int gridColour, int basalBackgroundColor, int basalCenterColor, int bolusInvalidColor, int carbsColor, int timespan) {
+ this(context,
+ raw.bgDataList,
+ raw.predictionList,
+ raw.tempWatchDataList,
+ raw.basalWatchDataList,
+ raw.bolusWatchDataList,
+ aPointSize,
+ aHighColor,
+ aLowColor,
+ aMidColor,
+ gridColour,
+ basalBackgroundColor,
+ basalCenterColor,
+ bolusInvalidColor,
+ carbsColor,
+ timespan);
+ }
+
+ public BgGraphBuilder(Context context, DisplayRawData raw, int aPointSize, int aMidColor, int gridColour, int basalBackgroundColor, int basalCenterColor, int bolusInvalidColor, int carbsColor, int timespan) {
+ this(context,
+ raw.bgDataList,
+ raw.predictionList,
+ raw.tempWatchDataList,
+ raw.basalWatchDataList,
+ raw.bolusWatchDataList,
+ aPointSize,
+ aMidColor,
+ gridColour,
+ basalBackgroundColor,
+ basalCenterColor,
+ bolusInvalidColor,
+ carbsColor,
+ timespan);
+ }
+
public LineChartData lineData() {
LineChartData lineData = new LineChartData(defaultLines());
lineData.setAxisYLeft(yAxis());
diff --git a/wear/src/main/java/info/nightscout/androidaps/watchfaces/Cockpit.java b/wear/src/main/java/info/nightscout/androidaps/watchfaces/Cockpit.java
index b949e3832a..31d293929a 100644
--- a/wear/src/main/java/info/nightscout/androidaps/watchfaces/Cockpit.java
+++ b/wear/src/main/java/info/nightscout/androidaps/watchfaces/Cockpit.java
@@ -48,13 +48,13 @@ public class Cockpit extends BaseWatchFace {
setTextSizes();
if (mHighLight != null && mLowLight != null) {
- if (sgvLevel == 1) {
+ if (rawData.sgvLevel == 1) {
mHighLight.setBackgroundResource(R.drawable.airplane_led_yellow_lit);
mLowLight.setBackgroundResource(R.drawable.airplane_led_grey_unlit);
- } else if (sgvLevel == 0) {
+ } else if (rawData.sgvLevel == 0) {
mHighLight.setBackgroundResource(R.drawable.airplane_led_grey_unlit);
mLowLight.setBackgroundResource(R.drawable.airplane_led_grey_unlit);
- } else if (sgvLevel == -1) {
+ } else if (rawData.sgvLevel == -1) {
mHighLight.setBackgroundResource(R.drawable.airplane_led_grey_unlit);
mLowLight.setBackgroundResource(R.drawable.airplane_led_red_lit);
}
@@ -82,7 +82,7 @@ public class Cockpit extends BaseWatchFace {
protected void setTextSizes() {
if (mIOB2 != null) {
- if (detailedIOB) {
+ if (rawData.detailedIOB) {
if (bIsRound) {
mIOB2.setTextSize(10);
} else {
diff --git a/wear/src/main/java/info/nightscout/androidaps/watchfaces/Home.java b/wear/src/main/java/info/nightscout/androidaps/watchfaces/Home.java
index 430a3feb47..209e6214e7 100644
--- a/wear/src/main/java/info/nightscout/androidaps/watchfaces/Home.java
+++ b/wear/src/main/java/info/nightscout/androidaps/watchfaces/Home.java
@@ -68,15 +68,15 @@ public class Home extends BaseWatchFace {
mLinearLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_statusView));
mTime.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_mTime));
mRelativeLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_background));
- if (sgvLevel == 1) {
+ if (rawData.sgvLevel == 1) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
- } else if (sgvLevel == 0) {
+ } else if (rawData.sgvLevel == 0) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
- } else if (sgvLevel == -1) {
+ } else if (rawData.sgvLevel == -1) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
@@ -88,7 +88,7 @@ public class Home extends BaseWatchFace {
mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_TimestampOld));
}
- if (batteryLevel == 1) {
+ if (rawData.batteryLevel == 1) {
mUploaderBattery.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_uploaderBattery));
} else {
mUploaderBattery.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_uploaderBatteryEmpty));
@@ -133,15 +133,15 @@ public class Home extends BaseWatchFace {
if (getCurrentWatchMode() == WatchMode.INTERACTIVE) {
mLinearLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.light_stripe_background));
mRelativeLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.light_background));
- if (sgvLevel == 1) {
+ if (rawData.sgvLevel == 1) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
- } else if (sgvLevel == 0) {
+ } else if (rawData.sgvLevel == 0) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
- } else if (sgvLevel == -1) {
+ } else if (rawData.sgvLevel == -1) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
@@ -153,7 +153,7 @@ public class Home extends BaseWatchFace {
mTimestamp.setTextColor(Color.RED);
}
- if (batteryLevel == 1) {
+ if (rawData.batteryLevel == 1) {
mUploaderBattery.setTextColor(Color.WHITE);
} else {
mUploaderBattery.setTextColor(Color.RED);
diff --git a/wear/src/main/java/info/nightscout/androidaps/watchfaces/Home2.java b/wear/src/main/java/info/nightscout/androidaps/watchfaces/Home2.java
index 41c9fd3029..fbc69f3c1a 100644
--- a/wear/src/main/java/info/nightscout/androidaps/watchfaces/Home2.java
+++ b/wear/src/main/java/info/nightscout/androidaps/watchfaces/Home2.java
@@ -78,13 +78,13 @@ public class Home2 extends BaseWatchFace {
setTextSizes();
- if (sgvLevel == 1) {
+ if (rawData.sgvLevel == 1) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
- } else if (sgvLevel == 0) {
+ } else if (rawData.sgvLevel == 0) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
- } else if (sgvLevel == -1) {
+ } else if (rawData.sgvLevel == -1) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
}
@@ -95,7 +95,7 @@ public class Home2 extends BaseWatchFace {
mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_TimestampOld));
}
- if (batteryLevel == 1) {
+ if (rawData.batteryLevel == 1) {
mUploaderBattery.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_uploaderBattery));
} else {
mUploaderBattery.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_uploaderBatteryEmpty));
@@ -176,13 +176,13 @@ public class Home2 extends BaseWatchFace {
setTextSizes();
- if (sgvLevel == 1) {
+ if (rawData.sgvLevel == 1) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
- } else if (sgvLevel == 0) {
+ } else if (rawData.sgvLevel == 0) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
- } else if (sgvLevel == -1) {
+ } else if (rawData.sgvLevel == -1) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
}
@@ -193,7 +193,7 @@ public class Home2 extends BaseWatchFace {
mTimestamp.setTextColor(Color.RED);
}
- if (batteryLevel == 1) {
+ if (rawData.batteryLevel == 1) {
mUploaderBattery.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
} else {
mUploaderBattery.setTextColor(Color.RED);
@@ -229,7 +229,7 @@ public class Home2 extends BaseWatchFace {
if (mIOB1 != null && mIOB2 != null) {
- if (detailedIOB) {
+ if (rawData.detailedIOB) {
mIOB1.setTextSize(14);
mIOB2.setTextSize(10);
} else {
diff --git a/wear/src/main/java/info/nightscout/androidaps/watchfaces/LargeHome.java b/wear/src/main/java/info/nightscout/androidaps/watchfaces/LargeHome.java
index ffb8dce3ad..75b7d995dd 100644
--- a/wear/src/main/java/info/nightscout/androidaps/watchfaces/LargeHome.java
+++ b/wear/src/main/java/info/nightscout/androidaps/watchfaces/LargeHome.java
@@ -52,15 +52,15 @@ public class LargeHome extends BaseWatchFace {
mLinearLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_mLinearLayout));
mTime.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_mTime));
mRelativeLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_background));
- if (sgvLevel == 1) {
+ if (rawData.sgvLevel == 1) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
- } else if (sgvLevel == 0) {
+ } else if (rawData.sgvLevel == 0) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
- } else if (sgvLevel == -1) {
+ } else if (rawData.sgvLevel == -1) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
@@ -72,7 +72,7 @@ public class LargeHome extends BaseWatchFace {
mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_TimestampOld));
}
- if (batteryLevel == 1) {
+ if (rawData.batteryLevel == 1) {
mUploaderBattery.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_uploaderBattery));
} else {
mUploaderBattery.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_uploaderBatteryEmpty));
@@ -86,15 +86,15 @@ public class LargeHome extends BaseWatchFace {
if (getCurrentWatchMode() == WatchMode.INTERACTIVE) {
mLinearLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.light_stripe_background));
mRelativeLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.light_background));
- if (sgvLevel == 1) {
+ if (rawData.sgvLevel == 1) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
- } else if (sgvLevel == 0) {
+ } else if (rawData.sgvLevel == 0) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
- } else if (sgvLevel == -1) {
+ } else if (rawData.sgvLevel == -1) {
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
@@ -106,7 +106,7 @@ public class LargeHome extends BaseWatchFace {
mTimestamp.setTextColor(Color.RED);
}
- if (batteryLevel == 1) {
+ if (rawData.batteryLevel == 1) {
mUploaderBattery.setTextColor(Color.WHITE);
} else {
mUploaderBattery.setTextColor(Color.RED);
@@ -116,15 +116,15 @@ public class LargeHome extends BaseWatchFace {
} else {
mRelativeLayout.setBackgroundColor(Color.BLACK);
mLinearLayout.setBackgroundColor(Color.LTGRAY);
- if (sgvLevel == 1) {
+ if (rawData.sgvLevel == 1) {
mSgv.setTextColor(Color.YELLOW);
mDirection.setTextColor(Color.YELLOW);
mDelta.setTextColor(Color.YELLOW);
- } else if (sgvLevel == 0) {
+ } else if (rawData.sgvLevel == 0) {
mSgv.setTextColor(Color.WHITE);
mDirection.setTextColor(Color.WHITE);
mDelta.setTextColor(Color.WHITE);
- } else if (sgvLevel == -1) {
+ } else if (rawData.sgvLevel == -1) {
mSgv.setTextColor(Color.RED);
mDirection.setTextColor(Color.RED);
mDelta.setTextColor(Color.RED);
diff --git a/wear/src/main/java/info/nightscout/androidaps/watchfaces/Steampunk.java b/wear/src/main/java/info/nightscout/androidaps/watchfaces/Steampunk.java
index c42aff1518..a600290a04 100644
--- a/wear/src/main/java/info/nightscout/androidaps/watchfaces/Steampunk.java
+++ b/wear/src/main/java/info/nightscout/androidaps/watchfaces/Steampunk.java
@@ -83,24 +83,24 @@ public class Steampunk extends BaseWatchFace {
}
}
- if (!sSgv.equals("---")) {
+ if (!rawData.sSgv.equals("---")) {
float rotationAngle = 0f; //by default, show ? on the dial (? is at 0 degrees on the dial)
- if (!sUnits.equals("-")) {
+ if (!rawData.sUnits.equals("-")) {
//ensure the glucose dial is the correct units
- if (sUnits.equals("mmol")) {
+ if (rawData.sUnits.equals("mmol")) {
mGlucoseDial.setImageResource(R.drawable.steampunk_dial_mmol);
} else {
mGlucoseDial.setImageResource(R.drawable.steampunk_dial_mgdl);
}
//convert the Sgv to degrees of rotation
- if (sUnits.equals("mmol")) {
- rotationAngle = Float.valueOf(sSgv) * 18f; //convert to mg/dL, which is equivalent to degrees
+ if (rawData.sUnits.equals("mmol")) {
+ rotationAngle = Float.valueOf(rawData.sSgv) * 18f; //convert to mg/dL, which is equivalent to degrees
} else {
- rotationAngle = Float.valueOf(sSgv); //if glucose a value is received, use it to determine the amount of rotation of the dial.
+ rotationAngle = Float.valueOf(rawData.sSgv); //if glucose a value is received, use it to determine the amount of rotation of the dial.
}
}
@@ -122,36 +122,36 @@ public class Steampunk extends BaseWatchFace {
//set the delta gauge and rotate the delta pointer
float deltaIsNegative = 1f; //by default go clockwise
- if (!sAvgDelta.equals("--")) { //if a legitimate delta value is received, then...
- if (sAvgDelta.substring(0,1).equals("-")) deltaIsNegative = -1f; //if the delta is negative, go counter-clockwise
+ if (!rawData.sAvgDelta.equals("--")) { //if a legitimate delta value is received, then...
+ if (rawData.sAvgDelta.substring(0,1).equals("-")) deltaIsNegative = -1f; //if the delta is negative, go counter-clockwise
//ensure the delta gauge is the right units and granularity
- if (!sUnits.equals("-")) {
- if (sUnits.equals("mmol")) {
+ if (!rawData.sUnits.equals("-")) {
+ if (rawData.sUnits.equals("mmol")) {
if (sharedPrefs.getString("delta_granularity", "2").equals("1")) { //low
mLinearLayout.setBackgroundResource(R.drawable.steampunk_gauge_mmol_10);
- deltaRotationAngle = (Float.valueOf(sAvgDelta.substring(1)) * 30f); //get rid of the sign so it can be converted to float.
+ deltaRotationAngle = (Float.valueOf(rawData.sAvgDelta.substring(1)) * 30f); //get rid of the sign so it can be converted to float.
}
if (sharedPrefs.getString("delta_granularity", "2").equals("2")) { //medium
mLinearLayout.setBackgroundResource(R.drawable.steampunk_gauge_mmol_05);
- deltaRotationAngle = (Float.valueOf(sAvgDelta.substring(1)) * 60f); //get rid of the sign so it can be converted to float.
+ deltaRotationAngle = (Float.valueOf(rawData.sAvgDelta.substring(1)) * 60f); //get rid of the sign so it can be converted to float.
}
if (sharedPrefs.getString("delta_granularity", "2").equals("3")) { //high
mLinearLayout.setBackgroundResource(R.drawable.steampunk_gauge_mmol_03);
- deltaRotationAngle = (Float.valueOf(sAvgDelta.substring(1)) * 100f); //get rid of the sign so it can be converted to float.
+ deltaRotationAngle = (Float.valueOf(rawData.sAvgDelta.substring(1)) * 100f); //get rid of the sign so it can be converted to float.
}
} else {
if (sharedPrefs.getString("delta_granularity", "2").equals("1")) { //low
mLinearLayout.setBackgroundResource(R.drawable.steampunk_gauge_mgdl_20);
- deltaRotationAngle = (Float.valueOf(sAvgDelta.substring(1)) * 1.5f); //get rid of the sign so it can be converted to float.
+ deltaRotationAngle = (Float.valueOf(rawData.sAvgDelta.substring(1)) * 1.5f); //get rid of the sign so it can be converted to float.
}
if (sharedPrefs.getString("delta_granularity", "2").equals("2")) { //medium
mLinearLayout.setBackgroundResource(R.drawable.steampunk_gauge_mgdl_10);
- deltaRotationAngle = (Float.valueOf(sAvgDelta.substring(1)) * 3f); //get rid of the sign so it can be converted to float.
+ deltaRotationAngle = (Float.valueOf(rawData.sAvgDelta.substring(1)) * 3f); //get rid of the sign so it can be converted to float.
}
if (sharedPrefs.getString("delta_granularity", "2").equals("3")) { //high
mLinearLayout.setBackgroundResource(R.drawable.steampunk_gauge_mgdl_5);
- deltaRotationAngle = (Float.valueOf(sAvgDelta.substring(1)) * 6f); //get rid of the sign so it can be converted to float.
+ deltaRotationAngle = (Float.valueOf(rawData.sAvgDelta.substring(1)) * 6f); //get rid of the sign so it can be converted to float.
}
}
}
@@ -213,7 +213,7 @@ public class Steampunk extends BaseWatchFace {
//top row. large font unless text too big (i.e. detailedIOB)
mCOB2.setTextSize(fontLarge);
mBasalRate.setTextSize(fontLarge);
- if (sIOB2.length() < 7) {
+ if (rawData.sIOB2.length() < 7) {
mIOB2.setTextSize(fontLarge);
} else {
mIOB2.setTextSize(fontSmall);
diff --git a/wear/src/main/res/drawable/ic_aaps_dark.xml b/wear/src/main/res/drawable/ic_aaps_dark.xml
new file mode 100644
index 0000000000..4126fec9d9
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_aaps_dark.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/wear/src/main/res/drawable/ic_aaps_full.xml b/wear/src/main/res/drawable/ic_aaps_full.xml
new file mode 100644
index 0000000000..cf9716870c
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_aaps_full.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/wear/src/main/res/drawable/ic_aaps_gray.xml b/wear/src/main/res/drawable/ic_aaps_gray.xml
new file mode 100644
index 0000000000..1797ca3c9a
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_aaps_gray.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/wear/src/main/res/drawable/ic_aaps_light.xml b/wear/src/main/res/drawable/ic_aaps_light.xml
new file mode 100644
index 0000000000..cf9716870c
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_aaps_light.xml
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/wear/src/main/res/drawable/ic_alert.xml b/wear/src/main/res/drawable/ic_alert.xml
new file mode 100644
index 0000000000..d95c322d47
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_alert.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_alert_burnin.xml b/wear/src/main/res/drawable/ic_alert_burnin.xml
new file mode 100644
index 0000000000..6f7bd23ef0
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_alert_burnin.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_alert_variant_outline.xml b/wear/src/main/res/drawable/ic_battery_alert_variant_outline.xml
new file mode 100644
index 0000000000..516ae49c17
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_alert_variant_outline.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless.xml
new file mode 100644
index 0000000000..bd6bee5fb1
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_10.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_10.xml
new file mode 100644
index 0000000000..932c4e5930
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_10.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_10_burnin.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_10_burnin.xml
new file mode 100644
index 0000000000..a47508a1a9
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_10_burnin.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_20.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_20.xml
new file mode 100644
index 0000000000..00af480fcd
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_20.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_20_burnin.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_20_burnin.xml
new file mode 100644
index 0000000000..e08ff88448
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_20_burnin.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_30.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_30.xml
new file mode 100644
index 0000000000..592d0f380c
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_30.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_30_burnin.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_30_burnin.xml
new file mode 100644
index 0000000000..eb36861925
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_30_burnin.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_40.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_40.xml
new file mode 100644
index 0000000000..f94f85a69b
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_40.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_40_burnin.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_40_burnin.xml
new file mode 100644
index 0000000000..8980db2391
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_40_burnin.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_50.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_50.xml
new file mode 100644
index 0000000000..f6a4148589
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_50.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_50_burnin.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_50_burnin.xml
new file mode 100644
index 0000000000..9a9ee645dc
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_50_burnin.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_60.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_60.xml
new file mode 100644
index 0000000000..29192af0ed
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_60.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_60_burnin.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_60_burnin.xml
new file mode 100644
index 0000000000..d5191601a6
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_60_burnin.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_70.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_70.xml
new file mode 100644
index 0000000000..02c0ae7f58
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_70.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_70_burnin.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_70_burnin.xml
new file mode 100644
index 0000000000..9efc928672
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_70_burnin.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_80.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_80.xml
new file mode 100644
index 0000000000..21e44f7105
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_80.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_80_burnin.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_80_burnin.xml
new file mode 100644
index 0000000000..9f212fad87
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_80_burnin.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_90.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_90.xml
new file mode 100644
index 0000000000..1004964eb2
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_90.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_90_burnin.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_90_burnin.xml
new file mode 100644
index 0000000000..b6b371fa20
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_90_burnin.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_burnin.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_burnin.xml
new file mode 100644
index 0000000000..fd11b20ac9
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_burnin.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_battery_charging_wireless_outline.xml b/wear/src/main/res/drawable/ic_battery_charging_wireless_outline.xml
new file mode 100644
index 0000000000..5fa535e117
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_charging_wireless_outline.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_outline.xml b/wear/src/main/res/drawable/ic_battery_outline.xml
new file mode 100644
index 0000000000..c066289e18
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_outline.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_unknown.xml b/wear/src/main/res/drawable/ic_battery_unknown.xml
new file mode 100644
index 0000000000..0ac1d8a740
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_unknown.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/drawable/ic_battery_unknown_burnin.xml b/wear/src/main/res/drawable/ic_battery_unknown_burnin.xml
new file mode 100644
index 0000000000..e6271cce70
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_battery_unknown_burnin.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_br_cob_iob.xml b/wear/src/main/res/drawable/ic_br_cob_iob.xml
new file mode 100644
index 0000000000..39ab3af490
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_br_cob_iob.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_carbs.xml b/wear/src/main/res/drawable/ic_carbs.xml
new file mode 100644
index 0000000000..a1ac753064
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_carbs.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_cob_detailed.xml b/wear/src/main/res/drawable/ic_cob_detailed.xml
new file mode 100644
index 0000000000..fc92be1910
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_cob_detailed.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_cob_iob.xml b/wear/src/main/res/drawable/ic_cob_iob.xml
new file mode 100644
index 0000000000..f029cf0d49
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_cob_iob.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_ins.xml b/wear/src/main/res/drawable/ic_ins.xml
new file mode 100644
index 0000000000..9fbb294190
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_ins.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_ins_burnin.xml b/wear/src/main/res/drawable/ic_ins_burnin.xml
new file mode 100644
index 0000000000..8a3a16c64b
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_ins_burnin.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_iob_detailed.xml b/wear/src/main/res/drawable/ic_iob_detailed.xml
new file mode 100644
index 0000000000..95974f2fed
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_iob_detailed.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_sgv.xml b/wear/src/main/res/drawable/ic_sgv.xml
new file mode 100644
index 0000000000..e7aefdd542
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_sgv.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/wear/src/main/res/drawable/ic_sync_alert.xml b/wear/src/main/res/drawable/ic_sync_alert.xml
new file mode 100644
index 0000000000..bd4ca18d5f
--- /dev/null
+++ b/wear/src/main/res/drawable/ic_sync_alert.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/values/strings.xml b/wear/src/main/res/values/strings.xml
index d50cb015e6..ca24978853 100644
--- a/wear/src/main/res/values/strings.xml
+++ b/wear/src/main/res/values/strings.xml
@@ -46,6 +46,25 @@
- 4
+
+ - Default
+ - Menu
+ - Wizard
+ - Bolus
+ - eCarb
+ - Status
+ - None
+
+
+
+ - default
+ - menu
+ - wizard
+ - bolus
+ - ecarb
+ - status
+ - none
+
AAPS
AAPS(Large)
@@ -53,4 +72,13 @@
AAPS(NoChart)
AAPS(Circle)
+
+ No data!
+ Old data!
+ Since %1$s
+ Sync with AAPS!
+
+ No data received since %1$s! Check if AAPS on the phone sends data to watch
+ AAPS data is %1$s old! Check your sensor, xDrip+, NS, AAPS config or other!
+
diff --git a/wear/src/main/res/xml/preferences.xml b/wear/src/main/res/xml/preferences.xml
index 0befaddfd0..aa8a3f6ba2 100644
--- a/wear/src/main/res/xml/preferences.xml
+++ b/wear/src/main/res/xml/preferences.xml
@@ -209,6 +209,20 @@
android:title="Wizard Percentage"
app:wear_iconOff="@drawable/settings_off"
app:wear_iconOn="@drawable/settings_on"/>
+
+