Wear: ad quick wizard tile
This commit is contained in:
parent
2c7cf27047
commit
0233db8226
27 changed files with 790 additions and 499 deletions
|
@ -1,12 +1,18 @@
|
||||||
package info.nightscout.androidaps.plugins.general.overview.activities
|
package info.nightscout.androidaps.plugins.general.overview.activities
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
|
import android.widget.ImageView
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper.*
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
@ -20,6 +26,8 @@ import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||||
|
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
|
||||||
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -30,20 +38,95 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
||||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
@Inject lateinit var quickWizard: QuickWizard
|
@Inject lateinit var quickWizard: QuickWizard
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
|
||||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||||
|
|
||||||
private lateinit var binding: OverviewQuickwizardlistActivityBinding
|
private lateinit var binding: OverviewQuickwizardlistActivityBinding
|
||||||
|
|
||||||
|
private val itemTouchHelper by lazy {
|
||||||
|
val simpleItemTouchCallback = object : ItemTouchHelper.SimpleCallback(UP or DOWN or START or END, 0) {
|
||||||
|
|
||||||
|
override fun onMove(
|
||||||
|
recyclerView: RecyclerView,
|
||||||
|
viewHolder: RecyclerView.ViewHolder,
|
||||||
|
target: RecyclerView.ViewHolder
|
||||||
|
): Boolean {
|
||||||
|
val adapter = recyclerView.adapter as RecyclerViewAdapter
|
||||||
|
val from = viewHolder.layoutPosition
|
||||||
|
val to = target.layoutPosition
|
||||||
|
adapter.moveItem(from, to)
|
||||||
|
adapter.notifyItemMoved(from, to)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
|
||||||
|
super.onSelectedChanged(viewHolder, actionState)
|
||||||
|
|
||||||
|
if (actionState == ACTION_STATE_DRAG) {
|
||||||
|
viewHolder?.itemView?.alpha = 0.5f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
|
||||||
|
super.clearView(recyclerView, viewHolder)
|
||||||
|
|
||||||
|
viewHolder.itemView.alpha = 1.0f
|
||||||
|
|
||||||
|
val adapter = recyclerView.adapter as RecyclerViewAdapter
|
||||||
|
adapter.onDrop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemTouchHelper(simpleItemTouchCallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startDragging(viewHolder: RecyclerView.ViewHolder) {
|
||||||
|
itemTouchHelper.startDrag(viewHolder)
|
||||||
|
}
|
||||||
|
|
||||||
private inner class RecyclerViewAdapter(var fragmentManager: FragmentManager) : RecyclerView.Adapter<RecyclerViewAdapter.QuickWizardEntryViewHolder>() {
|
private inner class RecyclerViewAdapter(var fragmentManager: FragmentManager) : RecyclerView.Adapter<RecyclerViewAdapter.QuickWizardEntryViewHolder>() {
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuickWizardEntryViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QuickWizardEntryViewHolder {
|
||||||
return QuickWizardEntryViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.overview_quickwizardlist_item, parent, false), fragmentManager)
|
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.overview_quickwizardlist_item, parent, false)
|
||||||
|
val viewHolder = QuickWizardEntryViewHolder(itemView, fragmentManager)
|
||||||
|
|
||||||
|
viewHolder.handleView.setOnTouchListener { _, event ->
|
||||||
|
if (event.actionMasked == MotionEvent.ACTION_DOWN) {
|
||||||
|
startDragging(viewHolder)
|
||||||
|
}
|
||||||
|
return@setOnTouchListener true
|
||||||
|
}
|
||||||
|
|
||||||
|
return viewHolder
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: QuickWizardEntryViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: QuickWizardEntryViewHolder, position: Int) {
|
||||||
holder.from.text = dateUtil.timeString(quickWizard[position].validFromDate())
|
holder.from.text = dateUtil.timeString(quickWizard[position].validFromDate())
|
||||||
holder.to.text = dateUtil.timeString(quickWizard[position].validToDate())
|
holder.to.text = dateUtil.timeString(quickWizard[position].validToDate())
|
||||||
|
val wearControl = sp.getBoolean(R.string.key_wear_control, false)
|
||||||
|
|
||||||
|
if (wearControl) {
|
||||||
|
holder.handleView.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
holder.handleView.visibility = View.GONE
|
||||||
|
}
|
||||||
|
if (quickWizard[position].device() == QuickWizardEntry.DEVICE_ALL) {
|
||||||
|
holder.device.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
holder.device.visibility = View.VISIBLE
|
||||||
|
holder.device.setImageResource(
|
||||||
|
when (quickWizard[position].device()) {
|
||||||
|
QuickWizardEntry.DEVICE_WATCH -> R.drawable.ic_watch
|
||||||
|
else -> R.drawable.ic_smartphone
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
holder.buttonText.text = quickWizard[position].buttonText()
|
holder.buttonText.text = quickWizard[position].buttonText()
|
||||||
holder.carbs.text = rh.gs(R.string.format_carbs, quickWizard[position].carbs())
|
holder.carbs.text = rh.gs(R.string.format_carbs, quickWizard[position].carbs())
|
||||||
}
|
}
|
||||||
|
@ -55,6 +138,8 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
||||||
val buttonText: TextView = itemView.findViewById(R.id.overview_quickwizard_item_buttonText)
|
val buttonText: TextView = itemView.findViewById(R.id.overview_quickwizard_item_buttonText)
|
||||||
val carbs: TextView = itemView.findViewById(R.id.overview_quickwizard_item_carbs)
|
val carbs: TextView = itemView.findViewById(R.id.overview_quickwizard_item_carbs)
|
||||||
val from: TextView = itemView.findViewById(R.id.overview_quickwizard_item_from)
|
val from: TextView = itemView.findViewById(R.id.overview_quickwizard_item_from)
|
||||||
|
val handleView: ImageView = itemView.findViewById(R.id.handleView)
|
||||||
|
val device: ImageView = itemView.findViewById(R.id.overview_quickwizard_item_device)
|
||||||
val to: TextView = itemView.findViewById(R.id.overview_quickwizard_item_to)
|
val to: TextView = itemView.findViewById(R.id.overview_quickwizard_item_to)
|
||||||
private val editButton: Button = itemView.findViewById(R.id.overview_quickwizard_item_edit_button)
|
private val editButton: Button = itemView.findViewById(R.id.overview_quickwizard_item_edit_button)
|
||||||
private val removeButton: Button = itemView.findViewById(R.id.overview_quickwizard_item_remove_button)
|
private val removeButton: Button = itemView.findViewById(R.id.overview_quickwizard_item_remove_button)
|
||||||
|
@ -74,6 +159,16 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun moveItem(from: Int, to: Int) {
|
||||||
|
Log.i("QuickWizard", "moveItem")
|
||||||
|
quickWizard.move(from, to)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onDrop() {
|
||||||
|
Log.i("QuickWizard", "onDrop")
|
||||||
|
rxBus.send(EventQuickWizardChange())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
@ -84,6 +179,7 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
||||||
binding.recyclerview.setHasFixedSize(true)
|
binding.recyclerview.setHasFixedSize(true)
|
||||||
binding.recyclerview.layoutManager = LinearLayoutManager(this)
|
binding.recyclerview.layoutManager = LinearLayoutManager(this)
|
||||||
binding.recyclerview.adapter = RecyclerViewAdapter(supportFragmentManager)
|
binding.recyclerview.adapter = RecyclerViewAdapter(supportFragmentManager)
|
||||||
|
itemTouchHelper.attachToRecyclerView(binding.recyclerview)
|
||||||
|
|
||||||
binding.addButton.setOnClickListener {
|
binding.addButton.setOnClickListener {
|
||||||
val manager = supportFragmentManager
|
val manager = supportFragmentManager
|
||||||
|
@ -98,9 +194,9 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
||||||
.toObservable(EventQuickWizardChange::class.java)
|
.toObservable(EventQuickWizardChange::class.java)
|
||||||
.observeOn(aapsSchedulers.main)
|
.observeOn(aapsSchedulers.main)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
val adapter = RecyclerViewAdapter(supportFragmentManager)
|
val adapter = RecyclerViewAdapter(supportFragmentManager)
|
||||||
binding.recyclerview.swapAdapter(adapter, false)
|
binding.recyclerview.swapAdapter(adapter, false)
|
||||||
}, fabricPrivacy::logException)
|
}, fabricPrivacy::logException)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import android.view.ViewGroup
|
||||||
import android.view.Window
|
import android.view.Window
|
||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import dagger.android.support.DaggerDialogFragment
|
import dagger.android.support.DaggerDialogFragment
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.databinding.OverviewEditquickwizardDialogBinding
|
import info.nightscout.androidaps.databinding.OverviewEditquickwizardDialogBinding
|
||||||
import info.nightscout.shared.logging.AAPSLogger
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
@ -21,6 +22,7 @@ import info.nightscout.androidaps.utils.extensions.setEnableForChildren
|
||||||
import info.nightscout.androidaps.utils.extensions.setSelection
|
import info.nightscout.androidaps.utils.extensions.setSelection
|
||||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||||
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
|
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
|
||||||
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ -30,6 +32,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
@Inject lateinit var quickWizard: QuickWizard
|
@Inject lateinit var quickWizard: QuickWizard
|
||||||
@Inject lateinit var dateUtil: DateUtil
|
@Inject lateinit var dateUtil: DateUtil
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
|
||||||
var position = -1
|
var position = -1
|
||||||
|
|
||||||
|
@ -57,6 +60,14 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
||||||
position = bundle.getInt("position", -1)
|
position = bundle.getInt("position", -1)
|
||||||
}
|
}
|
||||||
val entry = if (position == -1) quickWizard.newEmptyItem() else quickWizard[position]
|
val entry = if (position == -1) quickWizard.newEmptyItem() else quickWizard[position]
|
||||||
|
if (sp.getBoolean(R.string.key_wear_control, false)) {
|
||||||
|
binding.deviceLabel.visibility = View.VISIBLE
|
||||||
|
binding.device.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
binding.deviceLabel.visibility = View.GONE
|
||||||
|
binding.device.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
binding.okcancel.ok.setOnClickListener {
|
binding.okcancel.ok.setOnClickListener {
|
||||||
try {
|
try {
|
||||||
entry.storage.put("buttonText", binding.buttonEdit.text.toString())
|
entry.storage.put("buttonText", binding.buttonEdit.text.toString())
|
||||||
|
@ -66,6 +77,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
||||||
entry.storage.put("useBG", binding.useBg.selectedItemPosition)
|
entry.storage.put("useBG", binding.useBg.selectedItemPosition)
|
||||||
entry.storage.put("useCOB", binding.useCob.selectedItemPosition)
|
entry.storage.put("useCOB", binding.useCob.selectedItemPosition)
|
||||||
entry.storage.put("useBolusIOB", binding.useBolusIob.selectedItemPosition)
|
entry.storage.put("useBolusIOB", binding.useBolusIob.selectedItemPosition)
|
||||||
|
entry.storage.put("device", binding.device.selectedItemPosition)
|
||||||
entry.storage.put("useBasalIOB", binding.useBasalIob.selectedItemPosition)
|
entry.storage.put("useBasalIOB", binding.useBasalIob.selectedItemPosition)
|
||||||
entry.storage.put("useTrend", binding.useTrend.selectedItemPosition)
|
entry.storage.put("useTrend", binding.useTrend.selectedItemPosition)
|
||||||
entry.storage.put("useSuperBolus", binding.useSuperBolus.selectedItemPosition)
|
entry.storage.put("useSuperBolus", binding.useSuperBolus.selectedItemPosition)
|
||||||
|
@ -122,6 +134,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
||||||
binding.useCob.setSelection(entry.useCOB())
|
binding.useCob.setSelection(entry.useCOB())
|
||||||
binding.useBolusIob.setSelection(entry.useBolusIOB())
|
binding.useBolusIob.setSelection(entry.useBolusIOB())
|
||||||
binding.useBasalIob.setSelection(entry.useBasalIOB())
|
binding.useBasalIob.setSelection(entry.useBasalIOB())
|
||||||
|
binding.device.setSelection(entry.device())
|
||||||
binding.useTrend.setSelection(entry.useTrend())
|
binding.useTrend.setSelection(entry.useTrend())
|
||||||
binding.useSuperBolus.setSelection(entry.useSuperBolus())
|
binding.useSuperBolus.setSelection(entry.useSuperBolus())
|
||||||
binding.useTempTarget.setSelection(entry.useTempTarget())
|
binding.useTempTarget.setSelection(entry.useTempTarget())
|
||||||
|
|
|
@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.general.wear
|
||||||
|
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.util.Log
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.Constants
|
import info.nightscout.androidaps.Constants
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
@ -39,6 +40,7 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
||||||
|
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||||
import info.nightscout.shared.SafeParse
|
import info.nightscout.shared.SafeParse
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxkotlin.plusAssign
|
import io.reactivex.rxkotlin.plusAssign
|
||||||
|
@ -71,6 +73,7 @@ class ActionStringHandler @Inject constructor(
|
||||||
private val activePlugin: ActivePlugin,
|
private val activePlugin: ActivePlugin,
|
||||||
private val iobCobCalculator: IobCobCalculator,
|
private val iobCobCalculator: IobCobCalculator,
|
||||||
private val localInsightPlugin: LocalInsightPlugin,
|
private val localInsightPlugin: LocalInsightPlugin,
|
||||||
|
private val quickWizard: QuickWizard,
|
||||||
private val danaRPlugin: DanaRPlugin,
|
private val danaRPlugin: DanaRPlugin,
|
||||||
private val danaRKoreanPlugin: DanaRKoreanPlugin,
|
private val danaRKoreanPlugin: DanaRKoreanPlugin,
|
||||||
private val danaRv2Plugin: DanaRv2Plugin,
|
private val danaRv2Plugin: DanaRv2Plugin,
|
||||||
|
@ -144,34 +147,39 @@ class ActionStringHandler @Inject constructor(
|
||||||
}
|
}
|
||||||
rAction += "bolus $insulinAfterConstraints $carbsAfterConstraints"
|
rAction += "bolus $insulinAfterConstraints $carbsAfterConstraints"
|
||||||
} else if ("temptarget" == act[0]) { ///////////////////////////////////////////////////////// TEMPTARGET
|
} else if ("temptarget" == act[0]) { ///////////////////////////////////////////////////////// TEMPTARGET
|
||||||
aapsLogger.info(LTag.WEAR, "temptarget received:" + act)
|
aapsLogger.info(LTag.WEAR, "temptarget received: $act")
|
||||||
if ("cancel" == act[1]) {
|
if ("cancel" == act[1]) {
|
||||||
rMessage += rh.gs(R.string.wear_action_tempt_cancel_message)
|
rMessage += rh.gs(R.string.wear_action_tempt_cancel_message)
|
||||||
rAction = "temptarget true 0 0 0"
|
rAction = "temptarget true 0 0 0"
|
||||||
} else if ("preset" == act[1]) {
|
} else if ("preset" == act[1]) {
|
||||||
val presetIsMGDL = profileFunction.getUnits() == GlucoseUnit.MGDL
|
val presetIsMGDL = profileFunction.getUnits() == GlucoseUnit.MGDL
|
||||||
val preset = act[2]
|
val preset = act[2]
|
||||||
if ("activity" == preset) {
|
when (preset) {
|
||||||
val activityTTDuration = defaultValueHelper.determineActivityTTDuration()
|
"activity" -> {
|
||||||
val activityTT = defaultValueHelper.determineActivityTT()
|
val activityTTDuration = defaultValueHelper.determineActivityTTDuration()
|
||||||
val reason = rh.gs(R.string.activity)
|
val activityTT = defaultValueHelper.determineActivityTT()
|
||||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, activityTT, activityTTDuration)
|
val reason = rh.gs(R.string.activity)
|
||||||
rAction = "temptarget $presetIsMGDL $activityTTDuration $activityTT $activityTT"
|
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, activityTT, activityTTDuration)
|
||||||
} else if ("hypo" == preset) {
|
rAction = "temptarget $presetIsMGDL $activityTTDuration $activityTT $activityTT"
|
||||||
val hypoTTDuration = defaultValueHelper.determineHypoTTDuration()
|
}
|
||||||
val hypoTT = defaultValueHelper.determineHypoTT()
|
"hypo" -> {
|
||||||
val reason = rh.gs(R.string.hypo)
|
val hypoTTDuration = defaultValueHelper.determineHypoTTDuration()
|
||||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, hypoTT, hypoTTDuration)
|
val hypoTT = defaultValueHelper.determineHypoTT()
|
||||||
rAction = "temptarget $presetIsMGDL $hypoTTDuration $hypoTT $hypoTT"
|
val reason = rh.gs(R.string.hypo)
|
||||||
} else if ("eating" == preset) {
|
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, hypoTT, hypoTTDuration)
|
||||||
val eatingSoonTTDuration = defaultValueHelper.determineEatingSoonTTDuration()
|
rAction = "temptarget $presetIsMGDL $hypoTTDuration $hypoTT $hypoTT"
|
||||||
val eatingSoonTT = defaultValueHelper.determineEatingSoonTT()
|
}
|
||||||
val reason = rh.gs(R.string.eatingsoon)
|
"eating" -> {
|
||||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, eatingSoonTT, eatingSoonTTDuration)
|
val eatingSoonTTDuration = defaultValueHelper.determineEatingSoonTTDuration()
|
||||||
rAction = "temptarget $presetIsMGDL $eatingSoonTTDuration $eatingSoonTT $eatingSoonTT"
|
val eatingSoonTT = defaultValueHelper.determineEatingSoonTT()
|
||||||
} else {
|
val reason = rh.gs(R.string.eatingsoon)
|
||||||
sendError(rh.gs(R.string.wear_action_tempt_preset_error, preset))
|
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, eatingSoonTT, eatingSoonTTDuration)
|
||||||
return
|
rAction = "temptarget $presetIsMGDL $eatingSoonTTDuration $eatingSoonTT $eatingSoonTT"
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
sendError(rh.gs(R.string.wear_action_tempt_preset_error, preset))
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val isMGDL = java.lang.Boolean.parseBoolean(act[1])
|
val isMGDL = java.lang.Boolean.parseBoolean(act[1])
|
||||||
|
@ -281,6 +289,34 @@ class ActionStringHandler @Inject constructor(
|
||||||
rMessage += "\nPercentage: " + format.format(bolusWizard.totalBeforePercentageAdjustment) + "U * " + percentage + "% -> ~" + format.format(bolusWizard.calculatedTotalInsulin) + "U"
|
rMessage += "\nPercentage: " + format.format(bolusWizard.totalBeforePercentageAdjustment) + "U * " + percentage + "% -> ~" + format.format(bolusWizard.calculatedTotalInsulin) + "U"
|
||||||
}
|
}
|
||||||
lastBolusWizard = bolusWizard
|
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 pump = activePlugin.activePump
|
||||||
|
val quickWizardEntry = quickWizard.get(guid)
|
||||||
|
Log.i("QuickWizard", "handleInitiate: quick_wizard " + quickWizardEntry?.buttonText() + " c "+ quickWizardEntry?.carbs())
|
||||||
|
if (quickWizardEntry != null && actualBg != null && profile != null) {
|
||||||
|
// Logic related from Overview.kt
|
||||||
|
val wizard = quickWizardEntry.doCalc(profile, profileName, actualBg, true)
|
||||||
|
if (wizard.calculatedTotalInsulin > 0.0 && quickWizardEntry.carbs() > 0.0) {
|
||||||
|
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(quickWizardEntry.carbs())).value()
|
||||||
|
val insulinAfterConstraints = wizard.insulinAfterConstraints
|
||||||
|
if (abs(insulinAfterConstraints - wizard.calculatedTotalInsulin) >= pump.pumpDescription.pumpType.determineCorrectBolusStepSize(insulinAfterConstraints) || carbsAfterConstraints != quickWizardEntry.carbs()) {
|
||||||
|
// TODO check error is correct
|
||||||
|
sendError(rh.gs(R.string.constraints_violation) + "\n" + rh.gs(R.string.changeyourinput))
|
||||||
|
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")
|
||||||
|
} else {
|
||||||
|
sendError(rh.gs(R.string.quick_wizard_no_action))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendError(rh.gs(R.string.quick_wizard_can_not_calculate))
|
||||||
|
}
|
||||||
} else if ("opencpp" == act[0]) {
|
} else if ("opencpp" == act[0]) {
|
||||||
val activeProfileSwitch = repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet()
|
val activeProfileSwitch = repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet()
|
||||||
if (activeProfileSwitch is ValueWrapper.Existing) { // read CPP values
|
if (activeProfileSwitch is ValueWrapper.Existing) { // read CPP values
|
||||||
|
@ -364,7 +400,10 @@ class ActionStringHandler @Inject constructor(
|
||||||
rAction = "cancelChangeRequest"
|
rAction = "cancelChangeRequest"
|
||||||
wearPlugin.requestNotificationCancel(rAction)
|
wearPlugin.requestNotificationCancel(rAction)
|
||||||
return
|
return
|
||||||
} else return
|
} else {
|
||||||
|
sendError("Unknown action command: " + act[0] )
|
||||||
|
return
|
||||||
|
}
|
||||||
// send result
|
// send result
|
||||||
wearPlugin.requestActionConfirmation(rTitle, rMessage, rAction)
|
wearPlugin.requestActionConfirmation(rTitle, rMessage, rAction)
|
||||||
lastSentTimestamp = System.currentTimeMillis()
|
lastSentTimestamp = System.currentTimeMillis()
|
||||||
|
|
|
@ -46,6 +46,7 @@ import info.nightscout.androidaps.interfaces.Loop;
|
||||||
import info.nightscout.androidaps.interfaces.PluginBase;
|
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||||
import info.nightscout.androidaps.interfaces.Profile;
|
import info.nightscout.androidaps.interfaces.Profile;
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||||
|
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry;
|
||||||
import info.nightscout.shared.logging.AAPSLogger;
|
import info.nightscout.shared.logging.AAPSLogger;
|
||||||
import info.nightscout.shared.logging.LTag;
|
import info.nightscout.shared.logging.LTag;
|
||||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||||
|
@ -62,6 +63,7 @@ import info.nightscout.androidaps.utils.DecimalFormatter;
|
||||||
import info.nightscout.androidaps.utils.DefaultValueHelper;
|
import info.nightscout.androidaps.utils.DefaultValueHelper;
|
||||||
import info.nightscout.androidaps.utils.TrendCalculator;
|
import info.nightscout.androidaps.utils.TrendCalculator;
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||||
|
import info.nightscout.androidaps.utils.wizard.QuickWizard;
|
||||||
import info.nightscout.shared.sharedPreferences.SP;
|
import info.nightscout.shared.sharedPreferences.SP;
|
||||||
|
|
||||||
public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
public class WatchUpdaterService extends WearableListenerService implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
|
||||||
|
@ -81,6 +83,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
@Inject ReceiverStatusStore receiverStatusStore;
|
@Inject ReceiverStatusStore receiverStatusStore;
|
||||||
@Inject Config config;
|
@Inject Config config;
|
||||||
@Inject public TrendCalculator trendCalculator;
|
@Inject public TrendCalculator trendCalculator;
|
||||||
|
@Inject public QuickWizard quickWizard;
|
||||||
|
|
||||||
public static final String ACTION_RESEND = WatchUpdaterService.class.getName().concat(".Resend");
|
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_OPEN_SETTINGS = WatchUpdaterService.class.getName().concat(".OpenSettings");
|
||||||
|
@ -101,12 +104,14 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
private static final String OPEN_SETTINGS_PATH = "/openwearsettings";
|
private static final String OPEN_SETTINGS_PATH = "/openwearsettings";
|
||||||
private static final String NEW_STATUS_PATH = "/sendstatustowear";
|
private static final String NEW_STATUS_PATH = "/sendstatustowear";
|
||||||
private static final String NEW_PREFERENCES_PATH = "/sendpreferencestowear";
|
private static final String NEW_PREFERENCES_PATH = "/sendpreferencestowear";
|
||||||
|
private static final String QUICK_WIZARD_PATH = "/send_quick_wizard";
|
||||||
public static final String BASAL_DATA_PATH = "/nightscout_watch_basal";
|
public static final String BASAL_DATA_PATH = "/nightscout_watch_basal";
|
||||||
public static final String BOLUS_PROGRESS_PATH = "/nightscout_watch_bolusprogress";
|
public static final String BOLUS_PROGRESS_PATH = "/nightscout_watch_bolusprogress";
|
||||||
public static final String ACTION_CONFIRMATION_REQUEST_PATH = "/nightscout_watch_actionconfirmationrequest";
|
public static final String ACTION_CONFIRMATION_REQUEST_PATH = "/nightscout_watch_actionconfirmationrequest";
|
||||||
public static final String ACTION_CHANGECONFIRMATION_REQUEST_PATH = "/nightscout_watch_changeconfirmationrequest";
|
public static final String ACTION_CHANGECONFIRMATION_REQUEST_PATH = "/nightscout_watch_changeconfirmationrequest";
|
||||||
public static final String ACTION_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest";
|
public static final String ACTION_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest";
|
||||||
|
|
||||||
|
String TAG = "WatchUpdateService";
|
||||||
|
|
||||||
private static boolean lastLoopStatus;
|
private static boolean lastLoopStatus;
|
||||||
|
|
||||||
|
@ -156,7 +161,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
String action = intent != null ? intent.getAction() : null;
|
String action = intent != null ? intent.getAction() : null;
|
||||||
|
|
||||||
// Log.d(TAG, logPrefix + "onStartCommand: " + action);
|
// Log.d(TAG, "onStartCommand: " + action);
|
||||||
|
|
||||||
if (wearIntegration()) {
|
if (wearIntegration()) {
|
||||||
handler.post(() -> {
|
handler.post(() -> {
|
||||||
|
@ -235,7 +240,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
super.onPeerConnected(peer);
|
super.onPeerConnected(peer);
|
||||||
String id = peer.getId();
|
String id = peer.getId();
|
||||||
String name = peer.getDisplayName();
|
String name = peer.getDisplayName();
|
||||||
// Log.d(TAG, logPrefix + "onPeerConnected peer name & ID: " + name + "|" + id);
|
Log.d(TAG, "onPeerConnected peer name & ID: " + name + "|" + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -244,14 +249,14 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
super.onPeerDisconnected(peer);
|
super.onPeerDisconnected(peer);
|
||||||
String id = peer.getId();
|
String id = peer.getId();
|
||||||
String name = peer.getDisplayName();
|
String name = peer.getDisplayName();
|
||||||
// Log.d(TAG, logPrefix + "onPeerDisconnected peer name & ID: " + name + "|" + id);
|
Log.d(TAG, "onPeerDisconnected peer name & ID: " + name + "|" + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessageReceived(MessageEvent event) {
|
public void onMessageReceived(MessageEvent event) {
|
||||||
|
|
||||||
// Log.d(TAG, logPrefix + "onMessageRecieved: " + event);
|
// Log.d(TAG, "onMessageRecieved: " + event);
|
||||||
|
|
||||||
if (wearIntegration()) {
|
if (wearIntegration()) {
|
||||||
if (event != null && event.getPath().equals(WEARABLE_RESEND_PATH)) {
|
if (event != null && event.getPath().equals(WEARABLE_RESEND_PATH)) {
|
||||||
|
@ -283,7 +288,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
private void sendData() {
|
private void sendData() {
|
||||||
|
|
||||||
GlucoseValue lastBG = iobCobCalculator.getAds().lastBg();
|
GlucoseValue lastBG = iobCobCalculator.getAds().lastBg();
|
||||||
// Log.d(TAG, logPrefix + "LastBg=" + lastBG);
|
// Log.d(TAG, "LastBg=" + lastBG);
|
||||||
if (lastBG != null) {
|
if (lastBG != null) {
|
||||||
GlucoseStatus glucoseStatus = glucoseStatusProvider.getGlucoseStatusData();
|
GlucoseStatus glucoseStatus = glucoseStatusProvider.getGlucoseStatusData();
|
||||||
|
|
||||||
|
@ -364,6 +369,10 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
|
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
|
||||||
googleApiConnect();
|
googleApiConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sendPreferences();
|
||||||
|
sendQuickWizard();
|
||||||
|
|
||||||
long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5);
|
long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5);
|
||||||
GlucoseValue last_bg = iobCobCalculator.getAds().lastBg();
|
GlucoseValue last_bg = iobCobCalculator.getAds().lastBg();
|
||||||
|
|
||||||
|
@ -382,7 +391,6 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
entries.putDataMapArrayList("entries", dataMaps);
|
entries.putDataMapArrayList("entries", dataMaps);
|
||||||
(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, entries);
|
(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, entries);
|
||||||
}
|
}
|
||||||
sendPreferences();
|
|
||||||
sendBasals();
|
sendBasals();
|
||||||
sendStatus();
|
sendStatus();
|
||||||
}
|
}
|
||||||
|
@ -738,6 +746,41 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(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
|
@NonNull
|
||||||
private String generateStatusString(Profile profile, String currentBasal, String iobSum, String iobDetail, String bgiString) {
|
private String generateStatusString(Profile profile, String currentBasal, String iobSum, String iobDetail, String bgiString) {
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package info.nightscout.androidaps.utils.wizard
|
package info.nightscout.androidaps.utils.wizard
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
import dagger.android.HasAndroidInjector
|
import dagger.android.HasAndroidInjector
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@ -18,6 +20,18 @@ class QuickWizard @Inject constructor(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
setData(JSONArray(sp.getString(R.string.key_quickwizard, "[]")))
|
setData(JSONArray(sp.getString(R.string.key_quickwizard, "[]")))
|
||||||
|
setGuidsForOldEntries()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setGuidsForOldEntries() {
|
||||||
|
// for migration purposes; guid is a new required property
|
||||||
|
for (i in 0 until storage.length()) {
|
||||||
|
val entry = QuickWizardEntry(injector).from(storage.get(i) as JSONObject, i)
|
||||||
|
if (entry.guid() == "") {
|
||||||
|
val guid = UUID.randomUUID().toString()
|
||||||
|
entry.storage.put("guid", guid)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getActive(): QuickWizardEntry? {
|
fun getActive(): QuickWizardEntry? {
|
||||||
|
@ -41,6 +55,38 @@ class QuickWizard @Inject constructor(
|
||||||
operator fun get(position: Int): QuickWizardEntry =
|
operator fun get(position: Int): QuickWizardEntry =
|
||||||
QuickWizardEntry(injector).from(storage.get(position) as JSONObject, position)
|
QuickWizardEntry(injector).from(storage.get(position) as JSONObject, position)
|
||||||
|
|
||||||
|
fun get(guid: String): QuickWizardEntry? {
|
||||||
|
for (i in 0 until storage.length()) {
|
||||||
|
val entry = QuickWizardEntry(injector).from(storage.get(i) as JSONObject, i)
|
||||||
|
if (entry.guid() == guid) {
|
||||||
|
return entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun move(from: Int, to: Int) {
|
||||||
|
Log.i("QuickWizard", "moveItem: $from $to")
|
||||||
|
val fromEntry = storage[from] as JSONObject
|
||||||
|
storage.remove(from)
|
||||||
|
addToPos(to, fromEntry, storage)
|
||||||
|
save()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun removePos(pos: Int, jsonObj: JSONObject?, jsonArr: JSONArray) {
|
||||||
|
for (i in jsonArr.length() downTo pos + 1) {
|
||||||
|
jsonArr.put(i, jsonArr[i - 1])
|
||||||
|
}
|
||||||
|
jsonArr.put(pos, jsonObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addToPos(pos: Int, jsonObj: JSONObject?, jsonArr: JSONArray) {
|
||||||
|
for (i in jsonArr.length() downTo pos + 1) {
|
||||||
|
jsonArr.put(i, jsonArr[i - 1])
|
||||||
|
}
|
||||||
|
jsonArr.put(pos, jsonObj)
|
||||||
|
}
|
||||||
|
|
||||||
fun newEmptyItem(): QuickWizardEntry {
|
fun newEmptyItem(): QuickWizardEntry {
|
||||||
return QuickWizardEntry(injector)
|
return QuickWizardEntry(injector)
|
||||||
}
|
}
|
||||||
|
@ -57,4 +103,5 @@ class QuickWizard @Inject constructor(
|
||||||
storage.remove(position)
|
storage.remove(position)
|
||||||
save()
|
save()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import info.nightscout.androidaps.utils.JsonHelper.safeGetString
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import java.util.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjector) {
|
class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjector) {
|
||||||
|
@ -41,11 +42,15 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
|
||||||
const val NO = 1
|
const val NO = 1
|
||||||
private const val POSITIVE_ONLY = 2
|
private const val POSITIVE_ONLY = 2
|
||||||
private const val NEGATIVE_ONLY = 3
|
private const val NEGATIVE_ONLY = 3
|
||||||
|
const val DEVICE_ALL = 0
|
||||||
|
const val DEVICE_PHONE = 1
|
||||||
|
const val DEVICE_WATCH = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
injector.androidInjector().inject(this)
|
injector.androidInjector().inject(this)
|
||||||
val emptyData = "{\"buttonText\":\"\",\"carbs\":0,\"validFrom\":0,\"validTo\":86340}"
|
val guid = UUID.randomUUID().toString()
|
||||||
|
val emptyData = "{\"guid\": \"$guid\",\"buttonText\":\"\",\"carbs\":0,\"validFrom\":0,\"validTo\":86340, \"device\": \"all\"}"
|
||||||
try {
|
try {
|
||||||
storage = JSONObject(emptyData)
|
storage = JSONObject(emptyData)
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
|
@ -55,6 +60,8 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
|
||||||
|
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
|
guid: string,
|
||||||
|
device: string, // (phone, watch, all)
|
||||||
buttonText: "Meal",
|
buttonText: "Meal",
|
||||||
carbs: 36,
|
carbs: 36,
|
||||||
validFrom: 8 * 60 * 60, // seconds from midnight
|
validFrom: 8 * 60 * 60, // seconds from midnight
|
||||||
|
@ -69,12 +76,13 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
fun from(entry: JSONObject, position: Int): QuickWizardEntry {
|
fun from(entry: JSONObject, position: Int): QuickWizardEntry {
|
||||||
|
// TODO set guid if missing for migration
|
||||||
storage = entry
|
storage = entry
|
||||||
this.position = position
|
this.position = position
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isActive(): Boolean = profileFunction.secondsFromMidnight() >= validFrom() && profileFunction.secondsFromMidnight() <= validTo()
|
fun isActive(): Boolean = profileFunction.secondsFromMidnight() >= validFrom() && profileFunction.secondsFromMidnight() <= validTo() && forDevice(DEVICE_PHONE)
|
||||||
|
|
||||||
fun doCalc(profile: Profile, profileName: String, lastBG: GlucoseValue, _synchronized: Boolean): BolusWizard {
|
fun doCalc(profile: Profile, profileName: String, lastBG: GlucoseValue, _synchronized: Boolean): BolusWizard {
|
||||||
val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
val dbRecord = repository.getTemporaryTargetActiveAt(dateUtil.now()).blockingGet()
|
||||||
|
@ -123,6 +131,12 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
|
||||||
return BolusWizard(injector).doCalc(profile, profileName, tempTarget, carbs(), cob, bg, 0.0, percentage, true, useCOB() == YES, bolusIOB, basalIOB, superBolus, useTempTarget() == YES, trend, false, buttonText(), quickWizard = true) //tbc, ok if only quickwizard, but if other sources elsewhere use Sources.QuickWizard
|
return BolusWizard(injector).doCalc(profile, profileName, tempTarget, carbs(), cob, bg, 0.0, percentage, true, useCOB() == YES, bolusIOB, basalIOB, superBolus, useTempTarget() == YES, trend, false, buttonText(), quickWizard = true) //tbc, ok if only quickwizard, but if other sources elsewhere use Sources.QuickWizard
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun guid(): String = safeGetString(storage, "guid", "")
|
||||||
|
|
||||||
|
fun device(): Int = safeGetInt(storage, "device", DEVICE_ALL)
|
||||||
|
|
||||||
|
fun forDevice(device: Int) = device() == device || device() == DEVICE_ALL
|
||||||
|
|
||||||
fun buttonText(): String = safeGetString(storage, "buttonText", "")
|
fun buttonText(): String = safeGetString(storage, "buttonText", "")
|
||||||
|
|
||||||
fun carbs(): Int = safeGetInt(storage, "carbs")
|
fun carbs(): Int = safeGetInt(storage, "carbs")
|
||||||
|
|
|
@ -108,6 +108,35 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/device_label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/overview_editquickwizard_show_on_device"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||||
|
|
||||||
|
<RadioGroup
|
||||||
|
android:id="@+id/device"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_margin="15dp">
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="All" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Phone" />
|
||||||
|
|
||||||
|
<RadioButton
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Watch" />
|
||||||
|
|
||||||
|
</RadioGroup>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -16,9 +16,9 @@
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -29,37 +29,64 @@
|
||||||
card_view:srcCompat="@drawable/ic_quick_wizard" />
|
card_view:srcCompat="@drawable/ic_quick_wizard" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="vertical"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
android:baselineAligned="true"
|
android:baselineAligned="true"
|
||||||
android:orientation="horizontal">
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/overview_quickwizard_item_buttonText"
|
android:id="@+id/overview_quickwizard_item_buttonText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="10dp"
|
||||||
|
android:text="Sample button text"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:textColor="@color/cardObjectiveText"
|
||||||
|
android:textStyle="normal|bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/overview_quickwizard_item_carbs"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="10dp"
|
||||||
|
android:text="36g"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||||
|
android:textColor="@color/cardObjectiveText"
|
||||||
|
android:textStyle="normal|bold" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/overview_quickwizard_item_device"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingLeft="10dp"
|
android:adjustViewBounds="false"
|
||||||
android:text="Sample button text"
|
android:cropToPadding="false"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
android:paddingRight="10dp"
|
||||||
android:textStyle="normal|bold"
|
android:scaleType="fitStart"
|
||||||
android:textColor="@color/cardObjectiveText" />
|
card_view:srcCompat="@drawable/ic_smartphone" />
|
||||||
|
|
||||||
<TextView
|
<ImageView
|
||||||
android:id="@+id/overview_quickwizard_item_carbs"
|
android:id="@+id/handleView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingLeft="10dp"
|
android:layout_alignParentEnd="true"
|
||||||
android:text="36g"
|
android:layout_centerVertical="true"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
android:adjustViewBounds="false"
|
||||||
android:textColor="@color/cardObjectiveText"
|
android:cropToPadding="false"
|
||||||
android:textStyle="normal|bold" />
|
android:scaleType="fitStart"
|
||||||
|
card_view:srcCompat="@drawable/ic_reorder_gray_24dp" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -88,9 +115,9 @@
|
||||||
android:textStyle="normal|bold" />
|
android:textStyle="normal|bold" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:text="-"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content"
|
||||||
|
android:text="-" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/overview_quickwizard_item_to"
|
android:id="@+id/overview_quickwizard_item_to"
|
||||||
|
|
|
@ -1175,5 +1175,9 @@
|
||||||
<string name="wear_action_tempt_manual_range_message">Temptarget:\nMin: %1$s\nMax: %2$s\nDuration: %3$s</string>
|
<string name="wear_action_tempt_manual_range_message">Temptarget:\nMin: %1$s\nMax: %2$s\nDuration: %3$s</string>
|
||||||
<string name="wear_action_tempt_manual_message">Temptarget:\nTarget: %1$s\nDuration: %2$s</string>
|
<string name="wear_action_tempt_manual_message">Temptarget:\nTarget: %1$s\nDuration: %2$s</string>
|
||||||
<string name="wear_action_tempt_preset_message">Temptarget:\Reason: %1$s\nTarget: %2$s\nDuration: %3$s</string>
|
<string name="wear_action_tempt_preset_message">Temptarget:\Reason: %1$s\nTarget: %2$s\nDuration: %3$s</string>
|
||||||
|
<string name="quick_wizard_no_action">No insulin needed nor are carbs added.</string>
|
||||||
|
<string name="quick_wizard_can_not_calculate">Can not calculate wizard, requires actual blood glucose and active profile.</string>
|
||||||
|
<string name="quick_wizard_message">Quick Wizard: %1$s\nInsulin: %2$.2fU\nCarbs: %3$dg</string>
|
||||||
|
<string name="overview_editquickwizard_show_on_device">Show entry on device:</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
5
core/src/main/res/drawable/ic_smartphone.xml
Normal file
5
core/src/main/res/drawable/ic_smartphone.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24" android:viewportWidth="24"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19H7V5h10v14z"/>
|
||||||
|
</vector>
|
|
@ -258,6 +258,10 @@
|
||||||
android:host="*"
|
android:host="*"
|
||||||
android:pathPrefix="/openwearsettings"
|
android:pathPrefix="/openwearsettings"
|
||||||
android:scheme="wear" />
|
android:scheme="wear" />
|
||||||
|
<data
|
||||||
|
android:host="*"
|
||||||
|
android:pathPrefix="/send_quick_wizard"
|
||||||
|
android:scheme="wear" />
|
||||||
<data
|
<data
|
||||||
android:host="*"
|
android:host="*"
|
||||||
android:pathPrefix="/sendstatustowear"
|
android:pathPrefix="/sendstatustowear"
|
||||||
|
@ -544,6 +548,20 @@
|
||||||
android:resource="@drawable/temp_target_tile_preview" />
|
android:resource="@drawable/temp_target_tile_preview" />
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".tile.QuickWizardTileService"
|
||||||
|
android:exported="true"
|
||||||
|
android:label="@string/label_quick_wizard_tile"
|
||||||
|
android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data
|
||||||
|
android:name="androidx.wear.tiles.PREVIEW"
|
||||||
|
android:resource="@drawable/quick_wizard_tile_preview" />
|
||||||
|
</service>
|
||||||
|
|
||||||
<receiver android:name=".complications.ComplicationTapBroadcastReceiver" />
|
<receiver android:name=".complications.ComplicationTapBroadcastReceiver" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
|
@ -595,6 +613,10 @@
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/menu_tempt" />
|
android:label="@string/menu_tempt" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".interaction.actions.BackgroundActionActivity"
|
||||||
|
android:exported="true" />
|
||||||
|
|
||||||
<activity android:name=".interaction.ConfigurationActivity">
|
<activity android:name=".interaction.ConfigurationActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<!-- action-name must be equal with name of xml-ressource where the configuration is describe -->
|
<!-- action-name must be equal with name of xml-ressource where the configuration is describe -->
|
||||||
|
|
|
@ -13,6 +13,7 @@ import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
import android.util.Base64;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
@ -22,10 +23,6 @@ import androidx.wear.tiles.TileService;
|
||||||
|
|
||||||
import com.google.android.gms.common.ConnectionResult;
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
import com.google.android.gms.common.api.GoogleApiClient;
|
import com.google.android.gms.common.api.GoogleApiClient;
|
||||||
import com.google.android.gms.common.api.PendingResult;
|
|
||||||
import com.google.android.gms.common.api.ResultCallback;
|
|
||||||
import com.google.android.gms.wearable.CapabilityApi;
|
|
||||||
import com.google.android.gms.wearable.CapabilityInfo;
|
|
||||||
import com.google.android.gms.wearable.ChannelApi;
|
import com.google.android.gms.wearable.ChannelApi;
|
||||||
import com.google.android.gms.wearable.DataEvent;
|
import com.google.android.gms.wearable.DataEvent;
|
||||||
import com.google.android.gms.wearable.DataEventBuffer;
|
import com.google.android.gms.wearable.DataEventBuffer;
|
||||||
|
@ -36,7 +33,8 @@ import com.google.android.gms.wearable.NodeApi;
|
||||||
import com.google.android.gms.wearable.Wearable;
|
import com.google.android.gms.wearable.Wearable;
|
||||||
import com.google.android.gms.wearable.WearableListenerService;
|
import com.google.android.gms.wearable.WearableListenerService;
|
||||||
|
|
||||||
import java.util.Set;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -47,11 +45,11 @@ import info.nightscout.androidaps.interaction.AAPSPreferences;
|
||||||
import info.nightscout.androidaps.interaction.actions.AcceptActivity;
|
import info.nightscout.androidaps.interaction.actions.AcceptActivity;
|
||||||
import info.nightscout.androidaps.interaction.actions.CPPActivity;
|
import info.nightscout.androidaps.interaction.actions.CPPActivity;
|
||||||
import info.nightscout.androidaps.interaction.utils.Persistence;
|
import info.nightscout.androidaps.interaction.utils.Persistence;
|
||||||
|
import info.nightscout.androidaps.interaction.utils.WearUtil;
|
||||||
import info.nightscout.androidaps.tile.ActionsTileService;
|
import info.nightscout.androidaps.tile.ActionsTileService;
|
||||||
|
import info.nightscout.androidaps.tile.QuickWizardTileService;
|
||||||
import info.nightscout.androidaps.tile.TempTargetTileService;
|
import info.nightscout.androidaps.tile.TempTargetTileService;
|
||||||
import info.nightscout.shared.SafeParse;
|
import info.nightscout.shared.SafeParse;
|
||||||
import info.nightscout.androidaps.interaction.utils.WearUtil;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by emmablack on 12/26/14.
|
* Created by emmablack on 12/26/14.
|
||||||
|
@ -62,7 +60,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
@Inject WearUtil wearUtil;
|
@Inject WearUtil wearUtil;
|
||||||
@Inject Persistence persistence;
|
@Inject Persistence persistence;
|
||||||
|
|
||||||
private static final String WEARABLE_DATA_PATH = "/nightscout_watch_data";
|
|
||||||
private static final String WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend";
|
private static final String WEARABLE_RESEND_PATH = "/nightscout_watch_data_resend";
|
||||||
private static final String WEARABLE_CANCELBOLUS_PATH = "/nightscout_watch_cancel_bolus";
|
private static final String WEARABLE_CANCELBOLUS_PATH = "/nightscout_watch_cancel_bolus";
|
||||||
public static final String WEARABLE_CONFIRM_ACTIONSTRING_PATH = "/nightscout_watch_confirmactionstring";
|
public static final String WEARABLE_CONFIRM_ACTIONSTRING_PATH = "/nightscout_watch_confirmactionstring";
|
||||||
|
@ -71,13 +68,13 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
private static final String OPEN_SETTINGS = "/openwearsettings";
|
private static final String OPEN_SETTINGS = "/openwearsettings";
|
||||||
private static final String NEW_STATUS_PATH = "/sendstatustowear";
|
private static final String NEW_STATUS_PATH = "/sendstatustowear";
|
||||||
private static final String NEW_PREFERENCES_PATH = "/sendpreferencestowear";
|
private static final String NEW_PREFERENCES_PATH = "/sendpreferencestowear";
|
||||||
|
private static final String QUICK_WIZARD_PATH = "/send_quick_wizard";
|
||||||
public static final String BASAL_DATA_PATH = "/nightscout_watch_basal";
|
public static final String BASAL_DATA_PATH = "/nightscout_watch_basal";
|
||||||
public static final String BOLUS_PROGRESS_PATH = "/nightscout_watch_bolusprogress";
|
public static final String BOLUS_PROGRESS_PATH = "/nightscout_watch_bolusprogress";
|
||||||
public static final String ACTION_CONFIRMATION_REQUEST_PATH = "/nightscout_watch_actionconfirmationrequest";
|
public static final String ACTION_CONFIRMATION_REQUEST_PATH = "/nightscout_watch_actionconfirmationrequest";
|
||||||
public static final String NEW_CHANGECONFIRMATIONREQUEST_PATH = "/nightscout_watch_changeconfirmationrequest";
|
public static final String NEW_CHANGECONFIRMATIONREQUEST_PATH = "/nightscout_watch_changeconfirmationrequest";
|
||||||
public static final String ACTION_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest";
|
public static final String ACTION_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest";
|
||||||
|
|
||||||
|
|
||||||
public static final int BOLUS_PROGRESS_NOTIF_ID = 1;
|
public static final int BOLUS_PROGRESS_NOTIF_ID = 1;
|
||||||
public static final int CONFIRM_NOTIF_ID = 2;
|
public static final int CONFIRM_NOTIF_ID = 2;
|
||||||
public static final int CHANGE_NOTIF_ID = 556677;
|
public static final int CHANGE_NOTIF_ID = 556677;
|
||||||
|
@ -88,29 +85,15 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
private static final String ACTION_CONFIRMCHANGE = "com.dexdrip.stephenblack.nightwatch.CONFIRMCHANGE";
|
private static final String ACTION_CONFIRMCHANGE = "com.dexdrip.stephenblack.nightwatch.CONFIRMCHANGE";
|
||||||
private static final String ACTION_INITIATE_ACTION = "com.dexdrip.stephenblack.nightwatch.INITIATE_ACTION";
|
private static final String ACTION_INITIATE_ACTION = "com.dexdrip.stephenblack.nightwatch.INITIATE_ACTION";
|
||||||
|
|
||||||
|
|
||||||
private static final String ACTION_RESEND_BULK = "com.dexdrip.stephenblack.nightwatch.RESEND_BULK_DATA";
|
|
||||||
private static final String AAPS_NOTIFY_CHANNEL_ID_OPENLOOP = "AndroidAPS-OpenLoop";
|
private static final String AAPS_NOTIFY_CHANNEL_ID_OPENLOOP = "AndroidAPS-OpenLoop";
|
||||||
private static final String AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS = "bolus progress vibration";
|
private static final String AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS = "bolus progress vibration";
|
||||||
private static final String AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS_SILENT = "bolus progress silent";
|
private static final String AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS_SILENT = "bolus progress silent";
|
||||||
|
|
||||||
|
|
||||||
GoogleApiClient googleApiClient;
|
GoogleApiClient googleApiClient;
|
||||||
private long lastRequest = 0;
|
|
||||||
private DismissThread bolusprogressThread;
|
private DismissThread bolusprogressThread;
|
||||||
private static final String TAG = "ListenerService";
|
private static final String TAG = "ListenerService";
|
||||||
|
|
||||||
private DataRequester mDataRequester = null;
|
|
||||||
private static final int GET_CAPABILITIES_TIMEOUT_MS = 5000;
|
|
||||||
|
|
||||||
// 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";
|
|
||||||
private final String mPhoneNodeId = null;
|
|
||||||
private String localnode = null;
|
|
||||||
private final String logPrefix = ""; // "WR: "
|
private final String logPrefix = ""; // "WR: "
|
||||||
|
|
||||||
// Not derived from DaggerService, do injection here
|
// Not derived from DaggerService, do injection here
|
||||||
|
@ -120,143 +103,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DataRequester extends AsyncTask<Void, Void, Void> {
|
|
||||||
Context mContext;
|
|
||||||
String path;
|
|
||||||
byte[] payload;
|
|
||||||
|
|
||||||
|
|
||||||
DataRequester(Context context, String thispath, byte[] thispayload) {
|
|
||||||
path = thispath;
|
|
||||||
payload = thispayload;
|
|
||||||
// Log.d(TAG, logPrefix + "DataRequester DataRequester: " + thispath + " lastRequest:" + lastRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Void doInBackground(Void... params) {
|
|
||||||
// Log.d(TAG, logPrefix + "DataRequester: doInBack: " + params);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
forceGoogleApiConnect();
|
|
||||||
DataMap datamap;
|
|
||||||
|
|
||||||
if (isCancelled()) {
|
|
||||||
Log.d(TAG, "doInBackground CANCELLED programmatically");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (googleApiClient != null) {
|
|
||||||
if (!googleApiClient.isConnected())
|
|
||||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// this code might not be needed in this way, but we need to see that later
|
|
||||||
if ((googleApiClient != null) && (googleApiClient.isConnected())) {
|
|
||||||
if ((System.currentTimeMillis() - lastRequest > 20 * 1000)) {
|
|
||||||
|
|
||||||
// enforce 20-second debounce period
|
|
||||||
lastRequest = System.currentTimeMillis();
|
|
||||||
|
|
||||||
// NodeApi.GetConnectedNodesResult nodes =
|
|
||||||
// Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
|
||||||
if (localnode == null || (localnode != null && localnode.isEmpty()))
|
|
||||||
setLocalNodeName();
|
|
||||||
|
|
||||||
CapabilityInfo capabilityInfo = getCapabilities();
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
Node phoneNode = null;
|
|
||||||
|
|
||||||
if (capabilityInfo != null) {
|
|
||||||
phoneNode = updatePhoneSyncBgsCapability(capabilityInfo);
|
|
||||||
count = capabilityInfo.getNodes().size();
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.d(TAG, "doInBackground connected. CapabilityApi.GetCapabilityResult mPhoneNodeID="
|
|
||||||
+ (phoneNode != null ? phoneNode.getId() : "") + " count=" + count + " localnode="
|
|
||||||
+ localnode);// KS
|
|
||||||
|
|
||||||
if (count > 0) {
|
|
||||||
|
|
||||||
for (Node node : capabilityInfo.getNodes()) {
|
|
||||||
|
|
||||||
// Log.d(TAG, "doInBackground path: " + path);
|
|
||||||
|
|
||||||
switch (path) {
|
|
||||||
// simple send as is payloads
|
|
||||||
|
|
||||||
case WEARABLE_RESEND_PATH:
|
|
||||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(),
|
|
||||||
WEARABLE_RESEND_PATH, null);
|
|
||||||
break;
|
|
||||||
case WEARABLE_DATA_PATH:
|
|
||||||
case WEARABLE_CANCELBOLUS_PATH:
|
|
||||||
case WEARABLE_CONFIRM_ACTIONSTRING_PATH:
|
|
||||||
case WEARABLE_INITIATE_ACTIONSTRING_PATH:
|
|
||||||
case OPEN_SETTINGS:
|
|
||||||
case NEW_STATUS_PATH:
|
|
||||||
case NEW_PREFERENCES_PATH:
|
|
||||||
case BASAL_DATA_PATH:
|
|
||||||
case BOLUS_PROGRESS_PATH:
|
|
||||||
case ACTION_CONFIRMATION_REQUEST_PATH:
|
|
||||||
case NEW_CHANGECONFIRMATIONREQUEST_PATH:
|
|
||||||
case ACTION_CANCELNOTIFICATION_REQUEST_PATH: {
|
|
||||||
Log.w(TAG, logPrefix + "Unhandled path");
|
|
||||||
// sendMessagePayload(node, path, path, payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
default:// SYNC_ALL_DATA
|
|
||||||
// this fall through is messy and non-deterministic for new paths
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
Log.d(TAG, logPrefix + "doInBackground connected but getConnectedNodes returns 0.");
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// no resend
|
|
||||||
Log.d(TAG, logPrefix + "Inside the timeout, will not be executed");
|
|
||||||
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, logPrefix + "Not connected for sending: api "
|
|
||||||
+ ((googleApiClient == null) ? "is NULL!" : "not null"));
|
|
||||||
if (googleApiClient != null) {
|
|
||||||
googleApiClient.connect();
|
|
||||||
} else {
|
|
||||||
googleApiConnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception ex) {
|
|
||||||
Log.e(TAG, logPrefix + "Error executing DataRequester in background. Exception: " + ex.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public CapabilityInfo getCapabilities() {
|
|
||||||
|
|
||||||
CapabilityApi.GetCapabilityResult capabilityResult = Wearable.CapabilityApi.getCapability(googleApiClient,
|
|
||||||
CAPABILITY_PHONE_APP, CapabilityApi.FILTER_REACHABLE).await(GET_CAPABILITIES_TIMEOUT_MS,
|
|
||||||
TimeUnit.MILLISECONDS);
|
|
||||||
|
|
||||||
if (!capabilityResult.getStatus().isSuccess()) {
|
|
||||||
Log.e(TAG, logPrefix + "doInBackground Failed to get capabilities, status: "
|
|
||||||
+ capabilityResult.getStatus().getStatusMessage());
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return capabilityResult.getCapability();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class BolusCancelTask extends AsyncTask<Void, Void, Void> {
|
public class BolusCancelTask extends AsyncTask<Void, Void, Void> {
|
||||||
Context mContext;
|
Context mContext;
|
||||||
|
|
||||||
|
@ -266,8 +112,11 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
// Log.d(TAG, logPrefix + "BolusCancelTask: doInBack: " + params);
|
Log.d(TAG, logPrefix + "BolusCancelTask.doInBackground: " + params);
|
||||||
|
if (!googleApiClient.isConnected()) {
|
||||||
|
Log.i(TAG, "BolusCancelTask.doInBackground: not connected");
|
||||||
|
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
if (googleApiClient.isConnected()) {
|
if (googleApiClient.isConnected()) {
|
||||||
NodeApi.GetConnectedNodesResult nodes =
|
NodeApi.GetConnectedNodesResult nodes =
|
||||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||||
|
@ -275,16 +124,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_CANCELBOLUS_PATH, null);
|
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_CANCELBOLUS_PATH, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
|
||||||
if (googleApiClient.isConnected()) {
|
|
||||||
NodeApi.GetConnectedNodesResult nodes =
|
|
||||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
|
||||||
for (Node node : nodes.getNodes()) {
|
|
||||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_CANCELBOLUS_PATH, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -303,9 +142,12 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground(Void... params) {
|
protected Void doInBackground(Void... params) {
|
||||||
|
Log.i(TAG, "MessageActionTask.doInBackground: ");
|
||||||
|
|
||||||
forceGoogleApiConnect();
|
if (!googleApiClient.isConnected()) {
|
||||||
|
Log.i(TAG, "MessageActionTask.doInBackground: not connected");
|
||||||
|
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
if (googleApiClient.isConnected()) {
|
if (googleApiClient.isConnected()) {
|
||||||
NodeApi.GetConnectedNodesResult nodes =
|
NodeApi.GetConnectedNodesResult nodes =
|
||||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||||
|
@ -313,22 +155,42 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), mMessagePath, mActionstring.getBytes());
|
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), mMessagePath, mActionstring.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
|
||||||
if (googleApiClient.isConnected()) {
|
|
||||||
NodeApi.GetConnectedNodesResult nodes =
|
|
||||||
Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
|
||||||
for (Node node : nodes.getNodes()) {
|
|
||||||
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), mMessagePath, mActionstring.getBytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ResendDataTask extends AsyncTask<Void, Void, Void> {
|
||||||
|
Context mContext;
|
||||||
|
|
||||||
|
ResendDataTask(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Void doInBackground(Void... params) {
|
||||||
|
Log.d(TAG, logPrefix + "ResendDataTask.doInBackground: " + params);
|
||||||
|
|
||||||
|
if (!googleApiClient.isConnected()) {
|
||||||
|
Log.i(TAG, "ResendDataTask.doInBackground: not connected");
|
||||||
|
googleApiClient.blockingConnect(15, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
if (googleApiClient.isConnected()) {
|
||||||
|
Log.i(TAG, "ResendDataTask.doInBackground: connected");
|
||||||
|
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleApiClient).await();
|
||||||
|
for (Node node : nodes.getNodes()) {
|
||||||
|
Wearable.MessageApi.sendMessage(googleApiClient, node.getId(), WEARABLE_RESEND_PATH, null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "ResendDataTask.doInBackground: could not connect");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void requestData() {
|
public void requestData() {
|
||||||
sendData(WEARABLE_RESEND_PATH, null);
|
new ResendDataTask(this).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancelBolus() {
|
public void cancelBolus() {
|
||||||
|
@ -343,59 +205,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
new MessageActionTask(this, WEARABLE_INITIATE_ACTIONSTRING_PATH, actionstring).execute();
|
new MessageActionTask(this, WEARABLE_INITIATE_ACTIONSTRING_PATH, actionstring).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Node updatePhoneSyncBgsCapability(CapabilityInfo capabilityInfo) {
|
|
||||||
// Log.d(TAG, "CapabilityInfo: " + capabilityInfo);
|
|
||||||
|
|
||||||
Set<Node> connectedNodes = capabilityInfo.getNodes();
|
|
||||||
return pickBestNode(connectedNodes);
|
|
||||||
// mPhoneNodeId = pickBestNodeId(connectedNodes);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private Node pickBestNode(Set<Node> nodes) {
|
|
||||||
Node bestNode = null;
|
|
||||||
// Find a nearby node or pick one arbitrarily
|
|
||||||
for (Node node : nodes) {
|
|
||||||
if (node.isNearby()) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
bestNode = node;
|
|
||||||
}
|
|
||||||
return bestNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private synchronized void sendData(String path, byte[] payload) {
|
|
||||||
// Log.d(TAG, "WR: sendData: path: " + path + ", payload=" + payload);
|
|
||||||
|
|
||||||
if (path == null)
|
|
||||||
return;
|
|
||||||
if (mDataRequester != null) {
|
|
||||||
// Log.d(TAG, logPrefix + "sendData DataRequester != null lastRequest:" +
|
|
||||||
// WearUtil.dateTimeText(lastRequest));
|
|
||||||
if (mDataRequester.getStatus() != AsyncTask.Status.FINISHED) {
|
|
||||||
// Log.d(TAG, logPrefix + "sendData Should be canceled? Let run 'til finished.");
|
|
||||||
// mDataRequester.cancel(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.d(TAG,
|
|
||||||
logPrefix + "sendData: execute lastRequest:" + wearUtil.dateTimeText(lastRequest));
|
|
||||||
mDataRequester = (DataRequester) new DataRequester(this, path, payload).execute();
|
|
||||||
// executeTask(mDataRequester);
|
|
||||||
|
|
||||||
// if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
|
||||||
// Log.d(TAG, "sendData SDK < M call execute lastRequest:" + WearUtil.dateTimeText(lastRequest));
|
|
||||||
// mDataRequester = (DataRequester) new DataRequester(this, path, payload).execute();
|
|
||||||
// } else {
|
|
||||||
// Log.d(TAG, "sendData SDK >= M call executeOnExecutor lastRequest:" + WearUtil.dateTimeText(lastRequest));
|
|
||||||
// // TODO xdrip executor
|
|
||||||
// mDataRequester = (DataRequester) new DataRequester(this, path, payload).executeOnExecutor(xdrip.executor);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void googleApiConnect() {
|
private void googleApiConnect() {
|
||||||
if (googleApiClient != null) {
|
if (googleApiClient != null) {
|
||||||
// Remove old listener(s)
|
// Remove old listener(s)
|
||||||
|
@ -419,20 +228,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
Wearable.MessageApi.addListener(googleApiClient, this);
|
Wearable.MessageApi.addListener(googleApiClient, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void forceGoogleApiConnect() {
|
|
||||||
if (googleApiClient == null || (!googleApiClient.isConnected() && !googleApiClient.isConnecting())) {
|
|
||||||
try {
|
|
||||||
Log.d(TAG, "forceGoogleApiConnect: forcing google api reconnection");
|
|
||||||
googleApiConnect();
|
|
||||||
Thread.sleep(2000);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
|
||||||
|
@ -486,7 +281,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
return START_STICKY;
|
return START_STICKY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDataChanged(DataEventBuffer dataEvents) {
|
public void onDataChanged(DataEventBuffer dataEvents) {
|
||||||
|
|
||||||
|
@ -548,10 +342,13 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
String keyControl = getString(R.string.key_wear_control);
|
String keyControl = getString(R.string.key_wear_control);
|
||||||
if (dataMap.containsKey(keyControl)) {
|
if (dataMap.containsKey(keyControl)) {
|
||||||
|
boolean previousWearControl = sharedPreferences.getBoolean(keyControl, false);
|
||||||
boolean wearControl = dataMap.getBoolean(keyControl, false);
|
boolean wearControl = dataMap.getBoolean(keyControl, false);
|
||||||
editor.putBoolean(keyControl, wearControl);
|
editor.putBoolean(keyControl, wearControl);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
updateTiles();
|
if (wearControl != previousWearControl) {
|
||||||
|
updateTiles();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
String keyPercentage = getString(R.string.key_boluswizard_percentage);
|
String keyPercentage = getString(R.string.key_boluswizard_percentage);
|
||||||
if (dataMap.containsKey(keyPercentage)) {
|
if (dataMap.containsKey(keyPercentage)) {
|
||||||
|
@ -565,6 +362,26 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
editor.putBoolean(keyUnits, mgdl);
|
editor.putBoolean(keyUnits, mgdl);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
} else if (path.equals(QUICK_WIZARD_PATH)) {
|
||||||
|
dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
|
||||||
|
Log.i(TAG, "onDataChanged: QUICK_WIZARD_PATH" + dataMap);
|
||||||
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
dataMap.remove("timestamp");
|
||||||
|
String key = getString(R.string.key_quick_wizard_data_map);
|
||||||
|
String dataString = Base64.encodeToString(dataMap.toByteArray(), Base64.DEFAULT);
|
||||||
|
if (!dataString.equals(sharedPreferences.getString(key, ""))) {
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString(key, dataString);
|
||||||
|
editor.apply();
|
||||||
|
// Todo maybe add debounce function, due to 20 seconds update limit?
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
TileService.getUpdater(this)
|
||||||
|
.requestUpdate(QuickWizardTileService.class);
|
||||||
|
}
|
||||||
|
Log.i(TAG, "onDataChanged: updated QUICK_WIZARD");
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "onDataChanged: ignore update");
|
||||||
|
}
|
||||||
} else if (path.equals(NEW_CHANGECONFIRMATIONREQUEST_PATH)) {
|
} else if (path.equals(NEW_CHANGECONFIRMATIONREQUEST_PATH)) {
|
||||||
String title = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("title");
|
String title = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("title");
|
||||||
String message = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("message");
|
String message = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("message");
|
||||||
|
@ -592,6 +409,9 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
|
|
||||||
TileService.getUpdater(this)
|
TileService.getUpdater(this)
|
||||||
.requestUpdate(TempTargetTileService.class);
|
.requestUpdate(TempTargetTileService.class);
|
||||||
|
|
||||||
|
TileService.getUpdater(this)
|
||||||
|
.requestUpdate(QuickWizardTileService.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -666,7 +486,7 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
PendingIntent cancelPendingIntent = PendingIntent.getService(this, 0, cancelIntent, 0);
|
PendingIntent cancelPendingIntent = PendingIntent.getService(this, 0, cancelIntent, 0);
|
||||||
|
|
||||||
NotificationCompat.Builder notificationBuilder =
|
NotificationCompat.Builder notificationBuilder =
|
||||||
new NotificationCompat.Builder(this, vibrate ? AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS: AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS_SILENT)
|
new NotificationCompat.Builder(this, vibrate ? AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS : AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS_SILENT)
|
||||||
.setSmallIcon(R.drawable.ic_icon)
|
.setSmallIcon(R.drawable.ic_icon)
|
||||||
.setContentTitle(getString(R.string.bolus_progress))
|
.setContentTitle(getString(R.string.bolus_progress))
|
||||||
.setContentText(progresspercent + "% - " + progresstatus)
|
.setContentText(progresspercent + "% - " + progresstatus)
|
||||||
|
@ -723,7 +543,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
bolusprogressThread.start();
|
bolusprogressThread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private class DismissThread extends Thread {
|
private class DismissThread extends Thread {
|
||||||
private final int notificationID;
|
private final int notificationID;
|
||||||
private final int seconds;
|
private final int seconds;
|
||||||
|
@ -757,7 +576,7 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void initiateAction(Context context, String actionstring) {
|
public static void initiateAction(Context context, @NotNull String actionstring) {
|
||||||
Intent intent = new Intent(context, ListenerService.class);
|
Intent intent = new Intent(context, ListenerService.class);
|
||||||
intent.putExtra("actionstring", actionstring);
|
intent.putExtra("actionstring", actionstring);
|
||||||
intent.setAction(ACTION_INITIATE_ACTION);
|
intent.setAction(ACTION_INITIATE_ACTION);
|
||||||
|
@ -780,18 +599,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
public void onConnected(Bundle bundle) {
|
public void onConnected(Bundle bundle) {
|
||||||
// Log.d(TAG, logPrefix + "onConnected call requestData");
|
// Log.d(TAG, logPrefix + "onConnected call requestData");
|
||||||
|
|
||||||
CapabilityApi.CapabilityListener capabilityListener = new CapabilityApi.CapabilityListener() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCapabilityChanged(CapabilityInfo capabilityInfo) {
|
|
||||||
updatePhoneSyncBgsCapability(capabilityInfo);
|
|
||||||
Log.d(TAG, logPrefix + "onConnected onCapabilityChanged mPhoneNodeID:" + mPhoneNodeId
|
|
||||||
+ ", Capability: " + capabilityInfo);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Wearable.CapabilityApi.addCapabilityListener(googleApiClient, capabilityListener, CAPABILITY_PHONE_APP);
|
|
||||||
|
|
||||||
Wearable.ChannelApi.addListener(googleApiClient, this);
|
Wearable.ChannelApi.addListener(googleApiClient, this);
|
||||||
requestData();
|
requestData();
|
||||||
}
|
}
|
||||||
|
@ -806,28 +613,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void setLocalNodeName() {
|
|
||||||
forceGoogleApiConnect();
|
|
||||||
PendingResult<NodeApi.GetLocalNodeResult> result = Wearable.NodeApi.getLocalNode(googleApiClient);
|
|
||||||
result.setResultCallback(new ResultCallback<NodeApi.GetLocalNodeResult>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onResult(NodeApi.GetLocalNodeResult getLocalNodeResult) {
|
|
||||||
if (!getLocalNodeResult.getStatus().isSuccess()) {
|
|
||||||
Log.e(TAG, "ERROR: failed to getLocalNode Status="
|
|
||||||
+ getLocalNodeResult.getStatus().getStatusMessage());
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "getLocalNode Status=: " + getLocalNodeResult.getStatus().getStatusMessage());
|
|
||||||
Node getnode = getLocalNodeResult.getNode();
|
|
||||||
localnode = getnode != null ? getnode.getDisplayName() + "|" + getnode.getId() : "";
|
|
||||||
Log.d(TAG, "setLocalNodeName. localnode=" + localnode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package info.nightscout.androidaps.interaction.actions
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
|
import android.widget.Toast
|
||||||
|
import info.nightscout.androidaps.data.ListenerService
|
||||||
|
|
||||||
|
const val TAG = "QuickWizard"
|
||||||
|
|
||||||
|
class BackgroundActionActivity : Activity() {
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
val actionString = intent.extras?.getString("actionString")
|
||||||
|
Log.i(TAG, "QuickWizardActivity.onCreate: actionString=$actionString")
|
||||||
|
if (actionString != null) {
|
||||||
|
ListenerService.initiateAction(this, actionString)
|
||||||
|
val message = intent.extras?.getString("message")
|
||||||
|
if (message != null) {
|
||||||
|
Toast.makeText(this, message, Toast.LENGTH_LONG).show()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.e(TAG, "BackgroundActionActivity.onCreate extras 'actionString' required")
|
||||||
|
}
|
||||||
|
finishAffinity()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -31,9 +31,7 @@ public class TempTargetActivity extends ViewSelectorActivity {
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
if (executeInBackground()){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setAdapter(new MyGridViewPagerAdapter());
|
setAdapter(new MyGridViewPagerAdapter());
|
||||||
|
|
||||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
@ -41,21 +39,6 @@ public class TempTargetActivity extends ViewSelectorActivity {
|
||||||
isSingleTarget = sp.getBoolean("singletarget", true);
|
isSingleTarget = sp.getBoolean("singletarget", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean executeInBackground() {
|
|
||||||
Bundle extras = getIntent().getExtras();
|
|
||||||
if (extras != null) {
|
|
||||||
String actionString = extras.getString("actionString", "");
|
|
||||||
boolean inBackground = extras.getBoolean("inBackground", false);
|
|
||||||
if (inBackground) {
|
|
||||||
ListenerService.initiateAction(this, actionString);
|
|
||||||
confirmAction(this, R.string.action_tempt_confirmation);
|
|
||||||
finishAffinity();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onPause() {
|
protected void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package info.nightscout.androidaps.tile
|
package info.nightscout.androidaps.tile
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.interaction.actions.BolusActivity
|
import info.nightscout.androidaps.interaction.actions.BolusActivity
|
||||||
import info.nightscout.androidaps.interaction.actions.TreatmentActivity
|
import info.nightscout.androidaps.interaction.actions.TreatmentActivity
|
||||||
|
@ -7,48 +8,49 @@ import info.nightscout.androidaps.interaction.actions.ECarbActivity
|
||||||
import info.nightscout.androidaps.interaction.actions.TempTargetActivity
|
import info.nightscout.androidaps.interaction.actions.TempTargetActivity
|
||||||
import info.nightscout.androidaps.interaction.actions.WizardActivity
|
import info.nightscout.androidaps.interaction.actions.WizardActivity
|
||||||
|
|
||||||
object ActionSource : TileSource {
|
object ActionSource : StaticTileSource(), TileSource {
|
||||||
|
|
||||||
override fun getActions(): List<Action> {
|
override val preferencePrefix = "tile_action_"
|
||||||
|
|
||||||
|
override fun getActions(resources: Resources): List<StaticAction> {
|
||||||
return listOf(
|
return listOf(
|
||||||
Action(
|
StaticAction(
|
||||||
id = 0,
|
|
||||||
settingName = "wizard",
|
settingName = "wizard",
|
||||||
nameRes = R.string.menu_wizard_short,
|
buttonText = resources.getString(R.string.menu_wizard_short),
|
||||||
iconRes = R.drawable.ic_calculator_green,
|
iconRes = R.drawable.ic_calculator_green,
|
||||||
activityClass = WizardActivity::class.java.name,
|
activityClass = WizardActivity::class.java.name,
|
||||||
),
|
),
|
||||||
Action(
|
StaticAction(
|
||||||
id = 1,
|
|
||||||
settingName = "treatment",
|
settingName = "treatment",
|
||||||
nameRes = R.string.menu_treatment_short,
|
buttonText = resources.getString(R.string.menu_treatment_short),
|
||||||
iconRes = R.drawable.ic_bolus_carbs,
|
iconRes = R.drawable.ic_bolus_carbs,
|
||||||
activityClass = TreatmentActivity::class.java.name,
|
activityClass = TreatmentActivity::class.java.name,
|
||||||
),
|
),
|
||||||
Action(
|
StaticAction(
|
||||||
id = 2,
|
|
||||||
settingName = "bolus",
|
settingName = "bolus",
|
||||||
nameRes = R.string.action_insulin,
|
buttonText = resources.getString(R.string.action_insulin),
|
||||||
iconRes = R.drawable.ic_bolus,
|
iconRes = R.drawable.ic_bolus,
|
||||||
activityClass = BolusActivity::class.java.name,
|
activityClass = BolusActivity::class.java.name,
|
||||||
),
|
),
|
||||||
Action(
|
StaticAction(
|
||||||
id = 3,
|
|
||||||
settingName = "carbs",
|
settingName = "carbs",
|
||||||
nameRes = R.string.action_carbs,
|
buttonText = resources.getString(R.string.action_carbs),
|
||||||
iconRes = R.drawable.ic_carbs_orange,
|
iconRes = R.drawable.ic_carbs_orange,
|
||||||
activityClass = ECarbActivity::class.java.name,
|
activityClass = ECarbActivity::class.java.name,
|
||||||
),
|
),
|
||||||
Action(
|
StaticAction(
|
||||||
id = 4,
|
|
||||||
settingName = "temp_target",
|
settingName = "temp_target",
|
||||||
nameRes = R.string.menu_tempt,
|
buttonText = resources.getString(R.string.menu_tempt),
|
||||||
iconRes = R.drawable.ic_temptarget_flat,
|
iconRes = R.drawable.ic_temptarget_flat,
|
||||||
activityClass = TempTargetActivity::class.java.name,
|
activityClass = TempTargetActivity::class.java.name,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getResourceReferences(resources: Resources): List<Int> {
|
||||||
|
return getActions(resources).map { it.iconRes }
|
||||||
|
}
|
||||||
|
|
||||||
override fun getDefaultConfig(): Map<String, String> {
|
override fun getDefaultConfig(): Map<String, String> {
|
||||||
return mapOf(
|
return mapOf(
|
||||||
"tile_action_1" to "wizard",
|
"tile_action_1" to "wizard",
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
package info.nightscout.androidaps.tile
|
package info.nightscout.androidaps.tile
|
||||||
|
|
||||||
class ActionsTileService : TileBase() {
|
class ActionsTileService : TileBase() {
|
||||||
|
override val resourceVersion = "ActionsTileService"
|
||||||
override val preferencePrefix = "tile_action_"
|
|
||||||
override val resourceVersion = "1"
|
|
||||||
override val idIconActionPrefix = "ic_action_"
|
|
||||||
override val source = ActionSource
|
override val source = ActionSource
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
package info.nightscout.androidaps.tile
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.util.Base64
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.google.android.gms.wearable.DataMap
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.interaction.actions.BackgroundActionActivity
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
object QuickWizardSource : TileSource {
|
||||||
|
|
||||||
|
override fun getSelectedActions(context: Context): List<Action> {
|
||||||
|
val quickList = mutableListOf<Action>()
|
||||||
|
val quickMap = getDataMap(context)
|
||||||
|
val sfm = secondsFromMidnight()
|
||||||
|
|
||||||
|
for (quick in quickMap) {
|
||||||
|
val validFrom = quick.getInt("from", 0)
|
||||||
|
val validTo = quick.getInt("to", 0)
|
||||||
|
val isActive = sfm in validFrom..validTo
|
||||||
|
// use from and to to schedule new update for timeline, for now just refresh every minute
|
||||||
|
val guid = quick.getString("guid", "")
|
||||||
|
if (isActive && guid != "") {
|
||||||
|
quickList.add(
|
||||||
|
Action(
|
||||||
|
buttonText = quick.getString("button_text", "?"),
|
||||||
|
buttonTextSub = "${quick.getInt("carbs", 0)} g",
|
||||||
|
iconRes = R.drawable.ic_quick_wizard,
|
||||||
|
activityClass = BackgroundActionActivity::class.java.name,
|
||||||
|
actionString = "quick_wizard $guid",
|
||||||
|
message = context.resources.getString(R.string.action_quick_wizard_confirmation),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Log.i(TAG, "getSelectedActions: active " + quick.getString("button_text", "?") + " guid=" + guid)
|
||||||
|
} else {
|
||||||
|
Log.i(TAG, "getSelectedActions: not active " + quick.getString("button_text", "?") + " guid=" + guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return quickList
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getDataMap(context: Context): ArrayList<DataMap> {
|
||||||
|
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
val key = context.resources.getString(R.string.key_quick_wizard_data_map)
|
||||||
|
if (sharedPrefs.contains(key)) {
|
||||||
|
val rawB64Data: String? = sharedPrefs.getString(key, null)
|
||||||
|
val rawData: ByteArray = Base64.decode(rawB64Data, Base64.DEFAULT)
|
||||||
|
try {
|
||||||
|
val map = DataMap.fromByteArray(rawData)
|
||||||
|
return map.getDataMapArrayList("quick_wizard")
|
||||||
|
|
||||||
|
} catch (ex: IllegalArgumentException) {
|
||||||
|
Log.e(TAG, "getSelectedActions: IllegalArgumentException ", ex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arrayListOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun secondsFromMidnight(): Int {
|
||||||
|
val c = Calendar.getInstance()
|
||||||
|
c.set(Calendar.HOUR_OF_DAY, 0)
|
||||||
|
c.set(Calendar.MINUTE, 0)
|
||||||
|
c.set(Calendar.SECOND, 0)
|
||||||
|
c.set(Calendar.MILLISECOND, 0)
|
||||||
|
val passed: Long = System.currentTimeMillis() - c.timeInMillis
|
||||||
|
|
||||||
|
return (passed / 1000).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getResourceReferences(resources: Resources): List<Int> {
|
||||||
|
return listOf(R.drawable.ic_quick_wizard)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package info.nightscout.androidaps.tile
|
||||||
|
|
||||||
|
const val TAG = "QuickWizard"
|
||||||
|
|
||||||
|
class QuickWizardTileService : TileBase() {
|
||||||
|
override val resourceVersion = "QuickWizardTileService"
|
||||||
|
override val source = QuickWizardSource
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package info.nightscout.androidaps.tile
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.content.res.Resources
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
|
||||||
|
class StaticAction(
|
||||||
|
val settingName: String,
|
||||||
|
buttonText: String,
|
||||||
|
buttonTextSub: String? = null,
|
||||||
|
activityClass: String,
|
||||||
|
@DrawableRes iconRes: Int,
|
||||||
|
actionString: String? = null,
|
||||||
|
message: String? = null,
|
||||||
|
) : Action(buttonText, buttonTextSub, activityClass, iconRes, actionString, message)
|
||||||
|
|
||||||
|
abstract class StaticTileSource {
|
||||||
|
|
||||||
|
abstract fun getActions(resources: Resources): List<StaticAction>
|
||||||
|
|
||||||
|
abstract val preferencePrefix: String
|
||||||
|
abstract fun getDefaultConfig(): Map<String, String>
|
||||||
|
|
||||||
|
open fun getSelectedActions(context: Context): List<Action> {
|
||||||
|
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
setDefaultSettings(sharedPrefs)
|
||||||
|
|
||||||
|
val actionList: MutableList<Action> = mutableListOf()
|
||||||
|
for (i in 1..4) {
|
||||||
|
val action = getActionFromPreference(context.resources, sharedPrefs, i)
|
||||||
|
if (action != null) {
|
||||||
|
actionList.add(action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (actionList.isEmpty()) {
|
||||||
|
return getActions(context.resources).take(4)
|
||||||
|
}
|
||||||
|
return actionList
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getActionFromPreference(resources: Resources, sharedPrefs: SharedPreferences, index: Int): Action? {
|
||||||
|
val actionPref = sharedPrefs.getString(preferencePrefix + index, "none")
|
||||||
|
return getActions(resources).find { action -> action.settingName == actionPref }
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun setDefaultSettings(sharedPrefs: SharedPreferences) {
|
||||||
|
val defaults = getDefaultConfig()
|
||||||
|
val firstKey = defaults.firstNotNullOf { settings -> settings.key }
|
||||||
|
if (!sharedPrefs.contains(firstKey)) {
|
||||||
|
val editor = sharedPrefs.edit()
|
||||||
|
for ((key, value) in defaults) {
|
||||||
|
editor.putString(key, value)
|
||||||
|
}
|
||||||
|
editor.apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,61 +1,64 @@
|
||||||
package info.nightscout.androidaps.tile
|
package info.nightscout.androidaps.tile
|
||||||
|
|
||||||
|
import android.content.res.Resources
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.interaction.actions.BackgroundActionActivity
|
||||||
import info.nightscout.androidaps.interaction.actions.TempTargetActivity
|
import info.nightscout.androidaps.interaction.actions.TempTargetActivity
|
||||||
|
|
||||||
object TempTargetSource : TileSource {
|
object TempTargetSource : StaticTileSource(), TileSource {
|
||||||
|
override val preferencePrefix= "tile_tempt_"
|
||||||
|
|
||||||
override fun getActions(): List<Action> {
|
override fun getActions(resources: Resources): List<StaticAction> {
|
||||||
|
val message = resources.getString(R.string.action_tempt_confirmation)
|
||||||
return listOf(
|
return listOf(
|
||||||
Action(
|
StaticAction(
|
||||||
id = 0,
|
|
||||||
settingName = "activity",
|
settingName = "activity",
|
||||||
nameRes = R.string.temp_target_activity,
|
buttonText = resources.getString(R.string.temp_target_activity),
|
||||||
iconRes = R.drawable.ic_target_activity,
|
iconRes = R.drawable.ic_target_activity,
|
||||||
activityClass = TempTargetActivity::class.java.name,
|
activityClass = BackgroundActionActivity::class.java.name,
|
||||||
background = true,
|
message = message,
|
||||||
// actionString = "temptarget false 90 8.0 8.0",
|
// actionString = "temptarget false 90 8.0 8.0",
|
||||||
actionString = "temptarget preset activity",
|
actionString = "temptarget preset activity",
|
||||||
),
|
),
|
||||||
Action(
|
StaticAction(
|
||||||
id = 1,
|
|
||||||
settingName = "eating_soon",
|
settingName = "eating_soon",
|
||||||
nameRes = R.string.temp_target_eating_soon,
|
buttonText = resources.getString(R.string.temp_target_eating_soon),
|
||||||
iconRes = R.drawable.ic_target_eatingsoon,
|
iconRes = R.drawable.ic_target_eatingsoon,
|
||||||
activityClass = TempTargetActivity::class.java.name,
|
activityClass = BackgroundActionActivity::class.java.name,
|
||||||
background = true,
|
message = message,
|
||||||
// actionString = "temptarget false 45 4.5 4.5",
|
// actionString = "temptarget false 45 4.5 4.5",
|
||||||
actionString = "temptarget preset eating",
|
actionString = "temptarget preset eating",
|
||||||
),
|
),
|
||||||
Action(
|
StaticAction(
|
||||||
id = 2,
|
|
||||||
settingName = "hypo",
|
settingName = "hypo",
|
||||||
nameRes = R.string.temp_target_hypo,
|
buttonText = resources.getString(R.string.temp_target_hypo),
|
||||||
iconRes = R.drawable.ic_target_hypo,
|
iconRes = R.drawable.ic_target_hypo,
|
||||||
activityClass = TempTargetActivity::class.java.name,
|
activityClass = BackgroundActionActivity::class.java.name,
|
||||||
background = true,
|
message = message,
|
||||||
// actionString = "temptarget false 45 7.0 7.0",
|
// actionString = "temptarget false 45 7.0 7.0",
|
||||||
actionString = "temptarget preset hypo",
|
actionString = "temptarget preset hypo",
|
||||||
),
|
),
|
||||||
Action(
|
StaticAction(
|
||||||
id = 3,
|
|
||||||
settingName = "manual",
|
settingName = "manual",
|
||||||
nameRes = R.string.temp_target_manual,
|
buttonText = resources.getString(R.string.temp_target_manual),
|
||||||
iconRes = R.drawable.ic_target_manual,
|
iconRes = R.drawable.ic_target_manual,
|
||||||
activityClass = TempTargetActivity::class.java.name,
|
activityClass = TempTargetActivity::class.java.name,
|
||||||
),
|
),
|
||||||
Action(
|
StaticAction(
|
||||||
id = 4,
|
|
||||||
settingName = "cancel",
|
settingName = "cancel",
|
||||||
nameRes = R.string.generic_cancel,
|
buttonText = resources.getString(R.string.generic_cancel),
|
||||||
iconRes = R.drawable.ic_target_cancel,
|
iconRes = R.drawable.ic_target_cancel,
|
||||||
activityClass = TempTargetActivity::class.java.name,
|
activityClass = BackgroundActionActivity::class.java.name,
|
||||||
|
message = message,
|
||||||
actionString = "temptarget cancel",
|
actionString = "temptarget cancel",
|
||||||
background = true,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getResourceReferences(resources: Resources): List<Int> {
|
||||||
|
return getActions(resources).map { it.iconRes }
|
||||||
|
}
|
||||||
|
|
||||||
override fun getDefaultConfig(): Map<String, String> {
|
override fun getDefaultConfig(): Map<String, String> {
|
||||||
return mapOf(
|
return mapOf(
|
||||||
"tile_tempt_1" to "activity",
|
"tile_tempt_1" to "activity",
|
||||||
|
|
|
@ -2,9 +2,7 @@ package info.nightscout.androidaps.tile
|
||||||
|
|
||||||
class TempTargetTileService : TileBase() {
|
class TempTargetTileService : TileBase() {
|
||||||
|
|
||||||
override val preferencePrefix = "tile_tempt_"
|
override val resourceVersion = "TempTargetTileService"
|
||||||
override val resourceVersion = "1"
|
|
||||||
override val idIconActionPrefix = "ic_tempt_"
|
|
||||||
override val source = TempTargetSource;
|
override val source = TempTargetSource;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
package info.nightscout.androidaps.tile
|
package info.nightscout.androidaps.tile
|
||||||
|
|
||||||
import android.content.SharedPreferences
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.wear.tiles.ActionBuilders
|
import androidx.wear.tiles.ActionBuilders
|
||||||
|
@ -42,18 +43,17 @@ private const val LARGE_SCREEN_WIDTH_DP = 210
|
||||||
|
|
||||||
interface TileSource {
|
interface TileSource {
|
||||||
|
|
||||||
fun getActions(): List<Action>
|
fun getResourceReferences(resources: android.content.res.Resources): List<Int>
|
||||||
fun getDefaultConfig(): Map<String, String>
|
fun getSelectedActions(context: Context): List<Action>
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Action(
|
open class Action(
|
||||||
val id: Int,
|
val buttonText: String,
|
||||||
val settingName: String,
|
val buttonTextSub: String? = null,
|
||||||
@StringRes val nameRes: Int,
|
|
||||||
val activityClass: String,
|
val activityClass: String,
|
||||||
@DrawableRes val iconRes: Int,
|
@DrawableRes val iconRes: Int,
|
||||||
val background: Boolean = false,
|
|
||||||
val actionString: String? = null,
|
val actionString: String? = null,
|
||||||
|
val message: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class WearControl {
|
enum class WearControl {
|
||||||
|
@ -62,10 +62,7 @@ enum class WearControl {
|
||||||
|
|
||||||
abstract class TileBase : TileService() {
|
abstract class TileBase : TileService() {
|
||||||
|
|
||||||
open val resourceVersion = "1"
|
abstract val resourceVersion: String
|
||||||
open val idIconActionPrefix = "ic_action_"
|
|
||||||
|
|
||||||
abstract val preferencePrefix: String
|
|
||||||
abstract val source: TileSource
|
abstract val source: TileSource
|
||||||
|
|
||||||
private val serviceJob = Job()
|
private val serviceJob = Job()
|
||||||
|
@ -89,19 +86,25 @@ abstract class TileBase : TileService() {
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getSelectedActions(): List<Action> {
|
||||||
|
// TODO check why thi scan not be don in scope of the coroutine
|
||||||
|
return source.getSelectedActions(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
override fun onResourcesRequest(
|
override fun onResourcesRequest(
|
||||||
requestParams: ResourcesRequest
|
requestParams: ResourcesRequest
|
||||||
): ListenableFuture<Resources> = serviceScope.future {
|
): ListenableFuture<Resources> = serviceScope.future {
|
||||||
Resources.Builder()
|
Resources.Builder()
|
||||||
.setVersion(resourceVersion)
|
.setVersion(resourceVersion)
|
||||||
.apply {
|
.apply {
|
||||||
source.getActions().mapNotNull { action ->
|
source.getResourceReferences(resources).forEach { resourceId ->
|
||||||
addIdToImageMapping(
|
addIdToImageMapping(
|
||||||
idIconActionPrefix + action.id,
|
resourceId.toString(),
|
||||||
ImageResource.Builder()
|
ImageResource.Builder()
|
||||||
.setAndroidResourceByResId(
|
.setAndroidResourceByResId(
|
||||||
AndroidImageResourceByResId.Builder()
|
AndroidImageResourceByResId.Builder()
|
||||||
.setResourceId(action.iconRes)
|
.setResourceId(resourceId)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
|
@ -157,15 +160,17 @@ abstract class TileBase : TileService() {
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
private fun doAction(action: Action): ActionBuilders.Action {
|
private fun doAction(action: Action): ActionBuilders.Action {
|
||||||
val inBackground = ActionBuilders.AndroidBooleanExtra.Builder().setValue(action.background).build()
|
|
||||||
val builder = ActionBuilders.AndroidActivity.Builder()
|
val builder = ActionBuilders.AndroidActivity.Builder()
|
||||||
.setClassName(action.activityClass)
|
.setClassName(action.activityClass)
|
||||||
.setPackageName(this.packageName)
|
.setPackageName(this.packageName)
|
||||||
.addKeyToExtraMapping("inBackground", inBackground)
|
|
||||||
if (action.actionString != null) {
|
if (action.actionString != null) {
|
||||||
val actionString = ActionBuilders.AndroidStringExtra.Builder().setValue(action.actionString).build()
|
val actionString = ActionBuilders.AndroidStringExtra.Builder().setValue(action.actionString).build()
|
||||||
builder.addKeyToExtraMapping("actionString", actionString)
|
builder.addKeyToExtraMapping("actionString", actionString)
|
||||||
}
|
}
|
||||||
|
if (action.message != null) {
|
||||||
|
val message = ActionBuilders.AndroidStringExtra.Builder().setValue(action.message).build()
|
||||||
|
builder.addKeyToExtraMapping("message", message)
|
||||||
|
}
|
||||||
|
|
||||||
return ActionBuilders.LaunchAction.Builder()
|
return ActionBuilders.LaunchAction.Builder()
|
||||||
.setAndroidActivity(builder.build())
|
.setAndroidActivity(builder.build())
|
||||||
|
@ -174,8 +179,8 @@ abstract class TileBase : TileService() {
|
||||||
|
|
||||||
private fun action(action: Action, deviceParameters: DeviceParameters): LayoutElement {
|
private fun action(action: Action, deviceParameters: DeviceParameters): LayoutElement {
|
||||||
val circleDiameter = circleDiameter(deviceParameters)
|
val circleDiameter = circleDiameter(deviceParameters)
|
||||||
val iconSize = dp(circleDiameter * ICON_SIZE_FRACTION)
|
val text = action.buttonText
|
||||||
val text = resources.getString(action.nameRes)
|
val textSub = action.buttonTextSub
|
||||||
return Box.Builder()
|
return Box.Builder()
|
||||||
.setWidth(dp(circleDiameter))
|
.setWidth(dp(circleDiameter))
|
||||||
.setHeight(dp(circleDiameter))
|
.setHeight(dp(circleDiameter))
|
||||||
|
@ -193,7 +198,7 @@ abstract class TileBase : TileService() {
|
||||||
)
|
)
|
||||||
.setSemantics(
|
.setSemantics(
|
||||||
Semantics.Builder()
|
Semantics.Builder()
|
||||||
.setContentDescription(text)
|
.setContentDescription("$text $textSub")
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.setClickable(
|
.setClickable(
|
||||||
|
@ -203,32 +208,55 @@ abstract class TileBase : TileService() {
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
)
|
)
|
||||||
.addContent(
|
.addContent(addTextContent(action, deviceParameters))
|
||||||
Column.Builder()
|
|
||||||
.addContent(
|
|
||||||
Image.Builder()
|
|
||||||
.setWidth(iconSize)
|
|
||||||
.setHeight(iconSize)
|
|
||||||
.setResourceId(idIconActionPrefix + action.id)
|
|
||||||
.build()
|
|
||||||
).addContent(
|
|
||||||
Text.Builder()
|
|
||||||
.setText(text)
|
|
||||||
.setFontStyle(
|
|
||||||
FontStyle.Builder()
|
|
||||||
.setWeight(FONT_WEIGHT_BOLD)
|
|
||||||
.setColor(
|
|
||||||
argb(ContextCompat.getColor(baseContext, R.color.white))
|
|
||||||
)
|
|
||||||
.setSize(buttonTextSize(deviceParameters, text))
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
).build()
|
|
||||||
)
|
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addTextContent(action: Action, deviceParameters: DeviceParameters): LayoutElement {
|
||||||
|
val circleDiameter = circleDiameter(deviceParameters)
|
||||||
|
val iconSize = dp(circleDiameter * ICON_SIZE_FRACTION)
|
||||||
|
val text = action.buttonText
|
||||||
|
val textSub = action.buttonTextSub
|
||||||
|
val col = Column.Builder()
|
||||||
|
.addContent(
|
||||||
|
Image.Builder()
|
||||||
|
.setWidth(iconSize)
|
||||||
|
.setHeight(iconSize)
|
||||||
|
.setResourceId(action.iconRes.toString())
|
||||||
|
.build()
|
||||||
|
).addContent(
|
||||||
|
Text.Builder()
|
||||||
|
.setText(text)
|
||||||
|
.setFontStyle(
|
||||||
|
FontStyle.Builder()
|
||||||
|
.setWeight(FONT_WEIGHT_BOLD)
|
||||||
|
.setColor(
|
||||||
|
argb(ContextCompat.getColor(baseContext, R.color.white))
|
||||||
|
)
|
||||||
|
.setSize(buttonTextSize(deviceParameters, text))
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
if (textSub != null) {
|
||||||
|
col.addContent(
|
||||||
|
Text.Builder()
|
||||||
|
.setText(textSub)
|
||||||
|
.setFontStyle(
|
||||||
|
FontStyle.Builder()
|
||||||
|
.setColor(
|
||||||
|
argb(ContextCompat.getColor(baseContext, R.color.white))
|
||||||
|
)
|
||||||
|
.setSize(buttonTextSize(deviceParameters, textSub))
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return col.build()
|
||||||
|
}
|
||||||
|
|
||||||
private fun circleDiameter(deviceParameters: DeviceParameters) = when (deviceParameters.screenShape) {
|
private fun circleDiameter(deviceParameters: DeviceParameters) = when (deviceParameters.screenShape) {
|
||||||
SCREEN_SHAPE_ROUND -> ((sqrt(2f) - 1) * deviceParameters.screenHeightDp) - (2 * SPACING_ACTIONS)
|
SCREEN_SHAPE_ROUND -> ((sqrt(2f) - 1) * deviceParameters.screenHeightDp) - (2 * SPACING_ACTIONS)
|
||||||
else -> 0.5f * deviceParameters.screenHeightDp - SPACING_ACTIONS
|
else -> 0.5f * deviceParameters.screenHeightDp - SPACING_ACTIONS
|
||||||
|
@ -257,37 +285,4 @@ abstract class TileBase : TileService() {
|
||||||
return WearControl.DISABLED
|
return WearControl.DISABLED
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSelectedActions(): List<Action> {
|
|
||||||
val sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this)
|
|
||||||
setDefaultSettings(sharedPrefs)
|
|
||||||
|
|
||||||
val actionList: MutableList<Action> = mutableListOf()
|
|
||||||
for (i in 1..4) {
|
|
||||||
val action = getActionFromPreference(sharedPrefs, i)
|
|
||||||
if (action != null) {
|
|
||||||
actionList.add(action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (actionList.isEmpty()) {
|
|
||||||
return source.getActions().take(4)
|
|
||||||
}
|
|
||||||
return actionList
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getActionFromPreference(sharedPrefs: SharedPreferences, index: Int): Action? {
|
|
||||||
val actionPref = sharedPrefs.getString(preferencePrefix + index, "none")
|
|
||||||
return source.getActions().find { action -> action.settingName == actionPref }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun setDefaultSettings(sharedPrefs: SharedPreferences) {
|
|
||||||
val defaults = source.getDefaultConfig()
|
|
||||||
val firstKey = defaults.firstNotNullOf { settings -> settings.key }
|
|
||||||
if (!sharedPrefs.contains(firstKey)) {
|
|
||||||
val editor = sharedPrefs.edit()
|
|
||||||
for ((key, value) in defaults) {
|
|
||||||
editor.putString(key, value)
|
|
||||||
}
|
|
||||||
editor.apply()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -1,7 +1,6 @@
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:width="24dp"
|
android:width="24dp"
|
||||||
android:height="24dp"
|
android:height="24dp"
|
||||||
android:tint="?attr/colorControlNormal"
|
|
||||||
android:viewportWidth="6.35"
|
android:viewportWidth="6.35"
|
||||||
android:viewportHeight="6.3500004">
|
android:viewportHeight="6.3500004">
|
||||||
<path
|
<path
|
||||||
|
|
12
wear/src/main/res/drawable/ic_quick_wizard.xml
Normal file
12
wear/src/main/res/drawable/ic_quick_wizard.xml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<vector
|
||||||
|
android:height="48dp"
|
||||||
|
android:width="48dp"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FEAF05" android:pathData="M10.751,6.59c-0.561,0.69 -0.796,1.057 -1.25,1.797c-2.517,0.238 -3.932,2.751 -3.379,4.664c0.244,0.843 0.779,1.476 1.498,1.958c2.348,1.573 6.243,1.429 8.487,-0.306c1.187,-0.918 1.723,-2.084 1.334,-3.576c-0.412,-1.58 -1.445,-2.585 -3.039,-2.87c-1.112,-0.199 -1.973,0.37 -2.558,1.313c-0.494,0.796 -0.72,1.616 -1.628,2.345c-0.389,-0.431 -0.458,-0.961 -0.483,-1.481c-0.12,-2.486 2.019,-4.439 4.595,-4.213c2.365,0.207 4.466,1.956 5.114,4.256c0.611,2.172 -0.226,4.432 -2.19,5.909c-2.995,2.253 -7.895,2.327 -10.943,0.165c-2.057,-1.459 -2.88,-3.881 -2.099,-6.18C5.023,7.978 7.368,6.304 9.77,6.4C10.072,6.412 10.365,6.459 10.751,6.59z"/>
|
||||||
|
<path android:fillColor="#FEAF06" android:pathData="M7.141,13.406c0.526,-0.103 1.178,-0.22 1.665,-0.322c1.522,-0.319 2.625,-1.229 3.273,-2.678c0.289,-0.647 0.702,-1.125 1.448,-1.42c0.418,0.811 0.454,1.641 0.223,2.493c-0.284,1.049 -0.889,1.863 -1.819,2.429c-0.616,0.376 -1.284,0.638 -1.966,0.867C8.814,15.163 7.797,14.773 7.141,13.406z"/>
|
||||||
|
<path android:fillColor="#FEAF06" android:pathData="M12.313,14.203c0.734,-0.537 1.25,-1.089 1.469,-1.612c0.894,0.159 1.92,0.314 2.804,0.471C16.036,14.799 13.922,15.203 12.313,14.203z"/>
|
||||||
|
<path android:fillColor="#FEAF06" android:pathData="M2.377,13.882c0.179,-0.123 0.756,-0.189 1.192,-0.123c0.259,0.631 0.587,1.225 1.108,1.923c-0.572,0.116 -1.037,0.253 -1.567,0.224c-0.493,-0.027 -0.993,-0.353 -1.063,-0.989C2.013,14.61 2.047,14.109 2.377,13.882z"/>
|
||||||
|
<path android:fillColor="#FEAF06" android:pathData="M19.143,15.22c0.196,-0.497 0.362,-0.961 0.561,-1.411c0.235,-0.531 0.618,-0.76 1.121,-0.681c0.419,0.066 0.575,0.376 0.644,0.756c0.098,0.541 -0.078,0.989 -0.529,1.213C20.38,15.377 19.787,15.293 19.143,15.22z"/>
|
||||||
|
</vector>
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
<string name="label_actions_tile">AAPS(Actions)</string>
|
<string name="label_actions_tile">AAPS(Actions)</string>
|
||||||
<string name="label_temp_target_tile">AAPS(Temp Target)</string>
|
<string name="label_temp_target_tile">AAPS(Temp Target)</string>
|
||||||
|
<string name="label_quick_wizard_tile">AAPS(Quick Wizard)</string>
|
||||||
|
|
||||||
<string name="label_warning_sync">No data!</string>
|
<string name="label_warning_sync">No data!</string>
|
||||||
<string name="label_warning_old">Old data!</string>
|
<string name="label_warning_old">Old data!</string>
|
||||||
|
@ -86,9 +87,11 @@
|
||||||
<string name="menu_none">None</string>
|
<string name="menu_none">None</string>
|
||||||
<string name="menu_default">Default</string>
|
<string name="menu_default">Default</string>
|
||||||
<string name="menu_menu">Menu</string>
|
<string name="menu_menu">Menu</string>
|
||||||
|
<string name="quick_wizard_short">XL</string>
|
||||||
|
|
||||||
<string name="action_duration">Duration</string>
|
<string name="action_duration">Duration</string>
|
||||||
<string name="action_tempt_confirmation">Temp Target Requested</string>
|
<string name="action_tempt_confirmation">Temp Target Requested</string>
|
||||||
|
<string name="action_quick_wizard_confirmation">Quick Wizard Requested</string>
|
||||||
<string name="action_treatment_confirmation">Treatment Requested</string>
|
<string name="action_treatment_confirmation">Treatment Requested</string>
|
||||||
<string name="action_bolus_confirmation">Bolus Requested</string>
|
<string name="action_bolus_confirmation">Bolus Requested</string>
|
||||||
<string name="action_wizard_confirmation">Calculation Requested</string>
|
<string name="action_wizard_confirmation">Calculation Requested</string>
|
||||||
|
@ -165,7 +168,7 @@
|
||||||
<string name="bolus_progress_silent_channel_name">AAPS Bolus Progress Silent</string>
|
<string name="bolus_progress_silent_channel_name">AAPS Bolus Progress Silent</string>
|
||||||
<string name="bolus_progress_channel_description">Bolus progress and cancel</string>
|
<string name="bolus_progress_channel_description">Bolus progress and cancel</string>
|
||||||
<string name="bolus_progress_silent_channel_description">Bolus progress and cancel with less vibrations</string>
|
<string name="bolus_progress_silent_channel_description">Bolus progress and cancel with less vibrations</string>
|
||||||
|
<string name="key_quickwizard" translatable="false">QuickWizard</string>
|
||||||
<string name="key_wear_control" translatable="false">wearcontrol</string>
|
<string name="key_wear_control" translatable="false">wearcontrol</string>
|
||||||
<string name="key_units_mgdl" translatable="false">units_mgdl</string>
|
<string name="key_units_mgdl" translatable="false">units_mgdl</string>
|
||||||
<string name="key_boluswizard_percentage" translatable="false">boluswizard_percentage</string>
|
<string name="key_boluswizard_percentage" translatable="false">boluswizard_percentage</string>
|
||||||
|
@ -182,5 +185,6 @@
|
||||||
<string name="tile_no_config">No config available</string>
|
<string name="tile_no_config">No config available</string>
|
||||||
<string name="wear_control_not_enabled">Wear controls disabled</string>
|
<string name="wear_control_not_enabled">Wear controls disabled</string>
|
||||||
<string name="wear_control_no_data">No data available</string>
|
<string name="wear_control_no_data">No data available</string>
|
||||||
|
<string name="key_quick_wizard_data_map" translatable="false">quick_wizard_data_map</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue