Merge pull request #1666 from nightscout/wear

Wear
This commit is contained in:
Milos Kozak 2022-05-04 23:02:31 +02:00 committed by GitHub
commit 15a6d27349
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
550 changed files with 9286 additions and 13800 deletions

View file

@ -50,6 +50,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"
@ -110,14 +114,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
@ -177,65 +173,25 @@
</provider>
<service
android:name=".plugins.general.wear.wearintegration.WatchUpdaterService"
android:name=".plugins.general.wear.wearintegration.DataLayerListenerServiceMobile"
android:exported="true">
<intent-filter>
<!-- <action android:name="com.google.android.gms.wearable.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:scheme="wear" />
<data
android:host="*"
android:pathPrefix="/nightscout_watch_data_resend"
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="/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_rx_bridge"
android:scheme="wear" />
</intent-filter>
</service>
@ -253,10 +209,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"

View file

@ -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
@ -49,7 +53,6 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.exceptions.UndeliverableException
import io.reactivex.rxjava3.kotlin.plusAssign
import io.reactivex.rxjava3.plugins.RxJavaPlugins
import net.danlew.android.joda.JodaTimeAndroid
import java.io.IOException
import java.net.SocketException
import java.util.concurrent.TimeUnit
@ -98,7 +101,6 @@ class MainApp : DaggerApplication() {
}
disposable += compatDBHelper.dbChangeDisposable()
registerActivityLifecycleCallbacks(activityMonitor)
JodaTimeAndroid.init(this)
profileSwitchPlugin.setThemeMode()
aapsLogger.debug("Version: " + BuildConfig.VERSION_NAME)
aapsLogger.debug("BuildVersion: " + BuildConfig.BUILDVERSION)

View file

