Wear: migrate to RxBus comm and data classes
This commit is contained in:
parent
2dba081176
commit
2ebaffa4ad
99 changed files with 3716 additions and 6509 deletions
|
@ -167,7 +167,7 @@
|
|||
</provider>
|
||||
|
||||
<service
|
||||
android:name=".plugins.general.wear.wearintegration.WatchUpdaterService"
|
||||
android:name=".plugins.general.wear.wearintegration.DataLayerListenerServiceMobile"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.wearable.CHANNEL_EVENT" />
|
||||
|
@ -185,23 +185,7 @@
|
|||
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_pong"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_resend_data_request"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/@path_cancel_bolus_on_watch"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_confirm_action"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_initiate_action_on_phone"
|
||||
android:pathPrefix="@string/path_rx_bridge"
|
||||
android:scheme="wear" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
|
|
@ -5,7 +5,7 @@ import dagger.android.ContributesAndroidInjector
|
|||
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.DismissNotificationService
|
||||
import info.nightscout.androidaps.plugins.general.persistentNotification.DummyService
|
||||
import info.nightscout.androidaps.plugins.general.wear.wearintegration.WatchUpdaterService
|
||||
import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataLayerListenerServiceMobile
|
||||
import info.nightscout.androidaps.services.AlarmSoundService
|
||||
import info.nightscout.androidaps.services.LocationService
|
||||
|
||||
|
@ -18,5 +18,5 @@ abstract class ServicesModule {
|
|||
@ContributesAndroidInjector abstract fun contributesDummyService(): DummyService
|
||||
@ContributesAndroidInjector abstract fun contributesLocationService(): LocationService
|
||||
@ContributesAndroidInjector abstract fun contributesNSClientService(): NSClientService
|
||||
@ContributesAndroidInjector abstract fun contributesWatchUpdaterService(): WatchUpdaterService
|
||||
@ContributesAndroidInjector abstract fun contributesWatchUpdaterService(): DataLayerListenerServiceMobile
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
class EventBolusRequested(var amount: Double) : Event()
|
|
@ -27,6 +27,7 @@ import info.nightscout.androidaps.database.entities.ValueWithUnit
|
|||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction
|
||||
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
|
||||
import info.nightscout.androidaps.events.EventMobileToWear
|
||||
import info.nightscout.androidaps.events.EventTempTargetChange
|
||||
import info.nightscout.androidaps.extensions.buildDeviceStatus
|
||||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||
|
@ -44,8 +45,6 @@ import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
|
|||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction
|
||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
|
||||
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||
|
@ -58,6 +57,7 @@ import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
|||
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 io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
@ -349,7 +349,7 @@ class LoopPlugin @Inject constructor(
|
|||
//only send to wear if Native notifications are turned off
|
||||
if (!sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
|
||||
// Send to Wear
|
||||
rxBus.send(EventWearInitiateAction("changeRequest"))
|
||||
sendToWear()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -454,14 +454,28 @@ class LoopPlugin @Inject constructor(
|
|||
rxBus.send(EventNewOpenLoopNotification())
|
||||
|
||||
// Send to Wear
|
||||
rxBus.send(EventWearInitiateAction("changeRequest"))
|
||||
sendToWear()
|
||||
}
|
||||
|
||||
private fun dismissSuggestion() {
|
||||
// dismiss notifications
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.cancel(Constants.notificationID)
|
||||
rxBus.send(EventWearConfirmAction("cancelChangeRequest"))
|
||||
rxBus.send(EventMobileToWear(EventData.CancelNotification(dateUtil.now())))
|
||||
}
|
||||
|
||||
private fun sendToWear() {
|
||||
lastRun?.let {
|
||||
rxBus.send(
|
||||
EventMobileToWear(
|
||||
EventData.OpenLoopRequest(
|
||||
rh.gs(R.string.openloop_newsuggestion),
|
||||
it.constraintsProcessed.toString(),
|
||||
EventData.OpenLoopRequestConfirmed(dateUtil.now())
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun acceptChangeRequest() {
|
||||
|
|
|
@ -54,7 +54,6 @@ import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizar
|
|||
import info.nightscout.androidaps.plugins.general.overview.events.*
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
|
||||
|
@ -76,6 +75,7 @@ import info.nightscout.androidaps.utils.ui.UIRunnable
|
|||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.weardata.EventData
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import java.util.*
|
||||
|
@ -408,7 +408,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
?: "".toSpanned(), {
|
||||
uel.log(Action.ACCEPTS_TEMP_BASAL, Sources.Overview)
|
||||
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?)?.cancel(Constants.notificationID)
|
||||
rxBus.send(EventWearInitiateAction("cancelChangeRequest"))
|
||||
rxBus.send(EventMobileToWear(EventData.CancelNotification(dateUtil.now())))
|
||||
Thread { loop.acceptChangeRequest() }.run()
|
||||
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
|
||||
})
|
||||
|
|
|
@ -1,841 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear
|
||||
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.dana.DanaPump
|
||||
import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin
|
||||
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
|
||||
import info.nightscout.androidaps.danar.DanaRPlugin
|
||||
import info.nightscout.androidaps.danars.DanaRSPlugin
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.entities.TemporaryTarget
|
||||
import info.nightscout.androidaps.database.entities.TotalDailyDose
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Action
|
||||
import info.nightscout.androidaps.database.entities.UserEntry.Sources
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.interfaces.end
|
||||
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
|
||||
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
|
||||
import info.nightscout.androidaps.extensions.total
|
||||
import info.nightscout.androidaps.extensions.valueToUnits
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
|
||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction
|
||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
|
||||
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.utils.*
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||
import info.nightscout.shared.SafeParse
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.weardata.ActionData
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_BOLUS
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_CANCEL_CHANGE_REQUEST
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_CHANGE_REQUEST
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_CPP_SET
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_DISMISS_OVERVIEW_NOTIF
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_E_CARBS
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_FILL
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_FILL_PRESET
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_OPEN_CPP
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_QUICK_WIZARD
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_STATUS
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_TDD_STATS
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_TEMPORARY_TARGET
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_WIZARD
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.ACTION_WIZARD2
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.min
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
@Singleton
|
||||
class ActionStringHandler @Inject constructor(
|
||||
private val sp: SP,
|
||||
private val rxBus: RxBus,
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val aapsSchedulers: AapsSchedulers,
|
||||
private val rh: ResourceHelper,
|
||||
private val injector: HasAndroidInjector,
|
||||
private val context: Context,
|
||||
private val constraintChecker: ConstraintChecker,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val loop: Loop,
|
||||
private val wearPlugin: WearPlugin,
|
||||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val commandQueue: CommandQueue,
|
||||
private val activePlugin: ActivePlugin,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
private val localInsightPlugin: LocalInsightPlugin,
|
||||
private val quickWizard: QuickWizard,
|
||||
private val danaRPlugin: DanaRPlugin,
|
||||
private val danaRKoreanPlugin: DanaRKoreanPlugin,
|
||||
private val danaRv2Plugin: DanaRv2Plugin,
|
||||
private val danaRSPlugin: DanaRSPlugin,
|
||||
private val danaPump: DanaPump,
|
||||
private val dateUtil: DateUtil,
|
||||
private val config: Config,
|
||||
private val repository: AppRepository,
|
||||
private val uel: UserEntryLogger,
|
||||
private val defaultValueHelper: DefaultValueHelper
|
||||
) {
|
||||
|
||||
private val timeout = 65 * 1000
|
||||
private var lastSentTimestamp: Long = 0
|
||||
private var lastConfirmActionString: String? = null
|
||||
private var lastBolusWizard: BolusWizard? = null
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
fun setup() {
|
||||
disposable += rxBus
|
||||
.toObservable(EventWearInitiateAction::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ handleInitiateActionOnPhone(it.action) }, fabricPrivacy::logException)
|
||||
|
||||
disposable += rxBus
|
||||
.toObservable(EventWearConfirmAction::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ handleConfirmation(it.action) }, fabricPrivacy::logException)
|
||||
}
|
||||
|
||||
fun tearDown() {
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun handleInitiateActionOnPhone(actionString: String) {
|
||||
//TODO: i18n
|
||||
aapsLogger.debug(LTag.WEAR, "handleInitiateActionOnPhone actionString=$actionString")
|
||||
if (!sp.getBoolean(R.string.key_wear_control, false)) return
|
||||
lastBolusWizard = null
|
||||
var rTitle = rh.gs(R.string.confirm).uppercase()
|
||||
var rMessage = ""
|
||||
var rAction = ""
|
||||
|
||||
if (actionString.startsWith("{")) {
|
||||
when (val command = ActionData.deserialize(actionString)) {
|
||||
is ActionData.Bolus -> {
|
||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(command.insulin)).value()
|
||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(command.carbs)).value()
|
||||
val pump = activePlugin.activePump
|
||||
if (insulinAfterConstraints > 0 && (!pump.isInitialized() || pump.isSuspended() || loop.isDisconnected)) {
|
||||
sendError(rh.gs(R.string.wizard_pump_not_available))
|
||||
return
|
||||
}
|
||||
rMessage += rh.gs(R.string.bolus) + ": " + insulinAfterConstraints + "U\n"
|
||||
rMessage += rh.gs(R.string.carbs) + ": " + carbsAfterConstraints + "g"
|
||||
if (insulinAfterConstraints - command.insulin != 0.0 || carbsAfterConstraints - command.carbs != 0) {
|
||||
rMessage += "\n" + rh.gs(R.string.constraintapllied)
|
||||
}
|
||||
rAction += "bolus $insulinAfterConstraints $carbsAfterConstraints"
|
||||
}
|
||||
is ActionData.ProfileSwitch -> {
|
||||
val activeProfileSwitch = repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet()
|
||||
if (activeProfileSwitch is ValueWrapper.Existing) {
|
||||
rMessage = "Profile:" + "\n\n" +
|
||||
"Timeshift: " + command.timeShift + "\n" +
|
||||
"Percentage: " + command.percentage + "%"
|
||||
rAction = actionString
|
||||
} else { // read CPP values
|
||||
sendError("No active profile switch!")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// do the parsing and check constraints
|
||||
val act = actionString.split("\\s+".toRegex()).toTypedArray()
|
||||
when (act[0]) {
|
||||
ACTION_FILL_PRESET -> { ///////////////////////////////////// PRIME/FILL
|
||||
val amount: Double = when {
|
||||
"1" == act[1] -> sp.getDouble("fill_button1", 0.3)
|
||||
"2" == act[1] -> sp.getDouble("fill_button2", 0.0)
|
||||
"3" == act[1] -> sp.getDouble("fill_button3", 0.0)
|
||||
else -> return
|
||||
}
|
||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(amount)).value()
|
||||
rMessage += rh.gs(R.string.primefill) + ": " + insulinAfterConstraints + "U"
|
||||
if (insulinAfterConstraints - amount != 0.0) rMessage += "\n" + rh.gs(R.string.constraintapllied)
|
||||
rAction += "fill $insulinAfterConstraints"
|
||||
}
|
||||
|
||||
ACTION_FILL -> {
|
||||
val amount = SafeParse.stringToDouble(act[1])
|
||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(amount)).value()
|
||||
rMessage += rh.gs(R.string.primefill) + ": " + insulinAfterConstraints + "U"
|
||||
if (insulinAfterConstraints - amount != 0.0) rMessage += "\n" + rh.gs(R.string.constraintapllied)
|
||||
rAction += "fill $insulinAfterConstraints"
|
||||
}
|
||||
|
||||
ACTION_TEMPORARY_TARGET -> {
|
||||
aapsLogger.info(LTag.WEAR, "temptarget received: $act")
|
||||
if ("cancel" == act[1]) {
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_cancel_message)
|
||||
rAction = "temptarget true 0 0 0"
|
||||
} else if ("preset" == act[1]) {
|
||||
val presetIsMGDL = profileFunction.getUnits() == GlucoseUnit.MGDL
|
||||
val preset = act[2]
|
||||
when (preset) {
|
||||
"activity" -> {
|
||||
val activityTTDuration = defaultValueHelper.determineActivityTTDuration()
|
||||
val activityTT = defaultValueHelper.determineActivityTT()
|
||||
val reason = rh.gs(R.string.activity)
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, activityTT, activityTTDuration)
|
||||
rAction = "temptarget $presetIsMGDL $activityTTDuration $activityTT $activityTT"
|
||||
}
|
||||
|
||||
"hypo" -> {
|
||||
val hypoTTDuration = defaultValueHelper.determineHypoTTDuration()
|
||||
val hypoTT = defaultValueHelper.determineHypoTT()
|
||||
val reason = rh.gs(R.string.hypo)
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, hypoTT, hypoTTDuration)
|
||||
rAction = "temptarget $presetIsMGDL $hypoTTDuration $hypoTT $hypoTT"
|
||||
}
|
||||
|
||||
"eating" -> {
|
||||
val eatingSoonTTDuration = defaultValueHelper.determineEatingSoonTTDuration()
|
||||
val eatingSoonTT = defaultValueHelper.determineEatingSoonTT()
|
||||
val reason = rh.gs(R.string.eatingsoon)
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, eatingSoonTT, eatingSoonTTDuration)
|
||||
rAction = "temptarget $presetIsMGDL $eatingSoonTTDuration $eatingSoonTT $eatingSoonTT"
|
||||
}
|
||||
|
||||
else -> {
|
||||
sendError(rh.gs(R.string.wear_action_tempt_preset_error, preset))
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val isMGDL = java.lang.Boolean.parseBoolean(act[1])
|
||||
if (profileFunction.getUnits() == GlucoseUnit.MGDL != isMGDL) {
|
||||
sendError(rh.gs(R.string.wear_action_tempt_unit_error))
|
||||
return
|
||||
}
|
||||
val duration = SafeParse.stringToInt(act[2])
|
||||
if (duration == 0) {
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_zero_message)
|
||||
rAction = "temptarget true 0 0 0"
|
||||
} else {
|
||||
var low = SafeParse.stringToDouble(act[3])
|
||||
var high = SafeParse.stringToDouble(act[4])
|
||||
if (!isMGDL) {
|
||||
low *= Constants.MMOLL_TO_MGDL
|
||||
high *= Constants.MMOLL_TO_MGDL
|
||||
}
|
||||
if (low < HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0] || low > HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1]) {
|
||||
sendError(rh.gs(R.string.wear_action_tempt_min_bg_error))
|
||||
return
|
||||
}
|
||||
if (high < HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0] || high > HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1]) {
|
||||
sendError(rh.gs(R.string.wear_action_tempt_max_bg_error))
|
||||
return
|
||||
}
|
||||
rMessage += if (act[3] === act[4]) rh.gs(R.string.wear_action_tempt_manual_message, act[3], act[2])
|
||||
else rh.gs(R.string.wear_action_tempt_manual_range_message, act[3], act[4], act[2])
|
||||
rAction = actionString
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_STATUS -> {
|
||||
rTitle = "STATUS"
|
||||
rAction = "statusmessage"
|
||||
if ("pump" == act[1]) {
|
||||
rTitle += " PUMP"
|
||||
rMessage = pumpStatus
|
||||
} else if ("loop" == act[1]) {
|
||||
rTitle += " LOOP"
|
||||
rMessage = "TARGETS:\n$targetsStatus"
|
||||
rMessage += "\n\n" + loopStatus
|
||||
rMessage += "\n\nOAPS RESULT:\n$oAPSResultStatus"
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_WIZARD -> {
|
||||
sendError("Update APP on Watch!")
|
||||
return
|
||||
}
|
||||
|
||||
ACTION_WIZARD2 -> {
|
||||
val pump = activePlugin.activePump
|
||||
if (!pump.isInitialized() || pump.isSuspended() || loop.isDisconnected) {
|
||||
sendError(rh.gs(R.string.wizard_pump_not_available))
|
||||
return
|
||||
}
|
||||
val carbsBeforeConstraints = SafeParse.stringToInt(act[1])
|
||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbsBeforeConstraints)).value()
|
||||
if (carbsAfterConstraints - carbsBeforeConstraints != 0) {
|
||||
sendError(rh.gs(R.string.wizard_carbs_constraint))
|
||||
return
|
||||
}
|
||||
val useBG = sp.getBoolean(R.string.key_wearwizard_bg, true)
|
||||
val useTT = sp.getBoolean(R.string.key_wearwizard_tt, false)
|
||||
val useBolusIOB = sp.getBoolean(R.string.key_wearwizard_bolusiob, true)
|
||||
val useBasalIOB = sp.getBoolean(R.string.key_wearwizard_basaliob, true)
|
||||
val useCOB = sp.getBoolean(R.string.key_wearwizard_cob, true)
|
||||
val useTrend = sp.getBoolean(R.string.key_wearwizard_trend, false)
|
||||
val percentage = act[2].toInt()
|
||||
val profile = profileFunction.getProfile()
|
||||
val profileName = profileFunction.getProfileName()
|
||||
if (profile == null) {
|
||||
sendError(rh.gs(R.string.wizard_no_active_profile))
|
||||
return
|
||||
}
|
||||
val bgReading = iobCobCalculator.ads.actualBg()
|
||||
if (bgReading == null) {
|
||||
sendError(rh.gs(R.string.wizard_no_actual_bg))
|
||||
return
|
||||
}
|
||||
val cobInfo = iobCobCalculator.getCobInfo(false, "Wizard wear")
|
||||
if (cobInfo.displayCob == null) {
|
||||
sendError(rh.gs(R.string.wizard_no_cob))
|
||||
return
|
||||
}
|
||||
val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||
val tempTarget = if (dbRecord is ValueWrapper.Existing) dbRecord.value else null
|
||||
|
||||
val bolusWizard = BolusWizard(injector).doCalc(
|
||||
profile, profileName, tempTarget,
|
||||
carbsAfterConstraints, cobInfo.displayCob!!, bgReading.valueToUnits(profileFunction.getUnits()),
|
||||
0.0, percentage, useBG, useCOB, useBolusIOB, useBasalIOB, false, useTT, useTrend, false
|
||||
)
|
||||
val insulinAfterConstraints = bolusWizard.insulinAfterConstraints
|
||||
val minStep = pump.pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints)
|
||||
if (abs(insulinAfterConstraints - bolusWizard.calculatedTotalInsulin) >= minStep) {
|
||||
sendError(rh.gs(R.string.wizard_constraint_bolus_size, bolusWizard.calculatedTotalInsulin))
|
||||
return
|
||||
}
|
||||
if (bolusWizard.calculatedTotalInsulin <= 0 && bolusWizard.carbs <= 0) {
|
||||
rAction = "info"
|
||||
rTitle = rh.gs(R.string.info)
|
||||
} else {
|
||||
rAction = actionString
|
||||
}
|
||||
rMessage += rh.gs(R.string.wizard_result, bolusWizard.calculatedTotalInsulin, bolusWizard.carbs)
|
||||
rMessage += "\n_____________"
|
||||
rMessage += "\n" + bolusWizard.explainShort()
|
||||
lastBolusWizard = bolusWizard
|
||||
}
|
||||
|
||||
ACTION_QUICK_WIZARD -> {
|
||||
val guid = act[1]
|
||||
val actualBg = iobCobCalculator.ads.actualBg()
|
||||
val profile = profileFunction.getProfile()
|
||||
val profileName = profileFunction.getProfileName()
|
||||
val quickWizardEntry = quickWizard.get(guid)
|
||||
//Log.i("QuickWizard", "handleInitiate: quick_wizard " + quickWizardEntry?.buttonText() + " c " + quickWizardEntry?.carbs())
|
||||
if (quickWizardEntry == null) {
|
||||
sendError(rh.gs(R.string.quick_wizard_not_available))
|
||||
return
|
||||
}
|
||||
if (actualBg == null) {
|
||||
sendError(rh.gs(R.string.wizard_no_actual_bg))
|
||||
return
|
||||
}
|
||||
if (profile == null) {
|
||||
sendError(rh.gs(R.string.wizard_no_active_profile))
|
||||
return
|
||||
}
|
||||
val cobInfo = iobCobCalculator.getCobInfo(false, "QuickWizard wear")
|
||||
if (cobInfo.displayCob == null) {
|
||||
sendError(rh.gs(R.string.wizard_no_cob))
|
||||
return
|
||||
}
|
||||
val pump = activePlugin.activePump
|
||||
if (!pump.isInitialized() || pump.isSuspended() || loop.isDisconnected) {
|
||||
sendError(rh.gs(R.string.wizard_pump_not_available))
|
||||
return
|
||||
}
|
||||
|
||||
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg, true)
|
||||
|
||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value()
|
||||
if (carbsAfterConstraints != quickWizardEntry.carbs()) {
|
||||
sendError(rh.gs(R.string.wizard_carbs_constraint))
|
||||
return
|
||||
}
|
||||
val insulinAfterConstraints = wizard.insulinAfterConstraints
|
||||
val minStep = pump.pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints)
|
||||
if (abs(insulinAfterConstraints - wizard.calculatedTotalInsulin) >= minStep) {
|
||||
sendError(rh.gs(R.string.wizard_constraint_bolus_size, wizard.calculatedTotalInsulin))
|
||||
return
|
||||
}
|
||||
|
||||
rMessage = rh.gs(R.string.quick_wizard_message, quickWizardEntry.buttonText(), wizard.calculatedTotalInsulin, quickWizardEntry.carbs())
|
||||
rAction = "bolus $insulinAfterConstraints $carbsAfterConstraints"
|
||||
//Log.i("QuickWizard", "handleInitiate: quick_wizard action=$rAction")
|
||||
|
||||
rMessage += "\n_____________"
|
||||
rMessage += "\n" + wizard.explainShort()
|
||||
|
||||
}
|
||||
|
||||
ACTION_OPEN_CPP -> {
|
||||
val activeProfileSwitch = repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet()
|
||||
if (activeProfileSwitch is ValueWrapper.Existing) { // read CPP values
|
||||
rTitle = "opencpp"
|
||||
rMessage = "opencpp"
|
||||
rAction = "opencpp" + " " + activeProfileSwitch.value.originalPercentage + " " + activeProfileSwitch.value.originalTimeshift
|
||||
} else {
|
||||
sendError("No active profile switch!")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_TDD_STATS -> {
|
||||
val activePump = activePlugin.activePump
|
||||
// check if DB up to date
|
||||
val dummies: MutableList<TotalDailyDose> = LinkedList()
|
||||
val historyList = getTDDList(dummies)
|
||||
if (isOldData(historyList)) {
|
||||
rTitle = "TDD"
|
||||
rAction = "statusmessage"
|
||||
rMessage = "OLD DATA - "
|
||||
//if pump is not busy: try to fetch data
|
||||
if (activePump.isBusy()) {
|
||||
rMessage += rh.gs(R.string.pumpbusy)
|
||||
} else {
|
||||
rMessage += "trying to fetch data from pump."
|
||||
commandQueue.loadTDDs(object : Callback() {
|
||||
override fun run() {
|
||||
val dummies1: MutableList<TotalDailyDose> = LinkedList()
|
||||
val historyList1 = getTDDList(dummies1)
|
||||
if (isOldData(historyList1)) {
|
||||
sendStatusMessage("TDD: Still old data! Cannot load from pump.\n" + generateTDDMessage(historyList1, dummies1))
|
||||
} else {
|
||||
sendStatusMessage(generateTDDMessage(historyList1, dummies1))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
} else { // if up to date: prepare, send (check if CPP is activated -> add CPP stats)
|
||||
rTitle = "TDD"
|
||||
rAction = "statusmessage"
|
||||
rMessage = generateTDDMessage(historyList, dummies)
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_E_CARBS -> {
|
||||
val carbs = SafeParse.stringToInt(act[1])
|
||||
val starttime = SafeParse.stringToInt(act[2])
|
||||
val duration = SafeParse.stringToInt(act[3])
|
||||
val starttimestamp = System.currentTimeMillis() + starttime * 60 * 1000
|
||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
|
||||
rMessage += rh.gs(R.string.carbs) + ": " + carbsAfterConstraints + "g"
|
||||
rMessage += "\n" + rh.gs(R.string.time) + ": " + dateUtil.timeString(starttimestamp)
|
||||
rMessage += "\n" + rh.gs(R.string.duration) + ": " + duration + "h"
|
||||
if (carbsAfterConstraints - carbs != 0) {
|
||||
rMessage += "\n" + rh.gs(R.string.constraintapllied)
|
||||
}
|
||||
if (carbsAfterConstraints <= 0) {
|
||||
sendError("Carbs = 0! No action taken!")
|
||||
return
|
||||
}
|
||||
rAction += "ecarbs $carbsAfterConstraints $starttimestamp $duration"
|
||||
}
|
||||
|
||||
ACTION_CHANGE_REQUEST -> {
|
||||
rTitle = rh.gs(R.string.openloop_newsuggestion)
|
||||
rAction = "changeRequest"
|
||||
loop.lastRun?.let {
|
||||
rMessage += it.constraintsProcessed
|
||||
wearPlugin.requestChangeConfirmation(rTitle, rMessage, rAction)
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
lastConfirmActionString = rAction
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ACTION_CANCEL_CHANGE_REQUEST -> {
|
||||
rAction = "cancelChangeRequest"
|
||||
wearPlugin.requestNotificationCancel(rAction)
|
||||
return
|
||||
}
|
||||
|
||||
else -> {
|
||||
sendError(rh.gs(R.string.wear_unknown_action_string) + " " + act[0])
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
// send result
|
||||
wearPlugin.requestActionConfirmation(rTitle, rMessage, rAction)
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
lastConfirmActionString = rAction
|
||||
}
|
||||
|
||||
private fun generateTDDMessage(historyList: MutableList<TotalDailyDose>, dummies: MutableList<TotalDailyDose>): String {
|
||||
val profile = profileFunction.getProfile() ?: return "No profile loaded :("
|
||||
if (historyList.isEmpty()) {
|
||||
return "No history data!"
|
||||
}
|
||||
val df: DateFormat = SimpleDateFormat("dd.MM.", Locale.getDefault())
|
||||
var message = ""
|
||||
val refTDD = profile.baseBasalSum() * 2
|
||||
val pump = activePlugin.activePump
|
||||
if (df.format(Date(historyList[0].timestamp)) == df.format(Date())) {
|
||||
val tdd = historyList[0].total
|
||||
historyList.removeAt(0)
|
||||
message += "Today: " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100 * tdd / refTDD) + "%") + "\n"
|
||||
message += "\n"
|
||||
} else if (pump is DanaRPlugin) {
|
||||
val tdd = danaPump.dailyTotalUnits
|
||||
message += "Today: " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100 * tdd / refTDD) + "%") + "\n"
|
||||
message += "\n"
|
||||
}
|
||||
var weighted03 = 0.0
|
||||
var weighted05 = 0.0
|
||||
var weighted07 = 0.0
|
||||
historyList.reverse()
|
||||
for ((i, record) in historyList.withIndex()) {
|
||||
val tdd = record.total
|
||||
if (i == 0) {
|
||||
weighted03 = tdd
|
||||
weighted05 = tdd
|
||||
weighted07 = tdd
|
||||
} else {
|
||||
weighted07 = weighted07 * 0.3 + tdd * 0.7
|
||||
weighted05 = weighted05 * 0.5 + tdd * 0.5
|
||||
weighted03 = weighted03 * 0.7 + tdd * 0.3
|
||||
}
|
||||
}
|
||||
message += "weighted:\n"
|
||||
message += "0.3: " + DecimalFormatter.to2Decimal(weighted03) + "U " + (DecimalFormatter.to0Decimal(100 * weighted03 / refTDD) + "%") + "\n"
|
||||
message += "0.5: " + DecimalFormatter.to2Decimal(weighted05) + "U " + (DecimalFormatter.to0Decimal(100 * weighted05 / refTDD) + "%") + "\n"
|
||||
message += "0.7: " + DecimalFormatter.to2Decimal(weighted07) + "U " + (DecimalFormatter.to0Decimal(100 * weighted07 / refTDD) + "%") + "\n"
|
||||
message += "\n"
|
||||
historyList.reverse()
|
||||
//add TDDs:
|
||||
for (record in historyList) {
|
||||
val tdd = record.total
|
||||
message += df.format(Date(record.timestamp)) + " " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100 * tdd / refTDD) + "%") + (if (dummies.contains(record)) "x" else "") + "\n"
|
||||
}
|
||||
return message
|
||||
}
|
||||
|
||||
private fun isOldData(historyList: List<TotalDailyDose>): Boolean {
|
||||
val activePump = activePlugin.activePump
|
||||
val startsYesterday = activePump === danaRPlugin || activePump === danaRSPlugin || activePump === danaRv2Plugin || activePump === danaRKoreanPlugin || activePump === localInsightPlugin
|
||||
val df: DateFormat = SimpleDateFormat("dd.MM.", Locale.getDefault())
|
||||
return historyList.size < 3 || df.format(Date(historyList[0].timestamp)) != df.format(Date(System.currentTimeMillis() - if (startsYesterday) 1000 * 60 * 60 * 24 else 0))
|
||||
}
|
||||
|
||||
private fun getTDDList(returnDummies: MutableList<TotalDailyDose>): MutableList<TotalDailyDose> {
|
||||
var historyList = repository.getLastTotalDailyDoses(10, false).blockingGet().toMutableList()
|
||||
//var historyList = databaseHelper.getTDDs().toMutableList()
|
||||
historyList = historyList.subList(0, min(10, historyList.size))
|
||||
//fill single gaps - only needed for Dana*R data
|
||||
val dummies: MutableList<TotalDailyDose> = returnDummies
|
||||
val df: DateFormat = SimpleDateFormat("dd.MM.", Locale.getDefault())
|
||||
for (i in 0 until historyList.size - 1) {
|
||||
val elem1 = historyList[i]
|
||||
val elem2 = historyList[i + 1]
|
||||
if (df.format(Date(elem1.timestamp)) != df.format(Date(elem2.timestamp + 25 * 60 * 60 * 1000))) {
|
||||
val dummy = TotalDailyDose(timestamp = elem1.timestamp - T.hours(24).msecs(), bolusAmount = elem1.bolusAmount / 2, basalAmount = elem1.basalAmount / 2)
|
||||
dummies.add(dummy)
|
||||
elem1.basalAmount /= 2.0
|
||||
elem1.bolusAmount /= 2.0
|
||||
}
|
||||
}
|
||||
historyList.addAll(dummies)
|
||||
historyList.sortWith { lhs, rhs -> (rhs.timestamp - lhs.timestamp).toInt() }
|
||||
return historyList
|
||||
}
|
||||
|
||||
private val pumpStatus: String
|
||||
get() = activePlugin.activePump.shortStatus(false)
|
||||
|
||||
// decide if enabled/disabled closed/open; what Plugin as APS?
|
||||
private val loopStatus: String
|
||||
get() {
|
||||
var ret = ""
|
||||
// decide if enabled/disabled closed/open; what Plugin as APS?
|
||||
if ((loop as PluginBase).isEnabled()) {
|
||||
ret += if (constraintChecker.isClosedLoopAllowed().value()) {
|
||||
"CLOSED LOOP\n"
|
||||
} else {
|
||||
"OPEN LOOP\n"
|
||||
}
|
||||
val aps = activePlugin.activeAPS
|
||||
ret += "APS: " + (aps as PluginBase).name
|
||||
val lastRun = loop.lastRun
|
||||
if (lastRun != null) {
|
||||
ret += "\nLast Run: " + dateUtil.timeString(lastRun.lastAPSRun)
|
||||
if (lastRun.lastTBREnact != 0L) ret += "\nLast Enact: " + dateUtil.timeString(lastRun.lastTBREnact)
|
||||
}
|
||||
} else {
|
||||
ret += "LOOP DISABLED\n"
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
//Check for Temp-Target:
|
||||
private val targetsStatus: String
|
||||
get() {
|
||||
var ret = ""
|
||||
if (!config.APS) {
|
||||
return "Targets only apply in APS mode!"
|
||||
}
|
||||
val profile = profileFunction.getProfile() ?: return "No profile set :("
|
||||
//Check for Temp-Target:
|
||||
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||
if (tempTarget is ValueWrapper.Existing) {
|
||||
ret += "Temp Target: " + Profile.toTargetRangeString(tempTarget.value.lowTarget, tempTarget.value.lowTarget, GlucoseUnit.MGDL, profileFunction.getUnits())
|
||||
ret += "\nuntil: " + dateUtil.timeString(tempTarget.value.end)
|
||||
ret += "\n\n"
|
||||
}
|
||||
ret += "DEFAULT RANGE: "
|
||||
ret += Profile.fromMgdlToUnits(profile.getTargetLowMgdl(), profileFunction.getUnits()).toString() + " - " + Profile.fromMgdlToUnits(profile.getTargetHighMgdl(), profileFunction.getUnits())
|
||||
ret += " target: " + Profile.fromMgdlToUnits(profile.getTargetMgdl(), profileFunction.getUnits())
|
||||
return ret
|
||||
}
|
||||
|
||||
private val oAPSResultStatus: String
|
||||
get() {
|
||||
var ret = ""
|
||||
if (!config.APS)
|
||||
return "Only apply in APS mode!"
|
||||
val usedAPS = activePlugin.activeAPS
|
||||
val result = usedAPS.lastAPSResult ?: return "Last result not available!"
|
||||
ret += if (!result.isChangeRequested) {
|
||||
rh.gs(R.string.nochangerequested) + "\n"
|
||||
} else if (result.rate == 0.0 && result.duration == 0) {
|
||||
rh.gs(R.string.canceltemp) + "\n"
|
||||
} else {
|
||||
rh.gs(R.string.rate) + ": " + DecimalFormatter.to2Decimal(result.rate) + " U/h " +
|
||||
"(" + DecimalFormatter.to2Decimal(result.rate / activePlugin.activePump.baseBasalRate * 100) + "%)\n" +
|
||||
rh.gs(R.string.duration) + ": " + DecimalFormatter.to0Decimal(result.duration.toDouble()) + " min\n"
|
||||
}
|
||||
ret += "\n" + rh.gs(R.string.reason) + ": " + result.reason
|
||||
return ret
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun handleConfirmation(actionString: String) {
|
||||
if (!sp.getBoolean(R.string.key_wear_control, false)) return
|
||||
//Guard from old or duplicate confirmations
|
||||
if (lastConfirmActionString == null) return
|
||||
if (lastConfirmActionString != actionString) return
|
||||
if (System.currentTimeMillis() - lastSentTimestamp > timeout) return
|
||||
lastConfirmActionString = null
|
||||
// do the parsing, check constraints and enact!
|
||||
val act = actionString.split("\\s+".toRegex()).toTypedArray()
|
||||
when (act[0]) {
|
||||
ACTION_FILL -> {
|
||||
val amount = SafeParse.stringToDouble(act[1])
|
||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(amount)).value()
|
||||
if (amount - insulinAfterConstraints != 0.0) {
|
||||
ToastUtils.showToastInUiThread(context, "aborting: previously applied constraint changed")
|
||||
sendError("aborting: previously applied constraint changed")
|
||||
return
|
||||
}
|
||||
doFillBolus(amount)
|
||||
}
|
||||
|
||||
ACTION_TEMPORARY_TARGET -> {
|
||||
val duration = SafeParse.stringToInt(act[2])
|
||||
val low = SafeParse.stringToDouble(act[3])
|
||||
val high = SafeParse.stringToDouble(act[4])
|
||||
generateTempTarget(duration, low, high)
|
||||
}
|
||||
|
||||
ACTION_WIZARD2 -> {
|
||||
if (lastBolusWizard != null) { //use last calculation as confirmed string matches
|
||||
doBolus(lastBolusWizard!!.calculatedTotalInsulin, lastBolusWizard!!.carbs, null, 0)
|
||||
lastBolusWizard = null
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_BOLUS -> {
|
||||
val insulin = SafeParse.stringToDouble(act[1])
|
||||
val carbs = SafeParse.stringToInt(act[2])
|
||||
doBolus(insulin, carbs, null, 0)
|
||||
}
|
||||
|
||||
ACTION_CPP_SET -> {
|
||||
val timeshift = SafeParse.stringToInt(act[1])
|
||||
val percentage = SafeParse.stringToInt(act[2])
|
||||
setCPP(timeshift, percentage)
|
||||
}
|
||||
|
||||
ACTION_E_CARBS -> {
|
||||
val carbs = SafeParse.stringToInt(act[1])
|
||||
val starttime = SafeParse.stringToLong(act[2])
|
||||
val duration = SafeParse.stringToInt(act[3])
|
||||
doECarbs(carbs, starttime, duration)
|
||||
}
|
||||
|
||||
ACTION_DISMISS_OVERVIEW_NOTIF -> {
|
||||
rxBus.send(EventDismissNotification(SafeParse.stringToInt(act[1])))
|
||||
}
|
||||
|
||||
ACTION_CHANGE_REQUEST -> {
|
||||
loop.acceptChangeRequest()
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.cancel(Constants.notificationID)
|
||||
}
|
||||
}
|
||||
lastBolusWizard = null
|
||||
}
|
||||
|
||||
private fun setCPP(timeshift: Int, percentage: Int) {
|
||||
var msg = ""
|
||||
//check for validity
|
||||
if (percentage < Constants.CPP_MIN_PERCENTAGE || percentage > Constants.CPP_MAX_PERCENTAGE) {
|
||||
msg += rh.gs(R.string.valueoutofrange, "Profile-Percentage") + "\n"
|
||||
}
|
||||
if (timeshift < 0 || timeshift > 23) {
|
||||
msg += rh.gs(R.string.valueoutofrange, "Profile-Timeshift") + "\n"
|
||||
}
|
||||
val profile = profileFunction.getProfile()
|
||||
if (profile == null) {
|
||||
msg += rh.gs(R.string.notloadedplugins) + "\n"
|
||||
}
|
||||
if ("" != msg) {
|
||||
msg += rh.gs(R.string.valuesnotstored)
|
||||
val rTitle = "STATUS"
|
||||
val rAction = "statusmessage"
|
||||
wearPlugin.requestActionConfirmation(rTitle, msg, rAction)
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
lastConfirmActionString = rAction
|
||||
return
|
||||
}
|
||||
//send profile to pump
|
||||
uel.log(Action.PROFILE_SWITCH, Sources.Wear,
|
||||
ValueWithUnit.Percent(percentage),
|
||||
ValueWithUnit.Hour(timeshift).takeIf { timeshift != 0 })
|
||||
profileFunction.createProfileSwitch(0, percentage, timeshift)
|
||||
}
|
||||
|
||||
private fun generateTempTarget(duration: Int, low: Double, high: Double) {
|
||||
if (duration != 0) {
|
||||
disposable += repository.runTransactionForResult(
|
||||
InsertAndCancelCurrentTemporaryTargetTransaction(
|
||||
timestamp = System.currentTimeMillis(),
|
||||
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
|
||||
reason = TemporaryTarget.Reason.WEAR,
|
||||
lowTarget = Profile.toMgdl(low, profileFunction.getUnits()),
|
||||
highTarget = Profile.toMgdl(high, profileFunction.getUnits())
|
||||
)
|
||||
).subscribe({ result ->
|
||||
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") }
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
})
|
||||
uel.log(
|
||||
Action.TT, Sources.Wear,
|
||||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR),
|
||||
ValueWithUnit.fromGlucoseUnit(low, profileFunction.getUnits().asText),
|
||||
ValueWithUnit.fromGlucoseUnit(high, profileFunction.getUnits().asText).takeIf { low != high },
|
||||
ValueWithUnit.Minute(duration)
|
||||
)
|
||||
} else {
|
||||
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(System.currentTimeMillis()))
|
||||
.subscribe({ result ->
|
||||
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
|
||||
}, {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
|
||||
})
|
||||
uel.log(
|
||||
Action.CANCEL_TT, Sources.Wear,
|
||||
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doFillBolus(amount: Double) {
|
||||
val detailedBolusInfo = DetailedBolusInfo()
|
||||
detailedBolusInfo.insulin = amount
|
||||
detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.PRIMING
|
||||
uel.log(Action.PRIME_BOLUS, Sources.Wear,
|
||||
ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 })
|
||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
sendError(
|
||||
rh.gs(R.string.treatmentdeliveryerror) +
|
||||
"\n" +
|
||||
result.comment
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun doECarbs(carbs: Int, time: Long, duration: Int) {
|
||||
uel.log(if (duration == 0) Action.CARBS else Action.EXTENDED_CARBS, Sources.Wear,
|
||||
ValueWithUnit.Timestamp(time),
|
||||
ValueWithUnit.Gram(carbs),
|
||||
ValueWithUnit.Hour(duration).takeIf { duration != 0 })
|
||||
doBolus(0.0, carbs, time, duration)
|
||||
}
|
||||
|
||||
private fun doBolus(amount: Double, carbs: Int, carbsTime: Long?, carbsDuration: Int) {
|
||||
val detailedBolusInfo = DetailedBolusInfo()
|
||||
detailedBolusInfo.insulin = amount
|
||||
detailedBolusInfo.carbs = carbs.toDouble()
|
||||
detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.NORMAL
|
||||
detailedBolusInfo.carbsTimestamp = carbsTime
|
||||
detailedBolusInfo.carbsDuration = T.hours(carbsDuration.toLong()).msecs()
|
||||
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
|
||||
val action = when {
|
||||
amount.equals(0.0) -> Action.CARBS
|
||||
carbs.equals(0) -> Action.BOLUS
|
||||
carbsDuration > 0 -> Action.EXTENDED_CARBS
|
||||
else -> Action.TREATMENT
|
||||
}
|
||||
uel.log(action, Sources.Wear,
|
||||
ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 },
|
||||
ValueWithUnit.Gram(carbs).takeIf { carbs != 0 },
|
||||
ValueWithUnit.Hour(carbsDuration).takeIf { carbsDuration != 0 })
|
||||
commandQueue.bolus(detailedBolusInfo, object : Callback() {
|
||||
override fun run() {
|
||||
if (!result.success) {
|
||||
sendError(
|
||||
rh.gs(R.string.treatmentdeliveryerror) +
|
||||
"\n" +
|
||||
result.comment
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized private fun sendError(errorMessage: String) {
|
||||
wearPlugin.requestActionConfirmation("ERROR", errorMessage, "error")
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
lastConfirmActionString = null
|
||||
lastBolusWizard = null
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun sendStatusMessage(message: String) {
|
||||
wearPlugin.requestActionConfirmation("TDD", message, "statusmessage")
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
lastConfirmActionString = null
|
||||
lastBolusWizard = null
|
||||
}
|
||||
}
|
|
@ -6,10 +6,13 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.databinding.WearFragmentBinding
|
||||
import info.nightscout.androidaps.events.EventMobileToWear
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.weardata.EventData
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
@ -20,6 +23,7 @@ class WearFragment : DaggerFragment() {
|
|||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
|
||||
private var _binding: WearFragmentBinding? = null
|
||||
|
||||
|
@ -37,8 +41,8 @@ class WearFragment : DaggerFragment() {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding.resend.setOnClickListener { wearPlugin.resendDataToWatch() }
|
||||
binding.openSettings.setOnClickListener { wearPlugin.openSettings() }
|
||||
binding.resend.setOnClickListener { rxBus.send(EventData.ActionResendData("WearFragment")) }
|
||||
binding.openSettings.setOnClickListener { rxBus.send(EventMobileToWear(EventData.OpenSettings(dateUtil.now()))) }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
|
|
@ -2,24 +2,26 @@ package info.nightscout.androidaps.plugins.general.wear
|
|||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import dagger.Lazy
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.events.EventMobileToWear
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.plugins.aps.events.EventOpenAPSUpdateGui
|
||||
import info.nightscout.androidaps.plugins.aps.loop.events.EventLoopUpdateGui
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress
|
||||
import info.nightscout.androidaps.plugins.general.wear.wearintegration.WatchUpdaterService
|
||||
import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataHandlerMobile
|
||||
import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataLayerListenerServiceMobile
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.weardata.EventData
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
@ -32,10 +34,10 @@ class WearPlugin @Inject constructor(
|
|||
rh: ResourceHelper,
|
||||
private val aapsSchedulers: AapsSchedulers,
|
||||
private val sp: SP,
|
||||
private val ctx: Context,
|
||||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val rxBus: RxBus,
|
||||
private val actionStringHandler: Lazy<ActionStringHandler>
|
||||
private val context: Context,
|
||||
private val dataHandlerMobile: DataHandlerMobile
|
||||
|
||||
) : PluginBase(
|
||||
PluginDescription()
|
||||
|
@ -55,136 +57,43 @@ class WearPlugin @Inject constructor(
|
|||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
disposable += rxBus
|
||||
.toObservable(EventOpenAPSUpdateGui::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException)
|
||||
|
||||
disposable += rxBus
|
||||
.toObservable(EventExtendedBolusChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTempBasalChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventTreatmentChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventEffectiveProfileSwitchChanged::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendDataToWatch(status = false, basals = true, bgValue = false) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = true) }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
// possibly new high or low mark
|
||||
resendDataToWatch()
|
||||
// status may be formatted differently
|
||||
sendDataToWatch(status = true, basals = false, bgValue = false)
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventLoopUpdateGui::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({
|
||||
sendDataToWatch(status = true, basals = false, bgValue = false)
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventBolusRequested::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event: EventBolusRequested ->
|
||||
val status = rh.gs(R.string.bolusrequested, event.amount)
|
||||
val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUS_PROGRESS)
|
||||
intent.putExtra("progresspercent", 0)
|
||||
intent.putExtra("progressstatus", status)
|
||||
ctx.startService(intent)
|
||||
}, fabricPrivacy::logException)
|
||||
context.startService(Intent(context, DataLayerListenerServiceMobile::class.java))
|
||||
disposable += rxBus
|
||||
.toObservable(EventDismissBolusProgressIfRunning::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event: EventDismissBolusProgressIfRunning ->
|
||||
if (event.result == null) return@subscribe
|
||||
val status: String = if (event.result!!.success) {
|
||||
rh.gs(R.string.success)
|
||||
} else {
|
||||
rh.gs(R.string.nosuccess)
|
||||
event.result?.let {
|
||||
val status =
|
||||
if (it.success) rh.gs(R.string.success)
|
||||
else rh.gs(R.string.nosuccess)
|
||||
if (isEnabled()) rxBus.send(EventMobileToWear(EventData.BolusProgress(percent = 100, status = status)))
|
||||
}
|
||||
val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUS_PROGRESS)
|
||||
intent.putExtra("progresspercent", 100)
|
||||
intent.putExtra("progressstatus", status)
|
||||
ctx.startService(intent)
|
||||
}, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventOverviewBolusProgress::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ event: EventOverviewBolusProgress ->
|
||||
if (!event.isSMB() || sp.getBoolean("wear_notifySMB", true)) {
|
||||
val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUS_PROGRESS)
|
||||
intent.putExtra("progresspercent", event.percent)
|
||||
intent.putExtra("progressstatus", event.status)
|
||||
ctx.startService(intent)
|
||||
if (isEnabled()) rxBus.send(EventMobileToWear(EventData.BolusProgress(percent = event.percent, status = event.status)))
|
||||
}
|
||||
}, fabricPrivacy::logException)
|
||||
actionStringHandler.get().setup()
|
||||
disposable += rxBus
|
||||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ dataHandlerMobile.resendData("EventPreferenceChange") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ dataHandlerMobile.resendData("EventAutosensCalculationFinished") }, fabricPrivacy::logException)
|
||||
disposable += rxBus
|
||||
.toObservable(EventLoopUpdateGui::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ dataHandlerMobile.resendData("EventLoopUpdateGui") }, fabricPrivacy::logException)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
disposable.clear()
|
||||
super.onStop()
|
||||
actionStringHandler.get().tearDown()
|
||||
}
|
||||
|
||||
private fun sendDataToWatch(status: Boolean, basals: Boolean, bgValue: Boolean) {
|
||||
// only start service when this plugin is enabled
|
||||
if (isEnabled()) {
|
||||
if (bgValue) ctx.startService(Intent(ctx, WatchUpdaterService::class.java))
|
||||
if (basals) ctx.startService(Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BASALS))
|
||||
if (status) ctx.startService(Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_STATUS))
|
||||
}
|
||||
}
|
||||
|
||||
fun resendDataToWatch() {
|
||||
ctx.startService(Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_RESEND))
|
||||
}
|
||||
|
||||
fun openSettings() {
|
||||
ctx.startService(Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_OPEN_SETTINGS))
|
||||
}
|
||||
|
||||
fun requestNotificationCancel(actionString: String?) {
|
||||
ctx.startService(
|
||||
Intent(ctx, WatchUpdaterService::class.java)
|
||||
.setAction(WatchUpdaterService.ACTION_CANCEL_NOTIFICATION)
|
||||
.also {
|
||||
it.putExtra("actionstring", actionString)
|
||||
})
|
||||
}
|
||||
|
||||
fun requestActionConfirmation(title: String, message: String, actionString: String) {
|
||||
ctx.startService(
|
||||
Intent(ctx, WatchUpdaterService::class.java)
|
||||
.setAction(WatchUpdaterService.ACTION_SEND_ACTION_CONFIRMATION_REQUEST)
|
||||
.also {
|
||||
it.putExtra("title", title)
|
||||
it.putExtra("message", message)
|
||||
it.putExtra("actionstring", actionString)
|
||||
})
|
||||
}
|
||||
|
||||
fun requestChangeConfirmation(title: String, message: String, actionString: String) {
|
||||
ctx.startService(
|
||||
Intent(ctx, WatchUpdaterService::class.java)
|
||||
.setAction(WatchUpdaterService.ACTION_SEND_CHANGE_CONFIRMATION_REQUEST)
|
||||
.also {
|
||||
it.putExtra("title", title)
|
||||
it.putExtra("message", message)
|
||||
it.putExtra("actionstring", actionString)
|
||||
})
|
||||
context.stopService(Intent(context, DataLayerListenerServiceMobile::class.java))
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventWearConfirmAction(val action: String) : Event()
|
|
@ -1,5 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventWearInitiateAction(val action: String) : Event()
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,200 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear.wearintegration
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import com.google.android.gms.tasks.Tasks
|
||||
import com.google.android.gms.wearable.*
|
||||
import dagger.android.AndroidInjection
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.events.EventMobileToWear
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.Config
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||
import info.nightscout.androidaps.interfaces.Loop
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||
import info.nightscout.androidaps.plugins.general.wear.WearPlugin
|
||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearUpdateGui
|
||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||
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 io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.tasks.await
|
||||
import javax.inject.Inject
|
||||
|
||||
class DataLayerListenerServiceMobile : WearableListenerService() {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||
@Inject lateinit var rh: ResourceHelper
|
||||
@Inject lateinit var loop: Loop
|
||||
@Inject lateinit var wearPlugin: WearPlugin
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var quickWizard: QuickWizard
|
||||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
|
||||
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
|
||||
private val dataClient by lazy { Wearable.getDataClient(this) }
|
||||
private val messageClient by lazy { Wearable.getMessageClient(this) }
|
||||
private val capabilityClient by lazy { Wearable.getCapabilityClient(this) }
|
||||
//private val nodeClient by lazy { Wearable.getNodeClient(this) }
|
||||
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
||||
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
private val rxPath get() = getString(R.string.path_rx_bridge)
|
||||
|
||||
override fun onCreate() {
|
||||
AndroidInjection.inject(this)
|
||||
super.onCreate()
|
||||
aapsLogger.debug(LTag.WEAR, "onCreate")
|
||||
handler.post { updateTranscriptionCapability() }
|
||||
disposable += rxBus
|
||||
.toObservable(EventMobileToWear::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe { sendMessage(rxPath, it.payload.serialize()) }
|
||||
}
|
||||
|
||||
override fun onCapabilityChanged(p0: CapabilityInfo) {
|
||||
super.onCapabilityChanged(p0)
|
||||
handler.post { updateTranscriptionCapability() }
|
||||
aapsLogger.debug(LTag.WEAR, "onCapabilityChanged: ${p0.name} ${p0.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}")
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
disposable.clear()
|
||||
scope.cancel()
|
||||
}
|
||||
|
||||
@Suppress("ControlFlowWithEmptyBody", "UNUSED_EXPRESSION")
|
||||
override fun onDataChanged(dataEvents: DataEventBuffer) {
|
||||
//aapsLogger.debug(LTag.WEAR, "onDataChanged")
|
||||
|
||||
if (wearPlugin.isEnabled()) {
|
||||
dataEvents.forEach { event ->
|
||||
if (event.type == DataEvent.TYPE_CHANGED) {
|
||||
val path = event.dataItem.uri.path
|
||||
|
||||
aapsLogger.debug(LTag.WEAR, "onDataChanged: Path: $path, EventDataItem=${event.dataItem}")
|
||||
try {
|
||||
when (path) {
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
aapsLogger.error(LTag.WEAR, "Message failed", exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onDataChanged(dataEvents)
|
||||
}
|
||||
|
||||
override fun onMessageReceived(messageEvent: MessageEvent) {
|
||||
super.onMessageReceived(messageEvent)
|
||||
|
||||
if (wearPlugin.isEnabled()) {
|
||||
when (messageEvent.path) {
|
||||
rxPath -> {
|
||||
aapsLogger.debug(LTag.WEAR, "onMessageReceived: ${String(messageEvent.data)}")
|
||||
val command = EventData.deserialize(String(messageEvent.data))
|
||||
rxBus.send(command.also { it.sourceNodeId = messageEvent.sourceNodeId })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var transcriptionNodeId: String? = null
|
||||
|
||||
private fun updateTranscriptionCapability() {
|
||||
val capabilityInfo: CapabilityInfo = Tasks.await(
|
||||
capabilityClient.getCapability(WEAR_CAPABILITY, CapabilityClient.FILTER_REACHABLE)
|
||||
)
|
||||
aapsLogger.debug(LTag.WEAR, "Nodes: ${capabilityInfo.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}")
|
||||
val bestNode = pickBestNodeId(capabilityInfo.nodes)
|
||||
transcriptionNodeId = bestNode?.id
|
||||
wearPlugin.connectedDevice = bestNode?.displayName ?: "---"
|
||||
rxBus.send(EventWearUpdateGui())
|
||||
aapsLogger.debug(LTag.WEAR, "Selected node: ${bestNode?.displayName} $transcriptionNodeId")
|
||||
rxBus.send(EventMobileToWear(EventData.ActionPing(System.currentTimeMillis())))
|
||||
rxBus.send(EventData.ActionResendData("WatchUpdaterService"))
|
||||
}
|
||||
|
||||
// Find a nearby node or pick one arbitrarily
|
||||
private fun pickBestNodeId(nodes: Set<Node>): Node? =
|
||||
nodes.firstOrNull { it.isNearby } ?: nodes.firstOrNull()
|
||||
|
||||
@Suppress("unused")
|
||||
private fun sendData(path: String, vararg params: DataMap) {
|
||||
if (wearPlugin.isEnabled()) {
|
||||
scope.launch {
|
||||
try {
|
||||
for (dm in params) {
|
||||
val request = PutDataMapRequest.create(path).apply {
|
||||
dataMap.putAll(dm)
|
||||
}
|
||||
.asPutDataRequest()
|
||||
.setUrgent()
|
||||
|
||||
val result = dataClient.putDataItem(request).await()
|
||||
aapsLogger.debug(LTag.WEAR, "sendData: ${result.uri} ${params.joinToString()}")
|
||||
}
|
||||
} catch (cancellationException: CancellationException) {
|
||||
throw cancellationException
|
||||
} catch (exception: Exception) {
|
||||
aapsLogger.error(LTag.WEAR, "DataItem failed: $exception")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendMessage(path: String, data: String?) {
|
||||
aapsLogger.debug(LTag.WEAR, "sendMessage: $path $data")
|
||||
transcriptionNodeId?.also { nodeId ->
|
||||
messageClient
|
||||
.sendMessage(nodeId, path, data?.toByteArray() ?: byteArrayOf()).apply {
|
||||
addOnSuccessListener { }
|
||||
addOnFailureListener {
|
||||
aapsLogger.debug(LTag.WEAR, "sendMessage: $path failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
private fun sendMessage(path: String, data: ByteArray) {
|
||||
aapsLogger.debug(LTag.WEAR, "sendMessage: $path")
|
||||
transcriptionNodeId?.also { nodeId ->
|
||||
messageClient
|
||||
.sendMessage(nodeId, path, data).apply {
|
||||
addOnSuccessListener { }
|
||||
addOnFailureListener {
|
||||
aapsLogger.debug(LTag.WEAR, "sendMessage: $path failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val WEAR_CAPABILITY = "androidaps_wear"
|
||||
}
|
||||
}
|
|
@ -1,633 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear.wearintegration
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import com.google.android.gms.tasks.Tasks
|
||||
import com.google.android.gms.wearable.*
|
||||
import dagger.android.AndroidInjection
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.Bolus
|
||||
import info.nightscout.androidaps.database.entities.GlucoseValue
|
||||
import info.nightscout.androidaps.database.entities.TemporaryBasal
|
||||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||
import info.nightscout.androidaps.extensions.toStringShort
|
||||
import info.nightscout.androidaps.extensions.valueToUnitsString
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.interfaces.Profile.Companion.fromMgdlToUnits
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.GlucoseValueDataPoint
|
||||
import info.nightscout.androidaps.plugins.general.wear.WearPlugin
|
||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction
|
||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
|
||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearUpdateGui
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter.to0Decimal
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter.to1Decimal
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter.to2Decimal
|
||||
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||
import info.nightscout.androidaps.utils.TrendCalculator
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.weardata.WearConstants
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.tasks.await
|
||||
import java.util.function.Consumer
|
||||
import java.util.stream.Collectors
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.abs
|
||||
|
||||
class WatchUpdaterService : WearableListenerService() {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var iobCobCalculator: IobCobCalculator
|
||||
@Inject lateinit var rh: ResourceHelper
|
||||
@Inject lateinit var loop: Loop
|
||||
@Inject lateinit var wearPlugin: WearPlugin
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var quickWizard: QuickWizard
|
||||
@Inject lateinit var config: Config
|
||||
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
|
||||
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var defaultValueHelper: DefaultValueHelper
|
||||
@Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider
|
||||
@Inject lateinit var trendCalculator: TrendCalculator
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var wearConstants: WearConstants
|
||||
|
||||
private val dataClient by lazy { Wearable.getDataClient(this) }
|
||||
private val messageClient by lazy { Wearable.getMessageClient(this) }
|
||||
private val capabilityClient by lazy { Wearable.getCapabilityClient(this) }
|
||||
//private val nodeClient by lazy { Wearable.getNodeClient(this) }
|
||||
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
||||
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
override fun onCreate() {
|
||||
AndroidInjection.inject(this)
|
||||
super.onCreate()
|
||||
aapsLogger.debug(LTag.WEAR, "onCreate")
|
||||
handler.post { updateTranscriptionCapability() }
|
||||
}
|
||||
|
||||
override fun onCapabilityChanged(p0: CapabilityInfo) {
|
||||
super.onCapabilityChanged(p0)
|
||||
handler.post { updateTranscriptionCapability() }
|
||||
aapsLogger.debug(LTag.WEAR, "onCapabilityChanged: ${p0.name} ${p0.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}")
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
disposable.clear()
|
||||
scope.cancel()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
aapsLogger.debug(LTag.WEAR, "onStartCommand ${intent?.action}")
|
||||
if (wearPlugin.isEnabled()) {
|
||||
handler.post {
|
||||
when (intent?.action) {
|
||||
ACTION_RESEND -> resendData()
|
||||
ACTION_OPEN_SETTINGS -> sendMessage(wearConstants.M_W_OPEN_SETTINGS, byteArrayOf())
|
||||
ACTION_SEND_STATUS -> sendStatus()
|
||||
ACTION_SEND_BASALS -> sendBasals()
|
||||
ACTION_SEND_BOLUS_PROGRESS -> sendBolusProgress(
|
||||
intent.getIntExtra("progresspercent", 0),
|
||||
intent.getStringExtra("progressstatus")
|
||||
)
|
||||
ACTION_SEND_ACTION_CONFIRMATION_REQUEST -> sendActionConfirmationRequest(
|
||||
intent.getStringExtra("title"),
|
||||
intent.getStringExtra("message"),
|
||||
intent.getStringExtra("actionstring")
|
||||
)
|
||||
ACTION_SEND_CHANGE_CONFIRMATION_REQUEST -> sendChangeConfirmationRequest(
|
||||
intent.getStringExtra("title"),
|
||||
intent.getStringExtra("message"),
|
||||
intent.getStringExtra("actionstring")
|
||||
)
|
||||
ACTION_CANCEL_NOTIFICATION -> sendCancelNotificationRequest(intent.getStringExtra("actionstring"))
|
||||
|
||||
null -> {}
|
||||
|
||||
else -> sendData()
|
||||
}
|
||||
}
|
||||
}
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
@Suppress("ControlFlowWithEmptyBody", "UNUSED_EXPRESSION")
|
||||
override fun onDataChanged(dataEvents: DataEventBuffer) {
|
||||
//aapsLogger.debug(LTag.WEAR, "onDataChanged")
|
||||
|
||||
if (wearPlugin.isEnabled()) {
|
||||
dataEvents.forEach { event ->
|
||||
if (event.type == DataEvent.TYPE_CHANGED) {
|
||||
val path = event.dataItem.uri.path
|
||||
|
||||
aapsLogger.debug(LTag.WEAR, "onDataChanged: Path: $path, EventDataItem=${event.dataItem}")
|
||||
try {
|
||||
when (path) {
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
aapsLogger.error(LTag.WEAR, "Message failed", exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onDataChanged(dataEvents)
|
||||
}
|
||||
|
||||
override fun onMessageReceived(messageEvent: MessageEvent) {
|
||||
super.onMessageReceived(messageEvent)
|
||||
aapsLogger.debug(LTag.WEAR, "onMessageReceived: $messageEvent")
|
||||
|
||||
if (wearPlugin.isEnabled()) {
|
||||
when (messageEvent.path) {
|
||||
wearConstants.W_M_RESEND_DATA -> resendData()
|
||||
wearConstants.W_M_CANCEL_BOLUS -> activePlugin.activePump.stopBolusDelivering()
|
||||
|
||||
wearConstants.W_M_INITIATE_ACTION ->
|
||||
String(messageEvent.data).also { actionstring ->
|
||||
aapsLogger.debug(LTag.WEAR, "Initiate action: $actionstring")
|
||||
rxBus.send(EventWearInitiateAction(actionstring))
|
||||
}
|
||||
|
||||
wearConstants.W_M_CONFIRM_ACTION ->
|
||||
String(messageEvent.data).also { actionstring ->
|
||||
aapsLogger.debug(LTag.WEAR, "Wear confirm action: $actionstring")
|
||||
rxBus.send(EventWearConfirmAction(actionstring))
|
||||
}
|
||||
|
||||
wearConstants.W_M_PONG -> aapsLogger.debug(LTag.WEAR, "Pong response from ${messageEvent.sourceNodeId}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var transcriptionNodeId: String? = null
|
||||
|
||||
private fun updateTranscriptionCapability() {
|
||||
val capabilityInfo: CapabilityInfo = Tasks.await(
|
||||
capabilityClient.getCapability(WEAR_CAPABILITY, CapabilityClient.FILTER_REACHABLE)
|
||||
)
|
||||
aapsLogger.debug(LTag.WEAR, "Nodes: ${capabilityInfo.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}")
|
||||
val bestNode = pickBestNodeId(capabilityInfo.nodes)
|
||||
transcriptionNodeId = bestNode?.id
|
||||
wearPlugin.connectedDevice = bestNode?.displayName ?: "---"
|
||||
rxBus.send(EventWearUpdateGui())
|
||||
aapsLogger.debug(LTag.WEAR, "Selected node: ${bestNode?.displayName} $transcriptionNodeId")
|
||||
sendMessage(wearConstants.M_W_PING, byteArrayOf())
|
||||
}
|
||||
|
||||
// Find a nearby node or pick one arbitrarily
|
||||
private fun pickBestNodeId(nodes: Set<Node>): Node? =
|
||||
nodes.firstOrNull { it.isNearby } ?: nodes.firstOrNull()
|
||||
|
||||
private fun sendData(path: String, vararg params: DataMap) {
|
||||
if (wearPlugin.isEnabled()) {
|
||||
scope.launch {
|
||||
try {
|
||||
for (dm in params) {
|
||||
val request = PutDataMapRequest.create(path).apply {
|
||||
dataMap.putAll(dm)
|
||||
}
|
||||
.asPutDataRequest()
|
||||
.setUrgent()
|
||||
|
||||
val result = dataClient.putDataItem(request).await()
|
||||
aapsLogger.debug(LTag.WEAR, "sendData: ${result.uri} ${params.joinToString()}")
|
||||
}
|
||||
} catch (cancellationException: CancellationException) {
|
||||
throw cancellationException
|
||||
} catch (exception: Exception) {
|
||||
aapsLogger.error(LTag.WEAR, "DataItem failed: $exception")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendMessage(path: String, data: ByteArray) {
|
||||
if (wearPlugin.isEnabled()) {
|
||||
aapsLogger.debug(LTag.WEAR, "sendMessage: $path")
|
||||
transcriptionNodeId?.also { nodeId ->
|
||||
messageClient
|
||||
.sendMessage(nodeId, path, data).apply {
|
||||
addOnSuccessListener { }
|
||||
addOnFailureListener {
|
||||
aapsLogger.debug(LTag.WEAR, "sendMessage: $path failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendData() {
|
||||
val lastBG = iobCobCalculator.ads.lastBg() ?: return
|
||||
val glucoseStatus = glucoseStatusProvider.glucoseStatusData
|
||||
aapsLogger.debug(LTag.WEAR, "Sending bg data to wear")
|
||||
sendData(
|
||||
wearConstants.M_W_DATA,
|
||||
dataMapSingleBG(lastBG, glucoseStatus)
|
||||
)
|
||||
}
|
||||
|
||||
private fun resendData() {
|
||||
sendPreferences()
|
||||
sendQuickWizard()
|
||||
val startTime = System.currentTimeMillis() - (60000 * 60 * 5.5).toLong()
|
||||
val lastBg = iobCobCalculator.ads.lastBg() ?: return
|
||||
val graphBgs = repository.compatGetBgReadingsDataFromTime(startTime, true).blockingGet()
|
||||
val glucoseStatus = glucoseStatusProvider.getGlucoseStatusData(true)
|
||||
if (graphBgs.isNotEmpty()) {
|
||||
val entries = dataMapSingleBG(lastBg, glucoseStatus)
|
||||
val dataMaps = ArrayList<DataMap>(graphBgs.size)
|
||||
for (bg in graphBgs) {
|
||||
val dataMap: DataMap = dataMapSingleBG(bg, glucoseStatus)
|
||||
dataMaps.add(dataMap)
|
||||
}
|
||||
entries.putDataMapArrayList("entries", dataMaps)
|
||||
aapsLogger.debug(LTag.WEAR, "Sending graph bg data to wear")
|
||||
sendData(
|
||||
wearConstants.M_W_DATA,
|
||||
entries
|
||||
)
|
||||
}
|
||||
sendBasals()
|
||||
sendStatus()
|
||||
}
|
||||
|
||||
private fun sendBasals() {
|
||||
val now = System.currentTimeMillis()
|
||||
val startTimeWindow = now - (60000 * 60 * 5.5).toLong()
|
||||
val basals = java.util.ArrayList<DataMap>()
|
||||
val temps = java.util.ArrayList<DataMap>()
|
||||
val boluses = java.util.ArrayList<DataMap>()
|
||||
val predictions = java.util.ArrayList<DataMap>()
|
||||
val profile = profileFunction.getProfile() ?: return
|
||||
var beginBasalSegmentTime = startTimeWindow
|
||||
var runningTime = startTimeWindow
|
||||
var beginBasalValue = profile.getBasal(beginBasalSegmentTime)
|
||||
var endBasalValue = beginBasalValue
|
||||
var tb1 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime)
|
||||
var tb2: TemporaryBasal?
|
||||
var tbBefore = beginBasalValue
|
||||
var tbAmount = beginBasalValue
|
||||
var tbStart = runningTime
|
||||
if (tb1 != null) {
|
||||
val profileTB = profileFunction.getProfile(runningTime)
|
||||
if (profileTB != null) {
|
||||
tbAmount = tb1.convertedToAbsolute(runningTime, profileTB)
|
||||
tbStart = runningTime
|
||||
}
|
||||
}
|
||||
while (runningTime < now) {
|
||||
val profileTB = profileFunction.getProfile(runningTime) ?: return
|
||||
//basal rate
|
||||
endBasalValue = profile.getBasal(runningTime)
|
||||
if (endBasalValue != beginBasalValue) {
|
||||
//push the segment we recently left
|
||||
basals.add(basalMap(beginBasalSegmentTime, runningTime, beginBasalValue))
|
||||
|
||||
//begin new Basal segment
|
||||
beginBasalSegmentTime = runningTime
|
||||
beginBasalValue = endBasalValue
|
||||
}
|
||||
|
||||
//temps
|
||||
tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime)
|
||||
if (tb1 == null && tb2 == null) {
|
||||
//no temp stays no temp
|
||||
} else if (tb1 != null && tb2 == null) {
|
||||
//temp is over -> push it
|
||||
temps.add(tempMap(tbStart, tbBefore, runningTime, endBasalValue, tbAmount))
|
||||
tb1 = null
|
||||
} else if (tb1 == null && tb2 != null) {
|
||||
//temp begins
|
||||
tb1 = tb2
|
||||
tbStart = runningTime
|
||||
tbBefore = endBasalValue
|
||||
tbAmount = tb1.convertedToAbsolute(runningTime, profileTB)
|
||||
} else if (tb1 != null && tb2 != null) {
|
||||
val currentAmount = tb2.convertedToAbsolute(runningTime, profileTB)
|
||||
if (currentAmount != tbAmount) {
|
||||
temps.add(tempMap(tbStart, tbBefore, runningTime, currentAmount, tbAmount))
|
||||
tbStart = runningTime
|
||||
tbBefore = tbAmount
|
||||
tbAmount = currentAmount
|
||||
tb1 = tb2
|
||||
}
|
||||
}
|
||||
runningTime += (5 * 60 * 1000).toLong()
|
||||
}
|
||||
if (beginBasalSegmentTime != runningTime) {
|
||||
//push the remaining segment
|
||||
basals.add(basalMap(beginBasalSegmentTime, runningTime, beginBasalValue))
|
||||
}
|
||||
if (tb1 != null) {
|
||||
tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(now) //use "now" to express current situation
|
||||
if (tb2 == null) {
|
||||
//express the cancelled temp by painting it down one minute early
|
||||
temps.add(tempMap(tbStart, tbBefore, now - 60 * 1000, endBasalValue, tbAmount))
|
||||
} else {
|
||||
//express currently running temp by painting it a bit into the future
|
||||
val profileNow = profileFunction.getProfile(now)
|
||||
val currentAmount = tb2.convertedToAbsolute(now, profileNow!!)
|
||||
if (currentAmount != tbAmount) {
|
||||
temps.add(tempMap(tbStart, tbBefore, now, tbAmount, tbAmount))
|
||||
temps.add(tempMap(now, tbAmount, runningTime + 5 * 60 * 1000, currentAmount, currentAmount))
|
||||
} else {
|
||||
temps.add(tempMap(tbStart, tbBefore, runningTime + 5 * 60 * 1000, tbAmount, tbAmount))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(now) //use "now" to express current situation
|
||||
if (tb2 != null) {
|
||||
//onset at the end
|
||||
val profileTB = profileFunction.getProfile(runningTime)
|
||||
val currentAmount = tb2.convertedToAbsolute(runningTime, profileTB!!)
|
||||
temps.add(tempMap(now - 60 * 1000, endBasalValue, runningTime + 5 * 60 * 1000, currentAmount, currentAmount))
|
||||
}
|
||||
}
|
||||
repository.getBolusesIncludingInvalidFromTime(startTimeWindow, true).blockingGet()
|
||||
.stream()
|
||||
.filter { (_, _, _, _, _, _, _, _, _, type) -> type !== Bolus.Type.PRIMING }
|
||||
.forEach { (_, _, _, isValid, _, _, timestamp, _, amount, type) -> boluses.add(treatmentMap(timestamp, amount, 0.0, type === Bolus.Type.SMB, isValid)) }
|
||||
repository.getCarbsDataFromTimeExpanded(startTimeWindow, true).blockingGet()
|
||||
.forEach(Consumer { (_, _, _, isValid, _, _, timestamp, _, _, amount) -> boluses.add(treatmentMap(timestamp, 0.0, amount, false, isValid)) })
|
||||
val finalLastRun = loop.lastRun
|
||||
if (sp.getBoolean("wear_predictions", true) && finalLastRun?.request?.hasPredictions == true && finalLastRun.constraintsProcessed != null) {
|
||||
val predArray = finalLastRun.constraintsProcessed!!.predictions
|
||||
.stream().map { bg: GlucoseValue -> GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, rh) }
|
||||
.collect(Collectors.toList())
|
||||
if (predArray.isNotEmpty())
|
||||
for (bg in predArray) if (bg.data.value > 39) predictions.add(predictionMap(bg.data.timestamp, bg.data.value, bg.color(null)))
|
||||
}
|
||||
aapsLogger.debug(LTag.WEAR, "Sending basal data to wear")
|
||||
sendData(
|
||||
wearConstants.M_W_BASAL,
|
||||
DataMap().apply {
|
||||
putDataMapArrayList("basals", basals)
|
||||
putDataMapArrayList("temps", temps)
|
||||
putDataMapArrayList("boluses", boluses)
|
||||
putDataMapArrayList("predictions", predictions)
|
||||
})
|
||||
}
|
||||
|
||||
private fun deltaString(deltaMGDL: Double, deltaMMOL: Double, units: GlucoseUnit): String {
|
||||
val detailed = sp.getBoolean(R.string.key_wear_detailed_delta, false)
|
||||
var deltaString = if (deltaMGDL >= 0) "+" else "-"
|
||||
deltaString += if (units == GlucoseUnit.MGDL) {
|
||||
if (detailed) to1Decimal(abs(deltaMGDL)) else to0Decimal(abs(deltaMGDL))
|
||||
} else {
|
||||
if (detailed) to2Decimal(abs(deltaMMOL)) else to1Decimal(abs(deltaMMOL))
|
||||
}
|
||||
return deltaString
|
||||
}
|
||||
|
||||
private fun dataMapSingleBG(lastBG: GlucoseValue, glucoseStatus: GlucoseStatus?): DataMap {
|
||||
val units = profileFunction.getUnits()
|
||||
val lowLine = Profile.toMgdl(defaultValueHelper.determineLowLine(), units)
|
||||
val highLine = Profile.toMgdl(defaultValueHelper.determineHighLine(), units)
|
||||
val sgvLevel = if (lastBG.value > highLine) 1L else if (lastBG.value < lowLine) -1L else 0L
|
||||
val dataMap = DataMap()
|
||||
dataMap.putString("sgvString", lastBG.valueToUnitsString(units))
|
||||
dataMap.putString("glucoseUnits", units.asText)
|
||||
dataMap.putLong("timestamp", lastBG.timestamp)
|
||||
if (glucoseStatus == null) {
|
||||
dataMap.putString("slopeArrow", "")
|
||||
dataMap.putString("delta", "--")
|
||||
dataMap.putString("avgDelta", "--")
|
||||
} else {
|
||||
dataMap.putString("slopeArrow", trendCalculator.getTrendArrow(lastBG).symbol)
|
||||
dataMap.putString("delta", deltaString(glucoseStatus.delta, glucoseStatus.delta * Constants.MGDL_TO_MMOLL, units))
|
||||
dataMap.putString("avgDelta", deltaString(glucoseStatus.shortAvgDelta, glucoseStatus.shortAvgDelta * Constants.MGDL_TO_MMOLL, units))
|
||||
}
|
||||
dataMap.putLong("sgvLevel", sgvLevel)
|
||||
dataMap.putDouble("sgvDouble", lastBG.value)
|
||||
dataMap.putDouble("high", highLine)
|
||||
dataMap.putDouble("low", lowLine)
|
||||
return dataMap
|
||||
}
|
||||
|
||||
private fun tempMap(startTime: Long, startBasal: Double, to: Long, toBasal: Double, amount: Double) =
|
||||
DataMap().apply {
|
||||
putLong("starttime", startTime)
|
||||
putDouble("startBasal", startBasal)
|
||||
putLong("endtime", to)
|
||||
putDouble("endbasal", toBasal)
|
||||
putDouble("amount", amount)
|
||||
}
|
||||
|
||||
private fun basalMap(startTime: Long, endTime: Long, amount: Double) =
|
||||
DataMap().apply {
|
||||
putLong("starttime", startTime)
|
||||
putLong("endtime", endTime)
|
||||
putDouble("amount", amount)
|
||||
}
|
||||
|
||||
private fun treatmentMap(date: Long, bolus: Double, carbs: Double, isSMB: Boolean, isValid: Boolean) =
|
||||
DataMap().apply {
|
||||
putLong("date", date)
|
||||
putDouble("bolus", bolus)
|
||||
putDouble("carbs", carbs)
|
||||
putBoolean("isSMB", isSMB)
|
||||
putBoolean("isValid", isValid)
|
||||
}
|
||||
|
||||
private fun predictionMap(timestamp: Long, sgv: Double, color: Int) =
|
||||
DataMap().apply {
|
||||
putLong("timestamp", timestamp)
|
||||
putDouble("sgv", sgv)
|
||||
putInt("color", color)
|
||||
}
|
||||
|
||||
private fun quickMap(q: QuickWizardEntry) =
|
||||
DataMap().apply {
|
||||
putString("guid", q.guid())
|
||||
putString("button_text", q.buttonText())
|
||||
putInt("carbs", q.carbs())
|
||||
putInt("from", q.validFrom())
|
||||
putInt("to", q.validTo())
|
||||
}
|
||||
|
||||
private fun sendBolusProgress(progressPercent: Int?, status: String?) {
|
||||
progressPercent ?: return
|
||||
aapsLogger.debug(LTag.WEAR, "Sending bolus progress: $progressPercent $status")
|
||||
sendData(
|
||||
wearConstants.M_W_BOLUS_PROGRESS,
|
||||
DataMap().apply {
|
||||
putLong("timestamp", System.currentTimeMillis())
|
||||
putString("bolusProgress", "bolusProgress")
|
||||
putString("progressstatus", status ?: "")
|
||||
putInt("progresspercent", progressPercent)
|
||||
})
|
||||
}
|
||||
|
||||
private fun sendActionConfirmationRequest(title: String?, message: String?, actionstring: String?) {
|
||||
title ?: message ?: actionstring ?: return
|
||||
aapsLogger.debug(LTag.WEAR, "Requesting confirmation from wear: $actionstring")
|
||||
sendData(
|
||||
wearConstants.M_W_ACTION_CONFIRMATION_REQUEST,
|
||||
DataMap().apply {
|
||||
putLong("timestamp", System.currentTimeMillis())
|
||||
putString("actionConfirmationRequest", "actionConfirmationRequest")
|
||||
putString("title", title)
|
||||
putString("message", message)
|
||||
putString("actionstring", actionstring)
|
||||
})
|
||||
}
|
||||
|
||||
private fun sendChangeConfirmationRequest(title: String?, message: String?, actionstring: String?) {
|
||||
title ?: message ?: actionstring ?: return
|
||||
aapsLogger.debug(LTag.WEAR, "Requesting confirmation from wear: $actionstring")
|
||||
sendData(
|
||||
wearConstants.M_W_ACTION_CHANGE_CONFIRMATION_REQUEST,
|
||||
DataMap().apply {
|
||||
putLong("timestamp", System.currentTimeMillis())
|
||||
putString("changeConfirmationRequest", "changeConfirmationRequest")
|
||||
putString("title", title)
|
||||
putString("message", message)
|
||||
putString("actionstring", actionstring)
|
||||
})
|
||||
}
|
||||
|
||||
private fun sendCancelNotificationRequest(actionstring: String?) {
|
||||
actionstring ?: return
|
||||
aapsLogger.debug(LTag.WEAR, "Canceling notification on wear: $actionstring")
|
||||
sendData(
|
||||
wearConstants.M_W_ACTION_CANCEL_NOTIFICATION_REQUEST,
|
||||
DataMap().apply {
|
||||
putLong("timestamp", System.currentTimeMillis())
|
||||
putString("cancelNotificationRequest", "cancelNotificationRequest")
|
||||
putString("actionstring", actionstring)
|
||||
})
|
||||
}
|
||||
|
||||
private fun sendStatus() {
|
||||
aapsLogger.debug(LTag.WEAR, "Updating status on wear")
|
||||
val profile = profileFunction.getProfile()
|
||||
var status = rh.gs(R.string.noprofile)
|
||||
var iobSum = ""
|
||||
var iobDetail = ""
|
||||
var cobString = ""
|
||||
var currentBasal = ""
|
||||
var bgiString = ""
|
||||
if (profile != null) {
|
||||
val bolusIob = iobCobCalculator.calculateIobFromBolus().round()
|
||||
val basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round()
|
||||
iobSum = to2Decimal(bolusIob.iob + basalIob.basaliob)
|
||||
iobDetail = "(" + to2Decimal(bolusIob.iob) + "|" + to2Decimal(basalIob.basaliob) + ")"
|
||||
cobString = iobCobCalculator.getCobInfo(false, "WatcherUpdaterService").generateCOBString()
|
||||
currentBasal = generateBasalString()
|
||||
|
||||
//bgi
|
||||
val bgi = -(bolusIob.activity + basalIob.activity) * 5 * fromMgdlToUnits(profile.getIsfMgdl(), profileFunction.getUnits())
|
||||
bgiString = "" + (if (bgi >= 0) "+" else "") + to1Decimal(bgi)
|
||||
status = generateStatusString(profile, currentBasal, iobSum, iobDetail, bgiString)
|
||||
}
|
||||
|
||||
//batteries
|
||||
val phoneBattery = receiverStatusStore.batteryLevel
|
||||
val rigBattery = nsDeviceStatus.uploaderStatus.trim { it <= ' ' }
|
||||
//OpenAPS status
|
||||
val openApsStatus =
|
||||
if (config.APS) loop.lastRun?.let { if (it.lastTBREnact != 0L) it.lastTBREnact else -1 } ?: -1
|
||||
else nsDeviceStatus.openApsTimestamp
|
||||
|
||||
sendData(
|
||||
wearConstants.M_W_STATUS,
|
||||
DataMap().apply {
|
||||
//unique content
|
||||
putString("externalStatusString", status)
|
||||
putString("iobSum", iobSum)
|
||||
putString("iobDetail", iobDetail)
|
||||
putBoolean("detailedIob", sp.getBoolean(R.string.key_wear_detailediob, false))
|
||||
putString("cob", cobString)
|
||||
putString("currentBasal", currentBasal)
|
||||
putString("battery", "" + phoneBattery)
|
||||
putString("rigBattery", rigBattery)
|
||||
putLong("openApsStatus", openApsStatus)
|
||||
putString("bgi", bgiString)
|
||||
putBoolean("showBgi", sp.getBoolean(R.string.key_wear_showbgi, false))
|
||||
putInt("batteryLevel", if (phoneBattery >= 30) 1 else 0)
|
||||
})
|
||||
}
|
||||
|
||||
private fun sendPreferences() {
|
||||
sendData(
|
||||
wearConstants.M_W_PREFERENCES,
|
||||
DataMap().apply {
|
||||
putLong("timestamp", System.currentTimeMillis())
|
||||
putBoolean(rh.gs(R.string.key_wear_control), sp.getBoolean(R.string.key_wear_control, false))
|
||||
putBoolean(rh.gs(R.string.key_units_mgdl), profileFunction.getUnits() == GlucoseUnit.MGDL)
|
||||
putInt(rh.gs(R.string.key_boluswizard_percentage), sp.getInt(R.string.key_boluswizard_percentage, 100))
|
||||
putInt(rh.gs(R.string.key_treatmentssafety_maxcarbs), sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48))
|
||||
putDouble(rh.gs(R.string.key_treatmentssafety_maxbolus), sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0))
|
||||
})
|
||||
}
|
||||
|
||||
private fun sendQuickWizard() {
|
||||
val entities = ArrayList<DataMap>()
|
||||
for (i in 0 until quickWizard.size()) {
|
||||
val q = quickWizard[i]
|
||||
if (q.forDevice(QuickWizardEntry.DEVICE_WATCH)) entities.add(quickMap(q))
|
||||
}
|
||||
sendData(
|
||||
wearConstants.M_W_QUICK_WIZARD,
|
||||
DataMap().apply {
|
||||
putLong("timestamp", System.currentTimeMillis())
|
||||
putDataMapArrayList("quick_wizard", entities)
|
||||
})
|
||||
}
|
||||
|
||||
private fun generateStatusString(profile: Profile?, currentBasal: String, iobSum: String, iobDetail: String, bgiString: String): String {
|
||||
var status = ""
|
||||
if (profile == null) return rh.gs(R.string.noprofile)
|
||||
if (!(loop as PluginBase).isEnabled()) status += rh.gs(R.string.disabledloop) + "\n"
|
||||
|
||||
val iobString =
|
||||
if (sp.getBoolean(R.string.key_wear_detailediob, false)) "$iobSum $iobDetail"
|
||||
else iobSum + "U"
|
||||
|
||||
status += "$currentBasal $iobString"
|
||||
|
||||
//add BGI if shown, otherwise return
|
||||
if (sp.getBoolean(R.string.key_wear_showbgi, false)) status += " $bgiString"
|
||||
return status
|
||||
}
|
||||
|
||||
private fun generateBasalString(): String {
|
||||
val profile: Profile = profileFunction.getProfile() ?: return ""
|
||||
return iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis())?.toStringShort() ?: to2Decimal(profile.getBasal()) + "U/h"
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val WEAR_CAPABILITY = "androidaps_wear"
|
||||
|
||||
val ACTION_RESEND = WatchUpdaterService::class.java.name + ".Resend"
|
||||
val ACTION_OPEN_SETTINGS = WatchUpdaterService::class.java.name + ".OpenSettings"
|
||||
val ACTION_SEND_STATUS = WatchUpdaterService::class.java.name + ".SendStatus"
|
||||
val ACTION_SEND_BASALS = WatchUpdaterService::class.java.name + ".SendBasals"
|
||||
val ACTION_SEND_BOLUS_PROGRESS = WatchUpdaterService::class.java.name + ".BolusProgress"
|
||||
val ACTION_SEND_ACTION_CONFIRMATION_REQUEST = WatchUpdaterService::class.java.name + ".ActionConfirmationRequest"
|
||||
val ACTION_SEND_CHANGE_CONFIRMATION_REQUEST = WatchUpdaterService::class.java.name + ".ChangeConfirmationRequest"
|
||||
val ACTION_CANCEL_NOTIFICATION = WatchUpdaterService::class.java.name + ".CancelNotification"
|
||||
|
||||
}
|
||||
}
|
|
@ -1,778 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear.wearintegration;
|
||||
|
||||
/*
|
||||
public class WatchUpdaterService1 extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||
@Inject public GlucoseStatusProvider glucoseStatusProvider;
|
||||
@Inject public AAPSLogger aapsLogger;
|
||||
@Inject public WearPlugin wearPlugin;
|
||||
@Inject public ResourceHelper rh;
|
||||
@Inject public SP sp;
|
||||
@Inject public RxBus rxBus;
|
||||
@Inject public ProfileFunction profileFunction;
|
||||
@Inject public DefaultValueHelper defaultValueHelper;
|
||||
@Inject public NSDeviceStatus nsDeviceStatus;
|
||||
@Inject public ActivePlugin activePlugin;
|
||||
@Inject public Loop loop;
|
||||
@Inject public IobCobCalculator iobCobCalculator;
|
||||
@Inject public AppRepository repository;
|
||||
@Inject ReceiverStatusStore receiverStatusStore;
|
||||
@Inject Config config;
|
||||
@Inject public TrendCalculator trendCalculator;
|
||||
@Inject public QuickWizard quickWizard;
|
||||
|
||||
public static final String ACTION_RESEND = WatchUpdaterService.class.getName().concat(".Resend");
|
||||
public static final String ACTION_OPEN_SETTINGS = WatchUpdaterService.class.getName().concat(".OpenSettings");
|
||||
public static final String ACTION_SEND_STATUS = WatchUpdaterService.class.getName().concat(".SendStatus");
|
||||
public static final String ACTION_SEND_BASALS = WatchUpdaterService.class.getName().concat(".SendBasals");
|
||||
public static final String ACTION_SEND_BOLUSPROGRESS = WatchUpdaterService.class.getName().concat(".BolusProgress");
|
||||
public static final String ACTION_SEND_ACTIONCONFIRMATIONREQUEST = WatchUpdaterService.class.getName().concat(".ActionConfirmationRequest");
|
||||
public static final String ACTION_SEND_CHANGECONFIRMATIONREQUEST = WatchUpdaterService.class.getName().concat(".ChangeConfirmationRequest");
|
||||
public static final String ACTION_CANCEL_NOTIFICATION = WatchUpdaterService.class.getName().concat(".CancelNotification");
|
||||
|
||||
private GoogleApiClient googleApiClient;
|
||||
|
||||
String TAG = "WatchUpdateService";
|
||||
|
||||
private static boolean lastLoopStatus;
|
||||
|
||||
private Handler handler;
|
||||
|
||||
// Phone
|
||||
private static final String CAPABILITY_PHONE_APP = "phone_app_sync_bgs";
|
||||
private static final String MESSAGE_PATH_PHONE = "/phone_message_path";
|
||||
// Wear
|
||||
private static final String CAPABILITY_WEAR_APP = "wear_app_sync_bgs";
|
||||
private static final String MESSAGE_PATH_WEAR = "/wear_message_path";
|
||||
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
AndroidInjection.inject(this);
|
||||
if (wearIntegration()) {
|
||||
googleApiConnect();
|
||||
}
|
||||
if (handler == null) {
|
||||
HandlerThread handlerThread = new HandlerThread(this.getClass().getSimpleName() + "Handler");
|
||||
handlerThread.start();
|
||||
handler = new Handler(handlerThread.getLooper());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean wearIntegration() {
|
||||
return wearPlugin.isEnabled();
|
||||
}
|
||||
|
||||
private void googleApiConnect() {
|
||||
if (googleApiClient != null && (googleApiClient.isConnected() || googleApiClient.isConnecting())) {
|
||||
googleApiClient.disconnect();
|
||||
}
|
||||
googleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
|
||||
.addOnConnectionFailedListener(this).addApi(Wearable.API).build();
|
||||
Wearable.MessageApi.addListener(googleApiClient, this);
|
||||
if (googleApiClient.isConnected()) {
|
||||
aapsLogger.debug(LTag.WEAR, "API client is connected");
|
||||
} else {
|
||||
// Log.d("WatchUpdater", logPrefix + "API client is not connected and is trying to connect");
|
||||
googleApiClient.connect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
String action = intent != null ? intent.getAction() : null;
|
||||
|
||||
// Log.d(TAG, "onStartCommand: " + action);
|
||||
|
||||
if (wearIntegration()) {
|
||||
handler.post(() -> {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
if (ACTION_RESEND.equals(action)) {
|
||||
resendData();
|
||||
} else if (ACTION_OPEN_SETTINGS.equals(action)) {
|
||||
sendNotification();
|
||||
} else if (ACTION_SEND_STATUS.equals(action)) {
|
||||
sendStatus();
|
||||
} else if (ACTION_SEND_BASALS.equals(action)) {
|
||||
sendBasals();
|
||||
} else if (ACTION_SEND_BOLUSPROGRESS.equals(action)) {
|
||||
sendBolusProgress(intent.getIntExtra("progresspercent", 0), intent.hasExtra("progressstatus") ? intent.getStringExtra("progressstatus") : "");
|
||||
} else if (ACTION_SEND_ACTIONCONFIRMATIONREQUEST.equals(action)) {
|
||||
String title = intent.getStringExtra("title");
|
||||
String message = intent.getStringExtra("message");
|
||||
String actionstring = intent.getStringExtra("actionstring");
|
||||
sendActionConfirmationRequest(title, message, actionstring);
|
||||
} else if (ACTION_SEND_CHANGECONFIRMATIONREQUEST.equals(action)) {
|
||||
String title = intent.getStringExtra("title");
|
||||
String message = intent.getStringExtra("message");
|
||||
String actionstring = intent.getStringExtra("actionstring");
|
||||
sendChangeConfirmationRequest(title, message, actionstring);
|
||||
} else if (ACTION_CANCEL_NOTIFICATION.equals(action)) {
|
||||
String actionstring = intent.getStringExtra("actionstring");
|
||||
sendCancelNotificationRequest(actionstring);
|
||||
} else {
|
||||
sendData();
|
||||
}
|
||||
} else {
|
||||
if (googleApiClient != null) googleApiClient.connect();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
|
||||
private void updateWearSyncBgsCapability(CapabilityInfo capabilityInfo) {
|
||||
Log.d("WatchUpdaterService", "CabilityInfo: " + capabilityInfo);
|
||||
Set<Node> connectedNodes = capabilityInfo.getNodes();
|
||||
String mWearNodeId = pickBestNodeId(connectedNodes);
|
||||
}
|
||||
|
||||
|
||||
private String pickBestNodeId(Set<Node> nodes) {
|
||||
String bestNodeId = null;
|
||||
// Find a nearby node or pick one arbitrarily
|
||||
for (Node node : nodes) {
|
||||
if (node.isNearby()) {
|
||||
return node.getId();
|
||||
}
|
||||
bestNodeId = node.getId();
|
||||
}
|
||||
return bestNodeId;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onConnected(Bundle connectionHint) {
|
||||
CapabilityApi.CapabilityListener capabilityListener = capabilityInfo -> {
|
||||
updateWearSyncBgsCapability(capabilityInfo);
|
||||
// Log.d(TAG, logPrefix + "onConnected onCapabilityChanged mWearNodeID:" + mWearNodeId);
|
||||
// new CheckWearableConnected().execute();
|
||||
};
|
||||
|
||||
Wearable.CapabilityApi.addCapabilityListener(googleApiClient, capabilityListener, CAPABILITY_WEAR_APP);
|
||||
sendData();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onPeerConnected(com.google.android.gms.wearable.Node peer) {// KS
|
||||
super.onPeerConnected(peer);
|
||||
String id = peer.getId();
|
||||
String name = peer.getDisplayName();
|
||||
Log.d(TAG, "onPeerConnected peer name & ID: " + name + "|" + id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onPeerDisconnected(com.google.android.gms.wearable.Node peer) {// KS
|
||||
super.onPeerDisconnected(peer);
|
||||
String id = peer.getId();
|
||||
String name = peer.getDisplayName();
|
||||
Log.d(TAG, "onPeerDisconnected peer name & ID: " + name + "|" + id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(MessageEvent event) {
|
||||
|
||||
// Log.d(TAG, "onMessageRecieved: " + event);
|
||||
|
||||
if (wearIntegration()) {
|
||||
if (event != null && event.getPath().equals(WearUris.WEARABLE_RESEND_PATH)) {
|
||||
resendData();
|
||||
}
|
||||
|
||||
if (event != null && event.getPath().equals(WearUris.WEARABLE_CANCELBOLUS_PATH)) {
|
||||
cancelBolus();
|
||||
}
|
||||
|
||||
if (event != null && event.getPath().equals(WearUris.WEARABLE_INITIATE_ACTIONSTRING_PATH)) {
|
||||
String actionstring = new String(event.getData());
|
||||
aapsLogger.debug(LTag.WEAR, "Wear: " + actionstring);
|
||||
rxBus.send(new EventWearInitiateAction(actionstring));
|
||||
}
|
||||
|
||||
if (event != null && event.getPath().equals(WearUris.WEARABLE_CONFIRM_ACTIONSTRING_PATH)) {
|
||||
String actionstring = new String(event.getData());
|
||||
aapsLogger.debug(LTag.WEAR, "Wear Confirm: " + actionstring);
|
||||
rxBus.send(new EventWearConfirmAction(actionstring));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelBolus() {
|
||||
activePlugin.getActivePump().stopBolusDelivering();
|
||||
}
|
||||
|
||||
private void sendData() {
|
||||
|
||||
GlucoseValue lastBG = iobCobCalculator.getAds().lastBg();
|
||||
// Log.d(TAG, "LastBg=" + lastBG);
|
||||
if (lastBG != null) {
|
||||
GlucoseStatus glucoseStatus = glucoseStatusProvider.getGlucoseStatusData();
|
||||
|
||||
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
|
||||
googleApiConnect();
|
||||
}
|
||||
if (wearIntegration()) {
|
||||
|
||||
final DataMap dataMap = dataMapSingleBG(lastBG, glucoseStatus);
|
||||
|
||||
(new SendToDataLayerThread(WearUris.WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, dataMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private DataMap dataMapSingleBG(GlucoseValue lastBG, GlucoseStatus glucoseStatus) {
|
||||
GlucoseUnit units = profileFunction.getUnits();
|
||||
double convert2MGDL = 1.0;
|
||||
if (units.equals(GlucoseUnit.MMOL))
|
||||
convert2MGDL = Constants.MMOLL_TO_MGDL;
|
||||
double lowLine = defaultValueHelper.determineLowLine() * convert2MGDL;
|
||||
double highLine = defaultValueHelper.determineHighLine() * convert2MGDL;
|
||||
|
||||
long sgvLevel = 0L;
|
||||
if (lastBG.getValue() > highLine) {
|
||||
sgvLevel = 1;
|
||||
} else if (lastBG.getValue() < lowLine) {
|
||||
sgvLevel = -1;
|
||||
}
|
||||
|
||||
DataMap dataMap = new DataMap();
|
||||
dataMap.putString("sgvString", GlucoseValueExtensionKt.valueToUnitsString(lastBG, units));
|
||||
dataMap.putString("glucoseUnits", units.getAsText());
|
||||
dataMap.putLong("timestamp", lastBG.getTimestamp());
|
||||
if (glucoseStatus == null) {
|
||||
dataMap.putString("slopeArrow", "");
|
||||
dataMap.putString("delta", "--");
|
||||
dataMap.putString("avgDelta", "--");
|
||||
} else {
|
||||
dataMap.putString("slopeArrow", trendCalculator.getTrendArrow(lastBG).getSymbol());
|
||||
dataMap.putString("delta", deltastring(glucoseStatus.getDelta(), glucoseStatus.getDelta() * Constants.MGDL_TO_MMOLL, units));
|
||||
dataMap.putString("avgDelta", deltastring(glucoseStatus.getShortAvgDelta(), glucoseStatus.getShortAvgDelta() * Constants.MGDL_TO_MMOLL, units));
|
||||
}
|
||||
dataMap.putLong("sgvLevel", sgvLevel);
|
||||
dataMap.putDouble("sgvDouble", lastBG.getValue());
|
||||
dataMap.putDouble("high", highLine);
|
||||
dataMap.putDouble("low", lowLine);
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
private String deltastring(double deltaMGDL, double deltaMMOL, GlucoseUnit units) {
|
||||
String deltastring = "";
|
||||
if (deltaMGDL >= 0) {
|
||||
deltastring += "+";
|
||||
} else {
|
||||
deltastring += "-";
|
||||
}
|
||||
|
||||
boolean detailed = sp.getBoolean(R.string.key_wear_detailed_delta, false);
|
||||
if (units.equals(GlucoseUnit.MGDL)) {
|
||||
if (detailed) {
|
||||
deltastring += DecimalFormatter.INSTANCE.to1Decimal(Math.abs(deltaMGDL));
|
||||
} else {
|
||||
deltastring += DecimalFormatter.INSTANCE.to0Decimal(Math.abs(deltaMGDL));
|
||||
}
|
||||
} else {
|
||||
if (detailed) {
|
||||
deltastring += DecimalFormatter.INSTANCE.to2Decimal(Math.abs(deltaMMOL));
|
||||
} else {
|
||||
deltastring += DecimalFormatter.INSTANCE.to1Decimal(Math.abs(deltaMMOL));
|
||||
}
|
||||
}
|
||||
return deltastring;
|
||||
}
|
||||
|
||||
private void resendData() {
|
||||
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
|
||||
googleApiConnect();
|
||||
}
|
||||
|
||||
sendPreferences();
|
||||
sendQuickWizard();
|
||||
|
||||
long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5);
|
||||
GlucoseValue last_bg = iobCobCalculator.getAds().lastBg();
|
||||
|
||||
if (last_bg == null) return;
|
||||
|
||||
List<GlucoseValue> graph_bgs = repository.compatGetBgReadingsDataFromTime(startTime, true).blockingGet();
|
||||
GlucoseStatus glucoseStatus = glucoseStatusProvider.getGlucoseStatusData(true);
|
||||
|
||||
if (!graph_bgs.isEmpty()) {
|
||||
DataMap entries = dataMapSingleBG(last_bg, glucoseStatus);
|
||||
final ArrayList<DataMap> dataMaps = new ArrayList<>(graph_bgs.size());
|
||||
for (GlucoseValue bg : graph_bgs) {
|
||||
DataMap dataMap = dataMapSingleBG(bg, glucoseStatus);
|
||||
dataMaps.add(dataMap);
|
||||
}
|
||||
entries.putDataMapArrayList("entries", dataMaps);
|
||||
(new SendToDataLayerThread(WearUris.WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, entries);
|
||||
}
|
||||
sendBasals();
|
||||
sendStatus();
|
||||
}
|
||||
|
||||
private void sendBasals() {
|
||||
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
|
||||
googleApiConnect();
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
final long startTimeWindow = now - (long) (60000 * 60 * 5.5);
|
||||
|
||||
|
||||
ArrayList<DataMap> basals = new ArrayList<>();
|
||||
ArrayList<DataMap> temps = new ArrayList<>();
|
||||
ArrayList<DataMap> boluses = new ArrayList<>();
|
||||
ArrayList<DataMap> predictions = new ArrayList<>();
|
||||
|
||||
|
||||
Profile profile = profileFunction.getProfile();
|
||||
|
||||
if (profile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long beginBasalSegmentTime = startTimeWindow;
|
||||
long runningTime = startTimeWindow;
|
||||
|
||||
double beginBasalValue = profile.getBasal(beginBasalSegmentTime);
|
||||
double endBasalValue = beginBasalValue;
|
||||
|
||||
TemporaryBasal tb1 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime);
|
||||
TemporaryBasal tb2;
|
||||
double tb_before = beginBasalValue;
|
||||
double tb_amount = beginBasalValue;
|
||||
long tb_start = runningTime;
|
||||
|
||||
if (tb1 != null) {
|
||||
Profile profileTB = profileFunction.getProfile(runningTime);
|
||||
if (profileTB != null) {
|
||||
tb_amount = TemporaryBasalExtensionKt.convertedToAbsolute(tb1, runningTime, profileTB);
|
||||
tb_start = runningTime;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (; runningTime < now; runningTime += 5 * 60 * 1000) {
|
||||
Profile profileTB = profileFunction.getProfile(runningTime);
|
||||
if (profileTB == null)
|
||||
return;
|
||||
//basal rate
|
||||
endBasalValue = profile.getBasal(runningTime);
|
||||
if (endBasalValue != beginBasalValue) {
|
||||
//push the segment we recently left
|
||||
basals.add(basalMap(beginBasalSegmentTime, runningTime, beginBasalValue));
|
||||
|
||||
//begin new Basal segment
|
||||
beginBasalSegmentTime = runningTime;
|
||||
beginBasalValue = endBasalValue;
|
||||
}
|
||||
|
||||
//temps
|
||||
tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime);
|
||||
|
||||
if (tb1 == null && tb2 == null) {
|
||||
; //no temp stays no temp
|
||||
|
||||
} else if (tb1 != null && tb2 == null) {
|
||||
//temp is over -> push it
|
||||
temps.add(tempDatamap(tb_start, tb_before, runningTime, endBasalValue, tb_amount));
|
||||
tb1 = null;
|
||||
|
||||
} else if (tb1 == null && tb2 != null) {
|
||||
//temp begins
|
||||
tb1 = tb2;
|
||||
tb_start = runningTime;
|
||||
tb_before = endBasalValue;
|
||||
tb_amount = TemporaryBasalExtensionKt.convertedToAbsolute(tb1, runningTime, profileTB);
|
||||
|
||||
} else if (tb1 != null && tb2 != null) {
|
||||
double currentAmount = TemporaryBasalExtensionKt.convertedToAbsolute(tb2, runningTime, profileTB);
|
||||
if (currentAmount != tb_amount) {
|
||||
temps.add(tempDatamap(tb_start, tb_before, runningTime, currentAmount, tb_amount));
|
||||
tb_start = runningTime;
|
||||
tb_before = tb_amount;
|
||||
tb_amount = currentAmount;
|
||||
tb1 = tb2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (beginBasalSegmentTime != runningTime) {
|
||||
//push the remaining segment
|
||||
basals.add(basalMap(beginBasalSegmentTime, runningTime, beginBasalValue));
|
||||
}
|
||||
if (tb1 != null) {
|
||||
tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(now); //use "now" to express current situation
|
||||
if (tb2 == null) {
|
||||
//express the cancelled temp by painting it down one minute early
|
||||
temps.add(tempDatamap(tb_start, tb_before, now - 60 * 1000, endBasalValue, tb_amount));
|
||||
} else {
|
||||
//express currently running temp by painting it a bit into the future
|
||||
Profile profileNow = profileFunction.getProfile(now);
|
||||
double currentAmount = TemporaryBasalExtensionKt.convertedToAbsolute(tb2, now, profileNow);
|
||||
if (currentAmount != tb_amount) {
|
||||
temps.add(tempDatamap(tb_start, tb_before, now, tb_amount, tb_amount));
|
||||
temps.add(tempDatamap(now, tb_amount, runningTime + 5 * 60 * 1000, currentAmount, currentAmount));
|
||||
} else {
|
||||
temps.add(tempDatamap(tb_start, tb_before, runningTime + 5 * 60 * 1000, tb_amount, tb_amount));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(now); //use "now" to express current situation
|
||||
if (tb2 != null) {
|
||||
//onset at the end
|
||||
Profile profileTB = profileFunction.getProfile(runningTime);
|
||||
double currentAmount = TemporaryBasalExtensionKt.convertedToAbsolute(tb2, runningTime, profileTB);
|
||||
temps.add(tempDatamap(now - 60 * 1000, endBasalValue, runningTime + 5 * 60 * 1000, currentAmount, currentAmount));
|
||||
}
|
||||
}
|
||||
|
||||
repository.getBolusesIncludingInvalidFromTime(startTimeWindow, true).blockingGet()
|
||||
.stream()
|
||||
.filter(bolus -> bolus.getType() != Bolus.Type.PRIMING)
|
||||
.forEach(bolus -> boluses.add(treatmentMap(bolus.getTimestamp(), bolus.getAmount(), 0, bolus.getType() == Bolus.Type.SMB, bolus.isValid())));
|
||||
repository.getCarbsDataFromTimeExpanded(startTimeWindow, true).blockingGet()
|
||||
.forEach(carb -> boluses.add(treatmentMap(carb.getTimestamp(), 0, carb.getAmount(), false, carb.isValid())));
|
||||
|
||||
final LoopPlugin.LastRun finalLastRun = loop.getLastRun();
|
||||
if (sp.getBoolean("wear_predictions", true) && finalLastRun != null && finalLastRun.getRequest().getHasPredictions() && finalLastRun.getConstraintsProcessed() != null) {
|
||||
List<GlucoseValueDataPoint> predArray =
|
||||
finalLastRun.getConstraintsProcessed().getPredictions()
|
||||
.stream().map(bg -> new GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, rh))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!predArray.isEmpty()) {
|
||||
for (GlucoseValueDataPoint bg : predArray) {
|
||||
if (bg.getData().getValue() < 40) continue;
|
||||
predictions.add(predictionMap(bg.getData().getTimestamp(),
|
||||
bg.getData().getValue(), bg.color(null)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
DataMap dm = new DataMap();
|
||||
dm.putDataMapArrayList("basals", basals);
|
||||
dm.putDataMapArrayList("temps", temps);
|
||||
dm.putDataMapArrayList("boluses", boluses);
|
||||
dm.putDataMapArrayList("predictions", predictions);
|
||||
(new SendToDataLayerThread(WearUris.BASAL_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, dm);
|
||||
}
|
||||
|
||||
private DataMap tempDatamap(long startTime, double startBasal, long to, double toBasal, double amount) {
|
||||
DataMap dm = new DataMap();
|
||||
dm.putLong("starttime", startTime);
|
||||
dm.putDouble("startBasal", startBasal);
|
||||
dm.putLong("endtime", to);
|
||||
dm.putDouble("endbasal", toBasal);
|
||||
dm.putDouble("amount", amount);
|
||||
return dm;
|
||||
}
|
||||
|
||||
private DataMap basalMap(long startTime, long endTime, double amount) {
|
||||
DataMap dm = new DataMap();
|
||||
dm.putLong("starttime", startTime);
|
||||
dm.putLong("endtime", endTime);
|
||||
dm.putDouble("amount", amount);
|
||||
return dm;
|
||||
}
|
||||
|
||||
private DataMap treatmentMap(long date, double bolus, double carbs, boolean isSMB, boolean isValid) {
|
||||
DataMap dm = new DataMap();
|
||||
dm.putLong("date", date);
|
||||
dm.putDouble("bolus", bolus);
|
||||
dm.putDouble("carbs", carbs);
|
||||
dm.putBoolean("isSMB", isSMB);
|
||||
dm.putBoolean("isValid", isValid);
|
||||
return dm;
|
||||
}
|
||||
|
||||
private DataMap predictionMap(long timestamp, double sgv, int color) {
|
||||
DataMap dm = new DataMap();
|
||||
dm.putLong("timestamp", timestamp);
|
||||
dm.putDouble("sgv", sgv);
|
||||
dm.putInt("color", color);
|
||||
return dm;
|
||||
}
|
||||
|
||||
|
||||
private void sendNotification() {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.OPEN_SETTINGS_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putString("openSettings", "openSettings");
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
Log.e("OpenSettings", "No connection to wearable available!");
|
||||
}
|
||||
}
|
||||
|
||||
private void sendBolusProgress(int progresspercent, String status) {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.BOLUS_PROGRESS_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putString("bolusProgress", "bolusProgress");
|
||||
dataMapRequest.getDataMap().putString("progressstatus", status);
|
||||
dataMapRequest.getDataMap().putInt("progresspercent", progresspercent);
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
Log.e("BolusProgress", "No connection to wearable available!");
|
||||
}
|
||||
}
|
||||
|
||||
private void sendActionConfirmationRequest(String title, String message, String actionstring) {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.ACTION_CONFIRMATION_REQUEST_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putString("actionConfirmationRequest", "actionConfirmationRequest");
|
||||
dataMapRequest.getDataMap().putString("title", title);
|
||||
dataMapRequest.getDataMap().putString("message", message);
|
||||
dataMapRequest.getDataMap().putString("actionstring", actionstring);
|
||||
|
||||
aapsLogger.debug(LTag.WEAR, "Requesting confirmation from wear: " + actionstring);
|
||||
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
Log.e("confirmationRequest", "No connection to wearable available!");
|
||||
}
|
||||
}
|
||||
|
||||
private void sendChangeConfirmationRequest(String title, String message, String actionstring) {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.ACTION_CHANGECONFIRMATION_REQUEST_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putString("changeConfirmationRequest", "changeConfirmationRequest");
|
||||
dataMapRequest.getDataMap().putString("title", title);
|
||||
dataMapRequest.getDataMap().putString("message", message);
|
||||
dataMapRequest.getDataMap().putString("actionstring", actionstring);
|
||||
|
||||
aapsLogger.debug(LTag.WEAR, "Requesting confirmation from wear: " + actionstring);
|
||||
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
Log.e("changeConfirmRequest", "No connection to wearable available!");
|
||||
}
|
||||
}
|
||||
|
||||
private void sendCancelNotificationRequest(String actionstring) {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.ACTION_CANCELNOTIFICATION_REQUEST_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putString("cancelNotificationRequest", "cancelNotificationRequest");
|
||||
dataMapRequest.getDataMap().putString("actionstring", actionstring);
|
||||
|
||||
aapsLogger.debug(LTag.WEAR, "Canceling notification on wear: " + actionstring);
|
||||
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
Log.e("cancelNotificationReq", "No connection to wearable available!");
|
||||
}
|
||||
}
|
||||
|
||||
private void sendStatus() {
|
||||
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
Profile profile = profileFunction.getProfile();
|
||||
String status = rh.gs(R.string.noprofile);
|
||||
String iobSum, iobDetail, cobString, currentBasal, bgiString;
|
||||
iobSum = iobDetail = cobString = currentBasal = bgiString = "";
|
||||
if (profile != null) {
|
||||
IobTotal bolusIob = iobCobCalculator.calculateIobFromBolus().round();
|
||||
IobTotal basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round();
|
||||
|
||||
iobSum = DecimalFormatter.INSTANCE.to2Decimal(bolusIob.getIob() + basalIob.getBasaliob());
|
||||
iobDetail =
|
||||
"(" + DecimalFormatter.INSTANCE.to2Decimal(bolusIob.getIob()) + "|" + DecimalFormatter.INSTANCE.to2Decimal(basalIob.getBasaliob()) + ")";
|
||||
cobString = iobCobCalculator.getCobInfo(false, "WatcherUpdaterService").generateCOBString();
|
||||
currentBasal = generateBasalString();
|
||||
|
||||
//bgi
|
||||
double bgi =
|
||||
-(bolusIob.getActivity() + basalIob.getActivity()) * 5 * Profile.Companion.fromMgdlToUnits(profile.getIsfMgdl(), profileFunction.getUnits());
|
||||
bgiString = "" + ((bgi >= 0) ? "+" : "") + DecimalFormatter.INSTANCE.to1Decimal(bgi);
|
||||
|
||||
status = generateStatusString(profile, currentBasal, iobSum, iobDetail, bgiString);
|
||||
}
|
||||
|
||||
|
||||
//batteries
|
||||
int phoneBattery = receiverStatusStore.getBatteryLevel();
|
||||
String rigBattery = nsDeviceStatus.getUploaderStatus().trim();
|
||||
|
||||
|
||||
long openApsStatus;
|
||||
//OpenAPS status
|
||||
if (config.getAPS()) {
|
||||
//we are AndroidAPS
|
||||
openApsStatus = loop.getLastRun() != null && loop.getLastRun().getLastTBREnact() != 0 ? loop.getLastRun().getLastTBREnact() : -1;
|
||||
} else {
|
||||
//NSClient or remote
|
||||
openApsStatus = nsDeviceStatus.getOpenApsTimestamp();
|
||||
}
|
||||
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.NEW_STATUS_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putString("externalStatusString", status);
|
||||
dataMapRequest.getDataMap().putString("iobSum", iobSum);
|
||||
dataMapRequest.getDataMap().putString("iobDetail", iobDetail);
|
||||
dataMapRequest.getDataMap().putBoolean("detailedIob", sp.getBoolean(R.string.key_wear_detailediob, false));
|
||||
dataMapRequest.getDataMap().putString("cob", cobString);
|
||||
dataMapRequest.getDataMap().putString("currentBasal", currentBasal);
|
||||
dataMapRequest.getDataMap().putString("battery", "" + phoneBattery);
|
||||
dataMapRequest.getDataMap().putString("rigBattery", rigBattery);
|
||||
dataMapRequest.getDataMap().putLong("openApsStatus", openApsStatus);
|
||||
dataMapRequest.getDataMap().putString("bgi", bgiString);
|
||||
dataMapRequest.getDataMap().putBoolean("showBgi", sp.getBoolean(R.string.key_wear_showbgi, false));
|
||||
dataMapRequest.getDataMap().putInt("batteryLevel", (phoneBattery >= 30) ? 1 : 0);
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
Log.e("SendStatus", "No connection to wearable available!");
|
||||
}
|
||||
}
|
||||
|
||||
private void sendPreferences() {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
|
||||
GlucoseUnit units = profileFunction.getUnits();
|
||||
boolean wearcontrol = sp.getBoolean(R.string.key_wear_control, false);
|
||||
boolean mgdl = units.equals(GlucoseUnit.MGDL);
|
||||
int percentage = sp.getInt(R.string.key_boluswizard_percentage, 100);
|
||||
int maxCarbs = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48);
|
||||
double maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0);
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.NEW_PREFERENCES_PATH);
|
||||
//unique content
|
||||
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
|
||||
dataMapRequest.getDataMap().putBoolean(rh.gs(R.string.key_wear_control), wearcontrol);
|
||||
dataMapRequest.getDataMap().putBoolean(rh.gs(R.string.key_units_mgdl), mgdl);
|
||||
dataMapRequest.getDataMap().putInt(rh.gs(R.string.key_boluswizard_percentage), percentage);
|
||||
dataMapRequest.getDataMap().putInt(rh.gs(R.string.key_treatmentssafety_maxcarbs), maxCarbs);
|
||||
dataMapRequest.getDataMap().putDouble(rh.gs(R.string.key_treatmentssafety_maxbolus), maxBolus);
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
Log.e("SendPreferences", "No connection to wearable available!");
|
||||
}
|
||||
}
|
||||
|
||||
private void sendQuickWizard() {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
int size = quickWizard.size();
|
||||
ArrayList<DataMap> entities = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
QuickWizardEntry q = quickWizard.get(i);
|
||||
if (q.forDevice(QuickWizardEntry.DEVICE_WATCH)) {
|
||||
entities.add(quickMap(q));
|
||||
}
|
||||
}
|
||||
|
||||
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.QUICK_WIZARD_PATH);
|
||||
|
||||
DataMap dm = dataMapRequest.getDataMap();
|
||||
dm.putLong("timestamp", System.currentTimeMillis());
|
||||
dm.putDataMapArrayList("quick_wizard", entities);
|
||||
|
||||
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
|
||||
Log.i(TAG, "sendQuickWizard: " + putDataRequest);
|
||||
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
|
||||
} else {
|
||||
Log.e("sendQuickWizard", "No connection to wearable available!");
|
||||
}
|
||||
}
|
||||
|
||||
private DataMap quickMap(QuickWizardEntry q) {
|
||||
DataMap dm = new DataMap();
|
||||
dm.putString("guid", q.guid());
|
||||
dm.putString("button_text", q.buttonText());
|
||||
dm.putInt("carbs", q.carbs());
|
||||
dm.putInt("from", q.validFrom());
|
||||
dm.putInt("to", q.validTo());
|
||||
return dm;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String generateStatusString(Profile profile, String currentBasal, String iobSum, String iobDetail, String bgiString) {
|
||||
|
||||
String status = "";
|
||||
|
||||
if (profile == null) {
|
||||
status = rh.gs(R.string.noprofile);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!((PluginBase) loop).isEnabled()) {
|
||||
status += rh.gs(R.string.disabledloop) + "\n";
|
||||
lastLoopStatus = false;
|
||||
} else {
|
||||
lastLoopStatus = true;
|
||||
}
|
||||
|
||||
String iobString;
|
||||
if (sp.getBoolean(R.string.key_wear_detailediob, false)) {
|
||||
iobString = iobSum + " " + iobDetail;
|
||||
} else {
|
||||
iobString = iobSum + "U";
|
||||
}
|
||||
|
||||
status += currentBasal + " " + iobString;
|
||||
|
||||
//add BGI if shown, otherwise return
|
||||
if (sp.getBoolean(R.string.key_wear_showbgi, false)) {
|
||||
status += " " + bgiString;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String generateBasalString() {
|
||||
|
||||
String basalStringResult;
|
||||
|
||||
Profile profile = profileFunction.getProfile();
|
||||
if (profile == null)
|
||||
return "";
|
||||
|
||||
TemporaryBasal activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis());
|
||||
if (activeTemp != null) {
|
||||
basalStringResult = TemporaryBasalExtensionKt.toStringShort(activeTemp);
|
||||
} else {
|
||||
basalStringResult = DecimalFormatter.INSTANCE.to2Decimal(profile.getBasal()) + "U/h";
|
||||
}
|
||||
return basalStringResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
googleApiClient.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionSuspended(int cause) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
|
||||
}
|
||||
|
||||
public static boolean shouldReportLoopStatus(boolean enabled) {
|
||||
return (lastLoopStatus != enabled);
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -19,12 +19,10 @@ import info.nightscout.androidaps.database.entities.EffectiveProfileSwitch
|
|||
import info.nightscout.androidaps.database.entities.ProfileSwitch
|
||||
import info.nightscout.androidaps.database.interfaces.end
|
||||
import info.nightscout.androidaps.dialogs.BolusProgressDialog
|
||||
import info.nightscout.androidaps.events.EventBolusRequested
|
||||
import info.nightscout.androidaps.events.EventMobileToWear
|
||||
import info.nightscout.androidaps.events.EventProfileSwitchChanged
|
||||
import info.nightscout.androidaps.extensions.getCustomizedName
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissBolusProgressIfRunning
|
||||
|
@ -40,7 +38,10 @@ import info.nightscout.androidaps.utils.HtmlHelper
|
|||
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
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 io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||
|
@ -297,7 +298,7 @@ class CommandQueueImplementation @Inject constructor(
|
|||
// not when the Bolus command is starting. The command closes the dialog upon completion).
|
||||
showBolusProgressDialog(detailedBolusInfo)
|
||||
// Notify Wear about upcoming bolus
|
||||
rxBus.send(EventBolusRequested(detailedBolusInfo.insulin))
|
||||
rxBus.send(EventMobileToWear(EventData.BolusProgress(percent = 0, status = rh.gs(R.string.bolusrequested, detailedBolusInfo.insulin))))
|
||||
}
|
||||
}
|
||||
notifyAboutNewCommand()
|
||||
|
|
|
@ -65,10 +65,14 @@ class BolusWizard @Inject constructor(
|
|||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
var timeStamp : Long
|
||||
|
||||
init {
|
||||
injector.androidInjector().inject(this)
|
||||
timeStamp = dateUtil.now()
|
||||
}
|
||||
|
||||
|
||||
// Intermediate
|
||||
var sens = 0.0
|
||||
private set
|
||||
|
@ -236,7 +240,7 @@ class BolusWizard @Inject constructor(
|
|||
// Total
|
||||
calculatedTotalInsulin = insulinFromBG + insulinFromTrend + insulinFromCarbs + insulinFromBolusIOB + insulinFromBasalIOB + insulinFromCorrection + insulinFromSuperBolus + insulinFromCOB
|
||||
|
||||
var percentage = if (usePercentage) totalPercentage else percentageCorrection.toDouble()
|
||||
val percentage = if (usePercentage) totalPercentage else percentageCorrection.toDouble()
|
||||
|
||||
// Percentage adjustment
|
||||
totalBeforePercentageAdjustment = calculatedTotalInsulin
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.json.JSONObject
|
|||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@Singleton
|
||||
class QuickWizard @Inject constructor(
|
||||
|
@ -55,6 +56,11 @@ class QuickWizard @Inject constructor(
|
|||
operator fun get(position: Int): QuickWizardEntry =
|
||||
QuickWizardEntry(injector).from(storage.get(position) as JSONObject, position)
|
||||
|
||||
fun list(): ArrayList<QuickWizardEntry> =
|
||||
ArrayList<QuickWizardEntry>().also {
|
||||
for (i in 0 until size()) it.add(get(i))
|
||||
}
|
||||
|
||||
fun get(guid: String): QuickWizardEntry? {
|
||||
for (i in 0 until storage.length()) {
|
||||
val entry = QuickWizardEntry(injector).from(storage.get(i) as JSONObject, i)
|
||||
|
|
|
@ -1212,4 +1212,5 @@
|
|||
<string name="show_hide_records">Hide loop records</string>
|
||||
<string name="widget_description">AndroidAPS widget</string>
|
||||
<string name="configure">Configure opacity</string>
|
||||
<string name="loop_status">Loop status</string>
|
||||
</resources>
|
||||
|
|
|
@ -4,9 +4,9 @@ import android.content.Context
|
|||
import android.os.PowerManager
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.TestBaseWithProfile
|
||||
import info.nightscout.androidaps.TestPumpPlugin
|
||||
import info.nightscout.androidaps.core.R
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
|
@ -138,6 +138,7 @@ class CommandQueueImplementationTest : TestBaseWithProfile() {
|
|||
`when`(constraintChecker.applyBasalPercentConstraints(anyObject(), anyObject())).thenReturn(percentageConstraint)
|
||||
`when`(rh.gs(R.string.connectiontimedout)).thenReturn("Connection timed out")
|
||||
`when`(rh.gs(R.string.formatinsulinunits)).thenReturn("%1\$.2f U")
|
||||
`when`(rh.gs(R.string.bolusrequested)).thenReturn("Going to deliver %1\$.2f U")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -48,6 +48,7 @@ class BolusWizardTest : TestBase() {
|
|||
it.activePlugin = activePlugin
|
||||
it.commandQueue = commandQueue
|
||||
it.loop = loop
|
||||
it.dateUtil = dateUtil
|
||||
it.iobCobCalculator = iobCobCalculator
|
||||
it.glucoseStatusProvider = GlucoseStatusProvider(aapsLogger = aapsLogger, iobCobCalculator = iobCobCalculator, dateUtil = dateUtil)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
import info.nightscout.shared.weardata.EventData
|
||||
|
||||
class EventMobileToWear(val payload: EventData) : Event()
|
|
@ -0,0 +1,5 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
import info.nightscout.shared.weardata.EventData
|
||||
|
||||
class EventWearToMobile(val payload: EventData) : Event()
|
|
@ -1,7 +0,0 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
import info.nightscout.shared.weardata.ActionData
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class EventWearToMobileAction(val actionData: ActionData) : Event()
|
|
@ -1,7 +0,0 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
import info.nightscout.shared.weardata.ActionData
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class EventWearToMobileChange(val actionData: ActionData) : Event()
|
|
@ -1,7 +0,0 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
import info.nightscout.shared.weardata.ActionData
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class EventWearToMobileConfirm(val actionData: ActionData) : Event()
|
|
@ -1,33 +0,0 @@
|
|||
package info.nightscout.shared.weardata
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
@Serializable
|
||||
sealed class ActionData {
|
||||
|
||||
fun serialize() = Json.encodeToString(serializer(), this)
|
||||
|
||||
companion object {
|
||||
|
||||
fun deserialize(json: String) = Json.decodeFromString(serializer(), json)
|
||||
}
|
||||
// Wear -> Mobile
|
||||
@Serializable
|
||||
data class Pong(val timeStamp: Long) : ActionData()
|
||||
@Serializable
|
||||
data class Bolus(val insulin: Double, val carbs: Int) : ActionData()
|
||||
@Serializable
|
||||
data class ProfileSwitch(val timeShift: Int, val percentage: Int) : ActionData()
|
||||
|
||||
@Serializable
|
||||
data class OpenProfileSwitch(val timeShift: Int, val percentage: Int) : ActionData()
|
||||
|
||||
// Mobile -> Wear
|
||||
@Serializable
|
||||
data class Ping(val timeStamp: Long) : ActionData()
|
||||
@Serializable
|
||||
data class ConfirmAction(val title: String, val message: String, val originalCommand: ActionData) : ActionData()
|
||||
@Serializable
|
||||
data class ChangeAction(val title: String, val message: String, val originalCommand: ActionData) : ActionData()
|
||||
}
|
|
@ -0,0 +1,237 @@
|
|||
package info.nightscout.shared.weardata
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import java.util.*
|
||||
|
||||
@Serializable
|
||||
sealed class EventData : Event() {
|
||||
|
||||
var sourceNodeId = ""
|
||||
|
||||
fun serialize() = Json.encodeToString(serializer(), this)
|
||||
|
||||
companion object {
|
||||
|
||||
fun deserialize(json: String) = Json.decodeFromString(serializer(), json)
|
||||
}
|
||||
|
||||
// Mobile <- Wear
|
||||
@Serializable
|
||||
data class ActionPong(val timeStamp: Long) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class Error(val timeStamp: Long) : EventData() // ignored
|
||||
|
||||
@Serializable
|
||||
data class CancelBolus(val timeStamp: Long) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionResendData(val from: String) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionPumpStatus(val timeStamp: Long) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionLoopStatus(val timeStamp: Long) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionTddStatus(val timeStamp: Long) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionECarbsPreCheck(val carbs: Int, val carbsTimeShift: Int, val duration: Int) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionBolusPreCheck(val insulin: Double, val carbs: Int) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionFillPreCheck(val insulin: Double) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionFillPresetPreCheck(val button: Int) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionProfileSwitchSendInitialData(val timeStamp: Long) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionProfileSwitchPreCheck(val timeShift: Int, val percentage: Int) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionWizardPreCheck(val carbs: Int, val percentage: Int) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionQuickWizardPreCheck(val guid: String) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionTempTargetPreCheck(
|
||||
val command: TempTargetCommand,
|
||||
val isMgdl: Boolean = true, val duration: Int = 0, val low: Double = 0.0, val high: Double = 0.0 // manual
|
||||
) : EventData() {
|
||||
|
||||
@Serializable
|
||||
enum class TempTargetCommand {
|
||||
|
||||
PRESET_ACTIVITY, PRESET_HYPO, PRESET_EATING, CANCEL, MANUAL
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Mobile <- Wear return
|
||||
|
||||
@Serializable
|
||||
data class ActionWizardConfirmed(val timeStamp: Long) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionTempTargetConfirmed(val isMgdl: Boolean = true, val duration: Int = 0, val low: Double = 0.0, val high: Double = 0.0) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionBolusConfirmed(val insulin: Double, val carbs: Int) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionECarbsConfirmed(val carbs: Int, val carbsTime: Long, val duration: Int) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionFillConfirmed(val insulin: Double) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionProfileSwitchConfirmed(val timeShift: Int, val percentage: Int) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class OpenLoopRequestConfirmed(val timeStamp: Long) : EventData()
|
||||
|
||||
// Mobile -> Wear
|
||||
@Serializable
|
||||
data class CancelNotification(val timeStamp: Long) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionPing(val timeStamp: Long) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class OpenSettings(val timeStamp: Long) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class BolusProgress(val percent: Int, val status: String) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class SingleBg @JvmOverloads constructor(
|
||||
var timeStamp: Long,
|
||||
val sgvString: String = "---",
|
||||
val glucoseUnits: String = "-",
|
||||
val slopeArrow: String = "--",
|
||||
val delta: String = "--",
|
||||
val avgDelta: String = "--",
|
||||
val sgvLevel: Long = 0,
|
||||
val sgv: Double,
|
||||
val high: Double, // highLine
|
||||
val low: Double, // lowLine
|
||||
val color: Int = 0
|
||||
) : EventData(), Comparable<SingleBg> {
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
when {
|
||||
other !is SingleBg -> false
|
||||
color != other.color -> false
|
||||
else -> timeStamp == other.timeStamp
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return Objects.hash(timeStamp, color)
|
||||
}
|
||||
|
||||
override fun compareTo(other: SingleBg): Int {
|
||||
// reverse order endTime get latest first
|
||||
if (this.timeStamp < other.timeStamp) return 1
|
||||
return if (this.timeStamp > other.timeStamp) -1 else 0
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class GraphData(
|
||||
val entries: ArrayList<SingleBg>
|
||||
) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class TreatmentData(
|
||||
val temps: ArrayList<TempBasal>,
|
||||
val basals: ArrayList<Basal>,
|
||||
val boluses: ArrayList<Treatment>,
|
||||
val predictions: ArrayList<SingleBg>
|
||||
) : EventData() {
|
||||
|
||||
@Serializable
|
||||
data class TempBasal(
|
||||
val startTime: Long,
|
||||
val startBasal: Double,
|
||||
val endTime: Long,
|
||||
val endBasal: Double,
|
||||
val amount: Double
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Basal(
|
||||
val startTime: Long,
|
||||
val endTime: Long,
|
||||
val amount: Double
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Treatment(
|
||||
val date: Long,
|
||||
val bolus: Double,
|
||||
val carbs: Double,
|
||||
val isSMB: Boolean,
|
||||
val isValid: Boolean,
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class Status(
|
||||
val externalStatus: String,
|
||||
val iobSum: String,
|
||||
val iobDetail: String,
|
||||
val detailedIob: Boolean,
|
||||
val cob: String,
|
||||
val currentBasal: String,
|
||||
val battery: String,
|
||||
val rigBattery: String,
|
||||
val openApsStatus: Long,
|
||||
val bgi: String,
|
||||
val showBgi: Boolean,
|
||||
val batteryLevel: Int
|
||||
) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class Preferences(
|
||||
val timeStamp: Long,
|
||||
val wearControl: Boolean,
|
||||
val unitsMgdl: Boolean,
|
||||
val bolusPercentage: Int,
|
||||
val maxCarbs: Int,
|
||||
val maxBolus: Double
|
||||
) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class QuickWizard(
|
||||
val entries: ArrayList<QuickWizardEntry>
|
||||
) : EventData() {
|
||||
|
||||
@Serializable
|
||||
data class QuickWizardEntry(
|
||||
val guid: String,
|
||||
val buttonText: String,
|
||||
val carbs: Int,
|
||||
val validFrom: Int,
|
||||
val validTo: Int
|
||||
) : EventData()
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class ActionProfileSwitchOpenActivity(val timeShift: Int, val percentage: Int) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class OpenLoopRequest(val title: String, val message: String, val returnCommand: EventData?) : EventData()
|
||||
|
||||
@Serializable // returnCommand is sent back to Mobile after confirmation
|
||||
data class ConfirmAction(val title: String, val message: String, val returnCommand: EventData?) : EventData()
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package info.nightscout.shared.weardata
|
||||
|
||||
import android.content.Context
|
||||
import info.nightscout.shared.R
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Suppress("PropertyName")
|
||||
@Singleton
|
||||
class WearConstants @Inject constructor(private val context: Context) {
|
||||
|
||||
// Paths must be defined in manifest
|
||||
// mobile -> wear (data)
|
||||
val M_W_DATA get() = context.getString(R.string.path_watch_data)
|
||||
val M_W_STATUS get() = context.getString(R.string.path_status)
|
||||
val M_W_PREFERENCES get() = context.getString(R.string.path_preferences)
|
||||
val M_W_QUICK_WIZARD get() = context.getString(R.string.path_quick_wizard)
|
||||
val M_W_BASAL get() = context.getString(R.string.path_basal)
|
||||
val M_W_BOLUS_PROGRESS get() = context.getString(R.string.path_bolus_progress)
|
||||
val M_W_ACTION_CONFIRMATION_REQUEST get() = context.getString(R.string.path_action_confirmation)
|
||||
val M_W_ACTION_CHANGE_CONFIRMATION_REQUEST get() = context.getString(R.string.path_change_confirmation_request)
|
||||
val M_W_ACTION_CANCEL_NOTIFICATION_REQUEST get() = context.getString(R.string.path_cancel_notification_request)
|
||||
|
||||
// mobile -> wear (message)
|
||||
val M_W_OPEN_SETTINGS get() = context.getString(R.string.path_open_wear_setting)
|
||||
val M_W_PING get() = context.getString(R.string.path_ping)
|
||||
|
||||
// wear -> mobile (message)
|
||||
val W_M_RESEND_DATA get() = context.getString(R.string.path_resend_data_request)
|
||||
val W_M_CANCEL_BOLUS get() = context.getString(R.string.path_cancel_bolus_on_phone)
|
||||
val W_M_CONFIRM_ACTION get() = context.getString(R.string.path_confirm_action)
|
||||
val W_M_INITIATE_ACTION get() = context.getString(R.string.path_initiate_action_on_phone)
|
||||
val W_M_PONG get() = context.getString(R.string.path_pong)
|
||||
|
||||
companion object {
|
||||
|
||||
// actions for WEAR_INITIATE_ACTION_ON_PHONE
|
||||
// used by
|
||||
// DataLayerListenerService::initiateAction
|
||||
// ActionStringHandler::handleInitiateActionOnPhone
|
||||
// EventWearInitiateAction
|
||||
const val ACTION_FILL_PRESET = "fillpreset"
|
||||
const val ACTION_FILL = "fill"
|
||||
const val ACTION_BOLUS = "bolus"
|
||||
const val ACTION_TEMPORARY_TARGET = "temptarget"
|
||||
const val ACTION_STATUS = "status"
|
||||
const val ACTION_WIZARD = "wizard"
|
||||
const val ACTION_WIZARD2 = "wizard2"
|
||||
const val ACTION_QUICK_WIZARD = "quick_wizard"
|
||||
const val ACTION_OPEN_CPP = "opencpp"
|
||||
const val ACTION_CPP_SET = "cppset"
|
||||
const val ACTION_TDD_STATS = "tddstats"
|
||||
const val ACTION_E_CARBS = "ecarbs"
|
||||
const val ACTION_CHANGE_REQUEST = "changeRequest"
|
||||
const val ACTION_CANCEL_CHANGE_REQUEST = "cancelChangeRequest"
|
||||
const val ACTION_DISMISS_OVERVIEW_NOTIF = "dismissoverviewnotification"
|
||||
|
||||
//data keys
|
||||
const val KEY_ACTION_DATA = "actionData"
|
||||
}
|
||||
}
|
|
@ -1,19 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="path_ping" translatable="false">/ping</string>
|
||||
<string name="path_pong" translatable="false">/pong</string>
|
||||
<string name="path_open_wear_setting" translatable="false">/openwearsettings</string>
|
||||
<string name="path_resend_data_request" translatable="false">/nightscout_watch_data_resend</string>
|
||||
<string name="path_initiate_action_on_phone" translatable="false">/nightscout_watch_initiateactionstring</string>
|
||||
<string name="path_cancel_bolus_on_phone" translatable="false">/nightscout_watch_cancel_bolus</string>
|
||||
<string name="path_confirm_action" translatable="false">/nightscout_watch_confirmactionstring</string>
|
||||
<string name="path_watch_data" translatable="false">/nightscout_watch_data</string>
|
||||
<string name="path_status" translatable="false">/sendstatustowear</string>
|
||||
<string name="path_preferences" translatable="false">/sendpreferencestowear</string>
|
||||
<string name="path_quick_wizard" translatable="false">/send_quick_wizard</string>
|
||||
<string name="path_basal" translatable="false">/nightscout_watch_basal</string>
|
||||
<string name="path_bolus_progress" translatable="false">/nightscout_watch_bolusprogress</string>
|
||||
<string name="path_action_confirmation" translatable="false">/nightscout_watch_actionconfirmationrequest</string>
|
||||
<string name="path_change_confirmation_request" translatable="false">/nightscout_watch_changeconfirmationrequest</string>
|
||||
<string name="path_cancel_notification_request" translatable="false">/nightscout_watch_cancelnotificationrequest</string>
|
||||
<string name="path_rx_bridge" translatable="false">/rx_bridge</string>
|
||||
</resources>
|
|
@ -241,7 +241,7 @@
|
|||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service android:name=".data.DataLayerListenerService"
|
||||
<service android:name=".comm.DataLayerListenerServiceWear"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.wearable.CAPABILITY_CHANGED" />
|
||||
|
@ -252,42 +252,6 @@
|
|||
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_watch_data"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_status"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_preferences"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_quick_wizard"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_basal"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_bolus_progress"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_action_confirmation"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_change_confirmation_request"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_cancel_notification_request"
|
||||
android:scheme="wear" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
|
@ -299,15 +263,7 @@
|
|||
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_ping"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_open_wear_setting"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="@string/path_action_confirmation"
|
||||
android:pathPrefix="@string/path_rx_bridge"
|
||||
android:scheme="wear" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
@ -466,7 +422,7 @@
|
|||
</service>
|
||||
|
||||
<service
|
||||
android:name=".complications.UploaderBattery"
|
||||
android:name=".complications.UploaderBatteryComplication"
|
||||
android:icon="@drawable/ic_battery_charging_wireless_50"
|
||||
android:label="Uploader/Phone Battery"
|
||||
android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
|
||||
|
|
|
@ -7,7 +7,11 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
|||
import androidx.preference.PreferenceManager
|
||||
import dagger.android.AndroidInjector
|
||||
import dagger.android.DaggerApplication
|
||||
import info.nightscout.androidaps.comm.DataHandlerWear
|
||||
import info.nightscout.androidaps.comm.DataLayerListenerServiceWear
|
||||
import info.nightscout.androidaps.di.DaggerWearComponent
|
||||
import info.nightscout.androidaps.events.EventWearPreferenceChange
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import javax.inject.Inject
|
||||
|
@ -15,11 +19,15 @@ import javax.inject.Inject
|
|||
class Aaps : DaggerApplication(), OnSharedPreferenceChangeListener {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var dataHandlerWear: DataHandlerWear // instantiate only
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
aapsLogger.debug(LTag.WEAR, "onCreate")
|
||||
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this)
|
||||
startService(Intent(this, DataLayerListenerServiceWear::class.java))
|
||||
|
||||
}
|
||||
|
||||
override fun applicationInjector(): AndroidInjector<out DaggerApplication> =
|
||||
|
@ -30,6 +38,7 @@ class Aaps : DaggerApplication(), OnSharedPreferenceChangeListener {
|
|||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||
// we trigger update on Complications
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(Intent.ACTION_SEND))
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(DataLayerListenerServiceWear.INTENT_NEW_DATA))
|
||||
rxBus.send(EventWearPreferenceChange(key))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
package info.nightscout.androidaps.comm
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import androidx.wear.tiles.TileService
|
||||
import com.google.android.gms.wearable.WearableListenerService
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventWearToMobile
|
||||
import info.nightscout.androidaps.interaction.AAPSPreferences
|
||||
import info.nightscout.androidaps.interaction.actions.AcceptActivity
|
||||
import info.nightscout.androidaps.interaction.actions.CPPActivity
|
||||
import info.nightscout.androidaps.interaction.utils.Persistence
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.tile.ActionsTileService
|
||||
import info.nightscout.androidaps.tile.QuickWizardTileService
|
||||
import info.nightscout.androidaps.tile.TempTargetTileService
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
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 io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class DataHandlerWear @Inject constructor(
|
||||
private val context: Context,
|
||||
private val rxBus: RxBus,
|
||||
private val aapsSchedulers: AapsSchedulers,
|
||||
private val sp: SP,
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val persistence: Persistence
|
||||
) {
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
init {
|
||||
setupBus()
|
||||
}
|
||||
|
||||
private fun setupBus() {
|
||||
disposable += rxBus
|
||||
.toObservable(EventData.ActionPing::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe {
|
||||
aapsLogger.debug(LTag.WEAR, "Ping received from ${it.sourceNodeId}")
|
||||
rxBus.send(EventWearToMobile(EventData.ActionPong(System.currentTimeMillis())))
|
||||
}
|
||||
disposable += rxBus
|
||||
.toObservable(EventData.ConfirmAction::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe {
|
||||
aapsLogger.debug(LTag.WEAR, "ConfirmAction received from ${it.sourceNodeId}")
|
||||
context.startActivity(Intent(context, AcceptActivity::class.java).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
putExtras(
|
||||
Bundle().also { bundle ->
|
||||
bundle.putString("title", it.title)
|
||||
bundle.putString("message", it.message)
|
||||
bundle.putString(DataLayerListenerServiceWear.KEY_ACTION_DATA, it.returnCommand?.serialize())
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
disposable += rxBus
|
||||
.toObservable(EventData.CancelNotification::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe {
|
||||
aapsLogger.debug(LTag.WEAR, "ActionCancelNotification received from ${it.sourceNodeId}")
|
||||
(context.getSystemService(WearableListenerService.NOTIFICATION_SERVICE) as NotificationManager).cancel(DataLayerListenerServiceWear.CHANGE_NOTIF_ID)
|
||||
}
|
||||
disposable += rxBus
|
||||
.toObservable(EventData.OpenLoopRequest::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe {
|
||||
aapsLogger.debug(LTag.WEAR, "OpenLoopRequest received from ${it.sourceNodeId}")
|
||||
handleOpenLoopRequest(it)
|
||||
}
|
||||
disposable += rxBus
|
||||
.toObservable(EventData.OpenSettings::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe {
|
||||
aapsLogger.debug(LTag.WEAR, "ActionOpenSettings received from ${it.sourceNodeId}")
|
||||
context.startActivity(Intent(context, AAPSPreferences::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
}
|
||||
disposable += rxBus
|
||||
.toObservable(EventData.ActionProfileSwitchOpenActivity::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe { event ->
|
||||
aapsLogger.debug(LTag.WEAR, "ActionProfileSwitchOpenActivity received from ${event.sourceNodeId}")
|
||||
context.startActivity(Intent(context, CPPActivity::class.java).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
putExtras(Bundle().also { bundle ->
|
||||
bundle.putInt("percentage", event.percentage)
|
||||
bundle.putInt("timeshift", event.timeShift)
|
||||
})
|
||||
})
|
||||
}
|
||||
disposable += rxBus
|
||||
.toObservable(EventData.BolusProgress::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe {
|
||||
aapsLogger.debug(LTag.WEAR, "Bolus progress received from ${it.sourceNodeId}")
|
||||
handleBolusProgress(it)
|
||||
rxBus.send(EventWearToMobile(EventData.ActionPong(System.currentTimeMillis())))
|
||||
}
|
||||
disposable += rxBus
|
||||
.toObservable(EventData.Status::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.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())
|
||||
}
|
||||
)
|
||||
}
|
||||
disposable += rxBus
|
||||
.toObservable(EventData.SingleBg::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.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)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.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)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.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)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe {
|
||||
aapsLogger.debug(LTag.WEAR, "Preferences received from ${it.sourceNodeId}")
|
||||
if (it.wearControl != sp.getBoolean(R.string.key_wear_control, false)) {
|
||||
sp.putBoolean(R.string.key_wear_control, it.wearControl)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
TileService.getUpdater(context).requestUpdate(ActionsTileService::class.java)
|
||||
TileService.getUpdater(context).requestUpdate(TempTargetTileService::class.java)
|
||||
TileService.getUpdater(context).requestUpdate(QuickWizardTileService::class.java)
|
||||
}
|
||||
}
|
||||
sp.putBoolean(R.string.key_units_mgdl, it.unitsMgdl)
|
||||
sp.putInt(R.string.key_boluswizard_percentage, it.bolusPercentage)
|
||||
sp.putInt(R.string.key_treatmentssafety_maxcarbs, it.maxCarbs)
|
||||
sp.putDouble(R.string.key_treatmentssafety_maxbolus, it.maxBolus)
|
||||
}
|
||||
disposable += rxBus
|
||||
.toObservable(EventData.QuickWizard::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe {
|
||||
aapsLogger.debug(LTag.WEAR, "QuickWizard received from ${it.sourceNodeId}")
|
||||
val serialized = it.serialize()
|
||||
if (serialized != sp.getString(R.string.key_quick_wizard_data, "")) {
|
||||
sp.putString(R.string.key_quick_wizard_data, serialized)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
TileService.getUpdater(context).requestUpdate(QuickWizardTileService::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleBolusProgress(bolusProgress: EventData.BolusProgress) {
|
||||
val vibratePattern: LongArray
|
||||
val vibrate = sp.getBoolean("vibrateOnBolus", true)
|
||||
vibratePattern = if (vibrate) longArrayOf(0, 50, 1000) else longArrayOf(0, 1, 1000)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
createBolusProgressChannels()
|
||||
}
|
||||
val cancelIntent = Intent(context, DataLayerListenerServiceWear::class.java)
|
||||
cancelIntent.action = DataLayerListenerServiceWear.INTENT_CANCEL_BOLUS
|
||||
val cancelPendingIntent = PendingIntent.getService(context, 0, cancelIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val notificationBuilder: NotificationCompat.Builder =
|
||||
NotificationCompat.Builder(context, if (vibrate) DataLayerListenerServiceWear.AAPS_NOTIFY_CHANNEL_ID_BOLUS_PROGRESS else DataLayerListenerServiceWear.AAPS_NOTIFY_CHANNEL_ID_BOLUS_PROGRESS_SILENT)
|
||||
.setSmallIcon(R.drawable.ic_icon)
|
||||
.setContentTitle(context.getString(R.string.bolus_progress))
|
||||
.setContentText("${bolusProgress.percent}% - ${bolusProgress.status}")
|
||||
.setSubText(context.getString(R.string.press_to_cancel))
|
||||
.setContentIntent(cancelPendingIntent)
|
||||
.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||
.setVibrate(vibratePattern)
|
||||
.addAction(R.drawable.ic_cancel, context.getString(R.string.cancel_bolus), cancelPendingIntent)
|
||||
val notificationManager = NotificationManagerCompat.from(context)
|
||||
notificationManager.notify(DataLayerListenerServiceWear.BOLUS_PROGRESS_NOTIF_ID, notificationBuilder.build())
|
||||
notificationManager.cancel(DataLayerListenerServiceWear.CONFIRM_NOTIF_ID) // multiple watch setup
|
||||
if (bolusProgress.percent == 100) {
|
||||
scheduleDismissBolusProgress(5)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(value = 26) private fun createBolusProgressChannels() {
|
||||
createNotificationChannel(
|
||||
longArrayOf(0, 50, 1000),
|
||||
DataLayerListenerServiceWear.AAPS_NOTIFY_CHANNEL_ID_BOLUS_PROGRESS,
|
||||
context.getString(R.string.bolus_progress_channel_name),
|
||||
context.getString(R.string.bolus_progress_channel_description)
|
||||
)
|
||||
createNotificationChannel(
|
||||
longArrayOf(0, 1, 1000),
|
||||
DataLayerListenerServiceWear.AAPS_NOTIFY_CHANNEL_ID_BOLUS_PROGRESS_SILENT,
|
||||
context.getString(R.string.bolus_progress_silent_channel_name),
|
||||
context.getString(R.string.bolus_progress_silent_channel_description)
|
||||
)
|
||||
}
|
||||
|
||||
@TargetApi(value = 26) private fun createNotificationChannel(vibratePattern: LongArray, channelID: String, name: CharSequence, description: String) {
|
||||
val channel = NotificationChannel(channelID, name, NotificationManager.IMPORTANCE_HIGH)
|
||||
channel.description = description
|
||||
channel.enableVibration(true)
|
||||
channel.vibrationPattern = vibratePattern
|
||||
|
||||
// Register the channel with the system; you can't change the importance
|
||||
// or other notification behaviors after this
|
||||
context.getSystemService(NotificationManager::class.java)
|
||||
.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
private fun handleOpenLoopRequest(command: EventData.OpenLoopRequest) {
|
||||
// Create the NotificationChannel, but only on API 26+ because
|
||||
// the NotificationChannel class is new and not in the support library
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val name: CharSequence = "AAPS Open Loop"
|
||||
val description = "Open Loop request notification"
|
||||
val channel = NotificationChannel(DataLayerListenerServiceWear.AAPS_NOTIFY_CHANNEL_ID_OPEN_LOOP, name, NotificationManager.IMPORTANCE_HIGH)
|
||||
channel.description = description
|
||||
channel.enableVibration(true)
|
||||
|
||||
// Register the channel with the system; you can't change the importance
|
||||
// or other notification behaviors after this
|
||||
val notificationManager = context.getSystemService(NotificationManager::class.java)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
var builder = NotificationCompat.Builder(context, DataLayerListenerServiceWear.AAPS_NOTIFY_CHANNEL_ID_OPEN_LOOP)
|
||||
builder = builder.setSmallIcon(R.drawable.notif_icon)
|
||||
.setContentTitle(command.title)
|
||||
.setContentText(command.message)
|
||||
.setPriority(Notification.PRIORITY_HIGH)
|
||||
.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
|
||||
|
||||
// Creates an explicit intent for an Activity in your app
|
||||
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_ACTION_DATA, command.returnCommand?.serialize())
|
||||
})
|
||||
}
|
||||
val resultPendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
builder = builder.setContentIntent(resultPendingIntent)
|
||||
val mNotificationManager = context.getSystemService(WearableListenerService.NOTIFICATION_SERVICE) as NotificationManager
|
||||
// mId allows you to update the notification later on.
|
||||
mNotificationManager.notify(DataLayerListenerServiceWear.CHANGE_NOTIF_ID, builder.build())
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun scheduleDismissBolusProgress(seconds: Int) {
|
||||
Thread {
|
||||
SystemClock.sleep(seconds * 1000L)
|
||||
NotificationManagerCompat.from(context).cancel(DataLayerListenerServiceWear.BOLUS_PROGRESS_NOTIF_ID)
|
||||
}.start()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
package info.nightscout.androidaps.comm
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.google.android.gms.tasks.Tasks
|
||||
import com.google.android.gms.wearable.*
|
||||
import dagger.android.AndroidInjection
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventWearToMobile
|
||||
import info.nightscout.androidaps.interaction.utils.Persistence
|
||||
import info.nightscout.androidaps.interaction.utils.WearUtil
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
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 io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.tasks.await
|
||||
import javax.inject.Inject
|
||||
|
||||
class DataLayerListenerServiceWear : WearableListenerService() {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var wearUtil: WearUtil
|
||||
@Inject lateinit var persistence: Persistence
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
|
||||
private val dataClient by lazy { Wearable.getDataClient(this) }
|
||||
private val messageClient by lazy { Wearable.getMessageClient(this) }
|
||||
private val capabilityClient by lazy { Wearable.getCapabilityClient(this) }
|
||||
//private val nodeClient by lazy { Wearable.getNodeClient(this) }
|
||||
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
||||
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
private val rxPath get() = getString(R.string.path_rx_bridge)
|
||||
|
||||
override fun onCreate() {
|
||||
AndroidInjection.inject(this)
|
||||
super.onCreate()
|
||||
handler.post { updateTranscriptionCapability() }
|
||||
disposable += rxBus
|
||||
.toObservable(EventWearToMobile::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe {
|
||||
sendMessage(rxPath, it.payload.serialize())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPeerConnected(p0: Node) {
|
||||
super.onPeerConnected(p0)
|
||||
}
|
||||
|
||||
override fun onCapabilityChanged(p0: CapabilityInfo) {
|
||||
super.onCapabilityChanged(p0)
|
||||
handler.post { updateTranscriptionCapability() }
|
||||
aapsLogger.debug(LTag.WEAR, "onCapabilityChanged: ${p0.name} ${p0.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}")
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
scope.cancel()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
override fun onDataChanged(dataEvents: DataEventBuffer) {
|
||||
//aapsLogger.debug(LTag.WEAR, "onDataChanged")
|
||||
|
||||
dataEvents.forEach { event ->
|
||||
if (event.type == DataEvent.TYPE_CHANGED) {
|
||||
val path = event.dataItem.uri.path
|
||||
|
||||
aapsLogger.debug(LTag.WEAR, "onDataChanged: Path: $path, EventDataItem=${event.dataItem}")
|
||||
try {
|
||||
@Suppress("ControlFlowWithEmptyBody", "UNUSED_EXPRESSION")
|
||||
when (path) {
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
aapsLogger.error(LTag.WEAR, "onDataChanged failed", exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onDataChanged(dataEvents)
|
||||
}
|
||||
|
||||
override fun onMessageReceived(messageEvent: MessageEvent) {
|
||||
super.onMessageReceived(messageEvent)
|
||||
|
||||
when (messageEvent.path) {
|
||||
rxPath -> {
|
||||
aapsLogger.debug(LTag.WEAR, "onMessageReceived: ${String(messageEvent.data)}")
|
||||
val command = EventData.deserialize(String(messageEvent.data))
|
||||
rxBus.send(command.also { it.sourceNodeId = messageEvent.sourceNodeId })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
when (intent?.action) {
|
||||
|
||||
INTENT_CANCEL_BOLUS -> {
|
||||
//dismiss notification
|
||||
NotificationManagerCompat.from(this).cancel(BOLUS_PROGRESS_NOTIF_ID)
|
||||
//send cancel-request to phone.
|
||||
rxBus.send(EventWearToMobile(EventData.CancelBolus(System.currentTimeMillis())))
|
||||
}
|
||||
|
||||
}
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
private var transcriptionNodeId: String? = null
|
||||
|
||||
private fun updateTranscriptionCapability() {
|
||||
val capabilityInfo: CapabilityInfo = Tasks.await(
|
||||
capabilityClient.getCapability(PHONE_CAPABILITY, CapabilityClient.FILTER_REACHABLE)
|
||||
)
|
||||
aapsLogger.debug(LTag.WEAR, "Nodes: ${capabilityInfo.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}")
|
||||
transcriptionNodeId = pickBestNodeId(capabilityInfo.nodes)
|
||||
aapsLogger.debug(LTag.WEAR, "Selected node: $transcriptionNodeId")
|
||||
}
|
||||
|
||||
// Find a nearby node or pick one arbitrarily
|
||||
private fun pickBestNodeId(nodes: Set<Node>): String? =
|
||||
nodes.firstOrNull { it.isNearby }?.id ?: nodes.firstOrNull()?.id
|
||||
|
||||
@Suppress("unused")
|
||||
private fun sendData(path: String, vararg params: DataMap) {
|
||||
scope.launch {
|
||||
try {
|
||||
for (dm in params) {
|
||||
val request = PutDataMapRequest.create(path).apply {
|
||||
dataMap.putAll(dm)
|
||||
}
|
||||
.asPutDataRequest()
|
||||
.setUrgent()
|
||||
|
||||
val result = dataClient.putDataItem(request).await()
|
||||
aapsLogger.debug(LTag.WEAR, "sendData: ${result.uri} ${params.joinToString()}")
|
||||
}
|
||||
} catch (cancellationException: CancellationException) {
|
||||
throw cancellationException
|
||||
} catch (exception: Exception) {
|
||||
aapsLogger.error(LTag.WEAR, "DataItem failed: $exception")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendMessage(path: String, data: String?) {
|
||||
aapsLogger.debug(LTag.WEAR, "sendMessage: $path $data")
|
||||
transcriptionNodeId?.also { nodeId ->
|
||||
messageClient
|
||||
.sendMessage(nodeId, path, data?.toByteArray() ?: byteArrayOf()).apply {
|
||||
addOnSuccessListener { }
|
||||
addOnFailureListener {
|
||||
aapsLogger.debug(LTag.WEAR, "sendMessage: $path failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
private fun sendMessage(path: String, data: ByteArray) {
|
||||
aapsLogger.debug(LTag.WEAR, "sendMessage: $path")
|
||||
transcriptionNodeId?.also { nodeId ->
|
||||
messageClient
|
||||
.sendMessage(nodeId, path, data).apply {
|
||||
addOnSuccessListener { }
|
||||
addOnFailureListener {
|
||||
aapsLogger.debug(LTag.WEAR, "sendMessage: $path failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
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"
|
||||
|
||||
//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 BOLUS_PROGRESS_NOTIF_ID = 1
|
||||
const val CONFIRM_NOTIF_ID = 2
|
||||
const val CHANGE_NOTIF_ID = 556677
|
||||
|
||||
const val AAPS_NOTIFY_CHANNEL_ID_OPEN_LOOP = "AndroidAPS-OpenLoop"
|
||||
const val AAPS_NOTIFY_CHANNEL_ID_BOLUS_PROGRESS = "bolus progress vibration"
|
||||
const val AAPS_NOTIFY_CHANNEL_ID_BOLUS_PROGRESS_SILENT = "bolus progress silent"
|
||||
}
|
||||
}
|
|
@ -22,15 +22,18 @@ import javax.inject.Inject;
|
|||
|
||||
import dagger.android.AndroidInjection;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.comm.DataLayerListenerServiceWear;
|
||||
import info.nightscout.androidaps.data.RawDisplayData;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.utils.Constants;
|
||||
import info.nightscout.androidaps.interaction.utils.DisplayFormat;
|
||||
import info.nightscout.androidaps.interaction.utils.Inevitable;
|
||||
import info.nightscout.androidaps.interaction.utils.Persistence;
|
||||
import info.nightscout.androidaps.interaction.utils.WearUtil;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
import info.nightscout.shared.weardata.EventData;
|
||||
|
||||
/**
|
||||
* Base class for all complications
|
||||
|
@ -44,6 +47,7 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
|
|||
@Inject DisplayFormat displayFormat;
|
||||
@Inject Persistence persistence;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject RxBus rxBus;
|
||||
|
||||
// Not derived from DaggerService, do injection here
|
||||
@Override
|
||||
|
@ -199,13 +203,13 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
|
|||
persistence.putBoolean("complication_" + complicationId + "_since", usesSinceField());
|
||||
persistence.addToSet(KEY_COMPLICATIONS, "complication_" + complicationId);
|
||||
|
||||
IntentFilter messageFilter = new IntentFilter(Intent.ACTION_SEND);
|
||||
IntentFilter messageFilter = new IntentFilter(DataLayerListenerServiceWear.Companion.getINTENT_NEW_DATA());
|
||||
|
||||
messageReceiver = new MessageReceiver();
|
||||
localBroadcastManager = LocalBroadcastManager.getInstance(this);
|
||||
localBroadcastManager.registerReceiver(messageReceiver, messageFilter);
|
||||
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
rxBus.send(new EventWearToMobile(new EventData.ActionResendData("BaseComplicationProviderService")));
|
||||
checkIfUpdateNeeded();
|
||||
}
|
||||
|
||||
|
@ -232,12 +236,13 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
|
|||
ComplicationTapBroadcastReceiver.getTapActionIntent(
|
||||
getApplicationContext(), thisProvider, complicationId, getComplicationAction());
|
||||
|
||||
final RawDisplayData raw = new RawDisplayData(wearUtil);
|
||||
final RawDisplayData raw = new RawDisplayData();
|
||||
raw.updateForComplicationsFromPersistence(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, displayFormat.shortTimeSince(raw.datetime));
|
||||
persistence.putString(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);
|
||||
|
@ -249,11 +254,11 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
|
|||
final PendingIntent infoToast = ComplicationTapBroadcastReceiver.getTapWarningSinceIntent(
|
||||
getApplicationContext(), thisProvider, complicationId, ComplicationAction.WARNING_SYNC, persistence.whenDataUpdated());
|
||||
complicationData = buildNoSyncComplicationData(dataType, raw, complicationPendingIntent, infoToast, persistence.whenDataUpdated());
|
||||
} else if (wearUtil.msSince(raw.datetime) > Constants.STALE_MS) {
|
||||
} else if (wearUtil.msSince(raw.getSingleBg().getTimeStamp()) > Constants.STALE_MS) {
|
||||
// data arriving from phone AAPS, but it is outdated (uploader/NS/xDrip/Sensor error)
|
||||
final PendingIntent infoToast = ComplicationTapBroadcastReceiver.getTapWarningSinceIntent(
|
||||
getApplicationContext(), thisProvider, complicationId, ComplicationAction.WARNING_OLD, raw.datetime);
|
||||
complicationData = buildOutdatedComplicationData(dataType, raw, complicationPendingIntent, infoToast, raw.datetime);
|
||||
getApplicationContext(), thisProvider, complicationId, ComplicationAction.WARNING_OLD, raw.getSingleBg().getTimeStamp());
|
||||
complicationData = buildOutdatedComplicationData(dataType, raw, complicationPendingIntent, infoToast, raw.getSingleBg().getTimeStamp());
|
||||
} else {
|
||||
// data is up-to-date, we can render standard complication
|
||||
complicationData = buildComplicationData(dataType, raw, complicationPendingIntent);
|
||||
|
@ -310,13 +315,13 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
|
|||
* is up-to-date or need to be changed (a minute or more elapsed)
|
||||
*/
|
||||
private void requestUpdateIfSinceChanged() {
|
||||
final RawDisplayData raw = new RawDisplayData(wearUtil);
|
||||
final RawDisplayData raw = new RawDisplayData();
|
||||
raw.updateForComplicationsFromPersistence(persistence);
|
||||
|
||||
final String lastSince = persistence.getString(KEY_LAST_SHOWN_SINCE_VALUE, "-");
|
||||
final String calcSince = displayFormat.shortTimeSince(raw.datetime);
|
||||
final String calcSince = displayFormat.shortTimeSince(raw.getSingleBg().getTimeStamp());
|
||||
final boolean isStale = (wearUtil.msSince(persistence.whenDataUpdated()) > Constants.STALE_MS)
|
||||
|| (wearUtil.msSince(raw.datetime) > Constants.STALE_MS);
|
||||
|| (wearUtil.msSince(raw.getSingleBg().getTimeStamp()) > Constants.STALE_MS);
|
||||
|
||||
final boolean staleWasRefreshed = persistence.getBoolean(KEY_STALE_REPORTED, false);
|
||||
final boolean sinceWasChanged = !lastSince.equals(calcSince);
|
||||
|
|
|
@ -3,7 +3,6 @@ package info.nightscout.androidaps.complications;
|
|||
import android.app.PendingIntent;
|
||||
import android.support.wearable.complications.ComplicationData;
|
||||
import android.support.wearable.complications.ComplicationText;
|
||||
import android.util.Log;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
|
@ -32,11 +31,11 @@ public class BrCobIobComplication extends BaseComplicationProviderService {
|
|||
ComplicationData complicationData = null;
|
||||
|
||||
if (dataType == ComplicationData.TYPE_SHORT_TEXT) {
|
||||
final String cob = new SmallestDoubleString(raw.sCOB2, SmallestDoubleString.Units.USE).minimise(displayFormat.MIN_FIELD_LEN_COB);
|
||||
final String iob = new SmallestDoubleString(raw.sIOB1, SmallestDoubleString.Units.USE).minimise(Math.max(displayFormat.MIN_FIELD_LEN_IOB, (displayFormat.MAX_FIELD_LEN_SHORT - 1) - cob.length()));
|
||||
final String cob = new SmallestDoubleString(raw.getStatus().getCob(), SmallestDoubleString.Units.USE).minimise(displayFormat.MIN_FIELD_LEN_COB);
|
||||
final String iob = new SmallestDoubleString(raw.getStatus().getIobSum(), SmallestDoubleString.Units.USE).minimise(Math.max(displayFormat.MIN_FIELD_LEN_IOB, (displayFormat.MAX_FIELD_LEN_SHORT - 1) - cob.length()));
|
||||
|
||||
final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
|
||||
.setShortText(ComplicationText.plainText(displayFormat.basalRateSymbol() + raw.sBasalRate))
|
||||
.setShortText(ComplicationText.plainText(displayFormat.basalRateSymbol() + raw.getStatus().getCurrentBasal()))
|
||||
.setShortTitle(ComplicationText.plainText(cob + " " + iob))
|
||||
.setTapAction(complicationPendingIntent);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ public class CobIconComplication extends BaseComplicationProviderService {
|
|||
|
||||
if (dataType == ComplicationData.TYPE_SHORT_TEXT) {
|
||||
final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
|
||||
.setShortText(ComplicationText.plainText(raw.sCOB2))
|
||||
.setShortText(ComplicationText.plainText(raw.getStatus().getCob()))
|
||||
.setIcon(
|
||||
Icon.createWithResource(
|
||||
this, R.drawable.ic_carbs))
|
||||
|
|
|
@ -18,8 +18,8 @@ public class CobIobComplication extends BaseComplicationProviderService {
|
|||
ComplicationData complicationData = null;
|
||||
|
||||
if (dataType == ComplicationData.TYPE_SHORT_TEXT) {
|
||||
final String cob = raw.sCOB2;
|
||||
final String iob = new SmallestDoubleString(raw.sIOB1, SmallestDoubleString.Units.USE).minimise(displayFormat.MAX_FIELD_LEN_SHORT);
|
||||
final String cob = raw.getStatus().getCob();
|
||||
final String iob = new SmallestDoubleString(raw.getStatus().getIobSum(), SmallestDoubleString.Units.USE).minimise(displayFormat.MAX_FIELD_LEN_SHORT);
|
||||
|
||||
final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
|
||||
.setShortText(ComplicationText.plainText(cob))
|
||||
|
|
|
@ -20,7 +20,7 @@ public class IobIconComplication extends BaseComplicationProviderService {
|
|||
ComplicationData complicationData = null;
|
||||
|
||||
if (dataType == ComplicationData.TYPE_SHORT_TEXT) {
|
||||
final String iob = new SmallestDoubleString(raw.sIOB1, SmallestDoubleString.Units.USE).minimise(displayFormat.MAX_FIELD_LEN_SHORT);
|
||||
final String iob = new SmallestDoubleString(raw.getStatus().getIobSum(), SmallestDoubleString.Units.USE).minimise(displayFormat.MAX_FIELD_LEN_SHORT);
|
||||
|
||||
final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
|
||||
.setShortText(ComplicationText.plainText(iob))
|
||||
|
|
|
@ -32,7 +32,8 @@ public class SgvComplication extends BaseComplicationProviderService {
|
|||
switch (dataType) {
|
||||
case ComplicationData.TYPE_SHORT_TEXT:
|
||||
final ComplicationData.Builder builder = new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
|
||||
.setShortText(ComplicationText.plainText(raw.sSgv + raw.sDirection + "\uFE0E"))
|
||||
.setShortText(ComplicationText.plainText(raw.getSingleBg().getSgvString() + raw.getSingleBg().getSlopeArrow() +
|
||||
"\uFE0E"))
|
||||
.setShortTitle(ComplicationText.plainText(displayFormat.shortTrend(raw)))
|
||||
.setTapAction(complicationPendingIntent);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import info.nightscout.shared.logging.LTag;
|
|||
/*
|
||||
* Created by dlvoy on 2019-11-12
|
||||
*/
|
||||
public class UploaderBattery extends BaseComplicationProviderService {
|
||||
public class UploaderBatteryComplication extends BaseComplicationProviderService {
|
||||
|
||||
public ComplicationData buildComplicationData(int dataType, RawDisplayData raw, PendingIntent complicationPendingIntent) {
|
||||
|
||||
|
@ -25,9 +25,9 @@ public class UploaderBattery extends BaseComplicationProviderService {
|
|||
int level = 0;
|
||||
String levelStr = "???";
|
||||
|
||||
if (raw.sUploaderBattery.matches("^[0-9]+$")) {
|
||||
if (raw.getStatus().getBattery().matches("^[0-9]+$")) {
|
||||
try {
|
||||
level = Integer.parseInt(raw.sUploaderBattery);
|
||||
level = Integer.parseInt(raw.getStatus().getBattery());
|
||||
level = Math.max(Math.min(level, 100), 0);
|
||||
levelStr = level + "%";
|
||||
int iconNo = (int) Math.floor(level / 10.0);
|
||||
|
@ -112,7 +112,7 @@ public class UploaderBattery extends BaseComplicationProviderService {
|
|||
|
||||
|
||||
} catch (NumberFormatException ex) {
|
||||
aapsLogger.error(LTag.WEAR, "Cannot parse battery level of: " + raw.sUploaderBattery);
|
||||
aapsLogger.error(LTag.WEAR, "Cannot parse battery level of: " + raw.getStatus().getBattery());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ public class UploaderBattery extends BaseComplicationProviderService {
|
|||
|
||||
@Override
|
||||
public String getProviderCanonicalName() {
|
||||
return UploaderBattery.class.getCanonicalName();
|
||||
return UploaderBatteryComplication.class.getCanonicalName();
|
||||
}
|
||||
|
||||
@Override
|
|
@ -1,11 +0,0 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
/**
|
||||
* Created by adrian on 18/11/16.
|
||||
*/
|
||||
|
||||
public class BasalWatchData {
|
||||
public long startTime;
|
||||
public long endTime;
|
||||
public double amount;
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Created by emmablack on 1/7/15.
|
||||
*/
|
||||
public class BgWatchData implements Comparable<BgWatchData>{
|
||||
public double sgv;
|
||||
public double high;
|
||||
public double low;
|
||||
public long timestamp;
|
||||
public int color;
|
||||
|
||||
public BgWatchData(double aSgv, double aHigh, double aLow, long aTimestamp, int aColor) {
|
||||
this.sgv = aSgv;
|
||||
this.high = aHigh;
|
||||
this.low = aLow;
|
||||
this.timestamp = aTimestamp;
|
||||
this.color = aColor;
|
||||
}
|
||||
|
||||
public BgWatchData(){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that){
|
||||
if(! (that instanceof BgWatchData)){
|
||||
return false;
|
||||
}
|
||||
if (this.color != ((BgWatchData) that).color)
|
||||
return false;
|
||||
return this.timestamp == ((BgWatchData) that).timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(timestamp, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(BgWatchData that) {
|
||||
// reverse order endTime get latest first
|
||||
if(this.timestamp < that.timestamp) return 1;
|
||||
if(this.timestamp > that.timestamp) return -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
/**
|
||||
* Created by adrian on 17/11/16.
|
||||
*/
|
||||
|
||||
public class BolusWatchData {
|
||||
public long date;
|
||||
public double bolus;
|
||||
public double carbs;
|
||||
public boolean isSMB;
|
||||
public boolean isValid;
|
||||
}
|
|
@ -1,552 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package info.nightscout.androidaps.data
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.os.SystemClock
|
||||
import android.util.Base64
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import androidx.wear.tiles.TileService
|
||||
import com.google.android.gms.tasks.Tasks
|
||||
import com.google.android.gms.wearable.*
|
||||
import dagger.android.AndroidInjection
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventWearToMobileAction
|
||||
import info.nightscout.androidaps.events.EventWearToMobileChange
|
||||
import info.nightscout.androidaps.events.EventWearToMobileConfirm
|
||||
import info.nightscout.androidaps.interaction.AAPSPreferences
|
||||
import info.nightscout.androidaps.interaction.actions.AcceptActivity
|
||||
import info.nightscout.androidaps.interaction.actions.CPPActivity
|
||||
import info.nightscout.androidaps.interaction.utils.Persistence
|
||||
import info.nightscout.androidaps.interaction.utils.WearUtil
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.tile.ActionsTileService
|
||||
import info.nightscout.androidaps.tile.QuickWizardTileService
|
||||
import info.nightscout.androidaps.tile.TempTargetTileService
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.SafeParse.stringToInt
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.weardata.ActionData
|
||||
import info.nightscout.shared.weardata.WearConstants
|
||||
import info.nightscout.shared.weardata.WearConstants.Companion.KEY_ACTION_DATA
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.tasks.await
|
||||
import javax.inject.Inject
|
||||
|
||||
class DataLayerListenerService : WearableListenerService() {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var wearUtil: WearUtil
|
||||
@Inject lateinit var persistence: Persistence
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var wearConstants: WearConstants
|
||||
|
||||
private val dataClient by lazy { Wearable.getDataClient(this) }
|
||||
private val messageClient by lazy { Wearable.getMessageClient(this) }
|
||||
private val capabilityClient by lazy { Wearable.getCapabilityClient(this) }
|
||||
//private val nodeClient by lazy { Wearable.getNodeClient(this) }
|
||||
|
||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
||||
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
override fun onCreate() {
|
||||
AndroidInjection.inject(this)
|
||||
super.onCreate()
|
||||
handler.post { updateTranscriptionCapability() }
|
||||
disposable += rxBus
|
||||
.toObservable(EventWearToMobileAction::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe { sendMessage(wearConstants.W_M_INITIATE_ACTION, it.actionData.serialize().toByteArray()) }
|
||||
disposable += rxBus
|
||||
.toObservable(EventWearToMobileConfirm::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe {
|
||||
NotificationManagerCompat.from(this).cancel(CONFIRM_NOTIF_ID)
|
||||
sendMessage(wearConstants.W_M_CONFIRM_ACTION, it.actionData.serialize().toByteArray())
|
||||
}
|
||||
disposable += rxBus
|
||||
.toObservable(EventWearToMobileChange::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe {
|
||||
NotificationManagerCompat.from(this).cancel(CHANGE_NOTIF_ID)
|
||||
sendMessage(wearConstants.W_M_CONFIRM_ACTION, it.actionData.serialize().toByteArray())
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPeerConnected(p0: Node) {
|
||||
super.onPeerConnected(p0)
|
||||
}
|
||||
|
||||
override fun onCapabilityChanged(p0: CapabilityInfo) {
|
||||
super.onCapabilityChanged(p0)
|
||||
handler.post { updateTranscriptionCapability() }
|
||||
aapsLogger.debug(LTag.WEAR, "onCapabilityChanged: ${p0.name} ${p0.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}")
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
scope.cancel()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
override fun onDataChanged(dataEvents: DataEventBuffer) {
|
||||
//aapsLogger.debug(LTag.WEAR, "onDataChanged")
|
||||
|
||||
dataEvents.forEach { event ->
|
||||
if (event.type == DataEvent.TYPE_CHANGED) {
|
||||
val path = event.dataItem.uri.path
|
||||
|
||||
aapsLogger.debug(LTag.WEAR, "onDataChanged: Path: $path, EventDataItem=${event.dataItem}")
|
||||
try {
|
||||
when (path) {
|
||||
wearConstants.M_W_BOLUS_PROGRESS -> {
|
||||
val progress = DataMapItem.fromDataItem(event.dataItem).dataMap.getInt("progresspercent", 0)
|
||||
val status = DataMapItem.fromDataItem(event.dataItem).dataMap.getString("progressstatus", "")
|
||||
showBolusProgress(progress, status)
|
||||
}
|
||||
// remove when finished -> converted to message
|
||||
wearConstants.M_W_ACTION_CONFIRMATION_REQUEST -> {
|
||||
val title = DataMapItem.fromDataItem(event.dataItem).dataMap.getString("title") ?: return@forEach
|
||||
val message = DataMapItem.fromDataItem(event.dataItem).dataMap.getString("message") ?: return@forEach
|
||||
val actionstring = DataMapItem.fromDataItem(event.dataItem).dataMap.getString("actionstring") ?: return@forEach
|
||||
if ("opencpp" == title && actionstring.startsWith("opencpp")) {
|
||||
val act = actionstring.split("\\s+").toTypedArray()
|
||||
startActivity(Intent(this@DataLayerListenerService, CPPActivity::class.java).also { intent ->
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
intent.putExtras(Bundle().also {
|
||||
it.putInt("percentage", stringToInt(act[1]))
|
||||
it.putInt("timeshift", stringToInt(act[2]))
|
||||
})
|
||||
})
|
||||
} else {
|
||||
showConfirmationDialog(title, message, actionstring)
|
||||
}
|
||||
}
|
||||
|
||||
wearConstants.M_W_STATUS -> {
|
||||
val dataMap = DataMapItem.fromDataItem(event.dataItem).dataMap
|
||||
val messageIntent = Intent()
|
||||
messageIntent.action = Intent.ACTION_SEND
|
||||
messageIntent.putExtra("status", dataMap.toBundle())
|
||||
persistence.storeDataMap(RawDisplayData.STATUS_PERSISTENCE_KEY, dataMap)
|
||||
LocalBroadcastManager.getInstance(this@DataLayerListenerService).sendBroadcast(messageIntent)
|
||||
}
|
||||
|
||||
wearConstants.M_W_BASAL -> {
|
||||
val dataMap = DataMapItem.fromDataItem(event.dataItem).dataMap
|
||||
val messageIntent = Intent()
|
||||
messageIntent.action = Intent.ACTION_SEND
|
||||
messageIntent.putExtra("basals", dataMap.toBundle())
|
||||
persistence.storeDataMap(RawDisplayData.BASALS_PERSISTENCE_KEY, dataMap)
|
||||
LocalBroadcastManager.getInstance(this@DataLayerListenerService).sendBroadcast(messageIntent)
|
||||
}
|
||||
|
||||
wearConstants.M_W_PREFERENCES -> {
|
||||
val dataMap = DataMapItem.fromDataItem(event.dataItem).dataMap
|
||||
val keyControl = getString(R.string.key_wear_control)
|
||||
if (dataMap.containsKey(keyControl)) {
|
||||
val previousWearControl = sp.getBoolean(keyControl, false)
|
||||
val wearControl: Boolean = dataMap.getBoolean(keyControl, false)
|
||||
sp.putBoolean(keyControl, wearControl)
|
||||
if (wearControl != previousWearControl) {
|
||||
updateTiles()
|
||||
}
|
||||
}
|
||||
val keyPercentage = getString(R.string.key_boluswizard_percentage)
|
||||
if (dataMap.containsKey(keyPercentage)) {
|
||||
val wpercentage: Int = dataMap.getInt(keyPercentage, 100)
|
||||
sp.putInt(keyPercentage, wpercentage)
|
||||
}
|
||||
val keyUnits = getString(R.string.key_units_mgdl)
|
||||
if (dataMap.containsKey(keyUnits)) {
|
||||
val mgdl: Boolean = dataMap.getBoolean(keyUnits, true)
|
||||
sp.putBoolean(keyUnits, mgdl)
|
||||
}
|
||||
val keyMaxCarbs = getString(R.string.key_treatmentssafety_maxcarbs)
|
||||
if (dataMap.containsKey(keyMaxCarbs)) {
|
||||
val maxCarbs: Int = dataMap.getInt(keyMaxCarbs, 48)
|
||||
sp.putInt(keyMaxCarbs, maxCarbs)
|
||||
}
|
||||
val keyMaxBolus = getString(R.string.key_treatmentssafety_maxbolus)
|
||||
if (dataMap.containsKey(keyMaxBolus)) {
|
||||
sp.putDouble(keyMaxBolus, dataMap.getDouble(keyMaxBolus, 3.0))
|
||||
}
|
||||
}
|
||||
|
||||
wearConstants.M_W_QUICK_WIZARD -> {
|
||||
val dataMap = DataMapItem.fromDataItem(event.dataItem).dataMap
|
||||
aapsLogger.info(LTag.WEAR, "onDataChanged: QUICK_WIZARD_PATH$dataMap")
|
||||
dataMap.remove("timestamp")
|
||||
val key = getString(R.string.key_quick_wizard_data_map)
|
||||
val dataString = Base64.encodeToString(dataMap.toByteArray(), Base64.DEFAULT)
|
||||
if (dataString != sp.getString(key, "")) {
|
||||
sp.putString(key, dataString)
|
||||
// Todo maybe add debounce function, due to 20 seconds update limit?
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
TileService.getUpdater(this@DataLayerListenerService).requestUpdate(QuickWizardTileService::class.java)
|
||||
}
|
||||
aapsLogger.info(LTag.WEAR, "onDataChanged: updated QUICK_WIZARD")
|
||||
} else {
|
||||
aapsLogger.info(LTag.WEAR, "onDataChanged: ignore update")
|
||||
}
|
||||
}
|
||||
|
||||
wearConstants.M_W_ACTION_CHANGE_CONFIRMATION_REQUEST -> {
|
||||
val title = DataMapItem.fromDataItem(event.dataItem).dataMap.getString("title") ?: return@forEach
|
||||
val message = DataMapItem.fromDataItem(event.dataItem).dataMap.getString("message") ?: return@forEach
|
||||
val actionstring = DataMapItem.fromDataItem(event.dataItem).dataMap.getString("actionstring") ?: return@forEach
|
||||
notifyChangeRequest(title, message, actionstring)
|
||||
}
|
||||
|
||||
wearConstants.M_W_ACTION_CANCEL_NOTIFICATION_REQUEST -> {
|
||||
//val actionstring = DataMapItem.fromDataItem(event.getDataItem()).dataMap.getString("actionstring") ?: return@forEach
|
||||
cancelNotificationRequest()
|
||||
}
|
||||
|
||||
wearConstants.M_W_DATA -> {
|
||||
val dataMap = DataMapItem.fromDataItem(event.dataItem).dataMap
|
||||
val messageIntent = Intent()
|
||||
messageIntent.action = Intent.ACTION_SEND
|
||||
messageIntent.putExtra("data", dataMap.toBundle())
|
||||
persistence.storeDataMap(RawDisplayData.DATA_PERSISTENCE_KEY, dataMap)
|
||||
LocalBroadcastManager.getInstance(this@DataLayerListenerService).sendBroadcast(messageIntent)
|
||||
}
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
aapsLogger.error(LTag.WEAR, "onDataChanged failed", exception)
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onDataChanged(dataEvents)
|
||||
}
|
||||
|
||||
override fun onMessageReceived(messageEvent: MessageEvent) {
|
||||
super.onMessageReceived(messageEvent)
|
||||
aapsLogger.debug(LTag.WEAR, "onMessageReceived: $messageEvent")
|
||||
|
||||
when (messageEvent.path) {
|
||||
wearConstants.M_W_PING -> sendMessage(wearConstants.W_M_PONG, byteArrayOf())
|
||||
wearConstants.M_W_OPEN_SETTINGS -> startActivity(Intent(this@DataLayerListenerService, AAPSPreferences::class.java).also { it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
|
||||
wearConstants.M_W_ACTION_CONFIRMATION_REQUEST -> {
|
||||
val command = ActionData.deserialize(String(messageEvent.data)) as ActionData.ConfirmAction
|
||||
if (command.originalCommand is ActionData.OpenProfileSwitch) {
|
||||
val originalCommand = command.originalCommand as ActionData.OpenProfileSwitch
|
||||
startActivity(Intent(this, CPPActivity::class.java).also { intent ->
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
intent.putExtras(Bundle().also {
|
||||
it.putInt("percentage", originalCommand.percentage)
|
||||
it.putInt("timeshift", originalCommand.timeShift)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
startActivity(
|
||||
Intent(this, AcceptActivity::class.java).also { intent ->
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
intent.putExtras(
|
||||
Bundle().also { bundle ->
|
||||
bundle.putString("title", command.title)
|
||||
bundle.putString("message", command.message)
|
||||
bundle.putString(KEY_ACTION_DATA, command.originalCommand.serialize())
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
when (intent?.action) {
|
||||
ACTION_RESEND -> sendMessage(wearConstants.W_M_RESEND_DATA, byteArrayOf())
|
||||
|
||||
ACTION_CANCEL_BOLUS -> {
|
||||
//dismiss notification
|
||||
val notificationManager = NotificationManagerCompat.from(this)
|
||||
notificationManager.cancel(BOLUS_PROGRESS_NOTIF_ID)
|
||||
//send cancel-request to phone.
|
||||
sendMessage(wearConstants.W_M_CANCEL_BOLUS, byteArrayOf())
|
||||
}
|
||||
|
||||
ACTION_CONFIRMATION -> {
|
||||
//dismiss notification
|
||||
val notificationManager = NotificationManagerCompat.from(this)
|
||||
notificationManager.cancel(CONFIRM_NOTIF_ID)
|
||||
intent.getStringExtra("actionstring")?.let { actionString ->
|
||||
sendMessage(wearConstants.W_M_CONFIRM_ACTION, actionString.toByteArray())
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_CONFIRM_CHANGE -> {
|
||||
//dismiss notification
|
||||
val notificationManager = NotificationManagerCompat.from(this)
|
||||
notificationManager.cancel(CHANGE_NOTIF_ID)
|
||||
intent.getStringExtra("actionstring")?.let { actionString ->
|
||||
sendMessage(wearConstants.W_M_CONFIRM_ACTION, actionString.toByteArray())
|
||||
}
|
||||
}
|
||||
|
||||
ACTION_INITIATE_ACTION ->
|
||||
if (intent.hasExtra("actionstring"))
|
||||
intent.getStringExtra("actionstring")?.let { actionString ->
|
||||
sendMessage(wearConstants.W_M_INITIATE_ACTION, actionString.toByteArray())
|
||||
}
|
||||
else if (intent.hasExtra(KEY_ACTION_DATA))
|
||||
intent.getStringExtra(KEY_ACTION_DATA)?.let { actionData ->
|
||||
sendMessage(wearConstants.W_M_INITIATE_ACTION, actionData.toByteArray())
|
||||
}
|
||||
}
|
||||
return START_STICKY
|
||||
}
|
||||
|
||||
private var transcriptionNodeId: String? = null
|
||||
|
||||
private fun updateTranscriptionCapability() {
|
||||
val capabilityInfo: CapabilityInfo = Tasks.await(
|
||||
capabilityClient.getCapability(PHONE_CAPABILITY, CapabilityClient.FILTER_REACHABLE)
|
||||
)
|
||||
aapsLogger.debug(LTag.WEAR, "Nodes: ${capabilityInfo.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}")
|
||||
transcriptionNodeId = pickBestNodeId(capabilityInfo.nodes)
|
||||
aapsLogger.debug(LTag.WEAR, "Selected node: $transcriptionNodeId")
|
||||
}
|
||||
|
||||
// Find a nearby node or pick one arbitrarily
|
||||
private fun pickBestNodeId(nodes: Set<Node>): String? =
|
||||
nodes.firstOrNull { it.isNearby }?.id ?: nodes.firstOrNull()?.id
|
||||
|
||||
private fun sendData(path: String, vararg params: DataMap) {
|
||||
scope.launch {
|
||||
try {
|
||||
for (dm in params) {
|
||||
val request = PutDataMapRequest.create(path).apply {
|
||||
dataMap.putAll(dm)
|
||||
}
|
||||
.asPutDataRequest()
|
||||
.setUrgent()
|
||||
|
||||
val result = dataClient.putDataItem(request).await()
|
||||
aapsLogger.debug(LTag.WEAR, "sendData: ${result.uri} ${params.joinToString()}")
|
||||
}
|
||||
} catch (cancellationException: CancellationException) {
|
||||
throw cancellationException
|
||||
} catch (exception: Exception) {
|
||||
aapsLogger.error(LTag.WEAR, "DataItem failed: $exception")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendMessage(path: String, data: ByteArray) {
|
||||
aapsLogger.debug(LTag.WEAR, "sendMessage: $path")
|
||||
transcriptionNodeId?.also { nodeId ->
|
||||
messageClient
|
||||
.sendMessage(nodeId, path, data).apply {
|
||||
addOnSuccessListener { }
|
||||
addOnFailureListener {
|
||||
aapsLogger.debug(LTag.WEAR, "sendMessage: $path failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTiles() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(ActionsTileService::class.java)
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(TempTargetTileService::class.java)
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(QuickWizardTileService::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
private fun notifyChangeRequest(title: String, message: String, actionstring: String) {
|
||||
// Create the NotificationChannel, but only on API 26+ because
|
||||
// the NotificationChannel class is new and not in the support library
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val name: CharSequence = "AAPS Open Loop"
|
||||
val description = "Open Loop request notification"
|
||||
val channel = NotificationChannel(AAPS_NOTIFY_CHANNEL_ID_OPENLOOP, name, NotificationManager.IMPORTANCE_HIGH)
|
||||
channel.description = description
|
||||
channel.enableVibration(true)
|
||||
|
||||
// Register the channel with the system; you can't change the importance
|
||||
// or other notification behaviors after this
|
||||
val notificationManager = getSystemService(NotificationManager::class.java)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
var builder = NotificationCompat.Builder(this, AAPS_NOTIFY_CHANNEL_ID_OPENLOOP)
|
||||
builder = builder.setSmallIcon(R.drawable.notif_icon)
|
||||
.setContentTitle(title)
|
||||
.setContentText(message)
|
||||
.setPriority(Notification.PRIORITY_HIGH)
|
||||
.setVibrate(longArrayOf(1000, 1000, 1000, 1000, 1000))
|
||||
|
||||
// Creates an explicit intent for an Activity in your app
|
||||
val intent = Intent(this, AcceptActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
val params = Bundle()
|
||||
params.putString("title", title)
|
||||
params.putString("message", message)
|
||||
params.putString("actionstring", actionstring)
|
||||
intent.putExtras(params)
|
||||
val resultPendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
builder = builder.setContentIntent(resultPendingIntent)
|
||||
val mNotificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
// mId allows you to update the notification later on.
|
||||
mNotificationManager.notify(CHANGE_NOTIF_ID, builder.build())
|
||||
}
|
||||
|
||||
private fun cancelNotificationRequest() {
|
||||
(getSystemService(NOTIFICATION_SERVICE) as NotificationManager).cancel(CHANGE_NOTIF_ID)
|
||||
}
|
||||
|
||||
private fun showBolusProgress(progressPercent: Int, progresStatus: String) {
|
||||
val vibratePattern: LongArray
|
||||
val vibrate = sp.getBoolean("vibrateOnBolus", true)
|
||||
vibratePattern = if (vibrate) longArrayOf(0, 50, 1000) else longArrayOf(0, 1, 1000)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
createBolusProgressChannels()
|
||||
}
|
||||
val cancelIntent = Intent(this, DataLayerListenerService::class.java)
|
||||
cancelIntent.action = ACTION_CANCEL_BOLUS
|
||||
val cancelPendingIntent = PendingIntent.getService(this, 0, cancelIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
val notificationBuilder: NotificationCompat.Builder =
|
||||
NotificationCompat.Builder(this, if (vibrate) AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS else AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS_SILENT)
|
||||
.setSmallIcon(R.drawable.ic_icon)
|
||||
.setContentTitle(getString(R.string.bolus_progress))
|
||||
.setContentText("$progressPercent% - $progresStatus")
|
||||
.setSubText(getString(R.string.press_to_cancel))
|
||||
.setContentIntent(cancelPendingIntent)
|
||||
.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||
.setVibrate(vibratePattern)
|
||||
.addAction(R.drawable.ic_cancel, getString(R.string.cancel_bolus), cancelPendingIntent)
|
||||
val notificationManager = NotificationManagerCompat.from(this)
|
||||
notificationManager.notify(BOLUS_PROGRESS_NOTIF_ID, notificationBuilder.build())
|
||||
notificationManager.cancel(CONFIRM_NOTIF_ID) // multiple watch setup
|
||||
if (progressPercent == 100) {
|
||||
scheduleDismissBolusProgress(5)
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(value = 26) private fun createBolusProgressChannels() {
|
||||
createNotificationChannel(
|
||||
longArrayOf(0, 50, 1000),
|
||||
AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS,
|
||||
getString(R.string.bolus_progress_channel_name),
|
||||
getString(R.string.bolus_progress_channel_description)
|
||||
)
|
||||
createNotificationChannel(
|
||||
longArrayOf(0, 1, 1000),
|
||||
AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS_SILENT,
|
||||
getString(R.string.bolus_progress_silent_channel_name),
|
||||
getString(R.string.bolus_progress_silent_channel_description)
|
||||
)
|
||||
}
|
||||
|
||||
@TargetApi(value = 26) private fun createNotificationChannel(vibratePattern: LongArray, channelID: String, name: CharSequence, description: String) {
|
||||
val channel = NotificationChannel(channelID, name, NotificationManager.IMPORTANCE_HIGH)
|
||||
channel.description = description
|
||||
channel.enableVibration(true)
|
||||
channel.vibrationPattern = vibratePattern
|
||||
|
||||
// Register the channel with the system; you can't change the importance
|
||||
// or other notification behaviors after this
|
||||
val notificationManager = getSystemService(NotificationManager::class.java)
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
private fun showConfirmationDialog(title: String, message: String, actionstring: String) {
|
||||
val intent = Intent(this, AcceptActivity::class.java)
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
val params = Bundle()
|
||||
params.putString("title", title)
|
||||
params.putString("message", message)
|
||||
params.putString("actionstring", actionstring)
|
||||
intent.putExtras(params)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun scheduleDismissBolusProgress(seconds: Int) {
|
||||
Thread {
|
||||
SystemClock.sleep(seconds * 1000L)
|
||||
NotificationManagerCompat.from(this@DataLayerListenerService)
|
||||
.cancel(BOLUS_PROGRESS_NOTIF_ID)
|
||||
}.start()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val PHONE_CAPABILITY = "androidaps_mobile"
|
||||
|
||||
const val ACTION_RESEND = "com.dexdrip.stephenblack.nightwatch.RESEND_DATA"
|
||||
const val ACTION_CANCEL_BOLUS = "com.dexdrip.stephenblack.nightwatch.CANCELBOLUS"
|
||||
const val ACTION_CONFIRMATION = "com.dexdrip.stephenblack.nightwatch.CONFIRMACTION"
|
||||
const val ACTION_CONFIRM_CHANGE = "com.dexdrip.stephenblack.nightwatch.CONFIRMCHANGE"
|
||||
val ACTION_INITIATE_ACTION = DataLayerListenerService::class.java.name + ".INITIATE_ACTION"
|
||||
|
||||
const val BOLUS_PROGRESS_NOTIF_ID = 1
|
||||
const val CONFIRM_NOTIF_ID = 2
|
||||
const val CHANGE_NOTIF_ID = 556677
|
||||
|
||||
const val AAPS_NOTIFY_CHANNEL_ID_OPENLOOP = "AndroidAPS-OpenLoop"
|
||||
const val AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS = "bolus progress vibration"
|
||||
const val AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS_SILENT = "bolus progress silent"
|
||||
|
||||
fun initiateAction(context: Context, actionstring: String) {
|
||||
context.startService(
|
||||
Intent(context, DataLayerListenerService::class.java).also {
|
||||
it.putExtra("actionstring", actionstring)
|
||||
it.action = ACTION_INITIATE_ACTION
|
||||
})
|
||||
}
|
||||
|
||||
fun requestData(context: Context) {
|
||||
context.startService(
|
||||
Intent(context, DataLayerListenerService::class.java).also { it.action = ACTION_RESEND })
|
||||
}
|
||||
|
||||
fun confirmAction(context: Context, actionstring: String) {
|
||||
context.startService(
|
||||
Intent(context, DataLayerListenerService::class.java).also {
|
||||
it.putExtra("actionstring", actionstring)
|
||||
if (actionstring == "changeRequest") it.action = ACTION_CONFIRM_CHANGE
|
||||
else it.action = ACTION_CONFIRMATION
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,281 +0,0 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.PowerManager;
|
||||
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import info.nightscout.androidaps.interaction.utils.Constants;
|
||||
import info.nightscout.androidaps.interaction.utils.Persistence;
|
||||
import info.nightscout.androidaps.interaction.utils.WearUtil;
|
||||
|
||||
/**
|
||||
* Holds bunch of data model variables and lists that arrive from phone app and are due to be
|
||||
* displayed on watchface and complications. Keeping them together makes code cleaner and allows
|
||||
* passing it to complications via persistence layer.
|
||||
*
|
||||
* Created by dlvoy on 2019-11-12
|
||||
*/
|
||||
public class RawDisplayData {
|
||||
|
||||
private final WearUtil wearUtil;
|
||||
|
||||
public RawDisplayData(WearUtil wearUtil) {
|
||||
this.wearUtil = wearUtil;
|
||||
}
|
||||
|
||||
static final String DATA_PERSISTENCE_KEY = "raw_data";
|
||||
static final String BASALS_PERSISTENCE_KEY = "raw_basals";
|
||||
static final String STATUS_PERSISTENCE_KEY = "raw_status";
|
||||
|
||||
// data bundle
|
||||
public long sgvLevel = 0;
|
||||
public long datetime;
|
||||
public String sSgv = "---";
|
||||
public String sDirection = "--";
|
||||
public String sDelta = "--";
|
||||
public String sAvgDelta = "--";
|
||||
public String sUnits = "-";
|
||||
|
||||
// status bundle
|
||||
public String sBasalRate = "-.--U/h";
|
||||
public String sUploaderBattery = "--";
|
||||
public String sRigBattery = "--";
|
||||
public boolean detailedIOB = false;
|
||||
public String sIOB1 = "IOB";
|
||||
public String sIOB2 = "-.--";
|
||||
public String sCOB1 = "Carb";
|
||||
public String sCOB2= "--g";
|
||||
public String sBgi = "--";
|
||||
public boolean showBGI = false;
|
||||
public String externalStatusString = "no status";
|
||||
public int batteryLevel = 1;
|
||||
public long openApsStatus = -1;
|
||||
|
||||
// basals bundle
|
||||
public ArrayList<BgWatchData> bgDataList = new ArrayList<>();
|
||||
public ArrayList<TempWatchData> tempWatchDataList = new ArrayList<>();
|
||||
public ArrayList<BasalWatchData> basalWatchDataList = new ArrayList<>();
|
||||
public ArrayList<BolusWatchData> bolusWatchDataList = new ArrayList<>();
|
||||
public ArrayList<BgWatchData> predictionList = new ArrayList<>();
|
||||
|
||||
public String toDebugString() {
|
||||
return "DisplayRawData{" +
|
||||
"sgvLevel=" + sgvLevel +
|
||||
", datetime=" + datetime +
|
||||
", sSgv='" + sSgv + '\'' +
|
||||
", sDirection='" + sDirection + '\'' +
|
||||
", sDelta='" + sDelta + '\'' +
|
||||
", sAvgDelta='" + sAvgDelta + '\'' +
|
||||
", sUnits='" + sUnits + '\'' +
|
||||
", sBasalRate='" + sBasalRate + '\'' +
|
||||
", sUploaderBattery='" + sUploaderBattery + '\'' +
|
||||
", sRigBattery='" + sRigBattery + '\'' +
|
||||
", detailedIOB=" + detailedIOB +
|
||||
", sIOB1='" + sIOB1 + '\'' +
|
||||
", sIOB2='" + sIOB2 + '\'' +
|
||||
", sCOB1='" + sCOB1 + '\'' +
|
||||
", sCOB2='" + sCOB2 + '\'' +
|
||||
", sBgi='" + sBgi + '\'' +
|
||||
", showBGI=" + showBGI +
|
||||
", externalStatusString='" + externalStatusString + '\'' +
|
||||
", batteryLevel=" + batteryLevel +
|
||||
", openApsStatus=" + openApsStatus +
|
||||
", bgDataList size=" + bgDataList.size() +
|
||||
", tempWatchDataList size=" + tempWatchDataList.size() +
|
||||
", basalWatchDataList size=" + basalWatchDataList.size() +
|
||||
", bolusWatchDataLis size=" + bolusWatchDataList.size() +
|
||||
", predictionList size=" + predictionList.size() +
|
||||
'}';
|
||||
}
|
||||
|
||||
public void updateFromPersistence(Persistence persistence) {
|
||||
|
||||
DataMap dataMapData = persistence.getDataMap(DATA_PERSISTENCE_KEY);
|
||||
if (dataMapData != null) {
|
||||
updateData(dataMapData);
|
||||
}
|
||||
DataMap dataMapStatus = persistence.getDataMap(STATUS_PERSISTENCE_KEY);
|
||||
if (dataMapStatus != null) {
|
||||
updateStatus(dataMapStatus);
|
||||
}
|
||||
DataMap dataMapBasals = persistence.getDataMap(BASALS_PERSISTENCE_KEY);
|
||||
if (dataMapBasals != null) {
|
||||
updateBasals(dataMapBasals);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Since complications do not need Basals, we skip them for performance
|
||||
*/
|
||||
public void updateForComplicationsFromPersistence(Persistence persistence) {
|
||||
|
||||
DataMap dataMapData = persistence.getDataMap(DATA_PERSISTENCE_KEY);
|
||||
if (dataMapData != null) {
|
||||
updateData(dataMapData);
|
||||
}
|
||||
DataMap dataMapStatus = persistence.getDataMap(STATUS_PERSISTENCE_KEY);
|
||||
if (dataMapStatus != null) {
|
||||
updateStatus(dataMapStatus);
|
||||
}
|
||||
}
|
||||
|
||||
public DataMap updateDataFromMessage(Intent intent, PowerManager.WakeLock wakeLock) {
|
||||
Bundle bundle = intent.getBundleExtra("data");
|
||||
if (bundle != null) {
|
||||
DataMap dataMap = wearUtil.bundleToDataMap(bundle);
|
||||
updateData(dataMap);
|
||||
return dataMap;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void updateData(DataMap dataMap) {
|
||||
PowerManager.WakeLock wl = wearUtil.getWakeLock("readingPrefs", 50);
|
||||
sgvLevel = dataMap.getLong("sgvLevel");
|
||||
datetime = dataMap.getLong("timestamp");
|
||||
sSgv = dataMap.getString("sgvString");
|
||||
sDirection = dataMap.getString("slopeArrow");
|
||||
sDelta = dataMap.getString("delta");
|
||||
sAvgDelta = dataMap.getString("avgDelta");
|
||||
sUnits = dataMap.getString("glucoseUnits");
|
||||
wearUtil.releaseWakeLock(wl);
|
||||
}
|
||||
|
||||
public DataMap updateStatusFromMessage(Intent intent, PowerManager.WakeLock wakeLock) {
|
||||
Bundle bundle = intent.getBundleExtra("status");
|
||||
if (bundle != null) {
|
||||
DataMap dataMap = wearUtil.bundleToDataMap(bundle);
|
||||
updateStatus(dataMap);
|
||||
return dataMap;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void updateStatus(DataMap dataMap) {
|
||||
PowerManager.WakeLock wl = wearUtil.getWakeLock("readingPrefs", 50);
|
||||
sBasalRate = dataMap.getString("currentBasal");
|
||||
sUploaderBattery = dataMap.getString("battery");
|
||||
sRigBattery = dataMap.getString("rigBattery");
|
||||
detailedIOB = dataMap.getBoolean("detailedIob");
|
||||
sIOB1 = dataMap.getString("iobSum") + "U";
|
||||
sIOB2 = dataMap.getString("iobDetail");
|
||||
sCOB1 = "Carb";
|
||||
sCOB2 = dataMap.getString("cob");
|
||||
sBgi = dataMap.getString("bgi");
|
||||
showBGI = dataMap.getBoolean("showBgi");
|
||||
externalStatusString = dataMap.getString("externalStatusString");
|
||||
batteryLevel = dataMap.getInt("batteryLevel");
|
||||
openApsStatus = dataMap.getLong("openApsStatus");
|
||||
wearUtil.releaseWakeLock(wl);
|
||||
}
|
||||
|
||||
public DataMap updateBasalsFromMessage(Intent intent) {
|
||||
Bundle bundle = intent.getBundleExtra("basals");
|
||||
if (bundle != null) {
|
||||
DataMap dataMap = wearUtil.bundleToDataMap(bundle);
|
||||
updateBasals(dataMap);
|
||||
return dataMap;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void updateBasals(DataMap dataMap) {
|
||||
PowerManager.WakeLock wl = wearUtil.getWakeLock("readingPrefs", 500);
|
||||
loadBasalsAndTemps(dataMap);
|
||||
wearUtil.releaseWakeLock(wl);
|
||||
}
|
||||
|
||||
private void loadBasalsAndTemps(DataMap dataMap) {
|
||||
ArrayList<DataMap> 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<DataMap> basals = dataMap.getDataMapArrayList("basals");
|
||||
if (basals != null) {
|
||||
basalWatchDataList = new ArrayList<>();
|
||||
for (DataMap basal : basals) {
|
||||
BasalWatchData bwd = new BasalWatchData();
|
||||
bwd.startTime = basal.getLong("starttime");
|
||||
bwd.endTime = basal.getLong("endtime");
|
||||
bwd.amount = basal.getDouble("amount");
|
||||
basalWatchDataList.add(bwd);
|
||||
}
|
||||
}
|
||||
ArrayList<DataMap> boluses = dataMap.getDataMapArrayList("boluses");
|
||||
if (boluses != null) {
|
||||
bolusWatchDataList = new ArrayList<>();
|
||||
for (DataMap bolus : boluses) {
|
||||
BolusWatchData bwd = new BolusWatchData();
|
||||
bwd.date = bolus.getLong("date");
|
||||
bwd.bolus = bolus.getDouble("bolus");
|
||||
bwd.carbs = bolus.getDouble("carbs");
|
||||
bwd.isSMB = bolus.getBoolean("isSMB");
|
||||
bwd.isValid = bolus.getBoolean("isValid");
|
||||
bolusWatchDataList.add(bwd);
|
||||
}
|
||||
}
|
||||
ArrayList<DataMap> predictions = dataMap.getDataMapArrayList("predictions");
|
||||
if (boluses != null) {
|
||||
predictionList = new ArrayList<>();
|
||||
for (DataMap prediction : predictions) {
|
||||
BgWatchData bwd = new BgWatchData();
|
||||
bwd.timestamp = prediction.getLong("timestamp");
|
||||
bwd.sgv = prediction.getDouble("sgv");
|
||||
bwd.color = prediction.getInt("color");
|
||||
predictionList.add(bwd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addToWatchSet(DataMap dataMap) {
|
||||
ArrayList<DataMap> entries = dataMap.getDataMapArrayList("entries");
|
||||
if (entries != null) {
|
||||
bgDataList = new ArrayList<>();
|
||||
for (DataMap entry : entries) {
|
||||
double sgv = entry.getDouble("sgvDouble");
|
||||
double high = entry.getDouble("high");
|
||||
double low = entry.getDouble("low");
|
||||
long timestamp = entry.getLong("timestamp");
|
||||
int color = entry.getInt("color", 0);
|
||||
bgDataList.add(new BgWatchData(sgv, high, low, timestamp, color));
|
||||
}
|
||||
} else {
|
||||
double sgv = dataMap.getDouble("sgvDouble");
|
||||
double high = dataMap.getDouble("high");
|
||||
double low = dataMap.getDouble("low");
|
||||
long timestamp = dataMap.getLong("timestamp");
|
||||
int color = dataMap.getInt("color", 0);
|
||||
|
||||
final int size = bgDataList.size();
|
||||
if (size > 0) {
|
||||
if (bgDataList.get(size - 1).timestamp == timestamp)
|
||||
return; // Ignore duplicates.
|
||||
}
|
||||
|
||||
bgDataList.add(new BgWatchData(sgv, high, low, timestamp, color));
|
||||
}
|
||||
|
||||
// We use iterator instead for-loop because we iterate and remove on the go
|
||||
Iterator itr = bgDataList.iterator();
|
||||
while (itr.hasNext()) {
|
||||
BgWatchData entry = (BgWatchData)itr.next();
|
||||
if (entry.timestamp < (wearUtil.timestamp() - (Constants.HOUR_IN_MS * 5))) {
|
||||
itr.remove(); //Get rid of anything more than 5 hours old
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
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
|
||||
|
||||
/**
|
||||
* Holds bunch of data model variables and lists that arrive from phone app and are due to be
|
||||
* displayed on watchface and complications. Keeping them together makes code cleaner and allows
|
||||
* passing it to complications via persistence layer.
|
||||
*
|
||||
* Created by dlvoy on 2019-11-12
|
||||
*/
|
||||
class RawDisplayData {
|
||||
|
||||
// bg data bundle
|
||||
var singleBg = EventData.SingleBg(
|
||||
timeStamp = 0,
|
||||
sgv = 0.0,
|
||||
high = 0.0,
|
||||
low = 0.0,
|
||||
color = 0
|
||||
)
|
||||
|
||||
// status bundle
|
||||
var status = EventData.Status(
|
||||
externalStatus = "no status",
|
||||
iobSum = "IOB",
|
||||
iobDetail = "-.--",
|
||||
detailedIob = false,
|
||||
cob = "--g",
|
||||
currentBasal = "-.--U/h",
|
||||
battery = "--",
|
||||
rigBattery = "--",
|
||||
openApsStatus = -1,
|
||||
bgi = "--",
|
||||
showBgi = false,
|
||||
batteryLevel = 1
|
||||
)
|
||||
|
||||
// basals bundle
|
||||
var graphData = EventData.GraphData(
|
||||
entries = ArrayList<EventData.SingleBg>()
|
||||
)
|
||||
|
||||
var treatmentData = EventData.TreatmentData(
|
||||
temps = ArrayList<EventData.TreatmentData.TempBasal>(),
|
||||
basals = ArrayList<EventData.TreatmentData.Basal>(),
|
||||
boluses = ArrayList<EventData.TreatmentData.Treatment>(),
|
||||
predictions = ArrayList<EventData.SingleBg>()
|
||||
)
|
||||
|
||||
fun toDebugString(): String =
|
||||
"DisplayRawData{singleBg=$singleBg, status=$status, graphData=$graphData, treatmentData=$treatmentData}"
|
||||
|
||||
fun updateFromPersistence(persistence: Persistence) {
|
||||
persistence.readSingleBg()?.let { singleBg = it }
|
||||
persistence.readGraphData()?.let { graphData = it }
|
||||
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"
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
/**
|
||||
* Created by adrian on 17/11/16.
|
||||
*/
|
||||
|
||||
public class TempWatchData {
|
||||
public long startTime;
|
||||
public double startBasal;
|
||||
public long endTime;
|
||||
public double endBasal;
|
||||
public double amount;
|
||||
}
|
|
@ -3,6 +3,10 @@ package info.nightscout.androidaps.di
|
|||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import info.nightscout.androidaps.interaction.actions.*
|
||||
import info.nightscout.androidaps.interaction.menus.FillMenuActivity
|
||||
import info.nightscout.androidaps.interaction.menus.MainMenuActivity
|
||||
import info.nightscout.androidaps.interaction.menus.StatusMenuActivity
|
||||
import info.nightscout.androidaps.interaction.utils.MenuListActivity
|
||||
|
||||
@Module
|
||||
@Suppress("unused")
|
||||
|
@ -20,4 +24,9 @@ abstract class WearActivitiesModule {
|
|||
@ContributesAndroidInjector abstract fun contributesTempTargetActivity(): TempTargetActivity
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentActivity(): TreatmentActivity
|
||||
@ContributesAndroidInjector abstract fun contributesWizardActivity(): WizardActivity
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesMenuListActivity(): MenuListActivity
|
||||
@ContributesAndroidInjector abstract fun contributesFillMenuActivity(): FillMenuActivity
|
||||
@ContributesAndroidInjector abstract fun contributesMainMenuActivity(): MainMenuActivity
|
||||
@ContributesAndroidInjector abstract fun contributesStatusMenuActivity(): StatusMenuActivity
|
||||
}
|
|
@ -2,16 +2,18 @@ package info.nightscout.androidaps.di
|
|||
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import info.nightscout.androidaps.comm.DataLayerListenerServiceWear
|
||||
import info.nightscout.androidaps.complications.*
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService
|
||||
import info.nightscout.androidaps.interaction.actions.BackgroundActionActivity
|
||||
import info.nightscout.androidaps.tile.QuickWizardTileService
|
||||
import info.nightscout.androidaps.tile.TempTargetTileService
|
||||
import info.nightscout.androidaps.tile.TileBase
|
||||
import info.nightscout.androidaps.watchfaces.*
|
||||
|
||||
@Module
|
||||
@Suppress("unused")
|
||||
abstract class WearServicesModule {
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesDataLayerListenerService(): DataLayerListenerService
|
||||
@ContributesAndroidInjector abstract fun contributesDataLayerListenerService(): DataLayerListenerServiceWear
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesBaseComplicationProviderService(): BaseComplicationProviderService
|
||||
@ContributesAndroidInjector abstract fun contributesBrCobIobComplication(): BrCobIobComplication
|
||||
|
@ -24,7 +26,7 @@ abstract class WearServicesModule {
|
|||
@ContributesAndroidInjector abstract fun contributesLongStatusComplication(): LongStatusComplication
|
||||
@ContributesAndroidInjector abstract fun contributesLongStatusFlippedComplication(): LongStatusFlippedComplication
|
||||
@ContributesAndroidInjector abstract fun contributesSgvComplication(): SgvComplication
|
||||
@ContributesAndroidInjector abstract fun contributesUploaderBattery(): UploaderBattery
|
||||
@ContributesAndroidInjector abstract fun contributesUploaderBatteryComplication(): UploaderBatteryComplication
|
||||
@ContributesAndroidInjector abstract fun contributesWallpaperComplication(): WallpaperComplication
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesBaseWatchFace(): BaseWatchFace
|
||||
|
@ -34,4 +36,12 @@ abstract class WearServicesModule {
|
|||
@ContributesAndroidInjector abstract fun contributesSteampunk(): Steampunk
|
||||
@ContributesAndroidInjector abstract fun contributesDigitalStyle(): DigitalStyle
|
||||
@ContributesAndroidInjector abstract fun contributesCockpit(): Cockpit
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesBIGChart(): BIGChart
|
||||
@ContributesAndroidInjector abstract fun contributesNOChart(): NOChart
|
||||
@ContributesAndroidInjector abstract fun contributesCircleWatchface(): CircleWatchface
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesTileBase(): TileBase
|
||||
@ContributesAndroidInjector abstract fun contributesQuickWizardTileService(): QuickWizardTileService
|
||||
@ContributesAndroidInjector abstract fun contributesTempTargetTileService(): TempTargetTileService
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
import android.content.Context
|
||||
|
||||
@Suppress("unused")
|
||||
class EventWearPreferenceChange : Event {
|
||||
|
||||
var changedKey: String? = null
|
||||
private set
|
||||
|
||||
constructor(key: String) {
|
||||
changedKey = key
|
||||
}
|
||||
|
||||
constructor(context: Context, resourceID: Int) {
|
||||
changedKey = context.getString(resourceID)
|
||||
}
|
||||
|
||||
fun isChanged(context: Context, id: Int): Boolean {
|
||||
return changedKey == context.getString(id)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import static info.nightscout.shared.weardata.WearConstants.KEY_ACTION_DATA;
|
||||
import static info.nightscout.androidaps.comm.DataLayerListenerServiceWear.KEY_ACTION_DATA;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -21,10 +21,8 @@ import androidx.core.view.MotionEventCompat;
|
|||
import androidx.core.view.ViewConfigurationCompat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.events.EventWearToMobileChange;
|
||||
import info.nightscout.androidaps.events.EventWearToMobileConfirm;
|
||||
import info.nightscout.shared.weardata.ActionData;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.shared.weardata.EventData;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
|
@ -33,7 +31,6 @@ import info.nightscout.shared.weardata.ActionData;
|
|||
public class AcceptActivity extends ViewSelectorActivity {
|
||||
|
||||
String message = "";
|
||||
String actionstring = "";
|
||||
String actionKey = "";
|
||||
private DismissThread dismissThread;
|
||||
|
||||
|
@ -46,10 +43,9 @@ public class AcceptActivity extends ViewSelectorActivity {
|
|||
|
||||
Bundle extras = getIntent().getExtras();
|
||||
message = extras.getString("message", "");
|
||||
actionstring = extras.getString("actionstring", "");
|
||||
actionKey = extras.getString(KEY_ACTION_DATA, "");
|
||||
|
||||
if (message.isEmpty() || (actionstring.isEmpty() && actionKey.isEmpty())) {
|
||||
if (message.isEmpty() || actionKey.isEmpty()) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
@ -109,15 +105,9 @@ public class AcceptActivity extends ViewSelectorActivity {
|
|||
view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmButton = view.findViewById(R.id.confirmbutton);
|
||||
confirmButton.setOnClickListener((View v) -> {
|
||||
if (!actionstring.isEmpty())
|
||||
DataLayerListenerService.Companion.confirmAction(AcceptActivity.this, actionstring);
|
||||
else {
|
||||
ActionData actionData = ActionData.Companion.deserialize(actionKey);
|
||||
if (actionData instanceof ActionData.ConfirmAction)
|
||||
rxBus.send(new EventWearToMobileConfirm(actionData));
|
||||
if (actionData instanceof ActionData.ChangeAction)
|
||||
rxBus.send(new EventWearToMobileChange(actionData));
|
||||
}
|
||||
EventData returnCommand = EventData.Companion.deserialize(actionKey);
|
||||
rxBus.send(new EventWearToMobile(returnCommand));
|
||||
rxBus.send(new EventData.CancelNotification(System.currentTimeMillis()));
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
|
|
|
@ -3,21 +3,25 @@ package info.nightscout.androidaps.interaction.actions
|
|||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import dagger.android.DaggerActivity
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService
|
||||
import info.nightscout.androidaps.comm.DataLayerListenerServiceWear
|
||||
import info.nightscout.androidaps.events.EventWearToMobile
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.weardata.EventData
|
||||
import javax.inject.Inject
|
||||
|
||||
class BackgroundActionActivity : DaggerActivity() {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
intent.extras?.getString("actionString")?.let { actionString ->
|
||||
aapsLogger.info(LTag.WEAR, "QuickWizardActivity.onCreate: actionString=$actionString")
|
||||
DataLayerListenerService.initiateAction(this, actionString)
|
||||
intent.extras?.getString("message")?.let { message ->
|
||||
intent.extras?.getString(DataLayerListenerServiceWear.KEY_ACTION)?.let { action ->
|
||||
aapsLogger.info(LTag.WEAR, "QuickWizardActivity.onCreate: action=$action")
|
||||
rxBus.send(EventWearToMobile(EventData.deserialize(action)))
|
||||
intent.extras?.getString(DataLayerListenerServiceWear.KEY_MESSAGE)?.let { message ->
|
||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
} ?: aapsLogger.error(LTag.WEAR, "BackgroundActionActivity.onCreate extras 'actionString' required")
|
||||
|
|
|
@ -10,10 +10,10 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.events.EventWearToMobileAction;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.ActionData;
|
||||
import info.nightscout.shared.weardata.EventData;
|
||||
|
||||
public class BolusActivity extends ViewSelectorActivity {
|
||||
|
||||
|
@ -63,8 +63,7 @@ public class BolusActivity extends ViewSelectorActivity {
|
|||
view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmButton = view.findViewById(R.id.confirmbutton);
|
||||
confirmButton.setOnClickListener((View v) -> {
|
||||
ActionData.Bolus bolus = new ActionData.Bolus(SafeParse.stringToDouble(editInsulin.editText.getText().toString()), 0);
|
||||
rxBus.send(new EventWearToMobileAction(bolus));
|
||||
rxBus.send(new EventWearToMobile(new EventData.ActionBolusPreCheck(SafeParse.stringToDouble(editInsulin.editText.getText().toString()), 0)));
|
||||
showToast(BolusActivity.this, R.string.action_bolus_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
|
|
|
@ -10,11 +10,10 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.events.EventWearToMobileAction;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.ActionData;
|
||||
import info.nightscout.shared.weardata.EventData;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
|
@ -52,6 +51,7 @@ public class CPPActivity extends ViewSelectorActivity {
|
|||
finish();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private class MyGridViewPagerAdapter extends GridPagerAdapter {
|
||||
@Override
|
||||
public int getColumnCount(int arg0) {
|
||||
|
@ -94,9 +94,9 @@ public class CPPActivity extends ViewSelectorActivity {
|
|||
confirmButton.setOnClickListener((View v) -> {
|
||||
//check if it can happen that the fragment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
ActionData.ProfileSwitch ps =
|
||||
new ActionData.ProfileSwitch(SafeParse.stringToInt(editTimeshift.editText.getText().toString()), SafeParse.stringToInt(editPercentage.editText.getText().toString()));
|
||||
rxBus.send(new EventWearToMobileAction(ps));
|
||||
EventData.ActionProfileSwitchPreCheck ps =
|
||||
new EventData.ActionProfileSwitchPreCheck(SafeParse.stringToInt(editTimeshift.editText.getText().toString()), SafeParse.stringToInt(editPercentage.editText.getText().toString()));
|
||||
rxBus.send(new EventWearToMobile(ps));
|
||||
showToast(CPPActivity.this, R.string.action_cpp_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
|
@ -108,7 +108,7 @@ public class CPPActivity extends ViewSelectorActivity {
|
|||
@Override
|
||||
public void destroyItem(ViewGroup container, int row, int col, Object view) {
|
||||
// Handle this to get the data before the view is destroyed?
|
||||
// Object should still be kept by this, just setup for reinit?
|
||||
// Object should still be kept by this, just setup for re-init?
|
||||
container.removeView((View) view);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.EventData;
|
||||
|
||||
public class CarbActivity extends ViewSelectorActivity {
|
||||
|
||||
|
@ -32,6 +33,7 @@ public class CarbActivity extends ViewSelectorActivity {
|
|||
finish();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private class MyGridViewPagerAdapter extends GridPagerAdapter {
|
||||
@Override
|
||||
public int getColumnCount(int arg0) {
|
||||
|
@ -46,37 +48,42 @@ public class CarbActivity extends ViewSelectorActivity {
|
|||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int row, int col) {
|
||||
|
||||
final View view;
|
||||
if (col == 0) {
|
||||
final View view = getInflatedPlusMinusView(container);
|
||||
view = getInflatedPlusMinusView(container);
|
||||
double def = 0;
|
||||
if (editCarbs != null) {
|
||||
def = SafeParse.stringToDouble(editCarbs.editText.getText().toString());
|
||||
}
|
||||
editCarbs = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, (double)maxCarbs, 1d, new DecimalFormat("0"), true);
|
||||
editCarbs = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, (double) maxCarbs, 1d, new DecimalFormat("0"), true);
|
||||
setLabelToPlusMinusView(view, getString(R.string.action_carbs));
|
||||
container.addView(view);
|
||||
view.requestFocus();
|
||||
return view;
|
||||
} else {
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmButton = view.findViewById(R.id.confirmbutton);
|
||||
confirmButton.setOnClickListener((View v) -> {
|
||||
// With start time 0 and duration 0
|
||||
String actionstring = "ecarbs " + SafeParse.stringToInt(editCarbs.editText.getText().toString()) + " 0 0";
|
||||
DataLayerListenerService.Companion.initiateAction(CarbActivity.this, actionstring);
|
||||
EventData.ActionECarbsPreCheck bolus =
|
||||
new EventData.ActionECarbsPreCheck(
|
||||
SafeParse.stringToInt(editCarbs.editText.getText().toString()),
|
||||
0,
|
||||
0
|
||||
);
|
||||
rxBus.send(new EventWearToMobile(bolus));
|
||||
showToast(CarbActivity.this, R.string.action_ecarb_confirmation);
|
||||
finishAffinity();
|
||||
|
||||
});
|
||||
container.addView(view);
|
||||
return view;
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyItem(ViewGroup container, int row, int col, Object view) {
|
||||
// Handle this to get the data before the view is destroyed?
|
||||
// Object should still be kept by this, just setup for reinit?
|
||||
// Object should still be kept by this, just setup for re-init?
|
||||
container.removeView((View) view);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.EventData;
|
||||
|
||||
/**
|
||||
* Created by adrian on 04/08/18.
|
||||
|
@ -38,6 +39,7 @@ public class ECarbActivity extends ViewSelectorActivity {
|
|||
finish();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private class MyGridViewPagerAdapter extends GridPagerAdapter {
|
||||
@Override
|
||||
public int getColumnCount(int arg0) {
|
||||
|
@ -86,16 +88,19 @@ public class ECarbActivity extends ViewSelectorActivity {
|
|||
} else {
|
||||
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
final ImageView confirmButton = view.findViewById(R.id.confirmbutton);
|
||||
confirmButton.setOnClickListener((View v) -> {
|
||||
|
||||
//check if it can happen that the fragment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
|
||||
String actionstring = "ecarbs " + SafeParse.stringToInt(editCarbs.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToInt(editStartTime.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToInt(editDuration.editText.getText().toString());
|
||||
DataLayerListenerService.Companion.initiateAction(ECarbActivity.this, actionstring);
|
||||
EventData.ActionECarbsPreCheck bolus =
|
||||
new EventData.ActionECarbsPreCheck(
|
||||
SafeParse.stringToInt(editCarbs.editText.getText().toString()),
|
||||
SafeParse.stringToInt(editStartTime.editText.getText().toString()),
|
||||
SafeParse.stringToInt(editDuration.editText.getText().toString())
|
||||
);
|
||||
rxBus.send(new EventWearToMobile(bolus));
|
||||
showToast(ECarbActivity.this, R.string.action_ecarb_confirmation);
|
||||
finishAffinity();
|
||||
|
||||
|
@ -108,7 +113,7 @@ public class ECarbActivity extends ViewSelectorActivity {
|
|||
@Override
|
||||
public void destroyItem(ViewGroup container, int row, int col, Object view) {
|
||||
// Handle this to get the data before the view is destroyed?
|
||||
// Object should still be kept by this, just setup for reinit?
|
||||
// Object should still be kept by this, just setup for re-init?
|
||||
container.removeView((View) view);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.EventData;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
|
@ -34,6 +35,7 @@ public class FillActivity extends ViewSelectorActivity {
|
|||
finish();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private class MyGridViewPagerAdapter extends GridPagerAdapter {
|
||||
@Override
|
||||
public int getColumnCount(int arg0) {
|
||||
|
@ -67,8 +69,7 @@ public class FillActivity extends ViewSelectorActivity {
|
|||
//check if it can happen that the fagment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
|
||||
String actionstring = "fill " + SafeParse.stringToDouble(editInsulin.editText.getText().toString());
|
||||
DataLayerListenerService.Companion.initiateAction(FillActivity.this, actionstring);
|
||||
rxBus.send(new EventWearToMobile(new EventData.ActionFillPreCheck(SafeParse.stringToDouble(editInsulin.editText.getText().toString()))));
|
||||
showToast(FillActivity.this, R.string.action_fill_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
|
|
|
@ -10,9 +10,10 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.EventData;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
|
@ -42,6 +43,7 @@ public class TempTargetActivity extends ViewSelectorActivity {
|
|||
finish();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private class MyGridViewPagerAdapter extends GridPagerAdapter {
|
||||
@Override
|
||||
public int getColumnCount(int arg0) {
|
||||
|
@ -112,18 +114,20 @@ public class TempTargetActivity extends ViewSelectorActivity {
|
|||
} else {
|
||||
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
//check if it can happen that the fagment is never created that hold data?
|
||||
final ImageView confirmButton = view.findViewById(R.id.confirmbutton);
|
||||
confirmButton.setOnClickListener((View v) -> {
|
||||
//check if it can happen that the fragment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
|
||||
String actionstring = "temptarget"
|
||||
+ " " + isMGDL
|
||||
+ " " + SafeParse.stringToInt(time.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToDouble(lowRange.editText.getText().toString())
|
||||
+ " " + (isSingleTarget ? SafeParse.stringToDouble(lowRange.editText.getText().toString()) : SafeParse.stringToDouble(highRange.editText.getText().toString()));
|
||||
|
||||
DataLayerListenerService.Companion.initiateAction(TempTargetActivity.this, actionstring);
|
||||
EventData.ActionTempTargetPreCheck action = new EventData.ActionTempTargetPreCheck(
|
||||
EventData.ActionTempTargetPreCheck.TempTargetCommand.MANUAL,
|
||||
isMGDL,
|
||||
SafeParse.stringToInt(time.editText.getText().toString()),
|
||||
SafeParse.stringToDouble(lowRange.editText.getText().toString()),
|
||||
(isSingleTarget ?
|
||||
SafeParse.stringToDouble(lowRange.editText.getText().toString()) : SafeParse.stringToDouble(highRange.editText.getText().toString()))
|
||||
);
|
||||
rxBus.send(new EventWearToMobile(action));
|
||||
showToast(TempTargetActivity.this, R.string.action_tempt_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
|
@ -135,7 +139,7 @@ public class TempTargetActivity extends ViewSelectorActivity {
|
|||
@Override
|
||||
public void destroyItem(ViewGroup container, int row, int col, Object view) {
|
||||
// Handle this to get the data before the view is destroyed?
|
||||
// Object should still be kept by this, just setup for reinit?
|
||||
// Object should still be kept by this, just setup for re-init?
|
||||
container.removeView((View) view);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,11 +10,10 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.events.EventWearToMobileAction;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.ActionData;
|
||||
import info.nightscout.shared.weardata.EventData;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
|
@ -42,6 +41,7 @@ public class TreatmentActivity extends ViewSelectorActivity {
|
|||
}
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private class MyGridViewPagerAdapter extends GridPagerAdapter {
|
||||
@Override
|
||||
public int getColumnCount(int arg0) {
|
||||
|
@ -80,12 +80,12 @@ public class TreatmentActivity extends ViewSelectorActivity {
|
|||
} else {
|
||||
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
final ImageView confirmButton = view.findViewById(R.id.confirmbutton);
|
||||
confirmButton.setOnClickListener((View v) -> {
|
||||
//check if it can happen that the fragment is never created that hold data?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
ActionData.Bolus bolus = new ActionData.Bolus(SafeParse.stringToDouble(editInsulin.editText.getText().toString()), SafeParse.stringToInt(editCarbs.editText.getText().toString()));
|
||||
rxBus.send(new EventWearToMobileAction(bolus));
|
||||
EventData.ActionBolusPreCheck bolus = new EventData.ActionBolusPreCheck(SafeParse.stringToDouble(editInsulin.editText.getText().toString()), SafeParse.stringToInt(editCarbs.editText.getText().toString()));
|
||||
rxBus.send(new EventWearToMobile(bolus));
|
||||
showToast(TreatmentActivity.this, R.string.action_treatment_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
|
@ -97,7 +97,7 @@ public class TreatmentActivity extends ViewSelectorActivity {
|
|||
@Override
|
||||
public void destroyItem(ViewGroup container, int row, int col, Object view) {
|
||||
// Handle this to get the data before the view is destroyed?
|
||||
// Object should still be kept by this, just setup for reinit?
|
||||
// Object should still be kept by this, just setup for re-init?
|
||||
container.removeView((View) view);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,10 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.EventData;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
|
@ -42,6 +43,7 @@ public class WizardActivity extends ViewSelectorActivity {
|
|||
finish();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private class MyGridViewPagerAdapter extends GridPagerAdapter {
|
||||
@Override
|
||||
public int getColumnCount(int arg0) {
|
||||
|
@ -82,15 +84,17 @@ public class WizardActivity extends ViewSelectorActivity {
|
|||
} else {
|
||||
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_send_item, container, false);
|
||||
final ImageView confirmbutton = view.findViewById(R.id.confirmbutton);
|
||||
confirmbutton.setOnClickListener((View v) -> {
|
||||
final ImageView confirmButton = view.findViewById(R.id.confirmbutton);
|
||||
confirmButton.setOnClickListener((View v) -> {
|
||||
if (editPercentage != null) {
|
||||
percentage = SafeParse.stringToInt(editPercentage.editText.getText().toString());
|
||||
}
|
||||
|
||||
String actionstring = "wizard2 " + SafeParse.stringToInt(editCarbs.editText.getText().toString())
|
||||
+ " " + percentage;
|
||||
DataLayerListenerService.Companion.initiateAction(WizardActivity.this, actionstring);
|
||||
EventData.ActionWizardPreCheck action = new EventData.ActionWizardPreCheck(
|
||||
SafeParse.stringToInt(editCarbs.editText.getText().toString()),
|
||||
percentage
|
||||
);
|
||||
rxBus.send(new EventWearToMobile(action));
|
||||
showToast(WizardActivity.this, R.string.action_wizard_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
|
@ -102,7 +106,7 @@ public class WizardActivity extends ViewSelectorActivity {
|
|||
@Override
|
||||
public void destroyItem(ViewGroup container, int row, int col, Object view) {
|
||||
// Handle this to get the data before the view is destroyed?
|
||||
// Object should still be kept by this, just setup for reinit?
|
||||
// Object should still be kept by this, just setup for re-init?
|
||||
container.removeView((View) view);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
package info.nightscout.androidaps.interaction.menus;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.interaction.actions.FillActivity;
|
||||
import info.nightscout.androidaps.interaction.utils.MenuListActivity;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
*/
|
||||
|
||||
public class FillMenuActivity extends MenuListActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTitle(R.string.menu_prime_fill);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<MenuItem> getElements() {
|
||||
List<MenuItem> menuItems = new ArrayList<>();
|
||||
menuItems.add(new MenuItem(R.drawable.ic_canula, getString(R.string.action_preset_1)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_canula, getString(R.string.action_preset_2)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_canula, getString(R.string.action_preset_3)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_canula, getString(R.string.action_free_amount)));
|
||||
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction(String action) {
|
||||
if (getString(R.string.action_preset_1).equals(action)) {
|
||||
DataLayerListenerService.Companion.initiateAction(this, "fillpreset 1");
|
||||
} else if (getString(R.string.action_preset_2).equals(action)) {
|
||||
DataLayerListenerService.Companion.initiateAction(this, "fillpreset 2");
|
||||
} else if (getString(R.string.action_preset_3).equals(action)) {
|
||||
DataLayerListenerService.Companion.initiateAction(this, "fillpreset 3");
|
||||
} else if (getString(R.string.action_free_amount).equals(action)) {
|
||||
Intent intent = new Intent(this, FillActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
this.startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package info.nightscout.androidaps.interaction.menus
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventWearToMobile
|
||||
import info.nightscout.androidaps.interaction.actions.FillActivity
|
||||
import info.nightscout.androidaps.interaction.utils.MenuListActivity
|
||||
import info.nightscout.shared.weardata.EventData
|
||||
|
||||
class FillMenuActivity : MenuListActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setTitle(R.string.menu_prime_fill)
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun getElements(): List<MenuItem> =
|
||||
ArrayList<MenuItem>().apply {
|
||||
add(MenuItem(R.drawable.ic_canula, getString(R.string.action_preset_1)))
|
||||
add(MenuItem(R.drawable.ic_canula, getString(R.string.action_preset_2)))
|
||||
add(MenuItem(R.drawable.ic_canula, getString(R.string.action_preset_3)))
|
||||
add(MenuItem(R.drawable.ic_canula, getString(R.string.action_free_amount)))
|
||||
}
|
||||
|
||||
override fun doAction(action: String) {
|
||||
when (action) {
|
||||
getString(R.string.action_preset_1) -> rxBus.send(EventWearToMobile(EventData.ActionFillPresetPreCheck(1)))
|
||||
getString(R.string.action_preset_2) -> rxBus.send(EventWearToMobile(EventData.ActionFillPresetPreCheck(2)))
|
||||
getString(R.string.action_preset_3) -> rxBus.send(EventWearToMobile(EventData.ActionFillPresetPreCheck(3)))
|
||||
getString(R.string.action_free_amount) -> startActivity(Intent(this, FillActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
package info.nightscout.androidaps.interaction.menus;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.interaction.AAPSPreferences;
|
||||
import info.nightscout.androidaps.interaction.actions.ECarbActivity;
|
||||
import info.nightscout.androidaps.interaction.actions.TempTargetActivity;
|
||||
import info.nightscout.androidaps.interaction.actions.TreatmentActivity;
|
||||
import info.nightscout.androidaps.interaction.actions.WizardActivity;
|
||||
import info.nightscout.androidaps.interaction.utils.MenuListActivity;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
*/
|
||||
|
||||
public class MainMenuActivity extends MenuListActivity {
|
||||
|
||||
SharedPreferences sp;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
setTitle(R.string.label_actions_activity);
|
||||
super.onCreate(savedInstanceState);
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<MenuItem> getElements() {
|
||||
|
||||
List<MenuItem> menuItems = new ArrayList<>();
|
||||
if (!sp.getBoolean("wearcontrol", false)) {
|
||||
menuItems.add(new MenuItem(R.drawable.ic_settings, getString(R.string.menu_settings)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_sync, getString(R.string.menu_resync)));
|
||||
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
boolean showPrimeFill = sp.getBoolean("primefill", false);
|
||||
boolean showWizard = sp.getBoolean("showWizard", true);
|
||||
|
||||
if (showWizard) menuItems.add(new MenuItem(R.drawable.ic_calculator, getString(R.string.menu_wizard)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_e_carbs, getString(R.string.menu_ecarb)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_treatment, getString(R.string.menu_treatment)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_temptarget, getString(R.string.menu_tempt)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_settings, getString(R.string.menu_settings)));
|
||||
menuItems.add(new MenuItem(R.drawable.ic_status, getString(R.string.menu_status)));
|
||||
if (showPrimeFill) menuItems.add(new MenuItem(R.drawable.ic_canula, getString(R.string.menu_prime_fill)));
|
||||
|
||||
return menuItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction(String action) {
|
||||
|
||||
Intent intent;
|
||||
|
||||
if (getString(R.string.menu_settings).equals(action)) {
|
||||
intent = new Intent(this, AAPSPreferences.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
this.startActivity(intent);
|
||||
} else if (getString(R.string.menu_resync).equals(action)) {
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
} else if (getString(R.string.menu_tempt).equals(action)) {
|
||||
intent = new Intent(this, TempTargetActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
this.startActivity(intent);
|
||||
} else if (getString(R.string.menu_treatment).equals(action)) {
|
||||
intent = new Intent(this, TreatmentActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
this.startActivity(intent);
|
||||
} else if (getString(R.string.menu_wizard).equals(action)) {
|
||||
intent = new Intent(this, WizardActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
this.startActivity(intent);
|
||||
} else if (getString(R.string.menu_status).equals(action)) {
|
||||
intent = new Intent(this, StatusMenuActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
this.startActivity(intent);
|
||||
} else if (getString(R.string.menu_prime_fill).equals(action)) {
|
||||
intent = new Intent(this, FillMenuActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
this.startActivity(intent);
|
||||
} else if (getString(R.string.menu_ecarb).equals(action)) {
|
||||
intent = new Intent(this, ECarbActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
this.startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package info.nightscout.androidaps.interaction.menus
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventWearToMobile
|
||||
import info.nightscout.androidaps.interaction.AAPSPreferences
|
||||
import info.nightscout.androidaps.interaction.actions.ECarbActivity
|
||||
import info.nightscout.androidaps.interaction.actions.TempTargetActivity
|
||||
import info.nightscout.androidaps.interaction.actions.TreatmentActivity
|
||||
import info.nightscout.androidaps.interaction.actions.WizardActivity
|
||||
import info.nightscout.androidaps.interaction.utils.MenuListActivity
|
||||
import info.nightscout.shared.weardata.EventData
|
||||
import info.nightscout.shared.weardata.EventData.ActionResendData
|
||||
|
||||
class MainMenuActivity : MenuListActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setTitle(R.string.label_actions_activity)
|
||||
super.onCreate(savedInstanceState)
|
||||
rxBus.send(EventWearToMobile(ActionResendData("MainMenuListActivity")))
|
||||
}
|
||||
|
||||
override fun getElements(): List<MenuItem> =
|
||||
ArrayList<MenuItem>().apply {
|
||||
if (!sp.getBoolean(R.string.key_wear_control, false)) {
|
||||
add(MenuItem(R.drawable.ic_settings, getString(R.string.menu_settings)))
|
||||
add(MenuItem(R.drawable.ic_sync, getString(R.string.menu_resync)))
|
||||
} else {
|
||||
if (sp.getBoolean(R.string.key_show_wizard, true))
|
||||
add(MenuItem(R.drawable.ic_calculator, getString(R.string.menu_wizard)))
|
||||
add(MenuItem(R.drawable.ic_e_carbs, getString(R.string.menu_ecarb)))
|
||||
add(MenuItem(R.drawable.ic_treatment, getString(R.string.menu_treatment)))
|
||||
add(MenuItem(R.drawable.ic_temptarget, getString(R.string.menu_tempt)))
|
||||
add(MenuItem(R.drawable.ic_status, getString(R.string.status_cpp)))
|
||||
add(MenuItem(R.drawable.ic_settings, getString(R.string.menu_settings)))
|
||||
add(MenuItem(R.drawable.ic_status, getString(R.string.menu_status)))
|
||||
if (sp.getBoolean(R.string.key_prime_fill, false))
|
||||
add(MenuItem(R.drawable.ic_canula, getString(R.string.menu_prime_fill)))
|
||||
}
|
||||
}
|
||||
|
||||
override fun doAction(action: String) {
|
||||
when (action) {
|
||||
getString(R.string.menu_settings) -> startActivity(Intent(this, AAPSPreferences::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
getString(R.string.menu_resync) -> rxBus.send(EventWearToMobile(ActionResendData("Re-Sync")))
|
||||
getString(R.string.status_cpp) -> rxBus.send(EventWearToMobile(EventData.ActionProfileSwitchSendInitialData(System.currentTimeMillis())))
|
||||
getString(R.string.menu_tempt) -> startActivity(Intent(this, TempTargetActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
getString(R.string.menu_treatment) -> startActivity(Intent(this, TreatmentActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
getString(R.string.menu_wizard) -> startActivity(Intent(this, WizardActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
getString(R.string.menu_status) -> startActivity(Intent(this, StatusMenuActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
getString(R.string.menu_prime_fill) -> startActivity(Intent(this, FillMenuActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
getString(R.string.menu_ecarb) -> startActivity(Intent(this, ECarbActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package info.nightscout.androidaps.interaction.menus;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.interaction.utils.MenuListActivity;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
*/
|
||||
|
||||
public class StatusMenuActivity extends MenuListActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
setTitle(R.string.menu_status);
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<MenuItem> getElements() {
|
||||
List<MenuItem> menuitems = new ArrayList<>();
|
||||
menuitems.add(new MenuItem(R.drawable.ic_status, getString(R.string.status_pump)));
|
||||
menuitems.add(new MenuItem(R.drawable.ic_loop_closed, getString(R.string.status_loop)));
|
||||
menuitems.add(new MenuItem(R.drawable.ic_status, getString(R.string.status_cpp)));
|
||||
menuitems.add(new MenuItem(R.drawable.ic_tdd, getString(R.string.status_tdd)));
|
||||
|
||||
return menuitems;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction(String action) {
|
||||
if (getString(R.string.status_pump).equals(action)) {
|
||||
DataLayerListenerService.Companion.initiateAction(this, "status pump");
|
||||
} else if (getString(R.string.status_loop).equals(action)) {
|
||||
DataLayerListenerService.Companion.initiateAction(this, "status loop");
|
||||
} else if (getString(R.string.status_cpp).equals(action)) {
|
||||
DataLayerListenerService.Companion.initiateAction(this, "opencpp");
|
||||
} else if (getString(R.string.status_tdd).equals(action)) {
|
||||
DataLayerListenerService.Companion.initiateAction(this, "tddstats");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package info.nightscout.androidaps.interaction.menus
|
||||
|
||||
import android.os.Bundle
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventWearToMobile
|
||||
import info.nightscout.androidaps.interaction.utils.MenuListActivity
|
||||
import info.nightscout.shared.weardata.EventData.ActionLoopStatus
|
||||
import info.nightscout.shared.weardata.EventData.ActionPumpStatus
|
||||
import info.nightscout.shared.weardata.EventData.ActionTddStatus
|
||||
|
||||
class StatusMenuActivity : MenuListActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setTitle(R.string.menu_status)
|
||||
super.onCreate(savedInstanceState)
|
||||
}
|
||||
|
||||
override fun getElements(): List<MenuItem> =
|
||||
ArrayList<MenuItem>().apply {
|
||||
add(MenuItem(R.drawable.ic_status, getString(R.string.status_pump)))
|
||||
add(MenuItem(R.drawable.ic_loop_closed, getString(R.string.status_loop)))
|
||||
add(MenuItem(R.drawable.ic_tdd, getString(R.string.status_tdd)))
|
||||
}
|
||||
|
||||
override fun doAction(action: String) {
|
||||
when (action) {
|
||||
getString(R.string.status_pump) -> rxBus.send(EventWearToMobile(ActionPumpStatus(System.currentTimeMillis())))
|
||||
getString(R.string.status_loop) -> rxBus.send(EventWearToMobile(ActionLoopStatus(System.currentTimeMillis())))
|
||||
getString(R.string.status_tdd) -> rxBus.send(EventWearToMobile(ActionTddStatus(System.currentTimeMillis())))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -65,27 +65,27 @@ public class DisplayFormat {
|
|||
|
||||
public String shortTrend(final RawDisplayData raw) {
|
||||
String minutes = "--";
|
||||
if (raw.datetime > 0) {
|
||||
minutes = shortTimeSince(raw.datetime);
|
||||
if (raw.getSingleBg().getTimeStamp() > 0) {
|
||||
minutes = shortTimeSince(raw.getSingleBg().getTimeStamp());
|
||||
}
|
||||
|
||||
if (minutes.length() + raw.sDelta.length() + deltaSymbol().length() + 1 <= MAX_FIELD_LEN_SHORT) {
|
||||
return minutes + " " + deltaSymbol() + raw.sDelta;
|
||||
if (minutes.length() + raw.getSingleBg().getDelta().length() + deltaSymbol().length() + 1 <= MAX_FIELD_LEN_SHORT) {
|
||||
return minutes + " " + deltaSymbol() + raw.getSingleBg().getDelta();
|
||||
}
|
||||
|
||||
// that only optimizes obvious things like 0 before . or at end, + at beginning
|
||||
String delta = (new SmallestDoubleString(raw.sDelta)).minimise(MAX_FIELD_LEN_SHORT -1);
|
||||
String delta = (new SmallestDoubleString(raw.getSingleBg().getDelta())).minimise(MAX_FIELD_LEN_SHORT -1);
|
||||
if (minutes.length() + delta.length() + deltaSymbol().length() + 1 <= MAX_FIELD_LEN_SHORT) {
|
||||
return minutes + " " + deltaSymbol() + delta;
|
||||
}
|
||||
|
||||
String shortDelta = (new SmallestDoubleString(raw.sDelta)).minimise(MAX_FIELD_LEN_SHORT -(1+minutes.length()));
|
||||
String shortDelta = (new SmallestDoubleString(raw.getSingleBg().getDelta())).minimise(MAX_FIELD_LEN_SHORT -(1+minutes.length()));
|
||||
|
||||
return minutes + " " + shortDelta;
|
||||
}
|
||||
|
||||
public String longGlucoseLine(final RawDisplayData raw) {
|
||||
return raw.sSgv + raw.sDirection + " " + deltaSymbol() + (new SmallestDoubleString(raw.sDelta)).minimise(8) + " (" + shortTimeSince(raw.datetime) + ")";
|
||||
return raw.getSingleBg().getSgvString() + raw.getSingleBg().getSlopeArrow() + " " + deltaSymbol() + (new SmallestDoubleString(raw.getSingleBg().getDelta())).minimise(8) + " (" + shortTimeSince(raw.getSingleBg().getTimeStamp()) + ")";
|
||||
}
|
||||
|
||||
public String longDetailsLine(final RawDisplayData raw) {
|
||||
|
@ -95,40 +95,41 @@ public class DisplayFormat {
|
|||
final int SEP_SHORT_LEN = SEP_SHORT.length();
|
||||
final String SEP_MIN = " ";
|
||||
|
||||
String line = raw.sCOB2 + SEP_LONG + raw.sIOB1 + SEP_LONG + basalRateSymbol()+raw.sBasalRate;
|
||||
String line =
|
||||
raw.getStatus().getCob() + SEP_LONG + raw.getStatus().getIobSum() + SEP_LONG + basalRateSymbol()+raw.getStatus().getCurrentBasal();
|
||||
if (line.length() <= MAX_FIELD_LEN_LONG) {
|
||||
return line;
|
||||
}
|
||||
line = raw.sCOB2 + SEP_SHORT + raw.sIOB1 + SEP_SHORT + raw.sBasalRate;
|
||||
line = raw.getStatus().getCob() + SEP_SHORT + raw.getStatus().getIobSum() + SEP_SHORT + raw.getStatus().getCurrentBasal();
|
||||
if (line.length() <= MAX_FIELD_LEN_LONG) {
|
||||
return line;
|
||||
}
|
||||
|
||||
int remainingMax = MAX_FIELD_LEN_LONG - (raw.sCOB2.length() + raw.sBasalRate.length() + SEP_SHORT_LEN*2);
|
||||
final String smallestIoB = new SmallestDoubleString(raw.sIOB1, SmallestDoubleString.Units.USE).minimise(Math.max(MIN_FIELD_LEN_IOB, remainingMax));
|
||||
line = raw.sCOB2 + SEP_SHORT + smallestIoB + SEP_SHORT + raw.sBasalRate;
|
||||
int remainingMax = MAX_FIELD_LEN_LONG - (raw.getStatus().getCob().length() + raw.getStatus().getCurrentBasal().length() + SEP_SHORT_LEN*2);
|
||||
final String smallestIoB = new SmallestDoubleString(raw.getStatus().getIobSum(), SmallestDoubleString.Units.USE).minimise(Math.max(MIN_FIELD_LEN_IOB, remainingMax));
|
||||
line = raw.getStatus().getCob() + SEP_SHORT + smallestIoB + SEP_SHORT + raw.getStatus().getCurrentBasal();
|
||||
if (line.length() <= MAX_FIELD_LEN_LONG) {
|
||||
return line;
|
||||
}
|
||||
|
||||
remainingMax = MAX_FIELD_LEN_LONG - (smallestIoB.length() + raw.sBasalRate.length() + SEP_SHORT_LEN*2);
|
||||
final String simplifiedCob = new SmallestDoubleString(raw.sCOB2, SmallestDoubleString.Units.USE).minimise(Math.max(MIN_FIELD_LEN_COB, remainingMax));
|
||||
remainingMax = MAX_FIELD_LEN_LONG - (smallestIoB.length() + raw.getStatus().getCurrentBasal().length() + SEP_SHORT_LEN*2);
|
||||
final String simplifiedCob = new SmallestDoubleString(raw.getStatus().getCob(), SmallestDoubleString.Units.USE).minimise(Math.max(MIN_FIELD_LEN_COB, remainingMax));
|
||||
|
||||
line = simplifiedCob + SEP_SHORT + smallestIoB + SEP_SHORT + raw.sBasalRate;
|
||||
line = simplifiedCob + SEP_SHORT + smallestIoB + SEP_SHORT + raw.getStatus().getCurrentBasal();
|
||||
if (line.length() <= MAX_FIELD_LEN_LONG) {
|
||||
return line;
|
||||
}
|
||||
|
||||
line = simplifiedCob + SEP_MIN + smallestIoB + SEP_MIN + raw.sBasalRate;
|
||||
line = simplifiedCob + SEP_MIN + smallestIoB + SEP_MIN + raw.getStatus().getCurrentBasal();
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
public Pair<String, String> detailedIob(RawDisplayData raw) {
|
||||
final String iob1 = new SmallestDoubleString(raw.sIOB1, SmallestDoubleString.Units.USE).minimise(MAX_FIELD_LEN_SHORT);
|
||||
final String iob1 = new SmallestDoubleString(raw.getStatus().getIobSum(), SmallestDoubleString.Units.USE).minimise(MAX_FIELD_LEN_SHORT);
|
||||
String iob2 = "";
|
||||
if (raw.sIOB2.contains("|")) {
|
||||
String[] iobs = raw.sIOB2.replace("(", "").replace(")", "").split("\\|");
|
||||
if (raw.getStatus().getIobDetail().contains("|")) {
|
||||
String[] iobs = raw.getStatus().getIobDetail().replace("(", "").replace(")", "").split("\\|");
|
||||
|
||||
String iobBolus = new SmallestDoubleString(iobs[0]).minimise(MIN_FIELD_LEN_IOB);
|
||||
if (iobBolus.trim().length() == 0) {
|
||||
|
@ -144,7 +145,7 @@ public class DisplayFormat {
|
|||
}
|
||||
|
||||
public Pair<String, String> detailedCob(final RawDisplayData raw) {
|
||||
SmallestDoubleString cobMini = new SmallestDoubleString(raw.sCOB2, SmallestDoubleString.Units.USE);
|
||||
SmallestDoubleString cobMini = new SmallestDoubleString(raw.getStatus().getCob(), SmallestDoubleString.Units.USE);
|
||||
|
||||
String cob2 = "";
|
||||
if (cobMini.getExtra().length() > 0) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package info.nightscout.androidaps.interaction.utils;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -9,6 +8,7 @@ import android.widget.ImageView;
|
|||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.wear.widget.CurvedTextView;
|
||||
import androidx.wear.widget.WearableLinearLayoutManager;
|
||||
|
@ -16,13 +16,22 @@ import androidx.wear.widget.WearableRecyclerView;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.DaggerActivity;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.shared.sharedPreferences.SP;
|
||||
|
||||
/**
|
||||
* Created by adrian on 08/02/17.
|
||||
*/
|
||||
|
||||
public abstract class MenuListActivity extends Activity {
|
||||
public abstract class MenuListActivity extends DaggerActivity {
|
||||
|
||||
@Inject public RxBus rxBus;
|
||||
@Inject public SP sp;
|
||||
|
||||
List<MenuItem> elements;
|
||||
|
||||
protected abstract List<MenuItem> getElements();
|
||||
|
@ -96,7 +105,7 @@ public abstract class MenuListActivity extends Activity {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NonNull @Override
|
||||
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
|
||||
|
||||
|
|
|
@ -3,22 +3,20 @@ package info.nightscout.androidaps.interaction.utils;
|
|||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import info.nightscout.androidaps.Aaps;
|
||||
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
|
||||
|
@ -26,7 +24,6 @@ import info.nightscout.shared.logging.LTag;
|
|||
@Singleton
|
||||
public class Persistence {
|
||||
|
||||
private final Context context;
|
||||
private final AAPSLogger aapsLogger;
|
||||
private final WearUtil wearUtil;
|
||||
private final SharedPreferences preferences;
|
||||
|
@ -35,7 +32,6 @@ public class Persistence {
|
|||
|
||||
@Inject
|
||||
public Persistence(Context context, AAPSLogger aapsLogger, WearUtil wearUtil) {
|
||||
this.context = context;
|
||||
this.aapsLogger = aapsLogger;
|
||||
this.wearUtil = wearUtil;
|
||||
preferences = context.getSharedPreferences(COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0);
|
||||
|
@ -51,24 +47,6 @@ public class Persistence {
|
|||
return Base64.encodeToString(input, flags);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public DataMap getDataMap(String key) {
|
||||
if (preferences.contains(key)) {
|
||||
final String rawB64Data = preferences.getString(key, null);
|
||||
byte[] rawData = base64decode(rawB64Data, Base64.DEFAULT);
|
||||
try {
|
||||
return DataMap.fromByteArray(rawData);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// Should never happen, and if it happen - we ignore and fallback to null
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void putDataMap(String key, DataMap dataMap) {
|
||||
preferences.edit().putString(key, base64encodeToString(dataMap.toByteArray(), Base64.DEFAULT)).apply();
|
||||
}
|
||||
|
||||
public String getString(String key, String defaultValue) {
|
||||
return preferences.getString(key, defaultValue);
|
||||
}
|
||||
|
@ -109,11 +87,67 @@ public class Persistence {
|
|||
putString(key, joinSet(set, "|"));
|
||||
}
|
||||
|
||||
public void storeDataMap(String key, DataMap dataMap) {
|
||||
putDataMap(key, dataMap);
|
||||
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;
|
||||
|
|
|
@ -2,93 +2,64 @@ package info.nightscout.androidaps.tile
|
|||
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.gms.wearable.DataMap
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interaction.actions.BackgroundActionActivity
|
||||
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 java.util.*
|
||||
|
||||
object QuickWizardSource : TileSource {
|
||||
|
||||
override fun getSelectedActions(context: Context): List<Action> {
|
||||
override fun getSelectedActions(context: Context, sp: SP, aapsLogger: AAPSLogger): List<Action> {
|
||||
val quickList = mutableListOf<Action>()
|
||||
val quickMap = getDataMap(context)
|
||||
val quickMap = getQuickWizardData(sp)
|
||||
val sfm = secondsFromMidnight()
|
||||
|
||||
for (quick in quickMap) {
|
||||
val validFrom = quick.getInt("from", 0)
|
||||
val validTo = quick.getInt("to", 0)
|
||||
val isActive = sfm in validFrom..validTo
|
||||
val guid = quick.getString("guid", "")
|
||||
if (isActive && guid != "") {
|
||||
for (quick in quickMap.entries) {
|
||||
val isActive = sfm in quick.validFrom..quick.validTo
|
||||
if (isActive && quick.guid.isNotEmpty()) {
|
||||
quickList.add(
|
||||
Action(
|
||||
buttonText = quick.getString("button_text", "?"),
|
||||
buttonTextSub = "${quick.getInt("carbs", 0)} g",
|
||||
buttonText = quick.buttonText,
|
||||
buttonTextSub = "${quick.carbs} g",
|
||||
iconRes = R.drawable.ic_quick_wizard,
|
||||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
actionString = "quick_wizard $guid",
|
||||
message = context.resources.getString(R.string.action_quick_wizard_confirmation),
|
||||
action = EventData.ActionQuickWizardPreCheck(quick.guid),
|
||||
message = context.resources.getString(R.string.action_quick_wizard_confirmation)
|
||||
)
|
||||
)
|
||||
Log.i(TAG, "getSelectedActions: active " + quick.getString("button_text", "?") + " guid=" + guid)
|
||||
aapsLogger.info(LTag.WEAR, """getSelectedActions: active ${quick.buttonText} guid=${quick.guid}""")
|
||||
} else {
|
||||
Log.i(TAG, "getSelectedActions: not active " + quick.getString("button_text", "?") + " guid=" + guid)
|
||||
aapsLogger.info(LTag.WEAR, """getSelectedActions: not active ${quick.buttonText} guid=${quick.guid}""")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return quickList
|
||||
}
|
||||
|
||||
override fun getValidFor(context: Context): Long? {
|
||||
val quickMap = getDataMap(context)
|
||||
if (quickMap.size == 0) {
|
||||
return null
|
||||
}
|
||||
override fun getValidFor(sp: SP): Long? {
|
||||
val quickMap = getQuickWizardData(sp)
|
||||
if (quickMap.entries.size == 0) return null
|
||||
|
||||
val sfm = secondsFromMidnight()
|
||||
var validTill = 24 * 60 * 60
|
||||
|
||||
for (quick in quickMap) {
|
||||
val validFrom = quick.getInt("from", 0)
|
||||
val validTo = quick.getInt("to", 0)
|
||||
val isActive = sfm in validFrom..validTo
|
||||
val guid = quick.getString("guid", "")
|
||||
Log.i(TAG, "valid: " + validFrom + "-" + validTo)
|
||||
if (guid != "") {
|
||||
if (isActive && validTill > validTo) {
|
||||
validTill = validTo
|
||||
}
|
||||
if (validFrom > sfm && validTill > validFrom) {
|
||||
validTill = validFrom
|
||||
}
|
||||
for (quick in quickMap.entries) {
|
||||
val isActive = sfm in quick.validFrom..quick.validTo
|
||||
if (quick.guid.isNotEmpty()) {
|
||||
if (isActive && validTill > quick.validTo) validTill = quick.validTo
|
||||
if (quick.validFrom in (sfm + 1) until validTill) validTill = quick.validFrom
|
||||
}
|
||||
}
|
||||
|
||||
val validWithin = 60
|
||||
val delta = (validTill - sfm + validWithin) * 1000L
|
||||
Log.i(TAG, "getValidTill: sfm" + sfm + " till" + validTill + " d=" + delta)
|
||||
return delta
|
||||
//aapsLogger.info(LTag.WEAR, "getValidTill: sfm$sfm till$validTill d=$delta")
|
||||
return (validTill - sfm + validWithin) * 1000L
|
||||
}
|
||||
|
||||
private fun getDataMap(context: Context): ArrayList<DataMap> {
|
||||
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val key = context.resources.getString(R.string.key_quick_wizard_data_map)
|
||||
if (sharedPrefs.contains(key)) {
|
||||
val rawB64Data: String? = sharedPrefs.getString(key, null)
|
||||
val rawData: ByteArray = Base64.decode(rawB64Data, Base64.DEFAULT)
|
||||
try {
|
||||
val map = DataMap.fromByteArray(rawData)
|
||||
return map.getDataMapArrayList("quick_wizard")
|
||||
|
||||
} catch (ex: IllegalArgumentException) {
|
||||
Log.e(TAG, "getSelectedActions: IllegalArgumentException ", ex)
|
||||
}
|
||||
}
|
||||
return arrayListOf()
|
||||
}
|
||||
private fun getQuickWizardData(sp: SP): EventData.QuickWizard =
|
||||
EventData.deserialize(sp.getString(R.string.key_quick_wizard_data, EventData.QuickWizard(arrayListOf()).serialize())) as EventData.QuickWizard
|
||||
|
||||
private fun secondsFromMidnight(): Int {
|
||||
val c = Calendar.getInstance()
|
||||
|
@ -101,8 +72,5 @@ object QuickWizardSource : TileSource {
|
|||
return (passed / 1000).toInt()
|
||||
}
|
||||
|
||||
override fun getResourceReferences(resources: Resources): List<Int> {
|
||||
return listOf(R.drawable.ic_quick_wizard)
|
||||
}
|
||||
|
||||
override fun getResourceReferences(resources: Resources): List<Int> = listOf(R.drawable.ic_quick_wizard)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,9 @@ import android.content.SharedPreferences
|
|||
import android.content.res.Resources
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.preference.PreferenceManager
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.weardata.EventData
|
||||
|
||||
class StaticAction(
|
||||
val settingName: String,
|
||||
|
@ -12,9 +15,9 @@ class StaticAction(
|
|||
buttonTextSub: String? = null,
|
||||
activityClass: String,
|
||||
@DrawableRes iconRes: Int,
|
||||
actionString: String? = null,
|
||||
action: EventData? = null,
|
||||
message: String? = null,
|
||||
) : Action(buttonText, buttonTextSub, activityClass, iconRes, actionString, message)
|
||||
) : Action(buttonText, buttonTextSub, activityClass, iconRes, action, message)
|
||||
|
||||
abstract class StaticTileSource : TileSource {
|
||||
|
||||
|
@ -23,7 +26,7 @@ abstract class StaticTileSource : TileSource {
|
|||
abstract val preferencePrefix: String
|
||||
abstract fun getDefaultConfig(): Map<String, String>
|
||||
|
||||
override fun getSelectedActions(context: Context): List<Action> {
|
||||
override fun getSelectedActions(context: Context, sp: SP, aapsLogger: AAPSLogger): List<Action> {
|
||||
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
setDefaultSettings(sharedPrefs)
|
||||
|
||||
|
@ -40,7 +43,7 @@ abstract class StaticTileSource : TileSource {
|
|||
return actionList
|
||||
}
|
||||
|
||||
override fun getValidFor(context: Context): Long? = null
|
||||
override fun getValidFor(sp: SP): Long? = null
|
||||
|
||||
private fun getActionFromPreference(resources: Resources, sharedPrefs: SharedPreferences, index: Int): Action? {
|
||||
val actionPref = sharedPrefs.getString(preferencePrefix + index, "none")
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.content.res.Resources
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interaction.actions.BackgroundActionActivity
|
||||
import info.nightscout.androidaps.interaction.actions.TempTargetActivity
|
||||
import info.nightscout.shared.weardata.EventData
|
||||
|
||||
object TempTargetSource : StaticTileSource() {
|
||||
|
||||
|
@ -19,7 +20,8 @@ object TempTargetSource : StaticTileSource() {
|
|||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
message = message,
|
||||
// actionString = "temptarget false 90 8.0 8.0",
|
||||
actionString = "temptarget preset activity",
|
||||
// actionString = "temptarget preset activity",
|
||||
action = EventData.ActionTempTargetPreCheck(EventData.ActionTempTargetPreCheck.TempTargetCommand.PRESET_ACTIVITY)
|
||||
),
|
||||
StaticAction(
|
||||
settingName = "eating_soon",
|
||||
|
@ -28,7 +30,8 @@ object TempTargetSource : StaticTileSource() {
|
|||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
message = message,
|
||||
// actionString = "temptarget false 45 4.5 4.5",
|
||||
actionString = "temptarget preset eating",
|
||||
// actionString = "temptarget preset eating",
|
||||
action = EventData.ActionTempTargetPreCheck(EventData.ActionTempTargetPreCheck.TempTargetCommand.PRESET_EATING)
|
||||
),
|
||||
StaticAction(
|
||||
settingName = "hypo",
|
||||
|
@ -37,13 +40,15 @@ object TempTargetSource : StaticTileSource() {
|
|||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
message = message,
|
||||
// actionString = "temptarget false 45 7.0 7.0",
|
||||
actionString = "temptarget preset hypo",
|
||||
// actionString = "temptarget preset hypo",
|
||||
action = EventData.ActionTempTargetPreCheck(EventData.ActionTempTargetPreCheck.TempTargetCommand.PRESET_HYPO)
|
||||
),
|
||||
StaticAction(
|
||||
settingName = "manual",
|
||||
buttonText = resources.getString(R.string.temp_target_manual),
|
||||
iconRes = R.drawable.ic_target_manual,
|
||||
activityClass = TempTargetActivity::class.java.name,
|
||||
action = null
|
||||
),
|
||||
StaticAction(
|
||||
settingName = "cancel",
|
||||
|
@ -51,7 +56,8 @@ object TempTargetSource : StaticTileSource() {
|
|||
iconRes = R.drawable.ic_target_cancel,
|
||||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
message = message,
|
||||
actionString = "temptarget cancel",
|
||||
//actionString = "temptarget cancel",
|
||||
action = EventData.ActionTempTargetPreCheck(EventData.ActionTempTargetPreCheck.TempTargetCommand.CANCEL)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -5,11 +5,10 @@ import android.os.Build
|
|||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.wear.tiles.ActionBuilders
|
||||
import androidx.wear.tiles.ColorBuilders.argb
|
||||
import androidx.wear.tiles.DeviceParametersBuilders.SCREEN_SHAPE_ROUND
|
||||
import androidx.wear.tiles.DeviceParametersBuilders.DeviceParameters
|
||||
import androidx.wear.tiles.DeviceParametersBuilders.SCREEN_SHAPE_ROUND
|
||||
import androidx.wear.tiles.DimensionBuilders.SpProp
|
||||
import androidx.wear.tiles.DimensionBuilders.dp
|
||||
import androidx.wear.tiles.DimensionBuilders.sp
|
||||
|
@ -29,11 +28,17 @@ import androidx.wear.tiles.TileService
|
|||
import androidx.wear.tiles.TimelineBuilders.Timeline
|
||||
import androidx.wear.tiles.TimelineBuilders.TimelineEntry
|
||||
import com.google.common.util.concurrent.ListenableFuture
|
||||
import dagger.android.AndroidInjection
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.comm.DataLayerListenerServiceWear
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.shared.weardata.EventData
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.guava.future
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.sqrt
|
||||
|
||||
private const val SPACING_ACTIONS = 3f
|
||||
|
@ -44,8 +49,8 @@ private const val LARGE_SCREEN_WIDTH_DP = 210
|
|||
interface TileSource {
|
||||
|
||||
fun getResourceReferences(resources: android.content.res.Resources): List<Int>
|
||||
fun getSelectedActions(context: Context): List<Action>
|
||||
fun getValidFor(context: Context): Long?
|
||||
fun getSelectedActions(context: Context, sp: SP, aapsLogger: AAPSLogger): List<Action>
|
||||
fun getValidFor(sp: SP): Long?
|
||||
}
|
||||
|
||||
open class Action(
|
||||
|
@ -53,7 +58,7 @@ open class Action(
|
|||
val buttonTextSub: String? = null,
|
||||
val activityClass: String,
|
||||
@DrawableRes val iconRes: Int,
|
||||
val actionString: String? = null,
|
||||
val action: EventData? = null,
|
||||
val message: String? = null,
|
||||
)
|
||||
|
||||
|
@ -63,12 +68,21 @@ enum class WearControl {
|
|||
|
||||
abstract class TileBase : TileService() {
|
||||
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
|
||||
abstract val resourceVersion: String
|
||||
abstract val source: TileSource
|
||||
|
||||
private val serviceJob = Job()
|
||||
private val serviceScope = CoroutineScope(Dispatchers.IO + serviceJob)
|
||||
|
||||
// Not derived from DaggerService, do injection here
|
||||
override fun onCreate() {
|
||||
AndroidInjection.inject(this)
|
||||
super.onCreate()
|
||||
}
|
||||
|
||||
override fun onTileRequest(
|
||||
requestParams: RequestBuilders.TileRequest
|
||||
): ListenableFuture<Tile> = serviceScope.future {
|
||||
|
@ -93,11 +107,11 @@ abstract class TileBase : TileService() {
|
|||
|
||||
private fun getSelectedActions(): List<Action> {
|
||||
// TODO check why thi scan not be don in scope of the coroutine
|
||||
return source.getSelectedActions(this)
|
||||
return source.getSelectedActions(this, sp, aapsLogger)
|
||||
}
|
||||
|
||||
private fun validFor(): Long? {
|
||||
return source.getValidFor(this)
|
||||
return source.getValidFor(sp)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N)
|
||||
|
@ -172,13 +186,13 @@ abstract class TileBase : TileService() {
|
|||
val builder = ActionBuilders.AndroidActivity.Builder()
|
||||
.setClassName(action.activityClass)
|
||||
.setPackageName(this.packageName)
|
||||
if (action.actionString != null) {
|
||||
val actionString = ActionBuilders.AndroidStringExtra.Builder().setValue(action.actionString).build()
|
||||
builder.addKeyToExtraMapping("actionString", actionString)
|
||||
if (action.action != null) {
|
||||
val actionString = ActionBuilders.AndroidStringExtra.Builder().setValue(action.action.serialize()).build()
|
||||
builder.addKeyToExtraMapping(DataLayerListenerServiceWear.KEY_ACTION, actionString)
|
||||
}
|
||||
if (action.message != null) {
|
||||
val message = ActionBuilders.AndroidStringExtra.Builder().setValue(action.message).build()
|
||||
builder.addKeyToExtraMapping("message", message)
|
||||
builder.addKeyToExtraMapping(DataLayerListenerServiceWear.KEY_MESSAGE, message)
|
||||
}
|
||||
|
||||
return ActionBuilders.LaunchAction.Builder()
|
||||
|
@ -197,12 +211,8 @@ abstract class TileBase : TileService() {
|
|||
Modifiers.Builder()
|
||||
.setBackground(
|
||||
Background.Builder()
|
||||
.setColor(
|
||||
argb(ContextCompat.getColor(baseContext, BUTTON_COLOR))
|
||||
)
|
||||
.setCorner(
|
||||
Corner.Builder().setRadius(dp(circleDiameter / 2)).build()
|
||||
)
|
||||
.setColor(argb(ContextCompat.getColor(baseContext, BUTTON_COLOR)))
|
||||
.setCorner(Corner.Builder().setRadius(dp(circleDiameter / 2)).build())
|
||||
.build()
|
||||
)
|
||||
.setSemantics(
|
||||
|
@ -239,9 +249,7 @@ abstract class TileBase : TileService() {
|
|||
.setFontStyle(
|
||||
FontStyle.Builder()
|
||||
.setWeight(FONT_WEIGHT_BOLD)
|
||||
.setColor(
|
||||
argb(ContextCompat.getColor(baseContext, R.color.white))
|
||||
)
|
||||
.setColor(argb(ContextCompat.getColor(baseContext, R.color.white)))
|
||||
.setSize(buttonTextSize(deviceParameters, text))
|
||||
.build()
|
||||
)
|
||||
|
@ -253,9 +261,7 @@ abstract class TileBase : TileService() {
|
|||
.setText(textSub)
|
||||
.setFontStyle(
|
||||
FontStyle.Builder()
|
||||
.setColor(
|
||||
argb(ContextCompat.getColor(baseContext, R.color.white))
|
||||
)
|
||||
.setColor(argb(ContextCompat.getColor(baseContext, R.color.white)))
|
||||
.setSize(buttonTextSize(deviceParameters, textSub))
|
||||
.build()
|
||||
)
|
||||
|
@ -283,11 +289,10 @@ abstract class TileBase : TileService() {
|
|||
}
|
||||
|
||||
private fun getWearControl(): WearControl {
|
||||
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
if (!sharedPrefs.contains("wearcontrol")) {
|
||||
if (!sp.contains("wearcontrol")) {
|
||||
return WearControl.NO_DATA
|
||||
}
|
||||
val wearControlPref = sharedPrefs.getBoolean("wearcontrol", false)
|
||||
val wearControlPref = sp.getBoolean("wearcontrol", false)
|
||||
if (wearControlPref) {
|
||||
return WearControl.ENABLED
|
||||
}
|
||||
|
|
|
@ -1,29 +1,18 @@
|
|||
package info.nightscout.androidaps.watchfaces;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.annotation.SuppressLint;
|
||||
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.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import android.support.wearable.view.WatchViewStub;
|
||||
import android.support.wearable.watchface.WatchFaceStyle;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -32,7 +21,8 @@ import android.view.WindowManager;
|
|||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.ustwo.clockwise.common.WatchFaceTime;
|
||||
import com.ustwo.clockwise.common.WatchMode;
|
||||
import com.ustwo.clockwise.common.WatchShape;
|
||||
|
@ -40,25 +30,43 @@ import com.ustwo.clockwise.wearable.WatchFace;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.AndroidInjection;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.BasalWatchData;
|
||||
import info.nightscout.androidaps.data.BgWatchData;
|
||||
import info.nightscout.androidaps.data.BolusWatchData;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.data.TempWatchData;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.menus.MainMenuActivity;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
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 io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
import lecho.lib.hellocharts.view.LineChartView;
|
||||
|
||||
/**
|
||||
* Created by adrianLxM.
|
||||
*/
|
||||
public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public final static IntentFilter INTENT_FILTER;
|
||||
public static final int SCREENSIZE_SMALL = 280;
|
||||
public TextView mTime, mSgv, mTimestamp, mDelta, mAvgDelta;
|
||||
public RelativeLayout mRelativeLayout;
|
||||
public long sgvLevel = 0;
|
||||
public int batteryLevel = 1;
|
||||
@SuppressWarnings("deprecation")
|
||||
public class BIGChart extends WatchFace {
|
||||
|
||||
@Inject RxBus rxBus;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject SP sp;
|
||||
|
||||
CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
private EventData.SingleBg singleBg;
|
||||
private EventData.Status status;
|
||||
private EventData.TreatmentData treatmentData;
|
||||
private EventData.GraphData graphData;
|
||||
|
||||
private static final int SCREEN_SIZE_SMALL = 280;
|
||||
private TextView mTime, mSgv, mTimestamp, mDelta, mAvgDelta;
|
||||
private RelativeLayout mRelativeLayout;
|
||||
|
||||
public int ageLevel = 1;
|
||||
public int highColor = Color.YELLOW;
|
||||
public int lowColor = Color.RED;
|
||||
|
@ -73,36 +81,21 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
public boolean layoutSet = false;
|
||||
public BgGraphBuilder bgGraphBuilder;
|
||||
public LineChartView chart;
|
||||
public long datetime;
|
||||
public ArrayList<BgWatchData> bgDataList = new ArrayList<>();
|
||||
public ArrayList<TempWatchData> tempWatchDataList = new ArrayList<>();
|
||||
public ArrayList<BasalWatchData> basalWatchDataList = new ArrayList<>();
|
||||
public ArrayList<BolusWatchData> bolusWatchDataList = new ArrayList<>();
|
||||
public ArrayList<BgWatchData> predictionList = new ArrayList<>();
|
||||
public ArrayList<EventData.SingleBg> bgDataList = 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 rawString = "000 | 000 | 000";
|
||||
private String batteryString = "--";
|
||||
private String sgvString = "--";
|
||||
private String externalStatusString = "no status";
|
||||
private String cobString = "";
|
||||
|
||||
private TextView statusView;
|
||||
private long chartTapTime = 0L;
|
||||
private long sgvTapTime = 0L;
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
@Override
|
||||
public void onCreate() {
|
||||
AndroidInjection.inject(this);
|
||||
super.onCreate();
|
||||
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
|
||||
.getDefaultDisplay();
|
||||
|
@ -113,17 +106,71 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
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);
|
||||
DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||
if(metrics.widthPixels < SCREENSIZE_SMALL || metrics.heightPixels < SCREENSIZE_SMALL){
|
||||
if (metrics.widthPixels < SCREEN_SIZE_SMALL || metrics.heightPixels < SCREEN_SIZE_SMALL) {
|
||||
layoutView = inflater.inflate(R.layout.activity_bigchart_small, null);
|
||||
} else {
|
||||
layoutView = inflater.inflate(R.layout.activity_bigchart, null);
|
||||
}
|
||||
performViewSetup();
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.SingleBg.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> {
|
||||
aapsLogger.debug(LTag.WEAR, "SingleBg received");
|
||||
singleBg = event;
|
||||
|
||||
mSgv.setText(singleBg.getSgvString());
|
||||
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()));
|
||||
mDelta.setText(singleBg.getDelta());
|
||||
mAvgDelta.setText(singleBg.getAvgDelta());
|
||||
})
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.TreatmentData.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> treatmentData = event)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.GraphData.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> graphData = event)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.Status.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> {
|
||||
// this event is received as last batch of data
|
||||
aapsLogger.debug(LTag.WEAR, "Status received");
|
||||
status = event;
|
||||
showAgeAndStatus();
|
||||
addToWatchSet();
|
||||
mRelativeLayout.measure(specW, specH);
|
||||
mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
|
||||
mRelativeLayout.getMeasuredHeight());
|
||||
invalidate();
|
||||
setColor();
|
||||
})
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.Preferences.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> {
|
||||
setColor();
|
||||
if (layoutSet) {
|
||||
showAgeAndStatus();
|
||||
mRelativeLayout.measure(specW, specH);
|
||||
mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
|
||||
mRelativeLayout.getMeasuredHeight());
|
||||
}
|
||||
invalidate();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -134,54 +181,46 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
|
||||
public void performViewSetup() {
|
||||
final WatchViewStub stub = 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 = stub.findViewById(R.id.watch_time);
|
||||
mSgv = stub.findViewById(R.id.sgv);
|
||||
mTimestamp = stub.findViewById(R.id.timestamp);
|
||||
mDelta = stub.findViewById(R.id.delta);
|
||||
mAvgDelta = stub.findViewById(R.id.avgdelta);
|
||||
mRelativeLayout = stub.findViewById(R.id.main_layout);
|
||||
chart = stub.findViewById(R.id.chart);
|
||||
statusView = stub.findViewById(R.id.aps_status);
|
||||
layoutSet = true;
|
||||
showAgeAndStatus();
|
||||
mRelativeLayout.measure(specW, specH);
|
||||
mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
|
||||
mRelativeLayout.getMeasuredHeight());
|
||||
}
|
||||
stub.setOnLayoutInflatedListener(stub1 -> {
|
||||
mTime = stub1.findViewById(R.id.watch_time);
|
||||
mSgv = stub1.findViewById(R.id.sgv);
|
||||
mTimestamp = stub1.findViewById(R.id.timestamp);
|
||||
mDelta = stub1.findViewById(R.id.delta);
|
||||
mAvgDelta = stub1.findViewById(R.id.avgdelta);
|
||||
mRelativeLayout = stub1.findViewById(R.id.main_layout);
|
||||
chart = stub1.findViewById(R.id.chart);
|
||||
statusView = stub1.findViewById(R.id.aps_status);
|
||||
layoutSet = true;
|
||||
showAgeAndStatus();
|
||||
mRelativeLayout.measure(specW, specH);
|
||||
mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
|
||||
mRelativeLayout.getMeasuredHeight());
|
||||
});
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
rxBus.send(new EventWearToMobile(new EventData.ActionResendData("BIGChart:performViewSetup")));
|
||||
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;
|
||||
int extra = mSgv != null ? (mSgv.getRight() - mSgv.getLeft()) / 2 : 0;
|
||||
|
||||
if (tapType == TAP_TYPE_TAP&&
|
||||
x >=chart.getLeft() &&
|
||||
x <= chart.getRight()&&
|
||||
if (tapType == TAP_TYPE_TAP &&
|
||||
x >= chart.getLeft() &&
|
||||
x <= chart.getRight() &&
|
||||
y >= chart.getTop() &&
|
||||
y <= chart.getBottom()){
|
||||
if (eventTime - chartTapTime < 800){
|
||||
y <= chart.getBottom()) {
|
||||
if (eventTime - chartTapTime < 800) {
|
||||
changeChartTimeframe();
|
||||
}
|
||||
chartTapTime = eventTime;
|
||||
} else if (tapType == TAP_TYPE_TAP&&
|
||||
x + extra >=mSgv.getLeft() &&
|
||||
x - extra <= mSgv.getRight()&&
|
||||
} else if (tapType == TAP_TYPE_TAP &&
|
||||
x + extra >= mSgv.getLeft() &&
|
||||
x - extra <= mSgv.getRight() &&
|
||||
y >= mSgv.getTop() &&
|
||||
y <= mSgv.getBottom()){
|
||||
if (eventTime - sgvTapTime < 800){
|
||||
y <= mSgv.getBottom()) {
|
||||
if (eventTime - sgvTapTime < 800) {
|
||||
Intent intent = new Intent(this, MainMenuActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
|
@ -191,17 +230,17 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
}
|
||||
|
||||
private void changeChartTimeframe() {
|
||||
int timeframe = Integer.parseInt(sharedPrefs.getString("chart_timeframe", "3"));
|
||||
timeframe = (timeframe%5) + 1;
|
||||
sharedPrefs.edit().putString("chart_timeframe", "" + timeframe).apply();
|
||||
int timeframe = sp.getInt("chart_timeframe", 3);
|
||||
timeframe = (timeframe % 5) + 1;
|
||||
sp.putInt("chart_timeframe", timeframe);
|
||||
}
|
||||
|
||||
protected void onWatchModeChanged(WatchMode watchMode) {
|
||||
|
||||
if(lowResMode ^ isLowRes(watchMode)){ //if there was a change in lowResMode
|
||||
if (lowResMode ^ isLowRes(watchMode)) { //if there was a change in lowResMode
|
||||
lowResMode = isLowRes(watchMode);
|
||||
setColor();
|
||||
} else if (! sharedPrefs.getBoolean("dark", true)){
|
||||
} else if (!sp.getBoolean("dark", true)) {
|
||||
//in bright mode: different colours if active:
|
||||
setColor();
|
||||
}
|
||||
|
@ -213,14 +252,13 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
|
||||
|
||||
@Override
|
||||
protected WatchFaceStyle getWatchFaceStyle(){
|
||||
protected WatchFaceStyle getWatchFaceStyle() {
|
||||
return new WatchFaceStyle.Builder(this).setAcceptsTapEvents(true).build();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int ageLevel() {
|
||||
if(timeSince() <= (1000 * 60 * 12)) {
|
||||
if (timeSince() <= (1000 * 60 * 12)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -228,40 +266,30 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
}
|
||||
|
||||
public double timeSince() {
|
||||
return System.currentTimeMillis() - datetime;
|
||||
return System.currentTimeMillis() - singleBg.getTimeStamp();
|
||||
}
|
||||
|
||||
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");
|
||||
if (singleBg == null || singleBg.getTimeStamp() == 0) {
|
||||
return shortString ? "--'" : "-- Minute ago";
|
||||
}
|
||||
return minutesAgo + (shortString?"'":" Minutes 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);
|
||||
}
|
||||
disposable.clear();
|
||||
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) {
|
||||
if (layoutSet) {
|
||||
this.mRelativeLayout.draw(canvas);
|
||||
Log.d("onDraw", "draw");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -273,7 +301,7 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
mTime.setText(timeFormat.format(System.currentTimeMillis()));
|
||||
showAgeAndStatus();
|
||||
|
||||
if(ageLevel()<=0) {
|
||||
if (ageLevel() <= 0) {
|
||||
mSgv.setPaintFlags(mSgv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
|
||||
} else {
|
||||
mSgv.setPaintFlags(mSgv.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
|
||||
|
@ -286,173 +314,25 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
}
|
||||
}
|
||||
|
||||
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.getLong("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()));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 (!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");
|
||||
cobString = dataMap.getString("cob");
|
||||
|
||||
|
||||
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<DataMap> 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<DataMap> basals = dataMap.getDataMapArrayList("basals");
|
||||
if (basals != null) {
|
||||
basalWatchDataList = new ArrayList<>();
|
||||
for (DataMap basal : basals) {
|
||||
BasalWatchData bwd = new BasalWatchData();
|
||||
bwd.startTime = basal.getLong("starttime");
|
||||
bwd.endTime = basal.getLong("endtime");
|
||||
bwd.amount = basal.getDouble("amount");
|
||||
basalWatchDataList.add(bwd);
|
||||
}
|
||||
}
|
||||
ArrayList<DataMap> boluses = dataMap.getDataMapArrayList("boluses");
|
||||
if (boluses != null) {
|
||||
bolusWatchDataList = new ArrayList<>();
|
||||
for (DataMap bolus : boluses) {
|
||||
BolusWatchData bwd = new BolusWatchData();
|
||||
bwd.date = bolus.getLong("date");
|
||||
bwd.bolus = bolus.getDouble("bolus");
|
||||
bwd.carbs = bolus.getDouble("carbs");
|
||||
bwd.isSMB = bolus.getBoolean("isSMB");
|
||||
bwd.isValid = bolus.getBoolean("isValid");
|
||||
bolusWatchDataList.add(bwd);
|
||||
}
|
||||
}
|
||||
ArrayList<DataMap> predictions = dataMap.getDataMapArrayList("predictions");
|
||||
if (boluses != null) {
|
||||
predictionList = new ArrayList<>();
|
||||
for (DataMap prediction : predictions) {
|
||||
BgWatchData bwd = new BgWatchData();
|
||||
bwd.timestamp = prediction.getLong("timestamp");
|
||||
bwd.sgv = prediction.getDouble("sgv");
|
||||
bwd.color = prediction.getInt("color");
|
||||
predictionList.add(bwd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showAgeAndStatus() {
|
||||
|
||||
if( mTimestamp != null){
|
||||
if (mTimestamp != null) {
|
||||
mTimestamp.setText(readingAge(true));
|
||||
}
|
||||
|
||||
boolean showStatus = sharedPrefs.getBoolean("showExternalStatus", true);
|
||||
boolean showAvgDelta = sharedPrefs.getBoolean("showAvgDelta", true);
|
||||
boolean showStatus = sp.getBoolean("showExternalStatus", true);
|
||||
boolean showAvgDelta = sp.getBoolean("showAvgDelta", true);
|
||||
|
||||
if(showAvgDelta){
|
||||
if (showAvgDelta) {
|
||||
mAvgDelta.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mAvgDelta.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if(showStatus){
|
||||
String status = externalStatusString;
|
||||
if (sharedPrefs.getBoolean("show_cob", true)) {
|
||||
status = externalStatusString + " " + cobString;
|
||||
if (showStatus && status != null) {
|
||||
String status = this.status.getExternalStatus();
|
||||
if (sp.getBoolean("show_cob", true)) {
|
||||
status += " " + this.status.getCob();
|
||||
}
|
||||
|
||||
statusView.setText(status);
|
||||
|
@ -463,9 +343,9 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
}
|
||||
|
||||
public void setColor() {
|
||||
if(lowResMode){
|
||||
if (lowResMode) {
|
||||
setColorLowRes();
|
||||
} else if (sharedPrefs.getBoolean("dark", true)) {
|
||||
} else if (sp.getBoolean("dark", true)) {
|
||||
setColorDark();
|
||||
} else {
|
||||
setColorBright();
|
||||
|
@ -473,66 +353,6 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@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 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() {
|
||||
setIsAnimated(true);
|
||||
for (int i = 0; i <= 8 * 1000 / 40; i++) {
|
||||
updateRainbow();
|
||||
SystemClock.sleep(40);
|
||||
}
|
||||
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));
|
||||
|
@ -555,40 +375,41 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
}
|
||||
|
||||
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 (singleBg != null) {
|
||||
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 (singleBg.getSgvLevel() == 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 (singleBg.getSgvLevel() == 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 (singleBg.getSgvLevel() == -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));
|
||||
}
|
||||
if (ageLevel == 1) {
|
||||
mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_Timestamp));
|
||||
} else {
|
||||
mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_TimestampOld));
|
||||
}
|
||||
|
||||
if (chart != null) {
|
||||
highColor = ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor);
|
||||
lowColor = ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor);
|
||||
midColor = ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor);
|
||||
gridColour = ContextCompat.getColor(getApplicationContext(), R.color.dark_gridColor);
|
||||
basalBackgroundColor = ContextCompat.getColor(getApplicationContext(), R.color.basal_dark);
|
||||
basalCenterColor = ContextCompat.getColor(getApplicationContext(), R.color.basal_light);
|
||||
pointSize = 2;
|
||||
setupCharts();
|
||||
if (chart != null) {
|
||||
highColor = ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor);
|
||||
lowColor = ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor);
|
||||
midColor = ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor);
|
||||
gridColour = ContextCompat.getColor(getApplicationContext(), R.color.dark_gridColor);
|
||||
basalBackgroundColor = ContextCompat.getColor(getApplicationContext(), R.color.basal_dark);
|
||||
basalCenterColor = ContextCompat.getColor(getApplicationContext(), R.color.basal_light);
|
||||
pointSize = 2;
|
||||
setupCharts();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -598,15 +419,15 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
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) {
|
||||
if (singleBg.getSgvLevel() == 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) {
|
||||
} else if (singleBg.getSgvLevel() == 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) {
|
||||
} else if (singleBg.getSgvLevel() == -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));
|
||||
|
@ -636,61 +457,36 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
public void missedReadingAlert() {
|
||||
int minutes_since = (int) Math.floor(timeSince() / (1000 * 60));
|
||||
if (minutes_since >= 16 && ((minutes_since - 16) % 5) == 0) {
|
||||
DataLayerListenerService.Companion.requestData(this); // attempt endTime recover missing data
|
||||
// attempt endTime recover missing data
|
||||
rxBus.send(new EventWearToMobile(new EventData.ActionResendData("BIGChart:missedReadingAlert")));
|
||||
}
|
||||
}
|
||||
|
||||
public void addToWatchSet(DataMap dataMap) {
|
||||
|
||||
ArrayList<DataMap> entries = dataMap.getDataMapArrayList("entries");
|
||||
if (entries != null) {
|
||||
bgDataList = new ArrayList<BgWatchData>();
|
||||
for (DataMap entry : entries) {
|
||||
double sgv = entry.getDouble("sgvDouble");
|
||||
double high = entry.getDouble("high");
|
||||
double low = entry.getDouble("low");
|
||||
long timestamp = entry.getLong("timestamp");
|
||||
int color = entry.getInt("color", 0);
|
||||
bgDataList.add(new BgWatchData(sgv, high, low, timestamp, color));
|
||||
}
|
||||
public void addToWatchSet() {
|
||||
if (graphData != null) {
|
||||
bgDataList = graphData.getEntries();
|
||||
} else {
|
||||
double sgv = dataMap.getDouble("sgvDouble");
|
||||
double high = dataMap.getDouble("high");
|
||||
double low = dataMap.getDouble("low");
|
||||
long timestamp = dataMap.getLong("timestamp");
|
||||
int color = dataMap.getInt("color", 0);
|
||||
|
||||
final int size = bgDataList.size();
|
||||
if (size > 0) {
|
||||
if (bgDataList.get(size - 1).timestamp == timestamp)
|
||||
return; // Ignore duplicates.
|
||||
}
|
||||
|
||||
bgDataList.add(new BgWatchData(sgv, high, low, timestamp, color));
|
||||
}
|
||||
|
||||
for (int i = 0; i < bgDataList.size(); i++) {
|
||||
if (bgDataList.get(i).timestamp < (System.currentTimeMillis() - (1000 * 60 * 60 * 5))) {
|
||||
bgDataList.remove(i); //Get rid of anything more than 5 hours old
|
||||
break;
|
||||
}
|
||||
if (size > 0 && bgDataList.get(size - 1).getTimeStamp() == singleBg.getTimeStamp())
|
||||
return; // Ignore duplicates.
|
||||
bgDataList.add(singleBg);
|
||||
}
|
||||
}
|
||||
|
||||
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", "3"));
|
||||
if (bgDataList.size() > 0) {
|
||||
int timeframe = sp.getInt("chart_timeframe", 3);
|
||||
if (lowResMode) {
|
||||
bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), bgDataList, predictionList, tempWatchDataList, basalWatchDataList, bolusWatchDataList, pointSize, midColor, gridColour, basalBackgroundColor, basalCenterColor, bolusColor, carbsColor, timeframe);
|
||||
bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), bgDataList, treatmentData.getPredictions(), treatmentData.getTemps(), treatmentData.getBasals(), treatmentData.getBoluses(), pointSize, midColor, gridColour, basalBackgroundColor, basalCenterColor, bolusColor, carbsColor, timeframe);
|
||||
} else {
|
||||
bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), bgDataList, predictionList, tempWatchDataList, basalWatchDataList, bolusWatchDataList, pointSize, highColor, lowColor, midColor, gridColour, basalBackgroundColor, basalCenterColor, bolusColor, carbsColor, timeframe);
|
||||
bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), bgDataList, treatmentData.getPredictions(), treatmentData.getTemps(), treatmentData.getBasals(), treatmentData.getBoluses(), pointSize, highColor, lowColor, midColor, gridColour, basalBackgroundColor, basalCenterColor, bolusColor, carbsColor, timeframe);
|
||||
}
|
||||
|
||||
chart.setLineChartData(bgGraphBuilder.lineData());
|
||||
chart.setViewportCalculationEnabled(true);
|
||||
chart.setMaximumViewport(chart.getMaximumViewport());
|
||||
} else {
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
rxBus.send(new EventWearToMobile(new EventData.ActionResendData("BIGChart:setupCharts")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import android.content.BroadcastReceiver;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
|
@ -15,7 +14,6 @@ import android.graphics.Typeface;
|
|||
import android.os.BatteryManager;
|
||||
import android.os.PowerManager;
|
||||
import android.os.Vibrator;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.wearable.view.WatchViewStub;
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.Display;
|
||||
|
@ -28,15 +26,14 @@ import android.widget.RelativeLayout;
|
|||
import android.widget.TextView;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
import com.ustwo.clockwise.common.WatchFaceTime;
|
||||
import com.ustwo.clockwise.common.WatchMode;
|
||||
import com.ustwo.clockwise.common.WatchShape;
|
||||
import com.ustwo.clockwise.wearable.WatchFace;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -44,12 +41,17 @@ import javax.inject.Inject;
|
|||
|
||||
import dagger.android.AndroidInjection;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.data.RawDisplayData;
|
||||
import info.nightscout.androidaps.events.EventWearPreferenceChange;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.utils.Persistence;
|
||||
import info.nightscout.androidaps.interaction.utils.WearUtil;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
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 io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
import lecho.lib.hellocharts.view.LineChartView;
|
||||
|
||||
/**
|
||||
|
@ -58,20 +60,27 @@ import lecho.lib.hellocharts.view.LineChartView;
|
|||
* Refactored by dlvoy on 2019-11-2019
|
||||
*/
|
||||
|
||||
public abstract class BaseWatchFace extends WatchFace implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public abstract class BaseWatchFace extends WatchFace {
|
||||
|
||||
@Inject WearUtil wearUtil;
|
||||
@Inject Persistence persistence;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject RxBus rxBus;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
@Inject SP sp;
|
||||
|
||||
public final static IntentFilter INTENT_FILTER;
|
||||
CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
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);
|
||||
}
|
||||
protected EventData.SingleBg singleBg = new EventData.SingleBg(0, "---", "-", "--", "--", "--"
|
||||
, 0, 0.0, 0.0, 0.0, 0);
|
||||
protected EventData.Status status = new EventData.Status("no status", "IOB", "-.--", false, "--g", "-.--U/h", "--", "--", -1, "--", false, 1);
|
||||
protected EventData.TreatmentData treatmentData = new EventData.TreatmentData(
|
||||
new ArrayList<>(),
|
||||
new ArrayList<>(),
|
||||
new ArrayList<>(),
|
||||
new ArrayList<>()
|
||||
);
|
||||
protected EventData.GraphData graphData = new EventData.GraphData(new ArrayList<>());
|
||||
|
||||
static IntentFilter iFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
|
||||
|
||||
|
@ -96,7 +105,6 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
public int pointSize = 2;
|
||||
public BgGraphBuilder bgGraphBuilder;
|
||||
public LineChartView chart;
|
||||
public RawDisplayData rawData;
|
||||
public PowerManager.WakeLock wakeLock;
|
||||
// related endTime manual layout
|
||||
public View layoutView;
|
||||
|
@ -104,9 +112,6 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
public boolean forceSquareCanvas = false; // Set to true by the Steampunk watch face.
|
||||
public String sMinute = "0";
|
||||
public String sHour = "0";
|
||||
protected SharedPreferences sharedPrefs;
|
||||
private LocalBroadcastManager localBroadcastManager;
|
||||
private MessageReceiver messageReceiver;
|
||||
private BroadcastReceiver batteryReceiver;
|
||||
private int colorDarkHigh, colorDarkMid, colorDarkLow;
|
||||
private java.text.DateFormat timeFormat;
|
||||
|
@ -126,7 +131,6 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
colorDarkMid = ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor);
|
||||
colorDarkLow = ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor);
|
||||
|
||||
rawData = new RawDisplayData(wearUtil);
|
||||
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
|
||||
display.getSize(displaySize);
|
||||
wakeLock = ((PowerManager) getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS:BaseWatchFace");
|
||||
|
@ -137,8 +141,49 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
} else {
|
||||
specH = View.MeasureSpec.makeMeasureSpec(displaySize.y, View.MeasureSpec.EXACTLY);
|
||||
}
|
||||
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
sharedPrefs.registerOnSharedPreferenceChangeListener(this);
|
||||
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventWearPreferenceChange.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> {
|
||||
setupBatteryReceiver();
|
||||
if (event.getChangedKey() != null && event.getChangedKey().equals("delta_granularity"))
|
||||
rxBus.send(new EventWearToMobile(new EventData.ActionResendData("BaseWatchFace:onSharedPreferenceChanged")));
|
||||
if (layoutSet) setDataFields();
|
||||
invalidate();
|
||||
})
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.SingleBg.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> singleBg = event)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.TreatmentData.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> treatmentData = event)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.GraphData.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> graphData = event)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.Status.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> {
|
||||
// this event is received as last batch of data
|
||||
if (isSimpleUi()) {
|
||||
if (needUpdate()) {
|
||||
invalidate();
|
||||
}
|
||||
} else {
|
||||
setupCharts();
|
||||
setDataFields();
|
||||
invalidate();
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
persistence.turnOff();
|
||||
|
||||
|
@ -148,7 +193,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
private void setupBatteryReceiver() {
|
||||
String setting = sharedPrefs.getString("simplify_ui", "off");
|
||||
String setting = sp.getString("simplify_ui", "off");
|
||||
if ((setting.equals("charging") || setting.equals("ambient_charging")) && batteryReceiver == null) {
|
||||
IntentFilter intentBatteryFilter = new IntentFilter();
|
||||
intentBatteryFilter.addAction(BatteryManager.ACTION_CHARGING);
|
||||
|
@ -215,11 +260,6 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
|
||||
public void performViewSetup() {
|
||||
final WatchViewStub layoutStub = 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);
|
||||
|
||||
layoutStub.setOnLayoutInflatedListener((WatchViewStub stub) -> {
|
||||
mTime = stub.findViewById(R.id.watch_time);
|
||||
|
@ -274,11 +314,11 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
public double timeSince() {
|
||||
return System.currentTimeMillis() - rawData.datetime;
|
||||
return System.currentTimeMillis() - singleBg.getTimeStamp();
|
||||
}
|
||||
|
||||
public String readingAge(boolean shortString) {
|
||||
if (rawData.datetime == 0) {
|
||||
if (singleBg.getTimeStamp() == 0) {
|
||||
return shortString ? "--" : "-- Minute ago";
|
||||
}
|
||||
int minutesAgo = (int) Math.floor(timeSince() / (1000 * 60));
|
||||
|
@ -290,12 +330,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (localBroadcastManager != null && messageReceiver != null) {
|
||||
localBroadcastManager.unregisterReceiver(messageReceiver);
|
||||
}
|
||||
if (sharedPrefs != null) {
|
||||
sharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
disposable.clear();
|
||||
if (batteryReceiver != null) {
|
||||
unregisterReceiver(batteryReceiver);
|
||||
}
|
||||
|
@ -326,16 +361,16 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
float xHalf = displaySize.x / 2f;
|
||||
float yThird = displaySize.y / 3f;
|
||||
|
||||
boolean isOutdated = rawData.datetime > 0 && ageLevel() <= 0;
|
||||
boolean isOutdated = singleBg.getTimeStamp() > 0 && ageLevel() <= 0;
|
||||
mSvgPaint.setStrikeThruText(isOutdated);
|
||||
|
||||
mSvgPaint.setColor(getBgColour(rawData.sgvLevel));
|
||||
mDirectionPaint.setColor(getBgColour(rawData.sgvLevel));
|
||||
mSvgPaint.setColor(getBgColour(singleBg.getSgvLevel()));
|
||||
mDirectionPaint.setColor(getBgColour(singleBg.getSgvLevel()));
|
||||
|
||||
String sSvg = rawData.sSgv;
|
||||
String sSvg = singleBg.getSgvString();
|
||||
float svgWidth = mSvgPaint.measureText(sSvg);
|
||||
|
||||
String sDirection = " " + rawData.sDirection + "\uFE0E";
|
||||
String sDirection = " " + singleBg.getSgvString() + "\uFE0E";
|
||||
float directionWidth = mDirectionPaint.measureText(sDirection);
|
||||
|
||||
float xSvg = xHalf - (svgWidth + directionWidth) / 2;
|
||||
|
@ -382,7 +417,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
private void checkVibrateHourly(WatchFaceTime oldTime, WatchFaceTime newTime) {
|
||||
boolean hourlyVibratePref = sharedPrefs.getBoolean("vibrate_Hourly", false);
|
||||
boolean hourlyVibratePref = sp.getBoolean("vibrate_Hourly", false);
|
||||
if (hourlyVibratePref && layoutSet && newTime.hasHourChanged(oldTime)) {
|
||||
aapsLogger.info(LTag.WEAR, "hourlyVibratePref", "true --> " + newTime);
|
||||
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
|
||||
|
@ -394,8 +429,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
public void setDataFields() {
|
||||
setDateAndTime();
|
||||
if (mSgv != null) {
|
||||
if (sharedPrefs.getBoolean("showBG", true)) {
|
||||
mSgv.setText(rawData.sSgv);
|
||||
if (sp.getBoolean("showBG", true)) {
|
||||
mSgv.setText(singleBg.getSgvString());
|
||||
mSgv.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
// Leave the textview there but invisible, as a height holder for the empty space above the white line
|
||||
|
@ -407,8 +442,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
strikeThroughSgvIfNeeded();
|
||||
|
||||
if (mDirection != null) {
|
||||
if (sharedPrefs.getBoolean("show_direction", true)) {
|
||||
mDirection.setText(rawData.sDirection + "\uFE0E");
|
||||
if (sp.getBoolean("show_direction", true)) {
|
||||
mDirection.setText(singleBg.getSgvString() + "\uFE0E");
|
||||
mDirection.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mDirection.setVisibility(View.GONE);
|
||||
|
@ -416,8 +451,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
if (mDelta != null) {
|
||||
if (sharedPrefs.getBoolean("showDelta", true)) {
|
||||
mDelta.setText(rawData.sDelta);
|
||||
if (sp.getBoolean("showDelta", true)) {
|
||||
mDelta.setText(singleBg.getDelta());
|
||||
mDelta.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mDelta.setVisibility(View.GONE);
|
||||
|
@ -425,8 +460,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
if (mAvgDelta != null) {
|
||||
if (sharedPrefs.getBoolean("showAvgDelta", true)) {
|
||||
mAvgDelta.setText(rawData.sAvgDelta);
|
||||
if (sp.getBoolean("showAvgDelta", true)) {
|
||||
mAvgDelta.setText(singleBg.getAvgDelta());
|
||||
mAvgDelta.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mAvgDelta.setVisibility(View.GONE);
|
||||
|
@ -434,8 +469,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
if (mCOB1 != null && mCOB2 != null) {
|
||||
mCOB2.setText(rawData.sCOB2);
|
||||
if (sharedPrefs.getBoolean("show_cob", true)) {
|
||||
mCOB2.setText(status.getCob());
|
||||
if (sp.getBoolean("show_cob", true)) {
|
||||
mCOB1.setVisibility(View.VISIBLE);
|
||||
mCOB2.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
|
@ -444,8 +479,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
// Deal with cases where there is only the value shown for COB, and not the label
|
||||
} else if (mCOB2 != null) {
|
||||
mCOB2.setText(rawData.sCOB2);
|
||||
if (sharedPrefs.getBoolean("show_cob", true)) {
|
||||
mCOB2.setText(status.getCob());
|
||||
if (sp.getBoolean("show_cob", true)) {
|
||||
mCOB2.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mCOB2.setVisibility(View.GONE);
|
||||
|
@ -453,15 +488,15 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
if (mIOB1 != null && mIOB2 != null) {
|
||||
if (sharedPrefs.getBoolean("show_iob", true)) {
|
||||
if (sp.getBoolean("show_iob", true)) {
|
||||
mIOB1.setVisibility(View.VISIBLE);
|
||||
mIOB2.setVisibility(View.VISIBLE);
|
||||
if (rawData.detailedIOB) {
|
||||
mIOB1.setText(rawData.sIOB1);
|
||||
mIOB2.setText(rawData.sIOB2);
|
||||
if (status.getDetailedIob()) {
|
||||
mIOB1.setText(status.getIobSum());
|
||||
mIOB2.setText(status.getIobDetail());
|
||||
} else {
|
||||
mIOB1.setText(getString(R.string.activity_IOB));
|
||||
mIOB2.setText(rawData.sIOB1);
|
||||
mIOB2.setText(status.getIobSum());
|
||||
}
|
||||
} else {
|
||||
mIOB1.setVisibility(View.GONE);
|
||||
|
@ -469,12 +504,12 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
// Deal with cases where there is only the value shown for IOB, and not the label
|
||||
} else if (mIOB2 != null) {
|
||||
if (sharedPrefs.getBoolean("show_iob", true)) {
|
||||
if (sp.getBoolean("show_iob", true)) {
|
||||
mIOB2.setVisibility(View.VISIBLE);
|
||||
if (rawData.detailedIOB) {
|
||||
mIOB2.setText(rawData.sIOB2);
|
||||
if (status.getDetailedIob()) {
|
||||
mIOB2.setText(status.getIobDetail());
|
||||
} else {
|
||||
mIOB2.setText(rawData.sIOB1);
|
||||
mIOB2.setText(status.getIobSum());
|
||||
}
|
||||
} else {
|
||||
mIOB2.setText("");
|
||||
|
@ -482,11 +517,11 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
if (mTimestamp != null) {
|
||||
if (sharedPrefs.getBoolean("showAgo", true)) {
|
||||
if (sp.getBoolean("showAgo", true)) {
|
||||
if (isAAPSv2 != null) {
|
||||
mTimestamp.setText(readingAge(true));
|
||||
} else {
|
||||
boolean shortString = sharedPrefs.getBoolean("showExternalStatus", true);
|
||||
boolean shortString = sp.getBoolean("showExternalStatus", true);
|
||||
mTimestamp.setText(readingAge(shortString));
|
||||
}
|
||||
mTimestamp.setVisibility(View.VISIBLE);
|
||||
|
@ -496,15 +531,15 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
if (mUploaderBattery != null) {
|
||||
if (sharedPrefs.getBoolean("show_uploader_battery", true)) {
|
||||
if (sp.getBoolean("show_uploader_battery", true)) {
|
||||
if (isAAPSv2 != null) {
|
||||
mUploaderBattery.setText(rawData.sUploaderBattery + "%");
|
||||
mUploaderBattery.setText(status.getBattery() + "%");
|
||||
mUploaderBattery.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
if (sharedPrefs.getBoolean("showExternalStatus", true)) {
|
||||
mUploaderBattery.setText("U: " + rawData.sUploaderBattery + "%");
|
||||
if (sp.getBoolean("showExternalStatus", true)) {
|
||||
mUploaderBattery.setText("U: " + status.getBattery() + "%");
|
||||
} else {
|
||||
mUploaderBattery.setText("Uploader: " + rawData.sUploaderBattery + "%");
|
||||
mUploaderBattery.setText("Uploader: " + status.getBattery() + "%");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -513,8 +548,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
if (mRigBattery != null) {
|
||||
if (sharedPrefs.getBoolean("show_rig_battery", false)) {
|
||||
mRigBattery.setText(rawData.sRigBattery);
|
||||
if (sp.getBoolean("show_rig_battery", false)) {
|
||||
mRigBattery.setText(status.getRigBattery());
|
||||
mRigBattery.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mRigBattery.setVisibility(View.GONE);
|
||||
|
@ -522,8 +557,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
if (mBasalRate != null) {
|
||||
if (sharedPrefs.getBoolean("show_temp_basal", true)) {
|
||||
mBasalRate.setText(rawData.sBasalRate);
|
||||
if (sp.getBoolean("show_temp_basal", true)) {
|
||||
mBasalRate.setText(status.getCurrentBasal());
|
||||
mBasalRate.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mBasalRate.setVisibility(View.GONE);
|
||||
|
@ -531,8 +566,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
if (mBgi != null) {
|
||||
if (rawData.showBGI) {
|
||||
mBgi.setText(rawData.sBgi);
|
||||
if (status.getShowBgi()) {
|
||||
mBgi.setText(status.getBgi());
|
||||
mBgi.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mBgi.setVisibility(View.GONE);
|
||||
|
@ -540,8 +575,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
if (mStatus != null) {
|
||||
if (sharedPrefs.getBoolean("showExternalStatus", true)) {
|
||||
mStatus.setText(rawData.externalStatusString);
|
||||
if (sp.getBoolean("showExternalStatus", true)) {
|
||||
mStatus.setText(status.getExternalStatus());
|
||||
mStatus.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mStatus.setVisibility(View.GONE);
|
||||
|
@ -549,10 +584,10 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
if (mLoop != null) {
|
||||
if (sharedPrefs.getBoolean("showExternalStatus", true)) {
|
||||
if (sp.getBoolean("showExternalStatus", true)) {
|
||||
mLoop.setVisibility(View.VISIBLE);
|
||||
if (rawData.openApsStatus != -1) {
|
||||
int mins = (int) ((System.currentTimeMillis() - rawData.openApsStatus) / 1000 / 60);
|
||||
if (status.getOpenApsStatus() != -1) {
|
||||
int mins = (int) ((System.currentTimeMillis() - status.getOpenApsStatus()) / 1000 / 60);
|
||||
mLoop.setText(mins + "'");
|
||||
if (mins > 14) {
|
||||
loopLevel = 0;
|
||||
|
@ -605,7 +640,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
if (mDate != null && mDay != null && mMonth != null) {
|
||||
if (sharedPrefs.getBoolean("show_date", false)) {
|
||||
if (sp.getBoolean("show_date", false)) {
|
||||
if (mDayName != null) {
|
||||
mDayName.setText(sdfDayName.format(mDateTime));
|
||||
}
|
||||
|
@ -620,10 +655,10 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
public void setColor() {
|
||||
dividerMatchesBg = sharedPrefs.getBoolean("match_divider", false);
|
||||
dividerMatchesBg = sp.getBoolean("match_divider", false);
|
||||
if (lowResMode) {
|
||||
setColorLowRes();
|
||||
} else if (sharedPrefs.getBoolean("dark", true)) {
|
||||
} else if (sp.getBoolean("dark", true)) {
|
||||
setColorDark();
|
||||
} else {
|
||||
setColorBright();
|
||||
|
@ -632,8 +667,8 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
|
||||
public void strikeThroughSgvIfNeeded() {
|
||||
if (mSgv != null) {
|
||||
if (sharedPrefs.getBoolean("showBG", true)) {
|
||||
if (ageLevel() <= 0 && rawData.datetime > 0) {
|
||||
if (sp.getBoolean("showBG", true)) {
|
||||
if (ageLevel() <= 0 && singleBg.getTimeStamp() > 0) {
|
||||
mSgv.setPaintFlags(mSgv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
|
||||
} else {
|
||||
mSgv.setPaintFlags(mSgv.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
|
||||
|
@ -664,7 +699,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
|
||||
private boolean isSimpleUi() {
|
||||
String simplify = sharedPrefs.getString("simplify_ui", "off");
|
||||
String simplify = sp.getString("simplify_ui", "off");
|
||||
if (simplify.equals("off")) {
|
||||
return false;
|
||||
}
|
||||
|
@ -674,18 +709,6 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
return (simplify.equals("charging") || simplify.equals("ambient_charging")) && isCharging();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
setupBatteryReceiver();
|
||||
if ("delta_granularity".equals(key)) {
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
}
|
||||
if (layoutSet) {
|
||||
setDataFields();
|
||||
}
|
||||
invalidate();
|
||||
}
|
||||
|
||||
protected abstract void setColorDark();
|
||||
|
||||
protected abstract void setColorBright();
|
||||
|
@ -694,8 +717,9 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
|
||||
public void missedReadingAlert() {
|
||||
int minutes_since = (int) Math.floor(timeSince() / (1000 * 60));
|
||||
if (rawData.datetime == 0 || minutes_since >= 16 && ((minutes_since - 16) % 5) == 0) {
|
||||
DataLayerListenerService.Companion.requestData(this); // Attempt endTime recover missing data
|
||||
if (singleBg.getTimeStamp() == 0 || minutes_since >= 16 && ((minutes_since - 16) % 5) == 0) {
|
||||
// Attempt endTime recover missing data
|
||||
rxBus.send(new EventWearToMobile(new EventData.ActionResendData("BaseWatchFace:missedReadingAlert")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -703,12 +727,12 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
if (isSimpleUi()) {
|
||||
return;
|
||||
}
|
||||
if (rawData.bgDataList.size() > 0) { // Dont crash things just because we dont have values, people dont like crashy things
|
||||
int timeframe = Integer.parseInt(sharedPrefs.getString("chart_timeframe", "3"));
|
||||
if (chart != null && graphData.getEntries().size() > 0) {
|
||||
int timeframe = sp.getInt("chart_timeframe", 3);
|
||||
if (lowResMode) {
|
||||
bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), rawData, pointSize, midColor, gridColor, basalBackgroundColor, basalCenterColor, bolusColor, Color.GREEN, timeframe);
|
||||
bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), graphData.getEntries(), treatmentData.getPredictions(), treatmentData.getTemps(), treatmentData.getBasals(), treatmentData.getBoluses(), pointSize, midColor, gridColor, basalBackgroundColor, basalCenterColor, bolusColor, Color.GREEN, timeframe);
|
||||
} else {
|
||||
bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), rawData, pointSize, highColor, lowColor, midColor, gridColor, basalBackgroundColor, basalCenterColor, bolusColor, Color.GREEN, timeframe);
|
||||
bgGraphBuilder = new BgGraphBuilder(getApplicationContext(), graphData.getEntries(), treatmentData.getPredictions(), treatmentData.getTemps(), treatmentData.getBasals(), treatmentData.getBoluses(), pointSize, highColor, lowColor, midColor, gridColor, basalBackgroundColor, basalCenterColor, bolusColor, Color.GREEN, timeframe);
|
||||
}
|
||||
|
||||
chart.setLineChartData(bgGraphBuilder.lineData());
|
||||
|
@ -717,39 +741,12 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
}
|
||||
}
|
||||
|
||||
public class MessageReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
PowerManager.WakeLock wl = wearUtil.getWakeLock("readingPrefs", 50);
|
||||
|
||||
final DataMap dataMap = rawData.updateDataFromMessage(intent, wakeLock);
|
||||
if (chart != null && dataMap != null) {
|
||||
rawData.addToWatchSet(dataMap);
|
||||
setupCharts();
|
||||
}
|
||||
rawData.updateStatusFromMessage(intent, wakeLock);
|
||||
rawData.updateBasalsFromMessage(intent);
|
||||
|
||||
if (isSimpleUi()) {
|
||||
if (needUpdate()) {
|
||||
invalidate();
|
||||
}
|
||||
} else {
|
||||
setupCharts();
|
||||
setDataFields();
|
||||
invalidate();
|
||||
}
|
||||
wearUtil.releaseWakeLock(wl);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean needUpdate() {
|
||||
if (mLastSvg.equals(rawData.sSgv) && mLastDirection.equals(rawData.sDirection)) {
|
||||
if (mLastSvg.equals(singleBg.getSgvString()) && mLastDirection.equals(singleBg.getSgvString())) {
|
||||
return false;
|
||||
}
|
||||
mLastSvg = rawData.sSgv;
|
||||
mLastDirection = rawData.sDirection;
|
||||
mLastSvg = singleBg.getSgvString();
|
||||
mLastDirection = singleBg.getSgvString();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,17 +14,12 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import info.nightscout.androidaps.data.BasalWatchData;
|
||||
import info.nightscout.androidaps.data.BgWatchData;
|
||||
import info.nightscout.androidaps.data.BolusWatchData;
|
||||
import info.nightscout.androidaps.data.RawDisplayData;
|
||||
import info.nightscout.androidaps.data.TempWatchData;
|
||||
import info.nightscout.shared.weardata.EventData;
|
||||
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 emmablack on 11/15/14.
|
||||
|
@ -33,10 +28,10 @@ public class BgGraphBuilder {
|
|||
public static final double MAX_PREDICTION__TIME_RATIO = (3d / 5);
|
||||
public static final double UPPER_CUTOFF_SGV = 400;
|
||||
private final long predictionEndTime;
|
||||
private final List<BgWatchData> predictionsList;
|
||||
private final ArrayList<BolusWatchData> bolusWatchDataList;
|
||||
private final ArrayList<BasalWatchData> basalWatchDataList;
|
||||
public List<TempWatchData> tempWatchDataList;
|
||||
private final List<EventData.SingleBg> predictionsList;
|
||||
private final ArrayList<EventData.TreatmentData.Treatment> bolusWatchDataList;
|
||||
private final ArrayList<EventData.TreatmentData.Basal> basalWatchDataList;
|
||||
public List<EventData.TreatmentData.TempBasal> tempWatchDataList;
|
||||
private final int timespan;
|
||||
public long end_time;
|
||||
public long start_time;
|
||||
|
@ -44,7 +39,7 @@ public class BgGraphBuilder {
|
|||
public Context context;
|
||||
public double highMark;
|
||||
public double lowMark;
|
||||
public List<BgWatchData> bgDataList = new ArrayList<BgWatchData>();
|
||||
public List<EventData.SingleBg> bgDataList;
|
||||
|
||||
public int pointSize;
|
||||
public int highColor;
|
||||
|
@ -58,20 +53,24 @@ public class BgGraphBuilder {
|
|||
|
||||
public boolean singleLine = false;
|
||||
|
||||
private final List<PointValue> inRangeValues = new ArrayList<PointValue>();
|
||||
private final List<PointValue> highValues = new ArrayList<PointValue>();
|
||||
private final List<PointValue> lowValues = new ArrayList<PointValue>();
|
||||
public Viewport viewport;
|
||||
|
||||
private final List<PointValue> inRangeValues = new ArrayList<>();
|
||||
private final List<PointValue> highValues = new ArrayList<>();
|
||||
private final List<PointValue> lowValues = new ArrayList<>();
|
||||
|
||||
//used for low resolution screen.
|
||||
public BgGraphBuilder(Context context, List<BgWatchData> aBgList, List<BgWatchData> predictionsList, List<TempWatchData> tempWatchDataList, ArrayList<BasalWatchData> basalWatchDataList, ArrayList<BolusWatchData> bolusWatchDataList, int aPointSize, int aMidColor, int gridColour, int basalBackgroundColor, int basalCenterColor, int bolusInvalidColor, int carbsColor, int timespan) {
|
||||
this.start_time = System.currentTimeMillis() - (1000 * 60 * 60 * timespan); //timespan hours ago
|
||||
public BgGraphBuilder(Context context, List<EventData.SingleBg> aBgList,
|
||||
List<EventData.SingleBg> predictionsList,
|
||||
List<EventData.TreatmentData.TempBasal> tempWatchDataList,
|
||||
ArrayList<EventData.TreatmentData.Basal> basalWatchDataList,
|
||||
ArrayList<EventData.TreatmentData.Treatment> bolusWatchDataList,
|
||||
int aPointSize, int aMidColor, int gridColour, int basalBackgroundColor, int basalCenterColor, int bolusInvalidColor, int carbsColor, int timespan) {
|
||||
this.start_time = System.currentTimeMillis() - (1000L * 60 * 60 * timespan); //timespan
|
||||
// hours ago
|
||||
this.bgDataList = aBgList;
|
||||
this.predictionsList = predictionsList;
|
||||
this.context = context;
|
||||
this.highMark = aBgList.get(aBgList.size() - 1).high;
|
||||
this.lowMark = aBgList.get(aBgList.size() - 1).low;
|
||||
this.highMark = aBgList.get(aBgList.size() - 1).getHigh();
|
||||
this.lowMark = aBgList.get(aBgList.size() - 1).getLow();
|
||||
this.pointSize = aPointSize;
|
||||
this.singleLine = false;
|
||||
this.midColor = aMidColor;
|
||||
|
@ -80,24 +79,31 @@ public class BgGraphBuilder {
|
|||
this.timespan = timespan;
|
||||
this.tempWatchDataList = tempWatchDataList;
|
||||
this.basalWatchDataList = basalWatchDataList;
|
||||
this.bolusWatchDataList = (bolusWatchDataList!=null)?bolusWatchDataList:new ArrayList<BolusWatchData>();
|
||||
this.bolusWatchDataList = (bolusWatchDataList != null) ? bolusWatchDataList : new ArrayList<>();
|
||||
this.gridColour = gridColour;
|
||||
this.basalCenterColor = basalCenterColor;
|
||||
this.basalBackgroundColor = basalBackgroundColor;
|
||||
this.bolusInvalidColor = bolusInvalidColor;
|
||||
this.carbsColor = carbsColor;
|
||||
this.end_time = System.currentTimeMillis() + (1000 * 60 * 6 * timespan); //Now plus 30 minutes padding (for 5 hours. Less if less.)
|
||||
this.end_time = System.currentTimeMillis() + (1000L * 60 * 6 * timespan); //Now plus 30
|
||||
// minutes padding (for 5 hours. Less if less.)
|
||||
this.predictionEndTime = getPredictionEndTime();
|
||||
this.end_time = (predictionEndTime>end_time)?predictionEndTime:end_time;
|
||||
this.end_time = Math.max(predictionEndTime, end_time);
|
||||
}
|
||||
|
||||
public BgGraphBuilder(Context context, List<BgWatchData> aBgList, List<BgWatchData> predictionsList, List<TempWatchData> tempWatchDataList, ArrayList<BasalWatchData> basalWatchDataList, ArrayList<BolusWatchData> bolusWatchDataList, int aPointSize, int aHighColor, int aLowColor, int aMidColor, int gridColour, int basalBackgroundColor, int basalCenterColor, int bolusInvalidColor, int carbsColor, int timespan) {
|
||||
this.start_time = System.currentTimeMillis() - (1000 * 60 * 60 * timespan); //timespan hours ago
|
||||
public BgGraphBuilder(Context context, List<EventData.SingleBg> aBgList,
|
||||
List<EventData.SingleBg> predictionsList,
|
||||
List<EventData.TreatmentData.TempBasal> tempWatchDataList,
|
||||
ArrayList<EventData.TreatmentData.Basal> basalWatchDataList,
|
||||
ArrayList<EventData.TreatmentData.Treatment> bolusWatchDataList,
|
||||
int aPointSize, int aHighColor, int aLowColor, int aMidColor, int gridColour, int basalBackgroundColor, int basalCenterColor, int bolusInvalidColor, int carbsColor, int timespan) {
|
||||
this.start_time = System.currentTimeMillis() - (1000L * 60 * 60 * timespan); //timespan
|
||||
// hours ago
|
||||
this.bgDataList = aBgList;
|
||||
this.predictionsList = predictionsList;
|
||||
this.context = context;
|
||||
this.highMark = aBgList.get(aBgList.size() - 1).high;
|
||||
this.lowMark = aBgList.get(aBgList.size() - 1).low;
|
||||
this.highMark = aBgList.get(aBgList.size() - 1).getHigh();
|
||||
this.lowMark = aBgList.get(aBgList.size() - 1).getLow();
|
||||
this.pointSize = aPointSize;
|
||||
this.highColor = aHighColor;
|
||||
this.lowColor = aLowColor;
|
||||
|
@ -105,51 +111,16 @@ public class BgGraphBuilder {
|
|||
this.timespan = timespan;
|
||||
this.tempWatchDataList = tempWatchDataList;
|
||||
this.basalWatchDataList = basalWatchDataList;
|
||||
this.bolusWatchDataList = (bolusWatchDataList!=null)?bolusWatchDataList:new ArrayList<BolusWatchData>();
|
||||
this.bolusWatchDataList = (bolusWatchDataList != null) ? bolusWatchDataList : new ArrayList<>();
|
||||
this.gridColour = gridColour;
|
||||
this.basalCenterColor = basalCenterColor;
|
||||
this.basalBackgroundColor = basalBackgroundColor;
|
||||
this.bolusInvalidColor = bolusInvalidColor;
|
||||
this.carbsColor = carbsColor;
|
||||
this.end_time = System.currentTimeMillis() + (1000 * 60 * 6 * timespan); //Now plus 30 minutes padding (for 5 hours. Less if less.)
|
||||
this.end_time = System.currentTimeMillis() + (1000L * 60 * 6 * timespan); //Now plus 30
|
||||
// minutes padding (for 5 hours. Less if less.)
|
||||
this.predictionEndTime = getPredictionEndTime();
|
||||
this.end_time = (predictionEndTime>end_time)?predictionEndTime:end_time;
|
||||
}
|
||||
|
||||
public BgGraphBuilder(Context context, RawDisplayData raw, int aPointSize, int aHighColor, int aLowColor, int aMidColor, int gridColour, int basalBackgroundColor, int basalCenterColor, int bolusInvalidColor, int carbsColor, int timespan) {
|
||||
this(context,
|
||||
raw.bgDataList,
|
||||
raw.predictionList,
|
||||
raw.tempWatchDataList,
|
||||
raw.basalWatchDataList,
|
||||
raw.bolusWatchDataList,
|
||||
aPointSize,
|
||||
aHighColor,
|
||||
aLowColor,
|
||||
aMidColor,
|
||||
gridColour,
|
||||
basalBackgroundColor,
|
||||
basalCenterColor,
|
||||
bolusInvalidColor,
|
||||
carbsColor,
|
||||
timespan);
|
||||
}
|
||||
|
||||
public BgGraphBuilder(Context context, RawDisplayData raw, int aPointSize, int aMidColor, int gridColour, int basalBackgroundColor, int basalCenterColor, int bolusInvalidColor, int carbsColor, int timespan) {
|
||||
this(context,
|
||||
raw.bgDataList,
|
||||
raw.predictionList,
|
||||
raw.tempWatchDataList,
|
||||
raw.basalWatchDataList,
|
||||
raw.bolusWatchDataList,
|
||||
aPointSize,
|
||||
aMidColor,
|
||||
gridColour,
|
||||
basalBackgroundColor,
|
||||
basalCenterColor,
|
||||
bolusInvalidColor,
|
||||
carbsColor,
|
||||
timespan);
|
||||
this.end_time = Math.max(predictionEndTime, end_time);
|
||||
}
|
||||
|
||||
public LineChartData lineData() {
|
||||
|
@ -162,7 +133,7 @@ public class BgGraphBuilder {
|
|||
public List<Line> defaultLines() {
|
||||
|
||||
addBgReadingValues();
|
||||
List<Line> lines = new ArrayList<Line>();
|
||||
List<Line> lines = new ArrayList<>();
|
||||
lines.add(highLine());
|
||||
lines.add(lowLine());
|
||||
lines.add(inRangeValuesLine());
|
||||
|
@ -172,41 +143,41 @@ public class BgGraphBuilder {
|
|||
double minChart = lowMark;
|
||||
double maxChart = highMark;
|
||||
|
||||
for ( BgWatchData bgd:bgDataList) {
|
||||
if(bgd.sgv > maxChart){
|
||||
maxChart = bgd.sgv;
|
||||
for (EventData.SingleBg bgd : bgDataList) {
|
||||
if (bgd.getSgv() > maxChart) {
|
||||
maxChart = bgd.getSgv();
|
||||
}
|
||||
if(bgd.sgv < minChart){
|
||||
minChart = bgd.sgv;
|
||||
if (bgd.getSgv() < minChart) {
|
||||
minChart = bgd.getSgv();
|
||||
}
|
||||
}
|
||||
|
||||
double maxBasal = 0.1;
|
||||
for (BasalWatchData bwd: basalWatchDataList) {
|
||||
if(bwd.amount > maxBasal){
|
||||
maxBasal = bwd.amount;
|
||||
for (EventData.TreatmentData.Basal bwd : basalWatchDataList) {
|
||||
if (bwd.getAmount() > maxBasal) {
|
||||
maxBasal = bwd.getAmount();
|
||||
}
|
||||
}
|
||||
|
||||
double maxTemp = maxBasal;
|
||||
for (TempWatchData twd: tempWatchDataList) {
|
||||
if(twd.amount > maxTemp){
|
||||
maxTemp = twd.amount;
|
||||
for (EventData.TreatmentData.TempBasal twd : tempWatchDataList) {
|
||||
if (twd.getAmount() > maxTemp) {
|
||||
maxTemp = twd.getAmount();
|
||||
}
|
||||
}
|
||||
|
||||
double factor = (maxChart-minChart)/maxTemp;
|
||||
double factor = (maxChart - minChart) / maxTemp;
|
||||
// in case basal is the highest, don't paint it totally at the top.
|
||||
factor = Math.min(factor, ((maxChart-minChart)/maxBasal)*(2/3d));
|
||||
factor = Math.min(factor, ((maxChart - minChart) / maxBasal) * (2 / 3d));
|
||||
|
||||
boolean highlight = PreferenceManager
|
||||
.getDefaultSharedPreferences(context)
|
||||
.getBoolean("highlight_basals", false);
|
||||
|
||||
for (TempWatchData twd: tempWatchDataList) {
|
||||
if(twd.endTime > start_time) {
|
||||
lines.add(tempValuesLine(twd, (float) minChart, factor, false, highlight?(pointSize+1):pointSize));
|
||||
if(highlight){
|
||||
for (EventData.TreatmentData.TempBasal twd : tempWatchDataList) {
|
||||
if (twd.getEndTime() > start_time) {
|
||||
lines.add(tempValuesLine(twd, (float) minChart, factor, false, highlight ? (pointSize + 1) : pointSize));
|
||||
if (highlight) {
|
||||
lines.add(tempValuesLine(twd, (float) minChart, factor, true, 1));
|
||||
}
|
||||
}
|
||||
|
@ -224,13 +195,14 @@ public class BgGraphBuilder {
|
|||
|
||||
private Line basalLine(float offset, double factor, boolean highlight) {
|
||||
|
||||
List<PointValue> pointValues = new ArrayList<PointValue>();
|
||||
List<PointValue> pointValues = new ArrayList<>();
|
||||
|
||||
for (BasalWatchData bwd: basalWatchDataList) {
|
||||
if(bwd.endTime > start_time) {
|
||||
long begin = Math.max(start_time, bwd.startTime);
|
||||
pointValues.add(new PointValue(fuzz(begin), offset + (float) (factor * bwd.amount)));
|
||||
pointValues.add(new PointValue(fuzz(bwd.endTime), offset + (float) (factor * bwd.amount)));
|
||||
for (EventData.TreatmentData.Basal bwd : basalWatchDataList) {
|
||||
if (bwd.getEndTime() > start_time) {
|
||||
long begin = Math.max(start_time, bwd.getStartTime());
|
||||
pointValues.add(new PointValue(fuzz(begin), offset + (float) (factor * bwd.getAmount())));
|
||||
pointValues.add(new PointValue(fuzz(bwd.getEndTime()),
|
||||
offset + (float) (factor * bwd.getAmount())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,7 +210,7 @@ public class BgGraphBuilder {
|
|||
basalLine.setHasPoints(false);
|
||||
basalLine.setColor(basalCenterColor);
|
||||
basalLine.setPathEffect(new DashPathEffect(new float[]{4f, 3f}, 4f));
|
||||
basalLine.setStrokeWidth(highlight?2:1);
|
||||
basalLine.setStrokeWidth(highlight ? 2 : 1);
|
||||
return basalLine;
|
||||
|
||||
|
||||
|
@ -246,28 +218,28 @@ public class BgGraphBuilder {
|
|||
|
||||
private Line bolusLine(float offset) {
|
||||
|
||||
List<PointValue> pointValues = new ArrayList<PointValue>();
|
||||
List<PointValue> pointValues = new ArrayList<>();
|
||||
|
||||
for (BolusWatchData bwd: bolusWatchDataList) {
|
||||
if(bwd.date > start_time && bwd.date <= end_time && !bwd.isSMB && bwd.isValid && bwd.bolus > 0) {
|
||||
pointValues.add(new PointValue(fuzz(bwd.date), offset -2));
|
||||
for (EventData.TreatmentData.Treatment bwd : bolusWatchDataList) {
|
||||
if (bwd.getDate() > start_time && bwd.getDate() <= end_time && !bwd.isSMB() && bwd.isValid() && bwd.getBolus() > 0) {
|
||||
pointValues.add(new PointValue(fuzz(bwd.getDate()), offset - 2));
|
||||
}
|
||||
}
|
||||
Line line = new Line(pointValues);
|
||||
line.setColor(basalCenterColor);
|
||||
line.setHasLines(false);
|
||||
line.setPointRadius(pointSize*2);
|
||||
line.setPointRadius(pointSize * 2);
|
||||
line.setHasPoints(true);
|
||||
return line;
|
||||
}
|
||||
|
||||
private Line smbLine(float offset) {
|
||||
|
||||
List<PointValue> pointValues = new ArrayList<PointValue>();
|
||||
List<PointValue> pointValues = new ArrayList<>();
|
||||
|
||||
for (BolusWatchData bwd: bolusWatchDataList) {
|
||||
if(bwd.date > start_time && bwd.date <= end_time && bwd.isSMB && bwd.isValid && bwd.bolus > 0) {
|
||||
pointValues.add(new PointValue(fuzz(bwd.date), offset -2));
|
||||
for (EventData.TreatmentData.Treatment bwd : bolusWatchDataList) {
|
||||
if (bwd.getDate() > start_time && bwd.getDate() <= end_time && bwd.isSMB() && bwd.isValid() && bwd.getBolus() > 0) {
|
||||
pointValues.add(new PointValue(fuzz(bwd.getDate()), offset - 2));
|
||||
}
|
||||
}
|
||||
Line line = new Line(pointValues);
|
||||
|
@ -280,11 +252,11 @@ public class BgGraphBuilder {
|
|||
|
||||
private Line bolusInvalidLine(float offset) {
|
||||
|
||||
List<PointValue> pointValues = new ArrayList<PointValue>();
|
||||
List<PointValue> pointValues = new ArrayList<>();
|
||||
|
||||
for (BolusWatchData bwd: bolusWatchDataList) {
|
||||
if(bwd.date > start_time && bwd.date <= end_time && !(bwd.isValid && (bwd.bolus > 0 || bwd.carbs > 0))) {
|
||||
pointValues.add(new PointValue(fuzz(bwd.date), offset -2));
|
||||
for (EventData.TreatmentData.Treatment bwd : bolusWatchDataList) {
|
||||
if (bwd.getDate() > start_time && bwd.getDate() <= end_time && !(bwd.isValid() && (bwd.getBolus() > 0 || bwd.getCarbs() > 0))) {
|
||||
pointValues.add(new PointValue(fuzz(bwd.getDate()), offset - 2));
|
||||
}
|
||||
}
|
||||
Line line = new Line(pointValues);
|
||||
|
@ -297,17 +269,17 @@ public class BgGraphBuilder {
|
|||
|
||||
private Line carbsLine(float offset) {
|
||||
|
||||
List<PointValue> pointValues = new ArrayList<PointValue>();
|
||||
List<PointValue> pointValues = new ArrayList<>();
|
||||
|
||||
for (BolusWatchData bwd: bolusWatchDataList) {
|
||||
if(bwd.date > start_time && bwd.date <= end_time && !bwd.isSMB && bwd.isValid && bwd.carbs > 0) {
|
||||
pointValues.add(new PointValue(fuzz(bwd.date), offset +2));
|
||||
for (EventData.TreatmentData.Treatment bwd : bolusWatchDataList) {
|
||||
if (bwd.getDate() > start_time && bwd.getDate() <= end_time && !bwd.isSMB() && bwd.isValid() && bwd.getCarbs() > 0) {
|
||||
pointValues.add(new PointValue(fuzz(bwd.getDate()), offset + 2));
|
||||
}
|
||||
}
|
||||
Line line = new Line(pointValues);
|
||||
line.setColor(carbsColor);
|
||||
line.setHasLines(false);
|
||||
line.setPointRadius(pointSize*2);
|
||||
line.setPointRadius(pointSize * 2);
|
||||
line.setHasPoints(true);
|
||||
return line;
|
||||
}
|
||||
|
@ -316,13 +288,13 @@ public class BgGraphBuilder {
|
|||
private void addPredictionLines(List<Line> lines) {
|
||||
Map<Integer, List<PointValue>> values = new HashMap<>();
|
||||
long endTime = getPredictionEndTime();
|
||||
for (BgWatchData bwd : predictionsList) {
|
||||
if (bwd.timestamp <= endTime) {
|
||||
double value = Math.min(bwd.sgv, UPPER_CUTOFF_SGV);
|
||||
if (!values.containsKey(bwd.color)) {
|
||||
values.put(bwd.color, new ArrayList<>());
|
||||
for (EventData.SingleBg bwd : predictionsList) {
|
||||
if (bwd.getTimeStamp() <= endTime) {
|
||||
double value = Math.min(bwd.getSgv(), UPPER_CUTOFF_SGV);
|
||||
if (!values.containsKey(bwd.getColor())) {
|
||||
values.put(bwd.getColor(), new ArrayList<>());
|
||||
}
|
||||
values.get(bwd.color).add(new PointValue(fuzz(bwd.timestamp), (float) value));
|
||||
values.get(bwd.getColor()).add(new PointValue(fuzz(bwd.getTimeStamp()), (float) value));
|
||||
}
|
||||
}
|
||||
for (Map.Entry<Integer, List<PointValue>> entry : values.entrySet()) {
|
||||
|
@ -358,7 +330,7 @@ public class BgGraphBuilder {
|
|||
public Line inRangeValuesLine() {
|
||||
Line inRangeValuesLine = new Line(inRangeValues);
|
||||
inRangeValuesLine.setColor(midColor);
|
||||
if(singleLine) {
|
||||
if (singleLine) {
|
||||
inRangeValuesLine.setHasLines(true);
|
||||
inRangeValuesLine.setHasPoints(false);
|
||||
inRangeValuesLine.setStrokeWidth(pointSize);
|
||||
|
@ -371,19 +343,19 @@ public class BgGraphBuilder {
|
|||
}
|
||||
|
||||
|
||||
public Line tempValuesLine(TempWatchData twd, float offset, double factor, boolean isHighlightLine, int strokeWidth) {
|
||||
List<PointValue> lineValues = new ArrayList<PointValue>();
|
||||
long begin = Math.max(start_time, twd.startTime);
|
||||
lineValues.add(new PointValue(fuzz(begin), offset + (float) (factor * twd.startBasal)));
|
||||
lineValues.add(new PointValue(fuzz(begin), offset + (float) (factor * twd.amount)));
|
||||
lineValues.add(new PointValue(fuzz(twd.endTime), offset + (float) (factor * twd.amount)));
|
||||
lineValues.add(new PointValue(fuzz(twd.endTime), offset + (float) (factor * twd.endBasal)));
|
||||
public Line tempValuesLine(EventData.TreatmentData.TempBasal twd, float offset, double factor, boolean isHighlightLine, int strokeWidth) {
|
||||
List<PointValue> lineValues = new ArrayList<>();
|
||||
long begin = Math.max(start_time, twd.getStartTime());
|
||||
lineValues.add(new PointValue(fuzz(begin), offset + (float) (factor * twd.getStartBasal())));
|
||||
lineValues.add(new PointValue(fuzz(begin), offset + (float) (factor * twd.getAmount())));
|
||||
lineValues.add(new PointValue(fuzz(twd.getEndTime()), offset + (float) (factor * twd.getAmount())));
|
||||
lineValues.add(new PointValue(fuzz(twd.getEndTime()), offset + (float) (factor * twd.getEndBasal())));
|
||||
Line valueLine = new Line(lineValues);
|
||||
valueLine.setHasPoints(false);
|
||||
if (isHighlightLine){
|
||||
if (isHighlightLine) {
|
||||
valueLine.setColor(basalCenterColor);
|
||||
valueLine.setStrokeWidth(1);
|
||||
}else {
|
||||
} else {
|
||||
valueLine.setColor(basalBackgroundColor);
|
||||
valueLine.setStrokeWidth(strokeWidth);
|
||||
}
|
||||
|
@ -391,38 +363,36 @@ public class BgGraphBuilder {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private void addBgReadingValues() {
|
||||
if(singleLine) {
|
||||
for (BgWatchData bgReading : bgDataList) {
|
||||
if(bgReading.timestamp > start_time) {
|
||||
if (bgReading.sgv >= 450) {
|
||||
inRangeValues.add(new PointValue(fuzz(bgReading.timestamp), (float) 450));
|
||||
} 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));
|
||||
if (singleLine) {
|
||||
for (EventData.SingleBg bgReading : bgDataList) {
|
||||
if (bgReading.getTimeStamp() > start_time) {
|
||||
if (bgReading.getSgv() >= 450) {
|
||||
inRangeValues.add(new PointValue(fuzz(bgReading.getTimeStamp()), (float) 450));
|
||||
} else if (bgReading.getSgv() >= highMark) {
|
||||
inRangeValues.add(new PointValue(fuzz(bgReading.getTimeStamp()), (float) bgReading.getSgv()));
|
||||
} else if (bgReading.getSgv() >= lowMark) {
|
||||
inRangeValues.add(new PointValue(fuzz(bgReading.getTimeStamp()), (float) bgReading.getSgv()));
|
||||
} else if (bgReading.getSgv() >= 40) {
|
||||
inRangeValues.add(new PointValue(fuzz(bgReading.getTimeStamp()), (float) bgReading.getSgv()));
|
||||
} else if (bgReading.getSgv() >= 11) {
|
||||
inRangeValues.add(new PointValue(fuzz(bgReading.getTimeStamp()), (float) 40));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (BgWatchData bgReading : bgDataList) {
|
||||
if (bgReading.timestamp > start_time) {
|
||||
if (bgReading.sgv >= 450) {
|
||||
highValues.add(new PointValue(fuzz(bgReading.timestamp), (float) 450));
|
||||
} 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));
|
||||
for (EventData.SingleBg bgReading : bgDataList) {
|
||||
if (bgReading.getTimeStamp() > start_time) {
|
||||
if (bgReading.getSgv() >= 450) {
|
||||
highValues.add(new PointValue(fuzz(bgReading.getTimeStamp()), (float) 450));
|
||||
} else if (bgReading.getSgv() >= highMark) {
|
||||
highValues.add(new PointValue(fuzz(bgReading.getTimeStamp()), (float) bgReading.getSgv()));
|
||||
} else if (bgReading.getSgv() >= lowMark) {
|
||||
inRangeValues.add(new PointValue(fuzz(bgReading.getTimeStamp()), (float) bgReading.getSgv()));
|
||||
} else if (bgReading.getSgv() >= 40) {
|
||||
lowValues.add(new PointValue(fuzz(bgReading.getTimeStamp()), (float) bgReading.getSgv()));
|
||||
} else if (bgReading.getSgv() >= 11) {
|
||||
lowValues.add(new PointValue(fuzz(bgReading.getTimeStamp()), (float) 40));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -430,7 +400,7 @@ public class BgGraphBuilder {
|
|||
}
|
||||
|
||||
public Line highLine() {
|
||||
List<PointValue> highLineValues = new ArrayList<PointValue>();
|
||||
List<PointValue> 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);
|
||||
|
@ -441,7 +411,7 @@ public class BgGraphBuilder {
|
|||
}
|
||||
|
||||
public Line lowLine() {
|
||||
List<PointValue> lowLineValues = new ArrayList<PointValue>();
|
||||
List<PointValue> 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);
|
||||
|
@ -457,7 +427,7 @@ public class BgGraphBuilder {
|
|||
public Axis yAxis() {
|
||||
Axis yAxis = new Axis();
|
||||
yAxis.setAutoGenerated(true);
|
||||
List<AxisValue> axisValues = new ArrayList<AxisValue>();
|
||||
List<AxisValue> axisValues = new ArrayList<>();
|
||||
yAxis.setValues(axisValues);
|
||||
yAxis.setHasLines(false);
|
||||
yAxis.setLineColor(gridColour);
|
||||
|
@ -466,13 +436,13 @@ public class BgGraphBuilder {
|
|||
|
||||
public Axis xAxis() {
|
||||
final boolean is24 = DateFormat.is24HourFormat(context);
|
||||
SimpleDateFormat timeFormat = new SimpleDateFormat(is24? "HH" : "h a");
|
||||
SimpleDateFormat timeFormat = new SimpleDateFormat(is24 ? "HH" : "h a");
|
||||
timeFormat.setTimeZone(TimeZone.getDefault());
|
||||
long timeNow = System.currentTimeMillis();
|
||||
|
||||
Axis xAxis = new Axis();
|
||||
xAxis.setAutoGenerated(false);
|
||||
List<AxisValue> xAxisValues = new ArrayList<AxisValue>();
|
||||
List<AxisValue> xAxisValues = new ArrayList<>();
|
||||
|
||||
//get the time-tick at the full hour after start_time
|
||||
GregorianCalendar startGC = new GregorianCalendar();
|
||||
|
@ -484,14 +454,14 @@ public class BgGraphBuilder {
|
|||
long start_hour = startGC.getTimeInMillis();
|
||||
|
||||
//Display current time on the graph
|
||||
SimpleDateFormat longTimeFormat = new SimpleDateFormat(is24? "HH:mm" : "h:mm a");
|
||||
SimpleDateFormat longTimeFormat = new SimpleDateFormat(is24 ? "HH:mm" : "h:mm a");
|
||||
xAxisValues.add(new AxisValue(fuzz(timeNow)).setLabel((longTimeFormat.format(timeNow))));
|
||||
|
||||
long hourTick = start_hour;
|
||||
|
||||
// add all full hours within the timeframe
|
||||
while (hourTick < end_time){
|
||||
if(Math.abs(hourTick - timeNow) > (8 * (end_time-start_time)/60)){
|
||||
while (hourTick < end_time) {
|
||||
if (Math.abs(hourTick - timeNow) > (8 * (end_time - start_time) / 60)) {
|
||||
xAxisValues.add(new AxisValue(fuzz(hourTick)).setLabel(timeFormat.format(hourTick)));
|
||||
} else {
|
||||
//don't print hour label if too close to now to avoid overlaps
|
||||
|
@ -499,7 +469,7 @@ public class BgGraphBuilder {
|
|||
}
|
||||
|
||||
//increment by one hour
|
||||
hourTick += 60*60*1000;
|
||||
hourTick += 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
xAxis.setValues(xAxisValues);
|
||||
|
@ -513,16 +483,16 @@ public class BgGraphBuilder {
|
|||
|
||||
public long getPredictionEndTime() {
|
||||
long maxPredictionDate = System.currentTimeMillis();
|
||||
for (BgWatchData prediction :
|
||||
for (EventData.SingleBg prediction :
|
||||
predictionsList) {
|
||||
if (maxPredictionDate < prediction.timestamp) {
|
||||
maxPredictionDate = prediction.timestamp;
|
||||
if (maxPredictionDate < prediction.getTimeStamp()) {
|
||||
maxPredictionDate = prediction.getTimeStamp();
|
||||
}
|
||||
}
|
||||
return (long) Math.min(maxPredictionDate, System.currentTimeMillis() + MAX_PREDICTION__TIME_RATIO *timespan*1000*60*60);
|
||||
return (long) Math.min(maxPredictionDate, System.currentTimeMillis() + MAX_PREDICTION__TIME_RATIO * timespan * 1000 * 60 * 60);
|
||||
}
|
||||
|
||||
public float fuzz(long value) {
|
||||
return (float) Math.round(value / fuzzyTimeDenom);
|
||||
return (float) Math.round(value / fuzzyTimeDenom);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,15 @@
|
|||
package info.nightscout.androidaps.watchfaces;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.annotation.SuppressLint;
|
||||
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.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import android.support.wearable.watchface.WatchFaceStyle;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Display;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -27,21 +17,40 @@ import android.view.View;
|
|||
import android.view.WindowManager;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
import com.ustwo.clockwise.common.WatchFaceTime;
|
||||
import com.ustwo.clockwise.wearable.WatchFace;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.AndroidInjection;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.BgWatchData;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.menus.MainMenuActivity;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
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 io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
|
||||
|
||||
public class CircleWatchface extends WatchFace implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public class CircleWatchface extends WatchFace {
|
||||
|
||||
@Inject RxBus rxBus;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject SP sp;
|
||||
|
||||
CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
private EventData.SingleBg singleBg = new EventData.SingleBg(0, "---", "-", "--", "--", "--", 0, 0.0, 0.0, 0.0, 0);
|
||||
private EventData.GraphData graphData;
|
||||
private EventData.Status status = new EventData.Status("no status", "IOB", "-.--", false, "--g", "-.--U/h", "--", "--", -1, "--", false, 1);
|
||||
|
||||
public final float PADDING = 20f;
|
||||
public final float CIRCLE_WIDTH = 10f;
|
||||
public final int BIG_HAND_WIDTH = 16;
|
||||
|
@ -52,43 +61,27 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
//variables for time
|
||||
private float angleBig = 0f;
|
||||
private float angleSMALL = 0f;
|
||||
private int hour, minute;
|
||||
private int color;
|
||||
private final Paint circlePaint = new Paint();
|
||||
private final 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 final MessageReceiver messageReceiver = new MessageReceiver();
|
||||
|
||||
private int sgvLevel = 0;
|
||||
private String sgvString = "999";
|
||||
private String statusString = "no status";
|
||||
|
||||
|
||||
private int batteryLevel = 0;
|
||||
private long datetime = 0;
|
||||
private String direction = "";
|
||||
private String delta = "";
|
||||
private String avgDelta = "";
|
||||
public TreeSet<BgWatchData> bgDataList = new TreeSet<>();
|
||||
public ArrayList<EventData.SingleBg> bgDataList = new ArrayList<>();
|
||||
|
||||
private int specW;
|
||||
private int specH;
|
||||
private View myLayout;
|
||||
|
||||
protected SharedPreferences sharedPrefs;
|
||||
private TextView mSgv;
|
||||
private long sgvTapTime = 0;
|
||||
|
||||
|
||||
@Override
|
||||
@SuppressLint("InflateParams") @Override
|
||||
public void onCreate() {
|
||||
AndroidInjection.inject(this);
|
||||
super.onCreate();
|
||||
|
||||
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
|
||||
|
@ -104,19 +97,46 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
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
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.SingleBg.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> singleBg = event)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.GraphData.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> graphData = event)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.Status.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> {
|
||||
// this event is received as last batch of data
|
||||
aapsLogger.debug(LTag.WEAR, "Status received");
|
||||
status = event;
|
||||
addToWatchSet();
|
||||
prepareLayout();
|
||||
prepareDrawTime();
|
||||
invalidate();
|
||||
})
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.Preferences.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> {
|
||||
prepareDrawTime();
|
||||
prepareLayout();
|
||||
invalidate();
|
||||
})
|
||||
);
|
||||
rxBus.send(new EventWearToMobile(new EventData.ActionResendData("CircleWatchFace::onCreate")));
|
||||
|
||||
wakeLock.release();
|
||||
}
|
||||
|
@ -124,18 +144,13 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (messageReceiver != null) {
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(messageReceiver);
|
||||
}
|
||||
if (sharedPrefs != null) {
|
||||
sharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
disposable.clear();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void onDraw(Canvas canvas) {
|
||||
Log.d("CircleWatchface", "start onDraw");
|
||||
aapsLogger.debug(LTag.WEAR, "start onDraw");
|
||||
canvas.drawColor(getBackgroundColor());
|
||||
drawTime(canvas);
|
||||
drawOtherStuff(canvas);
|
||||
|
@ -145,27 +160,25 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
|
||||
private synchronized void prepareLayout() {
|
||||
|
||||
Log.d("CircleWatchface", "start startPrepareLayout");
|
||||
aapsLogger.debug(LTag.WEAR, "start startPrepareLayout");
|
||||
|
||||
// prepare fields
|
||||
|
||||
TextView textView;
|
||||
mSgv = myLayout.findViewById(R.id.sgvString);
|
||||
textView = myLayout.findViewById(R.id.sgvString);
|
||||
if (sharedPrefs.getBoolean("showBG", true)) {
|
||||
textView.setVisibility(View.VISIBLE);
|
||||
textView.setText(getSgvString());
|
||||
textView.setTextColor(getTextColor());
|
||||
if (sp.getBoolean("showBG", true)) {
|
||||
mSgv.setVisibility(View.VISIBLE);
|
||||
mSgv.setText(singleBg.getSgvString());
|
||||
mSgv.setTextColor(getTextColor());
|
||||
|
||||
} else {
|
||||
//Also possible: View.INVISIBLE instead of View.GONE (no layout change)
|
||||
textView.setVisibility(View.INVISIBLE);
|
||||
mSgv.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
textView = myLayout.findViewById(R.id.statusString);
|
||||
if (sharedPrefs.getBoolean("showExternalStatus", true)) {
|
||||
TextView textView = myLayout.findViewById(R.id.statusString);
|
||||
if (sp.getBoolean("showExternalStatus", true)) {
|
||||
textView.setVisibility(View.VISIBLE);
|
||||
textView.setText(getStatusString());
|
||||
textView.setText(status.getExternalStatus());
|
||||
textView.setTextColor(getTextColor());
|
||||
|
||||
} else {
|
||||
|
@ -174,10 +187,10 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
}
|
||||
|
||||
textView = myLayout.findViewById(R.id.agoString);
|
||||
if (sharedPrefs.getBoolean("showAgo", true)) {
|
||||
if (sp.getBoolean("showAgo", true)) {
|
||||
textView.setVisibility(View.VISIBLE);
|
||||
|
||||
if (sharedPrefs.getBoolean("showBigNumbers", false)) {
|
||||
if (sp.getBoolean("showBigNumbers", false)) {
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 26);
|
||||
} else {
|
||||
((TextView) myLayout.findViewById(R.id.agoString)).setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
|
||||
|
@ -190,17 +203,17 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
}
|
||||
|
||||
textView = myLayout.findViewById(R.id.deltaString);
|
||||
if (sharedPrefs.getBoolean("showDelta", true)) {
|
||||
if (sp.getBoolean("showDelta", true)) {
|
||||
textView.setVisibility(View.VISIBLE);
|
||||
textView.setText(getDelta());
|
||||
textView.setText(singleBg.getDelta());
|
||||
textView.setTextColor(getTextColor());
|
||||
if (sharedPrefs.getBoolean("showBigNumbers", false)) {
|
||||
if (sp.getBoolean("showBigNumbers", false)) {
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25);
|
||||
} else {
|
||||
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18);
|
||||
}
|
||||
if (sharedPrefs.getBoolean("showAvgDelta", true)) {
|
||||
textView.append(" " + getAvgDelta());
|
||||
if (sp.getBoolean("showAvgDelta", true)) {
|
||||
textView.append(" " + singleBg.getAvgDelta());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -215,8 +228,8 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
|
||||
public String getMinutes() {
|
||||
String minutes = "--'";
|
||||
if (getDatetime() != 0) {
|
||||
minutes = ((int) Math.floor((System.currentTimeMillis() - getDatetime()) / 60000.0)) + "'";
|
||||
if (singleBg.getTimeStamp() != 0) {
|
||||
minutes = ((int) Math.floor((System.currentTimeMillis() - singleBg.getTimeStamp()) / 60000.0)) + "'";
|
||||
}
|
||||
return minutes;
|
||||
}
|
||||
|
@ -249,16 +262,16 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
}
|
||||
|
||||
private synchronized void prepareDrawTime() {
|
||||
Log.d("CircleWatchface", "start prepareDrawTime");
|
||||
aapsLogger.debug(LTag.WEAR, "start prepareDrawTime");
|
||||
|
||||
hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY) % 12;
|
||||
minute = Calendar.getInstance().get(Calendar.MINUTE);
|
||||
int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY) % 12;
|
||||
int 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()) {
|
||||
switch ((int) singleBg.getSgvLevel()) {
|
||||
case -1:
|
||||
color = getLowColor();
|
||||
break;
|
||||
|
@ -271,20 +284,7 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
}
|
||||
|
||||
|
||||
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.setShader(null);
|
||||
|
||||
circlePaint.setStyle(Paint.Style.STROKE);
|
||||
circlePaint.setStrokeWidth(CIRCLE_WIDTH);
|
||||
|
@ -299,17 +299,10 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
rect = new RectF(PADDING, PADDING, displaySize.x - PADDING, displaySize.y - PADDING);
|
||||
rectDelete = new RectF(PADDING - CIRCLE_WIDTH / 2, PADDING - CIRCLE_WIDTH / 2, displaySize.x - PADDING + CIRCLE_WIDTH / 2, 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");
|
||||
aapsLogger.debug(LTag.WEAR, "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 ||
|
||||
|
@ -338,7 +331,7 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
|
||||
// defining color for dark and bright
|
||||
public int getLowColor() {
|
||||
if (sharedPrefs.getBoolean("dark", true)) {
|
||||
if (sp.getBoolean("dark", true)) {
|
||||
return Color.argb(255, 255, 120, 120);
|
||||
} else {
|
||||
return Color.argb(255, 255, 80, 80);
|
||||
|
@ -346,7 +339,7 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
}
|
||||
|
||||
public int getInRangeColor() {
|
||||
if (sharedPrefs.getBoolean("dark", true)) {
|
||||
if (sp.getBoolean("dark", true)) {
|
||||
return Color.argb(255, 120, 255, 120);
|
||||
} else {
|
||||
return Color.argb(255, 0, 240, 0);
|
||||
|
@ -355,7 +348,7 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
}
|
||||
|
||||
public int getHighColor() {
|
||||
if (sharedPrefs.getBoolean("dark", true)) {
|
||||
if (sp.getBoolean("dark", true)) {
|
||||
return Color.argb(255, 255, 255, 120);
|
||||
} else {
|
||||
return Color.argb(255, 255, 200, 0);
|
||||
|
@ -364,7 +357,7 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
}
|
||||
|
||||
public int getBackgroundColor() {
|
||||
if (sharedPrefs.getBoolean("dark", true)) {
|
||||
if (sp.getBoolean("dark", true)) {
|
||||
return Color.BLACK;
|
||||
} else {
|
||||
return Color.WHITE;
|
||||
|
@ -373,7 +366,7 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
}
|
||||
|
||||
public int getTextColor() {
|
||||
if (sharedPrefs.getBoolean("dark", true)) {
|
||||
if (sp.getBoolean("dark", true)) {
|
||||
return Color.WHITE;
|
||||
} else {
|
||||
return Color.BLACK;
|
||||
|
@ -382,23 +375,22 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
}
|
||||
|
||||
public void drawOtherStuff(Canvas canvas) {
|
||||
Log.d("CircleWatchface", "start onDrawOtherStuff. bgDataList.size(): " + bgDataList.size());
|
||||
aapsLogger.debug(LTag.WEAR, "start onDrawOtherStuff. bgDataList.size(): " + bgDataList.size());
|
||||
|
||||
if (isAnimated()) return; // too many repaints when animated
|
||||
if (sharedPrefs.getBoolean("showRingHistory", false)) {
|
||||
if (sp.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());
|
||||
addIndicator(canvas, (float) bgDataList.iterator().next().getLow(), getLowColor());
|
||||
addIndicator(canvas, (float) bgDataList.iterator().next().getHigh(), getHighColor());
|
||||
|
||||
|
||||
if (sharedPrefs.getBoolean("softRingHistory", true)) {
|
||||
for (BgWatchData data : bgDataList) {
|
||||
if (sp.getBoolean("softRingHistory", true)) {
|
||||
for (EventData.SingleBg data : bgDataList) {
|
||||
addReadingSoft(canvas, data);
|
||||
}
|
||||
} else {
|
||||
for (BgWatchData data : bgDataList) {
|
||||
for (EventData.SingleBg data : bgDataList) {
|
||||
addReading(canvas, data);
|
||||
}
|
||||
}
|
||||
|
@ -406,202 +398,15 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
}
|
||||
}
|
||||
|
||||
public int holdInMemory() {
|
||||
return 6;
|
||||
}
|
||||
public synchronized void addToWatchSet() {
|
||||
|
||||
//getters & setters
|
||||
bgDataList.clear();
|
||||
if (!sp.getBoolean("showRingHistory", false)) return;
|
||||
|
||||
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 long getDatetime() {
|
||||
return datetime;
|
||||
}
|
||||
|
||||
private synchronized void setDatetime(long 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 getStatusString() {
|
||||
return statusString;
|
||||
}
|
||||
|
||||
void setStatusString(String statusString) {
|
||||
this.statusString = statusString;
|
||||
}
|
||||
|
||||
public String getDelta() {
|
||||
return delta;
|
||||
}
|
||||
|
||||
private void setDelta(String delta) {
|
||||
this.delta = delta;
|
||||
}
|
||||
|
||||
private String getAvgDelta() {
|
||||
return avgDelta;
|
||||
}
|
||||
|
||||
private void setAvgDelta(String avgDelta) {
|
||||
this.avgDelta = avgDelta;
|
||||
}
|
||||
|
||||
@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() {
|
||||
setIsAnimated(true);
|
||||
for (int i = 0; i <= 8 * 1000 / 40; i++) {
|
||||
animationStep();
|
||||
SystemClock.sleep(40);
|
||||
}
|
||||
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, "AndroidAPS:MessageReceiver");
|
||||
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());
|
||||
setDelta(dataMap.getString("delta"));
|
||||
setAvgDelta(dataMap.getString("avgDelta"));
|
||||
setDatetime(dataMap.getLong("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();
|
||||
}
|
||||
//status
|
||||
bundle = intent.getBundleExtra("status");
|
||||
if (bundle != null) {
|
||||
DataMap dataMap = DataMap.fromBundle(bundle);
|
||||
wakeLock.acquire(50);
|
||||
setStatusString(dataMap.getString("externalStatusString"));
|
||||
|
||||
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<DataMap> entries = dataMap.getDataMapArrayList("entries");
|
||||
if (entries == null) {
|
||||
double sgv = dataMap.getDouble("sgvDouble");
|
||||
double high = dataMap.getDouble("high");
|
||||
double low = dataMap.getDouble("low");
|
||||
long timestamp = dataMap.getLong("timestamp");
|
||||
int color = dataMap.getInt("color", 0);
|
||||
bgDataList.add(new BgWatchData(sgv, high, low, timestamp, color));
|
||||
} 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");
|
||||
long timestamp = entry.getLong("timestamp");
|
||||
int color = entry.getInt("color", 0);
|
||||
bgDataList.add(new BgWatchData(sgv, high, low, timestamp, color));
|
||||
}
|
||||
} else
|
||||
|
||||
Log.d("addToWatchSet", "start removing bgDataList.size(): " + bgDataList.size());
|
||||
HashSet<BgWatchData> removeSet = new HashSet<>();
|
||||
double threshold = (System.currentTimeMillis() - (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();
|
||||
double threshold = (System.currentTimeMillis() - (1000L * 60 * 30)); // 30 min
|
||||
for (EventData.SingleBg entry : graphData.getEntries())
|
||||
if (entry.getTimeStamp() >= threshold) bgDataList.add(entry);
|
||||
aapsLogger.debug(LTag.WEAR, "addToWatchSet size=" + bgDataList.size());
|
||||
}
|
||||
|
||||
public int darken(int color, double fraction) {
|
||||
|
@ -618,10 +423,7 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -659,44 +461,46 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
}
|
||||
|
||||
|
||||
public void addReadingSoft(Canvas canvas, BgWatchData entry) {
|
||||
public void addReadingSoft(Canvas canvas, EventData.SingleBg entry) {
|
||||
|
||||
Log.d("CircleWatchface", "addReadingSoft");
|
||||
aapsLogger.debug(LTag.WEAR, "addReadingSoft");
|
||||
double size;
|
||||
int color = Color.LTGRAY;
|
||||
if (sharedPrefs.getBoolean("dark", true)) {
|
||||
if (sp.getBoolean("dark", true)) {
|
||||
color = Color.DKGRAY;
|
||||
}
|
||||
|
||||
float offsetMultiplier = (((displaySize.x / 2f) - PADDING) / 12f);
|
||||
float offset = (float) Math.max(1, Math.ceil((System.currentTimeMillis() - entry.timestamp) / (1000 * 60 * 5.0)));
|
||||
size = bgToAngle((float) entry.sgv);
|
||||
float offset = (float) Math.max(1,
|
||||
Math.ceil((System.currentTimeMillis() - entry.getTimeStamp()) / (1000 * 60 * 5.0)));
|
||||
size = bgToAngle((float) entry.getSgv());
|
||||
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");
|
||||
public void addReading(Canvas canvas, EventData.SingleBg entry) {
|
||||
aapsLogger.debug(LTag.WEAR, "addReading");
|
||||
|
||||
double size;
|
||||
int color = Color.LTGRAY;
|
||||
int indicatorColor = Color.DKGRAY;
|
||||
if (sharedPrefs.getBoolean("dark", true)) {
|
||||
if (sp.getBoolean("dark", true)) {
|
||||
color = Color.DKGRAY;
|
||||
indicatorColor = Color.LTGRAY;
|
||||
}
|
||||
int barColor = Color.GRAY;
|
||||
if (entry.sgv >= entry.high) {
|
||||
if (entry.getSgv() >= entry.getHigh()) {
|
||||
indicatorColor = getHighColor();
|
||||
barColor = darken(getHighColor(), .5);
|
||||
} else if (entry.sgv <= entry.low) {
|
||||
} else if (entry.getSgv() <= entry.getLow()) {
|
||||
indicatorColor = getLowColor();
|
||||
barColor = darken(getLowColor(), .5);
|
||||
}
|
||||
float offsetMultiplier = (((displaySize.x / 2f) - PADDING) / 12f);
|
||||
float offset = (float) Math.max(1, Math.ceil((System.currentTimeMillis() - entry.timestamp) / (1000 * 60 * 5.0)));
|
||||
size = bgToAngle((float) entry.sgv);
|
||||
float offset = (float) Math.max(1,
|
||||
Math.ceil((System.currentTimeMillis() - entry.getTimeStamp()) / (1000 * 60 * 5.0)));
|
||||
size = bgToAngle((float) entry.getSgv());
|
||||
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
|
||||
|
@ -705,8 +509,8 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
|
||||
@Override
|
||||
protected void onTapCommand(int tapType, int x, int y, long eventTime) {
|
||||
|
||||
int extra = mSgv != null ? (mSgv.getRight() - mSgv.getLeft()) / 2 : 0;
|
||||
if (mSgv == null) return;
|
||||
int extra = (mSgv.getRight() - mSgv.getLeft()) / 2;
|
||||
|
||||
if (tapType == TAP_TYPE_TAP &&
|
||||
x + extra >= mSgv.getLeft() &&
|
||||
|
@ -726,6 +530,4 @@ public class CircleWatchface extends WatchFace implements SharedPreferences.OnSh
|
|||
protected WatchFaceStyle getWatchFaceStyle() {
|
||||
return new WatchFaceStyle.Builder(this).setAcceptsTapEvents(true).build();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.watchfaces;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.support.wearable.watchface.WatchFaceStyle;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -16,7 +17,7 @@ public class Cockpit extends BaseWatchFace {
|
|||
|
||||
private long sgvTapTime = 0;
|
||||
|
||||
@Override
|
||||
@SuppressLint("InflateParams") @Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
|
||||
|
@ -48,13 +49,13 @@ public class Cockpit extends BaseWatchFace {
|
|||
setTextSizes();
|
||||
|
||||
if (mHighLight != null && mLowLight != null) {
|
||||
if (rawData.sgvLevel == 1) {
|
||||
if (singleBg.getSgvLevel() == 1) {
|
||||
mHighLight.setBackgroundResource(R.drawable.airplane_led_yellow_lit);
|
||||
mLowLight.setBackgroundResource(R.drawable.airplane_led_grey_unlit);
|
||||
} else if (rawData.sgvLevel == 0) {
|
||||
} else if (singleBg.getSgvLevel() == 0) {
|
||||
mHighLight.setBackgroundResource(R.drawable.airplane_led_grey_unlit);
|
||||
mLowLight.setBackgroundResource(R.drawable.airplane_led_grey_unlit);
|
||||
} else if (rawData.sgvLevel == -1) {
|
||||
} else if (singleBg.getSgvLevel() == -1) {
|
||||
mHighLight.setBackgroundResource(R.drawable.airplane_led_grey_unlit);
|
||||
mLowLight.setBackgroundResource(R.drawable.airplane_led_red_lit);
|
||||
}
|
||||
|
@ -84,7 +85,7 @@ public class Cockpit extends BaseWatchFace {
|
|||
protected void setTextSizes() {
|
||||
|
||||
if (mIOB2 != null) {
|
||||
if (rawData.detailedIOB) {
|
||||
if (status.getDetailedIob()) {
|
||||
if (bIsRound) {
|
||||
mIOB2.setTextSize(10);
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.watchfaces;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.support.wearable.watchface.WatchFaceStyle;
|
||||
|
@ -19,10 +20,9 @@ import info.nightscout.androidaps.interaction.menus.MainMenuActivity;
|
|||
|
||||
public class DigitalStyle extends BaseWatchFace {
|
||||
private static final long TIME_TAP_THRESHOLD = 800;
|
||||
private final long chartTapTime = 0;
|
||||
private long sgvTapTime = 0;
|
||||
|
||||
@Override
|
||||
@SuppressLint("InflateParams") @Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
|
||||
|
@ -57,13 +57,13 @@ public class DigitalStyle extends BaseWatchFace {
|
|||
}
|
||||
|
||||
protected void setColorDark() {
|
||||
if (rawData.sgvLevel == 1) {
|
||||
if (singleBg.getSgvLevel() == 1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
|
||||
} else if (rawData.sgvLevel == 0) {
|
||||
} else if (singleBg.getSgvLevel() == 0) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
|
||||
} else if (rawData.sgvLevel == -1) {
|
||||
} else if (singleBg.getSgvLevel() == -1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ public class DigitalStyle extends BaseWatchFace {
|
|||
mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_TimestampOld));
|
||||
}
|
||||
|
||||
if (rawData.batteryLevel == 1) {
|
||||
if (status.getBatteryLevel() == 1) {
|
||||
mUploaderBattery.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
|
||||
} else {
|
||||
mUploaderBattery.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_uploaderBatteryEmpty));
|
||||
|
@ -99,10 +99,11 @@ public class DigitalStyle extends BaseWatchFace {
|
|||
LinearLayout mShapesElements = layoutView.findViewById(R.id.shapes_elements);
|
||||
if (mShapesElements != null) {
|
||||
String displayFormatType = (mShapesElements.getContentDescription().toString().startsWith("round") ? "round" : "rect");
|
||||
String displayStyle=sharedPrefs.getString("digitalstyle_frameStyle", "full");
|
||||
String displayFrameColor=sharedPrefs.getString("digitalstyle_frameColor", "red");
|
||||
String displayFrameColorSaturation=sharedPrefs.getString("digitalstyle_frameColorSaturation", "500");
|
||||
String displayFrameColorOpacity=sharedPrefs.getString("digitalstyle_frameColorOpacity", "1");
|
||||
String displayStyle=sp.getString("digitalstyle_frameStyle", "full");
|
||||
String displayFrameColor=sp.getString("digitalstyle_frameColor", "red");
|
||||
String displayFrameColorSaturation=sp.getString("digitalstyle_frameColorSaturation",
|
||||
"500");
|
||||
String displayFrameColorOpacity=sp.getString("digitalstyle_frameColorOpacity", "1");
|
||||
|
||||
// Load image with shapes
|
||||
String styleDrawableName = "digitalstyle_bg_" + displayStyle + "_" + displayFormatType;
|
||||
|
@ -133,7 +134,7 @@ public class DigitalStyle extends BaseWatchFace {
|
|||
}
|
||||
|
||||
/* optimize font-size --> when date is off then increase font-size of time */
|
||||
Boolean isShowDate = sharedPrefs.getBoolean("show_date", false);
|
||||
Boolean isShowDate = sp.getBoolean("show_date", false);
|
||||
if (!isShowDate) {
|
||||
layoutView.findViewById(R.id.date_time).setVisibility(View.GONE);
|
||||
mHour.setTextSize(62);
|
||||
|
@ -148,7 +149,7 @@ public class DigitalStyle extends BaseWatchFace {
|
|||
mMinute.setLetterSpacing((float) 0);
|
||||
|
||||
/* display week number */
|
||||
Boolean isShowWeekNumber = sharedPrefs.getBoolean("show_weeknumber", false);
|
||||
Boolean isShowWeekNumber = sp.getBoolean("show_weeknumber", false);
|
||||
Log.i("---------------------------------","weeknumber refresh ");
|
||||
TextView mWeekNumber= layoutView.findViewById(R.id.weeknumber);
|
||||
if (isShowWeekNumber) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.watchfaces;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
@ -16,7 +17,7 @@ public class Home extends BaseWatchFace {
|
|||
private long chartTapTime = 0;
|
||||
private long sgvTapTime = 0;
|
||||
|
||||
@Override
|
||||
@SuppressLint("InflateParams") @Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
|
||||
|
@ -53,9 +54,9 @@ public class Home extends BaseWatchFace {
|
|||
}
|
||||
|
||||
private void changeChartTimeframe() {
|
||||
int timeframe = Integer.parseInt(sharedPrefs.getString("chart_timeframe", "3"));
|
||||
int timeframe = sp.getInt("chart_timeframe", 3);
|
||||
timeframe = (timeframe%5) + 1;
|
||||
sharedPrefs.edit().putString("chart_timeframe", "" + timeframe).apply();
|
||||
sp.putString("chart_timeframe", "" + timeframe);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -69,15 +70,15 @@ public class Home extends BaseWatchFace {
|
|||
R.color.dark_background : R.color.dark_statusView));
|
||||
mTime.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_mTime));
|
||||
mRelativeLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_background));
|
||||
if (rawData.sgvLevel == 1) {
|
||||
if (singleBg.getSgvLevel() == 1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
|
||||
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
|
||||
} else if (rawData.sgvLevel == 0) {
|
||||
} else if (singleBg.getSgvLevel() == 0) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
|
||||
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
|
||||
} else if (rawData.sgvLevel == -1) {
|
||||
} else if (singleBg.getSgvLevel() == -1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
|
||||
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
|
||||
|
@ -90,7 +91,7 @@ public class Home extends BaseWatchFace {
|
|||
mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_TimestampOld));
|
||||
}
|
||||
|
||||
if (rawData.batteryLevel == 1) {
|
||||
if (status.getBatteryLevel() == 1) {
|
||||
mUploaderBattery.setTextColor(ContextCompat.getColor(getApplicationContext(), dividerMatchesBg ?
|
||||
R.color.dark_midColor : R.color.dark_uploaderBattery));
|
||||
} else {
|
||||
|
@ -138,15 +139,15 @@ public class Home extends BaseWatchFace {
|
|||
mLinearLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), dividerMatchesBg ?
|
||||
R.color.light_background : R.color.light_stripe_background));
|
||||
mRelativeLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.light_background));
|
||||
if (rawData.sgvLevel == 1) {
|
||||
if (singleBg.getSgvLevel() == 1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
|
||||
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
|
||||
} else if (rawData.sgvLevel == 0) {
|
||||
} else if (singleBg.getSgvLevel() == 0) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
|
||||
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
|
||||
} else if (rawData.sgvLevel == -1) {
|
||||
} else if (singleBg.getSgvLevel() == -1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
|
||||
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
|
||||
|
@ -158,7 +159,7 @@ public class Home extends BaseWatchFace {
|
|||
mTimestamp.setTextColor(Color.RED);
|
||||
}
|
||||
|
||||
if (rawData.batteryLevel == 1) {
|
||||
if (status.getBatteryLevel() == 1) {
|
||||
mUploaderBattery.setTextColor(dividerMatchesBg ? Color.BLACK : Color.WHITE);
|
||||
} else {
|
||||
mUploaderBattery.setTextColor(Color.RED);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.watchfaces;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
|
||||
|
@ -19,7 +20,7 @@ public class Home2 extends BaseWatchFace {
|
|||
private long chartTapTime = 0;
|
||||
private long sgvTapTime = 0;
|
||||
|
||||
@Override
|
||||
@SuppressLint("InflateParams") @Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
|
||||
|
@ -57,9 +58,9 @@ public class Home2 extends BaseWatchFace {
|
|||
}
|
||||
|
||||
private void changeChartTimeframe() {
|
||||
int timeframe = Integer.parseInt(sharedPrefs.getString("chart_timeframe", "3"));
|
||||
int timeframe = sp.getInt("chart_timeframe", 3);
|
||||
timeframe = (timeframe % 5) + 1;
|
||||
sharedPrefs.edit().putString("chart_timeframe", "" + timeframe).apply();
|
||||
sp.putString("chart_timeframe", "" + timeframe);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,13 +90,13 @@ public class Home2 extends BaseWatchFace {
|
|||
|
||||
setTextSizes();
|
||||
|
||||
if (rawData.sgvLevel == 1) {
|
||||
if (singleBg.getSgvLevel() == 1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
|
||||
} else if (rawData.sgvLevel == 0) {
|
||||
} else if (singleBg.getSgvLevel() == 0) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
|
||||
} else if (rawData.sgvLevel == -1) {
|
||||
} else if (singleBg.getSgvLevel() == -1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
|
||||
}
|
||||
|
@ -106,7 +107,7 @@ public class Home2 extends BaseWatchFace {
|
|||
mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_TimestampOld));
|
||||
}
|
||||
|
||||
if (rawData.batteryLevel == 1) {
|
||||
if (status.getBatteryLevel() == 1) {
|
||||
mUploaderBattery.setTextColor(dividerBatteryOkColor);
|
||||
} else {
|
||||
mUploaderBattery.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_uploaderBatteryEmpty));
|
||||
|
@ -200,13 +201,13 @@ public class Home2 extends BaseWatchFace {
|
|||
|
||||
setTextSizes();
|
||||
|
||||
if (rawData.sgvLevel == 1) {
|
||||
if (singleBg.getSgvLevel() == 1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
|
||||
} else if (rawData.sgvLevel == 0) {
|
||||
} else if (singleBg.getSgvLevel() == 0) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
|
||||
} else if (rawData.sgvLevel == -1) {
|
||||
} else if (singleBg.getSgvLevel() == -1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
|
||||
}
|
||||
|
@ -217,7 +218,7 @@ public class Home2 extends BaseWatchFace {
|
|||
mTimestamp.setTextColor(Color.RED);
|
||||
}
|
||||
|
||||
if (rawData.batteryLevel == 1) {
|
||||
if (status.getBatteryLevel() == 1) {
|
||||
mUploaderBattery.setTextColor(dividerTxtColor);
|
||||
} else {
|
||||
mUploaderBattery.setTextColor(Color.RED);
|
||||
|
@ -255,7 +256,7 @@ public class Home2 extends BaseWatchFace {
|
|||
|
||||
if (mIOB1 != null && mIOB2 != null) {
|
||||
|
||||
if (rawData.detailedIOB) {
|
||||
if (status.getDetailedIob()) {
|
||||
mIOB1.setTextSize(14);
|
||||
mIOB2.setTextSize(10);
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.watchfaces;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
@ -15,7 +16,7 @@ public class LargeHome extends BaseWatchFace {
|
|||
|
||||
private long sgvTapTime = 0;
|
||||
|
||||
@Override
|
||||
@SuppressLint("InflateParams") @Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
|
||||
|
@ -25,8 +26,8 @@ public class LargeHome extends BaseWatchFace {
|
|||
|
||||
@Override
|
||||
protected void onTapCommand(int tapType, int x, int y, long eventTime) {
|
||||
|
||||
int extra = mSgv!=null?(mSgv.getRight() - mSgv.getLeft())/2:0;
|
||||
if (mSgv == null) return;
|
||||
int extra = (mSgv.getRight() - mSgv.getLeft())/2;
|
||||
|
||||
if (tapType == TAP_TYPE_TAP&&
|
||||
x + extra >=mSgv.getLeft() &&
|
||||
|
@ -53,15 +54,15 @@ public class LargeHome extends BaseWatchFace {
|
|||
R.color.dark_background : R.color.dark_mLinearLayout));
|
||||
mTime.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_mTime));
|
||||
mRelativeLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_background));
|
||||
if (rawData.sgvLevel == 1) {
|
||||
if (singleBg.getSgvLevel() == 1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
|
||||
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_highColor));
|
||||
} else if (rawData.sgvLevel == 0) {
|
||||
} else if (singleBg.getSgvLevel() == 0) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
|
||||
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_midColor));
|
||||
} else if (rawData.sgvLevel == -1) {
|
||||
} else if (singleBg.getSgvLevel() == -1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
|
||||
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_lowColor));
|
||||
|
@ -74,7 +75,7 @@ public class LargeHome extends BaseWatchFace {
|
|||
mTimestamp.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.dark_TimestampOld));
|
||||
}
|
||||
|
||||
if (rawData.batteryLevel == 1) {
|
||||
if (status.getBatteryLevel() == 1) {
|
||||
mUploaderBattery.setTextColor(ContextCompat.getColor(getApplicationContext(), dividerMatchesBg ?
|
||||
R.color.dark_midColor : R.color.dark_uploaderBattery));
|
||||
} else {
|
||||
|
@ -90,15 +91,15 @@ public class LargeHome extends BaseWatchFace {
|
|||
mLinearLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), dividerMatchesBg ?
|
||||
R.color.light_background : R.color.light_stripe_background));
|
||||
mRelativeLayout.setBackgroundColor(ContextCompat.getColor(getApplicationContext(), R.color.light_background));
|
||||
if (rawData.sgvLevel == 1) {
|
||||
if (singleBg.getSgvLevel() == 1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
|
||||
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_highColor));
|
||||
} else if (rawData.sgvLevel == 0) {
|
||||
} else if (singleBg.getSgvLevel() == 0) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
|
||||
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_midColor));
|
||||
} else if (rawData.sgvLevel == -1) {
|
||||
} else if (singleBg.getSgvLevel() == -1) {
|
||||
mSgv.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
|
||||
mDelta.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
|
||||
mDirection.setTextColor(ContextCompat.getColor(getApplicationContext(), R.color.light_lowColor));
|
||||
|
@ -110,7 +111,7 @@ public class LargeHome extends BaseWatchFace {
|
|||
mTimestamp.setTextColor(Color.RED);
|
||||
}
|
||||
|
||||
if (rawData.batteryLevel == 1) {
|
||||
if (status.getBatteryLevel() == 1) {
|
||||
mUploaderBattery.setTextColor(dividerMatchesBg ? Color.BLACK : Color.WHITE);
|
||||
} else {
|
||||
mUploaderBattery.setTextColor(Color.RED);
|
||||
|
@ -120,15 +121,15 @@ public class LargeHome extends BaseWatchFace {
|
|||
} else {
|
||||
mRelativeLayout.setBackgroundColor(Color.BLACK);
|
||||
mLinearLayout.setBackgroundColor(dividerMatchesBg ? Color.BLACK : Color.LTGRAY);
|
||||
if (rawData.sgvLevel == 1) {
|
||||
if (singleBg.getSgvLevel() == 1) {
|
||||
mSgv.setTextColor(Color.YELLOW);
|
||||
mDirection.setTextColor(Color.YELLOW);
|
||||
mDelta.setTextColor(Color.YELLOW);
|
||||
} else if (rawData.sgvLevel == 0) {
|
||||
} else if (singleBg.getSgvLevel() == 0) {
|
||||
mSgv.setTextColor(Color.WHITE);
|
||||
mDirection.setTextColor(Color.WHITE);
|
||||
mDelta.setTextColor(Color.WHITE);
|
||||
} else if (rawData.sgvLevel == -1) {
|
||||
} else if (singleBg.getSgvLevel() == -1) {
|
||||
mSgv.setTextColor(Color.RED);
|
||||
mDirection.setTextColor(Color.RED);
|
||||
mDelta.setTextColor(Color.RED);
|
||||
|
|
|
@ -1,29 +1,17 @@
|
|||
package info.nightscout.androidaps.watchfaces;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.annotation.SuppressLint;
|
||||
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.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import android.support.wearable.view.WatchViewStub;
|
||||
import android.support.wearable.watchface.WatchFaceStyle;
|
||||
import android.text.format.DateFormat;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -32,56 +20,60 @@ import android.view.WindowManager;
|
|||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.ustwo.clockwise.common.WatchFaceTime;
|
||||
import com.ustwo.clockwise.common.WatchMode;
|
||||
import com.ustwo.clockwise.common.WatchShape;
|
||||
import com.ustwo.clockwise.wearable.WatchFace;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.AndroidInjection;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.BasalWatchData;
|
||||
import info.nightscout.androidaps.data.BgWatchData;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.data.TempWatchData;
|
||||
import info.nightscout.androidaps.events.EventWearToMobile;
|
||||
import info.nightscout.androidaps.interaction.menus.MainMenuActivity;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers;
|
||||
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 io.reactivex.rxjava3.disposables.CompositeDisposable;
|
||||
|
||||
/**
|
||||
* Created by adrianLxM.
|
||||
*/
|
||||
public class NOChart extends WatchFace implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
public final static IntentFilter INTENT_FILTER;
|
||||
public class NOChart extends WatchFace {
|
||||
|
||||
@Inject RxBus rxBus;
|
||||
@Inject AapsSchedulers aapsSchedulers;
|
||||
@Inject AAPSLogger aapsLogger;
|
||||
@Inject SP sp;
|
||||
|
||||
CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
private EventData.SingleBg singleBg;
|
||||
private EventData.Status status;
|
||||
|
||||
public static final int SCREENSIZE_SMALL = 280;
|
||||
public TextView mTime, mSgv, mTimestamp, mDelta, mAvgDelta;
|
||||
public RelativeLayout mRelativeLayout;
|
||||
public long sgvLevel = 0;
|
||||
public int batteryLevel = 1;
|
||||
public int ageLevel = 1;
|
||||
public boolean lowResMode = false;
|
||||
public boolean layoutSet = false;
|
||||
public long datetime;
|
||||
public ArrayList<BgWatchData> bgDataList = new ArrayList<>();
|
||||
public ArrayList<TempWatchData> tempWatchDataList = new ArrayList<>();
|
||||
public ArrayList<BasalWatchData> 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
|
||||
@SuppressLint("InflateParams") @Override
|
||||
public void onCreate() {
|
||||
AndroidInjection.inject(this);
|
||||
super.onCreate();
|
||||
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE))
|
||||
.getDefaultDisplay();
|
||||
|
@ -92,17 +84,60 @@ public class NOChart extends WatchFace implements SharedPreferences.OnSharedPref
|
|||
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);
|
||||
|
||||
DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||
if(metrics.widthPixels < SCREENSIZE_SMALL || metrics.heightPixels < SCREENSIZE_SMALL){
|
||||
if (metrics.widthPixels < SCREENSIZE_SMALL || metrics.heightPixels < SCREENSIZE_SMALL) {
|
||||
layoutView = inflater.inflate(R.layout.activity_nochart_small, null);
|
||||
} else {
|
||||
layoutView = inflater.inflate(R.layout.activity_nochart, null);
|
||||
}
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.SingleBg.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> {
|
||||
aapsLogger.debug(LTag.WEAR, "SingleBg received");
|
||||
singleBg = event;
|
||||
|
||||
mSgv.setText(singleBg.getSgvString());
|
||||
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(this);
|
||||
mTime.setText(timeFormat.format(System.currentTimeMillis()));
|
||||
mDelta.setText(singleBg.getDelta());
|
||||
mAvgDelta.setText(singleBg.getAvgDelta());
|
||||
})
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.Status.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> {
|
||||
// this event is received as last batch of data
|
||||
aapsLogger.debug(LTag.WEAR, "Status received");
|
||||
status = event;
|
||||
showAgeAndStatus();
|
||||
mRelativeLayout.measure(specW, specH);
|
||||
mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
|
||||
mRelativeLayout.getMeasuredHeight());
|
||||
invalidate();
|
||||
setColor();
|
||||
})
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventData.Preferences.class)
|
||||
.observeOn(aapsSchedulers.getMain())
|
||||
.subscribe(event -> {
|
||||
setColor();
|
||||
if (layoutSet) {
|
||||
showAgeAndStatus();
|
||||
mRelativeLayout.measure(specW, specH);
|
||||
mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
|
||||
mRelativeLayout.getMeasuredHeight());
|
||||
}
|
||||
invalidate();
|
||||
})
|
||||
);
|
||||
performViewSetup();
|
||||
}
|
||||
|
||||
|
@ -114,44 +149,37 @@ public class NOChart extends WatchFace implements SharedPreferences.OnSharedPref
|
|||
|
||||
public void performViewSetup() {
|
||||
final WatchViewStub stub = 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 = stub.findViewById(R.id.watch_time);
|
||||
mSgv = stub.findViewById(R.id.sgv);
|
||||
mTimestamp = stub.findViewById(R.id.timestamp);
|
||||
mDelta = stub.findViewById(R.id.delta);
|
||||
mAvgDelta = stub.findViewById(R.id.avgdelta);
|
||||
mRelativeLayout = stub.findViewById(R.id.main_layout);
|
||||
statusView = stub.findViewById(R.id.aps_status);
|
||||
layoutSet = true;
|
||||
showAgeAndStatus();
|
||||
mRelativeLayout.measure(specW, specH);
|
||||
mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
|
||||
mRelativeLayout.getMeasuredHeight());
|
||||
}
|
||||
stub.setOnLayoutInflatedListener(stub1 -> {
|
||||
mTime = stub1.findViewById(R.id.watch_time);
|
||||
mSgv = stub1.findViewById(R.id.sgv);
|
||||
mTimestamp = stub1.findViewById(R.id.timestamp);
|
||||
mDelta = stub1.findViewById(R.id.delta);
|
||||
mAvgDelta = stub1.findViewById(R.id.avgdelta);
|
||||
mRelativeLayout = stub1.findViewById(R.id.main_layout);
|
||||
statusView = stub1.findViewById(R.id.aps_status);
|
||||
layoutSet = true;
|
||||
showAgeAndStatus();
|
||||
mRelativeLayout.measure(specW, specH);
|
||||
mRelativeLayout.layout(0, 0, mRelativeLayout.getMeasuredWidth(),
|
||||
mRelativeLayout.getMeasuredHeight());
|
||||
});
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
rxBus.send(new EventWearToMobile(new EventData.ActionResendData("NOChart" +
|
||||
":performViewSetup")));
|
||||
wakeLock.acquire(50);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTapCommand(int tapType, int x, int y, long eventTime) {
|
||||
if (mSgv == null) return;
|
||||
int extra = (mSgv.getRight() - mSgv.getLeft()) / 2;
|
||||
|
||||
int extra = mSgv!=null?(mSgv.getRight() - mSgv.getLeft())/2:0;
|
||||
|
||||
if (tapType == TAP_TYPE_TAP&&
|
||||
x + extra >=mSgv.getLeft() &&
|
||||
x - extra <= mSgv.getRight()&&
|
||||
if (tapType == TAP_TYPE_TAP &&
|
||||
x + extra >= mSgv.getLeft() &&
|
||||
x - extra <= mSgv.getRight() &&
|
||||
y >= mSgv.getTop() &&
|
||||
y <= mSgv.getBottom()){
|
||||
if (eventTime - sgvTapTime < 800){
|
||||
y <= mSgv.getBottom()) {
|
||||
if (eventTime - sgvTapTime < 800) {
|
||||
Intent intent = new Intent(this, MainMenuActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
|
@ -162,10 +190,10 @@ public class NOChart extends WatchFace implements SharedPreferences.OnSharedPref
|
|||
|
||||
protected void onWatchModeChanged(WatchMode watchMode) {
|
||||
|
||||
if(lowResMode ^ isLowRes(watchMode)){ //if there was a change in lowResMode
|
||||
if (lowResMode ^ isLowRes(watchMode)) { //if there was a change in lowResMode
|
||||
lowResMode = isLowRes(watchMode);
|
||||
setColor();
|
||||
} else if (! sharedPrefs.getBoolean("dark", true)){
|
||||
} else if (!sp.getBoolean("dark", true)) {
|
||||
//in bright mode: different colours if active:
|
||||
setColor();
|
||||
}
|
||||
|
@ -177,14 +205,13 @@ public class NOChart extends WatchFace implements SharedPreferences.OnSharedPref
|
|||
|
||||
|
||||
@Override
|
||||
protected WatchFaceStyle getWatchFaceStyle(){
|
||||
protected WatchFaceStyle getWatchFaceStyle() {
|
||||
return new WatchFaceStyle.Builder(this).setAcceptsTapEvents(true).build();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public int ageLevel() {
|
||||
if(timeSince() <= (1000 * 60 * 12)) {
|
||||
if (timeSince() <= (1000 * 60 * 12)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
|
@ -192,40 +219,30 @@ public class NOChart extends WatchFace implements SharedPreferences.OnSharedPref
|
|||
}
|
||||
|
||||
public double timeSince() {
|
||||
return System.currentTimeMillis() - datetime;
|
||||
return System.currentTimeMillis() - singleBg.getTimeStamp();
|
||||
}
|
||||
|
||||
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");
|
||||
if (singleBg == null || singleBg.getTimeStamp() == 0) {
|
||||
return shortString ? "--'" : "-- Minute ago";
|
||||
}
|
||||
return minutesAgo + (shortString?"'":" Minutes 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);
|
||||
}
|
||||
disposable.clear();
|
||||
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) {
|
||||
if (layoutSet) {
|
||||
this.mRelativeLayout.draw(canvas);
|
||||
Log.d("onDraw", "draw");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,7 +254,7 @@ public class NOChart extends WatchFace implements SharedPreferences.OnSharedPref
|
|||
mTime.setText(timeFormat.format(System.currentTimeMillis()));
|
||||
showAgeAndStatus();
|
||||
|
||||
if(ageLevel()<=0) {
|
||||
if (ageLevel() <= 0) {
|
||||
mSgv.setPaintFlags(mSgv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
|
||||
} else {
|
||||
mSgv.setPaintFlags(mSgv.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
|
||||
|
@ -250,142 +267,28 @@ public class NOChart extends WatchFace implements SharedPreferences.OnSharedPref
|
|||
}
|
||||
}
|
||||
|
||||
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.getLong("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<DataMap> 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<DataMap> 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){
|
||||
if (mTimestamp != null) {
|
||||
mTimestamp.setText(readingAge(true));
|
||||
}
|
||||
boolean showAvgDelta = sharedPrefs.getBoolean("showAvgDelta", true);
|
||||
boolean showAvgDelta = sp.getBoolean("showAvgDelta", true);
|
||||
|
||||
if(showAvgDelta){
|
||||
if (showAvgDelta) {
|
||||
mAvgDelta.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mAvgDelta.setVisibility(View.GONE);
|
||||
}
|
||||
statusView.setText(externalStatusString);
|
||||
if (status != null) {
|
||||
statusView.setText(status.getExternalStatus());
|
||||
statusView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setColor() {
|
||||
if(lowResMode){
|
||||
if (lowResMode) {
|
||||
setColorLowRes();
|
||||
} else if (sharedPrefs.getBoolean("dark", true)) {
|
||||
} else if (sp.getBoolean("dark", true)) {
|
||||
setColorDark();
|
||||
} else {
|
||||
setColorBright();
|
||||
|
@ -393,62 +296,6 @@ public class NOChart extends WatchFace implements SharedPreferences.OnSharedPref
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@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();
|
||||
SystemClock.sleep(40);
|
||||
}
|
||||
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));
|
||||
|
@ -516,9 +363,11 @@ public class NOChart extends WatchFace implements SharedPreferences.OnSharedPref
|
|||
}
|
||||
|
||||
public void missedReadingAlert() {
|
||||
int minutes_since = (int) Math.floor(timeSince()/(1000*60));
|
||||
if(minutes_since >= 16 && ((minutes_since - 16) % 5) == 0) {
|
||||
DataLayerListenerService.Companion.requestData(this); // attempt endTime recover missing data
|
||||
int minutes_since = (int) Math.floor(timeSince() / (1000 * 60));
|
||||
if (minutes_since >= 16 && ((minutes_since - 16) % 5) == 0) {
|
||||
// attempt endTime recover missing data
|
||||
rxBus.send(new EventWearToMobile(new EventData.ActionResendData("NOChart" +
|
||||
":missedReadingAlert")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
package info.nightscout.androidaps.watchfaces;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import android.support.wearable.watchface.WatchFaceStyle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
import android.view.animation.RotateAnimation;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.interaction.menus.MainMenuActivity;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
|
@ -23,7 +25,7 @@ public class Steampunk extends BaseWatchFace {
|
|||
private float lastEndDegrees = 0f;
|
||||
private float deltaRotationAngle = 0f;
|
||||
|
||||
@Override
|
||||
@SuppressLint("InflateParams") @Override
|
||||
public void onCreate() {
|
||||
forceSquareCanvas = true;
|
||||
super.onCreate();
|
||||
|
@ -35,22 +37,22 @@ public class Steampunk extends BaseWatchFace {
|
|||
@Override
|
||||
protected void onTapCommand(int tapType, int x, int y, long eventTime) {
|
||||
|
||||
if (tapType == TAP_TYPE_TAP&&
|
||||
if (tapType == TAP_TYPE_TAP &&
|
||||
x >= mChartTap.getLeft() &&
|
||||
x <= mChartTap.getRight()&&
|
||||
x <= mChartTap.getRight() &&
|
||||
y >= mChartTap.getTop() &&
|
||||
y <= mChartTap.getBottom()){
|
||||
if (eventTime - chartTapTime < 800){
|
||||
y <= mChartTap.getBottom()) {
|
||||
if (eventTime - chartTapTime < 800) {
|
||||
changeChartTimeframe();
|
||||
}
|
||||
chartTapTime = eventTime;
|
||||
|
||||
} else if (tapType == TAP_TYPE_TAP&&
|
||||
} else if (tapType == TAP_TYPE_TAP &&
|
||||
x >= mMainMenuTap.getLeft() &&
|
||||
x <= mMainMenuTap.getRight()&&
|
||||
x <= mMainMenuTap.getRight() &&
|
||||
y >= mMainMenuTap.getTop() &&
|
||||
y <= mMainMenuTap.getBottom()){
|
||||
if (eventTime - mainMenuTapTime < 800){
|
||||
y <= mMainMenuTap.getBottom()) {
|
||||
if (eventTime - mainMenuTapTime < 800) {
|
||||
Intent intent = new Intent(this, MainMenuActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
|
@ -67,7 +69,7 @@ public class Steampunk extends BaseWatchFace {
|
|||
protected void setColorDark() {
|
||||
|
||||
if (mLinearLayout2 != null) {
|
||||
if (ageLevel() <= 0 && rawData.datetime != 0) {
|
||||
if (ageLevel() <= 0 && singleBg.getTimeStamp() != 0) {
|
||||
mLinearLayout2.setBackgroundResource(R.drawable.redline);
|
||||
mTimestamp.setTextColor(getResources().getColor(R.color.red_600));
|
||||
} else {
|
||||
|
@ -84,30 +86,32 @@ public class Steampunk extends BaseWatchFace {
|
|||
}
|
||||
}
|
||||
|
||||
if (!rawData.sSgv.equals("---")) {
|
||||
if (!singleBg.getSgvString().equals("---")) {
|
||||
|
||||
float rotationAngle = 0f; //by default, show ? on the dial (? is at 0 degrees on the dial)
|
||||
|
||||
if (!rawData.sUnits.equals("-")) {
|
||||
if (!singleBg.getGlucoseUnits().equals("-")) {
|
||||
|
||||
//ensure the glucose dial is the correct units
|
||||
if (rawData.sUnits.equals("mmol")) {
|
||||
if (singleBg.getGlucoseUnits().equals("mmol")) {
|
||||
mGlucoseDial.setImageResource(R.drawable.steampunk_dial_mmol);
|
||||
} else {
|
||||
mGlucoseDial.setImageResource(R.drawable.steampunk_dial_mgdl);
|
||||
}
|
||||
|
||||
//convert the Sgv to degrees of rotation
|
||||
if (rawData.sUnits.equals("mmol")) {
|
||||
rotationAngle = Float.valueOf(rawData.sSgv) * 18f; //convert to mg/dL, which is equivalent to degrees
|
||||
if (singleBg.getGlucoseUnits().equals("mmol")) {
|
||||
rotationAngle = SafeParse.stringToFloat(singleBg.getSgvString()) * 18f; //convert to
|
||||
// mg/dL, which is equivalent to degrees
|
||||
} else {
|
||||
rotationAngle = Float.valueOf(rawData.sSgv); //if glucose a value is received, use it to determine the amount of rotation of the dial.
|
||||
rotationAngle = SafeParse.stringToFloat(singleBg.getSgvString()); //if glucose a value is received, use it to determine the amount of rotation of the dial.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (rotationAngle > 330) rotationAngle = 330; //if the glucose value is higher than 330 then show "HIGH" on the dial. ("HIGH" is at 330 degrees on the dial)
|
||||
if (rotationAngle != 0 && rotationAngle < 30) rotationAngle = 30; //if the glucose value is lower than 30 show "LOW" on the dial. ("LOW" is at 30 degrees on the dial)
|
||||
if (rotationAngle > 330)
|
||||
rotationAngle = 330; //if the glucose value is higher than 330 then show "HIGH" on the dial. ("HIGH" is at 330 degrees on the dial)
|
||||
if (rotationAngle != 0 && rotationAngle < 30)
|
||||
rotationAngle = 30; //if the glucose value is lower than 30 show "LOW" on the dial. ("LOW" is at 30 degrees on the dial)
|
||||
if (lastEndDegrees == 0) lastEndDegrees = rotationAngle;
|
||||
|
||||
//rotate glucose dial
|
||||
|
@ -124,51 +128,54 @@ public class Steampunk extends BaseWatchFace {
|
|||
|
||||
//set the delta gauge and rotate the delta pointer
|
||||
float deltaIsNegative = 1f; //by default go clockwise
|
||||
if (!rawData.sAvgDelta.equals("--")) { //if a legitimate delta value is received, then...
|
||||
if (rawData.sAvgDelta.charAt(0) == '-') deltaIsNegative = -1f; //if the delta is negative, go counter-clockwise
|
||||
Float AbssAvgDelta = SafeParse.stringToFloat(rawData.sAvgDelta.substring(1)) ; //get rid of the sign so it can be converted to float.
|
||||
String autogranularity = "0" ; //autogranularity off
|
||||
if (!singleBg.getAvgDelta().equals("--")) { //if a legitimate delta value is
|
||||
// received,
|
||||
// then...
|
||||
if (singleBg.getAvgDelta().charAt(0) == '-')
|
||||
deltaIsNegative = -1f; //if the delta is negative, go counter-clockwise
|
||||
Float AbssAvgDelta = SafeParse.stringToFloat(singleBg.getAvgDelta().substring(1)); //get rid of the sign so it can be converted to float.
|
||||
String autogranularity = "0"; //autogranularity off
|
||||
//ensure the delta gauge is the right units and granularity
|
||||
if (!rawData.sUnits.equals("-")) {
|
||||
if (rawData.sUnits.equals("mmol")) {
|
||||
if (sharedPrefs.getString("delta_granularity", "2").equals("4")) { //Auto granularity
|
||||
if (!singleBg.getGlucoseUnits().equals("-")) {
|
||||
if (singleBg.getGlucoseUnits().equals("mmol")) {
|
||||
if (sp.getString("delta_granularity", "2").equals("4")) { //Auto granularity
|
||||
autogranularity = "1"; // low (init)
|
||||
if (AbssAvgDelta < 0.3 ) {
|
||||
autogranularity = "3" ; // high if below 0.3 mmol/l
|
||||
if (AbssAvgDelta < 0.3) {
|
||||
autogranularity = "3"; // high if below 0.3 mmol/l
|
||||
} else if (AbssAvgDelta < 0.5) {
|
||||
autogranularity = "2" ; // medium if below 0.5 mmol/l
|
||||
autogranularity = "2"; // medium if below 0.5 mmol/l
|
||||
}
|
||||
}
|
||||
if (sharedPrefs.getString("delta_granularity", "2").equals("1") || autogranularity.equals("1")) { //low
|
||||
if (sp.getString("delta_granularity", "2").equals("1") || autogranularity.equals("1")) { //low
|
||||
mLinearLayout.setBackgroundResource(R.drawable.steampunk_gauge_mmol_10);
|
||||
deltaRotationAngle = (AbssAvgDelta * 30f);
|
||||
}
|
||||
if (sharedPrefs.getString("delta_granularity", "2").equals("2") || autogranularity.equals("2")) { //medium
|
||||
if (sp.getString("delta_granularity", "2").equals("2") || autogranularity.equals("2")) { //medium
|
||||
mLinearLayout.setBackgroundResource(R.drawable.steampunk_gauge_mmol_05);
|
||||
deltaRotationAngle = (AbssAvgDelta * 60f);
|
||||
}
|
||||
if (sharedPrefs.getString("delta_granularity", "2").equals("3") || autogranularity.equals("3")) { //high
|
||||
if (sp.getString("delta_granularity", "2").equals("3") || autogranularity.equals("3")) { //high
|
||||
mLinearLayout.setBackgroundResource(R.drawable.steampunk_gauge_mmol_03);
|
||||
deltaRotationAngle = (AbssAvgDelta * 100f);
|
||||
}
|
||||
} else {
|
||||
if (sharedPrefs.getString("delta_granularity", "2").equals("4")) { //Auto granularity
|
||||
if (sp.getString("delta_granularity", "2").equals("4")) { //Auto granularity
|
||||
autogranularity = "1"; // low (init)
|
||||
if (AbssAvgDelta < 5 ) {
|
||||
autogranularity = "3" ; // high if below 5 mg/dl
|
||||
if (AbssAvgDelta < 5) {
|
||||
autogranularity = "3"; // high if below 5 mg/dl
|
||||
} else if (AbssAvgDelta < 10) {
|
||||
autogranularity = "2" ; // medium if below 10 mg/dl
|
||||
autogranularity = "2"; // medium if below 10 mg/dl
|
||||
}
|
||||
}
|
||||
if (sharedPrefs.getString("delta_granularity", "2").equals("1") || autogranularity.equals("1")) { //low
|
||||
if (sp.getString("delta_granularity", "2").equals("1") || autogranularity.equals("1")) { //low
|
||||
mLinearLayout.setBackgroundResource(R.drawable.steampunk_gauge_mgdl_20);
|
||||
deltaRotationAngle = (AbssAvgDelta * 1.5f);
|
||||
}
|
||||
if (sharedPrefs.getString("delta_granularity", "2").equals("2") || autogranularity.equals("2")) { //medium
|
||||
if (sp.getString("delta_granularity", "2").equals("2") || autogranularity.equals("2")) { //medium
|
||||
mLinearLayout.setBackgroundResource(R.drawable.steampunk_gauge_mgdl_10);
|
||||
deltaRotationAngle = (AbssAvgDelta * 3f);
|
||||
}
|
||||
if (sharedPrefs.getString("delta_granularity", "2").equals("3") || autogranularity.equals("3")) { //high
|
||||
if (sp.getString("delta_granularity", "2").equals("3") || autogranularity.equals("3")) { //high
|
||||
mLinearLayout.setBackgroundResource(R.drawable.steampunk_gauge_mgdl_5);
|
||||
deltaRotationAngle = (AbssAvgDelta * 6f);
|
||||
}
|
||||
|
@ -179,10 +186,10 @@ public class Steampunk extends BaseWatchFace {
|
|||
}
|
||||
|
||||
//rotate the minute hand.
|
||||
mMinuteHand.setRotation(Float.valueOf(sMinute) * 6f);
|
||||
mMinuteHand.setRotation(Float.parseFloat(sMinute) * 6f);
|
||||
|
||||
//rotate the hour hand.
|
||||
mHourHand.setRotation((Float.valueOf(sHour) * 30f) + (Float.valueOf(sMinute) * 0.5f));
|
||||
mHourHand.setRotation((Float.parseFloat(sHour) * 30f) + (Float.parseFloat(sMinute) * 0.5f));
|
||||
|
||||
setTextSizes();
|
||||
|
||||
|
@ -197,7 +204,7 @@ public class Steampunk extends BaseWatchFace {
|
|||
gridColor = ContextCompat.getColor(getApplicationContext(), R.color.grey_steampunk);
|
||||
basalBackgroundColor = ContextCompat.getColor(getApplicationContext(), R.color.basal_dark);
|
||||
basalCenterColor = ContextCompat.getColor(getApplicationContext(), R.color.basal_dark);
|
||||
if (Integer.parseInt(sharedPrefs.getString("chart_timeframe", "3")) < 3) {
|
||||
if (sp.getInt("chart_timeframe", 3) < 3) {
|
||||
pointSize = 2;
|
||||
} else {
|
||||
pointSize = 1;
|
||||
|
@ -232,7 +239,7 @@ public class Steampunk extends BaseWatchFace {
|
|||
//top row. large font unless text too big (i.e. detailedIOB)
|
||||
mCOB2.setTextSize(fontLarge);
|
||||
mBasalRate.setTextSize(fontLarge);
|
||||
if (rawData.sIOB2.length() < 7) {
|
||||
if (status.getIobDetail().length() < 7) {
|
||||
mIOB2.setTextSize(fontLarge);
|
||||
} else {
|
||||
mIOB2.setTextSize(fontSmall);
|
||||
|
@ -248,7 +255,8 @@ public class Steampunk extends BaseWatchFace {
|
|||
}
|
||||
|
||||
//if both batteries are shown, make them smaller.
|
||||
if (sharedPrefs.getBoolean("show_uploader_battery", true) && sharedPrefs.getBoolean("show_rig_battery", false)) {
|
||||
if (sp.getBoolean("show_uploader_battery", true) && sp.getBoolean(
|
||||
"show_rig_battery", false)) {
|
||||
mUploaderBattery.setTextSize(fontSmall);
|
||||
mRigBattery.setTextSize(fontSmall);
|
||||
} else {
|
||||
|
@ -258,14 +266,14 @@ public class Steampunk extends BaseWatchFace {
|
|||
}
|
||||
|
||||
private void changeChartTimeframe() {
|
||||
int timeframe = Integer.parseInt(sharedPrefs.getString("chart_timeframe", "3"));
|
||||
timeframe = (timeframe%5) + 1;
|
||||
int timeframe = sp.getInt("chart_timeframe", 3);
|
||||
timeframe = (timeframe % 5) + 1;
|
||||
if (timeframe < 3) {
|
||||
pointSize = 2;
|
||||
} else {
|
||||
pointSize = 1;
|
||||
}
|
||||
setupCharts();
|
||||
sharedPrefs.edit().putString("chart_timeframe", "" + timeframe).apply();
|
||||
sp.putString("chart_timeframe", "" + timeframe);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -170,12 +170,6 @@
|
|||
<string name="bolus_progress_silent_channel_name">AAPS Bolus Progress Silent</string>
|
||||
<string name="bolus_progress_channel_description">Bolus progress and cancel</string>
|
||||
<string name="bolus_progress_silent_channel_description">Bolus progress and cancel with less vibrations</string>
|
||||
<string name="key_quickwizard" translatable="false">QuickWizard</string>
|
||||
<string name="key_wear_control" translatable="false">wearcontrol</string>
|
||||
<string name="key_units_mgdl" translatable="false">units_mgdl</string>
|
||||
<string name="key_boluswizard_percentage" translatable="false">boluswizard_percentage</string>
|
||||
<string name="key_treatmentssafety_maxcarbs" translatable="false">treatmentssafety_maxcarbs</string>
|
||||
<string name="key_treatmentssafety_maxbolus" translatable="false">treatmentssafety_maxbolus</string>
|
||||
<string name="simple_ui_off">Off</string>
|
||||
<string name="simple_ui_charging">During Charging</string>
|
||||
<string name="simple_ui_always_on">Always On Mode</string>
|
||||
|
@ -189,6 +183,15 @@
|
|||
<string name="tile_no_config">No config available</string>
|
||||
<string name="wear_control_not_enabled">Wear controls disabled</string>
|
||||
<string name="wear_control_no_data">No data available</string>
|
||||
<string name="key_quick_wizard_data_map" translatable="false">quick_wizard_data_map</string>
|
||||
|
||||
<string name="key_quickwizard" translatable="false">QuickWizard</string>
|
||||
<string name="key_wear_control" translatable="false">wearcontrol</string>
|
||||
<string name="key_units_mgdl" translatable="false">units_mgdl</string>
|
||||
<string name="key_boluswizard_percentage" translatable="false">boluswizard_percentage</string>
|
||||
<string name="key_treatmentssafety_maxcarbs" translatable="false">treatmentssafety_maxcarbs</string>
|
||||
<string name="key_treatmentssafety_maxbolus" translatable="false">treatmentssafety_maxbolus</string>
|
||||
<string name="key_quick_wizard_data" translatable="false">quick_wizard_data</string>
|
||||
<string name="key_prime_fill" translatable="false">primefill</string>
|
||||
<string name="key_show_wizard" translatable="false">showWizard</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1,97 +0,0 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import info.nightscout.androidaps.TestBase;
|
||||
import info.nightscout.androidaps.interaction.utils.Constants;
|
||||
import info.nightscout.androidaps.testing.mockers.WearUtilMocker;
|
||||
|
||||
public class BgWatchDataTest extends TestBase {
|
||||
|
||||
@Test
|
||||
public void bgWatchDataHashTest() {
|
||||
// GIVEN
|
||||
BgWatchData inserted = new BgWatchData(
|
||||
88.0, 160.0, 90.0,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 4, 1
|
||||
);
|
||||
Set<BgWatchData> set = new HashSet<>();
|
||||
|
||||
// THEN
|
||||
//noinspection ConstantConditions
|
||||
assertFalse(set.contains(inserted));
|
||||
set.add(inserted);
|
||||
assertTrue(set.contains(inserted));
|
||||
}
|
||||
|
||||
/**
|
||||
* BgWatchData has BIZARRE equals - only timestamp and color are checked!
|
||||
*/
|
||||
@Test
|
||||
public void bgWatchDataEqualsTest() {
|
||||
// GIVEN
|
||||
BgWatchData item1 = new BgWatchData(
|
||||
88.0, 160.0, 90.0,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS, 1
|
||||
);
|
||||
|
||||
BgWatchData item2sameTimeSameColor = new BgWatchData(
|
||||
123.0, 190, 90.0,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS, 1
|
||||
);
|
||||
|
||||
BgWatchData item3sameTimeSameDiffColor = new BgWatchData(
|
||||
96.0, 190, 90.0,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS, 0
|
||||
);
|
||||
BgWatchData item4differentTime = new BgWatchData(
|
||||
88.0, 160.0, 90.0,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 2, 1
|
||||
);
|
||||
|
||||
// THEN
|
||||
assertEquals(item1, item2sameTimeSameColor);
|
||||
assertNotEquals(item1, item3sameTimeSameDiffColor);
|
||||
assertNotEquals(item1, item4differentTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* BgWatchData is ordered by timestamp, reverse order
|
||||
*/
|
||||
@Test
|
||||
public void bgWatchDataCompareTest() {
|
||||
// GIVEN
|
||||
BgWatchData item1 = new BgWatchData(
|
||||
85, 160.0, 90.0,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 2, 1
|
||||
);
|
||||
|
||||
BgWatchData item2 = new BgWatchData(
|
||||
80, 190, 90.0,
|
||||
WearUtilMocker.REF_NOW, 1
|
||||
);
|
||||
|
||||
BgWatchData item3 = new BgWatchData(
|
||||
80, 190, 50.0,
|
||||
WearUtilMocker.REF_NOW + Constants.MINUTE_IN_MS * 5, 0
|
||||
);
|
||||
|
||||
BgWatchData item4 = new BgWatchData(
|
||||
160, 140, 70.0,
|
||||
WearUtilMocker.REF_NOW, 0
|
||||
);
|
||||
|
||||
// THEN
|
||||
assertTrue(item2.compareTo(item1) < 0);
|
||||
assertTrue(item2.compareTo(item3) > 0);
|
||||
assertEquals(0, item2.compareTo(item4));
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import info.nightscout.androidaps.TestBase;
|
||||
import info.nightscout.androidaps.interaction.utils.Constants;
|
||||
import info.nightscout.androidaps.testing.mockers.WearUtilMocker;
|
||||
import info.nightscout.androidaps.testing.mocks.BundleMock;
|
||||
import info.nightscout.androidaps.testing.mocks.IntentMock;
|
||||
|
||||
public class RawDataSgvDisplayDataTest extends TestBase {
|
||||
|
||||
//==============================================================================================
|
||||
// SGV DATA
|
||||
//==============================================================================================
|
||||
|
||||
private DataMap dataMapForData() {
|
||||
DataMap dataMap = new DataMap();
|
||||
dataMap.putLong("sgvLevel", 1L);
|
||||
dataMap.putLong("timestamp", WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS);
|
||||
dataMap.putString("sgvString", "106");
|
||||
dataMap.putString("slopeArrow", "↗");
|
||||
dataMap.putString("delta", "5.4");
|
||||
dataMap.putString("avgDelta", "3.7");
|
||||
dataMap.putString("glucoseUnits", "mg/dl");
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
private void assertDataEmpty(RawDisplayData newRaw) {
|
||||
assertEquals(newRaw.sgvLevel, 0L);
|
||||
assertEquals(newRaw.datetime, 0L);
|
||||
assertEquals(newRaw.sSgv, "---");
|
||||
assertEquals(newRaw.sDirection, "--");
|
||||
assertEquals(newRaw.sDelta, "--");
|
||||
assertEquals(newRaw.sAvgDelta, "--");
|
||||
assertEquals(newRaw.sUnits, "-");
|
||||
}
|
||||
|
||||
private void assertDataOk(RawDisplayData newRaw) {
|
||||
assertEquals(newRaw.sgvLevel, 1L);
|
||||
assertEquals(newRaw.datetime, WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS);
|
||||
assertEquals(newRaw.sSgv, "106");
|
||||
assertEquals(newRaw.sDirection, "↗");
|
||||
assertEquals(newRaw.sDelta, "5.4");
|
||||
assertEquals(newRaw.sAvgDelta, "3.7");
|
||||
assertEquals(newRaw.sUnits, "mg/dl");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateDataFromEmptyPersistenceTest() {
|
||||
// GIVEN
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
newRaw.updateFromPersistence(persistence);
|
||||
|
||||
// THEN
|
||||
assertDataEmpty(newRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateDataFromPersistenceTest() {
|
||||
// GIVEN
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
persistence.storeDataMap(RawDisplayData.DATA_PERSISTENCE_KEY, dataMapForData());
|
||||
newRaw.updateFromPersistence(persistence);
|
||||
|
||||
// THEN
|
||||
assertDataOk(newRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void partialUpdateDataFromPersistenceTest() {
|
||||
// GIVEN
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
persistence.storeDataMap(RawDisplayData.DATA_PERSISTENCE_KEY, dataMapForData());
|
||||
newRaw.updateForComplicationsFromPersistence(persistence);
|
||||
|
||||
// THEN
|
||||
assertDataOk(newRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateDataFromMessageTest() {
|
||||
// GIVEN
|
||||
Intent intent = IntentMock.mock();
|
||||
Bundle bundle = BundleMock.mock(dataMapForData());
|
||||
|
||||
intent.putExtra("data", bundle);
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
newRaw.updateDataFromMessage(intent, null);
|
||||
|
||||
// THEN
|
||||
assertDataOk(newRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateDataFromEmptyMessageTest() {
|
||||
// GIVEN
|
||||
Intent intent = IntentMock.mock();
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
newRaw.updateDataFromMessage(intent, null);
|
||||
|
||||
// THEN
|
||||
assertDataEmpty(newRaw);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,242 +0,0 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import info.nightscout.androidaps.TestBase;
|
||||
import info.nightscout.androidaps.interaction.utils.Constants;
|
||||
import info.nightscout.androidaps.testing.mockers.WearUtilMocker;
|
||||
import info.nightscout.androidaps.testing.mocks.BundleMock;
|
||||
import info.nightscout.androidaps.testing.mocks.IntentMock;
|
||||
import info.nightscout.androidaps.testing.utils.BasalWatchDataExt;
|
||||
import info.nightscout.androidaps.testing.utils.BgWatchDataExt;
|
||||
import info.nightscout.androidaps.testing.utils.BolusWatchDataExt;
|
||||
import info.nightscout.androidaps.testing.utils.TempWatchDataExt;
|
||||
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
public class RawDisplayDataBasalsTest extends TestBase {
|
||||
|
||||
|
||||
//==============================================================================================
|
||||
// BASALS for chart
|
||||
//==============================================================================================
|
||||
|
||||
private DataMap dataMapForBasals() {
|
||||
|
||||
DataMap dataMap = new DataMap();
|
||||
|
||||
ArrayList<DataMap> temps = new ArrayList<>();
|
||||
DataMap temp = new DataMap();
|
||||
temp.putLong("starttime", WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 20);
|
||||
temp.putDouble("startBasal", 1.5);
|
||||
temp.putLong("endtime", WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 10);
|
||||
temp.putDouble("endbasal", 1.5);
|
||||
temp.putDouble("amount", 1.8);
|
||||
temps.add(temp);
|
||||
|
||||
DataMap temp2 = new DataMap();
|
||||
temp2.putLong("starttime", WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 10);
|
||||
temp2.putDouble("startBasal", 1.3);
|
||||
temp2.putLong("endtime", WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 2);
|
||||
temp2.putDouble("endbasal", 1.3);
|
||||
temp2.putDouble("amount", 2.3);
|
||||
temps.add(temp2);
|
||||
dataMap.putDataMapArrayList("temps", temps);
|
||||
|
||||
ArrayList<DataMap> basals = new ArrayList<>();
|
||||
DataMap basal = new DataMap();
|
||||
basal.putLong("starttime", WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 20);
|
||||
basal.putLong("endtime", WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 2);
|
||||
basal.putDouble("amount", 1.2);
|
||||
basals.add(basal);
|
||||
dataMap.putDataMapArrayList("basals", basals);
|
||||
|
||||
ArrayList<DataMap> boluses = new ArrayList<>();
|
||||
DataMap bolus = new DataMap();
|
||||
bolus.putLong("date", WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 17);
|
||||
bolus.putDouble("bolus", 5.5);
|
||||
bolus.putDouble("carbs", 20.0);
|
||||
bolus.putBoolean("isSMB", false);
|
||||
bolus.putBoolean("isValid", true);
|
||||
boluses.add(bolus);
|
||||
|
||||
DataMap bolus2 = new DataMap();
|
||||
bolus2.putLong("date", WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 11);
|
||||
bolus2.putDouble("bolus", 3.0);
|
||||
bolus2.putDouble("carbs", 0.0);
|
||||
bolus2.putBoolean("isSMB", false);
|
||||
bolus2.putBoolean("isValid", true);
|
||||
boluses.add(bolus2);
|
||||
|
||||
DataMap bolus3 = new DataMap();
|
||||
bolus3.putLong("date", WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 3);
|
||||
bolus3.putDouble("bolus", 0.0);
|
||||
bolus3.putDouble("carbs", 15.0);
|
||||
bolus3.putBoolean("isSMB", true);
|
||||
bolus3.putBoolean("isValid", false);
|
||||
boluses.add(bolus3);
|
||||
|
||||
dataMap.putDataMapArrayList("boluses", boluses);
|
||||
|
||||
ArrayList<DataMap> predictions = new ArrayList<>();
|
||||
for (int i = 0; i < 10; i++) {
|
||||
DataMap prediction = new DataMap();
|
||||
prediction.putLong("timestamp", WearUtilMocker.REF_NOW + Constants.MINUTE_IN_MS * i);
|
||||
prediction.putDouble("sgv", 160 - 4 * i);
|
||||
prediction.putInt("color", 0);
|
||||
predictions.add(prediction);
|
||||
}
|
||||
dataMap.putDataMapArrayList("predictions", predictions);
|
||||
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
private void assertBasalsEmpty(RawDisplayData newRaw) {
|
||||
assertEquals(newRaw.tempWatchDataList.size(), 0);
|
||||
assertEquals(newRaw.basalWatchDataList.size(), 0);
|
||||
assertEquals(newRaw.bolusWatchDataList.size(), 0);
|
||||
assertEquals(newRaw.predictionList.size(), 0);
|
||||
}
|
||||
|
||||
private void assertBasalsOk(RawDisplayData newRaw) {
|
||||
assertEquals(newRaw.tempWatchDataList.size(), 2);
|
||||
assertEquals(newRaw.basalWatchDataList.size(), 1);
|
||||
assertEquals(newRaw.bolusWatchDataList.size(), 3);
|
||||
assertEquals(newRaw.predictionList.size(), 10);
|
||||
|
||||
assertEquals(new TempWatchDataExt(newRaw.tempWatchDataList.get(0)), TempWatchDataExt.build(
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 20,
|
||||
1.5,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 10,
|
||||
1.5,
|
||||
1.8
|
||||
));
|
||||
|
||||
assertEquals(new TempWatchDataExt(newRaw.tempWatchDataList.get(1)), TempWatchDataExt.build(
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 10,
|
||||
1.3,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 2,
|
||||
1.3,
|
||||
2.3
|
||||
));
|
||||
|
||||
assertEquals(new BasalWatchDataExt(newRaw.basalWatchDataList.get(0)), BasalWatchDataExt.build(
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 20,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 2,
|
||||
1.2
|
||||
));
|
||||
|
||||
assertEquals(new BolusWatchDataExt(newRaw.bolusWatchDataList.get(0)), BolusWatchDataExt.build(
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 17,
|
||||
5.5,
|
||||
20,
|
||||
false,
|
||||
true
|
||||
));
|
||||
|
||||
assertEquals(new BolusWatchDataExt(newRaw.bolusWatchDataList.get(1)), BolusWatchDataExt.build(
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 11,
|
||||
3,
|
||||
0,
|
||||
false,
|
||||
true
|
||||
));
|
||||
|
||||
assertEquals(new BolusWatchDataExt(newRaw.bolusWatchDataList.get(2)), BolusWatchDataExt.build(
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 3,
|
||||
0,
|
||||
15,
|
||||
true,
|
||||
false
|
||||
));
|
||||
|
||||
|
||||
assertEquals(new BgWatchDataExt(newRaw.predictionList.get(3)), BgWatchDataExt.build(
|
||||
160 - 4 * 3,
|
||||
WearUtilMocker.REF_NOW + Constants.MINUTE_IN_MS * 3,
|
||||
0
|
||||
));
|
||||
|
||||
assertEquals(new BgWatchDataExt(newRaw.predictionList.get(7)), BgWatchDataExt.build(
|
||||
160 - 4 * 7,
|
||||
WearUtilMocker.REF_NOW + Constants.MINUTE_IN_MS * 7,
|
||||
0
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBasalsFromEmptyPersistenceTest() {
|
||||
// GIVEN
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
newRaw.updateFromPersistence(persistence);
|
||||
|
||||
// THEN
|
||||
assertBasalsEmpty(newRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBasalsFromPersistenceTest() {
|
||||
// GIVEN
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
persistence.storeDataMap(RawDisplayData.BASALS_PERSISTENCE_KEY, dataMapForBasals());
|
||||
newRaw.updateFromPersistence(persistence);
|
||||
|
||||
// THEN
|
||||
assertBasalsOk(newRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void partialUpdateBasalsFromPersistenceTest() {
|
||||
// GIVEN
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
persistence.storeDataMap(RawDisplayData.BASALS_PERSISTENCE_KEY, dataMapForBasals());
|
||||
newRaw.updateForComplicationsFromPersistence(persistence);
|
||||
|
||||
// THEN
|
||||
assertBasalsEmpty(newRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBasalsFromMessageTest() {
|
||||
// GIVEN
|
||||
Intent intent = IntentMock.mock();
|
||||
Bundle bundle = BundleMock.mock(dataMapForBasals());
|
||||
|
||||
intent.putExtra("basals", bundle);
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
newRaw.updateBasalsFromMessage(intent);
|
||||
|
||||
// THEN
|
||||
assertBasalsOk(newRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateBasalsFromEmptyMessageTest() {
|
||||
// GIVEN
|
||||
Intent intent = IntentMock.mock();
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
newRaw.updateBasalsFromMessage(intent);
|
||||
|
||||
// THEN
|
||||
assertBasalsEmpty(newRaw);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import info.nightscout.androidaps.TestBase;
|
||||
import info.nightscout.androidaps.interaction.utils.Constants;
|
||||
import info.nightscout.androidaps.testing.mockers.WearUtilMocker;
|
||||
import info.nightscout.androidaps.testing.utils.BgWatchDataExt;
|
||||
|
||||
@SuppressWarnings("PointlessArithmeticExpression")
|
||||
public class RawDisplayDataBgEntriesTest extends TestBase {
|
||||
|
||||
//==============================================================================================
|
||||
// ENTRIES for chart
|
||||
//==============================================================================================
|
||||
|
||||
private DataMap dataMapForEntries() {
|
||||
|
||||
DataMap dataMap = new DataMap();
|
||||
ArrayList<DataMap> entries = new ArrayList<>();
|
||||
for (int i = 0; i < 12; i++) {
|
||||
DataMap entry = new DataMap();
|
||||
entry.putLong("timestamp", WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 4 * (16 - i));
|
||||
entry.putDouble("sgvDouble", 145.0 - 5 * i);
|
||||
entry.putDouble("high", 170.0);
|
||||
entry.putDouble("low", 80.0);
|
||||
entry.putInt("color", 0);
|
||||
entries.add(entry);
|
||||
}
|
||||
dataMap.putDataMapArrayList("entries", entries);
|
||||
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
private DataMap dataMapForEntries(long timestamp, double sgv) {
|
||||
DataMap entry = new DataMap();
|
||||
entry.putLong("timestamp", timestamp);
|
||||
entry.putDouble("sgvDouble", sgv);
|
||||
entry.putDouble("high", 160.0);
|
||||
entry.putDouble("low", 90.0);
|
||||
entry.putInt("color", 1);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addToWatchSetTest() {
|
||||
// GIVEN
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
DataMap multipleEntries = dataMapForEntries();
|
||||
DataMap singleEntry1 = dataMapForEntries(WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 4 * 2, 92);
|
||||
DataMap singleEntry2 = dataMapForEntries(WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 4 * 1, 88);
|
||||
|
||||
// WHEN, THEN
|
||||
// add list
|
||||
newRaw.addToWatchSet(multipleEntries);
|
||||
assertEquals(newRaw.bgDataList.size(), 12);
|
||||
|
||||
assertEquals(new BgWatchDataExt(newRaw.bgDataList.get(5)),
|
||||
new BgWatchDataExt(new BgWatchData(
|
||||
120.0, 170.0, 80.0,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 4 * (16 - 5), 0
|
||||
)));
|
||||
|
||||
assertEquals(new BgWatchDataExt(newRaw.bgDataList.get(11)),
|
||||
new BgWatchDataExt(new BgWatchData(
|
||||
90.0, 170.0, 80.0,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 4 * (16 - 11), 0
|
||||
)));
|
||||
|
||||
// add single entries
|
||||
newRaw.addToWatchSet(singleEntry1);
|
||||
newRaw.addToWatchSet(singleEntry2);
|
||||
assertEquals(newRaw.bgDataList.size(), 14);
|
||||
|
||||
assertEquals(new BgWatchDataExt(newRaw.bgDataList.get(12)),
|
||||
new BgWatchDataExt(new BgWatchData(
|
||||
92.0, 160.0, 90.0,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 4 * 2, 1
|
||||
)));
|
||||
assertEquals(new BgWatchDataExt(newRaw.bgDataList.get(13)),
|
||||
new BgWatchDataExt(new BgWatchData(
|
||||
88.0, 160.0, 90.0,
|
||||
WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 4 * 1, 1
|
||||
)));
|
||||
|
||||
// ignore duplicates
|
||||
newRaw.addToWatchSet(singleEntry2);
|
||||
assertEquals(newRaw.bgDataList.size(), 14);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addToWatchSetCleanupOldTest() {
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
newRaw.addToWatchSet(dataMapForEntries(getWearUtil().timestamp(), 125));
|
||||
assertEquals(newRaw.bgDataList.size(), 1);
|
||||
|
||||
getWearUtilMocker().progressClock(Constants.HOUR_IN_MS * 2);
|
||||
newRaw.addToWatchSet(dataMapForEntries(getWearUtil().timestamp(), 140));
|
||||
assertEquals(newRaw.bgDataList.size(), 2);
|
||||
|
||||
getWearUtilMocker().progressClock(Constants.HOUR_IN_MS * 1);
|
||||
newRaw.addToWatchSet(dataMapForEntries(getWearUtil().timestamp(), 150));
|
||||
getWearUtilMocker().progressClock(Constants.HOUR_IN_MS * 1 + Constants.MINUTE_IN_MS * 30);
|
||||
newRaw.addToWatchSet(dataMapForEntries(getWearUtil().timestamp(), 101));
|
||||
assertEquals(newRaw.bgDataList.size(), 4);
|
||||
|
||||
getWearUtilMocker().progressClock(Constants.MINUTE_IN_MS * 30);
|
||||
newRaw.addToWatchSet(dataMapForEntries(getWearUtil().timestamp(), 90));
|
||||
assertEquals(newRaw.bgDataList.size(), 5);
|
||||
|
||||
getWearUtilMocker().progressClock(Constants.HOUR_IN_MS * 1 + Constants.MINUTE_IN_MS * 30);
|
||||
newRaw.addToWatchSet(dataMapForEntries(getWearUtil().timestamp(), 80));
|
||||
assertEquals(newRaw.bgDataList.size(), 5);
|
||||
|
||||
getWearUtilMocker().progressClock(Constants.HOUR_IN_MS * 4);
|
||||
newRaw.addToWatchSet(dataMapForEntries(getWearUtil().timestamp(), 92));
|
||||
assertEquals(newRaw.bgDataList.size(), 2);
|
||||
|
||||
getWearUtilMocker().progressClock(Constants.HOUR_IN_MS * 5 + Constants.MINUTE_IN_MS * 30);
|
||||
newRaw.addToWatchSet(dataMapForEntries(getWearUtil().timestamp(), 107));
|
||||
assertEquals(newRaw.bgDataList.size(), 1);
|
||||
|
||||
getWearUtilMocker().progressClock(Constants.HOUR_IN_MS * 6 + Constants.MINUTE_IN_MS * 30);
|
||||
newRaw.addToWatchSet(dataMapForEntries(getWearUtil().timestamp() - Constants.HOUR_IN_MS * 6, 138));
|
||||
assertEquals(newRaw.bgDataList.size(), 0);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
package info.nightscout.androidaps.data;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import info.nightscout.androidaps.TestBase;
|
||||
import info.nightscout.androidaps.interaction.utils.Constants;
|
||||
import info.nightscout.androidaps.testing.mockers.RawDataMocker;
|
||||
import info.nightscout.androidaps.testing.mockers.WearUtilMocker;
|
||||
import info.nightscout.androidaps.testing.mocks.BundleMock;
|
||||
import info.nightscout.androidaps.testing.mocks.IntentMock;
|
||||
|
||||
@SuppressWarnings("SimplifiableAssertion")
|
||||
public class RawDisplayDataStatusTest extends TestBase {
|
||||
|
||||
private RawDataMocker rawDataMocker;
|
||||
|
||||
@Before
|
||||
public void mock() {
|
||||
rawDataMocker = new RawDataMocker(getWearUtil());
|
||||
}
|
||||
|
||||
@SuppressWarnings("AssertBetweenInconvertibleTypes") @Test
|
||||
public void toDebugStringTest() {
|
||||
RawDisplayData raw = rawDataMocker.rawDelta(5, "1.5");
|
||||
raw.externalStatusString = "placeholder-here";
|
||||
|
||||
assertEquals(raw.datetime, WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 5);
|
||||
assertTrue(raw.toDebugString().contains("placeholder-here"));
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
// STATUS
|
||||
//==============================================================================================
|
||||
|
||||
private DataMap dataMapForStatus() {
|
||||
DataMap dataMap = new DataMap();
|
||||
dataMap.putString("currentBasal", "120%");
|
||||
dataMap.putString("battery", "76");
|
||||
dataMap.putString("rigBattery", "40%");
|
||||
dataMap.putBoolean("detailedIob", true);
|
||||
dataMap.putString("iobSum", "12.5");
|
||||
dataMap.putString("iobDetail", "(11,2|1,3)");
|
||||
dataMap.putString("cob", "5(10)g");
|
||||
dataMap.putString("bgi", "13");
|
||||
dataMap.putBoolean("showBgi", false);
|
||||
dataMap.putString("externalStatusString", "");
|
||||
dataMap.putInt("batteryLevel", 1);
|
||||
dataMap.putLong("openApsStatus", WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 2);
|
||||
return dataMap;
|
||||
}
|
||||
|
||||
private void assertStatusEmpty(RawDisplayData newRaw) {
|
||||
assertEquals(newRaw.sBasalRate, "-.--U/h");
|
||||
assertEquals(newRaw.sUploaderBattery, "--");
|
||||
assertEquals(newRaw.sRigBattery, "--");
|
||||
assertEquals(newRaw.detailedIOB, false);
|
||||
assertEquals(newRaw.sIOB1, "IOB");
|
||||
assertEquals(newRaw.sIOB2, "-.--");
|
||||
assertEquals(newRaw.sCOB1, "Carb");
|
||||
assertEquals(newRaw.sCOB2, "--g");
|
||||
assertEquals(newRaw.sBgi, "--");
|
||||
assertEquals(newRaw.showBGI, false);
|
||||
assertEquals(newRaw.externalStatusString, "no status");
|
||||
assertEquals(newRaw.batteryLevel, 1);
|
||||
assertEquals(newRaw.openApsStatus, -1L);
|
||||
}
|
||||
|
||||
private void assertStatusOk(RawDisplayData newRaw) {
|
||||
assertEquals(newRaw.sBasalRate, "120%");
|
||||
assertEquals(newRaw.sUploaderBattery, "76");
|
||||
assertEquals(newRaw.sRigBattery, "40%");
|
||||
assertEquals(newRaw.detailedIOB, true);
|
||||
assertEquals(newRaw.sIOB1, "12.5U");
|
||||
assertEquals(newRaw.sIOB2, "(11,2|1,3)");
|
||||
assertEquals(newRaw.sCOB1, "Carb");
|
||||
assertEquals(newRaw.sCOB2, "5(10)g");
|
||||
assertEquals(newRaw.sBgi, "13");
|
||||
assertEquals(newRaw.showBGI, false);
|
||||
assertEquals(newRaw.externalStatusString, "");
|
||||
assertEquals(newRaw.batteryLevel, 1);
|
||||
assertEquals(newRaw.openApsStatus, WearUtilMocker.REF_NOW - Constants.MINUTE_IN_MS * 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateStatusFromEmptyPersistenceTest() {
|
||||
// GIVEN
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
newRaw.updateFromPersistence(persistence);
|
||||
|
||||
// THEN
|
||||
assertStatusEmpty(newRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateStatusFromPersistenceTest() {
|
||||
// GIVEN
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
persistence.storeDataMap(RawDisplayData.STATUS_PERSISTENCE_KEY, dataMapForStatus());
|
||||
newRaw.updateFromPersistence(persistence);
|
||||
|
||||
// THEN
|
||||
assertStatusOk(newRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void partialUpdateStatusFromPersistenceTest() {
|
||||
// GIVEN
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
persistence.storeDataMap(RawDisplayData.STATUS_PERSISTENCE_KEY, dataMapForStatus());
|
||||
newRaw.updateForComplicationsFromPersistence(persistence);
|
||||
|
||||
// THEN
|
||||
assertStatusOk(newRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateStatusFromMessageTest() {
|
||||
// GIVEN
|
||||
Intent intent = IntentMock.mock();
|
||||
Bundle bundle = BundleMock.mock(dataMapForStatus());
|
||||
|
||||
intent.putExtra("status", bundle);
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
newRaw.updateStatusFromMessage(intent, null);
|
||||
|
||||
// THEN
|
||||
assertStatusOk(newRaw);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateStatusFromEmptyMessageTest() {
|
||||
// GIVEN
|
||||
Intent intent = IntentMock.mock();
|
||||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
newRaw.updateStatusFromMessage(intent, null);
|
||||
|
||||
// THEN
|
||||
assertStatusEmpty(newRaw);
|
||||
}
|
||||
|
||||
}
|
|
@ -106,10 +106,10 @@ public class DisplayFormatTest extends TestBase {
|
|||
|
||||
@Test
|
||||
public void shortTrendTest() {
|
||||
RawDisplayData raw = new RawDisplayData(wearUtil);
|
||||
RawDisplayData raw = new RawDisplayData();
|
||||
assertEquals(displayFormat.shortTrend(raw), "-- Δ--");
|
||||
|
||||
raw.datetime = wearUtilMocker.backInTime(0, 0, 2, 0);
|
||||
raw.getSingleBg().setTimeStamp(wearUtilMocker.backInTime(0, 0, 2, 0));
|
||||
assertEquals(displayFormat.shortTrend(raw), "2' Δ--");
|
||||
|
||||
when(sp.getBoolean("complication_unicode", true)).thenReturn(true);
|
||||
|
|
|
@ -2,12 +2,7 @@ package info.nightscout.androidaps.interaction.utils;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static info.nightscout.androidaps.testing.mockers.WearUtilMocker.REF_NOW;
|
||||
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -42,62 +37,6 @@ public class PersistenceTest extends TestBase {
|
|||
assertTrue(updatedGot);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenDataUpdatedTest() {
|
||||
// GIVEN
|
||||
DataMap map = new DataMap();
|
||||
|
||||
// WHEN
|
||||
final long whenNotUpdated = persistence.whenDataUpdated();
|
||||
|
||||
persistence.storeDataMap("data-map", map);
|
||||
final long whenUpdatedFirst = persistence.whenDataUpdated();
|
||||
|
||||
getWearUtilMocker().progressClock(60000);
|
||||
persistence.storeDataMap("data-map", map);
|
||||
final long whenUpdatedNext = persistence.whenDataUpdated();
|
||||
|
||||
// THEN
|
||||
assertEquals(whenNotUpdated, 0L);
|
||||
assertEquals(whenUpdatedFirst, REF_NOW);
|
||||
assertEquals(whenUpdatedNext, REF_NOW + 60000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getDataMapTest() {
|
||||
// GIVEN
|
||||
DataMap map = new DataMap();
|
||||
map.putByteArray("test-key", new byte[]{9, 42, 127, -5});
|
||||
|
||||
// WHEN
|
||||
DataMap notExisting = persistence.getDataMap("not-there");
|
||||
persistence.storeDataMap("data-map", map);
|
||||
DataMap restoredMap = persistence.getDataMap("data-map");
|
||||
assert restoredMap != null;
|
||||
byte[] restoredMapContents = restoredMap.getByteArray("test-key");
|
||||
|
||||
// THEN
|
||||
assertNull(notExisting);
|
||||
assertNotNull(restoredMap);
|
||||
assertTrue(restoredMap.containsKey("test-key"));
|
||||
|
||||
assertEquals(restoredMapContents.length, 4);
|
||||
assertEquals(restoredMapContents[0], (byte) 9);
|
||||
assertEquals(restoredMapContents[1], (byte) 42);
|
||||
assertEquals(restoredMapContents[2], (byte) 127);
|
||||
assertEquals(restoredMapContents[3], (byte) -5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void brokenDataMapTest() {
|
||||
// WHEN
|
||||
persistence.putString("data-map", "ZmFrZSBkYXRh");
|
||||
DataMap restoredMap = persistence.getDataMap("data-map");
|
||||
|
||||
// THEN
|
||||
assertNull(restoredMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setsTest() {
|
||||
// WHEN
|
||||
|
|
|
@ -4,15 +4,14 @@ import com.google.android.gms.wearable.DataMap
|
|||
import info.nightscout.androidaps.TestBase
|
||||
import info.nightscout.androidaps.testing.mockers.WearUtilMocker
|
||||
import info.nightscout.androidaps.testing.mocks.BundleMock
|
||||
import org.hamcrest.CoreMatchers
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Created by dlvoy on 22.11.2019.
|
||||
*/
|
||||
@Suppress("SpellCheckingInspection") class WearUtilTest : TestBase() {
|
||||
@Suppress("SpellCheckingInspection")
|
||||
class WearUtilTest : TestBase() {
|
||||
|
||||
@Test fun timestampAndTimeDiffsTest() {
|
||||
|
||||
|
|
|
@ -3,70 +3,138 @@ package info.nightscout.androidaps.testing.mockers;
|
|||
import info.nightscout.androidaps.data.RawDisplayData;
|
||||
import info.nightscout.androidaps.interaction.utils.WearUtil;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.EventData;
|
||||
|
||||
@SuppressWarnings("PointlessArithmeticExpression")
|
||||
public class RawDataMocker {
|
||||
|
||||
private final WearUtil wearUtil;
|
||||
private final WearUtilMocker wearUtilMocker;
|
||||
|
||||
public RawDataMocker(WearUtil wearUtil) {
|
||||
this.wearUtil = wearUtil;
|
||||
wearUtilMocker = new WearUtilMocker(wearUtil);
|
||||
}
|
||||
|
||||
public RawDisplayData rawSgv(String sgv, int m, String deltaString) {
|
||||
RawDisplayData raw = new RawDisplayData(wearUtil);
|
||||
raw.datetime = wearUtilMocker.backInTime(0, 0, m, 0);
|
||||
raw.sDelta = deltaString;
|
||||
raw.sSgv = sgv;
|
||||
|
||||
RawDisplayData raw = new RawDisplayData();
|
||||
double delta = SafeParse.stringToDouble(deltaString);
|
||||
String d;
|
||||
|
||||
if (delta <= (-3.5 * 5)) {
|
||||
raw.sDirection = "\u21ca";
|
||||
d = "\u21ca";
|
||||
} else if (delta <= (-2 * 5)) {
|
||||
raw.sDirection = "\u2193";
|
||||
d = "\u2193";
|
||||
} else if (delta <= (-1 * 5)) {
|
||||
raw.sDirection = "\u2198";
|
||||
d = "\u2198";
|
||||
} else if (delta <= (1 * 5)) {
|
||||
raw.sDirection = "\u2192";
|
||||
d = "\u2192";
|
||||
} else if (delta <= (2 * 5)) {
|
||||
raw.sDirection = "\u2197";
|
||||
d = "\u2197";
|
||||
} else if (delta <= (3.5 * 5)) {
|
||||
raw.sDirection = "\u2191";
|
||||
d = "\u2191";
|
||||
} else {
|
||||
raw.sDirection = "\u21c8";
|
||||
d = "\u21c8";
|
||||
}
|
||||
|
||||
raw.setSingleBg(
|
||||
new EventData.SingleBg(
|
||||
wearUtilMocker.backInTime(0, 0, m, 0),
|
||||
sgv,
|
||||
"",
|
||||
d,
|
||||
deltaString,
|
||||
"",
|
||||
0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0
|
||||
)
|
||||
);
|
||||
return raw;
|
||||
}
|
||||
|
||||
public RawDisplayData rawDelta(int m, String delta) {
|
||||
RawDisplayData raw = new RawDisplayData(wearUtil);
|
||||
raw.datetime = wearUtilMocker.backInTime(0, 0, m, 0);
|
||||
raw.sDelta = delta;
|
||||
RawDisplayData raw = new RawDisplayData();
|
||||
raw.setSingleBg(
|
||||
new EventData.SingleBg(
|
||||
wearUtilMocker.backInTime(0, 0, m, 0),
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
delta,
|
||||
"",
|
||||
0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0
|
||||
)
|
||||
);
|
||||
return raw;
|
||||
}
|
||||
|
||||
public RawDisplayData rawCobIobBr(String cob, String iob, String br) {
|
||||
RawDisplayData raw = new RawDisplayData(wearUtil);
|
||||
raw.sCOB2 = cob;
|
||||
raw.sIOB1 = iob;
|
||||
raw.sBasalRate = br;
|
||||
RawDisplayData raw = new RawDisplayData();
|
||||
raw.setStatus(
|
||||
new EventData.Status(
|
||||
"",
|
||||
iob,
|
||||
"",
|
||||
true,
|
||||
cob,
|
||||
br,
|
||||
"",
|
||||
"",
|
||||
0L,
|
||||
"",
|
||||
true,
|
||||
0
|
||||
|
||||
)
|
||||
);
|
||||
return raw;
|
||||
}
|
||||
|
||||
public RawDisplayData rawIob(String iob, String iob2) {
|
||||
RawDisplayData raw = new RawDisplayData(wearUtil);
|
||||
raw.sIOB1 = iob;
|
||||
raw.sIOB2 = iob2;
|
||||
RawDisplayData raw = new RawDisplayData();
|
||||
raw.setStatus(
|
||||
new EventData.Status(
|
||||
"",
|
||||
iob,
|
||||
iob2,
|
||||
true,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
0L,
|
||||
"",
|
||||
true,
|
||||
0
|
||||
|
||||
)
|
||||
);
|
||||
return raw;
|
||||
}
|
||||
|
||||
public RawDisplayData rawCob(String cob) {
|
||||
RawDisplayData raw = new RawDisplayData(wearUtil);
|
||||
raw.sCOB2 = cob;
|
||||
RawDisplayData raw = new RawDisplayData();
|
||||
raw.setStatus(
|
||||
new EventData.Status(
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
true,
|
||||
cob,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
0L,
|
||||
"",
|
||||
true,
|
||||
0
|
||||
|
||||
)
|
||||
);
|
||||
return raw;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
package info.nightscout.androidaps.testing.utils;
|
||||
|
||||
import static info.nightscout.androidaps.testing.utils.ExtUtil.assertClassHaveSameFields;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import info.nightscout.androidaps.data.BasalWatchData;
|
||||
|
||||
public class BasalWatchDataExt extends BasalWatchData {
|
||||
|
||||
private BasalWatchDataExt() {
|
||||
super();
|
||||
}
|
||||
|
||||
public BasalWatchDataExt(BasalWatchData ref) {
|
||||
super();
|
||||
|
||||
// since we do not want modify BasalWatchData - we use this wrapper class
|
||||
// but we make sure it has same fields
|
||||
assertClassHaveSameFields(BasalWatchData.class, "startTime,endTime,amount");
|
||||
|
||||
this.startTime = ref.startTime;
|
||||
this.endTime = ref.endTime;
|
||||
this.amount = ref.amount;
|
||||
}
|
||||
|
||||
public static BasalWatchDataExt build(long startTime, long endTime, double amount) {
|
||||
BasalWatchDataExt bwd = new BasalWatchDataExt();
|
||||
bwd.startTime = startTime;
|
||||
bwd.endTime = endTime;
|
||||
bwd.amount = amount;
|
||||
return bwd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj instanceof BasalWatchData) {
|
||||
return (this.startTime == ((BasalWatchData) obj).startTime)
|
||||
&& (this.endTime == ((BasalWatchData) obj).endTime)
|
||||
&& (this.amount == ((BasalWatchData) obj).amount);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public String toString() {
|
||||
return startTime + ", " + endTime + ", " + amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(startTime, endTime, amount);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package info.nightscout.androidaps.testing.utils;
|
||||
|
||||
import static info.nightscout.androidaps.testing.utils.ExtUtil.assertClassHaveSameFields;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import info.nightscout.androidaps.data.BgWatchData;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class BgWatchDataExt extends BgWatchData {
|
||||
|
||||
private BgWatchDataExt() {
|
||||
super();
|
||||
}
|
||||
|
||||
public BgWatchDataExt(double aSgv, double aHigh, double aLow, long aTimestamp, int aColor) {
|
||||
super(aSgv, aHigh, aLow, aTimestamp, aColor);
|
||||
}
|
||||
|
||||
public BgWatchDataExt(BgWatchData ref) {
|
||||
super();
|
||||
|
||||
// since we do not want modify BgWatchDataExt - we use this wrapper class
|
||||
// but we make sure it has same fields
|
||||
assertClassHaveSameFields(BgWatchData.class, "sgv,high,low,timestamp,color");
|
||||
|
||||
this.sgv = ref.sgv;
|
||||
this.high = ref.high;
|
||||
this.low = ref.low;
|
||||
this.timestamp = ref.timestamp;
|
||||
this.color = ref.color;
|
||||
}
|
||||
|
||||
public static BgWatchDataExt build(double sgv, long timestamp, int color) {
|
||||
BgWatchDataExt twd = new BgWatchDataExt();
|
||||
twd.sgv = sgv;
|
||||
twd.timestamp = timestamp;
|
||||
twd.color = color;
|
||||
return twd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj instanceof BgWatchData) {
|
||||
return (this.sgv == ((BgWatchData) obj).sgv)
|
||||
&& (this.high == ((BgWatchData) obj).high)
|
||||
&& (this.low == ((BgWatchData) obj).low)
|
||||
&& (this.timestamp == ((BgWatchData) obj).timestamp)
|
||||
&& (this.color == ((BgWatchData) obj).color);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override @NonNull
|
||||
public String toString() {
|
||||
return sgv + ", " + high + ", " + low + ", " + timestamp + ", " + color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(sgv, high, low, timestamp, color);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package info.nightscout.androidaps.testing.utils;
|
||||
|
||||
import static info.nightscout.androidaps.testing.utils.ExtUtil.assertClassHaveSameFields;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import info.nightscout.androidaps.data.BolusWatchData;
|
||||
|
||||
public class BolusWatchDataExt extends BolusWatchData {
|
||||
|
||||
private BolusWatchDataExt() {
|
||||
super();
|
||||
}
|
||||
|
||||
public BolusWatchDataExt(BolusWatchData ref) {
|
||||
super();
|
||||
|
||||
// since we do not want modify BolusWatchData - we use this wrapper class
|
||||
// but we make sure it has same fields
|
||||
assertClassHaveSameFields(BolusWatchData.class, "date,bolus,carbs,isSMB,isValid");
|
||||
|
||||
this.date = ref.date;
|
||||
this.bolus = ref.bolus;
|
||||
this.carbs = ref.carbs;
|
||||
this.isSMB = ref.isSMB;
|
||||
this.isValid = ref.isValid;
|
||||
}
|
||||
|
||||
public static BolusWatchDataExt build(long date, double bolus, double carbs, boolean isSMB, boolean isValid) {
|
||||
BolusWatchDataExt bwd = new BolusWatchDataExt();
|
||||
bwd.date = date;
|
||||
bwd.bolus = bolus;
|
||||
bwd.carbs = carbs;
|
||||
bwd.isSMB = isSMB;
|
||||
bwd.isValid = isValid;
|
||||
return bwd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj instanceof BolusWatchData) {
|
||||
return (this.date == ((BolusWatchData) obj).date)
|
||||
&& (this.bolus == ((BolusWatchData) obj).bolus)
|
||||
&& (this.carbs == ((BolusWatchData) obj).carbs)
|
||||
&& (this.isSMB == ((BolusWatchData) obj).isSMB)
|
||||
&& (this.isValid == ((BolusWatchData) obj).isValid);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public String toString() {
|
||||
return date + ", " + bolus + ", " + carbs + ", " + isSMB + ", " + isValid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(date, bolus, carbs, isSMB, isValid);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package info.nightscout.androidaps.testing.utils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
class ExtUtil {
|
||||
|
||||
static <T> void assertClassHaveSameFields(Class<T> checkedClass, String commaSeparatedFieldList) {
|
||||
Set<String> parentFields = new HashSet<>();
|
||||
for (Field f : checkedClass.getDeclaredFields()) {
|
||||
final String fieldName = f.getName();
|
||||
// skip runtime-injected fields like $jacocoData
|
||||
if (fieldName.startsWith("$")) {
|
||||
continue;
|
||||
}
|
||||
parentFields.add(fieldName);
|
||||
}
|
||||
|
||||
Set<String> knownFields = new HashSet<>(Arrays.asList(commaSeparatedFieldList.split(",")));
|
||||
assertEquals(parentFields, knownFields);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
package info.nightscout.androidaps.testing.utils;
|
||||
|
||||
import static info.nightscout.androidaps.testing.utils.ExtUtil.assertClassHaveSameFields;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import info.nightscout.androidaps.data.TempWatchData;
|
||||
|
||||
|
||||
public class TempWatchDataExt extends TempWatchData {
|
||||
|
||||
private TempWatchDataExt() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TempWatchDataExt(TempWatchData ref) {
|
||||
super();
|
||||
|
||||
// since we do not want modify BolusWatchData - we use this wrapper class
|
||||
// but we make sure it has same fields
|
||||
assertClassHaveSameFields(TempWatchData.class, "startTime,startBasal,endTime,endBasal,amount");
|
||||
|
||||
this.startTime = ref.startTime;
|
||||
this.startBasal = ref.startBasal;
|
||||
this.endTime = ref.endTime;
|
||||
this.endBasal = ref.endBasal;
|
||||
this.amount = ref.amount;
|
||||
}
|
||||
|
||||
public static TempWatchDataExt build(long startTime, double startBasal, long endTime,
|
||||
double endBasal, double amount) {
|
||||
TempWatchDataExt twd = new TempWatchDataExt();
|
||||
twd.startTime = startTime;
|
||||
twd.startBasal = startBasal;
|
||||
twd.endTime = endTime;
|
||||
twd.endBasal = endBasal;
|
||||
twd.amount = amount;
|
||||
return twd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (obj instanceof TempWatchData) {
|
||||
return (this.startTime == ((TempWatchData) obj).startTime)
|
||||
&& (this.startBasal == ((TempWatchData) obj).startBasal)
|
||||
&& (this.endTime == ((TempWatchData) obj).endTime)
|
||||
&& (this.endBasal == ((TempWatchData) obj).endBasal)
|
||||
&& (this.amount == ((TempWatchData) obj).amount);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
public String toString() {
|
||||
return startTime + ", " + startBasal + ", " + endTime + ", " + endBasal + ", " + amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(startTime, startBasal, endTime, endBasal, amount);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue