This commit is contained in:
Milos Kozak 2022-05-02 21:54:37 +02:00
parent 416f512a52
commit 8ce4a7d716
25 changed files with 332 additions and 336 deletions

View file

@ -68,8 +68,8 @@ class DataHandlerWear @Inject constructor(
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtras(
Bundle().also { bundle ->
bundle.putString("title", it.title)
bundle.putString("message", it.message)
bundle.putString(DataLayerListenerServiceWear.KEY_TITLE, it.title)
bundle.putString(DataLayerListenerServiceWear.KEY_MESSAGE, it.message)
bundle.putString(DataLayerListenerServiceWear.KEY_ACTION_DATA, it.returnCommand?.serialize())
}
)
@ -123,11 +123,7 @@ class DataHandlerWear @Inject constructor(
.subscribe {
aapsLogger.debug(LTag.WEAR, "Status received from ${it.sourceNodeId}")
persistence.store(it)
LocalBroadcastManager.getInstance(context).sendBroadcast(
Intent(DataLayerListenerServiceWear.INTENT_NEW_DATA).apply {
putExtra(DataLayerListenerServiceWear.KEY_STATUS_DATA, it.serialize())
}
)
LocalBroadcastManager.getInstance(context).sendBroadcast(Intent(DataLayerListenerServiceWear.INTENT_NEW_DATA))
}
disposable += rxBus
.toObservable(EventData.SingleBg::class.java)
@ -135,11 +131,6 @@ class DataHandlerWear @Inject constructor(
.subscribe {
aapsLogger.debug(LTag.WEAR, "SingleBg received from ${it.sourceNodeId}")
persistence.store(it)
LocalBroadcastManager.getInstance(context).sendBroadcast(
Intent(DataLayerListenerServiceWear.INTENT_NEW_DATA).apply {
putExtra(DataLayerListenerServiceWear.KEY_SINGLE_BG_DATA, it.serialize())
}
)
}
disposable += rxBus
.toObservable(EventData.GraphData::class.java)
@ -147,11 +138,6 @@ class DataHandlerWear @Inject constructor(
.subscribe {
aapsLogger.debug(LTag.WEAR, "GraphData received from ${it.sourceNodeId}")
persistence.store(it)
LocalBroadcastManager.getInstance(context).sendBroadcast(
Intent(DataLayerListenerServiceWear.INTENT_NEW_DATA).apply {
putExtra(DataLayerListenerServiceWear.KEY_GRAPH_DATA, it.serialize())
}
)
}
disposable += rxBus
.toObservable(EventData.TreatmentData::class.java)
@ -159,11 +145,6 @@ class DataHandlerWear @Inject constructor(
.subscribe {
aapsLogger.debug(LTag.WEAR, "TreatmentData received from ${it.sourceNodeId}")
persistence.store(it)
LocalBroadcastManager.getInstance(context).sendBroadcast(
Intent(DataLayerListenerServiceWear.INTENT_NEW_DATA).apply {
putExtra(DataLayerListenerServiceWear.KEY_TREATMENTS_DATA, it.serialize())
}
)
}
disposable += rxBus
.toObservable(EventData.Preferences::class.java)
@ -282,8 +263,8 @@ class DataHandlerWear @Inject constructor(
val intent = Intent(context, AcceptActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtras(Bundle().also { bundle ->
bundle.putString("title", command.title)
bundle.putString("message", command.message)
bundle.putString(DataLayerListenerServiceWear.KEY_TITLE, command.title)
bundle.putString(DataLayerListenerServiceWear.KEY_MESSAGE, command.message)
bundle.putString(DataLayerListenerServiceWear.KEY_ACTION_DATA, command.returnCommand?.serialize())
})
}

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.comm
import android.app.NotificationManager
import android.content.Intent
import android.os.Handler
import android.os.HandlerThread
@ -100,6 +101,9 @@ class DataLayerListenerServiceWear : WearableListenerService() {
aapsLogger.debug(LTag.WEAR, "onMessageReceived: ${String(messageEvent.data)}")
val command = EventData.deserialize(String(messageEvent.data))
rxBus.send(command.also { it.sourceNodeId = messageEvent.sourceNodeId })
// Use this sender
transcriptionNodeId = messageEvent.sourceNodeId
aapsLogger.debug(LTag.WEAR, "Updated node: $transcriptionNodeId")
}
}
}
@ -114,6 +118,8 @@ class DataLayerListenerServiceWear : WearableListenerService() {
rxBus.send(EventWearToMobile(EventData.CancelBolus(System.currentTimeMillis())))
}
INTENT_WEAR_TO_MOBILE -> sendMessage(rxPath, intent.extras?.getString(KEY_ACTION_DATA))
INTENT_CANCEL_NOTIFICATION -> (getSystemService(NOTIFICATION_SERVICE) as NotificationManager).cancel(CHANGE_NOTIF_ID)
}
return START_STICKY
}
@ -125,7 +131,7 @@ class DataLayerListenerServiceWear : WearableListenerService() {
capabilityClient.getCapability(PHONE_CAPABILITY, CapabilityClient.FILTER_REACHABLE)
)
aapsLogger.debug(LTag.WEAR, "Nodes: ${capabilityInfo.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}")
transcriptionNodeId = pickBestNodeId(capabilityInfo.nodes)
pickBestNodeId(capabilityInfo.nodes)?.let { transcriptionNodeId = it }
aapsLogger.debug(LTag.WEAR, "Selected node: $transcriptionNodeId")
}
@ -156,16 +162,16 @@ class DataLayerListenerServiceWear : WearableListenerService() {
}
private fun sendMessage(path: String, data: String?) {
aapsLogger.debug(LTag.WEAR, "sendMessage: $path $data")
transcriptionNodeId?.also { nodeId ->
aapsLogger.debug(LTag.WEAR, "sendMessage: $path $data")
messageClient
.sendMessage(nodeId, path, data?.toByteArray() ?: byteArrayOf()).apply {
addOnSuccessListener { }
addOnFailureListener {
aapsLogger.debug(LTag.WEAR, "sendMessage: $path failure")
}
aapsLogger.debug(LTag.WEAR, "sendMessage: $path failure $it")
}
}
} ?: aapsLogger.debug(LTag.WEAR, "sendMessage: Ignoring message. No node selected.")
}
@Suppress("unused")
@ -187,17 +193,16 @@ class DataLayerListenerServiceWear : WearableListenerService() {
const val PHONE_CAPABILITY = "androidaps_mobile"
// Accepted intents
val INTENT_CANCEL_BOLUS = DataLayerListenerServiceWear::class.java.name + ".CancelBolus"
val INTENT_NEW_DATA = DataLayerListenerServiceWear::class.java.name + ".NewData"
val INTENT_CANCEL_BOLUS = DataLayerListenerServiceWear::class.java.name + ".CancelBolus"
val INTENT_WEAR_TO_MOBILE = DataLayerListenerServiceWear::class.java.name + ".WearToMobile"
val INTENT_CANCEL_NOTIFICATION = DataLayerListenerServiceWear::class.java.name + ".CancelNotification"
//data keys
const val KEY_ACTION_DATA = "actionData"
const val KEY_ACTION = "action"
const val KEY_MESSAGE = "message"
const val KEY_SINGLE_BG_DATA = "single_bg_data"
const val KEY_TREATMENTS_DATA = "treatments_data"
const val KEY_GRAPH_DATA = "graph_data"
const val KEY_STATUS_DATA = "status_data"
const val KEY_TITLE = "title"
const val BOLUS_PROGRESS_NOTIF_ID = 1
const val CONFIRM_NOTIF_ID = 2

View file

@ -0,0 +1,11 @@
package info.nightscout.androidaps.comm
import android.content.Context
import android.content.Intent
class IntentCancelNotification(context: Context) : Intent(context, DataLayerListenerServiceWear::class.java) {
init {
action = DataLayerListenerServiceWear.INTENT_CANCEL_NOTIFICATION
addFlags(FLAG_ACTIVITY_NEW_TASK)
}
}

View file

@ -0,0 +1,19 @@
package info.nightscout.androidaps.comm
import android.content.Context
import android.content.Intent
import android.os.Bundle
import info.nightscout.shared.weardata.EventData
class IntentWearToMobile(context: Context, command: String) : Intent(context, DataLayerListenerServiceWear::class.java) {
init {
action = DataLayerListenerServiceWear.INTENT_WEAR_TO_MOBILE
addFlags(FLAG_ACTIVITY_NEW_TASK)
putExtras(Bundle().also { bundle ->
bundle.putString(DataLayerListenerServiceWear.KEY_ACTION_DATA, command)
})
}
@Suppress("unused")
constructor(context: Context, command: EventData) : this(context, command.serialize())
}

View file

@ -40,6 +40,7 @@ import info.nightscout.shared.weardata.EventData;
* <p>
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public abstract class BaseComplicationProviderService extends ComplicationProviderService {
@Inject Inevitable inevitable;
@ -56,9 +57,6 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
super.onCreate();
}
public static final String KEY_COMPLICATIONS = "complications";
private static final String KEY_LAST_SHOWN_SINCE_VALUE = "lastSince";
private static final String KEY_STALE_REPORTED = "staleReported";
private static final String TASK_ID_REFRESH_COMPLICATION = "refresh-complication";
@ -201,7 +199,7 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
persistence.putString("complication_" + complicationId, getProviderCanonicalName());
persistence.putBoolean("complication_" + complicationId + "_since", usesSinceField());
persistence.addToSet(KEY_COMPLICATIONS, "complication_" + complicationId);
persistence.addToSet(Persistence.KEY_COMPLICATIONS, "complication_" + complicationId);
IntentFilter messageFilter = new IntentFilter(DataLayerListenerServiceWear.Companion.getINTENT_NEW_DATA());
@ -237,15 +235,15 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
getApplicationContext(), thisProvider, complicationId, getComplicationAction());
final RawDisplayData raw = new RawDisplayData();
raw.updateForComplicationsFromPersistence(persistence);
raw.updateFromPersistence(persistence);
aapsLogger.warn(LTag.WEAR, "Complication data: " + raw.toDebugString());
// store what is currently rendered in 'SGV since' field, to detect if it was changed and need update
persistence.putString(KEY_LAST_SHOWN_SINCE_VALUE,
persistence.putString(Persistence.KEY_LAST_SHOWN_SINCE_VALUE,
displayFormat.shortTimeSince(raw.getSingleBg().getTimeStamp()));
// by each render we clear stale flag to ensure it is re-rendered at next refresh detection round
persistence.putBoolean(KEY_STALE_REPORTED, false);
persistence.putBoolean(Persistence.KEY_STALE_REPORTED, false);
ComplicationData complicationData;
@ -280,7 +278,7 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
public void onComplicationDeactivated(int complicationId) {
aapsLogger.warn(LTag.WEAR, "onComplicationDeactivated(): " + complicationId);
persistence.removeFromSet(KEY_COMPLICATIONS, "complication_" + complicationId);
persistence.removeFromSet(Persistence.KEY_COMPLICATIONS, "complication_" + complicationId);
if (localBroadcastManager != null && messageReceiver != null) {
localBroadcastManager.unregisterReceiver(messageReceiver);
@ -297,7 +295,7 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
*/
public void checkIfUpdateNeeded() {
aapsLogger.warn(LTag.WEAR, "Pending check if update needed - " + persistence.getString(KEY_COMPLICATIONS, ""));
aapsLogger.warn(LTag.WEAR, "Pending check if update needed - " + persistence.getString(Persistence.KEY_COMPLICATIONS, ""));
inevitable.task(TASK_ID_REFRESH_COMPLICATION, 15 * Constants.SECOND_IN_MS, () -> {
if (wearUtil.isBelowRateLimit("complication-checkIfUpdateNeeded", 5)) {
@ -316,19 +314,19 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
*/
private void requestUpdateIfSinceChanged() {
final RawDisplayData raw = new RawDisplayData();
raw.updateForComplicationsFromPersistence(persistence);
raw.updateFromPersistence(persistence);
final String lastSince = persistence.getString(KEY_LAST_SHOWN_SINCE_VALUE, "-");
final String lastSince = persistence.getString(Persistence.KEY_LAST_SHOWN_SINCE_VALUE, "-");
final String calcSince = displayFormat.shortTimeSince(raw.getSingleBg().getTimeStamp());
final boolean isStale = (wearUtil.msSince(persistence.whenDataUpdated()) > Constants.STALE_MS)
|| (wearUtil.msSince(raw.getSingleBg().getTimeStamp()) > Constants.STALE_MS);
final boolean staleWasRefreshed = persistence.getBoolean(KEY_STALE_REPORTED, false);
final boolean staleWasRefreshed = persistence.getBoolean(Persistence.KEY_STALE_REPORTED, false);
final boolean sinceWasChanged = !lastSince.equals(calcSince);
if (sinceWasChanged || (isStale && !staleWasRefreshed)) {
persistence.putString(KEY_LAST_SHOWN_SINCE_VALUE, calcSince);
persistence.putBoolean(KEY_STALE_REPORTED, isStale);
persistence.putString(Persistence.KEY_LAST_SHOWN_SINCE_VALUE, calcSince);
persistence.putBoolean(Persistence.KEY_STALE_REPORTED, isStale);
aapsLogger.warn(LTag.WEAR, "Detected refresh of time needed! Reason: "
+ (isStale ? "- stale detected" : "")
@ -367,7 +365,7 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
*/
private Set<String> getActiveProviderClasses() {
Set<String> providers = new HashSet<>();
Set<String> complications = persistence.getSetOf(KEY_COMPLICATIONS);
Set<String> complications = persistence.getSetOf(Persistence.KEY_COMPLICATIONS);
for (String complication : complications) {
final String providerClass = persistence.getString(complication, "");
if (providerClass.length() > 0) {
@ -384,7 +382,7 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
*/
private Set<String> getSinceDependingProviderClasses() {
Set<String> providers = new HashSet<>();
Set<String> complications = persistence.getSetOf(KEY_COMPLICATIONS);
Set<String> complications = persistence.getSetOf(Persistence.KEY_COMPLICATIONS);
for (String complication : complications) {
final String providerClass = persistence.getString(complication, "");
final boolean dependOnSince = persistence.getBoolean(complication + "_since", false);
@ -401,7 +399,12 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
public class MessageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Set<String> complications = persistence.getSetOf(KEY_COMPLICATIONS);
updateAll();
}
}
private void updateAll() {
Set<String> complications = persistence.getSetOf(Persistence.KEY_COMPLICATIONS);
if (complications.size() > 0) {
checkIfUpdateNeeded();
// We request all active providers
@ -409,6 +412,3 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
}
}
}
}

View file

@ -15,6 +15,7 @@ import info.nightscout.shared.logging.LTag;
/*
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public class BrCobIobComplication extends BaseComplicationProviderService {
@Inject DisplayFormat displayFormat;

View file

@ -11,6 +11,7 @@ import info.nightscout.shared.logging.LTag;
/*
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public class CobDetailedComplication extends BaseComplicationProviderService {
public ComplicationData buildComplicationData(int dataType, RawDisplayData raw, PendingIntent complicationPendingIntent) {

View file

@ -12,6 +12,7 @@ import info.nightscout.shared.logging.LTag;
/*
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public class CobIconComplication extends BaseComplicationProviderService {
public ComplicationData buildComplicationData(int dataType, RawDisplayData raw, PendingIntent complicationPendingIntent) {

View file

@ -11,6 +11,7 @@ import info.nightscout.shared.logging.LTag;
/*
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public class CobIobComplication extends BaseComplicationProviderService {
public ComplicationData buildComplicationData(int dataType, RawDisplayData raw, PendingIntent complicationPendingIntent) {

View file

@ -29,6 +29,7 @@ import info.nightscout.shared.sharedPreferences.SP;
/*
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public class ComplicationTapBroadcastReceiver extends DaggerBroadcastReceiver {
@Inject WearUtil wearUtil;

View file

@ -11,6 +11,7 @@ import info.nightscout.shared.logging.LTag;
/*
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public class IobDetailedComplication extends BaseComplicationProviderService {
public ComplicationData buildComplicationData(int dataType, RawDisplayData raw, PendingIntent complicationPendingIntent) {

View file

@ -13,6 +13,7 @@ import info.nightscout.shared.logging.LTag;
/*
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public class IobIconComplication extends BaseComplicationProviderService {
public ComplicationData buildComplicationData(int dataType, RawDisplayData raw, PendingIntent complicationPendingIntent) {

View file

@ -14,6 +14,7 @@ import info.nightscout.shared.logging.LTag;
/*
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public class LongStatusComplication extends BaseComplicationProviderService {
@Inject DisplayFormat displayFormat;

View file

@ -14,6 +14,7 @@ import info.nightscout.shared.logging.LTag;
/*
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public class LongStatusFlippedComplication extends BaseComplicationProviderService {
@Inject DisplayFormat displayFormat;

View file

@ -14,6 +14,7 @@ import info.nightscout.shared.logging.LTag;
/*
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public class SgvComplication extends BaseComplicationProviderService {
@Inject DisplayFormat displayFormat;

View file

@ -14,6 +14,7 @@ import info.nightscout.shared.logging.LTag;
/*
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public class UploaderBatteryComplication extends BaseComplicationProviderService {
public ComplicationData buildComplicationData(int dataType, RawDisplayData raw, PendingIntent complicationPendingIntent) {

View file

@ -19,6 +19,7 @@ import info.nightscout.shared.logging.LTag;
/*
* Created by dlvoy on 2019-11-12
*/
@SuppressWarnings("deprecation")
public abstract class WallpaperComplication extends BaseComplicationProviderService {
public abstract String getWallpaperAssetsFileName();

View file

@ -1,7 +1,5 @@
package info.nightscout.androidaps.data
import android.content.Intent
import info.nightscout.androidaps.comm.DataLayerListenerServiceWear
import info.nightscout.androidaps.interaction.utils.Persistence
import info.nightscout.shared.weardata.EventData
@ -11,17 +9,23 @@ import info.nightscout.shared.weardata.EventData
* passing it to complications via persistence layer.
*
* Created by dlvoy on 2019-11-12
* Refactored by MilosKozak 24/04/2022
*
*/
class RawDisplayData {
// bg data bundle
var singleBg = EventData.SingleBg(
timeStamp = 0,
sgvString = "---",
glucoseUnits = "-",
slopeArrow = "--",
delta = "--",
avgDelta = "--",
sgvLevel = 0,
sgv = 0.0,
high = 0.0,
low = 0.0,
color = 0
)
color = 0)
// status bundle
var status = EventData.Status(
@ -39,16 +43,15 @@ class RawDisplayData {
batteryLevel = 1
)
// basals bundle
var graphData = EventData.GraphData(
entries = ArrayList<EventData.SingleBg>()
entries = ArrayList()
)
var treatmentData = EventData.TreatmentData(
temps = ArrayList<EventData.TreatmentData.TempBasal>(),
basals = ArrayList<EventData.TreatmentData.Basal>(),
boluses = ArrayList<EventData.TreatmentData.Treatment>(),
predictions = ArrayList<EventData.SingleBg>()
temps = ArrayList(),
basals = ArrayList(),
boluses = ArrayList(),
predictions = ArrayList()
)
fun toDebugString(): String =
@ -60,36 +63,4 @@ class RawDisplayData {
persistence.readStatus()?.let { status = it }
persistence.readTreatments()?.let { treatmentData = it }
}
/*
* Since complications do not need Basals, we skip them for performance
*/
fun updateForComplicationsFromPersistence(persistence: Persistence) {
persistence.readSingleBg()?.let { singleBg = it }
persistence.readGraphData()?.let { graphData = it }
persistence.readStatus()?.let { status = it }
}
fun updateFromMessage(intent: Intent) {
intent.getStringExtra(DataLayerListenerServiceWear.KEY_SINGLE_BG_DATA)?.let{
singleBg = EventData.deserialize(it) as EventData.SingleBg
}
intent.getStringExtra(DataLayerListenerServiceWear.KEY_STATUS_DATA)?.let{
status = EventData.deserialize(it) as EventData.Status
}
intent.getStringExtra(DataLayerListenerServiceWear.KEY_TREATMENTS_DATA)?.let{
treatmentData = EventData.deserialize(it) as EventData.TreatmentData
}
intent.getStringExtra(DataLayerListenerServiceWear.KEY_GRAPH_DATA)?.let{
graphData = EventData.deserialize(it) as EventData.GraphData
}
}
companion object {
const val BG_DATA_PERSISTENCE_KEY = "raw_data"
const val GRAPH_DATA_PERSISTENCE_KEY = "raw_data"
const val BASALS_PERSISTENCE_KEY = "raw_basals"
const val STATUS_PERSISTENCE_KEY = "raw_status"
}
}

View file

@ -19,9 +19,8 @@ import androidx.core.view.MotionEventCompat
import androidx.core.view.ViewConfigurationCompat
import info.nightscout.androidaps.R
import info.nightscout.androidaps.comm.DataLayerListenerServiceWear
import info.nightscout.androidaps.events.EventWearToMobile
import info.nightscout.shared.weardata.EventData.CancelNotification
import info.nightscout.shared.weardata.EventData.Companion.deserialize
import info.nightscout.androidaps.comm.IntentCancelNotification
import info.nightscout.androidaps.comm.IntentWearToMobile
import kotlin.math.roundToInt
class AcceptActivity : ViewSelectorActivity() {
@ -35,9 +34,9 @@ class AcceptActivity : ViewSelectorActivity() {
dismissThread = DismissThread()
dismissThread?.start()
val extras = intent.extras
message = extras?.getString("message", "") ?: ""
message = extras?.getString(DataLayerListenerServiceWear.KEY_MESSAGE, "") ?: ""
actionKey = extras?.getString(DataLayerListenerServiceWear.KEY_ACTION_DATA, "") ?: ""
if (message.isEmpty() || actionKey.isEmpty()) {
if (message.isEmpty()) {
finish()
return
}
@ -84,9 +83,8 @@ class AcceptActivity : ViewSelectorActivity() {
view = LayoutInflater.from(applicationContext).inflate(R.layout.action_confirm_ok, container, false)
val confirmButton = view.findViewById<ImageView>(R.id.confirmbutton)
confirmButton.setOnClickListener {
val returnCommand = deserialize(actionKey)
rxBus.send(EventWearToMobile(returnCommand))
rxBus.send(CancelNotification(System.currentTimeMillis()))
if (actionKey.isNotEmpty()) startService(IntentWearToMobile(this@AcceptActivity, actionKey))
startService(IntentCancelNotification(this@AcceptActivity))
finishAffinity()
}
container.addView(view)

View file

@ -1,185 +0,0 @@
package info.nightscout.androidaps.interaction.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Base64;
import androidx.annotation.Nullable;
import java.util.HashSet;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import info.nightscout.androidaps.complications.BaseComplicationProviderService;
import info.nightscout.androidaps.data.RawDisplayData;
import info.nightscout.shared.logging.AAPSLogger;
import info.nightscout.shared.logging.LTag;
import info.nightscout.shared.weardata.EventData;
/**
* Created by dlvoy on 2019-11-12
*/
@Singleton
public class Persistence {
private final AAPSLogger aapsLogger;
private final WearUtil wearUtil;
private final SharedPreferences preferences;
private final String COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY =
"info.nightscout.androidaps.complications.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY";
@Inject
public Persistence(Context context, AAPSLogger aapsLogger, WearUtil wearUtil) {
this.aapsLogger = aapsLogger;
this.wearUtil = wearUtil;
preferences = context.getSharedPreferences(COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0);
}
// For mocking only
public byte[] base64decode(String str, int flags) {
return Base64.decode(str, flags);
}
// For mocking only
public String base64encodeToString(byte[] input, int flags) {
return Base64.encodeToString(input, flags);
}
public String getString(String key, String defaultValue) {
return preferences.getString(key, defaultValue);
}
public void putString(String key, String value) {
preferences.edit().putString(key, value).apply();
}
public boolean getBoolean(String key, boolean defaultValue) {
return preferences.getBoolean(key, defaultValue);
}
public void putBoolean(String key, boolean value) {
preferences.edit().putBoolean(key, value).apply();
}
public long whenDataUpdated() {
return preferences.getLong("data_updated_at", 0);
}
private void markDataUpdated() {
preferences.edit().putLong("data_updated_at", wearUtil.timestamp()).apply();
}
public Set<String> getSetOf(String key) {
return explodeSet(getString(key, ""), "|");
}
public void addToSet(String key, String value) {
final Set<String> set = explodeSet(getString(key, ""), "|");
set.add(value);
putString(key, joinSet(set, "|"));
}
public void removeFromSet(String key, String value) {
final Set<String> set = explodeSet(getString(key, ""), "|");
set.remove(value);
putString(key, joinSet(set, "|"));
}
public void store(EventData.SingleBg singleBg) {
putString(RawDisplayData.BG_DATA_PERSISTENCE_KEY, singleBg.serialize());
markDataUpdated();
}
@Nullable
public EventData.SingleBg readSingleBg() {
try {
String s = getString(RawDisplayData.BG_DATA_PERSISTENCE_KEY, null);
if (s != null) {
return (EventData.SingleBg) EventData.Companion.deserialize(s);
}
} catch (Exception ignored) {}
return null;
}
@Nullable
public EventData.Status readStatus() {
try {
String s = getString(RawDisplayData.STATUS_PERSISTENCE_KEY, null);
if (s != null) {
return (EventData.Status) EventData.Companion.deserialize(s);
}
} catch (Exception ignored) {}
return null;
}
@Nullable
public EventData.TreatmentData readTreatments() {
try {
String s = getString(RawDisplayData.BASALS_PERSISTENCE_KEY, null);
if (s != null) {
return (EventData.TreatmentData) EventData.Companion.deserialize(s);
}
} catch (Exception ignored) {}
return null;
}
@Nullable
public EventData.GraphData readGraphData() {
try {
String s = getString(RawDisplayData.BG_DATA_PERSISTENCE_KEY, null);
if (s != null) {
return (EventData.GraphData) EventData.Companion.deserialize(s);
}
} catch (Exception ignored) {}
return null;
}
public void store(EventData.GraphData graphData) {
putString(RawDisplayData.GRAPH_DATA_PERSISTENCE_KEY, graphData.serialize());
}
public void store(EventData.TreatmentData treatmentData) {
putString(RawDisplayData.BASALS_PERSISTENCE_KEY, treatmentData.serialize());
}
public void store(EventData.Status status) {
putString(RawDisplayData.STATUS_PERSISTENCE_KEY, status.serialize());
}
public String joinSet(Set<String> set, String separator) {
StringBuilder sb = new StringBuilder();
int i = 0;
for (String item : set) {
final String itemToAdd = item.trim();
if (itemToAdd.length() > 0) {
if (i > 0) {
sb.append(separator);
}
i++;
sb.append(itemToAdd);
}
}
return sb.toString();
}
public Set<String> explodeSet(String joined, String separator) {
// special RegEx literal \\Q starts sequence we escape, \\E ends is
// we use it to escape separator for use in RegEx
String[] items = joined.split("\\Q"+separator+"\\E");
Set<String> set = new HashSet<>();
for (String item : items) {
final String itemToAdd = item.trim();
if (itemToAdd.length() > 0) {
set.add(itemToAdd);
}
}
return set;
}
public void turnOff() {
aapsLogger.debug(LTag.WEAR, "TURNING OFF all active complications");
putString(BaseComplicationProviderService.KEY_COMPLICATIONS, "");
}
}

View file

@ -0,0 +1,195 @@
package info.nightscout.androidaps.interaction.utils
import android.util.Base64
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.weardata.EventData
import info.nightscout.shared.weardata.EventData.Companion.deserialize
import info.nightscout.shared.weardata.EventData.SingleBg
import info.nightscout.shared.weardata.EventData.TreatmentData
import javax.inject.Inject
import javax.inject.Singleton
/**
* Created by dlvoy on 2019-11-12
* Refactored by MilosKozak 25/04/2022
*/
@Singleton
class Persistence @Inject constructor(
private val aapsLogger: AAPSLogger,
private val dateUtil: DateUtil,
private val sp: SP
) {
companion object {
const val BG_DATA_PERSISTENCE_KEY = "bg_data"
const val GRAPH_DATA_PERSISTENCE_KEY = "graph_data"
const val TREATMENT_PERSISTENCE_KEY = "treatment_data"
const val STATUS_PERSISTENCE_KEY = "status_data"
const val KEY_COMPLICATIONS = "complications"
const val KEY_LAST_SHOWN_SINCE_VALUE = "lastSince"
const val KEY_STALE_REPORTED = "staleReported"
const val KEY_DATA_UPDATED = "data_updated_at"
}
// For mocking only
fun base64decode(str: String, flags: Int): ByteArray {
return Base64.decode(str, flags)
}
// For mocking only
fun base64encodeToString(input: ByteArray, flags: Int): String {
return Base64.encodeToString(input, flags)
}
fun getString(key: String, defaultValue: String): String {
return sp.getString(key, defaultValue)
}
fun putString(key: String, value: String) {
sp.putString(key, value)
}
fun getBoolean(key: String, defaultValue: Boolean): Boolean {
return sp.getBoolean(key, defaultValue)
}
fun putBoolean(key: String, value: Boolean) {
sp.putBoolean(key, value)
}
fun whenDataUpdated(): Long {
return sp.getLong(KEY_DATA_UPDATED, 0)
}
private fun markDataUpdated() {
sp.putLong(KEY_DATA_UPDATED, dateUtil.now())
}
fun getSetOf(key: String): Set<String> {
return explodeSet(getString(key, ""), "|")
}
fun addToSet(key: String, value: String) {
val set = explodeSet(getString(key, ""), "|")
set.add(value)
putString(key, joinSet(set, "|"))
}
fun removeFromSet(key: String, value: String) {
val set = explodeSet(getString(key, ""), "|")
set.remove(value)
putString(key, joinSet(set, "|"))
}
fun readSingleBg(): SingleBg? {
try {
val s = sp.getStringOrNull(BG_DATA_PERSISTENCE_KEY, null)
//aapsLogger.debug(LTag.WEAR, "Loaded BG data: $s")
if (s != null) {
return deserialize(s) as SingleBg
}
} catch (exception: Exception) {
aapsLogger.error(LTag.WEAR, exception.toString())
}
return null
}
fun readStatus(): EventData.Status? {
try {
val s = sp.getStringOrNull(STATUS_PERSISTENCE_KEY, null)
//aapsLogger.debug(LTag.WEAR, "Loaded Status data: $s")
if (s != null) {
return deserialize(s) as EventData.Status
}
} catch (exception: Exception) {
aapsLogger.error(LTag.WEAR, exception.toString())
}
return null
}
fun readTreatments(): TreatmentData? {
try {
val s = sp.getStringOrNull(TREATMENT_PERSISTENCE_KEY, null)
//aapsLogger.debug(LTag.WEAR, "Loaded Treatments data: $s")
if (s != null) {
return deserialize(s) as TreatmentData
}
} catch (exception: Exception) {
aapsLogger.error(LTag.WEAR, exception.toString())
}
return null
}
fun readGraphData(): EventData.GraphData? {
try {
val s = sp.getStringOrNull(GRAPH_DATA_PERSISTENCE_KEY, null)
//aapsLogger.debug(LTag.WEAR, "Loaded Graph data: $s")
if (s != null) {
return deserialize(s) as EventData.GraphData
}
} catch (exception: Exception) {
aapsLogger.error(LTag.WEAR, exception.toString())
}
return null
}
fun store(singleBg: SingleBg) {
putString(BG_DATA_PERSISTENCE_KEY, singleBg.serialize())
aapsLogger.debug(LTag.WEAR, "Stored BG data: $singleBg")
markDataUpdated()
}
fun store(graphData: EventData.GraphData) {
putString(GRAPH_DATA_PERSISTENCE_KEY, graphData.serialize())
aapsLogger.debug(LTag.WEAR, "Stored Graph data: $graphData")
}
fun store(treatmentData: TreatmentData) {
putString(TREATMENT_PERSISTENCE_KEY, treatmentData.serialize())
aapsLogger.debug(LTag.WEAR, "Stored Treatments data: $treatmentData")
}
fun store(status: EventData.Status) {
putString(STATUS_PERSISTENCE_KEY, status.serialize())
aapsLogger.debug(LTag.WEAR, "Stored Status data: $status")
}
fun joinSet(set: Set<String>, separator: String?): String {
val sb = StringBuilder()
var i = 0
for (item in set) {
val itemToAdd = item.trim { it <= ' ' }
if (itemToAdd.isNotEmpty()) {
if (i > 0) sb.append(separator)
i++
sb.append(itemToAdd)
}
}
return sb.toString()
}
fun explodeSet(joined: String, separator: String): MutableSet<String> {
// special RegEx literal \\Q starts sequence we escape, \\E ends is
// we use it to escape separator for use in RegEx
val items = joined.split("\\Q$separator\\E").toTypedArray()
val set: MutableSet<String> = HashSet()
for (item in items) {
val itemToAdd = item.trim { it <= ' ' }
if (itemToAdd.isNotEmpty()) {
set.add(itemToAdd)
}
}
return set
}
fun turnOff() {
aapsLogger.debug(LTag.WEAR, "TURNING OFF all active complications")
putString(KEY_COMPLICATIONS, "")
}
}

View file

@ -23,17 +23,16 @@ import java.util.concurrent.TimeUnit;
public class PlusMinusEditText implements View.OnKeyListener,
View.OnTouchListener, View.OnClickListener, View.OnGenericMotionListener {
Integer editTextID;
public TextView editText;
ImageView minusImage;
ImageView plusImage;
Double value;
Double minValue = 0d;
Double maxValue = 1d;
Double step = 1d;
Double minValue;
Double maxValue;
Double step;
NumberFormat formatter;
boolean allowZero = false;
boolean allowZero;
boolean roundRobin;
private int mChangeCounter = 0;
@ -50,14 +49,13 @@ public class PlusMinusEditText implements View.OnKeyListener,
private int repeated = 0;
private int multiplier = 1;
private final int doubleLimit = 5;
public UpdateCounterTask(boolean inc) {
mInc = inc;
}
public void run() {
Message msg = new Message();
int doubleLimit = 5;
if (repeated % doubleLimit == 0) multiplier *= 2;
repeated++;
msg.arg1 = multiplier;
@ -125,10 +123,6 @@ public class PlusMinusEditText implements View.OnKeyListener,
return value;
}
public void setStep(Double step) {
this.step = step;
}
private void inc(int multiplier) {
value += step * multiplier;
if (value > maxValue) {

View file

@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")
package info.nightscout.androidaps.watchfaces
import android.annotation.SuppressLint
@ -25,6 +27,7 @@ import com.ustwo.clockwise.common.WatchShape
import com.ustwo.clockwise.wearable.WatchFace
import dagger.android.AndroidInjection
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.RawDisplayData
import info.nightscout.androidaps.events.EventWearPreferenceChange
import info.nightscout.androidaps.events.EventWearToMobile
import info.nightscout.androidaps.extensions.toVisibility
@ -66,10 +69,12 @@ abstract class BaseWatchFace : WatchFace() {
private var disposable = CompositeDisposable()
protected var singleBg = SingleBg(0, "---", "-", "--", "--", "--", 0, 0.0, 0.0, 0.0, 0)
protected var status = EventData.Status("no status", "IOB", "-.--", false, "--g", "-.--U/h", "--", "--", -1, "--", false, 1)
protected var treatmentData = TreatmentData(ArrayList(), ArrayList(), ArrayList(), ArrayList())
protected var graphData = EventData.GraphData(ArrayList())
private val rawData = RawDisplayData()
protected val singleBg get() = rawData.singleBg
protected val status get() = rawData.status
protected val treatmentData get() = rawData.treatmentData
protected val graphData get() = rawData.graphData
// Layout
@LayoutRes abstract fun layoutResource(): Int
@ -169,30 +174,19 @@ abstract class BaseWatchFace : WatchFace() {
if (layoutSet) setDataFields()
invalidate()
}
disposable += rxBus
.toObservable(SingleBg::class.java)
.observeOn(aapsSchedulers.main)
.subscribe { event: SingleBg -> singleBg = event }
disposable += rxBus
.toObservable(TreatmentData::class.java)
.observeOn(aapsSchedulers.main)
.subscribe { event: TreatmentData -> treatmentData = event }
disposable += rxBus
.toObservable(EventData.GraphData::class.java)
.observeOn(aapsSchedulers.main)
.subscribe { event: EventData.GraphData -> graphData = event }
disposable += rxBus
.toObservable(EventData.Status::class.java)
.observeOn(aapsSchedulers.main)
.subscribe { event: EventData.Status ->
status = event
.subscribe {
// this event is received as last batch of data
rawData.updateFromPersistence(persistence)
if (!isSimpleUi || !needUpdate()) {
setupCharts()
setDataFields()
}
invalidate()
}
rawData.updateFromPersistence(persistence)
persistence.turnOff()
setupBatteryReceiver()
setupSimpleUi()

View file

@ -20,8 +20,10 @@ import com.ustwo.clockwise.common.WatchFaceTime
import com.ustwo.clockwise.wearable.WatchFace
import dagger.android.AndroidInjection
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.RawDisplayData
import info.nightscout.androidaps.events.EventWearToMobile
import info.nightscout.androidaps.interaction.menus.MainMenuActivity
import info.nightscout.androidaps.interaction.utils.Persistence
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
@ -45,11 +47,15 @@ class CircleWatchface : WatchFace() {
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var sp: SP
@Inject lateinit var persistence: Persistence
private var disposable = CompositeDisposable()
private var singleBg = SingleBg(0, "---", "-", "--", "--", "--", 0, 0.0, 0.0, 0.0, 0)
private var graphData = EventData.GraphData(ArrayList())
private var status = EventData.Status("no status", "IOB", "-.--", false, "--g", "-.--U/h", "--", "--", -1, "--", false, 1)
private val rawData = RawDisplayData()
private val singleBg get() = rawData.singleBg
private val status get() = rawData.status
private val graphData get() = rawData.graphData
companion object {
@ -96,21 +102,13 @@ class CircleWatchface : WatchFace() {
myLayout = inflater.inflate(R.layout.activity_circle, null)
prepareLayout()
prepareDrawTime()
disposable += rxBus
.toObservable(SingleBg::class.java)
.observeOn(aapsSchedulers.main)
.subscribe { event -> singleBg = event }
disposable += rxBus
.toObservable(EventData.GraphData::class.java)
.observeOn(aapsSchedulers.main)
.subscribe { event -> graphData = event }
disposable += rxBus
.toObservable(EventData.Status::class.java)
.observeOn(aapsSchedulers.main)
.subscribe { event ->
.subscribe {
// this event is received as last batch of data
aapsLogger.debug(LTag.WEAR, "Status received")
status = event
rawData.updateFromPersistence(persistence)
addToWatchSet()
prepareLayout()
prepareDrawTime()
@ -124,6 +122,7 @@ class CircleWatchface : WatchFace() {
prepareLayout()
invalidate()
}
rawData.updateFromPersistence(persistence)
rxBus.send(EventWearToMobile(ActionResendData("CircleWatchFace::onCreate")))
wakeLock.release()
}

View file

@ -1,3 +1,5 @@
@file:Suppress("DEPRECATION")
package info.nightscout.androidaps.watchfaces
import android.view.animation.Animation