@ -150,7 +150,7 @@ class HistoryBrowseActivity : NoSplashAppCompatActivity() {
binding.date.setOnClickListener {
MaterialDatePicker.Builder.datePicker()
.setSelection(dateUtil.timeStampToUtcDateMilis(overviewData.fromTime))
.setSelection(dateUtil.timeStampToUtcDateMillis(overviewData.fromTime))
.setTheme(R.style.DatePicker)
.build()
.apply {

View file

@ -47,7 +47,7 @@ import info.nightscout.androidaps.plugins.source.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog.show
import info.nightscout.androidaps.utils.protection.PasswordCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.ProtectionType.*
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.SafeParse
import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject

View file

@ -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) {

View file

@ -41,7 +41,7 @@ import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag

View file

@ -26,7 +26,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientR
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag

View file

@ -33,7 +33,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag

View file

@ -37,7 +37,7 @@ import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag

View file

@ -35,7 +35,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventNewHi
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag

View file

@ -38,7 +38,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag

View file

@ -24,7 +24,7 @@ import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.Translator
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.userEntry.UserEntryPresentationHelper
import io.reactivex.rxjava3.disposables.CompositeDisposable

View file

@ -31,7 +31,7 @@ import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.buildHelper.BuildHelperImpl
import info.nightscout.androidaps.utils.buildHelper.ConfigImpl
import info.nightscout.androidaps.utils.resources.IconsProviderImplementation
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.rx.DefaultAapsSchedulers
import info.nightscout.androidaps.utils.storage.FileStorage

View file

@ -5,7 +5,7 @@ import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.plugins.general.nsclient.services.NSClientService
import info.nightscout.androidaps.plugins.general.overview.notifications.DismissNotificationService
import info.nightscout.androidaps.plugins.general.persistentNotification.DummyService
import info.nightscout.androidaps.plugins.general.wear.wearintegration.WatchUpdaterService
import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataLayerListenerServiceMobile
import info.nightscout.androidaps.services.AlarmSoundService
import info.nightscout.androidaps.services.LocationService
@ -18,5 +18,5 @@ abstract class ServicesModule {
@ContributesAndroidInjector abstract fun contributesDummyService(): DummyService
@ContributesAndroidInjector abstract fun contributesLocationService(): LocationService
@ContributesAndroidInjector abstract fun contributesNSClientService(): NSClientService
@ContributesAndroidInjector abstract fun contributesWatchUpdaterService(): WatchUpdaterService
@ContributesAndroidInjector abstract fun contributesWatchUpdaterService(): DataLayerListenerServiceMobile
}

View file

@ -19,7 +19,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProv
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.XDripBroadcast
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import java.text.DecimalFormat
import java.util.*
import javax.inject.Inject

View file

@ -29,7 +29,7 @@ import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import java.text.DecimalFormat

View file

@ -30,7 +30,7 @@ import info.nightscout.androidaps.utils.Translator
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.extensions.fromConstant
import info.nightscout.androidaps.interfaces.GlucoseUnit
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import java.text.DecimalFormat

View file

@ -25,7 +25,7 @@ import info.nightscout.androidaps.extensions.formatColor
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.logging.LTag
import java.text.DecimalFormat
import java.util.*

View file

@ -31,7 +31,7 @@ import info.nightscout.androidaps.extensions.formatColor
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import java.util.*

View file

@ -30,7 +30,7 @@ import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.extensions.toSignedString
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.SafeParse
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign

View file

@ -40,7 +40,7 @@ import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign

View file

@ -35,7 +35,7 @@ import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import java.text.DecimalFormat

View file

@ -23,7 +23,7 @@ import info.nightscout.androidaps.extensions.formatColor
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.logging.LTag
import java.text.DecimalFormat
import java.util.*

View file

@ -31,7 +31,7 @@ import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import java.text.DecimalFormat

View file

@ -32,7 +32,7 @@ import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.extensions.formatColor
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import java.text.DecimalFormat

View file

@ -32,7 +32,7 @@ import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.BOLUS
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.wizard.BolusWizard
import info.nightscout.shared.SafeParse

View file

@ -17,7 +17,7 @@ import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import org.json.JSONObject
import javax.inject.Inject

View file

@ -1,3 +0,0 @@
package info.nightscout.androidaps.events
class EventBolusRequested(var amount: Double) : Event()

View file

@ -13,7 +13,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP

View file

@ -27,6 +27,7 @@ import info.nightscout.androidaps.database.entities.ValueWithUnit
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentOfflineEventTransaction
import info.nightscout.androidaps.database.transactions.InsertTherapyEventAnnouncementTransaction
import info.nightscout.androidaps.events.EventAcceptOpenLoopChange
import info.nightscout.androidaps.events.EventMobileToWear
import info.nightscout.androidaps.events.EventTempTargetChange
import info.nightscout.androidaps.extensions.buildDeviceStatus
import info.nightscout.androidaps.extensions.convertedToAbsolute
@ -44,8 +45,6 @@ import info.nightscout.androidaps.plugins.configBuilder.RunningConfiguration
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
import info.nightscout.androidaps.plugins.pump.virtual.VirtualPumpPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.receivers.ReceiverStatusStore
@ -53,11 +52,12 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.weardata.EventData
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import javax.inject.Inject
@ -349,7 +349,7 @@ class LoopPlugin @Inject constructor(
//only send to wear if Native notifications are turned off
if (!sp.getBoolean(R.string.key_raise_notifications_as_android_notifications, true)) {
// Send to Wear
rxBus.send(EventWearInitiateAction("changeRequest"))
sendToWear()
}
}
} else {
@ -454,14 +454,28 @@ class LoopPlugin @Inject constructor(
rxBus.send(EventNewOpenLoopNotification())
// Send to Wear
rxBus.send(EventWearInitiateAction("changeRequest"))
sendToWear()
}
private fun dismissSuggestion() {
// dismiss notifications
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(Constants.notificationID)
rxBus.send(EventWearConfirmAction("cancelChangeRequest"))
rxBus.send(EventMobileToWear(EventData.CancelNotification(dateUtil.now())))
}
private fun sendToWear() {
lastRun?.let {
rxBus.send(
EventMobileToWear(
EventData.OpenLoopRequest(
rh.gs(R.string.openloop_newsuggestion),
it.constraintsProcessed.toString(),
EventData.OpenLoopRequestConfirmed(dateUtil.now())
)
)
)
}
}
override fun acceptChangeRequest() {

View file

@ -12,7 +12,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.JSONFormatter
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag

View file

@ -23,7 +23,7 @@ import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.Profiler
import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.extensions.target
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import org.json.JSONException
import javax.inject.Inject
import javax.inject.Singleton

View file

@ -16,7 +16,7 @@ import info.nightscout.androidaps.plugins.aps.loop.ScriptReader
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.shared.SafeParse
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONArray
import org.json.JSONException

View file

@ -14,7 +14,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.JSONFormatter
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag

View file

@ -21,7 +21,7 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.Profiler
import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP

View file

@ -21,7 +21,7 @@ import info.nightscout.androidaps.plugins.aps.openAPSSMB.SMBDefaults
import info.nightscout.androidaps.plugins.configBuilder.ConstraintChecker
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.stats.TddCalculator
import info.nightscout.shared.SafeParse
import info.nightscout.shared.logging.AAPSLogger

View file

@ -18,7 +18,7 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.Profiler
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject

View file

@ -26,7 +26,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.PREFERENCES
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign

View file

@ -16,7 +16,7 @@ import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.configBuilder.events.EventConfigBuilderUpdateGui
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import java.util.*
import javax.inject.Inject

View file

@ -19,7 +19,7 @@ import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable

View file

@ -8,7 +8,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventBucke
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag

View file

@ -10,7 +10,7 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotifi
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import java.util.*
import javax.inject.Inject

View file

@ -38,7 +38,7 @@ import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.SntpClient
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import io.reactivex.rxjava3.kotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable

View file

@ -14,7 +14,7 @@ import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.*
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import java.util.*
import javax.inject.Inject

View file

@ -15,7 +15,7 @@ import info.nightscout.androidaps.plugins.constraints.objectives.objectives.Obje
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
class ObjectivesExamDialog : DaggerDialogFragment() {

View file

@ -11,7 +11,7 @@ import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import java.util.*
import javax.inject.Inject

View file

@ -10,7 +10,7 @@ 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.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
import javax.inject.Singleton

View file

@ -20,7 +20,7 @@ import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.HardLimits
import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONObject
import javax.inject.Inject

View file

@ -13,7 +13,7 @@ import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import org.spongycastle.util.encoders.Hex
import java.io.*

View file

@ -16,7 +16,7 @@ import info.nightscout.shared.logging.LTag
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
import javax.inject.Singleton

View file

@ -9,7 +9,7 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotifi
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.extensions.daysToMillis
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP
import java.util.concurrent.TimeUnit

View file

@ -41,7 +41,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.androidaps.utils.ui.SingleClickButton
@ -84,14 +84,15 @@ class ActionsFragment : DaggerFragment() {
// This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
//check screen width
dm = DisplayMetrics()
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
@Suppress("DEPRECATION")
activity?.display?.getRealMetrics(dm)
} else {
@Suppress("DEPRECATION") activity?.windowManager?.defaultDisplay?.getMetrics(dm)
@Suppress("DEPRECATION")
activity?.windowManager?.defaultDisplay?.getMetrics(dm)
}
_binding = ActionsFragmentBinding.inflate(inflater, container, false)
return binding.root

View file

@ -7,7 +7,7 @@ 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.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
import javax.inject.Singleton

View file

@ -22,7 +22,7 @@ import info.nightscout.androidaps.services.Intents
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag

View file

@ -28,7 +28,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.ui.UIRunnable
import info.nightscout.shared.logging.AAPSLogger

View file

@ -17,7 +17,7 @@ import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.androidaps.receivers.DataWorker
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONObject
import javax.inject.Inject

View file

@ -39,7 +39,7 @@ import info.nightscout.androidaps.utils.alertDialogs.TwoMessagesAlertDialog
import info.nightscout.androidaps.utils.alertDialogs.WarningDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.protection.PasswordCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.storage.Storage
import info.nightscout.androidaps.utils.userEntry.UserEntryPresentationHelper
import info.nightscout.shared.logging.AAPSLogger

View file

@ -31,7 +31,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.eros.history.database.Ero
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.protection.ProtectionCheck.Protection.PREFERENCES
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import io.reactivex.rxjava3.core.Completable.fromAction
import io.reactivex.rxjava3.disposables.CompositeDisposable

View file

@ -14,7 +14,7 @@ import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import java.io.*
import java.util.*

View file

@ -18,7 +18,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientR
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable

View file

@ -35,7 +35,7 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.HtmlHelper.fromHtml
import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable

View file

@ -6,7 +6,7 @@ import info.nightscout.androidaps.events.EventNetworkChange
import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject
import javax.inject.Singleton

View file

@ -11,7 +11,7 @@ import info.nightscout.androidaps.utils.HtmlHelper.fromHtml
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP

View file

@ -16,7 +16,7 @@ import info.nightscout.androidaps.plugins.general.overview.notifications.Notific
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject

View file

@ -1,7 +1,7 @@
package info.nightscout.androidaps.plugins.general.nsclient.events
import info.nightscout.androidaps.events.EventStatus
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
class EventNSClientStatus(var text: String) : EventStatus() {
override fun getStatus(rh: ResourceHelper): String = text

View file

@ -44,7 +44,7 @@ import info.nightscout.androidaps.utils.JsonHelper.safeGetStringAllowNull
import info.nightscout.androidaps.utils.T.Companion.mins
import info.nightscout.androidaps.utils.XDripBroadcast
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag

View file

@ -28,7 +28,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP
import java.util.*

View file

@ -54,7 +54,6 @@ import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizar
import info.nightscout.androidaps.plugins.general.overview.events.*
import info.nightscout.androidaps.plugins.general.overview.graphData.GraphData
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.plugins.pump.omnipod.eros.OmnipodErosPumpPlugin
@ -69,13 +68,14 @@ import info.nightscout.androidaps.utils.TrendCalculator
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.protection.ProtectionCheck
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.ui.SingleClickButton
import info.nightscout.androidaps.utils.ui.UIRunnable
import info.nightscout.androidaps.utils.wizard.QuickWizard
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.weardata.EventData
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import java.util.*
@ -407,7 +407,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
?: "".toSpanned(), {
uel.log(Action.ACCEPTS_TEMP_BASAL, Sources.Overview)
(context?.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager?)?.cancel(Constants.notificationID)
rxBus.send(EventWearInitiateAction("cancelChangeRequest"))
rxBus.send(EventMobileToWear(EventData.CancelNotification(dateUtil.now())))
Thread { loop.acceptChangeRequest() }.run()
binding.buttonsLayout.acceptTempButton.visibility = View.GONE
})

View file

@ -18,7 +18,7 @@ import info.nightscout.androidaps.interfaces.Loop
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.buildHelper.BuildHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject

View file

@ -21,7 +21,7 @@ import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Scale
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationStore
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventIobCalculationProgress
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP

View file

@ -16,7 +16,7 @@ import info.nightscout.androidaps.plugins.pump.omnipod.eros.driver.definition.Om
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.WarnColors
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject
import javax.inject.Singleton

View file

@ -17,7 +17,7 @@ import info.nightscout.androidaps.plugins.general.overview.graphExtensions.Doubl
import info.nightscout.androidaps.plugins.general.overview.graphExtensions.TimeAsXAxisLabelFormatter
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import java.util.*
import javax.inject.Inject
import kotlin.math.abs

View file

@ -7,7 +7,7 @@ import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
class BolusDataPoint @Inject constructor(

View file

@ -3,7 +3,7 @@ package info.nightscout.androidaps.plugins.general.overview.graphExtensions
import android.content.Context
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.database.entities.Carbs
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
class CarbsDataPoint @Inject constructor(

View file

@ -4,7 +4,7 @@ import android.content.Context
import android.graphics.Color
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.database.entities.EffectiveProfileSwitch
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
class EffectiveProfileSwitchDataPoint @Inject constructor(

View file

@ -5,7 +5,7 @@ import android.graphics.Color
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.database.entities.ExtendedBolus
import info.nightscout.androidaps.extensions.toStringTotal
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
class ExtendedBolusDataPoint @Inject constructor(

View file

@ -7,7 +7,7 @@ import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.interfaces.GlucoseUnit
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
class GlucoseValueDataPoint @Inject constructor(

View file

@ -6,7 +6,7 @@ import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.data.InMemoryGlucoseValue
import info.nightscout.androidaps.interfaces.GlucoseUnit
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
class InMemoryGlucoseValueDataPoint @Inject constructor(

View file

@ -8,7 +8,7 @@ import info.nightscout.androidaps.database.entities.TherapyEvent
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.utils.Translator
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
class TherapyEventDataPoint @Inject constructor(

View file

@ -22,7 +22,7 @@ import info.nightscout.shared.logging.LTag
import info.nightscout.androidaps.plugins.general.overview.events.EventUpdateOverviewNotification
import info.nightscout.androidaps.services.AlarmSoundServiceHelper
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import java.util.*
import javax.inject.Inject

View file

@ -8,7 +8,7 @@ import info.nightscout.androidaps.plugins.general.nsclient.NSClientPlugin
import info.nightscout.androidaps.plugins.general.nsclient.data.NSAlarm
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Inject

View file

@ -20,7 +20,7 @@ import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import io.reactivex.rxjava3.disposables.CompositeDisposable

View file

@ -11,7 +11,7 @@ import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePas
import info.nightscout.androidaps.plugins.general.smsCommunicator.otp.OneTimePasswordValidationResult
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
class AuthRequest internal constructor(

View file

@ -43,7 +43,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProv
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.receivers.DataWorker
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.androidaps.utils.textValidator.ValidatingEditTextPreference

View file

@ -7,7 +7,7 @@ import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.annotations.OpenForTesting
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import java.net.URLEncoder
import javax.crypto.KeyGenerator

View file

@ -13,7 +13,7 @@ import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable
import javax.inject.Inject

View file

@ -31,7 +31,7 @@ import info.nightscout.androidaps.utils.HtmlHelper
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils
import io.reactivex.rxjava3.kotlin.plusAssign
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable

View file

@ -18,7 +18,7 @@ import info.nightscout.androidaps.plugins.general.tidepool.messages.UploadReplyM
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.shared.sharedPreferences.SP
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient

View file

@ -2,4 +2,4 @@ package info.nightscout.androidaps.plugins.general.tidepool.events
import info.nightscout.androidaps.events.Event
class EventTidepoolResetData :Event()
class EventTidepoolResetData : Event()

View file

@ -1,778 +0,0 @@
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
import info.nightscout.androidaps.dana.DanaPump
import info.nightscout.androidaps.danaRKorean.DanaRKoreanPlugin
import info.nightscout.androidaps.danaRv2.DanaRv2Plugin
import info.nightscout.androidaps.danar.DanaRPlugin
import info.nightscout.androidaps.danars.DanaRSPlugin
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.entities.TemporaryTarget
import info.nightscout.androidaps.database.entities.TotalDailyDose
import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.database.entities.ValueWithUnit
import info.nightscout.androidaps.database.interfaces.end
import info.nightscout.androidaps.database.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import info.nightscout.androidaps.database.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
import info.nightscout.androidaps.extensions.total
import info.nightscout.androidaps.extensions.valueToUnits
import info.nightscout.androidaps.interfaces.*
import info.nightscout.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
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification
import info.nightscout.androidaps.plugins.general.wear.events.EventWearConfirmAction
import info.nightscout.androidaps.plugins.general.wear.events.EventWearInitiateAction
import info.nightscout.androidaps.plugins.pump.insight.LocalInsightPlugin
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.*
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.androidaps.utils.wizard.BolusWizard
import info.nightscout.androidaps.utils.wizard.QuickWizard
import info.nightscout.shared.SafeParse
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.math.abs
import kotlin.math.min
@Suppress("SpellCheckingInspection")
@Singleton
class ActionStringHandler @Inject constructor(
private val sp: SP,
private val rxBus: RxBus,
private val aapsLogger: AAPSLogger,
private val aapsSchedulers: AapsSchedulers,
private val rh: ResourceHelper,
private val injector: HasAndroidInjector,
private val context: Context,
private val constraintChecker: ConstraintChecker,
private val profileFunction: ProfileFunction,
private val loop: Loop,
private val wearPlugin: WearPlugin,
private val fabricPrivacy: FabricPrivacy,
private val commandQueue: CommandQueue,
private val activePlugin: ActivePlugin,
private val iobCobCalculator: IobCobCalculator,
private val localInsightPlugin: LocalInsightPlugin,
private val quickWizard: QuickWizard,
private val danaRPlugin: DanaRPlugin,
private val danaRKoreanPlugin: DanaRKoreanPlugin,
private val danaRv2Plugin: DanaRv2Plugin,
private val danaRSPlugin: DanaRSPlugin,
private val danaPump: DanaPump,
private val dateUtil: DateUtil,
private val config: Config,
private val repository: AppRepository,
private val uel: UserEntryLogger,
private val defaultValueHelper: DefaultValueHelper
) {
private val timeout = 65 * 1000
private var lastSentTimestamp: Long = 0
private var lastConfirmActionString: String? = null
private var lastBolusWizard: BolusWizard? = null
private val disposable = CompositeDisposable()
fun setup() {
disposable += rxBus
.toObservable(EventWearInitiateAction::class.java)
.observeOn(aapsSchedulers.main)
.subscribe({ handleInitiate(it.action) }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventWearConfirmAction::class.java)
.observeOn(aapsSchedulers.main)
.subscribe({ handleConfirmation(it.action) }, fabricPrivacy::logException)
}
fun tearDown() {
disposable.clear()
}
@Synchronized
private fun handleInitiate(actionString: String) {
//TODO: i18n
Log.i("ActionStringHandler", "handleInitiate 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"
}
"eating" -> {
val eatingSoonTTDuration = defaultValueHelper.determineEatingSoonTTDuration()
val eatingSoonTT = defaultValueHelper.determineEatingSoonTT()
val reason = rh.gs(R.string.eatingsoon)
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, eatingSoonTT, eatingSoonTTDuration)
rAction = "temptarget $presetIsMGDL $eatingSoonTTDuration $eatingSoonTT $eatingSoonTT"
}
else -> {
sendError(rh.gs(R.string.wear_action_tempt_preset_error, preset))
return
}
}
} else {
val isMGDL = java.lang.Boolean.parseBoolean(act[1])
if (profileFunction.getUnits() == GlucoseUnit.MGDL != isMGDL) {
sendError(rh.gs(R.string.wear_action_tempt_unit_error))
return
}
val duration = SafeParse.stringToInt(act[2])
if (duration == 0) {
rMessage += rh.gs(R.string.wear_action_tempt_zero_message)
rAction = "temptarget true 0 0 0"
} else {
var low = SafeParse.stringToDouble(act[3])
var high = SafeParse.stringToDouble(act[4])
if (!isMGDL) {
low *= Constants.MMOLL_TO_MGDL
high *= Constants.MMOLL_TO_MGDL
}
if (low < HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[0] || low > HardLimits.VERY_HARD_LIMIT_TEMP_MIN_BG[1]) {
sendError(rh.gs(R.string.wear_action_tempt_min_bg_error))
return
}
if (high < HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[0] || high > HardLimits.VERY_HARD_LIMIT_TEMP_MAX_BG[1]) {
sendError(rh.gs(R.string.wear_action_tempt_max_bg_error))
return
}
rMessage += if (act[3] === act[4]) rh.gs(R.string.wear_action_tempt_manual_message, act[3], act[2])
else rh.gs(R.string.wear_action_tempt_manual_range_message, act[3], act[4], act[2])
rAction = actionString
}
}
} 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
}
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()
} 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 { // 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)
lastSentTimestamp = System.currentTimeMillis()
lastConfirmActionString = rAction
}
private fun generateTDDMessage(historyList: MutableList<TotalDailyDose>, dummies: MutableList<TotalDailyDose>): String {
val profile = profileFunction.getProfile() ?: return "No profile loaded :("
if (historyList.isEmpty()) {
return "No history data!"
}
val df: DateFormat = SimpleDateFormat("dd.MM.", Locale.getDefault())
var message = ""
val refTDD = profile.baseBasalSum() * 2
val pump = activePlugin.activePump
if (df.format(Date(historyList[0].timestamp)) == df.format(Date())) {
val tdd = historyList[0].total
historyList.removeAt(0)
message += "Today: " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100 * tdd / refTDD) + "%") + "\n"
message += "\n"
} else if (pump is DanaRPlugin) {
val tdd = danaPump.dailyTotalUnits
message += "Today: " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100 * tdd / refTDD) + "%") + "\n"
message += "\n"
}
var weighted03 = 0.0
var weighted05 = 0.0
var weighted07 = 0.0
historyList.reverse()
for ((i, record) in historyList.withIndex()) {
val tdd = record.total
if (i == 0) {
weighted03 = tdd
weighted05 = tdd
weighted07 = tdd
} else {
weighted07 = weighted07 * 0.3 + tdd * 0.7
weighted05 = weighted05 * 0.5 + tdd * 0.5
weighted03 = weighted03 * 0.7 + tdd * 0.3
}
}
message += "weighted:\n"
message += "0.3: " + DecimalFormatter.to2Decimal(weighted03) + "U " + (DecimalFormatter.to0Decimal(100 * weighted03 / refTDD) + "%") + "\n"
message += "0.5: " + DecimalFormatter.to2Decimal(weighted05) + "U " + (DecimalFormatter.to0Decimal(100 * weighted05 / refTDD) + "%") + "\n"
message += "0.7: " + DecimalFormatter.to2Decimal(weighted07) + "U " + (DecimalFormatter.to0Decimal(100 * weighted07 / refTDD) + "%") + "\n"
message += "\n"
historyList.reverse()
//add TDDs:
for (record in historyList) {
val tdd = record.total
message += df.format(Date(record.timestamp)) + " " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100 * tdd / refTDD) + "%") + (if (dummies.contains(record)) "x" else "") + "\n"
}
return message
}
private fun isOldData(historyList: List<TotalDailyDose>): Boolean {
val activePump = activePlugin.activePump
val startsYesterday = activePump === danaRPlugin || activePump === danaRSPlugin || activePump === danaRv2Plugin || activePump === danaRKoreanPlugin || activePump === localInsightPlugin
val df: DateFormat = SimpleDateFormat("dd.MM.", Locale.getDefault())
return historyList.size < 3 || df.format(Date(historyList[0].timestamp)) != df.format(Date(System.currentTimeMillis() - if (startsYesterday) 1000 * 60 * 60 * 24 else 0))
}
private fun getTDDList(returnDummies: MutableList<TotalDailyDose>): MutableList<TotalDailyDose> {
var historyList = repository.getLastTotalDailyDoses(10, false).blockingGet().toMutableList()
//var historyList = databaseHelper.getTDDs().toMutableList()
historyList = historyList.subList(0, min(10, historyList.size))
//fill single gaps - only needed for Dana*R data
val dummies: MutableList<TotalDailyDose> = returnDummies
val df: DateFormat = SimpleDateFormat("dd.MM.", Locale.getDefault())
for (i in 0 until historyList.size - 1) {
val elem1 = historyList[i]
val elem2 = historyList[i + 1]
if (df.format(Date(elem1.timestamp)) != df.format(Date(elem2.timestamp + 25 * 60 * 60 * 1000))) {
val dummy = TotalDailyDose(timestamp = elem1.timestamp - T.hours(24).msecs(), bolusAmount = elem1.bolusAmount / 2, basalAmount = elem1.basalAmount / 2)
dummies.add(dummy)
elem1.basalAmount /= 2.0
elem1.bolusAmount /= 2.0
}
}
historyList.addAll(dummies)
historyList.sortWith { lhs, rhs -> (rhs.timestamp - lhs.timestamp).toInt() }
return historyList
}
private val pumpStatus: String
get() = activePlugin.activePump.shortStatus(false)
// decide if enabled/disabled closed/open; what Plugin as APS?
private val loopStatus: String
get() {
var ret = ""
// decide if enabled/disabled closed/open; what Plugin as APS?
if ((loop as PluginBase).isEnabled()) {
ret += if (constraintChecker.isClosedLoopAllowed().value()) {
"CLOSED LOOP\n"
} else {
"OPEN LOOP\n"
}
val aps = activePlugin.activeAPS
ret += "APS: " + (aps as PluginBase).name
val lastRun = loop.lastRun
if (lastRun != null) {
ret += "\nLast Run: " + dateUtil.timeString(lastRun.lastAPSRun)
if (lastRun.lastTBREnact != 0L) ret += "\nLast Enact: " + dateUtil.timeString(lastRun.lastTBREnact)
}
} else {
ret += "LOOP DISABLED\n"
}
return ret
}
//Check for Temp-Target:
private val targetsStatus: String
get() {
var ret = ""
if (!config.APS) {
return "Targets only apply in APS mode!"
}
val profile = profileFunction.getProfile() ?: return "No profile set :("
//Check for Temp-Target:
val tempTarget = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
if (tempTarget is ValueWrapper.Existing) {
ret += "Temp Target: " + Profile.toTargetRangeString(tempTarget.value.lowTarget, tempTarget.value.lowTarget, GlucoseUnit.MGDL, profileFunction.getUnits())
ret += "\nuntil: " + dateUtil.timeString(tempTarget.value.end)
ret += "\n\n"
}
ret += "DEFAULT RANGE: "
ret += Profile.fromMgdlToUnits(profile.getTargetLowMgdl(), profileFunction.getUnits()).toString() + " - " + Profile.fromMgdlToUnits(profile.getTargetHighMgdl(), profileFunction.getUnits())
ret += " target: " + Profile.fromMgdlToUnits(profile.getTargetMgdl(), profileFunction.getUnits())
return ret
}
private val oAPSResultStatus: String
get() {
var ret = ""
if (!config.APS)
return "Only apply in APS mode!"
val usedAPS = activePlugin.activeAPS
val result = usedAPS.lastAPSResult ?: return "Last result not available!"
ret += if (!result.isChangeRequested) {
rh.gs(R.string.nochangerequested) + "\n"
} else if (result.rate == 0.0 && result.duration == 0) {
rh.gs(R.string.canceltemp) + "\n"
} else {
rh.gs(R.string.rate) + ": " + DecimalFormatter.to2Decimal(result.rate) + " U/h " +
"(" + DecimalFormatter.to2Decimal(result.rate / activePlugin.activePump.baseBasalRate * 100) + "%)\n" +
rh.gs(R.string.duration) + ": " + DecimalFormatter.to0Decimal(result.duration.toDouble()) + " min\n"
}
ret += "\n" + rh.gs(R.string.reason) + ": " + result.reason
return ret
}
@Synchronized
fun handleConfirmation(actionString: String) {
if (!sp.getBoolean(R.string.key_wear_control, false)) return
//Guard from old or duplicate confirmations
if (lastConfirmActionString == null) return
if (lastConfirmActionString != actionString) return
if (System.currentTimeMillis() - lastSentTimestamp > timeout) return
lastConfirmActionString = null
// do the parsing, check constraints and enact!
val act = actionString.split("\\s+".toRegex()).toTypedArray()
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
}
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
}
} 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
}
private fun setCPP(timeshift: Int, percentage: Int) {
var msg = ""
//check for validity
if (percentage < Constants.CPP_MIN_PERCENTAGE || percentage > Constants.CPP_MAX_PERCENTAGE) {
msg += rh.gs(R.string.valueoutofrange, "Profile-Percentage") + "\n"
}
if (timeshift < 0 || timeshift > 23) {
msg += rh.gs(R.string.valueoutofrange, "Profile-Timeshift") + "\n"
}
val profile = profileFunction.getProfile()
if (profile == null) {
msg += rh.gs(R.string.notloadedplugins) + "\n"
}
if ("" != msg) {
msg += rh.gs(R.string.valuesnotstored)
val rTitle = "STATUS"
val rAction = "statusmessage"
wearPlugin.requestActionConfirmation(rTitle, msg, rAction)
lastSentTimestamp = System.currentTimeMillis()
lastConfirmActionString = rAction
return
}
//send profile to pump
uel.log(Action.PROFILE_SWITCH, Sources.Wear,
ValueWithUnit.Percent(percentage),
ValueWithUnit.Hour(timeshift).takeIf { timeshift != 0 })
profileFunction.createProfileSwitch(0, percentage, timeshift)
}
private fun generateTempTarget(duration: Int, low: Double, high: Double) {
if (duration != 0) {
disposable += repository.runTransactionForResult(
InsertAndCancelCurrentTemporaryTargetTransaction(
timestamp = System.currentTimeMillis(),
duration = TimeUnit.MINUTES.toMillis(duration.toLong()),
reason = TemporaryTarget.Reason.WEAR,
lowTarget = Profile.toMgdl(low, profileFunction.getUnits()),
highTarget = Profile.toMgdl(high, profileFunction.getUnits())
)
).subscribe({ result ->
result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted temp target $it") }
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
}, {
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
})
uel.log(
Action.TT, Sources.Wear,
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR),
ValueWithUnit.fromGlucoseUnit(low, profileFunction.getUnits().asText),
ValueWithUnit.fromGlucoseUnit(high, profileFunction.getUnits().asText).takeIf { low != high },
ValueWithUnit.Minute(duration)
)
} else {
disposable += repository.runTransactionForResult(CancelCurrentTemporaryTargetIfAnyTransaction(System.currentTimeMillis()))
.subscribe({ result ->
result.updated.forEach { aapsLogger.debug(LTag.DATABASE, "Updated temp target $it") }
}, {
aapsLogger.error(LTag.DATABASE, "Error while saving temporary target", it)
})
uel.log(
Action.CANCEL_TT, Sources.Wear,
ValueWithUnit.TherapyEventTTReason(TemporaryTarget.Reason.WEAR)
)
}
}
private fun doFillBolus(amount: Double) {
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.insulin = amount
detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.PRIMING
uel.log(Action.PRIME_BOLUS, Sources.Wear,
ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 })
commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() {
if (!result.success) {
sendError(
rh.gs(R.string.treatmentdeliveryerror) +
"\n" +
result.comment
)
}
}
})
}
private fun doECarbs(carbs: Int, time: Long, duration: Int) {
uel.log(if (duration == 0) Action.CARBS else Action.EXTENDED_CARBS, Sources.Wear,
ValueWithUnit.Timestamp(time),
ValueWithUnit.Gram(carbs),
ValueWithUnit.Hour(duration).takeIf { duration != 0 })
doBolus(0.0, carbs, time, duration)
}
private fun doBolus(amount: Double, carbs: Int, carbsTime: Long?, carbsDuration: Int) {
val detailedBolusInfo = DetailedBolusInfo()
detailedBolusInfo.insulin = amount
detailedBolusInfo.carbs = carbs.toDouble()
detailedBolusInfo.bolusType = DetailedBolusInfo.BolusType.NORMAL
detailedBolusInfo.carbsTimestamp = carbsTime
detailedBolusInfo.carbsDuration = T.hours(carbsDuration.toLong()).msecs()
if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) {
val action = when {
amount.equals(0.0) -> Action.CARBS
carbs.equals(0) -> Action.BOLUS
carbsDuration > 0 -> Action.EXTENDED_CARBS
else -> Action.TREATMENT
}
uel.log(action, Sources.Wear,
ValueWithUnit.Insulin(amount).takeIf { amount != 0.0 },
ValueWithUnit.Gram(carbs).takeIf { carbs != 0 },
ValueWithUnit.Hour(carbsDuration).takeIf { carbsDuration != 0 })
commandQueue.bolus(detailedBolusInfo, object : Callback() {
override fun run() {
if (!result.success) {
sendError(
rh.gs(R.string.treatmentdeliveryerror) +
"\n" +
result.comment
)
}
}
})
}
}
@Synchronized private fun sendError(errorMessage: String) {
wearPlugin.requestActionConfirmation("ERROR", errorMessage, "error")
lastSentTimestamp = System.currentTimeMillis()
lastConfirmActionString = null
lastBolusWizard = null
}
@Synchronized
private fun sendStatusMessage(message: String) {
wearPlugin.requestActionConfirmation("TDD", message, "statusmessage")
lastSentTimestamp = System.currentTimeMillis()
lastConfirmActionString = null
lastBolusWizard = null
}
}

