diff --git a/wear/build.gradle b/wear/build.gradle index 241fedbe9a..26779263e2 100644 --- a/wear/build.gradle +++ b/wear/build.gradle @@ -27,6 +27,7 @@ android { resValue "string", "label_xdrip", "AAPS" resValue "string", "label_xdrip_large", "AAPS(Large)" resValue "string", "label_xdrip_big_chart", "AAPS(BigChart)" + resValue "string", "label_xdrip_no_chart", "AAPS(NoChart)" resValue "string", "label_xdrip_circle", "AAPS(Circle)" resValue "string", "label_xdrip_activity", "AAPS Prefs." resValue "string", "app_settings", "AAPS Settings" @@ -39,6 +40,7 @@ android { resValue "string", "label_xdrip", "AAPS" resValue "string", "label_xdrip_large", "AAPS(Large)" resValue "string", "label_xdrip_big_chart", "AAPS(BigChart)" + resValue "string", "label_xdrip_no_chart", "AAPS(NoChart)" resValue "string", "label_xdrip_circle", "AAPS(Circle)" resValue "string", "label_xdrip_activity", "AAPS Prefs." resValue "string", "app_settings", "AAPS Settings" diff --git a/wear/src/main/AndroidManifest.xml b/wear/src/main/AndroidManifest.xml index 8909f8a3f8..fc40e930cd 100644 --- a/wear/src/main/AndroidManifest.xml +++ b/wear/src/main/AndroidManifest.xml @@ -34,6 +34,24 @@ + + + + + + + + + + bgDataList = new ArrayList<>(); + public ArrayList tempWatchDataList = new ArrayList<>(); + public ArrayList basalWatchDataList = new ArrayList<>(); + public PowerManager.WakeLock wakeLock; + 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 sgvString = "--"; + private String externalStatusString = "no status"; + private TextView statusView; + private long sgvTapTime = 0l; + + @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_nochart, 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); + mAvgDelta = (TextView) stub.findViewById(R.id.avgdelta); + mRelativeLayout = (RelativeLayout) stub.findViewById(R.id.main_layout); + statusView = (TextView) stub.findViewById(R.id.aps_status); + layoutSet = true; + showAgeAndStatus(); + mRelativeLayout.measure(specW, specH); + mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(), + mRelativeLayout.getMeasuredHeight()); + } + }); + ListenerService.requestData(this); + wakeLock.acquire(50); + } + + @Override + protected void onTapCommand(int tapType, int x, int y, long eventTime) { + + int extra = mSgv!=null?(mSgv.getRight() - mSgv.getLeft())/2:0; + + if (tapType == TAP_TYPE_TAP&& + x + extra >=mSgv.getLeft() && + x - extra <= mSgv.getRight()&& + y >= mSgv.getTop() && + y <= mSgv.getBottom()){ + if (eventTime - sgvTapTime < 800){ + Intent intent = new Intent(this, MainMenuActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } + sgvTapTime = eventTime; + } + } + + protected void onWatchModeChanged(WatchMode watchMode) { + + if(lowResMode ^ isLowRes(watchMode)){ //if there was a change in lowResMode + lowResMode = isLowRes(watchMode); + setColor(); + } else if (! sharedPrefs.getBoolean("dark", true)){ + //in bright mode: different colours if active: + setColor(); + } + } + + private boolean isLowRes(WatchMode watchMode) { + return (watchMode == WatchMode.LOW_BIT) || (watchMode == WatchMode.LOW_BIT_BURN_IN) || (watchMode == WatchMode.LOW_BIT_BURN_IN); + } + + + @Override + protected WatchFaceStyle getWatchFaceStyle(){ + return new WatchFaceStyle.Builder(this).setAcceptsTapEvents(true).build(); + } + + + + 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(NOChart.this); + mTime.setText(timeFormat.format(System.currentTimeMillis())); + showAgeAndStatus(); + + 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 (layoutSet && bundle !=null) { + DataMap dataMap = DataMap.fromBundle(bundle); + wakeLock.acquire(50); + sgvLevel = dataMap.getLong("sgvLevel"); + batteryLevel = dataMap.getInt("batteryLevel"); + datetime = dataMap.getDouble("timestamp"); + sgvString = dataMap.getString("sgvString"); + 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(NOChart.this); + mTime.setText(timeFormat.format(System.currentTimeMillis())); + + showAgeAndStatus(); + + String delta = dataMap.getString("delta"); + + if (delta.endsWith(" mg/dl")) { + mDelta.setText(delta.substring(0, delta.length() - 6)); + } else if (delta.endsWith(" mmol/l")||delta.endsWith(" mmol")) { + mDelta.setText(delta.substring(0, delta.length() - 5)); + } else { + mDelta.setText(delta); + } + + + String avgDelta = dataMap.getString("avgDelta"); + + if (delta.endsWith(" mg/dl")) { + mAvgDelta.setText(avgDelta.substring(0, avgDelta.length() - 6)); + } else if (avgDelta.endsWith(" mmol/l")||avgDelta.endsWith(" mmol")) { + mAvgDelta.setText(avgDelta.substring(0, avgDelta.length() - 5)); + } else { + mAvgDelta.setText(avgDelta); + } + + 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 (!lowResMode && (sharedPrefs.getBoolean("animation", false) && dataMap.getDataMapArrayList("entries") == null && (sgvString.equals("100") || sgvString.equals("5.5") || sgvString.equals("5,5")))) { + startAnimation(); + } + } + //status + bundle = intent.getBundleExtra("status"); + if (layoutSet && bundle != null) { + DataMap dataMap = DataMap.fromBundle(bundle); + wakeLock.acquire(50); + externalStatusString = dataMap.getString("externalStatusString"); + + showAgeAndStatus(); + + mRelativeLayout.measure(specW, specH); + mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(), + mRelativeLayout.getMeasuredHeight()); + invalidate(); + setColor(); + } + //basals and temps + bundle = intent.getBundleExtra("basals"); + if (layoutSet && bundle != null) { + DataMap dataMap = DataMap.fromBundle(bundle); + wakeLock.acquire(500); + + loadBasalsAndTemps(dataMap); + + mRelativeLayout.measure(specW, specH); + mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(), + mRelativeLayout.getMeasuredHeight()); + invalidate(); + setColor(); + } + } + } + + 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); + } + } + } + + private void showAgeAndStatus() { + + if( mTimestamp != null){ + mTimestamp.setText(readingAge(true)); + } + boolean showAvgDelta = sharedPrefs.getBoolean("showAvgDelta", true); + + if(showAvgDelta){ + mAvgDelta.setVisibility(View.VISIBLE); + } else { + mAvgDelta.setVisibility(View.GONE); + } + statusView.setText(externalStatusString); + statusView.setVisibility(View.VISIBLE); + } + + public void setColor() { + if(lowResMode){ + setColorLowRes(); + } else if (sharedPrefs.getBoolean("dark", true)) { + setColorDark(); + } else { + setColorBright(); + } + + } + + + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key){ + setColor(); + if(layoutSet){ + showAgeAndStatus(); + 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 void setIsAnimated(boolean isAnimated) { + this.isAnimated = isAnimated; + } + + void startAnimation() { + Log.d("CircleWatchface", "start startAnimation"); + + Thread animator = new Thread() { + + + public void run() { + 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 setColorLowRes() { + mTime.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_mTime)); + statusView.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_statusView)); + mRelativeLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_background)); + mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor)); + mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor)); + mAvgDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor)); + mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_Timestamp)); + } + + protected void setColorDark() { + mTime.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_mTime)); + statusView.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_statusView)); + mRelativeLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_background)); + if (sgvLevel == 1) { + mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor)); + mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor)); + mAvgDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor)); + } else if (sgvLevel == 0) { + mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor)); + mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor)); + mAvgDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor)); + } else if (sgvLevel == -1) { + mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor)); + mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor)); + mAvgDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor)); + } + + if (ageLevel == 1) { + mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_Timestamp)); + } else { + mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_TimestampOld)); + } + } + + + protected void setColorBright() { + + if (getCurrentWatchMode() == WatchMode.INTERACTIVE) { + mTime.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_bigchart_time)); + statusView.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_bigchart_status)); + mRelativeLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.light_background)); + if (sgvLevel == 1) { + mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor)); + mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor)); + mAvgDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor)); + } else if (sgvLevel == 0) { + mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor)); + mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor)); + mAvgDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor)); + } else if (sgvLevel == -1) { + mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor)); + mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor)); + mAvgDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor)); + } + + if (ageLevel == 1) { + mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_mTimestamp1)); + } else { + mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_mTimestamp)); + } + } else { + setColorDark(); + } + } + + public void missedReadingAlert() { + int minutes_since = (int) Math.floor(timeSince()/(1000*60)); + if(minutes_since >= 16 && ((minutes_since - 16) % 5) == 0) { + ListenerService.requestData(this); // attempt endTime recover missing data + } + } +} \ No newline at end of file diff --git a/wear/src/main/res/drawable/watchface_nochart.png b/wear/src/main/res/drawable/watchface_nochart.png new file mode 100755 index 0000000000..c0e9e67747 Binary files /dev/null and b/wear/src/main/res/drawable/watchface_nochart.png differ diff --git a/wear/src/main/res/layout/activity_nochart.xml b/wear/src/main/res/layout/activity_nochart.xml new file mode 100644 index 0000000000..4b7198aa78 --- /dev/null +++ b/wear/src/main/res/layout/activity_nochart.xml @@ -0,0 +1,12 @@ + + diff --git a/wear/src/main/res/layout/rect_activity_nochart.xml b/wear/src/main/res/layout/rect_activity_nochart.xml new file mode 100644 index 0000000000..47938873b2 --- /dev/null +++ b/wear/src/main/res/layout/rect_activity_nochart.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/wear/src/main/res/layout/round_activity_nochart.xml b/wear/src/main/res/layout/round_activity_nochart.xml new file mode 100644 index 0000000000..47938873b2 --- /dev/null +++ b/wear/src/main/res/layout/round_activity_nochart.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +