Wear refactor
This commit is contained in:
parent
391a471b27
commit
2dba081176
|
@ -46,6 +46,10 @@
|
|||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme.Launcher" >
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
|
||||
<activity
|
||||
android:name=".widget.WidgetConfigureActivity"
|
||||
android:theme="@android:style/Theme.Material.Dialog.NoActionBar"
|
||||
|
@ -106,14 +110,6 @@
|
|||
android:theme="@style/AppTheme" />
|
||||
<activity android:name=".activities.StatsActivity"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity
|
||||
android:name="com.google.firebase.auth.internal.FederatedSignInActivity"
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="true"
|
||||
android:launchMode="singleInstance"
|
||||
android:permission="com.google.firebase.auth.api.gms.permission.LAUNCH_FEDERATED_SIGN_IN"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
tools:replace="android:launchMode" />
|
||||
|
||||
<!-- Receive new BG readings from other local apps -->
|
||||
<receiver
|
||||
|
@ -174,62 +170,38 @@
|
|||
android:name=".plugins.general.wear.wearintegration.WatchUpdaterService"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<!-- <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> -->
|
||||
<!-- listeners receive events that match the action and data filters -->
|
||||
<action android:name="com.google.android.gms.wearable.CAPABILITY_CHANGED" />
|
||||
<action android:name="com.google.android.gms.wearable.CHANNEL_EVENT" />
|
||||
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.wearable.CAPABILITY_CHANGED" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:scheme="wear" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<!-- listeners receive events that match the action and data filters -->
|
||||
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
|
||||
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_data"
|
||||
android:pathPrefix="@string/path_pong"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_data_resend"
|
||||
android:pathPrefix="@string/path_resend_data_request"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_cancel_bolus"
|
||||
android:pathPrefix="/@path_cancel_bolus_on_watch"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_confirmactionstring"
|
||||
android:pathPrefix="@string/path_confirm_action"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_initiateactionstring"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/openwearsettings"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/sendstatustowear"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/sendpreferencestowear"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_basal"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_bolusprogress"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_actionconfirmationrequest"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_changeconfirmationrequest"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_cancelnotificationrequest"
|
||||
android:pathPrefix="@string/path_initiate_action_on_phone"
|
||||
android:scheme="wear" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
@ -247,10 +219,6 @@
|
|||
|
||||
<service android:name=".plugins.general.persistentNotification.DummyService" />
|
||||
|
||||
<meta-data
|
||||
android:name="io.fabric.ApiKey"
|
||||
android:value="59d462666c664c57b29e1d79ea123e01f8057cfa" />
|
||||
|
||||
<activity
|
||||
android:name=".setupwizard.SetupWizardActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
|
|
|
@ -33,7 +33,11 @@ import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionChec
|
|||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
|
||||
import info.nightscout.androidaps.plugins.general.themes.ThemeSwitcherPlugin
|
||||
import info.nightscout.androidaps.receivers.*
|
||||
import info.nightscout.androidaps.receivers.BTReceiver
|
||||
import info.nightscout.androidaps.receivers.ChargingStateReceiver
|
||||
import info.nightscout.androidaps.receivers.KeepAliveWorker
|
||||
import info.nightscout.androidaps.receivers.NetworkChangeReceiver
|
||||
import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver
|
||||
import info.nightscout.androidaps.services.AlarmSoundServiceHelper
|
||||
import info.nightscout.androidaps.utils.ActivityMonitor
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
|
|
|
@ -37,7 +37,7 @@ class SurveyActivity : NoSplashAppCompatActivity() {
|
|||
binding = ActivitySurveyBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
binding.id.text = InstanceId.instanceId()
|
||||
binding.id.text = InstanceId.instanceId
|
||||
|
||||
val profileStore = activePlugin.activeProfileSource.profile
|
||||
val profileList = profileStore?.getProfileList() ?: return
|
||||
|
@ -80,7 +80,7 @@ class SurveyActivity : NoSplashAppCompatActivity() {
|
|||
|
||||
binding.submit.setOnClickListener {
|
||||
val r = FirebaseRecord()
|
||||
r.id = InstanceId.instanceId()
|
||||
r.id = InstanceId.instanceId
|
||||
r.age = SafeParse.stringToInt(binding.age.text.toString())
|
||||
r.weight = SafeParse.stringToInt(binding.weight.text.toString())
|
||||
if (r.age < 1 || r.age > 120) {
|
||||
|
|
|
@ -2,4 +2,4 @@ package info.nightscout.androidaps.plugins.general.tidepool.events
|
|||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventTidepoolResetData :Event()
|
||||
class EventTidepoolResetData : Event()
|
|
@ -2,7 +2,6 @@ package info.nightscout.androidaps.plugins.general.wear
|
|||
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
|
@ -25,8 +24,6 @@ import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTe
|
|||
import info.nightscout.androidaps.extensions.total
|
||||
import info.nightscout.androidaps.extensions.valueToUnits
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
|
||||
|
@ -38,10 +35,28 @@ 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.shared.sharedPreferences.SP
|
||||
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
|
||||
|
@ -96,7 +111,7 @@ class ActionStringHandler @Inject constructor(
|
|||
disposable += rxBus
|
||||
.toObservable(EventWearInitiateAction::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ handleInitiate(it.action) }, fabricPrivacy::logException)
|
||||
.subscribe({ handleInitiateActionOnPhone(it.action) }, fabricPrivacy::logException)
|
||||
|
||||
disposable += rxBus
|
||||
.toObservable(EventWearConfirmAction::class.java)
|
||||
|
@ -109,328 +124,360 @@ class ActionStringHandler @Inject constructor(
|
|||
}
|
||||
|
||||
@Synchronized
|
||||
private fun handleInitiate(actionString: String) {
|
||||
private fun handleInitiateActionOnPhone(actionString: String) {
|
||||
//TODO: i18n
|
||||
Log.i("ActionStringHandler", "handleInitiate actionString=$actionString")
|
||||
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 = ""
|
||||
// do the parsing and check constraints
|
||||
val act = actionString.split("\\s+".toRegex()).toTypedArray()
|
||||
if ("fillpreset" == act[0]) { ///////////////////////////////////// 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"
|
||||
} else if ("fill" == act[0]) { ////////////////////////////////////////////// PRIME/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"
|
||||
} else if ("bolus" == act[0]) { ////////////////////////////////////////////// BOLUS
|
||||
val insulin = SafeParse.stringToDouble(act[1])
|
||||
val carbs = SafeParse.stringToInt(act[2])
|
||||
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
|
||||
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(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 - insulin != 0.0 || carbsAfterConstraints - carbs != 0) {
|
||||
rMessage += "\n" + rh.gs(R.string.constraintapllied)
|
||||
}
|
||||
rAction += "bolus $insulinAfterConstraints $carbsAfterConstraints"
|
||||
} else if ("temptarget" == act[0]) { ///////////////////////////////////////////////////////// TEMPTARGET
|
||||
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"
|
||||
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
|
||||
}
|
||||
|
||||
"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"
|
||||
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)
|
||||
}
|
||||
|
||||
else -> {
|
||||
sendError(rh.gs(R.string.wear_action_tempt_preset_error, preset))
|
||||
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 {
|
||||
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
|
||||
}
|
||||
} 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"
|
||||
}
|
||||
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_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"
|
||||
}
|
||||
}
|
||||
} else if ("status" == act[0]) { ////////////////////////////////////////////// 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"
|
||||
}
|
||||
} else if ("wizard" == act[0]) {
|
||||
sendError("Update APP on Watch!")
|
||||
return
|
||||
} else if ("wizard2" == act[0]) { ////////////////////////////////////////////// WIZARD
|
||||
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
|
||||
} else if ("quick_wizard" == act[0]) {
|
||||
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
|
||||
}
|
||||
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"
|
||||
}
|
||||
|
||||
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg, true)
|
||||
"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"
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
"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"
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
} else if ("opencpp" == act[0]) {
|
||||
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
|
||||
}
|
||||
} else if ("cppset" == act[0]) {
|
||||
val activeProfileSwitch = repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet()
|
||||
if (activeProfileSwitch is ValueWrapper.Existing) {
|
||||
rMessage = "CPP:" + "\n\n" +
|
||||
"Timeshift: " + act[1] + "\n" +
|
||||
"Percentage: " + act[2] + "%"
|
||||
rAction = actionString
|
||||
} else { // read CPP values
|
||||
sendError("No active profile switch!")
|
||||
return
|
||||
}
|
||||
} else if ("tddstats" == act[0]) {
|
||||
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 -> {
|
||||
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
|
||||
}
|
||||
} else { // if up to date: prepare, send (check if CPP is activated -> add CPP stats)
|
||||
rTitle = "TDD"
|
||||
rAction = "statusmessage"
|
||||
rMessage = generateTDDMessage(historyList, dummies)
|
||||
}
|
||||
} else if ("ecarbs" == act[0]) { ////////////////////////////////////////////// ECARBS
|
||||
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"
|
||||
} else if ("changeRequest" == act[0]) { ////////////////////////////////////////////// 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
|
||||
} else if ("cancelChangeRequest" == act[0]) { ////////////////////////////////////////////// CANCEL CHANGE REQUEST NOTIFICATION
|
||||
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)
|
||||
|
@ -594,44 +641,60 @@ class ActionStringHandler @Inject constructor(
|
|||
lastConfirmActionString = null
|
||||
// do the parsing, check constraints and enact!
|
||||
val act = actionString.split("\\s+".toRegex()).toTypedArray()
|
||||
if ("fill" == act[0]) {
|
||||
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
|
||||
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)
|
||||
}
|
||||
doFillBolus(amount)
|
||||
} else if ("temptarget" == act[0]) {
|
||||
val duration = SafeParse.stringToInt(act[2])
|
||||
val low = SafeParse.stringToDouble(act[3])
|
||||
val high = SafeParse.stringToDouble(act[4])
|
||||
generateTempTarget(duration, low, high)
|
||||
} else if ("wizard2" == act[0]) {
|
||||
if (lastBolusWizard != null) { //use last calculation as confirmed string matches
|
||||
doBolus(lastBolusWizard!!.calculatedTotalInsulin, lastBolusWizard!!.carbs, null, 0)
|
||||
lastBolusWizard = null
|
||||
|
||||
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)
|
||||
}
|
||||
} else if ("bolus" == act[0]) {
|
||||
val insulin = SafeParse.stringToDouble(act[1])
|
||||
val carbs = SafeParse.stringToInt(act[2])
|
||||
doBolus(insulin, carbs, null, 0)
|
||||
} else if ("cppset" == act[0]) {
|
||||
val timeshift = SafeParse.stringToInt(act[1])
|
||||
val percentage = SafeParse.stringToInt(act[2])
|
||||
setCPP(timeshift, percentage)
|
||||
} else if ("ecarbs" == act[0]) {
|
||||
val carbs = SafeParse.stringToInt(act[1])
|
||||
val starttime = SafeParse.stringToLong(act[2])
|
||||
val duration = SafeParse.stringToInt(act[3])
|
||||
doECarbs(carbs, starttime, duration)
|
||||
} else if ("dismissoverviewnotification" == act[0]) {
|
||||
rxBus.send(EventDismissNotification(SafeParse.stringToInt(act[1])))
|
||||
} else if ("changeRequest" == act[0]) {
|
||||
loop.acceptChangeRequest()
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.cancel(Constants.notificationID)
|
||||
}
|
||||
lastBolusWizard = null
|
||||
}
|
||||
|
|
|
@ -6,14 +6,25 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import dagger.android.support.DaggerFragment
|
||||
import info.nightscout.androidaps.databinding.WearFragmentBinding
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
|
||||
class WearFragment : DaggerFragment() {
|
||||
|
||||
@Inject lateinit var wearPlugin: WearPlugin
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
@Inject lateinit var aapsSchedulers: AapsSchedulers
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
|
||||
private var _binding: WearFragmentBinding? = null
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
@ -27,7 +38,21 @@ 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.openSettings.setOnClickListener { wearPlugin.openSettings() }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
disposable += rxBus
|
||||
.toObservable(EventNSClientUpdateGUI::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({ updateGui() }, fabricPrivacy::logException)
|
||||
updateGui()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
@ -35,4 +60,9 @@ class WearFragment : DaggerFragment() {
|
|||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
fun updateGui() {
|
||||
_binding ?: return
|
||||
binding.connectedDevice.text = wearPlugin.connectedDevice
|
||||
}
|
||||
}
|
|
@ -6,12 +6,11 @@ import dagger.Lazy
|
|||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.*
|
||||
import info.nightscout.androidaps.interfaces.Loop
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
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
|
||||
|
@ -19,8 +18,10 @@ import info.nightscout.androidaps.plugins.general.wear.wearintegration.WatchUpda
|
|||
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 io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -33,100 +34,103 @@ class WearPlugin @Inject constructor(
|
|||
private val sp: SP,
|
||||
private val ctx: Context,
|
||||
private val fabricPrivacy: FabricPrivacy,
|
||||
private val loop: Loop,
|
||||
private val rxBus: RxBus,
|
||||
private val actionStringHandler: Lazy<ActionStringHandler>
|
||||
|
||||
) : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
.fragmentClass(WearFragment::class.java.name)
|
||||
.pluginIcon(R.drawable.ic_watch)
|
||||
.pluginName(R.string.wear)
|
||||
.shortName(R.string.wear_shortname)
|
||||
.preferencesId(R.xml.pref_wear)
|
||||
.description(R.string.description_wear),
|
||||
) : PluginBase(
|
||||
PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
.fragmentClass(WearFragment::class.java.name)
|
||||
.pluginIcon(R.drawable.ic_watch)
|
||||
.pluginName(R.string.wear)
|
||||
.shortName(R.string.wear_shortname)
|
||||
.preferencesId(R.xml.pref_wear)
|
||||
.description(R.string.description_wear),
|
||||
aapsLogger, rh, injector
|
||||
) {
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
var connectedDevice = "---"
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
disposable.add(rxBus
|
||||
disposable += rxBus
|
||||
.toObservable(EventOpenAPSUpdateGui::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
.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.add(rxBus
|
||||
.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.add(rxBus
|
||||
.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.add(rxBus
|
||||
.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.add(rxBus
|
||||
.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.add(rxBus
|
||||
.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.add(rxBus
|
||||
.toObservable(EventRefreshOverview::class.java)
|
||||
// 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({
|
||||
if (WatchUpdaterService.shouldReportLoopStatus((loop as PluginBase).isEnabled()))
|
||||
sendDataToWatch(status = true, basals = false, bgValue = false)
|
||||
}, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
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_BOLUSPROGRESS)
|
||||
intent.putExtra("progresspercent", 0)
|
||||
intent.putExtra("progressstatus", status)
|
||||
ctx.startService(intent)
|
||||
}, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
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)
|
||||
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)
|
||||
}
|
||||
val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_BOLUSPROGRESS)
|
||||
intent.putExtra("progresspercent", 100)
|
||||
intent.putExtra("progressstatus", status)
|
||||
ctx.startService(intent)
|
||||
}, fabricPrivacy::logException))
|
||||
disposable.add(rxBus
|
||||
if (event.result == null) return@subscribe
|
||||
val status: String = if (event.result!!.success) {
|
||||
rh.gs(R.string.success)
|
||||
} else {
|
||||
rh.gs(R.string.nosuccess)
|
||||
}
|
||||
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_BOLUSPROGRESS)
|
||||
intent.putExtra("progresspercent", event.percent)
|
||||
intent.putExtra("progressstatus", event.status)
|
||||
ctx.startService(intent)
|
||||
}
|
||||
}, fabricPrivacy::logException))
|
||||
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)
|
||||
}
|
||||
}, fabricPrivacy::logException)
|
||||
actionStringHandler.get().setup()
|
||||
}
|
||||
|
||||
|
@ -137,51 +141,50 @@ class WearPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
private fun sendDataToWatch(status: Boolean, basals: Boolean, bgValue: Boolean) {
|
||||
//Log.d(TAG, "WR: WearPlugin:sendDataToWatch (status=" + status + ",basals=" + basals + ",bgValue=" + bgValue + ")");
|
||||
if (isEnabled(getType())) {
|
||||
// only start service when this plugin is enabled
|
||||
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))
|
||||
}
|
||||
// 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() {
|
||||
//Log.d(TAG, "WR: WearPlugin:resendDataToWatch");
|
||||
ctx.startService(Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_RESEND))
|
||||
}
|
||||
|
||||
fun openSettings() {
|
||||
//Log.d(TAG, "WR: WearPlugin:openSettings");
|
||||
ctx.startService(Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_OPEN_SETTINGS))
|
||||
}
|
||||
|
||||
fun requestNotificationCancel(actionString: String?) { //Log.d(TAG, "WR: WearPlugin:requestNotificationCancel");
|
||||
val intent = Intent(ctx, WatchUpdaterService::class.java)
|
||||
.setAction(WatchUpdaterService.ACTION_CANCEL_NOTIFICATION)
|
||||
intent.putExtra("actionstring", actionString)
|
||||
ctx.startService(intent)
|
||||
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) {
|
||||
val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_ACTIONCONFIRMATIONREQUEST)
|
||||
intent.putExtra("title", title)
|
||||
intent.putExtra("message", message)
|
||||
intent.putExtra("actionstring", actionString)
|
||||
ctx.startService(intent)
|
||||
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) {
|
||||
val intent = Intent(ctx, WatchUpdaterService::class.java).setAction(WatchUpdaterService.ACTION_SEND_CHANGECONFIRMATIONREQUEST)
|
||||
intent.putExtra("title", title)
|
||||
intent.putExtra("message", message)
|
||||
intent.putExtra("actionstring", actionString)
|
||||
ctx.startService(intent)
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventWearUpdateGui : Event()
|
|
@ -1,139 +0,0 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear.wearintegration;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.wearable.DataApi;
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
import com.google.android.gms.wearable.Node;
|
||||
import com.google.android.gms.wearable.NodeApi;
|
||||
import com.google.android.gms.wearable.PutDataMapRequest;
|
||||
import com.google.android.gms.wearable.PutDataRequest;
|
||||
import com.google.android.gms.wearable.Wearable;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* Created by emmablack on 12/26/14.
|
||||
*/
|
||||
class SendToDataLayerThread extends AsyncTask<DataMap,Void,Void> {
|
||||
private final GoogleApiClient googleApiClient;
|
||||
private static final String TAG = "SendToDataLayerThread";
|
||||
private final String path;
|
||||
private final String logPrefix = ""; // "WR: ";
|
||||
private static int concurrency = 0;
|
||||
private static int state = 0;
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
private static long lastlock = 0;
|
||||
private static final boolean testlockup = false; // always false in production
|
||||
|
||||
|
||||
SendToDataLayerThread(String path, GoogleApiClient pGoogleApiClient) {
|
||||
// Log.d(TAG, logPrefix + "SendToDataLayerThread: " + path);
|
||||
this.path = path;
|
||||
googleApiClient = pGoogleApiClient;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
concurrency++;
|
||||
if ((concurrency > 12) || ((concurrency > 3 && (lastlock != 0) && (tsl() - lastlock) > 300000))) {
|
||||
// error if 9 concurrent threads or lock held for >5 minutes with concurrency of 4
|
||||
final String err = "Wear Integration deadlock detected!! " + ((lastlock != 0) ? "locked" : "") + " state:"
|
||||
+ state + " @" + hourMinuteString(tsl());
|
||||
// Home.toaststaticnext(err);
|
||||
Log.e(TAG, logPrefix + err);
|
||||
}
|
||||
if (concurrency < 0)
|
||||
Log.d(TAG, logPrefix + "Wear Integration impossible concurrency!!");
|
||||
|
||||
Log.d(TAG, logPrefix + "SendDataToLayerThread pre-execute concurrency: " + concurrency);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(DataMap... params) {
|
||||
if (testlockup) {
|
||||
try {
|
||||
Log.e(TAG, logPrefix + "WARNING RUNNING TEST LOCK UP CODE - NEVER FOR PRODUCTION");
|
||||
Thread.sleep(1000000); // DEEEBBUUGGGG
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
sendToWear(params);
|
||||
concurrency--;
|
||||
Log.d(TAG, logPrefix + "SendDataToLayerThread post-execute concurrency: " + concurrency);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Debug function to expose where it might be locking up
|
||||
private synchronized void sendToWear(final DataMap... params) {
|
||||
if (!lock.tryLock()) {
|
||||
Log.d(TAG, logPrefix + "Concurrent access - waiting for thread unlock");
|
||||
lock.lock(); // enforce single threading
|
||||
Log.d(TAG, logPrefix + "Thread unlocked - proceeding");
|
||||
}
|
||||
lastlock = tsl();
|
||||
try {
|
||||
if (state != 0) {
|
||||
Log.e(TAG, logPrefix + "WEAR STATE ERROR: state=" + state);
|
||||
}
|
||||
state = 1;
|
||||
final NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await(15,
|
||||
TimeUnit.SECONDS);
|
||||
|
||||
Log.d(TAG, logPrefix + "Nodes: " + nodes);
|
||||
|
||||
state = 2;
|
||||
for (Node node : nodes.getNodes()) {
|
||||
state = 3;
|
||||
for (DataMap dataMap : params) {
|
||||
state = 4;
|
||||
PutDataMapRequest putDMR = PutDataMapRequest.create(path);
|
||||
state = 5;
|
||||
putDMR.getDataMap().putAll(dataMap);
|
||||
putDMR.setUrgent();
|
||||
state = 6;
|
||||
PutDataRequest request = putDMR.asPutDataRequest();
|
||||
state = 7;
|
||||
DataApi.DataItemResult result = Wearable.DataApi.putDataItem(googleApiClient, request).await(15,
|
||||
TimeUnit.SECONDS);
|
||||
state = 8;
|
||||
if (result.getStatus().isSuccess()) {
|
||||
Log.d(TAG, logPrefix + "DataMap: " + dataMap + " sent to: " + node.getDisplayName());
|
||||
} else {
|
||||
Log.e(TAG, logPrefix + "ERROR: failed to send DataMap");
|
||||
result = Wearable.DataApi.putDataItem(googleApiClient, request).await(30, TimeUnit.SECONDS);
|
||||
if (result.getStatus().isSuccess()) {
|
||||
Log.d(TAG, logPrefix + "DataMap retry: " + dataMap + " sent to: " + node.getDisplayName());
|
||||
} else {
|
||||
Log.e(TAG, logPrefix + "ERROR on retry: failed to send DataMap: "
|
||||
+ result.getStatus().toString());
|
||||
}
|
||||
}
|
||||
state = 9;
|
||||
}
|
||||
}
|
||||
state = 0;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, logPrefix + "Got exception in sendToWear: " + e);
|
||||
} finally {
|
||||
lastlock = 0;
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static long tsl() {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
|
||||
private static String hourMinuteString(long timestamp) {
|
||||
return android.text.format.DateFormat.format("kk:mm", timestamp).toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,633 @@
|
|||
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,73 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.general.wear.wearintegration;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.wearable.CapabilityApi;
|
||||
import com.google.android.gms.wearable.CapabilityInfo;
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
import com.google.android.gms.wearable.MessageEvent;
|
||||
import com.google.android.gms.wearable.Node;
|
||||
import com.google.android.gms.wearable.PutDataMapRequest;
|
||||
import com.google.android.gms.wearable.PutDataRequest;
|
||||
import com.google.android.gms.wearable.Wearable;
|
||||
import com.google.android.gms.wearable.WearableListenerService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.AndroidInjection;
|
||||
import info.nightscout.androidaps.Constants;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.IobTotal;
|
||||
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.GlucoseValueExtensionKt;
|
||||
import info.nightscout.androidaps.extensions.TemporaryBasalExtensionKt;
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin;
|
||||
import info.nightscout.androidaps.interfaces.Config;
|
||||
import info.nightscout.androidaps.interfaces.GlucoseUnit;
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator;
|
||||
import info.nightscout.androidaps.interfaces.Loop;
|
||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.Profile;
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
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.iob.iobCobCalculator.GlucoseStatus;
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider;
|
||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore;
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter;
|
||||
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.WearUris;
|
||||
|
||||
public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||
/*
|
||||
public class WatchUpdaterService1 extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||
@Inject public GlucoseStatusProvider glucoseStatusProvider;
|
||||
@Inject public AAPSLogger aapsLogger;
|
||||
@Inject public WearPlugin wearPlugin;
|
||||
|
@ -841,3 +775,4 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
return (lastLoopStatus != enabled);
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -29,6 +29,7 @@ import info.nightscout.androidaps.utils.T
|
|||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.workflow.CalculationWorkflow
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
|
|
|
@ -5,13 +5,13 @@ import info.nightscout.androidaps.R
|
|||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.common.ManufacturerType
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.InstanceId.instanceId
|
||||
import info.nightscout.androidaps.utils.InstanceId
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
|
@ -152,7 +152,7 @@ class MDIPlugin @Inject constructor(
|
|||
|
||||
override fun manufacturer(): ManufacturerType = ManufacturerType.AndroidAPS
|
||||
override fun model(): PumpType = PumpType.MDI
|
||||
override fun serialNumber(): String = instanceId()
|
||||
override fun serialNumber(): String = InstanceId.instanceId
|
||||
override fun shortStatus(veryShort: Boolean): String = model().model
|
||||
override fun canHandleDST(): Boolean = true
|
||||
}
|
|
@ -11,8 +11,6 @@ import info.nightscout.androidaps.events.EventPreferenceChange
|
|||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||
import info.nightscout.androidaps.extensions.plannedRemainingMinutes
|
||||
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.common.ManufacturerType
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||
|
@ -22,11 +20,13 @@ import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
|||
import info.nightscout.androidaps.plugins.pump.virtual.events.EventVirtualPumpUpdateGui
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.InstanceId.instanceId
|
||||
import info.nightscout.androidaps.utils.InstanceId
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.TimeChangeType
|
||||
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 io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
|
@ -365,7 +365,7 @@ open class VirtualPumpPlugin @Inject constructor(
|
|||
|
||||
override fun model(): PumpType = pumpDescription.pumpType
|
||||
|
||||
override fun serialNumber(): String = instanceId()
|
||||
override fun serialNumber(): String = InstanceId.instanceId
|
||||
|
||||
override fun shortStatus(veryShort: Boolean): String = "Virtual Pump"
|
||||
|
||||
|
|
|
@ -10,31 +10,38 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
style="@style/GrayButton"
|
||||
android:id="@+id/resend"
|
||||
android:layout_width="fill_parent"
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connected_device"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="3dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="@string/resend_all_data"
|
||||
android:textColor="?attr/treatmentButton" />
|
||||
android:gravity="center_vertical|center_horizontal"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
tools:text="---" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
style="@style/GrayButton"
|
||||
android:id="@+id/opensettings"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="3dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:layout_marginTop="3dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="@string/open_settings_on_wear"
|
||||
android:textColor="?attr/treatmentButton" />
|
||||
android:id="@+id/resend"
|
||||
style="@style/ButtonSmallFontStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:drawableTop="@drawable/ic_refresh"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingRight="0dp"
|
||||
android:text="@string/resend_all_data" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/open_settings"
|
||||
style="@style/ButtonSmallFontStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:drawableTop="@drawable/ic_settings"
|
||||
android:paddingLeft="0dp"
|
||||
android:paddingRight="0dp"
|
||||
android:text="@string/open_settings_on_wear" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
25
app/src/main/res/values/wear.xml
Normal file
25
app/src/main/res/values/wear.xml
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 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
|
||||
|
||||
http://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.
|
||||
-->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string-array
|
||||
name="android_wear_capabilities"
|
||||
translatable="false"
|
||||
tools:ignore="UnusedResources">
|
||||
<!-- declaring the provided capabilities -->
|
||||
<item>androidaps_mobile</item>
|
||||
</string-array>
|
||||
</resources>
|
|
@ -10,7 +10,7 @@ buildscript {
|
|||
room_version = '2.4.2'
|
||||
lifecycle_version = '2.4.1'
|
||||
dagger_version = '2.41'
|
||||
coroutines_version = '1.4.1'
|
||||
coroutines_version = '1.6.1'
|
||||
activity_version = '1.3.1'
|
||||
fragmentktx_version = '1.3.6'
|
||||
ormLite_version = '4.46'
|
||||
|
@ -51,6 +51,7 @@ buildscript {
|
|||
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
classpath 'com.hiya:jacoco-android:0.2'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1343,7 +1343,7 @@ public class ComboPlugin extends PumpPluginBase implements Pump, Constraints {
|
|||
}
|
||||
|
||||
private String fakeSerialNumber() {
|
||||
return InstanceId.INSTANCE.instanceId();
|
||||
return InstanceId.INSTANCE.getInstanceId();
|
||||
}
|
||||
|
||||
@NonNull @Override
|
||||
|
|
|
@ -5,6 +5,8 @@ dependencies {
|
|||
api "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-guava:$coroutines_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutines_version"
|
||||
api "androidx.core:core-ktx:$core_version"
|
||||
api 'androidx.legacy:legacy-support-v13:1.0.0'
|
||||
api 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
|
@ -25,7 +27,7 @@ dependencies {
|
|||
api "com.google.dagger:dagger-android-support:$dagger_version"
|
||||
|
||||
//Firebase
|
||||
api platform('com.google.firebase:firebase-bom:25.12.0')
|
||||
api platform('com.google.firebase:firebase-bom:29.3.0')
|
||||
api "com.google.firebase:firebase-analytics-ktx"
|
||||
api "com.google.firebase:firebase-crashlytics-ktx"
|
||||
api "com.google.firebase:firebase-messaging-ktx"
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
import info.nightscout.androidaps.utils.StringUtils
|
||||
|
||||
class EventNetworkChange : Event() {
|
||||
|
||||
var mobileConnected = false
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
package info.nightscout.androidaps.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventNtpStatus(val status: String, val percent: Int) : Event()
|
|
@ -1,10 +1,13 @@
|
|||
package info.nightscout.androidaps.utils
|
||||
|
||||
import com.google.firebase.iid.FirebaseInstanceId
|
||||
import com.google.firebase.installations.FirebaseInstallations
|
||||
|
||||
object InstanceId {
|
||||
fun instanceId(): String {
|
||||
var id = FirebaseInstanceId.getInstance().id
|
||||
return id
|
||||
var instanceId : String = ""
|
||||
|
||||
init {
|
||||
FirebaseInstallations.getInstance().id.addOnCompleteListener {
|
||||
instanceId = it.result
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,6 +18,9 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
// shared needed for OpenForTesting
|
||||
implementation project(':shared')
|
||||
|
||||
api "androidx.core:core-ktx:$core_version"
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ apply plugin: 'kotlin-android'
|
|||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'kotlin-allopen'
|
||||
apply plugin: 'com.hiya.jacoco-android'
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
apply from: "${project.rootDir}/gradle/android_dependencies.gradle"
|
||||
apply from: "${project.rootDir}/gradle/android_module_dependencies.gradle"
|
||||
|
@ -29,6 +30,9 @@ dependencies {
|
|||
exclude group: "com.google.android", module: "android"
|
||||
}
|
||||
|
||||
api "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2"
|
||||
api "org.apache.commons:commons-lang3:$commonslang3_version"
|
||||
|
||||
//RxBus
|
||||
api "io.reactivex.rxjava3:rxjava:$rxjava_version"
|
||||
api "io.reactivex.rxjava3:rxkotlin:$rxkotlin_version"
|
||||
|
|
|
@ -15,4 +15,4 @@ abstract class Event {
|
|||
ReflectionToStringBuilder.setDefaultStyle(ToStringStyle.SHORT_PREFIX_STYLE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
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()
|
|
@ -0,0 +1,7 @@
|
|||
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()
|
|
@ -0,0 +1,7 @@
|
|||
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()
|
|
@ -0,0 +1,33 @@
|
|||
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,61 @@
|
|||
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,21 +0,0 @@
|
|||
package info.nightscout.shared.weardata
|
||||
|
||||
object WearUris {
|
||||
|
||||
const val WEARABLE_DATA_PATH = "/nightscout_watch_data"
|
||||
const val WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend"
|
||||
const val WEARABLE_CANCELBOLUS_PATH = "/nightscout_watch_cancel_bolus"
|
||||
const val WEARABLE_CONFIRM_ACTIONSTRING_PATH = "/nightscout_watch_confirmactionstring"
|
||||
const val WEARABLE_INITIATE_ACTIONSTRING_PATH = "/nightscout_watch_initiateactionstring"
|
||||
|
||||
const val OPEN_SETTINGS_PATH = "/openwearsettings"
|
||||
const val NEW_STATUS_PATH = "/sendstatustowear"
|
||||
const val NEW_PREFERENCES_PATH = "/sendpreferencestowear"
|
||||
const val QUICK_WIZARD_PATH = "/send_quick_wizard"
|
||||
const val BASAL_DATA_PATH = "/nightscout_watch_basal"
|
||||
const val BOLUS_PROGRESS_PATH = "/nightscout_watch_bolusprogress"
|
||||
const val ACTION_CONFIRMATION_REQUEST_PATH = "/nightscout_watch_actionconfirmationrequest"
|
||||
const val ACTION_CHANGECONFIRMATION_REQUEST_PATH = "/nightscout_watch_changeconfirmationrequest"
|
||||
const val ACTION_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest"
|
||||
|
||||
}
|
19
shared/src/main/res/values/wear_paths.xml
Normal file
19
shared/src/main/res/values/wear_paths.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?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>
|
||||
</resources>
|
|
@ -23,8 +23,7 @@ apply from: "${project.rootDir}/gradle/jacoco_global.gradle"
|
|||
|
||||
ext {
|
||||
wearableVersion = "2.9.0"
|
||||
// playServicesWearable 17.1.0 breaks test
|
||||
playServicesWearable = "17.0.0"
|
||||
playServicesWearable = "17.1.0"
|
||||
}
|
||||
|
||||
def generateGitBuild = { ->
|
||||
|
@ -52,7 +51,6 @@ android {
|
|||
compileSdkVersion 31
|
||||
|
||||
defaultConfig {
|
||||
applicationId "info.nightscout.androidaps"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 29
|
||||
versionCode 2
|
||||
|
@ -112,8 +110,10 @@ dependencies {
|
|||
implementation(files('libs/wearpreferenceactivity-0.5.0.aar'))
|
||||
implementation('com.github.lecho:hellocharts-library:1.5.8@aar')
|
||||
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.6.1'
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-guava:$coroutines_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutines_version"
|
||||
implementation "androidx.core:core-ktx:$core_version"
|
||||
implementation "androidx.wear.tiles:tiles:1.0.1"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
|
|
|
@ -17,6 +17,11 @@
|
|||
android:icon="@drawable/ic_icon"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.DeviceDefault">
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.wearable.standalone"
|
||||
android:value="false" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.version"
|
||||
android:value="@integer/google_play_services_version" />
|
||||
|
@ -25,7 +30,8 @@
|
|||
android:name=".watchfaces.BIGChart"
|
||||
android:allowEmbedded="true"
|
||||
android:label="@string/label_xdrip_big_chart"
|
||||
android:permission="android.permission.BIND_WALLPAPER">
|
||||
android:permission="android.permission.BIND_WALLPAPER"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/watch_face" />
|
||||
|
@ -46,7 +52,8 @@
|
|||
android:name=".watchfaces.NOChart"
|
||||
android:allowEmbedded="true"
|
||||
android:label="@string/label_xdrip_no_chart"
|
||||
android:permission="android.permission.BIND_WALLPAPER">
|
||||
android:permission="android.permission.BIND_WALLPAPER"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/watch_face" />
|
||||
|
@ -67,7 +74,8 @@
|
|||
android:name=".watchfaces.Home"
|
||||
android:allowEmbedded="true"
|
||||
android:label="@string/label_xdrip"
|
||||
android:permission="android.permission.BIND_WALLPAPER">
|
||||
android:permission="android.permission.BIND_WALLPAPER"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/watch_face" />
|
||||
|
@ -91,7 +99,8 @@
|
|||
android:name=".watchfaces.Home2"
|
||||
android:allowEmbedded="true"
|
||||
android:label="@string/label_xdrip_v2"
|
||||
android:permission="android.permission.BIND_WALLPAPER">
|
||||
android:permission="android.permission.BIND_WALLPAPER"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/watch_face" />
|
||||
|
@ -115,7 +124,8 @@
|
|||
android:name=".watchfaces.Cockpit"
|
||||
android:allowEmbedded="true"
|
||||
android:label="@string/label_xdrip_cockpit"
|
||||
android:permission="android.permission.BIND_WALLPAPER">
|
||||
android:permission="android.permission.BIND_WALLPAPER"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/watch_face" />
|
||||
|
@ -139,7 +149,8 @@
|
|||
android:name=".watchfaces.Steampunk"
|
||||
android:allowEmbedded="true"
|
||||
android:label="@string/label_xdrip_steampunk"
|
||||
android:permission="android.permission.BIND_WALLPAPER">
|
||||
android:permission="android.permission.BIND_WALLPAPER"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/watch_face" />
|
||||
|
@ -163,7 +174,8 @@
|
|||
android:name=".watchfaces.LargeHome"
|
||||
android:allowEmbedded="true"
|
||||
android:label="@string/label_xdrip_large"
|
||||
android:permission="android.permission.BIND_WALLPAPER">
|
||||
android:permission="android.permission.BIND_WALLPAPER"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/watch_face" />
|
||||
|
@ -186,7 +198,8 @@
|
|||
android:name=".watchfaces.CircleWatchface"
|
||||
android:allowEmbedded="true"
|
||||
android:label="@string/label_xdrip_circle"
|
||||
android:permission="android.permission.BIND_WALLPAPER">
|
||||
android:permission="android.permission.BIND_WALLPAPER"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/watch_face" />
|
||||
|
@ -207,7 +220,8 @@
|
|||
android:name=".watchfaces.DigitalStyle"
|
||||
android:allowEmbedded="true"
|
||||
android:label="@string/label_digitalstyle"
|
||||
android:permission="android.permission.BIND_WALLPAPER">
|
||||
android:permission="android.permission.BIND_WALLPAPER"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
android:name="android.service.wallpaper"
|
||||
android:resource="@xml/watch_face" />
|
||||
|
@ -227,68 +241,73 @@
|
|||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<service android:name=".data.ListenerService">
|
||||
<service android:name=".data.DataLayerListenerService"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<!-- <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> -->
|
||||
<!-- listeners receive events that match the action and data filters -->
|
||||
<action android:name="com.google.android.gms.wearable.CAPABILITY_CHANGED" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:scheme="wear" />
|
||||
</intent-filter>
|
||||
|
||||
<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>
|
||||
<action android:name="com.google.android.gms.wearable.CHANNEL_EVENT" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
|
||||
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_data"
|
||||
android:pathPrefix="@string/path_ping"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_data_resend"
|
||||
android:pathPrefix="@string/path_open_wear_setting"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_cancel_bolus"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_confirmactionstring"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_initiateactionstring"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/openwearsettings"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/send_quick_wizard"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/sendstatustowear"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/sendpreferencestowear"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_basal"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_bolusprogress"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_actionconfirmationrequest"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_changeconfirmationrequest"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/nightscout_watch_cancelnotificationrequest"
|
||||
android:pathPrefix="@string/path_action_confirmation"
|
||||
android:scheme="wear" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
@ -466,7 +485,7 @@
|
|||
<service
|
||||
android:name=".complications.WallpaperLightComplication"
|
||||
android:icon="@drawable/ic_aaps_light"
|
||||
android:label="Light Walpaper"
|
||||
android:label="Light Wallpaper"
|
||||
android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
|
||||
<intent-filter>
|
||||
<action android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST" />
|
||||
|
@ -483,7 +502,7 @@
|
|||
<service
|
||||
android:name=".complications.WallpaperDarkComplication"
|
||||
android:icon="@drawable/ic_aaps_dark"
|
||||
android:label="Dark Walpaper"
|
||||
android:label="Dark Wallpaper"
|
||||
android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
|
||||
<intent-filter>
|
||||
<action android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST" />
|
||||
|
@ -500,7 +519,7 @@
|
|||
<service
|
||||
android:name=".complications.WallpaperGrayComplication"
|
||||
android:icon="@drawable/ic_aaps_gray"
|
||||
android:label="Gray Walpaper"
|
||||
android:label="Gray Wallpaper"
|
||||
android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
|
||||
<intent-filter>
|
||||
<action android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST" />
|
||||
|
@ -623,7 +642,7 @@
|
|||
|
||||
<activity android:name=".interaction.ConfigurationActivity">
|
||||
<intent-filter>
|
||||
<!-- action-name must be equal with name of xml-ressource where the configuration is describe -->
|
||||
<!-- action-name must be equal with name of xml-resource where the configuration is describe -->
|
||||
<action android:name="watch_face_configuration_bigchart" />
|
||||
<action android:name="watch_face_configuration_circle" />
|
||||
<action android:name="watch_face_configuration_cockpit" />
|
||||
|
|
39
wear/src/main/assets/logback.xml
Normal file
39
wear/src/main/assets/logback.xml
Normal file
|
@ -0,0 +1,39 @@
|
|||
<configuration>
|
||||
<!-- Create a file appender for a log in the application's data directory -->
|
||||
<property name="EXT_FILES_DIR" scope="context"
|
||||
value="${EXT_DIR:-/sdcard}/AAPS/logs/${PACKAGE_NAME}" />
|
||||
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${EXT_FILES_DIR}/AndroidAPS.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!-- daily rollover. Make sure the path matches the one in the file element or else
|
||||
the rollover logs are placed in the working directory. -->
|
||||
<fileNamePattern>${EXT_FILES_DIR}/AndroidAPS._%d{yyyy-MM-dd}_%d{HH-mm-ss, aux}_.%i.zip
|
||||
</fileNamePattern>
|
||||
|
||||
<timeBasedFileNamingAndTriggeringPolicy
|
||||
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>5MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
<!-- keep 30 days' worth of history -->
|
||||
<maxHistory>120</maxHistory>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %.-1level/%logger: %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
|
||||
<tagEncoder>
|
||||
<pattern>%logger{0}</pattern>
|
||||
</tagEncoder>
|
||||
<encoder>
|
||||
<pattern>[%thread]: %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- Write INFO (and higher-level) messages to the log file -->
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="file" />
|
||||
<appender-ref ref="logcat" />
|
||||
</root>
|
||||
</configuration>
|
|
@ -8,11 +8,17 @@ import androidx.preference.PreferenceManager
|
|||
import dagger.android.AndroidInjector
|
||||
import dagger.android.DaggerApplication
|
||||
import info.nightscout.androidaps.di.DaggerWearComponent
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import javax.inject.Inject
|
||||
|
||||
class Aaps : DaggerApplication(), OnSharedPreferenceChangeListener {
|
||||
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
aapsLogger.debug(LTag.WEAR, "onCreate")
|
||||
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import javax.inject.Inject;
|
|||
|
||||
import dagger.android.AndroidInjection;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.data.RawDisplayData;
|
||||
import info.nightscout.androidaps.interaction.utils.Constants;
|
||||
import info.nightscout.androidaps.interaction.utils.DisplayFormat;
|
||||
|
@ -205,7 +205,7 @@ public abstract class BaseComplicationProviderService extends ComplicationProvid
|
|||
localBroadcastManager = LocalBroadcastManager.getInstance(this);
|
||||
localBroadcastManager.registerReceiver(messageReceiver, messageFilter);
|
||||
|
||||
ListenerService.requestData(this);
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
checkIfUpdateNeeded();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,552 @@
|
|||
/*
|
||||
* 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,628 +0,0 @@
|
|||
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.content.SharedPreferences;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
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.common.ConnectionResult;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.wearable.ChannelApi;
|
||||
import com.google.android.gms.wearable.DataEvent;
|
||||
import com.google.android.gms.wearable.DataEventBuffer;
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
import com.google.android.gms.wearable.DataMapItem;
|
||||
import com.google.android.gms.wearable.Node;
|
||||
import com.google.android.gms.wearable.NodeApi;
|
||||
import com.google.android.gms.wearable.Wearable;
|
||||
import com.google.android.gms.wearable.WearableListenerService;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import dagger.android.AndroidInjection;
|
||||
import info.nightscout.androidaps.R;
|
||||
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.tile.ActionsTileService;
|
||||
import info.nightscout.androidaps.tile.QuickWizardTileService;
|
||||
import info.nightscout.androidaps.tile.TempTargetTileService;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.WearUris;
|
||||
|
||||
/**
|
||||
* Created by emmablack on 12/26/14.
|
||||
*/
|
||||
public class ListenerService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks,
|
||||
GoogleApiClient.OnConnectionFailedListener, ChannelApi.ChannelListener {
|
||||
|
||||
@Inject WearUtil wearUtil;
|
||||
@Inject Persistence persistence;
|
||||
|
||||
public static final int BOLUS_PROGRESS_NOTIF_ID = 1;
|
||||
public static final int CONFIRM_NOTIF_ID = 2;
|
||||
public static final int CHANGE_NOTIF_ID = 556677;
|
||||
|
||||
private static final String ACTION_RESEND = "com.dexdrip.stephenblack.nightwatch.RESEND_DATA";
|
||||
private static final String ACTION_CANCELBOLUS = "com.dexdrip.stephenblack.nightwatch.CANCELBOLUS";
|
||||
private static final String ACTION_CONFIRMATION = "com.dexdrip.stephenblack.nightwatch.CONFIRMACTION";
|
||||
private static final String ACTION_CONFIRMCHANGE = "com.dexdrip.stephenblack.nightwatch.CONFIRMCHANGE";
|
||||
private static final String ACTION_INITIATE_ACTION = "com.dexdrip.stephenblack.nightwatch.INITIATE_ACTION";
|
||||
|
||||
private static final String AAPS_NOTIFY_CHANNEL_ID_OPENLOOP = "AndroidAPS-OpenLoop";
|
||||
private static final String AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS = "bolus progress vibration";
|
||||
private static final String AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS_SILENT = "bolus progress silent";
|
||||
|
||||
GoogleApiClient googleApiClient;
|
||||
|
||||
private DismissThread bolusprogressThread;
|
||||
private static final String TAG = "ListenerService";
|
||||
|
||||
private final String logPrefix = ""; // "WR: "
|
||||
|
||||
// Not derived from DaggerService, do injection here
|
||||
@Override
|
||||
public void onCreate() {
|
||||
AndroidInjection.inject(this);
|
||||
super.onCreate();
|
||||
}
|
||||
|
||||
public class BolusCancelTask extends AsyncTask<Void, Void, Void> {
|
||||
Context mContext;
|
||||
|
||||
BolusCancelTask(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
Log.d(TAG, logPrefix + "BolusCancelTask.doInBackground: " + params);
|
||||
if (!googleApiClient.isConnected()) {
|
||||
Log.i(TAG, "BolusCancelTask.doInBackground: not connected");
|
||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||
}
|
||||
if (googleApiClient.isConnected()) {
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
for (Node node : nodes.getNodes()) {
|
||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(),
|
||||
WearUris.WEARABLE_CANCELBOLUS_PATH, null);
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class MessageActionTask extends AsyncTask<Void, Void, Void> {
|
||||
Context mContext;
|
||||
String mActionstring;
|
||||
String mMessagePath;
|
||||
|
||||
MessageActionTask(Context context, String messagePath, String actionstring) {
|
||||
mContext = context;
|
||||
mActionstring = actionstring;
|
||||
mMessagePath = messagePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
Log.i(TAG, "MessageActionTask.doInBackground: ");
|
||||
|
||||
if (!googleApiClient.isConnected()) {
|
||||
Log.i(TAG, "MessageActionTask.doInBackground: not connected");
|
||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||
}
|
||||
if (googleApiClient.isConnected()) {
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
for (Node node : nodes.getNodes()) {
|
||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), mMessagePath, mActionstring.getBytes());
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class ResendDataTask extends AsyncTask<Void, Void, Void> {
|
||||
Context mContext;
|
||||
|
||||
ResendDataTask(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
Log.d(TAG, logPrefix + "ResendDataTask.doInBackground: " + params);
|
||||
|
||||
if (!googleApiClient.isConnected()) {
|
||||
Log.i(TAG, "ResendDataTask.doInBackground: not connected");
|
||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||
}
|
||||
if (googleApiClient.isConnected()) {
|
||||
Log.i(TAG, "ResendDataTask.doInBackground: connected");
|
||||
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||
for (Node node : nodes.getNodes()) {
|
||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WearUris.WEARABLE_RESEND_PATH, null);
|
||||
}
|
||||
} else {
|
||||
Log.i(TAG, "ResendDataTask.doInBackground: could not connect");
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void requestData() {
|
||||
new ResendDataTask(this).execute();
|
||||
}
|
||||
|
||||
public void cancelBolus() {
|
||||
new BolusCancelTask(this).execute();
|
||||
}
|
||||
|
||||
private void sendConfirmActionstring(String actionstring) {
|
||||
new MessageActionTask(this, WearUris.WEARABLE_CONFIRM_ACTIONSTRING_PATH, actionstring).execute();
|
||||
}
|
||||
|
||||
private void sendInitiateActionstring(String actionstring) {
|
||||
new MessageActionTask(this, WearUris.WEARABLE_INITIATE_ACTIONSTRING_PATH, actionstring).execute();
|
||||
}
|
||||
|
||||
private void googleApiConnect() {
|
||||
if (googleApiClient != null) {
|
||||
// Remove old listener(s)
|
||||
try {
|
||||
Wearable.ChannelApi.removeListener(googleApiClient, this);
|
||||
} catch (Exception e) {
|
||||
//
|
||||
}
|
||||
try {
|
||||
Wearable.MessageApi.removeListener(googleApiClient, this);
|
||||
} catch (Exception e) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
googleApiClient = new GoogleApiClient.Builder(this)
|
||||
.addConnectionCallbacks(this)
|
||||
.addOnConnectionFailedListener(this)
|
||||
.addApi(Wearable.API)
|
||||
.build();
|
||||
Wearable.MessageApi.addListener(googleApiClient, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
// Log.d(TAG, logPrefix + "onStartCommand: Intent: " + intent);
|
||||
|
||||
if (intent != null && ACTION_RESEND.equals(intent.getAction())) {
|
||||
googleApiConnect();
|
||||
requestData();
|
||||
} else if (intent != null && ACTION_CANCELBOLUS.equals(intent.getAction())) {
|
||||
googleApiConnect();
|
||||
|
||||
//dismiss notification
|
||||
NotificationManagerCompat notificationManager =
|
||||
NotificationManagerCompat.from(ListenerService.this);
|
||||
notificationManager.cancel(BOLUS_PROGRESS_NOTIF_ID);
|
||||
|
||||
//send cancel-request to phone.
|
||||
cancelBolus();
|
||||
|
||||
|
||||
} else if (intent != null && ACTION_CONFIRMATION.equals(intent.getAction())) {
|
||||
googleApiConnect();
|
||||
|
||||
//dismiss notification
|
||||
NotificationManagerCompat notificationManager =
|
||||
NotificationManagerCompat.from(ListenerService.this);
|
||||
notificationManager.cancel(CONFIRM_NOTIF_ID);
|
||||
|
||||
String actionstring = intent.getStringExtra("actionstring");
|
||||
sendConfirmActionstring(actionstring);
|
||||
|
||||
} else if (intent != null && ACTION_CONFIRMCHANGE.equals(intent.getAction())) {
|
||||
googleApiConnect();
|
||||
|
||||
//dismiss notification
|
||||
NotificationManagerCompat notificationManager =
|
||||
NotificationManagerCompat.from(ListenerService.this);
|
||||
notificationManager.cancel(CHANGE_NOTIF_ID);
|
||||
|
||||
String actionstring = intent.getStringExtra("actionstring");
|
||||
sendConfirmActionstring(actionstring);
|
||||
|
||||
} else if (intent != null && ACTION_INITIATE_ACTION.equals(intent.getAction())) {
|
||||
googleApiConnect();
|
||||
|
||||
String actionstring = intent.getStringExtra("actionstring");
|
||||
sendInitiateActionstring(actionstring);
|
||||
|
||||
}
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataChanged(DataEventBuffer dataEvents) {
|
||||
|
||||
DataMap dataMap;
|
||||
// Log.d(TAG, logPrefix + "onDataChanged: DataEvents=" + dataEvents);
|
||||
|
||||
for (DataEvent event : dataEvents) {
|
||||
|
||||
if (event.getType() == DataEvent.TYPE_CHANGED) {
|
||||
|
||||
String path = event.getDataItem().getUri().getPath();
|
||||
|
||||
//Log.d(TAG, "WR: onDataChanged: Path: " + path + ", EventDataItem=" + event.getDataItem());
|
||||
|
||||
if (path.equals(WearUris.OPEN_SETTINGS_PATH)) {
|
||||
Intent intent = new Intent(this, AAPSPreferences.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
} else if (path.equals(WearUris.BOLUS_PROGRESS_PATH)) {
|
||||
int progress = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getInt("progresspercent", 0);
|
||||
String status = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("progressstatus", "");
|
||||
showBolusProgress(progress, status);
|
||||
} else if (path.equals(WearUris.ACTION_CONFIRMATION_REQUEST_PATH)) {
|
||||
String title = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("title");
|
||||
String message = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("message");
|
||||
String actionstring = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("actionstring");
|
||||
|
||||
if ("opencpp".equals(title) && actionstring.startsWith("opencpp")) {
|
||||
String[] act = actionstring.split("\\s+");
|
||||
Intent intent = new Intent(this, CPPActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
//TODO adrian: parse actionstring and add parameters
|
||||
Bundle params = new Bundle();
|
||||
params.putInt("percentage", SafeParse.stringToInt(act[1]));
|
||||
params.putInt("timeshift", SafeParse.stringToInt(act[2]));
|
||||
intent.putExtras(params);
|
||||
startActivity(intent);
|
||||
} else {
|
||||
showConfirmationDialog(title, message, actionstring);
|
||||
}
|
||||
|
||||
} else if (path.equals(WearUris.NEW_STATUS_PATH)) {
|
||||
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
|
||||
Intent messageIntent = new Intent();
|
||||
messageIntent.setAction(Intent.ACTION_SEND);
|
||||
messageIntent.putExtra("status", dataMap.toBundle());
|
||||
persistence.storeDataMap(RawDisplayData.STATUS_PERSISTENCE_KEY, dataMap);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
|
||||
} else if (path.equals(WearUris.BASAL_DATA_PATH)) {
|
||||
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
|
||||
Intent messageIntent = new Intent();
|
||||
messageIntent.setAction(Intent.ACTION_SEND);
|
||||
messageIntent.putExtra("basals", dataMap.toBundle());
|
||||
persistence.storeDataMap(RawDisplayData.BASALS_PERSISTENCE_KEY, dataMap);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
|
||||
} else if (path.equals(WearUris.NEW_PREFERENCES_PATH)) {
|
||||
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
String keyControl = getString(R.string.key_wear_control);
|
||||
if (dataMap.containsKey(keyControl)) {
|
||||
boolean previousWearControl = sharedPreferences.getBoolean(keyControl, false);
|
||||
boolean wearControl = dataMap.getBoolean(keyControl, false);
|
||||
editor.putBoolean(keyControl, wearControl);
|
||||
editor.apply();
|
||||
if (wearControl != previousWearControl) {
|
||||
updateTiles();
|
||||
}
|
||||
}
|
||||
String keyPercentage = getString(R.string.key_boluswizard_percentage);
|
||||
if (dataMap.containsKey(keyPercentage)) {
|
||||
int wpercentage = dataMap.getInt(keyPercentage, 100);
|
||||
editor.putInt(keyPercentage, wpercentage);
|
||||
editor.apply();
|
||||
}
|
||||
String keyUnits = getString(R.string.key_units_mgdl);
|
||||
if (dataMap.containsKey(keyUnits)) {
|
||||
boolean mgdl = dataMap.getBoolean(keyUnits, true);
|
||||
editor.putBoolean(keyUnits, mgdl);
|
||||
editor.apply();
|
||||
}
|
||||
String keyMaxCarbs = getString(R.string.key_treatmentssafety_maxcarbs);
|
||||
if (dataMap.containsKey(keyMaxCarbs)) {
|
||||
int maxCarbs = dataMap.getInt(keyMaxCarbs, 48);
|
||||
editor.putInt(keyMaxCarbs, maxCarbs);
|
||||
editor.apply();
|
||||
}
|
||||
String keyMaxBolus = getString(R.string.key_treatmentssafety_maxbolus);
|
||||
if (dataMap.containsKey(keyMaxBolus)) {
|
||||
float maxBolus = (float) dataMap.getDouble(keyMaxBolus, 3.0f);
|
||||
editor.putFloat(keyMaxBolus, maxBolus);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
} else if (path.equals(WearUris.QUICK_WIZARD_PATH)) {
|
||||
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
|
||||
Log.i(TAG, "onDataChanged: QUICK_WIZARD_PATH" + dataMap);
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
dataMap.remove("timestamp");
|
||||
String key = getString(R.string.key_quick_wizard_data_map);
|
||||
String dataString = Base64.encodeToString(dataMap.toByteArray(), Base64.DEFAULT);
|
||||
if (!dataString.equals(sharedPreferences.getString(key, ""))) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.putString(key, dataString);
|
||||
editor.apply();
|
||||
// Todo maybe add debounce function, due to 20 seconds update limit?
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(QuickWizardTileService.class);
|
||||
}
|
||||
Log.i(TAG, "onDataChanged: updated QUICK_WIZARD");
|
||||
} else {
|
||||
Log.i(TAG, "onDataChanged: ignore update");
|
||||
}
|
||||
} else if (path.equals(WearUris.ACTION_CHANGECONFIRMATION_REQUEST_PATH)) {
|
||||
String title = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("title");
|
||||
String message = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("message");
|
||||
String actionstring = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("actionstring");
|
||||
notifyChangeRequest(title, message, actionstring);
|
||||
} else if (path.equals(WearUris.ACTION_CANCELNOTIFICATION_REQUEST_PATH)) {
|
||||
String actionstring = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("actionstring");
|
||||
cancelNotificationRequest(actionstring);
|
||||
} else {
|
||||
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
|
||||
Intent messageIntent = new Intent();
|
||||
messageIntent.setAction(Intent.ACTION_SEND);
|
||||
messageIntent.putExtra("data", dataMap.toBundle());
|
||||
persistence.storeDataMap(RawDisplayData.DATA_PERSISTENCE_KEY, dataMap);
|
||||
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTiles() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(ActionsTileService.class);
|
||||
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(TempTargetTileService.class);
|
||||
|
||||
TileService.getUpdater(this)
|
||||
.requestUpdate(QuickWizardTileService.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyChangeRequest(String title, String message, String actionstring) {
|
||||
// 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) {
|
||||
CharSequence name = "AAPS Open Loop";
|
||||
String description = "Open Loop request notiffication";//getString(R.string.channel_description);
|
||||
NotificationChannel channel = new NotificationChannel(AAPS_NOTIFY_CHANNEL_ID_OPENLOOP, name, NotificationManager.IMPORTANCE_HIGH);
|
||||
channel.setDescription(description);
|
||||
channel.enableVibration(true);
|
||||
|
||||
// Register the channel with the system; you can't change the importance
|
||||
// or other notification behaviors after this
|
||||
NotificationManager notificationManager = getSystemService(NotificationManager.class);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
NotificationCompat.Builder builder =
|
||||
new NotificationCompat.Builder(this, AAPS_NOTIFY_CHANNEL_ID_OPENLOOP);
|
||||
|
||||
builder = builder.setSmallIcon(R.drawable.notif_icon)
|
||||
.setContentTitle(title)
|
||||
.setContentText(message)
|
||||
.setPriority(Notification.PRIORITY_HIGH)
|
||||
.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000});
|
||||
|
||||
// Creates an explicit intent for an Activity in your app
|
||||
Intent intent = new Intent(this, AcceptActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
Bundle params = new Bundle();
|
||||
params.putString("title", title);
|
||||
params.putString("message", message);
|
||||
params.putString("actionstring", actionstring);
|
||||
intent.putExtras(params);
|
||||
|
||||
PendingIntent resultPendingIntent =
|
||||
PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
builder = builder.setContentIntent(resultPendingIntent);
|
||||
|
||||
NotificationManager mNotificationManager =
|
||||
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
// mId allows you to update the notification later on.
|
||||
mNotificationManager.notify(CHANGE_NOTIF_ID, builder.build());
|
||||
}
|
||||
|
||||
private void cancelNotificationRequest(String actionstring) {
|
||||
NotificationManager mNotificationManager =
|
||||
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||
mNotificationManager.cancel(CHANGE_NOTIF_ID);
|
||||
}
|
||||
|
||||
private void showBolusProgress(int progresspercent, String progresstatus) {
|
||||
|
||||
long[] vibratePattern;
|
||||
boolean vibrate = PreferenceManager
|
||||
.getDefaultSharedPreferences(this).getBoolean("vibrateOnBolus", true);
|
||||
if (vibrate) {
|
||||
vibratePattern = new long[]{0, 50, 1000};
|
||||
} else {
|
||||
vibratePattern = new long[]{0, 1, 1000};
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
createBolusProgressChannels();
|
||||
}
|
||||
|
||||
Intent cancelIntent = new Intent(this, ListenerService.class);
|
||||
cancelIntent.setAction(ACTION_CANCELBOLUS);
|
||||
PendingIntent cancelPendingIntent = PendingIntent.getService(this, 0, cancelIntent, 0);
|
||||
|
||||
NotificationCompat.Builder notificationBuilder =
|
||||
new NotificationCompat.Builder(this, vibrate ? AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS : 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);
|
||||
|
||||
NotificationManagerCompat 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 void createBolusProgressChannels() {
|
||||
createNotificationChannel(new long[]{0, 50, 1000}, AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS, getString(R.string.bolus_progress_channel_name), getString(R.string.bolus_progress_channel_description));
|
||||
createNotificationChannel(new long[]{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 void createNotificationChannel(long[] vibratePattern, String channelID, CharSequence name, String description) {
|
||||
NotificationChannel channel = new NotificationChannel(channelID, name, NotificationManager.IMPORTANCE_HIGH);
|
||||
channel.setDescription(description);
|
||||
channel.enableVibration(true);
|
||||
channel.setVibrationPattern(vibratePattern);
|
||||
|
||||
// Register the channel with the system; you can't change the importance
|
||||
// or other notification behaviors after this
|
||||
NotificationManager notificationManager = getSystemService(NotificationManager.class);
|
||||
notificationManager.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
private void showConfirmationDialog(String title, String message, String actionstring) {
|
||||
Intent intent = new Intent(this, AcceptActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
Bundle params = new Bundle();
|
||||
params.putString("title", title);
|
||||
params.putString("message", message);
|
||||
params.putString("actionstring", actionstring);
|
||||
intent.putExtras(params);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private void scheduleDismissBolusprogress(final int seconds) {
|
||||
bolusprogressThread = new DismissThread(BOLUS_PROGRESS_NOTIF_ID, seconds);
|
||||
bolusprogressThread.start();
|
||||
}
|
||||
|
||||
private class DismissThread extends Thread {
|
||||
private final int notificationID;
|
||||
private final int seconds;
|
||||
private boolean valid = true;
|
||||
|
||||
DismissThread(int notificationID, int seconds) {
|
||||
this.notificationID = notificationID;
|
||||
this.seconds = seconds;
|
||||
}
|
||||
|
||||
public synchronized void invalidate() {
|
||||
valid = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
SystemClock.sleep(seconds * 1000);
|
||||
synchronized (this) {
|
||||
if (valid) {
|
||||
NotificationManagerCompat notificationManager =
|
||||
NotificationManagerCompat.from(ListenerService.this);
|
||||
notificationManager.cancel(notificationID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void requestData(Context context) {
|
||||
Intent intent = new Intent(context, ListenerService.class);
|
||||
intent.setAction(ACTION_RESEND);
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
public static void initiateAction(Context context, @NotNull String actionstring) {
|
||||
Intent intent = new Intent(context, ListenerService.class);
|
||||
intent.putExtra("actionstring", actionstring);
|
||||
intent.setAction(ACTION_INITIATE_ACTION);
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
public static void confirmAction(Context context, String actionstring) {
|
||||
Intent intent = new Intent(context, ListenerService.class);
|
||||
intent.putExtra("actionstring", actionstring);
|
||||
|
||||
if (actionstring.equals("changeRequest")) {
|
||||
intent.setAction(ACTION_CONFIRMCHANGE);
|
||||
} else {
|
||||
intent.setAction(ACTION_CONFIRMATION);
|
||||
}
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected(Bundle bundle) {
|
||||
// Log.d(TAG, logPrefix + "onConnected call requestData");
|
||||
|
||||
Wearable.ChannelApi.addListener(googleApiClient, this);
|
||||
// requestData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionSuspended(int i) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFailed(ConnectionResult connectionResult) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (googleApiClient != null && googleApiClient.isConnected()) {
|
||||
googleApiClient.disconnect();
|
||||
}
|
||||
|
||||
if (googleApiClient != null) {
|
||||
Wearable.MessageApi.removeListener(googleApiClient, this);
|
||||
Wearable.ChannelApi.removeListener(googleApiClient, this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -174,7 +174,7 @@ public class RawDisplayData {
|
|||
wearUtil.releaseWakeLock(wl);
|
||||
}
|
||||
|
||||
public DataMap updateBasalsFromMessage(Intent intent, PowerManager.WakeLock wakeLock) {
|
||||
public DataMap updateBasalsFromMessage(Intent intent) {
|
||||
Bundle bundle = intent.getBundleExtra("basals");
|
||||
if (bundle != null) {
|
||||
DataMap dataMap = wearUtil.bundleToDataMap(bundle);
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package info.nightscout.androidaps.di
|
||||
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import info.nightscout.androidaps.interaction.actions.*
|
||||
|
||||
@Module
|
||||
@Suppress("unused")
|
||||
abstract class WearActivitiesModule {
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesBackgroundActionActivity(): BackgroundActionActivity
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesViewSelectorActivity(): ViewSelectorActivity
|
||||
@ContributesAndroidInjector abstract fun contributesAcceptActivity(): AcceptActivity
|
||||
@ContributesAndroidInjector abstract fun contributesBolusActivity(): BolusActivity
|
||||
@ContributesAndroidInjector abstract fun contributesCarbActivity(): CarbActivity
|
||||
@ContributesAndroidInjector abstract fun contributesCPPActivity(): CPPActivity
|
||||
@ContributesAndroidInjector abstract fun contributesECarbActivity(): ECarbActivity
|
||||
@ContributesAndroidInjector abstract fun contributesFillActivity(): FillActivity
|
||||
@ContributesAndroidInjector abstract fun contributesTempTargetActivity(): TempTargetActivity
|
||||
@ContributesAndroidInjector abstract fun contributesTreatmentActivity(): TreatmentActivity
|
||||
@ContributesAndroidInjector abstract fun contributesWizardActivity(): WizardActivity
|
||||
}
|
|
@ -7,6 +7,8 @@ import dagger.Module
|
|||
import dagger.Provides
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Aaps
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.rx.DefaultAapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.AAPSLoggerProduction
|
||||
import info.nightscout.shared.logging.L
|
||||
|
@ -16,7 +18,8 @@ import javax.inject.Singleton
|
|||
|
||||
@Suppress("unused")
|
||||
@Module(includes = [
|
||||
WearModule.AppBindings::class
|
||||
WearModule.AppBindings::class,
|
||||
WearActivitiesModule::class
|
||||
])
|
||||
open class WearModule {
|
||||
|
||||
|
@ -28,6 +31,10 @@ open class WearModule {
|
|||
@Singleton
|
||||
fun provideAAPSLogger(l: L): AAPSLogger = AAPSLoggerProduction(l)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
internal fun provideSchedulers(): AapsSchedulers = DefaultAapsSchedulers()
|
||||
|
||||
@Module
|
||||
interface AppBindings {
|
||||
|
||||
|
|
|
@ -3,14 +3,15 @@ package info.nightscout.androidaps.di
|
|||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import info.nightscout.androidaps.complications.*
|
||||
import info.nightscout.androidaps.data.ListenerService
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService
|
||||
import info.nightscout.androidaps.interaction.actions.BackgroundActionActivity
|
||||
import info.nightscout.androidaps.watchfaces.*
|
||||
|
||||
@Module
|
||||
@Suppress("unused")
|
||||
abstract class WearServicesModule {
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesListenerService(): ListenerService
|
||||
@ContributesAndroidInjector abstract fun contributesDataLayerListenerService(): DataLayerListenerService
|
||||
|
||||
@ContributesAndroidInjector abstract fun contributesBaseComplicationProviderService(): BaseComplicationProviderService
|
||||
@ContributesAndroidInjector abstract fun contributesBrCobIobComplication(): BrCobIobComplication
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import static info.nightscout.shared.weardata.WearConstants.KEY_ACTION_DATA;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
@ -19,7 +21,10 @@ import androidx.core.view.MotionEventCompat;
|
|||
import androidx.core.view.ViewConfigurationCompat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.events.EventWearToMobileChange;
|
||||
import info.nightscout.androidaps.events.EventWearToMobileConfirm;
|
||||
import info.nightscout.shared.weardata.ActionData;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
|
@ -29,6 +34,7 @@ public class AcceptActivity extends ViewSelectorActivity {
|
|||
|
||||
String message = "";
|
||||
String actionstring = "";
|
||||
String actionKey = "";
|
||||
private DismissThread dismissThread;
|
||||
|
||||
@Override
|
||||
|
@ -41,8 +47,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 ("".equals(message) || "".equals(actionstring)) {
|
||||
if (message.isEmpty() || (actionstring.isEmpty() && actionKey.isEmpty())) {
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
@ -60,6 +67,7 @@ public class AcceptActivity extends ViewSelectorActivity {
|
|||
finish();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private class MyGridViewPagerAdapter extends GridPagerAdapter {
|
||||
@Override
|
||||
public int getColumnCount(int arg0) {
|
||||
|
@ -74,48 +82,53 @@ public class AcceptActivity extends ViewSelectorActivity {
|
|||
@Override
|
||||
public Object instantiateItem(ViewGroup container, int row, int col) {
|
||||
|
||||
final View view;
|
||||
if (col == 0) {
|
||||
final View view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_confirm_text, container, false);
|
||||
view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_confirm_text, container, false);
|
||||
final TextView textView = view.findViewById(R.id.message);
|
||||
final View scrollView = view.findViewById(R.id.message_scroll);
|
||||
textView.setText(message);
|
||||
container.addView(view);
|
||||
scrollView.setOnGenericMotionListener(new View.OnGenericMotionListener() {
|
||||
@Override
|
||||
public boolean onGenericMotion(View v, MotionEvent ev) {
|
||||
if (ev.getAction() == MotionEvent.ACTION_SCROLL &&
|
||||
ev.isFromSource(InputDeviceCompat.SOURCE_ROTARY_ENCODER)
|
||||
) {
|
||||
float delta = -ev.getAxisValue(MotionEventCompat.AXIS_SCROLL) *
|
||||
ViewConfigurationCompat.getScaledVerticalScrollFactor(
|
||||
ViewConfiguration.get(container.getContext()),
|
||||
container.getContext());
|
||||
v.scrollBy(0, Math.round(delta));
|
||||
scrollView.setOnGenericMotionListener((v, ev) -> {
|
||||
if (ev.getAction() == MotionEvent.ACTION_SCROLL &&
|
||||
ev.isFromSource(InputDeviceCompat.SOURCE_ROTARY_ENCODER)
|
||||
) {
|
||||
float delta = -ev.getAxisValue(MotionEventCompat.AXIS_SCROLL) *
|
||||
ViewConfigurationCompat.getScaledVerticalScrollFactor(
|
||||
ViewConfiguration.get(container.getContext()),
|
||||
container.getContext());
|
||||
v.scrollBy(0, Math.round(delta));
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
scrollView.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) -> {
|
||||
ListenerService.confirmAction(AcceptActivity.this, actionstring);
|
||||
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));
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,28 +1,26 @@
|
|||
package info.nightscout.androidaps.interaction.actions
|
||||
|
||||
import android.app.Activity
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import info.nightscout.androidaps.data.ListenerService
|
||||
import dagger.android.DaggerActivity
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import javax.inject.Inject
|
||||
|
||||
const val TAG = "QuickWizard"
|
||||
class BackgroundActionActivity : DaggerActivity() {
|
||||
|
||||
class BackgroundActionActivity : Activity() {
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val actionString = intent.extras?.getString("actionString")
|
||||
Log.i(TAG, "QuickWizardActivity.onCreate: actionString=$actionString")
|
||||
if (actionString != null) {
|
||||
ListenerService.initiateAction(this, actionString)
|
||||
val message = intent.extras?.getString("message")
|
||||
if (message != null) {
|
||||
intent.extras?.getString("actionString")?.let { actionString ->
|
||||
aapsLogger.info(LTag.WEAR, "QuickWizardActivity.onCreate: actionString=$actionString")
|
||||
DataLayerListenerService.initiateAction(this, actionString)
|
||||
intent.extras?.getString("message")?.let { message ->
|
||||
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "BackgroundActionActivity.onCreate extras 'actionString' required")
|
||||
}
|
||||
} ?: aapsLogger.error(LTag.WEAR, "BackgroundActionActivity.onCreate extras 'actionString' required")
|
||||
finishAffinity()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.wearable.view.GridPagerAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -12,21 +10,21 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.events.EventWearToMobileAction;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.ActionData;
|
||||
|
||||
public class BolusActivity extends ViewSelectorActivity {
|
||||
|
||||
PlusMinusEditText editInsulin;
|
||||
float maxBolus;
|
||||
double maxBolus;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setAdapter(new MyGridViewPagerAdapter());
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
maxBolus = sp.getFloat(getString(R.string.key_treatmentssafety_maxbolus), 3f);
|
||||
maxBolus = sp.getDouble(getString(R.string.key_treatmentssafety_maxbolus), 3.0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,6 +33,7 @@ public class BolusActivity extends ViewSelectorActivity {
|
|||
finish();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private class MyGridViewPagerAdapter extends GridPagerAdapter {
|
||||
@Override
|
||||
public int getColumnCount(int arg0) {
|
||||
|
@ -49,30 +48,29 @@ public class BolusActivity 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 (editInsulin != null) {
|
||||
def = SafeParse.stringToDouble(editInsulin.editText.getText().toString());
|
||||
}
|
||||
editInsulin = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, (double)maxBolus, 0.1d, new DecimalFormat("#0.0"),false);
|
||||
editInsulin = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, maxBolus, 0.1d, new DecimalFormat("#0.0"), false);
|
||||
setLabelToPlusMinusView(view, getString(R.string.action_insulin));
|
||||
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) -> {
|
||||
String actionstring = "bolus " + SafeParse.stringToDouble(editInsulin.editText.getText().toString())
|
||||
+ " 0"; // Zero carbs
|
||||
ListenerService.initiateAction(BolusActivity.this, actionstring);
|
||||
confirmAction(BolusActivity.this, R.string.action_bolus_confirmation);
|
||||
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));
|
||||
showToast(BolusActivity.this, R.string.action_bolus_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
return view;
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,9 +10,11 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.events.EventWearToMobileAction;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.ActionData;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
|
@ -88,15 +90,14 @@ public class CPPActivity 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 = "cppset " + SafeParse.stringToInt(editTimeshift.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToInt(editPercentage.editText.getText().toString());
|
||||
ListenerService.initiateAction(CPPActivity.this, actionstring);
|
||||
confirmAction(CPPActivity.this, R.string.action_cpp_confirmation);
|
||||
ActionData.ProfileSwitch ps =
|
||||
new ActionData.ProfileSwitch(SafeParse.stringToInt(editTimeshift.editText.getText().toString()), SafeParse.stringToInt(editPercentage.editText.getText().toString()));
|
||||
rxBus.send(new EventWearToMobileAction(ps));
|
||||
showToast(CPPActivity.this, R.string.action_cpp_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.wearable.view.GridPagerAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -12,7 +10,7 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
|
||||
|
@ -25,7 +23,6 @@ public class CarbActivity extends ViewSelectorActivity {
|
|||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setAdapter(new MyGridViewPagerAdapter());
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
maxCarbs = sp.getInt(getString(R.string.key_treatmentssafety_maxcarbs), 48);
|
||||
}
|
||||
|
||||
|
@ -66,8 +63,8 @@ public class CarbActivity extends ViewSelectorActivity {
|
|||
confirmbutton.setOnClickListener((View v) -> {
|
||||
// With start time 0 and duration 0
|
||||
String actionstring = "ecarbs " + SafeParse.stringToInt(editCarbs.editText.getText().toString()) + " 0 0";
|
||||
ListenerService.initiateAction(CarbActivity.this, actionstring);
|
||||
confirmAction(CarbActivity.this, R.string.action_ecarb_confirmation);
|
||||
DataLayerListenerService.Companion.initiateAction(CarbActivity.this, actionstring);
|
||||
showToast(CarbActivity.this, R.string.action_ecarb_confirmation);
|
||||
finishAffinity();
|
||||
|
||||
});
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.wearable.view.GridPagerAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -12,7 +10,7 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
|
||||
|
@ -31,7 +29,6 @@ public class ECarbActivity extends ViewSelectorActivity {
|
|||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setAdapter(new MyGridViewPagerAdapter());
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
maxCarbs = sp.getInt(getString(R.string.key_treatmentssafety_maxcarbs), 48);
|
||||
}
|
||||
|
||||
|
@ -92,14 +89,14 @@ public class ECarbActivity extends ViewSelectorActivity {
|
|||
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?
|
||||
//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());
|
||||
ListenerService.initiateAction(ECarbActivity.this, actionstring);
|
||||
confirmAction(ECarbActivity.this, R.string.action_ecarb_confirmation);
|
||||
DataLayerListenerService.Companion.initiateAction(ECarbActivity.this, actionstring);
|
||||
showToast(ECarbActivity.this, R.string.action_ecarb_confirmation);
|
||||
finishAffinity();
|
||||
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
|
||||
|
@ -64,13 +64,13 @@ public class FillActivity extends ViewSelectorActivity {
|
|||
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?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
//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());
|
||||
ListenerService.initiateAction(FillActivity.this, actionstring);
|
||||
confirmAction(FillActivity.this, R.string.action_fill_confirmation);
|
||||
finishAffinity();
|
||||
String actionstring = "fill " + SafeParse.stringToDouble(editInsulin.editText.getText().toString());
|
||||
DataLayerListenerService.Companion.initiateAction(FillActivity.this, actionstring);
|
||||
showToast(FillActivity.this, R.string.action_fill_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
return view;
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.wearable.view.GridPagerAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -12,7 +10,7 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
|
||||
|
@ -34,7 +32,6 @@ public class TempTargetActivity extends ViewSelectorActivity {
|
|||
|
||||
setAdapter(new MyGridViewPagerAdapter());
|
||||
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
isMGDL = sp.getBoolean("units_mgdl", true);
|
||||
isSingleTarget = sp.getBoolean("singletarget", true);
|
||||
}
|
||||
|
@ -126,8 +123,8 @@ public class TempTargetActivity extends ViewSelectorActivity {
|
|||
+ " " + SafeParse.stringToDouble(lowRange.editText.getText().toString())
|
||||
+ " " + (isSingleTarget ? SafeParse.stringToDouble(lowRange.editText.getText().toString()) : SafeParse.stringToDouble(highRange.editText.getText().toString()));
|
||||
|
||||
ListenerService.initiateAction(TempTargetActivity.this, actionstring);
|
||||
confirmAction(TempTargetActivity.this, R.string.action_tempt_confirmation);
|
||||
DataLayerListenerService.Companion.initiateAction(TempTargetActivity.this, actionstring);
|
||||
showToast(TempTargetActivity.this, R.string.action_tempt_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.wearable.view.GridPagerAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -12,9 +10,11 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.events.EventWearToMobileAction;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.shared.weardata.ActionData;
|
||||
|
||||
/**
|
||||
* Created by adrian on 09/02/17.
|
||||
|
@ -25,15 +25,14 @@ public class TreatmentActivity extends ViewSelectorActivity {
|
|||
PlusMinusEditText editCarbs;
|
||||
PlusMinusEditText editInsulin;
|
||||
int maxCarbs;
|
||||
float maxBolus;
|
||||
double maxBolus;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setAdapter(new MyGridViewPagerAdapter());
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
maxCarbs = sp.getInt(getString(R.string.key_treatmentssafety_maxcarbs), 48);
|
||||
maxBolus = sp.getFloat(getString(R.string.key_treatmentssafety_maxbolus), 3f);
|
||||
maxBolus = sp.getDouble(getString(R.string.key_treatmentssafety_maxbolus), 3.0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,7 +62,7 @@ public class TreatmentActivity extends ViewSelectorActivity {
|
|||
if (editInsulin != null) {
|
||||
def = SafeParse.stringToDouble(editInsulin.editText.getText().toString());
|
||||
}
|
||||
editInsulin = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, (double) maxBolus, 0.1d, new DecimalFormat("#0.0"),false);
|
||||
editInsulin = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, (double) maxBolus, 0.1d, new DecimalFormat("#0.0"), false);
|
||||
setLabelToPlusMinusView(view, getString(R.string.action_insulin));
|
||||
container.addView(view);
|
||||
view.requestFocus();
|
||||
|
@ -74,7 +73,7 @@ public class TreatmentActivity extends ViewSelectorActivity {
|
|||
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"),false);
|
||||
editCarbs = new PlusMinusEditText(view, R.id.amountfield, R.id.plusbutton, R.id.minusbutton, def, 0d, (double) maxCarbs, 1d, new DecimalFormat("0"), false);
|
||||
setLabelToPlusMinusView(view, getString(R.string.action_carbs));
|
||||
container.addView(view);
|
||||
return view;
|
||||
|
@ -83,13 +82,12 @@ public class TreatmentActivity extends ViewSelectorActivity {
|
|||
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?
|
||||
// (you have to swipe past them anyways - but still)
|
||||
String actionstring = "bolus " + SafeParse.stringToDouble(editInsulin.editText.getText().toString())
|
||||
+ " " + SafeParse.stringToInt(editCarbs.editText.getText().toString());
|
||||
ListenerService.initiateAction(TreatmentActivity.this, actionstring);
|
||||
confirmAction(TreatmentActivity.this, R.string.action_treatment_confirmation);
|
||||
finishAffinity();
|
||||
//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));
|
||||
showToast(TreatmentActivity.this, R.string.action_treatment_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
return view;
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.wearable.view.DotsPageIndicator;
|
||||
import android.support.wearable.view.GridPagerAdapter;
|
||||
import android.support.wearable.view.GridViewPager;
|
||||
|
@ -16,13 +13,21 @@ import android.widget.Toast;
|
|||
|
||||
import androidx.wear.widget.CurvedTextView;
|
||||
|
||||
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 13/02/17.
|
||||
*/
|
||||
|
||||
public class ViewSelectorActivity extends Activity {
|
||||
public class ViewSelectorActivity extends DaggerActivity {
|
||||
|
||||
@Inject SP sp;
|
||||
@Inject RxBus rxBus;
|
||||
|
||||
private GridViewPager pager;
|
||||
|
||||
|
@ -81,9 +86,7 @@ public class ViewSelectorActivity extends Activity {
|
|||
}
|
||||
|
||||
View getInflatedPlusMinusView(ViewGroup container) {
|
||||
SharedPreferences sharedPrefs = PreferenceManager
|
||||
.getDefaultSharedPreferences(this);
|
||||
int design = Integer.parseInt(sharedPrefs.getString("input_design", "1"));
|
||||
int design = sp.getInt("input_design", 1);
|
||||
|
||||
if (design == 2) {
|
||||
return LayoutInflater.from(getApplicationContext()).inflate(R.layout.action_editplusminus_item_quickrighty, container, false);
|
||||
|
@ -102,7 +105,7 @@ public class ViewSelectorActivity extends Activity {
|
|||
textView.setText(labelText);
|
||||
}
|
||||
|
||||
void confirmAction(Context context, int text) {
|
||||
void showToast(Context context, int text) {
|
||||
Toast.makeText(context, getString(text), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package info.nightscout.androidaps.interaction.actions;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.wearable.view.GridPagerAdapter;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -12,7 +10,7 @@ import android.widget.ImageView;
|
|||
import java.text.DecimalFormat;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.interaction.utils.PlusMinusEditText;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
|
||||
|
@ -33,7 +31,6 @@ public class WizardActivity extends ViewSelectorActivity {
|
|||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setAdapter(new MyGridViewPagerAdapter());
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
hasPercentage = sp.getBoolean("wizardpercentage", false);
|
||||
percentage = sp.getInt(getString(R.string.key_boluswizard_percentage), 100);
|
||||
maxCarbs = sp.getInt(getString(R.string.key_treatmentssafety_maxcarbs), 48);
|
||||
|
@ -93,8 +90,8 @@ public class WizardActivity extends ViewSelectorActivity {
|
|||
|
||||
String actionstring = "wizard2 " + SafeParse.stringToInt(editCarbs.editText.getText().toString())
|
||||
+ " " + percentage;
|
||||
ListenerService.initiateAction(WizardActivity.this, actionstring);
|
||||
confirmAction(WizardActivity.this, R.string.action_wizard_confirmation);
|
||||
DataLayerListenerService.Companion.initiateAction(WizardActivity.this, actionstring);
|
||||
showToast(WizardActivity.this, R.string.action_wizard_confirmation);
|
||||
finishAffinity();
|
||||
});
|
||||
container.addView(view);
|
||||
|
|
|
@ -7,7 +7,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.interaction.actions.FillActivity;
|
||||
import info.nightscout.androidaps.interaction.utils.MenuListActivity;
|
||||
|
||||
|
@ -37,11 +37,11 @@ public class FillMenuActivity extends MenuListActivity {
|
|||
@Override
|
||||
protected void doAction(String action) {
|
||||
if (getString(R.string.action_preset_1).equals(action)) {
|
||||
ListenerService.initiateAction(this, "fillpreset 1");
|
||||
DataLayerListenerService.Companion.initiateAction(this, "fillpreset 1");
|
||||
} else if (getString(R.string.action_preset_2).equals(action)) {
|
||||
ListenerService.initiateAction(this, "fillpreset 2");
|
||||
DataLayerListenerService.Companion.initiateAction(this, "fillpreset 2");
|
||||
} else if (getString(R.string.action_preset_3).equals(action)) {
|
||||
ListenerService.initiateAction(this, "fillpreset 3");
|
||||
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);
|
||||
|
|
|
@ -9,11 +9,11 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.interaction.AAPSPreferences;
|
||||
import info.nightscout.androidaps.interaction.actions.TreatmentActivity;
|
||||
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;
|
||||
|
||||
|
@ -30,7 +30,7 @@ public class MainMenuActivity extends MenuListActivity {
|
|||
sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
setTitle(R.string.label_actions_activity);
|
||||
super.onCreate(savedInstanceState);
|
||||
ListenerService.requestData(this);
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -68,7 +68,7 @@ public class MainMenuActivity extends MenuListActivity {
|
|||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
this.startActivity(intent);
|
||||
} else if (getString(R.string.menu_resync).equals(action)) {
|
||||
ListenerService.requestData(this);
|
||||
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);
|
||||
|
|
|
@ -6,7 +6,7 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.interaction.utils.MenuListActivity;
|
||||
|
||||
/**
|
||||
|
@ -35,13 +35,13 @@ public class StatusMenuActivity extends MenuListActivity {
|
|||
@Override
|
||||
protected void doAction(String action) {
|
||||
if (getString(R.string.status_pump).equals(action)) {
|
||||
ListenerService.initiateAction(this, "status pump");
|
||||
DataLayerListenerService.Companion.initiateAction(this, "status pump");
|
||||
} else if (getString(R.string.status_loop).equals(action)) {
|
||||
ListenerService.initiateAction(this, "status loop");
|
||||
DataLayerListenerService.Companion.initiateAction(this, "status loop");
|
||||
} else if (getString(R.string.status_cpp).equals(action)) {
|
||||
ListenerService.initiateAction(this, "opencpp");
|
||||
DataLayerListenerService.Companion.initiateAction(this, "opencpp");
|
||||
} else if (getString(R.string.status_tdd).equals(action)) {
|
||||
ListenerService.initiateAction(this, "tddstats");
|
||||
DataLayerListenerService.Companion.initiateAction(this, "tddstats");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ 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.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.data.TempWatchData;
|
||||
import info.nightscout.androidaps.interaction.menus.MainMenuActivity;
|
||||
import lecho.lib.hellocharts.view.LineChartView;
|
||||
|
@ -158,7 +158,7 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
mRelativeLayout.getMeasuredHeight());
|
||||
}
|
||||
});
|
||||
ListenerService.requestData(this);
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
wakeLock.acquire(50);
|
||||
}
|
||||
|
||||
|
@ -634,9 +634,9 @@ 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) {
|
||||
ListenerService.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) {
|
||||
DataLayerListenerService.Companion.requestData(this); // attempt endTime recover missing data
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -690,7 +690,7 @@ public class BIGChart extends WatchFace implements SharedPreferences.OnSharedPre
|
|||
chart.setViewportCalculationEnabled(true);
|
||||
chart.setMaximumViewport(chart.getMaximumViewport());
|
||||
} else {
|
||||
ListenerService.requestData(this);
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ import javax.inject.Inject;
|
|||
|
||||
import dagger.android.AndroidInjection;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.data.RawDisplayData;
|
||||
import info.nightscout.androidaps.interaction.utils.Persistence;
|
||||
import info.nightscout.androidaps.interaction.utils.WearUtil;
|
||||
|
@ -678,7 +678,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
setupBatteryReceiver();
|
||||
if ("delta_granularity".equals(key)) {
|
||||
ListenerService.requestData(this);
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
}
|
||||
if (layoutSet) {
|
||||
setDataFields();
|
||||
|
@ -695,7 +695,7 @@ 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) {
|
||||
ListenerService.requestData(this); // Attempt endTime recover missing data
|
||||
DataLayerListenerService.Companion.requestData(this); // Attempt endTime recover missing data
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -728,7 +728,7 @@ public abstract class BaseWatchFace extends WatchFace implements SharedPreferenc
|
|||
setupCharts();
|
||||
}
|
||||
rawData.updateStatusFromMessage(intent, wakeLock);
|
||||
rawData.updateBasalsFromMessage(intent, wakeLock);
|
||||
rawData.updateBasalsFromMessage(intent);
|
||||
|
||||
if (isSimpleUi()) {
|
||||
if (needUpdate()) {
|
||||
|
|
|
@ -43,7 +43,7 @@ import java.util.ArrayList;
|
|||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.BasalWatchData;
|
||||
import info.nightscout.androidaps.data.BgWatchData;
|
||||
import info.nightscout.androidaps.data.ListenerService;
|
||||
import info.nightscout.androidaps.data.DataLayerListenerService;
|
||||
import info.nightscout.androidaps.data.TempWatchData;
|
||||
import info.nightscout.androidaps.interaction.menus.MainMenuActivity;
|
||||
|
||||
|
@ -137,7 +137,7 @@ public class NOChart extends WatchFace implements SharedPreferences.OnSharedPref
|
|||
mRelativeLayout.getMeasuredHeight());
|
||||
}
|
||||
});
|
||||
ListenerService.requestData(this);
|
||||
DataLayerListenerService.Companion.requestData(this);
|
||||
wakeLock.acquire(50);
|
||||
}
|
||||
|
||||
|
@ -518,7 +518,7 @@ 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) {
|
||||
ListenerService.requestData(this); // attempt endTime recover missing data
|
||||
DataLayerListenerService.Companion.requestData(this); // attempt endTime recover missing data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Copyright 2015 Google Inc. All rights reserved.
|
||||
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
|
||||
http://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.
|
||||
-->
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2021 The Android Open Source Project
|
||||
|
||||
<resources>
|
||||
<string-array name="android_wear_capabilities">
|
||||
<item>phone_app_sync_bgs</item>
|
||||
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
|
||||
|
||||
http://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.
|
||||
-->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<string-array
|
||||
name="android_wear_capabilities"
|
||||
translatable="false"
|
||||
tools:ignore="UnusedResources">
|
||||
<!-- declaring the provided capabilities -->
|
||||
<item>androidaps_wear</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -220,7 +220,7 @@ public class RawDisplayDataBasalsTest extends TestBase {
|
|||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
newRaw.updateBasalsFromMessage(intent, null);
|
||||
newRaw.updateBasalsFromMessage(intent);
|
||||
|
||||
// THEN
|
||||
assertBasalsOk(newRaw);
|
||||
|
@ -233,7 +233,7 @@ public class RawDisplayDataBasalsTest extends TestBase {
|
|||
RawDisplayData newRaw = new RawDisplayData(getWearUtil());
|
||||
|
||||
// WHEN
|
||||
newRaw.updateBasalsFromMessage(intent, null);
|
||||
newRaw.updateBasalsFromMessage(intent);
|
||||
|
||||
// THEN
|
||||
assertBasalsEmpty(newRaw);
|
||||
|
|
Loading…
Reference in a new issue