View file

@ -6,14 +6,29 @@ import android.view.View
import android.view.ViewGroup
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.databinding.WearFragmentBinding
import info.nightscout.androidaps.events.EventMobileToWear
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.nsclient.events.EventNSClientUpdateGUI
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.weardata.EventData
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import javax.inject.Inject
class WearFragment : DaggerFragment() {
@Inject lateinit var wearPlugin: WearPlugin
@Inject lateinit var rxBus: RxBus
@Inject lateinit var aapsSchedulers: AapsSchedulers
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var dateUtil: DateUtil
private var _binding: WearFragmentBinding? = null
private val disposable = CompositeDisposable()
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
@ -26,8 +41,22 @@ class WearFragment : DaggerFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.resend.setOnClickListener { wearPlugin.resendDataToWatch() }
binding.opensettings.setOnClickListener { wearPlugin.openSettings() }
binding.resend.setOnClickListener { rxBus.send(EventData.ActionResendData("WearFragment")) }
binding.openSettings.setOnClickListener { rxBus.send(EventMobileToWear(EventData.OpenSettings(dateUtil.now()))) }
}
override fun onResume() {
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 +64,9 @@ class WearFragment : DaggerFragment() {
super.onDestroyView()
_binding = null
}
fun updateGui() {
_binding ?: return
binding.connectedDevice.text = wearPlugin.connectedDevice
}
}

