diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index fe72da5070..2cb270bcda 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -10,6 +10,7 @@
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 1f66ee889a..beeeadee79 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -4,6 +4,7 @@
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 66b3675c8d..faa095502d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -97,6 +97,7 @@ android {
}
dependencies {
+ fullWearApp project(path: ':wear', configuration: 'fullRelease')
compile fileTree(dir: 'libs', include: ['*.jar'])
compile('com.crashlytics.sdk.android:crashlytics:2.5.7@aar') {
transitive = true;
@@ -116,4 +117,5 @@ dependencies {
compile 'com.eclipsesource.j2v8:j2v8:3.1.6@aar'
compile 'com.joanzapata.iconify:android-iconify-fontawesome:2.1.1'
testCompile 'junit:junit:4.12'
+ compile 'com.google.android.gms:play-services-wearable:7.5.0'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f7d91f83c1..6a73ee2100 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -14,6 +14,7 @@
+
diff --git a/app/src/main/java/info/nightscout/androidaps/Services/Intents.java b/app/src/main/java/info/nightscout/androidaps/Services/Intents.java
index 63ef83e298..cff4854411 100644
--- a/app/src/main/java/info/nightscout/androidaps/Services/Intents.java
+++ b/app/src/main/java/info/nightscout/androidaps/Services/Intents.java
@@ -18,15 +18,15 @@ public interface Intents {
String ACTION_RESTART = "info.nightscout.client.RESTART";
// xDrip -> App
- String RECEIVER_PERMISSION = "com.eveningoutpost.dexdrip.permissions.RECEIVE_BG_ESTIMATE";
+ String RECEIVER_PERMISSION = "info.nightscout.androidaps.permissions.RECEIVE_BG_ESTIMATE";
- String ACTION_NEW_BG_ESTIMATE = "com.eveningoutpost.dexdrip.BgEstimate";
- String EXTRA_BG_ESTIMATE = "com.eveningoutpost.dexdrip.Extras.BgEstimate";
- String EXTRA_BG_SLOPE = "com.eveningoutpost.dexdrip.Extras.BgSlope";
- String EXTRA_BG_SLOPE_NAME = "com.eveningoutpost.dexdrip.Extras.BgSlopeName";
- String EXTRA_SENSOR_BATTERY = "com.eveningoutpost.dexdrip.Extras.SensorBattery";
- String EXTRA_TIMESTAMP = "com.eveningoutpost.dexdrip.Extras.Time";
- String EXTRA_RAW = "com.eveningoutpost.dexdrip.Extras.Raw";
+ String ACTION_NEW_BG_ESTIMATE = "info.nightscout.androidaps.BgEstimate";
+ String EXTRA_BG_ESTIMATE = "info.nightscout.androidaps.Extras.BgEstimate";
+ String EXTRA_BG_SLOPE = "info.nightscout.androidaps.Extras.BgSlope";
+ String EXTRA_BG_SLOPE_NAME = "info.nightscout.androidaps.Extras.BgSlopeName";
+ String EXTRA_SENSOR_BATTERY = "info.nightscout.androidaps.Extras.SensorBattery";
+ String EXTRA_TIMESTAMP = "info.nightscout.androidaps.Extras.Time";
+ String EXTRA_RAW = "info.nightscout.androidaps.Extras.Raw";
- String ACTION_NEW_BG_ESTIMATE_NO_DATA = "com.eveningoutpost.dexdrip.BgEstimateNoData";
+ String ACTION_NEW_BG_ESTIMATE_NO_DATA = "info.nightscout.androidaps.BgEstimateNoData";
}
diff --git a/settings.gradle b/settings.gradle
index e7b4def49c..9ccfb61915 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app'
+include ':app', ':wear'
diff --git a/wear/.gitignore b/wear/.gitignore
new file mode 100644
index 0000000000..796b96d1c4
--- /dev/null
+++ b/wear/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/wear/build.gradle b/wear/build.gradle
new file mode 100644
index 0000000000..d09c726980
--- /dev/null
+++ b/wear/build.gradle
@@ -0,0 +1,42 @@
+apply plugin: 'com.android.application'
+
+
+android {
+ compileSdkVersion 23
+ buildToolsVersion "23.0.3"
+
+ defaultConfig {
+ applicationId "info.nightscout.androidaps"
+ minSdkVersion 20
+ targetSdkVersion 23
+ versionCode 1
+ versionName "1.0.2"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ publishNonDefault true
+
+ productFlavors {
+ full {
+ applicationId = "info.nightscout.androidaps"
+ resValue "string", "label_xdrip", "AAPS"
+ resValue "string", "label_xdrip_large", "AAPS(Large)"
+ resValue "string", "label_xdrip_big_chart", "AAPS(BigChart)"
+ resValue "string", "label_xdrip_circle", "AAPS(Circle)"
+ resValue "string", "label_xdrip_activity", "AAPS Prefs."
+ resValue "string", "app_settings", "AAPS Settings"
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile 'com.ustwo.android:clockwise-wearable:1.0.2'
+ compile 'com.google.android.support:wearable:1.1.0'
+ compile 'com.google.android.gms:play-services-wearable:7.3.0'
+}
diff --git a/wear/libs/hellocharts-library-1.1.jar b/wear/libs/hellocharts-library-1.1.jar
new file mode 100644
index 0000000000..85b265168b
Binary files /dev/null and b/wear/libs/hellocharts-library-1.1.jar differ
diff --git a/wear/proguard-rules.pro b/wear/proguard-rules.pro
new file mode 100644
index 0000000000..3278718200
--- /dev/null
+++ b/wear/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /Users/stephenblack/Library/Android/sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/wear/src/main/AndroidManifest.xml b/wear/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..9985511e12
--- /dev/null
+++ b/wear/src/main/AndroidManifest.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wear/src/main/java/info/nightscout/androidaps/BIGChart.java b/wear/src/main/java/info/nightscout/androidaps/BIGChart.java
new file mode 100644
index 0000000000..a502311756
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/BIGChart.java
@@ -0,0 +1,510 @@
+package info.nightscout.androidaps;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.preference.PreferenceManager;
+import android.support.v4.content.LocalBroadcastManager;
+import android.support.wearable.view.WatchViewStub;
+import android.text.format.DateFormat;
+import android.util.Log;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.google.android.gms.wearable.DataMap;
+import com.ustwo.clockwise.WatchFace;
+import com.ustwo.clockwise.WatchFaceTime;
+import com.ustwo.clockwise.WatchMode;
+import com.ustwo.clockwise.WatchShape;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+import lecho.lib.hellocharts.util.Utils;
+import lecho.lib.hellocharts.view.LineChartView;
+
+/**
+ * Created by stephenblack on 12/29/14.
+ */
+public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPreferenceChangeListener {
+ public final static IntentFilter INTENT_FILTER;
+ public static final long[] vibratePattern = {0,400,300,400,300,400};
+ public TextView mTime, mSgv, mTimestamp, mDelta;
+ public RelativeLayout mRelativeLayout;
+ //public LinearLayout mLinearLayout;
+ public long sgvLevel = 0;
+ public int batteryLevel = 1;
+ public int ageLevel = 1;
+ public int highColor = Color.YELLOW;
+ public int lowColor = Color.RED;
+ public int midColor = Color.WHITE;
+ public int pointSize = 2;
+ public boolean singleLine = false;
+ public boolean layoutSet = false;
+ public int missed_readings_alert_id = 818;
+ public BgGraphBuilder bgGraphBuilder;
+ public LineChartView chart;
+ public double datetime;
+ public ArrayList bgDataList = new ArrayList<>();
+ public PowerManager.WakeLock wakeLock;
+ // related to manual layout
+ public View layoutView;
+ private final Point displaySize = new Point();
+ private int specW, specH;
+ private int animationAngle = 0;
+ private boolean isAnimated = false;
+
+ private LocalBroadcastManager localBroadcastManager;
+ private MessageReceiver messageReceiver;
+
+ protected SharedPreferences sharedPrefs;
+ private String rawString = "000 | 000 | 000";
+ private String batteryString = "--";
+ private String sgvString = "--";
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay();
+ display.getSize(displaySize);
+ wakeLock = ((PowerManager) getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Clock");
+
+ specW = View.MeasureSpec.makeMeasureSpec(displaySize.x,
+ View.MeasureSpec.EXACTLY);
+ specH = View.MeasureSpec.makeMeasureSpec(displaySize.y,
+ View.MeasureSpec.EXACTLY);
+ sharedPrefs = PreferenceManager
+ .getDefaultSharedPreferences(this);
+ sharedPrefs.registerOnSharedPreferenceChangeListener(this);
+ LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ layoutView = inflater.inflate(R.layout.activity_bigchart, null);
+ performViewSetup();
+ }
+
+ @Override
+ protected void onLayout(WatchShape shape, Rect screenBounds, WindowInsets screenInsets) {
+ super.onLayout(shape, screenBounds, screenInsets);
+ layoutView.onApplyWindowInsets(screenInsets);
+ }
+
+ public void performViewSetup() {
+ final WatchViewStub stub = (WatchViewStub) layoutView.findViewById(R.id.watch_view_stub);
+ IntentFilter messageFilter = new IntentFilter(Intent.ACTION_SEND);
+
+ messageReceiver = new MessageReceiver();
+ localBroadcastManager = LocalBroadcastManager.getInstance(this);
+ localBroadcastManager.registerReceiver(messageReceiver, messageFilter);
+
+ stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
+ @Override
+ public void onLayoutInflated(WatchViewStub stub) {
+ mTime = (TextView) stub.findViewById(R.id.watch_time);
+ mSgv = (TextView) stub.findViewById(R.id.sgv);
+ mTimestamp = (TextView) stub.findViewById(R.id.timestamp);
+ mDelta = (TextView) stub.findViewById(R.id.delta);
+ mRelativeLayout = (RelativeLayout) stub.findViewById(R.id.main_layout);
+ chart = (LineChartView) stub.findViewById(R.id.chart);
+ layoutSet = true;
+ showAgoRawBatt();
+ mRelativeLayout.measure(specW, specH);
+ mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
+ mRelativeLayout.getMeasuredHeight());
+ }
+ });
+ ListenerService.requestData(this);
+ wakeLock.acquire(50);
+ }
+
+ public int ageLevel() {
+ if(timeSince() <= (1000 * 60 * 12)) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ public double timeSince() {
+ return System.currentTimeMillis() - datetime;
+ }
+
+ public String readingAge(boolean shortString) {
+ if (datetime == 0) { return shortString?"--'":"-- Minute ago"; }
+ int minutesAgo = (int) Math.floor(timeSince()/(1000*60));
+ if (minutesAgo == 1) {
+ return minutesAgo + (shortString?"'":" Minute ago");
+ }
+ return minutesAgo + (shortString?"'":" Minutes ago");
+ }
+
+ @Override
+ public void onDestroy() {
+ if(localBroadcastManager != null && messageReceiver != null){
+ localBroadcastManager.unregisterReceiver(messageReceiver);}
+ if (sharedPrefs != null){
+ sharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
+ }
+ super.onDestroy();
+ }
+
+ static {
+ INTENT_FILTER = new IntentFilter();
+ INTENT_FILTER.addAction(Intent.ACTION_TIME_TICK);
+ INTENT_FILTER.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ INTENT_FILTER.addAction(Intent.ACTION_TIME_CHANGED);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if(layoutSet) {
+ this.mRelativeLayout.draw(canvas);
+ Log.d("onDraw", "draw");
+ }
+ }
+
+ @Override
+ protected void onTimeChanged(WatchFaceTime oldTime, WatchFaceTime newTime) {
+ if (layoutSet && (newTime.hasHourChanged(oldTime) || newTime.hasMinuteChanged(oldTime))) {
+ wakeLock.acquire(50);
+ final java.text.DateFormat timeFormat = DateFormat.getTimeFormat(BIGChart.this);
+ mTime.setText(timeFormat.format(System.currentTimeMillis()));
+ showAgoRawBatt();
+
+ if(ageLevel()<=0) {
+ mSgv.setPaintFlags(mSgv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
+ } else {
+ mSgv.setPaintFlags(mSgv.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
+ }
+
+ missedReadingAlert();
+ mRelativeLayout.measure(specW, specH);
+ mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
+ mRelativeLayout.getMeasuredHeight());
+ }
+ }
+
+ public class MessageReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Bundle bundle = intent.getBundleExtra("data");
+ if (bundle ==null){
+ return;
+ }
+ DataMap dataMap = DataMap.fromBundle(bundle);
+ if (layoutSet) {
+ wakeLock.acquire(50);
+ sgvLevel = dataMap.getLong("sgvLevel");
+ batteryLevel = dataMap.getInt("batteryLevel");
+ datetime = dataMap.getDouble("timestamp");
+ rawString = dataMap.getString("rawString");
+ sgvString = dataMap.getString("sgvString");
+ batteryString = dataMap.getString("battery");
+ mSgv.setText(dataMap.getString("sgvString"));
+
+ if(ageLevel()<=0) {
+ mSgv.setPaintFlags(mSgv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
+ } else {
+ mSgv.setPaintFlags(mSgv.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
+ }
+
+ final java.text.DateFormat timeFormat = DateFormat.getTimeFormat(BIGChart.this);
+ mTime.setText(timeFormat.format(System.currentTimeMillis()));
+
+ showAgoRawBatt();
+
+ String delta = dataMap.getString("delta");
+
+ if (delta.endsWith(" mg/dl")) {
+ mDelta.setText(delta.substring(0, delta.length() - 6));
+ } else if (delta.endsWith(" mmol")) {
+ mDelta.setText(delta.substring(0, delta.length() - 5));
+ }
+
+ if (chart != null) {
+ addToWatchSet(dataMap);
+ setupCharts();
+ }
+ mRelativeLayout.measure(specW, specH);
+ mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
+ mRelativeLayout.getMeasuredHeight());
+ invalidate();
+ setColor();
+
+ //start animation?
+ // dataMap.getDataMapArrayList("entries") == null -> not on "resend data".
+ if (sharedPrefs.getBoolean("animation", false) && dataMap.getDataMapArrayList("entries") == null && (sgvString.equals("100") || sgvString.equals("5.5") || sgvString.equals("5,5"))) {
+ startAnimation();
+ }
+
+
+ } else {
+ Log.d("ERROR: ", "DATA IS NOT YET SET");
+ }
+ }
+ }
+
+ private void showAgoRawBatt() {
+
+ if( mTimestamp == null){
+ return;
+ }
+ mTimestamp.setText(readingAge(true));
+ }
+
+ public void setColor() {
+ if (sharedPrefs.getBoolean("dark", true)) {
+ setColorDark();
+ } else {
+ setColorBright();
+ }
+
+ }
+
+
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key){
+ setColor();
+ if(layoutSet){
+ showAgoRawBatt();
+ mRelativeLayout.measure(specW, specH);
+ mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
+ mRelativeLayout.getMeasuredHeight());
+ }
+ invalidate();
+ }
+
+ protected void updateRainbow() {
+ animationAngle = (animationAngle + 1) % 360;
+ //Animation matrix:
+ int[] rainbow = {Color.RED, Color.YELLOW, Color.GREEN, Color.BLUE
+ , Color.CYAN};
+ Shader shader = new LinearGradient(0, 0, 0, 20, rainbow,
+ null, Shader.TileMode.MIRROR);
+ Matrix matrix = new Matrix();
+ matrix.setRotate(animationAngle);
+ shader.setLocalMatrix(matrix);
+ mSgv.getPaint().setShader(shader);
+ invalidate();
+ }
+
+ private synchronized boolean isAnimated() {
+ return isAnimated;
+ }
+
+ private synchronized void setIsAnimated(boolean isAnimated) {
+ this.isAnimated = isAnimated;
+ }
+
+ void startAnimation() {
+ Log.d("CircleWatchface", "start startAnimation");
+
+ Thread animator = new Thread() {
+
+
+ public void run() {
+ //TODO:Wakelock?
+ setIsAnimated(true);
+ for (int i = 0; i <= 8 * 1000 / 40; i++) {
+ updateRainbow();
+ try {
+ Thread.sleep(40);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ mSgv.getPaint().setShader(null);
+ setIsAnimated(false);
+ invalidate();
+ setColor();
+
+ System.gc();
+ }
+ };
+
+ animator.start();
+ }
+
+
+ protected void setColorDark() {
+ mTime.setTextColor(Color.WHITE);
+ mRelativeLayout.setBackgroundColor(Color.BLACK);
+ if (sgvLevel == 1) {
+ mSgv.setTextColor(Color.YELLOW);
+ mDelta.setTextColor(Color.YELLOW);
+ } else if (sgvLevel == 0) {
+ mSgv.setTextColor(Color.WHITE);
+ mDelta.setTextColor(Color.WHITE);
+ } else if (sgvLevel == -1) {
+ mSgv.setTextColor(Color.RED);
+ mDelta.setTextColor(Color.RED);
+ }
+
+
+ if (ageLevel == 1) {
+ mTimestamp.setTextColor(Color.WHITE);
+ } else {
+ mTimestamp.setTextColor(Color.RED);
+ }
+
+ if (batteryLevel == 1) {
+ } else {
+ }
+ if (chart != null) {
+ highColor = Color.YELLOW;
+ lowColor = Color.RED;
+ midColor = Color.WHITE;
+ singleLine = false;
+ pointSize = 2;
+ setupCharts();
+ }
+
+ }
+
+
+ protected void setColorBright() {
+
+ if (getCurrentWatchMode() == WatchMode.INTERACTIVE) {
+ mRelativeLayout.setBackgroundColor(Color.WHITE);
+ if (sgvLevel == 1) {
+ mSgv.setTextColor(Utils.COLOR_ORANGE);
+ mDelta.setTextColor(Utils.COLOR_ORANGE);
+ } else if (sgvLevel == 0) {
+ mSgv.setTextColor(Color.BLACK);
+ mDelta.setTextColor(Color.BLACK);
+ } else if (sgvLevel == -1) {
+ mSgv.setTextColor(Color.RED);
+ mDelta.setTextColor(Color.RED);
+ }
+
+ if (ageLevel == 1) {
+ mTimestamp.setTextColor(Color.BLACK);
+ } else {
+ mTimestamp.setTextColor(Color.RED);
+ }
+
+
+ mTime.setTextColor(Color.BLACK);
+ if (chart != null) {
+ highColor = Utils.COLOR_ORANGE;
+ midColor = Color.BLUE;
+ lowColor = Color.RED;
+ singleLine = false;
+ pointSize = 2;
+ setupCharts();
+ }
+ } else {
+ mRelativeLayout.setBackgroundColor(Color.BLACK);
+ if (sgvLevel == 1) {
+ mSgv.setTextColor(Color.YELLOW);
+ mDelta.setTextColor(Color.YELLOW);
+ } else if (sgvLevel == 0) {
+ mSgv.setTextColor(Color.WHITE);
+ mDelta.setTextColor(Color.WHITE);
+ } else if (sgvLevel == -1) {
+ mSgv.setTextColor(Color.RED);
+ mDelta.setTextColor(Color.RED);
+ }
+ mTimestamp.setTextColor(Color.WHITE);
+
+ mTime.setTextColor(Color.WHITE);
+ if (chart != null) {
+ highColor = Color.YELLOW;
+ midColor = Color.WHITE;
+ lowColor = Color.RED;
+ singleLine = true;
+ pointSize = 2;
+ setupCharts();
+ }
+ }
+
+ }
+
+
+ public void missedReadingAlert() {
+ int minutes_since = (int) Math.floor(timeSince()/(1000*60));
+ if(minutes_since >= 16 && ((minutes_since - 16) % 5) == 0) {
+ /*NotificationCompat.Builder notification = new NotificationCompat.Builder(getApplicationContext())
+ .setContentTitle("Missed BG Readings")
+ .setVibrate(vibratePattern);
+ NotificationManager mNotifyMgr = (hNotificationManager) getApplicationContext().getSystemService(getApplicationContext().NOTIFICATION_SERVICE);
+ mNotifyMgr.notify(missed_readings_alert_id, notification.build());*/
+ ListenerService.requestData(this); // attempt to recover missing data
+ }
+ }
+
+ public void addToWatchSet(DataMap dataMap) {
+
+ ArrayList entries = dataMap.getDataMapArrayList("entries");
+ if (entries != null) {
+ for (DataMap entry : entries) {
+ double sgv = entry.getDouble("sgvDouble");
+ double high = entry.getDouble("high");
+ double low = entry.getDouble("low");
+ double timestamp = entry.getDouble("timestamp");
+
+ final int size = bgDataList.size();
+ if (size > 0) {
+ if (bgDataList.get(size - 1).timestamp == timestamp)
+ continue; // Ignore duplicates.
+ }
+
+ bgDataList.add(new BgWatchData(sgv, high, low, timestamp));
+ }
+ } else {
+ double sgv = dataMap.getDouble("sgvDouble");
+ double high = dataMap.getDouble("high");
+ double low = dataMap.getDouble("low");
+ double timestamp = dataMap.getDouble("timestamp");
+
+ 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));
+ }
+
+ for (int i = 0; i < bgDataList.size(); i++) {
+ if (bgDataList.get(i).timestamp < (new Date().getTime() - (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
+ int timeframe = Integer.parseInt(sharedPrefs.getString("chart_timeframe", "5"));
+ if (singleLine) {
+ bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), bgDataList, pointSize, midColor, timeframe);
+ } else {
+ bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), bgDataList, pointSize, highColor, lowColor, midColor, timeframe);
+ }
+
+ chart.setLineChartData(bgGraphBuilder.lineData());
+ chart.setViewportCalculationEnabled(true);
+ chart.setMaximumViewport(chart.getMaximumViewport());
+ } else {
+ ListenerService.requestData(this);
+ }
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/BaseWatchFace.java b/wear/src/main/java/info/nightscout/androidaps/BaseWatchFace.java
new file mode 100644
index 0000000000..e127725a66
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/BaseWatchFace.java
@@ -0,0 +1,391 @@
+package info.nightscout.androidaps;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.graphics.Canvas;
+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 android.support.v4.content.LocalBroadcastManager;
+import android.support.wearable.view.WatchViewStub;
+import android.text.format.DateFormat;
+import android.util.Log;
+import android.view.Display;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import com.google.android.gms.wearable.DataMap;
+import com.ustwo.clockwise.WatchFace;
+import com.ustwo.clockwise.WatchFaceTime;
+import com.ustwo.clockwise.WatchShape;
+
+import java.util.ArrayList;
+import java.util.Date;
+
+import lecho.lib.hellocharts.view.LineChartView;
+
+/**
+ * Created by stephenblack on 12/29/14.
+ */
+public abstract class BaseWatchFace extends WatchFace implements SharedPreferences.OnSharedPreferenceChangeListener {
+ public final static IntentFilter INTENT_FILTER;
+ public static final long[] vibratePattern = {0,400,300,400,300,400};
+ public TextView mTime, mSgv, mDirection, mTimestamp, mUploaderBattery, mDelta, mRaw, mStatus;
+ public RelativeLayout mRelativeLayout;
+ public LinearLayout mLinearLayout;
+ public long sgvLevel = 0;
+ public int batteryLevel = 1;
+ public int ageLevel = 1;
+ public int highColor = Color.YELLOW;
+ public int lowColor = Color.RED;
+ public int midColor = Color.WHITE;
+ public int pointSize = 2;
+ public boolean singleLine = false;
+ public boolean layoutSet = false;
+ public int missed_readings_alert_id = 818;
+ public BgGraphBuilder bgGraphBuilder;
+ public LineChartView chart;
+ public double datetime;
+ public ArrayList bgDataList = new ArrayList<>();
+ public PowerManager.WakeLock wakeLock;
+ // related to manual layout
+ public View layoutView;
+ private final Point displaySize = new Point();
+ private int specW, specH;
+
+ private LocalBroadcastManager localBroadcastManager;
+ private MessageReceiver messageReceiver;
+
+ protected SharedPreferences sharedPrefs;
+ // private String rawString = "000 | 000 | 000";
+ private String rawString = "";
+ private String batteryString = "--";
+ private String sgvString = "--";
+ private String externalStatusString = "no status";
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay();
+ display.getSize(displaySize);
+ wakeLock = ((PowerManager) getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Clock");
+
+ specW = View.MeasureSpec.makeMeasureSpec(displaySize.x,
+ View.MeasureSpec.EXACTLY);
+ specH = View.MeasureSpec.makeMeasureSpec(displaySize.y,
+ View.MeasureSpec.EXACTLY);
+ sharedPrefs = PreferenceManager
+ .getDefaultSharedPreferences(this);
+ sharedPrefs.registerOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ protected void onLayout(WatchShape shape, Rect screenBounds, WindowInsets screenInsets) {
+ super.onLayout(shape, screenBounds, screenInsets);
+ layoutView.onApplyWindowInsets(screenInsets);
+ }
+
+ public void performViewSetup() {
+ final WatchViewStub stub = (WatchViewStub) layoutView.findViewById(R.id.watch_view_stub);
+ IntentFilter messageFilter = new IntentFilter(Intent.ACTION_SEND);
+
+ messageReceiver = new MessageReceiver();
+ localBroadcastManager = LocalBroadcastManager.getInstance(this);
+ localBroadcastManager.registerReceiver(messageReceiver, messageFilter);
+
+ stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
+ @Override
+ public void onLayoutInflated(WatchViewStub stub) {
+ mTime = (TextView) stub.findViewById(R.id.watch_time);
+ mSgv = (TextView) stub.findViewById(R.id.sgv);
+ mDirection = (TextView) stub.findViewById(R.id.direction);
+ mTimestamp = (TextView) stub.findViewById(R.id.timestamp);
+ mRaw = (TextView) stub.findViewById(R.id.raw);
+ mStatus = (TextView) stub.findViewById(R.id.externaltstatus);
+ mUploaderBattery = (TextView) stub.findViewById(R.id.uploader_battery);
+ mDelta = (TextView) stub.findViewById(R.id.delta);
+ mRelativeLayout = (RelativeLayout) stub.findViewById(R.id.main_layout);
+ mLinearLayout = (LinearLayout) stub.findViewById(R.id.secondary_layout);
+ chart = (LineChartView) stub.findViewById(R.id.chart);
+ layoutSet = true;
+ showAgoRawBattStatus();
+ mRelativeLayout.measure(specW, specH);
+ mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
+ mRelativeLayout.getMeasuredHeight());
+ }
+ });
+ ListenerService.requestData(this);
+ wakeLock.acquire(50);
+ }
+
+ public int ageLevel() {
+ if(timeSince() <= (1000 * 60 * 12)) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ public double timeSince() {
+ return System.currentTimeMillis() - datetime;
+ }
+
+ public String readingAge(boolean shortString) {
+ if (datetime == 0) { return shortString?"--'":"-- Minute ago"; }
+ int minutesAgo = (int) Math.floor(timeSince()/(1000*60));
+ if (minutesAgo == 1) {
+ return minutesAgo + (shortString?"'":" Minute ago");
+ }
+ return minutesAgo + (shortString?"'":" Minutes ago");
+ }
+
+ @Override
+ public void onDestroy() {
+ if(localBroadcastManager != null && messageReceiver != null){
+ localBroadcastManager.unregisterReceiver(messageReceiver);}
+ if (sharedPrefs != null){
+ sharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
+ }
+ super.onDestroy();
+ }
+
+ static {
+ INTENT_FILTER = new IntentFilter();
+ INTENT_FILTER.addAction(Intent.ACTION_TIME_TICK);
+ INTENT_FILTER.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ INTENT_FILTER.addAction(Intent.ACTION_TIME_CHANGED);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if(layoutSet) {
+ this.mRelativeLayout.draw(canvas);
+ Log.d("onDraw", "draw");
+ }
+ }
+
+ @Override
+ protected void onTimeChanged(WatchFaceTime oldTime, WatchFaceTime newTime) {
+ if (layoutSet && (newTime.hasHourChanged(oldTime) || newTime.hasMinuteChanged(oldTime))) {
+ wakeLock.acquire(50);
+ final java.text.DateFormat timeFormat = DateFormat.getTimeFormat(BaseWatchFace.this);
+ mTime.setText(timeFormat.format(System.currentTimeMillis()));
+ showAgoRawBattStatus();
+
+ if(ageLevel()<=0) {
+ mSgv.setPaintFlags(mSgv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
+ } else {
+ mSgv.setPaintFlags(mSgv.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
+ }
+
+ missedReadingAlert();
+ mRelativeLayout.measure(specW, specH);
+ mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
+ mRelativeLayout.getMeasuredHeight());
+ }
+ }
+
+ public class MessageReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+
+ //data
+ Bundle bundle = intent.getBundleExtra("data");
+ if (layoutSet && bundle != null) {
+ DataMap dataMap = DataMap.fromBundle(bundle);
+ wakeLock.acquire(50);
+ sgvLevel = dataMap.getLong("sgvLevel");
+ batteryLevel = dataMap.getInt("batteryLevel");
+ datetime = dataMap.getDouble("timestamp");
+ rawString = dataMap.getString("rawString");
+ sgvString = dataMap.getString("sgvString");
+ batteryString = dataMap.getString("battery");
+ mSgv.setText(dataMap.getString("sgvString"));
+
+ if(ageLevel()<=0) {
+ mSgv.setPaintFlags(mSgv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
+ } else {
+ mSgv.setPaintFlags(mSgv.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
+ }
+
+ final java.text.DateFormat timeFormat = DateFormat.getTimeFormat(BaseWatchFace.this);
+ mTime.setText(timeFormat.format(System.currentTimeMillis()));
+
+ showAgoRawBattStatus();
+
+ mDirection.setText(dataMap.getString("slopeArrow"));
+ mDelta.setText(dataMap.getString("delta"));
+
+ if (chart != null) {
+ addToWatchSet(dataMap);
+ setupCharts();
+ }
+ mRelativeLayout.measure(specW, specH);
+ mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
+ mRelativeLayout.getMeasuredHeight());
+ invalidate();
+ setColor();
+ }
+ //status
+ bundle = intent.getBundleExtra("status");
+ if (layoutSet && bundle != null) {
+ DataMap dataMap = DataMap.fromBundle(bundle);
+ wakeLock.acquire(50);
+ externalStatusString = dataMap.getString("externalStatusString");
+
+ showAgoRawBattStatus();
+
+ mRelativeLayout.measure(specW, specH);
+ mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
+ mRelativeLayout.getMeasuredHeight());
+ invalidate();
+ setColor();
+ }
+
+ }
+ }
+
+ private void showAgoRawBattStatus() {
+
+ if(mRaw == null || mTimestamp == null || mUploaderBattery == null|| mStatus == null){
+ return;
+ }
+
+ boolean showRaw = sharedPrefs.getBoolean("showRaw", false)
+ || (sharedPrefs.getBoolean("showRawNoise", true)
+ && sgvString.equals("???"));
+
+ boolean showStatus = sharedPrefs.getBoolean("showExternalStatus", false);
+
+ if(showRaw || showStatus){
+ //use short forms
+ mTimestamp.setText(readingAge(true));
+ mUploaderBattery.setText("U: " + batteryString + "%");
+ } else {
+ mTimestamp.setText(readingAge(false));
+ mUploaderBattery.setText("Uploader: " + batteryString + "%");
+ }
+
+ if (showRaw) {
+ mRaw.setVisibility(View.VISIBLE);
+ mRaw.setText("R: " + rawString);
+ } else {
+ mRaw.setVisibility(View.GONE);
+ }
+
+ if (showStatus) {
+ mStatus.setVisibility(View.VISIBLE);
+ mStatus.setText("S: " + externalStatusString);
+ } else {
+ mStatus.setVisibility(View.GONE);
+ }
+ }
+
+ public void setColor() {
+ if (sharedPrefs.getBoolean("dark", true)) {
+ setColorDark();
+ } else {
+ setColorBright();
+ }
+
+ }
+
+
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key){
+ setColor();
+ if(layoutSet){
+ showAgoRawBattStatus();
+ mRelativeLayout.measure(specW, specH);
+ mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
+ mRelativeLayout.getMeasuredHeight());
+ }
+ invalidate();
+ }
+protected abstract void setColorDark();
+ protected abstract void setColorBright();
+
+
+ public void missedReadingAlert() {
+ int minutes_since = (int) Math.floor(timeSince()/(1000*60));
+ if(minutes_since >= 16 && ((minutes_since - 16) % 5) == 0) {
+ /*NotificationCompat.Builder notification = new NotificationCompat.Builder(getApplicationContext())
+ .setContentTitle("Missed BG Readings")
+ .setVibrate(vibratePattern);
+ NotificationManager mNotifyMgr = (NotificationManager) getApplicationContext().getSystemService(getApplicationContext().NOTIFICATION_SERVICE);
+ mNotifyMgr.notify(missed_readings_alert_id, notification.build());*/
+ ListenerService.requestData(this); // attempt to recover missing data
+ }
+ }
+
+ public void addToWatchSet(DataMap dataMap) {
+
+ ArrayList entries = dataMap.getDataMapArrayList("entries");
+ if (entries != null) {
+ for (DataMap entry : entries) {
+ double sgv = entry.getDouble("sgvDouble");
+ double high = entry.getDouble("high");
+ double low = entry.getDouble("low");
+ double timestamp = entry.getDouble("timestamp");
+
+ final int size = bgDataList.size();
+ if (size > 0) {
+ if (bgDataList.get(size - 1).timestamp == timestamp)
+ continue; // Ignore duplicates.
+ }
+
+ bgDataList.add(new BgWatchData(sgv, high, low, timestamp));
+ }
+ } else {
+ double sgv = dataMap.getDouble("sgvDouble");
+ double high = dataMap.getDouble("high");
+ double low = dataMap.getDouble("low");
+ double timestamp = dataMap.getDouble("timestamp");
+
+ 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));
+ }
+
+ for (int i = 0; i < bgDataList.size(); i++) {
+ if (bgDataList.get(i).timestamp < (new Date().getTime() - (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
+ int timeframe = Integer.parseInt(sharedPrefs.getString("chart_timeframe", "5"));
+ if (singleLine) {
+ bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), bgDataList, pointSize, midColor, timeframe);
+ } else {
+ bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), bgDataList, pointSize, highColor, lowColor, midColor, timeframe);
+ }
+
+ chart.setLineChartData(bgGraphBuilder.lineData());
+ chart.setViewportCalculationEnabled(true);
+ chart.setMaximumViewport(chart.getMaximumViewport());
+ } else {
+ ListenerService.requestData(this);
+ }
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/BgGraphBuilder.java b/wear/src/main/java/info/nightscout/androidaps/BgGraphBuilder.java
new file mode 100644
index 0000000000..01fb281328
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/BgGraphBuilder.java
@@ -0,0 +1,237 @@
+package info.nightscout.androidaps;
+
+import android.content.Context;
+import android.text.format.DateFormat;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.TimeZone;
+
+import lecho.lib.hellocharts.model.Axis;
+import lecho.lib.hellocharts.model.AxisValue;
+import lecho.lib.hellocharts.model.Line;
+import lecho.lib.hellocharts.model.LineChartData;
+import lecho.lib.hellocharts.model.PointValue;
+import lecho.lib.hellocharts.model.Viewport;
+
+/**
+ * Created by stephenblack on 11/15/14.
+ */
+public class BgGraphBuilder {
+ private int timespan;
+ public double end_time;
+ public double start_time;
+ public double fuzzyTimeDenom = (1000 * 60 * 1);
+ public Context context;
+ public double highMark;
+ public double lowMark;
+ public List bgDataList = new ArrayList();
+
+ public int pointSize;
+ public int highColor;
+ public int lowColor;
+ public int midColor;
+ public boolean singleLine = false;
+
+ private double endHour;
+ private List inRangeValues = new ArrayList();
+ private List highValues = new ArrayList();
+ private List lowValues = new ArrayList();
+ public Viewport viewport;
+
+ public BgGraphBuilder(Context context, List aBgList, int aPointSize, int aMidColor, int timespan) {
+ end_time = new Date().getTime() + (1000 * 60 * 6 * timespan); //Now plus 30 minutes padding (for 5 hours. Less if less.)
+ start_time = new Date().getTime() - (1000 * 60 * 60 * timespan); //timespan hours ago
+ this.bgDataList = aBgList;
+ this.context = context;
+ this.highMark = aBgList.get(aBgList.size() - 1).high;
+ this.lowMark = aBgList.get(aBgList.size() - 1).low;
+ this.pointSize = aPointSize;
+ this.singleLine = true;
+ this.midColor = aMidColor;
+ this.lowColor = aMidColor;
+ this.highColor = aMidColor;
+ this.timespan = timespan;
+ }
+
+ public BgGraphBuilder(Context context, List aBgList, int aPointSize, int aHighColor, int aLowColor, int aMidColor, int timespan) {
+ end_time = new Date().getTime() + (1000 * 60 * 6 * timespan); //Now plus 30 minutes padding (for 5 hours. Less if less.)
+ start_time = new Date().getTime() - (1000 * 60 * 60 * timespan); //timespan hours ago
+ this.bgDataList = aBgList;
+ this.context = context;
+ this.highMark = aBgList.get(aBgList.size() - 1).high;
+ this.lowMark = aBgList.get(aBgList.size() - 1).low;
+ this.pointSize = aPointSize;
+ this.highColor = aHighColor;
+ this.lowColor = aLowColor;
+ this.midColor = aMidColor;
+ this.timespan = timespan;
+ }
+
+ public LineChartData lineData() {
+ LineChartData lineData = new LineChartData(defaultLines());
+ lineData.setAxisYLeft(yAxis());
+ lineData.setAxisXBottom(xAxis());
+ return lineData;
+ }
+
+ public List defaultLines() {
+ addBgReadingValues();
+ List lines = new ArrayList();
+ lines.add(highLine());
+ lines.add(lowLine());
+ lines.add(inRangeValuesLine());
+ lines.add(lowValuesLine());
+ lines.add(highValuesLine());
+ return lines;
+ }
+
+ public Line highValuesLine() {
+ Line highValuesLine = new Line(highValues);
+ highValuesLine.setColor(highColor);
+ highValuesLine.setHasLines(false);
+ highValuesLine.setPointRadius(pointSize);
+ highValuesLine.setHasPoints(true);
+ return highValuesLine;
+ }
+
+ public Line lowValuesLine() {
+ Line lowValuesLine = new Line(lowValues);
+ lowValuesLine.setColor(lowColor);
+ lowValuesLine.setHasLines(false);
+ lowValuesLine.setPointRadius(pointSize);
+ lowValuesLine.setHasPoints(true);
+ return lowValuesLine;
+ }
+
+ public Line inRangeValuesLine() {
+ Line inRangeValuesLine = new Line(inRangeValues);
+ inRangeValuesLine.setColor(midColor);
+ if(singleLine) {
+ inRangeValuesLine.setHasLines(true);
+ inRangeValuesLine.setHasPoints(false);
+ inRangeValuesLine.setStrokeWidth(pointSize);
+ } else {
+ inRangeValuesLine.setPointRadius(pointSize);
+ inRangeValuesLine.setHasPoints(true);
+ inRangeValuesLine.setHasLines(false);
+ }
+ return inRangeValuesLine;
+ }
+
+ private void addBgReadingValues() {
+ if(singleLine) {
+ for (BgWatchData bgReading : bgDataList) {
+ if(bgReading.timestamp > start_time) {
+ if (bgReading.sgv >= 400) {
+ inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) 400));
+ } else if (bgReading.sgv >= highMark) {
+ inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) bgReading.sgv));
+ } else if (bgReading.sgv >= lowMark) {
+ inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) bgReading.sgv));
+ } else if (bgReading.sgv >= 40) {
+ inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) bgReading.sgv));
+ } else if (bgReading.sgv >= 11) {
+ inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) 40));
+ }
+ }
+ }
+ } else {
+ for (BgWatchData bgReading : bgDataList) {
+ if (bgReading.timestamp > start_time) {
+ if (bgReading.sgv >= 400) {
+ highValues.add(new PointValue(fuzz(bgReading.timestamp), (float) 400));
+ } else if (bgReading.sgv >= highMark) {
+ highValues.add(new PointValue(fuzz(bgReading.timestamp), (float) bgReading.sgv));
+ } else if (bgReading.sgv >= lowMark) {
+ inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) bgReading.sgv));
+ } else if (bgReading.sgv >= 40) {
+ lowValues.add(new PointValue(fuzz(bgReading.timestamp), (float) bgReading.sgv));
+ } else if (bgReading.sgv >= 11) {
+ lowValues.add(new PointValue(fuzz(bgReading.timestamp), (float) 40));
+ }
+ }
+ }
+ }
+ }
+
+ public Line highLine() {
+ List highLineValues = new ArrayList();
+ highLineValues.add(new PointValue(fuzz(start_time), (float) highMark));
+ highLineValues.add(new PointValue(fuzz(end_time), (float) highMark));
+ Line highLine = new Line(highLineValues);
+ highLine.setHasPoints(false);
+ highLine.setStrokeWidth(1);
+ highLine.setColor(highColor);
+ return highLine;
+ }
+
+ public Line lowLine() {
+ List lowLineValues = new ArrayList();
+ lowLineValues.add(new PointValue(fuzz(start_time), (float) lowMark));
+ lowLineValues.add(new PointValue(fuzz(end_time), (float) lowMark));
+ Line lowLine = new Line(lowLineValues);
+ lowLine.setHasPoints(false);
+ lowLine.setColor(lowColor);
+ lowLine.setStrokeWidth(1);
+ return lowLine;
+ }
+
+ /////////AXIS RELATED//////////////
+ public Axis yAxis() {
+ Axis yAxis = new Axis();
+ yAxis.setAutoGenerated(true);
+ List axisValues = new ArrayList();
+ yAxis.setValues(axisValues);
+ yAxis.setHasLines(false);
+ return yAxis;
+ }
+
+ public Axis xAxis() {
+ final boolean is24 = DateFormat.is24HourFormat(context);
+ Axis xAxis = new Axis();
+ xAxis.setAutoGenerated(false);
+ List xAxisValues = new ArrayList();
+ GregorianCalendar now = new GregorianCalendar();
+ GregorianCalendar today = new GregorianCalendar(now.get(Calendar.YEAR), now.get(Calendar.MONTH), now.get(Calendar.DAY_OF_MONTH));
+ SimpleDateFormat timeFormat = new SimpleDateFormat(is24? "HH" : "h a");
+ timeFormat.setTimeZone(TimeZone.getDefault());
+ double start_hour = today.getTime().getTime();
+ double timeNow = new Date().getTime();
+ for (int l = 0; l <= 24; l++) {
+ if ((start_hour + (60000 * 60 * (l))) < timeNow) {
+ if ((start_hour + (60000 * 60 * (l + 1))) >= timeNow) {
+ endHour = start_hour + (60000 * 60 * (l));
+ l = 25;
+ }
+ }
+ }
+ //Display current time on the graph
+ SimpleDateFormat longTimeFormat = new SimpleDateFormat(is24? "HH:mm" : "h:mm a");
+ xAxisValues.add(new AxisValue(fuzz(timeNow), (longTimeFormat.format(timeNow)).toCharArray()));
+
+ //Add whole hours to the axis (as long as they are more than 15 mins away from the current time)
+ for (int l = 0; l <= 24; l++) {
+ double timestamp = endHour - (60000 * 60 * l);
+ if((timestamp - timeNow < 0) && (timestamp > start_time)) {
+ if(Math.abs(timestamp - timeNow) > (1000 * 60 * 8 * timespan)){
+ xAxisValues.add(new AxisValue(fuzz(timestamp), (timeFormat.format(timestamp)).toCharArray()));
+ }else {
+ xAxisValues.add(new AxisValue(fuzz(timestamp), "".toCharArray()));
+ }
+ }
+ }
+ xAxis.setValues(xAxisValues);
+ xAxis.setTextSize(10);
+ xAxis.setHasLines(true);
+ return xAxis;
+ }
+
+ public float fuzz(double value) {
+ return (float) Math.round(value / fuzzyTimeDenom);
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/BgWatchData.java b/wear/src/main/java/info/nightscout/androidaps/BgWatchData.java
new file mode 100644
index 0000000000..9a6ea01b62
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/BgWatchData.java
@@ -0,0 +1,39 @@
+package info.nightscout.androidaps;
+
+/**
+ * Created by stephenblack on 1/7/15.
+ */
+public class BgWatchData implements Comparable{
+ public double sgv;
+ public double high;
+ public double low;
+ public double timestamp;
+
+ public BgWatchData(double aSgv, double aHigh, double aLow, double aTimestamp) {
+ this.sgv = aSgv;
+ this.high = aHigh;
+ this.low = aLow;
+ this.timestamp = aTimestamp;
+ }
+
+ @Override
+ public boolean equals(Object that){
+ if(! (that instanceof BgWatchData)){
+ return false;
+ }
+ return this.timestamp == ((BgWatchData) that).timestamp;
+ }
+
+ @Override
+ public int hashCode(){
+ return (int) (timestamp%Integer.MAX_VALUE);
+ }
+
+ @Override
+ public int compareTo(BgWatchData that) {
+ // reverse order to get latest first
+ if(this.timestamp < that.timestamp) return 1;
+ if(this.timestamp > that.timestamp) return -1;
+ return 0;
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/CircleWatchface.java b/wear/src/main/java/info/nightscout/androidaps/CircleWatchface.java
new file mode 100644
index 0000000000..d4cc9acd06
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/CircleWatchface.java
@@ -0,0 +1,691 @@
+package info.nightscout.androidaps;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.LinearGradient;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.os.Bundle;
+import android.os.PowerManager;
+import android.preference.PreferenceManager;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import com.google.android.gms.wearable.DataMap;
+import com.ustwo.clockwise.WatchFace;
+import com.ustwo.clockwise.WatchFaceTime;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.TreeSet;
+
+
+public class CircleWatchface extends WatchFace implements SharedPreferences.OnSharedPreferenceChangeListener {
+ public final float PADDING = 20f;
+ public final float CIRCLE_WIDTH = 10f;
+ public final int BIG_HAND_WIDTH = 16;
+ public final int SMALL_HAND_WIDTH = 8;
+ public final int NEAR = 2; //how near do the hands have to be to activate overlapping mode
+ public final boolean ALWAYS_HIGHLIGT_SMALL = false;
+
+ //variables for time
+ private float angleBig = 0f;
+ private float angleSMALL = 0f;
+ private int hour, minute;
+ private int color;
+ private Paint circlePaint = new Paint();
+ private Paint removePaint = new Paint();
+ private RectF rect, rectDelete;
+ private boolean overlapping;
+
+ private int animationAngle = 0;
+ private boolean isAnimated = false;
+
+
+ public Point displaySize = new Point();
+ private MessageReceiver messageReceiver = new MessageReceiver();
+
+ private int sgvLevel = 0;
+ private String sgvString = "999";
+ private String rawString = "x | x | x";
+
+
+ private int batteryLevel = 0;
+ private double datetime = 0;
+ private String direction = "";
+ private String delta = "";
+ public TreeSet bgDataList = new TreeSet();
+
+ private View layoutView;
+ private int specW;
+ private int specH;
+ private View myLayout;
+
+ protected SharedPreferences sharedPrefs;
+
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
+ PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "CreateWakelock");
+ wakeLock.acquire(30000);
+
+ Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay();
+ display.getSize(displaySize);
+
+ specW = View.MeasureSpec.makeMeasureSpec(displaySize.x,
+ View.MeasureSpec.EXACTLY);
+ specH = View.MeasureSpec.makeMeasureSpec(displaySize.y,
+ View.MeasureSpec.EXACTLY);
+
+ sharedPrefs = PreferenceManager
+ .getDefaultSharedPreferences(this);
+ sharedPrefs.registerOnSharedPreferenceChangeListener(this);
+
+ //register Message Receiver
+ LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, new IntentFilter(Intent.ACTION_SEND));
+
+ LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ myLayout = inflater.inflate(R.layout.modern_layout, null);
+ prepareLayout();
+ prepareDrawTime();
+
+ //ListenerService.requestData(this); //usually connection is not set up yet
+
+ wakeLock.release();
+ }
+
+
+ @Override
+ public void onDestroy() {
+ if (messageReceiver != null) {
+ LocalBroadcastManager.getInstance(this).unregisterReceiver(messageReceiver);
+ }
+ if (sharedPrefs != null) {
+ sharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
+ }
+ super.onDestroy();
+ }
+
+ @Override
+ protected synchronized void onDraw(Canvas canvas) {
+ Log.d("CircleWatchface", "start onDraw");
+ canvas.drawColor(getBackgroundColor());
+ drawTime(canvas);
+ drawOtherStuff(canvas);
+ myLayout.draw(canvas);
+
+ }
+
+ private synchronized void prepareLayout() {
+
+ Log.d("CircleWatchface", "start startPrepareLayout");
+
+ // prepare fields
+
+ TextView textView = null;
+
+ textView = (TextView) myLayout.findViewById(R.id.sgvString);
+ if (sharedPrefs.getBoolean("showBG", true)) {
+ textView.setVisibility(View.VISIBLE);
+ textView.setText(getSgvString());
+ textView.setTextColor(getTextColor());
+
+ } else {
+ //Also possible: View.INVISIBLE instead of View.GONE (no layout change)
+ textView.setVisibility(View.INVISIBLE);
+ }
+
+ textView = (TextView) myLayout.findViewById(R.id.rawString);
+ if (sharedPrefs.getBoolean("showRaw", false)||
+ (sharedPrefs.getBoolean("showRawNoise", true) && getSgvString().equals("???"))
+ ) {
+ textView.setVisibility(View.VISIBLE);
+ textView.setText(getRawString());
+ textView.setTextColor(getTextColor());
+
+ } else {
+ //Also possible: View.INVISIBLE instead of View.GONE (no layout change)
+ textView.setVisibility(View.GONE);
+ }
+
+ textView = (TextView) myLayout.findViewById(R.id.agoString);
+ if (sharedPrefs.getBoolean("showAgo", true)) {
+ textView.setVisibility(View.VISIBLE);
+
+ if (sharedPrefs.getBoolean("showBigNumbers", false)) {
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 26);
+ } else {
+ ((TextView) myLayout.findViewById(R.id.agoString)).setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
+ }
+ textView.setText(getMinutes());
+ textView.setTextColor(getTextColor());
+ } else {
+ //Also possible: View.INVISIBLE instead of View.GONE (no layout change)
+ textView.setVisibility(View.INVISIBLE);
+ }
+
+ textView = (TextView) myLayout.findViewById(R.id.deltaString);
+ if (sharedPrefs.getBoolean("showDelta", true)) {
+ textView.setVisibility(View.VISIBLE);
+ textView.setText(getDelta());
+ textView.setTextColor(getTextColor());
+ if (sharedPrefs.getBoolean("showBigNumbers", false)) {
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25);
+ if (delta.endsWith(" mg/dl")) {
+ textView.setText(getDelta().substring(0, delta.length() - 6));
+ } else if (delta.endsWith(" mmol")) {
+ textView.setText(getDelta().substring(0, delta.length() - 5));
+ }
+ } else {
+ textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
+ textView.setText(getDelta());
+ }
+ } else {
+ //Also possible: View.INVISIBLE instead of View.GONE (no layout change)
+ textView.setVisibility(View.INVISIBLE);
+ }
+ //TODO: add more view elements?
+
+ myLayout.measure(specW, specH);
+ myLayout.layout(0, 0, myLayout.getMeasuredWidth(),
+ myLayout.getMeasuredHeight());
+ }
+
+ public String getMinutes() {
+ String minutes = "--\'";
+ if (getDatetime() != 0) {
+ minutes = ((int) Math.floor((System.currentTimeMillis() - getDatetime()) / 60000)) + "\'";
+ }
+ return minutes;
+ }
+
+ private void drawTime(Canvas canvas) {
+
+ //draw circle
+ circlePaint.setColor(color);
+ circlePaint.setStrokeWidth(CIRCLE_WIDTH);
+ canvas.drawArc(rect, 0, 360, false, circlePaint);
+ //"remove" hands from circle
+ removePaint.setStrokeWidth(CIRCLE_WIDTH * 3);
+
+ canvas.drawArc(rectDelete, angleBig, (float) BIG_HAND_WIDTH, false, removePaint);
+ canvas.drawArc(rectDelete, angleSMALL, (float) SMALL_HAND_WIDTH, false, removePaint);
+
+
+ if (overlapping) {
+ //add small hand with extra
+ circlePaint.setStrokeWidth(CIRCLE_WIDTH * 2);
+ circlePaint.setColor(color);
+ canvas.drawArc(rect, angleSMALL, (float) SMALL_HAND_WIDTH, false, circlePaint);
+
+ //remove inner part of hands
+ removePaint.setStrokeWidth(CIRCLE_WIDTH);
+ canvas.drawArc(rect, angleBig, (float) BIG_HAND_WIDTH, false, removePaint);
+ canvas.drawArc(rect, angleSMALL, (float) SMALL_HAND_WIDTH, false, removePaint);
+ }
+
+ }
+
+ private synchronized void prepareDrawTime() {
+ Log.d("CircleWatchface", "start prepareDrawTime");
+
+ hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY) % 12;
+ minute = Calendar.getInstance().get(Calendar.MINUTE);
+ angleBig = (((hour + minute / 60f) / 12f * 360) - 90 - BIG_HAND_WIDTH / 2f + 360) % 360;
+ angleSMALL = ((minute / 60f * 360) - 90 - SMALL_HAND_WIDTH / 2f + 360) % 360;
+
+
+ color = 0;
+ switch (getSgvLevel()) {
+ case -1:
+ color = getLowColor();
+ break;
+ case 0:
+ color = getInRangeColor();
+ break;
+ case 1:
+ color = getHighColor();
+ break;
+ }
+
+
+ if (isAnimated()) {
+ //Animation matrix:
+ int[] rainbow = {Color.RED, Color.YELLOW, Color.GREEN, Color.BLUE
+ , Color.CYAN};
+ Shader shader = new LinearGradient(0, 0, 0, 20, rainbow,
+ null, Shader.TileMode.MIRROR);
+ Matrix matrix = new Matrix();
+ matrix.setRotate(animationAngle);
+ shader.setLocalMatrix(matrix);
+ circlePaint.setShader(shader);
+ } else {
+ circlePaint.setShader(null);
+ }
+
+
+ circlePaint.setStyle(Paint.Style.STROKE);
+ circlePaint.setStrokeWidth(CIRCLE_WIDTH);
+ circlePaint.setAntiAlias(true);
+ circlePaint.setColor(color);
+
+ removePaint.setStyle(Paint.Style.STROKE);
+ removePaint.setStrokeWidth(CIRCLE_WIDTH);
+ removePaint.setAntiAlias(true);
+ removePaint.setColor(getBackgroundColor());
+
+ ;
+
+ rect = new RectF(PADDING, PADDING, (float) (displaySize.x - PADDING), (float) (displaySize.y - PADDING));
+ rectDelete = new RectF(PADDING - CIRCLE_WIDTH / 2, PADDING - CIRCLE_WIDTH / 2, (float) (displaySize.x - PADDING + CIRCLE_WIDTH / 2), (float) (displaySize.y - PADDING + CIRCLE_WIDTH / 2));
+ overlapping = ALWAYS_HIGHLIGT_SMALL || areOverlapping(angleSMALL, angleSMALL + SMALL_HAND_WIDTH + NEAR, angleBig, angleBig + BIG_HAND_WIDTH + NEAR);
+ Log.d("CircleWatchface", "end prepareDrawTime");
+
+ }
+
+ synchronized void animationStep() {
+ animationAngle = (animationAngle + 1) % 360;
+ prepareDrawTime();
+ invalidate();
+ }
+
+
+ private boolean areOverlapping(float aBegin, float aEnd, float bBegin, float bEnd) {
+ return
+ aBegin <= bBegin && aEnd >= bBegin ||
+ aBegin <= bBegin && (bEnd > 360) && bEnd % 360 > aBegin ||
+ bBegin <= aBegin && bEnd >= aBegin ||
+ bBegin <= aBegin && aEnd > 360 && aEnd % 360 > bBegin;
+ }
+
+ @Override
+ protected void onTimeChanged(WatchFaceTime oldTime, WatchFaceTime newTime) {
+ if (oldTime.hasMinuteChanged(newTime)) {
+ PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
+ PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "TimeChangedWakelock");
+ wakeLock.acquire(30000);
+ /*Preparing the layout just on every minute tick:
+ * - hopefully better battery life
+ * - drawback: might update the minutes since last reading up to one minute late*/
+ prepareLayout();
+ prepareDrawTime();
+ invalidate(); //redraw the time
+ wakeLock.release();
+
+ }
+ }
+
+
+ // defining color for dark and bright
+ public int getLowColor() {
+ if (sharedPrefs.getBoolean("dark", true)) {
+ return Color.argb(255, 255, 120, 120);
+ } else {
+ return Color.argb(255, 255, 80, 80);
+ }
+ }
+
+ public int getInRangeColor() {
+ if (sharedPrefs.getBoolean("dark", false)) {
+ return Color.argb(255, 120, 255, 120);
+ } else {
+ return Color.argb(255, 0, 240, 0);
+
+ }
+ }
+
+ public int getHighColor() {
+ if (sharedPrefs.getBoolean("dark", false)) {
+ return Color.argb(255, 255, 255, 120);
+ } else {
+ return Color.argb(255, 255, 200, 0);
+ }
+
+ }
+
+ public int getBackgroundColor() {
+ if (sharedPrefs.getBoolean("dark", false)) {
+ return Color.BLACK;
+ } else {
+ return Color.WHITE;
+
+ }
+ }
+
+ public int getTextColor() {
+ if (sharedPrefs.getBoolean("dark", false)) {
+ return Color.WHITE;
+ } else {
+ return Color.BLACK;
+
+ }
+ }
+
+ public void drawOtherStuff(Canvas canvas) {
+ Log.d("CircleWatchface", "start onDrawOtherStuff. bgDataList.size(): " + bgDataList.size());
+
+ if (isAnimated()) return; // too many repaints when animated
+ if (sharedPrefs.getBoolean("showRingHistory", false)) {
+ //Perfect low and High indicators
+ if (bgDataList.size() > 0) {
+ addIndicator(canvas, 100, Color.LTGRAY);
+ addIndicator(canvas, (float) bgDataList.iterator().next().low, getLowColor());
+ addIndicator(canvas, (float) bgDataList.iterator().next().high, getHighColor());
+
+
+ if (sharedPrefs.getBoolean("softRingHistory", true)) {
+ for (BgWatchData data : bgDataList) {
+ addReadingSoft(canvas, data);
+ }
+ } else {
+ for (BgWatchData data : bgDataList) {
+ addReading(canvas, data);
+ }
+ }
+ }
+ }
+ }
+
+ public int holdInMemory() {
+ return 6;
+ }
+
+ //getters & setters
+
+ private synchronized int getSgvLevel() {
+ return sgvLevel;
+ }
+
+ private synchronized void setSgvLevel(int sgvLevel) {
+ this.sgvLevel = sgvLevel;
+ }
+
+ private synchronized int getBatteryLevel() {
+ return batteryLevel;
+ }
+
+ private synchronized void setBatteryLevel(int batteryLevel) {
+ this.batteryLevel = batteryLevel;
+ }
+
+
+ private synchronized double getDatetime() {
+ return datetime;
+ }
+
+ private synchronized void setDatetime(double datetime) {
+ this.datetime = datetime;
+ }
+
+ private synchronized String getDirection() {
+ return direction;
+ }
+
+ private void setDirection(String direction) {
+ this.direction = direction;
+ }
+
+ String getSgvString() {
+ return sgvString;
+ }
+
+ void setSgvString(String sgvString) {
+ this.sgvString = sgvString;
+ }
+
+ String getRawString() {
+ return rawString;
+ }
+
+ void setRawString(String rawString) {
+ this.rawString = rawString;
+ }
+
+ public String getDelta() {
+ return delta;
+ }
+
+ private void setDelta(String delta) {
+ this.delta = delta;
+ }
+
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ prepareDrawTime();
+ prepareLayout();
+ invalidate();
+ }
+
+ private synchronized boolean isAnimated() {
+ return isAnimated;
+ }
+
+ private synchronized void setIsAnimated(boolean isAnimated) {
+ this.isAnimated = isAnimated;
+ }
+
+ void startAnimation() {
+ Log.d("CircleWatchface", "start startAnimation");
+
+ Thread animator = new Thread() {
+
+
+ public void run() {
+ //TODO:Wakelock?
+ setIsAnimated(true);
+ for (int i = 0; i <= 8 * 1000 / 40; i++) {
+ animationStep();
+ try {
+ Thread.sleep(40);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ setIsAnimated(false);
+ prepareDrawTime();
+ invalidate();
+ System.gc();
+ }
+ };
+
+ animator.start();
+ }
+
+
+ public class MessageReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
+ PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
+ "MyWakelockTag");
+ wakeLock.acquire(30000);
+ Bundle bundle = intent.getBundleExtra("data");
+ if (bundle!= null) {
+ DataMap dataMap = DataMap.fromBundle(bundle);
+ setSgvLevel((int) dataMap.getLong("sgvLevel"));
+ Log.d("CircleWatchface", "sgv level : " + getSgvLevel());
+ setSgvString(dataMap.getString("sgvString"));
+ Log.d("CircleWatchface", "sgv string : " + getSgvString());
+ setRawString(dataMap.getString("rawString"));
+ setDelta(dataMap.getString("delta"));
+ setDatetime(dataMap.getDouble("timestamp"));
+ addToWatchSet(dataMap);
+
+
+ //start animation?
+ // dataMap.getDataMapArrayList("entries") == null -> not on "resend data".
+ if (sharedPrefs.getBoolean("animation", false) && dataMap.getDataMapArrayList("entries") == null && (getSgvString().equals("100") || getSgvString().equals("5.5") || getSgvString().equals("5,5"))) {
+ startAnimation();
+ }
+
+ prepareLayout();
+ prepareDrawTime();
+ invalidate();
+ }
+ wakeLock.release();
+ }
+ }
+
+ public synchronized void addToWatchSet(DataMap dataMap) {
+
+ if(!sharedPrefs.getBoolean("showRingHistory", false)){
+ bgDataList.clear();
+ return;
+ }
+
+ Log.d("CircleWatchface", "start addToWatchSet");
+ ArrayList entries = dataMap.getDataMapArrayList("entries");
+ if (entries == null) {
+ double sgv = dataMap.getDouble("sgvDouble");
+ double high = dataMap.getDouble("high");
+ double low = dataMap.getDouble("low");
+ double timestamp = dataMap.getDouble("timestamp");
+ bgDataList.add(new BgWatchData(sgv, high, low, timestamp));
+ } else if (!sharedPrefs.getBoolean("animation", false)) {
+ // don't load history at once if animations are set (less resource consumption)
+ Log.d("addToWatchSet", "entries.size(): " + entries.size());
+
+ for (DataMap entry : entries) {
+ double sgv = entry.getDouble("sgvDouble");
+ double high = entry.getDouble("high");
+ double low = entry.getDouble("low");
+ double timestamp = entry.getDouble("timestamp");
+ bgDataList.add(new BgWatchData(sgv, high, low, timestamp));
+ }
+ } else
+
+ Log.d("addToWatchSet", "start removing bgDataList.size(): " + bgDataList.size());
+ HashSet removeSet = new HashSet();
+ double threshold = (new Date().getTime() - (1000 * 60 * 5 * holdInMemory()));
+ for (BgWatchData data : bgDataList) {
+ if (data.timestamp < threshold) {
+ removeSet.add(data);
+
+ }
+ }
+ bgDataList.removeAll(removeSet);
+ Log.d("addToWatchSet", "after bgDataList.size(): " + bgDataList.size());
+ removeSet = null;
+ System.gc();
+ }
+
+ public int darken(int color, double fraction) {
+ int red = Color.red(color);
+ int green = Color.green(color);
+ int blue = Color.blue(color);
+ red = darkenColor(red, fraction);
+ green = darkenColor(green, fraction);
+ blue = darkenColor(blue, fraction);
+ int alpha = Color.alpha(color);
+
+ return Color.argb(alpha, red, green, blue);
+ }
+
+ private int darkenColor(int color, double fraction) {
+
+ //if (sharedPrefs.getBoolean("dark", false)) {
+ return (int) Math.max(color - (color * fraction), 0);
+ //}
+ // return (int)Math.min(color + (color * fraction), 255);
+ }
+
+
+ public void addArch(Canvas canvas, float offset, int color, float size) {
+ Paint paint = new Paint();
+ paint.setColor(color);
+ RectF rectTemp = new RectF(PADDING + offset - CIRCLE_WIDTH / 2, PADDING + offset - CIRCLE_WIDTH / 2, (displaySize.x - PADDING - offset + CIRCLE_WIDTH / 2), (displaySize.y - PADDING - offset + CIRCLE_WIDTH / 2));
+ canvas.drawArc(rectTemp, 270, size, true, paint);
+ }
+
+ public void addArch(Canvas canvas, float start, float offset, int color, float size) {
+ Paint paint = new Paint();
+ paint.setColor(color);
+ RectF rectTemp = new RectF(PADDING + offset - CIRCLE_WIDTH / 2, PADDING + offset - CIRCLE_WIDTH / 2, (displaySize.x - PADDING - offset + CIRCLE_WIDTH / 2), (displaySize.y - PADDING - offset + CIRCLE_WIDTH / 2));
+ canvas.drawArc(rectTemp, start + 270, size, true, paint);
+ }
+
+ public void addIndicator(Canvas canvas, float bg, int color) {
+ float convertedBg;
+ convertedBg = bgToAngle(bg);
+ convertedBg += 270;
+ Paint paint = new Paint();
+ paint.setColor(color);
+ float offset = 9;
+ RectF rectTemp = new RectF(PADDING + offset - CIRCLE_WIDTH / 2, PADDING + offset - CIRCLE_WIDTH / 2, (displaySize.x - PADDING - offset + CIRCLE_WIDTH / 2), (displaySize.y - PADDING - offset + CIRCLE_WIDTH / 2));
+ canvas.drawArc(rectTemp, convertedBg, 2, true, paint);
+ }
+
+ private float bgToAngle(float bg) {
+ if (bg > 100) {
+ return (((bg - 100f) / 300f) * 225f) + 135;
+ } else {
+ return ((bg / 100) * 135);
+ }
+ }
+
+
+ public void addReadingSoft(Canvas canvas, BgWatchData entry) {
+
+ Log.d("CircleWatchface", "addReadingSoft");
+ double size;
+ int color = Color.LTGRAY;
+ if (sharedPrefs.getBoolean("dark", false)) {
+ color = Color.DKGRAY;
+ }
+
+ float offsetMultiplier = (((displaySize.x / 2f) - PADDING) / 12f);
+ float offset = (float) Math.max(1, Math.ceil((new Date().getTime() - entry.timestamp) / (1000 * 60 * 5)));
+ size = bgToAngle((float) entry.sgv);
+ addArch(canvas, offset * offsetMultiplier + 10, color, (float) size);
+ addArch(canvas, (float) size, offset * offsetMultiplier + 10, getBackgroundColor(), (float) (360 - size));
+ addArch(canvas, (offset + .8f) * offsetMultiplier + 10, getBackgroundColor(), 360);
+ }
+
+ public void addReading(Canvas canvas, BgWatchData entry) {
+ Log.d("CircleWatchface", "addReading");
+
+ double size;
+ int color = Color.LTGRAY;
+ int indicatorColor = Color.DKGRAY;
+ if (sharedPrefs.getBoolean("dark", false)) {
+ color = Color.DKGRAY;
+ indicatorColor = Color.LTGRAY;
+ }
+ int barColor = Color.GRAY;
+ if (entry.sgv >= entry.high) {
+ indicatorColor = getHighColor();
+ barColor = darken(getHighColor(), .5);
+ } else if (entry.sgv <= entry.low) {
+ indicatorColor = getLowColor();
+ barColor = darken(getLowColor(), .5);
+ }
+ float offsetMultiplier = (((displaySize.x / 2f) - PADDING) / 12f);
+ float offset = (float) Math.max(1, Math.ceil((new Date().getTime() - entry.timestamp) / (1000 * 60 * 5)));
+ size = bgToAngle((float) entry.sgv);
+ addArch(canvas, offset * offsetMultiplier + 11, barColor, (float) size - 2); // Dark Color Bar
+ addArch(canvas, (float) size - 2, offset * offsetMultiplier + 11, indicatorColor, 2f); // Indicator at end of bar
+ addArch(canvas, (float) size, offset * offsetMultiplier + 11, color, (float) (360f - size)); // Dark fill
+ addArch(canvas, (offset + .8f) * offsetMultiplier + 11, getBackgroundColor(), 360);
+ }
+}
\ No newline at end of file
diff --git a/wear/src/main/java/info/nightscout/androidaps/Home.java b/wear/src/main/java/info/nightscout/androidaps/Home.java
new file mode 100644
index 0000000000..7d0e78fc3f
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/Home.java
@@ -0,0 +1,137 @@
+package info.nightscout.androidaps;
+
+import android.graphics.Color;
+import android.view.LayoutInflater;
+
+import com.ustwo.clockwise.WatchMode;
+
+import lecho.lib.hellocharts.util.Utils;
+
+public class Home extends BaseWatchFace {
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
+ layoutView = inflater.inflate(R.layout.activity_home, null);
+ performViewSetup();
+ }
+
+ protected void setColorDark() {
+ mTime.setTextColor(Color.WHITE);
+ mRelativeLayout.setBackgroundColor(Color.BLACK);
+ mLinearLayout.setBackgroundColor(Color.WHITE);
+ if (sgvLevel == 1) {
+ mSgv.setTextColor(Color.YELLOW);
+ mDirection.setTextColor(Color.YELLOW);
+ mDelta.setTextColor(Color.YELLOW);
+ } else if (sgvLevel == 0) {
+ mSgv.setTextColor(Color.WHITE);
+ mDirection.setTextColor(Color.WHITE);
+ mDelta.setTextColor(Color.WHITE);
+ } else if (sgvLevel == -1) {
+ mSgv.setTextColor(Color.RED);
+ mDirection.setTextColor(Color.RED);
+ mDelta.setTextColor(Color.RED);
+ }
+ if (ageLevel == 1) {
+ mTimestamp.setTextColor(Color.BLACK);
+ } else {
+ mTimestamp.setTextColor(Color.RED);
+ }
+
+ if (batteryLevel == 1) {
+ mUploaderBattery.setTextColor(Color.BLACK);
+ } else {
+ mUploaderBattery.setTextColor(Color.RED);
+ }
+ mRaw.setTextColor(Color.BLACK);
+ mStatus.setTextColor(Color.BLACK);
+ if (chart != null) {
+ highColor = Color.YELLOW;
+ lowColor = Color.RED;
+ midColor = Color.WHITE;
+ singleLine = false;
+ pointSize = 2;
+ setupCharts();
+ }
+
+ }
+
+
+ protected void setColorBright() {
+
+ if (getCurrentWatchMode() == WatchMode.INTERACTIVE) {
+ mRelativeLayout.setBackgroundColor(Color.WHITE);
+ mLinearLayout.setBackgroundColor(Color.BLACK);
+ if (sgvLevel == 1) {
+ mSgv.setTextColor(Utils.COLOR_ORANGE);
+ mDirection.setTextColor(Utils.COLOR_ORANGE);
+ mDelta.setTextColor(Utils.COLOR_ORANGE);
+ } else if (sgvLevel == 0) {
+ mSgv.setTextColor(Color.BLACK);
+ mDirection.setTextColor(Color.BLACK);
+ mDelta.setTextColor(Color.BLACK);
+ } else if (sgvLevel == -1) {
+ mSgv.setTextColor(Color.RED);
+ mDirection.setTextColor(Color.RED);
+ mDelta.setTextColor(Color.RED);
+ }
+
+ if (ageLevel == 1) {
+ mTimestamp.setTextColor(Color.WHITE);
+ } else {
+ mTimestamp.setTextColor(Color.RED);
+ }
+
+ if (batteryLevel == 1) {
+ mUploaderBattery.setTextColor(Color.WHITE);
+ } else {
+ mUploaderBattery.setTextColor(Color.RED);
+ }
+ mRaw.setTextColor(Color.WHITE);
+ mStatus.setTextColor(Color.WHITE);
+
+ mTime.setTextColor(Color.BLACK);
+ if (chart != null) {
+ highColor = Utils.COLOR_ORANGE;
+ midColor = Color.BLUE;
+ lowColor = Color.RED;
+ singleLine = false;
+ pointSize = 2;
+ setupCharts();
+ }
+ } else {
+ mRelativeLayout.setBackgroundColor(Color.BLACK);
+ mLinearLayout.setBackgroundColor(Color.WHITE);
+ if (sgvLevel == 1) {
+ mSgv.setTextColor(Color.YELLOW);
+ mDirection.setTextColor(Color.YELLOW);
+ mDelta.setTextColor(Color.YELLOW);
+ } else if (sgvLevel == 0) {
+ mSgv.setTextColor(Color.WHITE);
+ mDirection.setTextColor(Color.WHITE);
+ mDelta.setTextColor(Color.WHITE);
+ } else if (sgvLevel == -1) {
+ mSgv.setTextColor(Color.RED);
+ mDirection.setTextColor(Color.RED);
+ mDelta.setTextColor(Color.RED);
+ }
+ mRaw.setTextColor(Color.BLACK);
+ mStatus.setTextColor(Color.BLACK);
+ mUploaderBattery.setTextColor(Color.BLACK);
+ mTimestamp.setTextColor(Color.BLACK);
+
+ mTime.setTextColor(Color.WHITE);
+ if (chart != null) {
+ highColor = Color.YELLOW;
+ midColor = Color.WHITE;
+ lowColor = Color.RED;
+ singleLine = true;
+ pointSize = 2;
+ setupCharts();
+ }
+ }
+
+ }
+ }
diff --git a/wear/src/main/java/info/nightscout/androidaps/LargeHome.java b/wear/src/main/java/info/nightscout/androidaps/LargeHome.java
new file mode 100644
index 0000000000..bc5ccb6393
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/LargeHome.java
@@ -0,0 +1,113 @@
+package info.nightscout.androidaps;
+
+import android.graphics.Color;
+import android.view.LayoutInflater;
+
+import com.ustwo.clockwise.WatchMode;
+
+public class LargeHome extends BaseWatchFace {
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
+ layoutView = inflater.inflate(R.layout.activity_home_large, null);
+ performViewSetup();
+ }
+
+
+ @Override
+ protected void setColorDark(){
+ mTime.setTextColor(Color.WHITE);
+ mRelativeLayout.setBackgroundColor(Color.BLACK);
+ mLinearLayout.setBackgroundColor(Color.WHITE);
+ if (sgvLevel == 1) {
+ mSgv.setTextColor(Color.YELLOW);
+ mDirection.setTextColor(Color.YELLOW);
+ mDelta.setTextColor(Color.YELLOW);
+ } else if (sgvLevel == 0) {
+ mSgv.setTextColor(Color.WHITE);
+ mDirection.setTextColor(Color.WHITE);
+ mDelta.setTextColor(Color.WHITE);
+ } else if (sgvLevel == -1) {
+ mSgv.setTextColor(Color.RED);
+ mDirection.setTextColor(Color.RED);
+ mDelta.setTextColor(Color.RED);
+ }
+ if (ageLevel == 1) {
+ mTimestamp.setTextColor(Color.BLACK);
+ } else {
+ mTimestamp.setTextColor(Color.RED);
+ }
+
+ if (batteryLevel == 1) {
+ mUploaderBattery.setTextColor(Color.BLACK);
+ } else {
+ mUploaderBattery.setTextColor(Color.RED);
+ }
+
+ mRaw.setTextColor(Color.BLACK);
+ mStatus.setTextColor(Color.BLACK);
+
+ }
+
+
+
+ @Override
+ protected void setColorBright() {
+ if (getCurrentWatchMode() == WatchMode.INTERACTIVE) {
+ mRelativeLayout.setBackgroundColor(Color.WHITE);
+ mLinearLayout.setBackgroundColor(Color.BLACK);
+ if (sgvLevel == 1) {
+ mSgv.setTextColor(Color.YELLOW);
+ mDirection.setTextColor(Color.YELLOW);
+ mDelta.setTextColor(Color.YELLOW);
+ } else if (sgvLevel == 0) {
+ mSgv.setTextColor(Color.BLACK);
+ mDirection.setTextColor(Color.BLACK);
+ mDelta.setTextColor(Color.BLACK);
+ } else if (sgvLevel == -1) {
+ mSgv.setTextColor(Color.RED);
+ mDirection.setTextColor(Color.RED);
+ mDelta.setTextColor(Color.RED);
+ }
+
+ if (ageLevel == 1) {
+ mTimestamp.setTextColor(Color.WHITE);
+ } else {
+ mTimestamp.setTextColor(Color.RED);
+ }
+
+ if (batteryLevel == 1) {
+ mUploaderBattery.setTextColor(Color.WHITE);
+ } else {
+ mUploaderBattery.setTextColor(Color.RED);
+ }
+ mRaw.setTextColor(Color.WHITE);
+ mStatus.setTextColor(Color.WHITE);
+ mTime.setTextColor(Color.BLACK);
+ } else {
+ mRelativeLayout.setBackgroundColor(Color.BLACK);
+ mLinearLayout.setBackgroundColor(Color.LTGRAY);
+ if (sgvLevel == 1) {
+ mSgv.setTextColor(Color.YELLOW);
+ mDirection.setTextColor(Color.YELLOW);
+ mDelta.setTextColor(Color.YELLOW);
+ } else if (sgvLevel == 0) {
+ mSgv.setTextColor(Color.WHITE);
+ mDirection.setTextColor(Color.WHITE);
+ mDelta.setTextColor(Color.WHITE);
+ } else if (sgvLevel == -1) {
+ mSgv.setTextColor(Color.RED);
+ mDirection.setTextColor(Color.RED);
+ mDelta.setTextColor(Color.RED);
+ }
+
+ mUploaderBattery.setTextColor(Color.BLACK);
+ mTimestamp.setTextColor(Color.BLACK);
+ mRaw.setTextColor(Color.BLACK);
+ mStatus.setTextColor(Color.BLACK);
+ mTime.setTextColor(Color.WHITE);
+ }
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/ListenerService.java b/wear/src/main/java/info/nightscout/androidaps/ListenerService.java
new file mode 100644
index 0000000000..2011bcb414
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/ListenerService.java
@@ -0,0 +1,149 @@
+package info.nightscout.androidaps;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.v4.content.LocalBroadcastManager;
+
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.android.gms.wearable.DataEvent;
+import com.google.android.gms.wearable.DataEventBuffer;
+import com.google.android.gms.wearable.DataMap;
+import com.google.android.gms.wearable.DataMapItem;
+import com.google.android.gms.wearable.Node;
+import com.google.android.gms.wearable.NodeApi;
+import com.google.android.gms.wearable.Wearable;
+import com.google.android.gms.wearable.WearableListenerService;
+
+/**
+ * Created by stephenblack on 12/26/14.
+ */
+public class ListenerService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks,
+ GoogleApiClient.OnConnectionFailedListener {
+ private static final String WEARABLE_DATA_PATH = "/nightscout_watch_data";
+ private static final String WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend";
+ private static final String OPEN_SETTINGS = "/openwearsettings";
+ private static final String NEW_STATUS_PATH = "/sendstatustowear";
+
+ private static final String ACTION_RESEND = "com.dexdrip.stephenblack.nightwatch.RESEND_DATA";
+ private static final String ACTION_RESEND_BULK = "com.dexdrip.stephenblack.nightwatch.RESEND_BULK_DATA";
+ GoogleApiClient googleApiClient;
+ private long lastRequest = 0;
+
+ public class DataRequester extends AsyncTask {
+ Context mContext;
+
+ DataRequester(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ if (googleApiClient.isConnected()) {
+ if (System.currentTimeMillis() - lastRequest > 20 * 1000) { // enforce 20-second debounce period
+ lastRequest = System.currentTimeMillis();
+
+ NodeApi.GetConnectedNodesResult nodes =
+ Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
+ for (Node node : nodes.getNodes()) {
+ Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_RESEND_PATH, null);
+ }
+ }
+ } else
+ googleApiClient.connect();
+ return null;
+ }
+ }
+
+ public void requestData() {
+ new DataRequester(this).execute();
+ }
+
+ public void googleApiConnect() {
+ googleApiClient = new GoogleApiClient.Builder(this)
+ .addConnectionCallbacks(this)
+ .addOnConnectionFailedListener(this)
+ .addApi(Wearable.API)
+ .build();
+ Wearable.MessageApi.addListener(googleApiClient, this);
+ }
+
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (intent != null && ACTION_RESEND.equals(intent.getAction())) {
+ googleApiConnect();
+ requestData();
+ }
+ return START_STICKY;
+ }
+
+ @Override
+ public void onDataChanged(DataEventBuffer dataEvents) {
+
+ DataMap dataMap;
+
+ for (DataEvent event : dataEvents) {
+
+ if (event.getType() == DataEvent.TYPE_CHANGED) {
+
+
+ String path = event.getDataItem().getUri().getPath();
+ if (path.equals(OPEN_SETTINGS)) {
+ //TODO: OpenSettings
+ Intent intent = new Intent(this, NWPreferences.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
+
+ } else if (path.equals(NEW_STATUS_PATH)){
+ dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
+ Intent messageIntent = new Intent();
+ messageIntent.setAction(Intent.ACTION_SEND);
+ messageIntent.putExtra("status", dataMap.toBundle());
+ LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
+
+ } else {
+ dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
+ Intent messageIntent = new Intent();
+ messageIntent.setAction(Intent.ACTION_SEND);
+ messageIntent.putExtra("data", dataMap.toBundle());
+ LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
+ }
+ }
+ }
+ }
+
+ public static void requestData(Context context) {
+ Intent intent = new Intent(context, ListenerService.class);
+ intent.setAction(ACTION_RESEND);
+ context.startService(intent);
+ }
+
+ @Override
+ public void onConnected(Bundle bundle) {
+ requestData();
+ }
+
+ @Override
+ public void onConnectionSuspended(int i) {
+
+ }
+
+ @Override
+ public void onConnectionFailed(ConnectionResult connectionResult) {
+
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (googleApiClient != null && googleApiClient.isConnected()) {
+ googleApiClient.disconnect();
+ }
+ if (googleApiClient != null) {
+ Wearable.MessageApi.removeListener(googleApiClient, this);
+ }
+ }
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/NWPreferences.java b/wear/src/main/java/info/nightscout/androidaps/NWPreferences.java
new file mode 100644
index 0000000000..cd32e46599
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/NWPreferences.java
@@ -0,0 +1,18 @@
+package info.nightscout.androidaps;
+
+
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+import info.nightscout.androidaps.R;
+
+public class NWPreferences extends PreferenceActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ // TODO Auto-generated method stub
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.preferences);
+ }
+
+}
\ No newline at end of file
diff --git a/wear/src/main/res/drawable-hdpi/ic_launcher.png b/wear/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000000..55621cc107
Binary files /dev/null and b/wear/src/main/res/drawable-hdpi/ic_launcher.png differ
diff --git a/wear/src/main/res/drawable-mdpi/ic_launcher.png b/wear/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000000..11ec2068be
Binary files /dev/null and b/wear/src/main/res/drawable-mdpi/ic_launcher.png differ
diff --git a/wear/src/main/res/drawable-nodpi/ic_icon.png b/wear/src/main/res/drawable-nodpi/ic_icon.png
new file mode 100755
index 0000000000..700e274f5b
Binary files /dev/null and b/wear/src/main/res/drawable-nodpi/ic_icon.png differ
diff --git a/wear/src/main/res/drawable-xhdpi/ic_launcher.png b/wear/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000000..7c02b784aa
Binary files /dev/null and b/wear/src/main/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/wear/src/main/res/drawable-xxhdpi/ic_launcher.png b/wear/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000000..915d914413
Binary files /dev/null and b/wear/src/main/res/drawable-xxhdpi/ic_launcher.png differ
diff --git a/wear/src/main/res/drawable/ic_icon.png b/wear/src/main/res/drawable/ic_icon.png
new file mode 100644
index 0000000000..d65498c609
Binary files /dev/null and b/wear/src/main/res/drawable/ic_icon.png differ
diff --git a/wear/src/main/res/drawable/watchface_bigchart.png b/wear/src/main/res/drawable/watchface_bigchart.png
new file mode 100644
index 0000000000..34d267e45e
Binary files /dev/null and b/wear/src/main/res/drawable/watchface_bigchart.png differ
diff --git a/wear/src/main/res/drawable/watchface_circle.png b/wear/src/main/res/drawable/watchface_circle.png
new file mode 100644
index 0000000000..d33ae99fd4
Binary files /dev/null and b/wear/src/main/res/drawable/watchface_circle.png differ
diff --git a/wear/src/main/res/drawable/watchface_dark.png b/wear/src/main/res/drawable/watchface_dark.png
new file mode 100644
index 0000000000..9ad14f52a1
Binary files /dev/null and b/wear/src/main/res/drawable/watchface_dark.png differ
diff --git a/wear/src/main/res/drawable/watchface_graph.png b/wear/src/main/res/drawable/watchface_graph.png
new file mode 100644
index 0000000000..af9e88a227
Binary files /dev/null and b/wear/src/main/res/drawable/watchface_graph.png differ
diff --git a/wear/src/main/res/layout/activity_bigchart.xml b/wear/src/main/res/layout/activity_bigchart.xml
new file mode 100644
index 0000000000..1fa3cdad8d
--- /dev/null
+++ b/wear/src/main/res/layout/activity_bigchart.xml
@@ -0,0 +1,12 @@
+
+
diff --git a/wear/src/main/res/layout/activity_home.xml b/wear/src/main/res/layout/activity_home.xml
new file mode 100644
index 0000000000..152f7869a6
--- /dev/null
+++ b/wear/src/main/res/layout/activity_home.xml
@@ -0,0 +1,12 @@
+
+
diff --git a/wear/src/main/res/layout/activity_home_large.xml b/wear/src/main/res/layout/activity_home_large.xml
new file mode 100644
index 0000000000..3af188265c
--- /dev/null
+++ b/wear/src/main/res/layout/activity_home_large.xml
@@ -0,0 +1,12 @@
+
+
diff --git a/wear/src/main/res/layout/modern_layout.xml b/wear/src/main/res/layout/modern_layout.xml
new file mode 100644
index 0000000000..835dcfc40d
--- /dev/null
+++ b/wear/src/main/res/layout/modern_layout.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/wear/src/main/res/layout/rect_activity_bigchart.xml b/wear/src/main/res/layout/rect_activity_bigchart.xml
new file mode 100644
index 0000000000..511ac6dfc9
--- /dev/null
+++ b/wear/src/main/res/layout/rect_activity_bigchart.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wear/src/main/res/layout/rect_activity_home.xml b/wear/src/main/res/layout/rect_activity_home.xml
new file mode 100644
index 0000000000..344321fea6
--- /dev/null
+++ b/wear/src/main/res/layout/rect_activity_home.xml
@@ -0,0 +1,157 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wear/src/main/res/layout/rect_activity_home_large.xml b/wear/src/main/res/layout/rect_activity_home_large.xml
new file mode 100644
index 0000000000..20cc6ee40f
--- /dev/null
+++ b/wear/src/main/res/layout/rect_activity_home_large.xml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wear/src/main/res/layout/round_activity_bigchart.xml b/wear/src/main/res/layout/round_activity_bigchart.xml
new file mode 100644
index 0000000000..c2d7646bdf
--- /dev/null
+++ b/wear/src/main/res/layout/round_activity_bigchart.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wear/src/main/res/layout/round_activity_home.xml b/wear/src/main/res/layout/round_activity_home.xml
new file mode 100644
index 0000000000..231a0910b8
--- /dev/null
+++ b/wear/src/main/res/layout/round_activity_home.xml
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wear/src/main/res/layout/round_activity_home_large.xml b/wear/src/main/res/layout/round_activity_home_large.xml
new file mode 100644
index 0000000000..6217af3a5c
--- /dev/null
+++ b/wear/src/main/res/layout/round_activity_home_large.xml
@@ -0,0 +1,138 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wear/src/main/res/values/strings.xml b/wear/src/main/res/values/strings.xml
new file mode 100644
index 0000000000..2462ff00a4
--- /dev/null
+++ b/wear/src/main/res/values/strings.xml
@@ -0,0 +1,22 @@
+
+
+
+ AAPS Prefs.
+
+
+ - 1 hour
+ - 2 hours
+ - 3 hours
+ - 4 hours
+ - 5 hours
+
+
+
+ - 1
+ - 2
+ - 3
+ - 4
+ - 5
+
+
+
diff --git a/wear/src/main/res/xml/preferences.xml b/wear/src/main/res/xml/preferences.xml
new file mode 100644
index 0000000000..c3e40eb052
--- /dev/null
+++ b/wear/src/main/res/xml/preferences.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/wear/src/main/res/xml/watch_face.xml b/wear/src/main/res/xml/watch_face.xml
new file mode 100644
index 0000000000..699f0562ca
--- /dev/null
+++ b/wear/src/main/res/xml/watch_face.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file