View file

@ -2,25 +2,28 @@ package info.nightscout.androidaps.plugins.general.wear
import android.content.Context
import android.content.Intent
import dagger.Lazy
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R
import info.nightscout.androidaps.events.*
import info.nightscout.androidaps.interfaces.Loop
import info.nightscout.androidaps.events.EventAutosensCalculationFinished
import info.nightscout.androidaps.events.EventMobileToWear
import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.PluginDescription
import info.nightscout.androidaps.interfaces.PluginType
import info.nightscout.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
import info.nightscout.androidaps.plugins.general.wear.wearintegration.WatchUpdaterService
import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataHandlerMobile
import info.nightscout.androidaps.plugins.general.wear.wearintegration.DataLayerListenerServiceMobile
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.weardata.EventData
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import javax.inject.Inject
import javax.inject.Singleton
@ -31,157 +34,66 @@ class WearPlugin @Inject constructor(
rh: ResourceHelper,
private val aapsSchedulers: AapsSchedulers,
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>
private val context: Context,
private val dataHandlerMobile: DataHandlerMobile
) : 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
.toObservable(EventOpenAPSUpdateGui::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventExtendedBolusChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventTempBasalChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventTreatmentChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = false) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventEffectiveProfileSwitchChanged::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ sendDataToWatch(status = false, basals = true, bgValue = false) }, fabricPrivacy::logException))
disposable.add(rxBus
.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ sendDataToWatch(status = true, basals = true, bgValue = true) }, fabricPrivacy::logException))
disposable.add(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)
.observeOn(aapsSchedulers.io)
.subscribe({
if (WatchUpdaterService.shouldReportLoopStatus((loop as PluginBase).isEnabled()))
sendDataToWatch(status = true, basals = false, bgValue = false)
}, fabricPrivacy::logException))
disposable.add(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
context.startService(Intent(context, DataLayerListenerServiceMobile::class.java))
disposable += rxBus
.toObservable(EventDismissBolusProgressIfRunning::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ event: EventDismissBolusProgressIfRunning ->
if (event.result == null) return@subscribe
val status: String = if (event.result!!.success) {
rh.gs(R.string.success)
} else {
rh.gs(R.string.nosuccess)
}
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
event.result?.let {
val status =
if (it.success) rh.gs(R.string.success)
else rh.gs(R.string.nosuccess)
if (isEnabled()) rxBus.send(EventMobileToWear(EventData.BolusProgress(percent = 100, status = status)))
}
}, 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))
actionStringHandler.get().setup()
if (!event.isSMB() || sp.getBoolean("wear_notifySMB", true)) {
if (isEnabled()) rxBus.send(EventMobileToWear(EventData.BolusProgress(percent = event.percent, status = event.status)))
}
}, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventPreferenceChange::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ dataHandlerMobile.resendData("EventPreferenceChange") }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventAutosensCalculationFinished::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ dataHandlerMobile.resendData("EventAutosensCalculationFinished") }, fabricPrivacy::logException)
disposable += rxBus
.toObservable(EventLoopUpdateGui::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ dataHandlerMobile.resendData("EventLoopUpdateGui") }, fabricPrivacy::logException)
}
override fun onStop() {
disposable.clear()
super.onStop()
actionStringHandler.get().tearDown()
}
private fun sendDataToWatch(status: Boolean, basals: Boolean, bgValue: Boolean) {
//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))
}
}
}
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 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)
}
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)
context.stopService(Intent(context, DataLayerListenerServiceMobile::class.java))
}
}

View file

@ -1,5 +0,0 @@
package info.nightscout.androidaps.plugins.general.wear.events
import info.nightscout.androidaps.events.Event
class EventWearInitiateAction(val action: String) : Event()

View file

@ -2,4 +2,4 @@ package info.nightscout.androidaps.plugins.general.wear.events
import info.nightscout.androidaps.events.Event
class EventWearConfirmAction(val action: String) : Event()
class EventWearUpdateGui : Event()

View file

@ -0,0 +1,200 @@
package info.nightscout.androidaps.plugins.general.wear.wearintegration
import android.os.Handler
import android.os.HandlerThread
import com.google.android.gms.tasks.Tasks
import com.google.android.gms.wearable.*
import dagger.android.AndroidInjection
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.events.EventMobileToWear
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.Loop
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
import info.nightscout.androidaps.plugins.general.wear.WearPlugin
import info.nightscout.androidaps.plugins.general.wear.events.EventWearUpdateGui
import info.nightscout.androidaps.receivers.ReceiverStatusStore
import info.nightscout.androidaps.utils.DefaultValueHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.wizard.QuickWizard
import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.shared.weardata.EventData
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import kotlinx.coroutines.*
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
class DataLayerListenerServiceMobile : WearableListenerService() {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var iobCobCalculator: IobCobCalculator
@Inject lateinit var rh: ResourceHelper
@Inject lateinit var loop: Loop
@Inject lateinit var wearPlugin: WearPlugin
@Inject lateinit var sp: SP
@Inject lateinit var quickWizard: QuickWizard
@Inject lateinit var config: Config
@Inject lateinit var nsDeviceStatus: NSDeviceStatus
@Inject lateinit var receiverStatusStore: ReceiverStatusStore
@Inject lateinit var repository: AppRepository
@Inject lateinit var defaultValueHelper: DefaultValueHelper
@Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var rxBus: RxBus
@Inject lateinit var aapsSchedulers: AapsSchedulers
private val dataClient by lazy { Wearable.getDataClient(this) }
private val messageClient by lazy { Wearable.getMessageClient(this) }
private val capabilityClient by lazy { Wearable.getCapabilityClient(this) }
//private val nodeClient by lazy { Wearable.getNodeClient(this) }
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
private val disposable = CompositeDisposable()
private val rxPath get() = getString(R.string.path_rx_bridge)
override fun onCreate() {
AndroidInjection.inject(this)
super.onCreate()
aapsLogger.debug(LTag.WEAR, "onCreate")
handler.post { updateTranscriptionCapability() }
disposable += rxBus
.toObservable(EventMobileToWear::class.java)
.observeOn(aapsSchedulers.io)
.subscribe { sendMessage(rxPath, it.payload.serialize()) }
}
override fun onCapabilityChanged(p0: CapabilityInfo) {
super.onCapabilityChanged(p0)
handler.post { updateTranscriptionCapability() }
aapsLogger.debug(LTag.WEAR, "onCapabilityChanged: ${p0.name} ${p0.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}")
}
override fun onDestroy() {
super.onDestroy()
disposable.clear()
scope.cancel()
}
@Suppress("ControlFlowWithEmptyBody", "UNUSED_EXPRESSION")
override fun onDataChanged(dataEvents: DataEventBuffer) {
//aapsLogger.debug(LTag.WEAR, "onDataChanged")
if (wearPlugin.isEnabled()) {
dataEvents.forEach { event ->
if (event.type == DataEvent.TYPE_CHANGED) {
val path = event.dataItem.uri.path
aapsLogger.debug(LTag.WEAR, "onDataChanged: Path: $path, EventDataItem=${event.dataItem}")
try {
when (path) {
}
} catch (exception: Exception) {
aapsLogger.error(LTag.WEAR, "Message failed", exception)
}
}
}
}
super.onDataChanged(dataEvents)
}
override fun onMessageReceived(messageEvent: MessageEvent) {
super.onMessageReceived(messageEvent)
if (wearPlugin.isEnabled()) {
when (messageEvent.path) {
rxPath -> {
aapsLogger.debug(LTag.WEAR, "onMessageReceived: ${String(messageEvent.data)}")
val command = EventData.deserialize(String(messageEvent.data))
rxBus.send(command.also { it.sourceNodeId = messageEvent.sourceNodeId })
}
}
}
}
private var transcriptionNodeId: String? = null
private fun updateTranscriptionCapability() {
val capabilityInfo: CapabilityInfo = Tasks.await(
capabilityClient.getCapability(WEAR_CAPABILITY, CapabilityClient.FILTER_REACHABLE)
)
aapsLogger.debug(LTag.WEAR, "Nodes: ${capabilityInfo.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}")
val bestNode = pickBestNodeId(capabilityInfo.nodes)
transcriptionNodeId = bestNode?.id
wearPlugin.connectedDevice = bestNode?.displayName ?: "---"
rxBus.send(EventWearUpdateGui())
aapsLogger.debug(LTag.WEAR, "Selected node: ${bestNode?.displayName} $transcriptionNodeId")
rxBus.send(EventMobileToWear(EventData.ActionPing(System.currentTimeMillis())))
rxBus.send(EventData.ActionResendData("WatchUpdaterService"))
}
// Find a nearby node or pick one arbitrarily
private fun pickBestNodeId(nodes: Set<Node>): Node? =
nodes.firstOrNull { it.isNearby } ?: nodes.firstOrNull()
@Suppress("unused")
private fun sendData(path: String, vararg params: DataMap) {
if (wearPlugin.isEnabled()) {
scope.launch {
try {
for (dm in params) {
val request = PutDataMapRequest.create(path).apply {
dataMap.putAll(dm)
}
.asPutDataRequest()
.setUrgent()
val result = dataClient.putDataItem(request).await()
aapsLogger.debug(LTag.WEAR, "sendData: ${result.uri} ${params.joinToString()}")
}
} catch (cancellationException: CancellationException) {
throw cancellationException
} catch (exception: Exception) {
aapsLogger.error(LTag.WEAR, "DataItem failed: $exception")
}
}
}
}
private fun sendMessage(path: String, data: String?) {
aapsLogger.debug(LTag.WEAR, "sendMessage: $path $data")
transcriptionNodeId?.also { nodeId ->
messageClient
.sendMessage(nodeId, path, data?.toByteArray() ?: byteArrayOf()).apply {
addOnSuccessListener { }
addOnFailureListener {
aapsLogger.debug(LTag.WEAR, "sendMessage: $path failure")
}
}
}
}
@Suppress("unused")
private fun sendMessage(path: String, data: ByteArray) {
aapsLogger.debug(LTag.WEAR, "sendMessage: $path")
transcriptionNodeId?.also { nodeId ->
messageClient
.sendMessage(nodeId, path, data).apply {
addOnSuccessListener { }
addOnFailureListener {
aapsLogger.debug(LTag.WEAR, "sendMessage: $path failure")
}
}
}
}
companion object {
const val WEAR_CAPABILITY = "androidaps_wear"
}
}

View file

@ -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();
}
}

View file

@ -1,843 +0,0 @@
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 {
@Inject public GlucoseStatusProvider glucoseStatusProvider;
@Inject public AAPSLogger aapsLogger;
@Inject public WearPlugin wearPlugin;
@Inject public ResourceHelper rh;
@Inject public SP sp;
@Inject public RxBus rxBus;
@Inject public ProfileFunction profileFunction;
@Inject public DefaultValueHelper defaultValueHelper;
@Inject public NSDeviceStatus nsDeviceStatus;
@Inject public ActivePlugin activePlugin;
@Inject public Loop loop;
@Inject public IobCobCalculator iobCobCalculator;
@Inject public AppRepository repository;
@Inject ReceiverStatusStore receiverStatusStore;
@Inject Config config;
@Inject public TrendCalculator trendCalculator;
@Inject public QuickWizard quickWizard;
public static final String ACTION_RESEND = WatchUpdaterService.class.getName().concat(".Resend");
public static final String ACTION_OPEN_SETTINGS = WatchUpdaterService.class.getName().concat(".OpenSettings");
public static final String ACTION_SEND_STATUS = WatchUpdaterService.class.getName().concat(".SendStatus");
public static final String ACTION_SEND_BASALS = WatchUpdaterService.class.getName().concat(".SendBasals");
public static final String ACTION_SEND_BOLUSPROGRESS = WatchUpdaterService.class.getName().concat(".BolusProgress");
public static final String ACTION_SEND_ACTIONCONFIRMATIONREQUEST = WatchUpdaterService.class.getName().concat(".ActionConfirmationRequest");
public static final String ACTION_SEND_CHANGECONFIRMATIONREQUEST = WatchUpdaterService.class.getName().concat(".ChangeConfirmationRequest");
public static final String ACTION_CANCEL_NOTIFICATION = WatchUpdaterService.class.getName().concat(".CancelNotification");
private GoogleApiClient googleApiClient;
String TAG = "WatchUpdateService";
private static boolean lastLoopStatus;
private Handler handler;
// Phone
private static final String CAPABILITY_PHONE_APP = "phone_app_sync_bgs";
private static final String MESSAGE_PATH_PHONE = "/phone_message_path";
// Wear
private static final String CAPABILITY_WEAR_APP = "wear_app_sync_bgs";
private static final String MESSAGE_PATH_WEAR = "/wear_message_path";
@Override
public void onCreate() {
AndroidInjection.inject(this);
if (wearIntegration()) {
googleApiConnect();
}
if (handler == null) {
HandlerThread handlerThread = new HandlerThread(this.getClass().getSimpleName() + "Handler");
handlerThread.start();
handler = new Handler(handlerThread.getLooper());
}
}
private boolean wearIntegration() {
return wearPlugin.isEnabled();
}
private void googleApiConnect() {
if (googleApiClient != null && (googleApiClient.isConnected() || googleApiClient.isConnecting())) {
googleApiClient.disconnect();
}
googleApiClient = new GoogleApiClient.Builder(this).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).addApi(Wearable.API).build();
Wearable.MessageApi.addListener(googleApiClient, this);
if (googleApiClient.isConnected()) {
aapsLogger.debug(LTag.WEAR, "API client is connected");
} else {
// Log.d("WatchUpdater", logPrefix + "API client is not connected and is trying to connect");
googleApiClient.connect();
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent != null ? intent.getAction() : null;
// Log.d(TAG, "onStartCommand: " + action);
if (wearIntegration()) {
handler.post(() -> {
if (googleApiClient != null && googleApiClient.isConnected()) {
if (ACTION_RESEND.equals(action)) {
resendData();
} else if (ACTION_OPEN_SETTINGS.equals(action)) {
sendNotification();
} else if (ACTION_SEND_STATUS.equals(action)) {
sendStatus();
} else if (ACTION_SEND_BASALS.equals(action)) {
sendBasals();
} else if (ACTION_SEND_BOLUSPROGRESS.equals(action)) {
sendBolusProgress(intent.getIntExtra("progresspercent", 0), intent.hasExtra("progressstatus") ? intent.getStringExtra("progressstatus") : "");
} else if (ACTION_SEND_ACTIONCONFIRMATIONREQUEST.equals(action)) {
String title = intent.getStringExtra("title");
String message = intent.getStringExtra("message");
String actionstring = intent.getStringExtra("actionstring");
sendActionConfirmationRequest(title, message, actionstring);
} else if (ACTION_SEND_CHANGECONFIRMATIONREQUEST.equals(action)) {
String title = intent.getStringExtra("title");
String message = intent.getStringExtra("message");
String actionstring = intent.getStringExtra("actionstring");
sendChangeConfirmationRequest(title, message, actionstring);
} else if (ACTION_CANCEL_NOTIFICATION.equals(action)) {
String actionstring = intent.getStringExtra("actionstring");
sendCancelNotificationRequest(actionstring);
} else {
sendData();
}
} else {
if (googleApiClient != null) googleApiClient.connect();
}
});
}
return START_STICKY;
}
private void updateWearSyncBgsCapability(CapabilityInfo capabilityInfo) {
Log.d("WatchUpdaterService", "CabilityInfo: " + capabilityInfo);
Set<Node> connectedNodes = capabilityInfo.getNodes();
String mWearNodeId = pickBestNodeId(connectedNodes);
}
private String pickBestNodeId(Set<Node> nodes) {
String bestNodeId = null;
// Find a nearby node or pick one arbitrarily
for (Node node : nodes) {
if (node.isNearby()) {
return node.getId();
}
bestNodeId = node.getId();
}
return bestNodeId;
}
@Override
public void onConnected(Bundle connectionHint) {
CapabilityApi.CapabilityListener capabilityListener = capabilityInfo -> {
updateWearSyncBgsCapability(capabilityInfo);
// Log.d(TAG, logPrefix + "onConnected onCapabilityChanged mWearNodeID:" + mWearNodeId);
// new CheckWearableConnected().execute();
};
Wearable.CapabilityApi.addCapabilityListener(googleApiClient, capabilityListener, CAPABILITY_WEAR_APP);
sendData();
}
@Override
public void onPeerConnected(com.google.android.gms.wearable.Node peer) {// KS
super.onPeerConnected(peer);
String id = peer.getId();
String name = peer.getDisplayName();
Log.d(TAG, "onPeerConnected peer name & ID: " + name + "|" + id);
}
@Override
public void onPeerDisconnected(com.google.android.gms.wearable.Node peer) {// KS
super.onPeerDisconnected(peer);
String id = peer.getId();
String name = peer.getDisplayName();
Log.d(TAG, "onPeerDisconnected peer name & ID: " + name + "|" + id);
}
@Override
public void onMessageReceived(MessageEvent event) {
// Log.d(TAG, "onMessageRecieved: " + event);
if (wearIntegration()) {
if (event != null && event.getPath().equals(WearUris.WEARABLE_RESEND_PATH)) {
resendData();
}
if (event != null && event.getPath().equals(WearUris.WEARABLE_CANCELBOLUS_PATH)) {
cancelBolus();
}
if (event != null && event.getPath().equals(WearUris.WEARABLE_INITIATE_ACTIONSTRING_PATH)) {
String actionstring = new String(event.getData());
aapsLogger.debug(LTag.WEAR, "Wear: " + actionstring);
rxBus.send(new EventWearInitiateAction(actionstring));
}
if (event != null && event.getPath().equals(WearUris.WEARABLE_CONFIRM_ACTIONSTRING_PATH)) {
String actionstring = new String(event.getData());
aapsLogger.debug(LTag.WEAR, "Wear Confirm: " + actionstring);
rxBus.send(new EventWearConfirmAction(actionstring));
}
}
}
private void cancelBolus() {
activePlugin.getActivePump().stopBolusDelivering();
}
private void sendData() {
GlucoseValue lastBG = iobCobCalculator.getAds().lastBg();
// Log.d(TAG, "LastBg=" + lastBG);
if (lastBG != null) {
GlucoseStatus glucoseStatus = glucoseStatusProvider.getGlucoseStatusData();
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
googleApiConnect();
}
if (wearIntegration()) {
final DataMap dataMap = dataMapSingleBG(lastBG, glucoseStatus);
(new SendToDataLayerThread(WearUris.WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, dataMap);
}
}
}
private DataMap dataMapSingleBG(GlucoseValue lastBG, GlucoseStatus glucoseStatus) {
GlucoseUnit units = profileFunction.getUnits();
double convert2MGDL = 1.0;
if (units.equals(GlucoseUnit.MMOL))
convert2MGDL = Constants.MMOLL_TO_MGDL;
double lowLine = defaultValueHelper.determineLowLine() * convert2MGDL;
double highLine = defaultValueHelper.determineHighLine() * convert2MGDL;
long sgvLevel = 0L;
if (lastBG.getValue() > highLine) {
sgvLevel = 1;
} else if (lastBG.getValue() < lowLine) {
sgvLevel = -1;
}
DataMap dataMap = new DataMap();
dataMap.putString("sgvString", GlucoseValueExtensionKt.valueToUnitsString(lastBG, units));
dataMap.putString("glucoseUnits", units.getAsText());
dataMap.putLong("timestamp", lastBG.getTimestamp());
if (glucoseStatus == null) {
dataMap.putString("slopeArrow", "");
dataMap.putString("delta", "--");
dataMap.putString("avgDelta", "--");
} else {
dataMap.putString("slopeArrow", trendCalculator.getTrendArrow(lastBG).getSymbol());
dataMap.putString("delta", deltastring(glucoseStatus.getDelta(), glucoseStatus.getDelta() * Constants.MGDL_TO_MMOLL, units));
dataMap.putString("avgDelta", deltastring(glucoseStatus.getShortAvgDelta(), glucoseStatus.getShortAvgDelta() * Constants.MGDL_TO_MMOLL, units));
}
dataMap.putLong("sgvLevel", sgvLevel);
dataMap.putDouble("sgvDouble", lastBG.getValue());
dataMap.putDouble("high", highLine);
dataMap.putDouble("low", lowLine);
return dataMap;
}
private String deltastring(double deltaMGDL, double deltaMMOL, GlucoseUnit units) {
String deltastring = "";
if (deltaMGDL >= 0) {
deltastring += "+";
} else {
deltastring += "-";
}
boolean detailed = sp.getBoolean(R.string.key_wear_detailed_delta, false);
if (units.equals(GlucoseUnit.MGDL)) {
if (detailed) {
deltastring += DecimalFormatter.INSTANCE.to1Decimal(Math.abs(deltaMGDL));
} else {
deltastring += DecimalFormatter.INSTANCE.to0Decimal(Math.abs(deltaMGDL));
}
} else {
if (detailed) {
deltastring += DecimalFormatter.INSTANCE.to2Decimal(Math.abs(deltaMMOL));
} else {
deltastring += DecimalFormatter.INSTANCE.to1Decimal(Math.abs(deltaMMOL));
}
}
return deltastring;
}
private void resendData() {
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
googleApiConnect();
}
sendPreferences();
sendQuickWizard();
long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5);
GlucoseValue last_bg = iobCobCalculator.getAds().lastBg();
if (last_bg == null) return;
List<GlucoseValue> graph_bgs = repository.compatGetBgReadingsDataFromTime(startTime, true).blockingGet();
GlucoseStatus glucoseStatus = glucoseStatusProvider.getGlucoseStatusData(true);
if (!graph_bgs.isEmpty()) {
DataMap entries = dataMapSingleBG(last_bg, glucoseStatus);
final ArrayList<DataMap> dataMaps = new ArrayList<>(graph_bgs.size());
for (GlucoseValue bg : graph_bgs) {
DataMap dataMap = dataMapSingleBG(bg, glucoseStatus);
dataMaps.add(dataMap);
}
entries.putDataMapArrayList("entries", dataMaps);
(new SendToDataLayerThread(WearUris.WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, entries);
}
sendBasals();
sendStatus();
}
private void sendBasals() {
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
googleApiConnect();
}
long now = System.currentTimeMillis();
final long startTimeWindow = now - (long) (60000 * 60 * 5.5);
ArrayList<DataMap> basals = new ArrayList<>();
ArrayList<DataMap> temps = new ArrayList<>();
ArrayList<DataMap> boluses = new ArrayList<>();
ArrayList<DataMap> predictions = new ArrayList<>();
Profile profile = profileFunction.getProfile();
if (profile == null) {
return;
}
long beginBasalSegmentTime = startTimeWindow;
long runningTime = startTimeWindow;
double beginBasalValue = profile.getBasal(beginBasalSegmentTime);
double endBasalValue = beginBasalValue;
TemporaryBasal tb1 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime);
TemporaryBasal tb2;
double tb_before = beginBasalValue;
double tb_amount = beginBasalValue;
long tb_start = runningTime;
if (tb1 != null) {
Profile profileTB = profileFunction.getProfile(runningTime);
if (profileTB != null) {
tb_amount = TemporaryBasalExtensionKt.convertedToAbsolute(tb1, runningTime, profileTB);
tb_start = runningTime;
}
}
for (; runningTime < now; runningTime += 5 * 60 * 1000) {
Profile profileTB = profileFunction.getProfile(runningTime);
if (profileTB == null)
return;
//basal rate
endBasalValue = profile.getBasal(runningTime);
if (endBasalValue != beginBasalValue) {
//push the segment we recently left
basals.add(basalMap(beginBasalSegmentTime, runningTime, beginBasalValue));
//begin new Basal segment
beginBasalSegmentTime = runningTime;
beginBasalValue = endBasalValue;
}
//temps
tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(runningTime);
if (tb1 == null && tb2 == null) {
; //no temp stays no temp
} else if (tb1 != null && tb2 == null) {
//temp is over -> push it
temps.add(tempDatamap(tb_start, tb_before, runningTime, endBasalValue, tb_amount));
tb1 = null;
} else if (tb1 == null && tb2 != null) {
//temp begins
tb1 = tb2;
tb_start = runningTime;
tb_before = endBasalValue;
tb_amount = TemporaryBasalExtensionKt.convertedToAbsolute(tb1, runningTime, profileTB);
} else if (tb1 != null && tb2 != null) {
double currentAmount = TemporaryBasalExtensionKt.convertedToAbsolute(tb2, runningTime, profileTB);
if (currentAmount != tb_amount) {
temps.add(tempDatamap(tb_start, tb_before, runningTime, currentAmount, tb_amount));
tb_start = runningTime;
tb_before = tb_amount;
tb_amount = currentAmount;
tb1 = tb2;
}
}
}
if (beginBasalSegmentTime != runningTime) {
//push the remaining segment
basals.add(basalMap(beginBasalSegmentTime, runningTime, beginBasalValue));
}
if (tb1 != null) {
tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(now); //use "now" to express current situation
if (tb2 == null) {
//express the cancelled temp by painting it down one minute early
temps.add(tempDatamap(tb_start, tb_before, now - 60 * 1000, endBasalValue, tb_amount));
} else {
//express currently running temp by painting it a bit into the future
Profile profileNow = profileFunction.getProfile(now);
double currentAmount = TemporaryBasalExtensionKt.convertedToAbsolute(tb2, now, profileNow);
if (currentAmount != tb_amount) {
temps.add(tempDatamap(tb_start, tb_before, now, tb_amount, tb_amount));
temps.add(tempDatamap(now, tb_amount, runningTime + 5 * 60 * 1000, currentAmount, currentAmount));
} else {
temps.add(tempDatamap(tb_start, tb_before, runningTime + 5 * 60 * 1000, tb_amount, tb_amount));
}
}
} else {
tb2 = iobCobCalculator.getTempBasalIncludingConvertedExtended(now); //use "now" to express current situation
if (tb2 != null) {
//onset at the end
Profile profileTB = profileFunction.getProfile(runningTime);
double currentAmount = TemporaryBasalExtensionKt.convertedToAbsolute(tb2, runningTime, profileTB);
temps.add(tempDatamap(now - 60 * 1000, endBasalValue, runningTime + 5 * 60 * 1000, currentAmount, currentAmount));
}
}
repository.getBolusesIncludingInvalidFromTime(startTimeWindow, true).blockingGet()
.stream()
.filter(bolus -> bolus.getType() != Bolus.Type.PRIMING)
.forEach(bolus -> boluses.add(treatmentMap(bolus.getTimestamp(), bolus.getAmount(), 0, bolus.getType() == Bolus.Type.SMB, bolus.isValid())));
repository.getCarbsDataFromTimeExpanded(startTimeWindow, true).blockingGet()
.forEach(carb -> boluses.add(treatmentMap(carb.getTimestamp(), 0, carb.getAmount(), false, carb.isValid())));
final LoopPlugin.LastRun finalLastRun = loop.getLastRun();
if (sp.getBoolean("wear_predictions", true) && finalLastRun != null && finalLastRun.getRequest().getHasPredictions() && finalLastRun.getConstraintsProcessed() != null) {
List<GlucoseValueDataPoint> predArray =
finalLastRun.getConstraintsProcessed().getPredictions()
.stream().map(bg -> new GlucoseValueDataPoint(bg, defaultValueHelper, profileFunction, rh))
.collect(Collectors.toList());
if (!predArray.isEmpty()) {
for (GlucoseValueDataPoint bg : predArray) {
if (bg.getData().getValue() < 40) continue;
predictions.add(predictionMap(bg.getData().getTimestamp(),
bg.getData().getValue(), bg.color(null)));
}
}
}
DataMap dm = new DataMap();
dm.putDataMapArrayList("basals", basals);
dm.putDataMapArrayList("temps", temps);
dm.putDataMapArrayList("boluses", boluses);
dm.putDataMapArrayList("predictions", predictions);
(new SendToDataLayerThread(WearUris.BASAL_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, dm);
}
private DataMap tempDatamap(long startTime, double startBasal, long to, double toBasal, double amount) {
DataMap dm = new DataMap();
dm.putLong("starttime", startTime);
dm.putDouble("startBasal", startBasal);
dm.putLong("endtime", to);
dm.putDouble("endbasal", toBasal);
dm.putDouble("amount", amount);
return dm;
}
private DataMap basalMap(long startTime, long endTime, double amount) {
DataMap dm = new DataMap();
dm.putLong("starttime", startTime);
dm.putLong("endtime", endTime);
dm.putDouble("amount", amount);
return dm;
}
private DataMap treatmentMap(long date, double bolus, double carbs, boolean isSMB, boolean isValid) {
DataMap dm = new DataMap();
dm.putLong("date", date);
dm.putDouble("bolus", bolus);
dm.putDouble("carbs", carbs);
dm.putBoolean("isSMB", isSMB);
dm.putBoolean("isValid", isValid);
return dm;
}
private DataMap predictionMap(long timestamp, double sgv, int color) {
DataMap dm = new DataMap();
dm.putLong("timestamp", timestamp);
dm.putDouble("sgv", sgv);
dm.putInt("color", color);
return dm;
}
private void sendNotification() {
if (googleApiClient != null && googleApiClient.isConnected()) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.OPEN_SETTINGS_PATH);
//unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putString("openSettings", "openSettings");
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("OpenSettings", "No connection to wearable available!");
}
}
private void sendBolusProgress(int progresspercent, String status) {
if (googleApiClient != null && googleApiClient.isConnected()) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.BOLUS_PROGRESS_PATH);
//unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putString("bolusProgress", "bolusProgress");
dataMapRequest.getDataMap().putString("progressstatus", status);
dataMapRequest.getDataMap().putInt("progresspercent", progresspercent);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("BolusProgress", "No connection to wearable available!");
}
}
private void sendActionConfirmationRequest(String title, String message, String actionstring) {
if (googleApiClient != null && googleApiClient.isConnected()) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.ACTION_CONFIRMATION_REQUEST_PATH);
//unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putString("actionConfirmationRequest", "actionConfirmationRequest");
dataMapRequest.getDataMap().putString("title", title);
dataMapRequest.getDataMap().putString("message", message);
dataMapRequest.getDataMap().putString("actionstring", actionstring);
aapsLogger.debug(LTag.WEAR, "Requesting confirmation from wear: " + actionstring);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("confirmationRequest", "No connection to wearable available!");
}
}
private void sendChangeConfirmationRequest(String title, String message, String actionstring) {
if (googleApiClient != null && googleApiClient.isConnected()) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.ACTION_CHANGECONFIRMATION_REQUEST_PATH);
//unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putString("changeConfirmationRequest", "changeConfirmationRequest");
dataMapRequest.getDataMap().putString("title", title);
dataMapRequest.getDataMap().putString("message", message);
dataMapRequest.getDataMap().putString("actionstring", actionstring);
aapsLogger.debug(LTag.WEAR, "Requesting confirmation from wear: " + actionstring);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("changeConfirmRequest", "No connection to wearable available!");
}
}
private void sendCancelNotificationRequest(String actionstring) {
if (googleApiClient != null && googleApiClient.isConnected()) {
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.ACTION_CANCELNOTIFICATION_REQUEST_PATH);
//unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putString("cancelNotificationRequest", "cancelNotificationRequest");
dataMapRequest.getDataMap().putString("actionstring", actionstring);
aapsLogger.debug(LTag.WEAR, "Canceling notification on wear: " + actionstring);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("cancelNotificationReq", "No connection to wearable available!");
}
}
private void sendStatus() {
if (googleApiClient != null && googleApiClient.isConnected()) {
Profile profile = profileFunction.getProfile();
String status = rh.gs(R.string.noprofile);
String iobSum, iobDetail, cobString, currentBasal, bgiString;
iobSum = iobDetail = cobString = currentBasal = bgiString = "";
if (profile != null) {
IobTotal bolusIob = iobCobCalculator.calculateIobFromBolus().round();
IobTotal basalIob = iobCobCalculator.calculateIobFromTempBasalsIncludingConvertedExtended().round();
iobSum = DecimalFormatter.INSTANCE.to2Decimal(bolusIob.getIob() + basalIob.getBasaliob());
iobDetail =
"(" + DecimalFormatter.INSTANCE.to2Decimal(bolusIob.getIob()) + "|" + DecimalFormatter.INSTANCE.to2Decimal(basalIob.getBasaliob()) + ")";
cobString = iobCobCalculator.getCobInfo(false, "WatcherUpdaterService").generateCOBString();
currentBasal = generateBasalString();
//bgi
double bgi =
-(bolusIob.getActivity() + basalIob.getActivity()) * 5 * Profile.Companion.fromMgdlToUnits(profile.getIsfMgdl(), profileFunction.getUnits());
bgiString = "" + ((bgi >= 0) ? "+" : "") + DecimalFormatter.INSTANCE.to1Decimal(bgi);
status = generateStatusString(profile, currentBasal, iobSum, iobDetail, bgiString);
}
//batteries
int phoneBattery = receiverStatusStore.getBatteryLevel();
String rigBattery = nsDeviceStatus.getUploaderStatus().trim();
long openApsStatus;
//OpenAPS status
if (config.getAPS()) {
//we are AndroidAPS
openApsStatus = loop.getLastRun() != null && loop.getLastRun().getLastTBREnact() != 0 ? loop.getLastRun().getLastTBREnact() : -1;
} else {
//NSClient or remote
openApsStatus = nsDeviceStatus.getOpenApsTimestamp();
}
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.NEW_STATUS_PATH);
//unique content
dataMapRequest.getDataMap().putString("externalStatusString", status);
dataMapRequest.getDataMap().putString("iobSum", iobSum);
dataMapRequest.getDataMap().putString("iobDetail", iobDetail);
dataMapRequest.getDataMap().putBoolean("detailedIob", sp.getBoolean(R.string.key_wear_detailediob, false));
dataMapRequest.getDataMap().putString("cob", cobString);
dataMapRequest.getDataMap().putString("currentBasal", currentBasal);
dataMapRequest.getDataMap().putString("battery", "" + phoneBattery);
dataMapRequest.getDataMap().putString("rigBattery", rigBattery);
dataMapRequest.getDataMap().putLong("openApsStatus", openApsStatus);
dataMapRequest.getDataMap().putString("bgi", bgiString);
dataMapRequest.getDataMap().putBoolean("showBgi", sp.getBoolean(R.string.key_wear_showbgi, false));
dataMapRequest.getDataMap().putInt("batteryLevel", (phoneBattery >= 30) ? 1 : 0);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("SendStatus", "No connection to wearable available!");
}
}
private void sendPreferences() {
if (googleApiClient != null && googleApiClient.isConnected()) {
GlucoseUnit units = profileFunction.getUnits();
boolean wearcontrol = sp.getBoolean(R.string.key_wear_control, false);
boolean mgdl = units.equals(GlucoseUnit.MGDL);
int percentage = sp.getInt(R.string.key_boluswizard_percentage, 100);
int maxCarbs = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48);
double maxBolus = sp.getDouble(R.string.key_treatmentssafety_maxbolus, 3.0);
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.NEW_PREFERENCES_PATH);
//unique content
dataMapRequest.getDataMap().putLong("timestamp", System.currentTimeMillis());
dataMapRequest.getDataMap().putBoolean(rh.gs(R.string.key_wear_control), wearcontrol);
dataMapRequest.getDataMap().putBoolean(rh.gs(R.string.key_units_mgdl), mgdl);
dataMapRequest.getDataMap().putInt(rh.gs(R.string.key_boluswizard_percentage), percentage);
dataMapRequest.getDataMap().putInt(rh.gs(R.string.key_treatmentssafety_maxcarbs), maxCarbs);
dataMapRequest.getDataMap().putDouble(rh.gs(R.string.key_treatmentssafety_maxbolus), maxBolus);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("SendPreferences", "No connection to wearable available!");
}
}
private void sendQuickWizard() {
if (googleApiClient != null && googleApiClient.isConnected()) {
int size = quickWizard.size();
ArrayList<DataMap> entities = new ArrayList<>();
for (int i = 0; i < size; i++) {
QuickWizardEntry q = quickWizard.get(i);
if (q.forDevice(QuickWizardEntry.DEVICE_WATCH)) {
entities.add(quickMap(q));
}
}
PutDataMapRequest dataMapRequest = PutDataMapRequest.create(WearUris.QUICK_WIZARD_PATH);
DataMap dm = dataMapRequest.getDataMap();
dm.putLong("timestamp", System.currentTimeMillis());
dm.putDataMapArrayList("quick_wizard", entities);
PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest();
Log.i(TAG, "sendQuickWizard: " + putDataRequest);
Wearable.DataApi.putDataItem(googleApiClient, putDataRequest);
} else {
Log.e("sendQuickWizard", "No connection to wearable available!");
}
}
private DataMap quickMap(QuickWizardEntry q) {
DataMap dm = new DataMap();
dm.putString("guid", q.guid());
dm.putString("button_text", q.buttonText());
dm.putInt("carbs", q.carbs());
dm.putInt("from", q.validFrom());
dm.putInt("to", q.validTo());
return dm;
}
@NonNull
private String generateStatusString(Profile profile, String currentBasal, String iobSum, String iobDetail, String bgiString) {
String status = "";
if (profile == null) {
status = rh.gs(R.string.noprofile);
return status;
}
if (!((PluginBase) loop).isEnabled()) {
status += rh.gs(R.string.disabledloop) + "\n";
lastLoopStatus = false;
} else {
lastLoopStatus = true;
}
String iobString;
if (sp.getBoolean(R.string.key_wear_detailediob, false)) {
iobString = iobSum + " " + iobDetail;
} else {
iobString = iobSum + "U";
}
status += currentBasal + " " + iobString;
//add BGI if shown, otherwise return
if (sp.getBoolean(R.string.key_wear_showbgi, false)) {
status += " " + bgiString;
}
return status;
}
@NonNull
private String generateBasalString() {
String basalStringResult;
Profile profile = profileFunction.getProfile();
if (profile == null)
return "";
TemporaryBasal activeTemp = iobCobCalculator.getTempBasalIncludingConvertedExtended(System.currentTimeMillis());
if (activeTemp != null) {
basalStringResult = TemporaryBasalExtensionKt.toStringShort(activeTemp);
} else {
basalStringResult = DecimalFormatter.INSTANCE.to2Decimal(profile.getBasal()) + "U/h";
}
return basalStringResult;
}
@Override
public void onDestroy() {
if (googleApiClient != null && googleApiClient.isConnected()) {
googleApiClient.disconnect();
}
}
@Override
public void onConnectionSuspended(int cause) {
}
@Override
public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
}
public static boolean shouldReportLoopStatus(boolean enabled) {
return (lastLoopStatus != enabled);
}
}

View file

@ -12,7 +12,7 @@ import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.DecimalFormatter
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.shared.sharedPreferences.SP
import io.reactivex.rxjava3.disposables.CompositeDisposable

View file

@ -8,7 +8,7 @@ import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.InsulinFragmentBinding
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.interfaces.ResourceHelper
import javax.inject.Inject
class InsulinFragment : DaggerFragment() {

Some files were not shown because too many files have changed in this diff Show more