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
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.ItemTouchHelper.*
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import info.nightscout.androidaps.R
|
||||
|
@ -20,6 +26,8 @@ import info.nightscout.androidaps.utils.FabricPrivacy
|
|||
import io.reactivex.rxkotlin.plusAssign
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
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 javax.inject.Inject
|
||||
|
||||
|
@ -30,20 +38,95 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
|||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var quickWizard: QuickWizard
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var sp: SP
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
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>() {
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
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) {
|
||||
holder.from.text = dateUtil.timeString(quickWizard[position].validFromDate())
|
||||
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.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 carbs: TextView = itemView.findViewById(R.id.overview_quickwizard_item_carbs)
|
||||
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)
|
||||
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)
|
||||
|
@ -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?) {
|
||||
|
@ -84,6 +179,7 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
|||
binding.recyclerview.setHasFixedSize(true)
|
||||
binding.recyclerview.layoutManager = LinearLayoutManager(this)
|
||||
binding.recyclerview.adapter = RecyclerViewAdapter(supportFragmentManager)
|
||||
itemTouchHelper.attachToRecyclerView(binding.recyclerview)
|
||||
|
||||
binding.addButton.setOnClickListener {
|
||||
val manager = supportFragmentManager
|
||||
|
@ -98,13 +194,13 @@ class QuickWizardListActivity : NoSplashAppCompatActivity() {
|
|||
.toObservable(EventQuickWizardChange::class.java)
|
||||
.observeOn(aapsSchedulers.main)
|
||||
.subscribe({
|
||||
val adapter = RecyclerViewAdapter(supportFragmentManager)
|
||||
binding.recyclerview.swapAdapter(adapter, false)
|
||||
}, fabricPrivacy::logException)
|
||||
val adapter = RecyclerViewAdapter(supportFragmentManager)
|
||||
binding.recyclerview.swapAdapter(adapter, false)
|
||||
}, fabricPrivacy::logException)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
disposable.clear()
|
||||
super.onPause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import android.view.ViewGroup
|
|||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import dagger.android.support.DaggerDialogFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.databinding.OverviewEditquickwizardDialogBinding
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
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.wizard.QuickWizard
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import org.json.JSONException
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -30,6 +32,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
|||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var quickWizard: QuickWizard
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var sp: SP
|
||||
|
||||
var position = -1
|
||||
|
||||
|
@ -57,6 +60,14 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
|||
position = bundle.getInt("position", -1)
|
||||
}
|
||||
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 {
|
||||
try {
|
||||
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("useCOB", binding.useCob.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("useTrend", binding.useTrend.selectedItemPosition)
|
||||
entry.storage.put("useSuperBolus", binding.useSuperBolus.selectedItemPosition)
|
||||
|
@ -122,6 +134,7 @@ class EditQuickWizardDialog : DaggerDialogFragment(), View.OnClickListener {
|
|||
binding.useCob.setSelection(entry.useCOB())
|
||||
binding.useBolusIob.setSelection(entry.useBolusIOB())
|
||||
binding.useBasalIob.setSelection(entry.useBasalIOB())
|
||||
binding.device.setSelection(entry.device())
|
||||
binding.useTrend.setSelection(entry.useTrend())
|
||||
binding.useSuperBolus.setSelection(entry.useSuperBolus())
|
||||
binding.useTempTarget.setSelection(entry.useTempTarget())
|
||||
|
|
|
@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.general.wear
|
|||
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
|
@ -39,6 +40,7 @@ import info.nightscout.androidaps.utils.resources.ResourceHelper
|
|||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.androidaps.utils.wizard.BolusWizard
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||
import info.nightscout.shared.SafeParse
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
|
@ -71,6 +73,7 @@ class ActionStringHandler @Inject constructor(
|
|||
private val activePlugin: ActivePlugin,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
private val localInsightPlugin: LocalInsightPlugin,
|
||||
private val quickWizard: QuickWizard,
|
||||
private val danaRPlugin: DanaRPlugin,
|
||||
private val danaRKoreanPlugin: DanaRKoreanPlugin,
|
||||
private val danaRv2Plugin: DanaRv2Plugin,
|
||||
|
@ -144,34 +147,39 @@ class ActionStringHandler @Inject constructor(
|
|||
}
|
||||
rAction += "bolus $insulinAfterConstraints $carbsAfterConstraints"
|
||||
} else if ("temptarget" == act[0]) { ///////////////////////////////////////////////////////// TEMPTARGET
|
||||
aapsLogger.info(LTag.WEAR, "temptarget received:" + act)
|
||||
aapsLogger.info(LTag.WEAR, "temptarget received: $act")
|
||||
if ("cancel" == act[1]) {
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_cancel_message)
|
||||
rAction = "temptarget true 0 0 0"
|
||||
} else if ("preset" == act[1]) {
|
||||
val presetIsMGDL = profileFunction.getUnits() == GlucoseUnit.MGDL
|
||||
val preset = act[2]
|
||||
if ("activity" == preset) {
|
||||
val activityTTDuration = defaultValueHelper.determineActivityTTDuration()
|
||||
val activityTT = defaultValueHelper.determineActivityTT()
|
||||
val reason = rh.gs(R.string.activity)
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, activityTT, activityTTDuration)
|
||||
rAction = "temptarget $presetIsMGDL $activityTTDuration $activityTT $activityTT"
|
||||
} else if ("hypo" == preset) {
|
||||
val hypoTTDuration = defaultValueHelper.determineHypoTTDuration()
|
||||
val hypoTT = defaultValueHelper.determineHypoTT()
|
||||
val reason = rh.gs(R.string.hypo)
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, hypoTT, hypoTTDuration)
|
||||
rAction = "temptarget $presetIsMGDL $hypoTTDuration $hypoTT $hypoTT"
|
||||
} else if ("eating" == preset) {
|
||||
val eatingSoonTTDuration = defaultValueHelper.determineEatingSoonTTDuration()
|
||||
val eatingSoonTT = defaultValueHelper.determineEatingSoonTT()
|
||||
val reason = rh.gs(R.string.eatingsoon)
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, eatingSoonTT, eatingSoonTTDuration)
|
||||
rAction = "temptarget $presetIsMGDL $eatingSoonTTDuration $eatingSoonTT $eatingSoonTT"
|
||||
} else {
|
||||
sendError(rh.gs(R.string.wear_action_tempt_preset_error, preset))
|
||||
return
|
||||
when (preset) {
|
||||
"activity" -> {
|
||||
val activityTTDuration = defaultValueHelper.determineActivityTTDuration()
|
||||
val activityTT = defaultValueHelper.determineActivityTT()
|
||||
val reason = rh.gs(R.string.activity)
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, activityTT, activityTTDuration)
|
||||
rAction = "temptarget $presetIsMGDL $activityTTDuration $activityTT $activityTT"
|
||||
}
|
||||
"hypo" -> {
|
||||
val hypoTTDuration = defaultValueHelper.determineHypoTTDuration()
|
||||
val hypoTT = defaultValueHelper.determineHypoTT()
|
||||
val reason = rh.gs(R.string.hypo)
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, hypoTT, hypoTTDuration)
|
||||
rAction = "temptarget $presetIsMGDL $hypoTTDuration $hypoTT $hypoTT"
|
||||
}
|
||||
"eating" -> {
|
||||
val eatingSoonTTDuration = defaultValueHelper.determineEatingSoonTTDuration()
|
||||
val eatingSoonTT = defaultValueHelper.determineEatingSoonTT()
|
||||
val reason = rh.gs(R.string.eatingsoon)
|
||||
rMessage += rh.gs(R.string.wear_action_tempt_preset_message, reason, eatingSoonTT, eatingSoonTTDuration)
|
||||
rAction = "temptarget $presetIsMGDL $eatingSoonTTDuration $eatingSoonTT $eatingSoonTT"
|
||||
}
|
||||
else -> {
|
||||
sendError(rh.gs(R.string.wear_action_tempt_preset_error, preset))
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val isMGDL = java.lang.Boolean.parseBoolean(act[1])
|
||||
|
@ -281,6 +289,34 @@ class ActionStringHandler @Inject constructor(
|
|||
rMessage += "\nPercentage: " + format.format(bolusWizard.totalBeforePercentageAdjustment) + "U * " + percentage + "% -> ~" + format.format(bolusWizard.calculatedTotalInsulin) + "U"
|
||||
}
|
||||
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]) {
|
||||
val activeProfileSwitch = repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet()
|
||||
if (activeProfileSwitch is ValueWrapper.Existing) { // read CPP values
|
||||
|
@ -364,7 +400,10 @@ class ActionStringHandler @Inject constructor(
|
|||
rAction = "cancelChangeRequest"
|
||||
wearPlugin.requestNotificationCancel(rAction)
|
||||
return
|
||||
} else return
|
||||
} else {
|
||||
sendError("Unknown action command: " + act[0] )
|
||||
return
|
||||
}
|
||||
// send result
|
||||
wearPlugin.requestActionConfirmation(rTitle, rMessage, rAction)
|
||||
lastSentTimestamp = System.currentTimeMillis()
|
||||
|
@ -698,4 +737,4 @@ class ActionStringHandler @Inject constructor(
|
|||
lastConfirmActionString = null
|
||||
lastBolusWizard = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ import info.nightscout.androidaps.interfaces.Loop;
|
|||
import info.nightscout.androidaps.interfaces.PluginBase;
|
||||
import info.nightscout.androidaps.interfaces.Profile;
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction;
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizardEntry;
|
||||
import info.nightscout.shared.logging.AAPSLogger;
|
||||
import info.nightscout.shared.logging.LTag;
|
||||
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.TrendCalculator;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.wizard.QuickWizard;
|
||||
import info.nightscout.shared.sharedPreferences.SP;
|
||||
|
||||
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 Config config;
|
||||
@Inject public TrendCalculator trendCalculator;
|
||||
@Inject public QuickWizard quickWizard;
|
||||
|
||||
public static final String ACTION_RESEND = WatchUpdaterService.class.getName().concat(".Resend");
|
||||
public static final String ACTION_OPEN_SETTINGS = WatchUpdaterService.class.getName().concat(".OpenSettings");
|
||||
|
@ -101,12 +104,14 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
private static final String OPEN_SETTINGS_PATH = "/openwearsettings";
|
||||
private static final String NEW_STATUS_PATH = "/sendstatustowear";
|
||||
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 BOLUS_PROGRESS_PATH = "/nightscout_watch_bolusprogress";
|
||||
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_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest";
|
||||
|
||||
String TAG = "WatchUpdateService";
|
||||
|
||||
private static boolean lastLoopStatus;
|
||||
|
||||
|
@ -156,7 +161,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
String action = intent != null ? intent.getAction() : null;
|
||||
|
||||
// Log.d(TAG, logPrefix + "onStartCommand: " + action);
|
||||
// Log.d(TAG, "onStartCommand: " + action);
|
||||
|
||||
if (wearIntegration()) {
|
||||
handler.post(() -> {
|
||||
|
@ -235,7 +240,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
super.onPeerConnected(peer);
|
||||
String id = peer.getId();
|
||||
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);
|
||||
String id = peer.getId();
|
||||
String name = peer.getDisplayName();
|
||||
// Log.d(TAG, logPrefix + "onPeerDisconnected peer name & ID: " + name + "|" + id);
|
||||
Log.d(TAG, "onPeerDisconnected peer name & ID: " + name + "|" + id);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(MessageEvent event) {
|
||||
|
||||
// Log.d(TAG, logPrefix + "onMessageRecieved: " + event);
|
||||
// Log.d(TAG, "onMessageRecieved: " + event);
|
||||
|
||||
if (wearIntegration()) {
|
||||
if (event != null && event.getPath().equals(WEARABLE_RESEND_PATH)) {
|
||||
|
@ -283,7 +288,7 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
private void sendData() {
|
||||
|
||||
GlucoseValue lastBG = iobCobCalculator.getAds().lastBg();
|
||||
// Log.d(TAG, logPrefix + "LastBg=" + lastBG);
|
||||
// Log.d(TAG, "LastBg=" + lastBG);
|
||||
if (lastBG != null) {
|
||||
GlucoseStatus glucoseStatus = glucoseStatusProvider.getGlucoseStatusData();
|
||||
|
||||
|
@ -364,6 +369,10 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
if (googleApiClient != null && !googleApiClient.isConnected() && !googleApiClient.isConnecting()) {
|
||||
googleApiConnect();
|
||||
}
|
||||
|
||||
sendPreferences();
|
||||
sendQuickWizard();
|
||||
|
||||
long startTime = System.currentTimeMillis() - (long) (60000 * 60 * 5.5);
|
||||
GlucoseValue last_bg = iobCobCalculator.getAds().lastBg();
|
||||
|
||||
|
@ -382,7 +391,6 @@ public class WatchUpdaterService extends WearableListenerService implements Goog
|
|||
entries.putDataMapArrayList("entries", dataMaps);
|
||||
(new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient)).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, entries);
|
||||
}
|
||||
sendPreferences();
|
||||
sendBasals();
|
||||
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
|
||||
private String generateStatusString(Profile profile, String currentBasal, String iobSum, String iobDetail, String bgiString) {
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package info.nightscout.androidaps.utils.wizard
|
||||
|
||||
import android.util.Log
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -18,6 +20,18 @@ class QuickWizard @Inject constructor(
|
|||
|
||||
init {
|
||||
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? {
|
||||
|
@ -41,6 +55,38 @@ class QuickWizard @Inject constructor(
|
|||
operator fun get(position: Int): QuickWizardEntry =
|
||||
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 {
|
||||
return QuickWizardEntry(injector)
|
||||
}
|
||||
|
@ -57,4 +103,5 @@ class QuickWizard @Inject constructor(
|
|||
storage.remove(position)
|
||||
save()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import info.nightscout.androidaps.utils.JsonHelper.safeGetString
|
|||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
|
||||
class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjector) {
|
||||
|
@ -41,11 +42,15 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
|
|||
const val NO = 1
|
||||
private const val POSITIVE_ONLY = 2
|
||||
private const val NEGATIVE_ONLY = 3
|
||||
const val DEVICE_ALL = 0
|
||||
const val DEVICE_PHONE = 1
|
||||
const val DEVICE_WATCH = 2
|
||||
}
|
||||
|
||||
init {
|
||||
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 {
|
||||
storage = JSONObject(emptyData)
|
||||
} catch (e: JSONException) {
|
||||
|
@ -55,6 +60,8 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
|
|||
|
||||
/*
|
||||
{
|
||||
guid: string,
|
||||
device: string, // (phone, watch, all)
|
||||
buttonText: "Meal",
|
||||
carbs: 36,
|
||||
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 {
|
||||
// TODO set guid if missing for migration
|
||||
storage = entry
|
||||
this.position = position
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
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 carbs(): Int = safeGetInt(storage, "carbs")
|
||||
|
@ -148,4 +162,4 @@ class QuickWizardEntry @Inject constructor(private val injector: HasAndroidInjec
|
|||
fun useSuperBolus(): Int = safeGetInt(storage, "useSuperBolus", NO)
|
||||
|
||||
fun useTempTarget(): Int = safeGetInt(storage, "useTempTarget", NO)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,6 +108,35 @@
|
|||
|
||||
</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
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -29,37 +29,64 @@
|
|||
card_view:srcCompat="@drawable/ic_quick_wizard" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:baselineAligned="true"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/overview_quickwizard_item_buttonText"
|
||||
<TextView
|
||||
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_height="wrap_content"
|
||||
android:paddingLeft="10dp"
|
||||
android:text="Sample button text"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:textStyle="normal|bold"
|
||||
android:textColor="@color/cardObjectiveText" />
|
||||
android:adjustViewBounds="false"
|
||||
android:cropToPadding="false"
|
||||
android:paddingRight="10dp"
|
||||
android:scaleType="fitStart"
|
||||
card_view:srcCompat="@drawable/ic_smartphone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/overview_quickwizard_item_carbs"
|
||||
<ImageView
|
||||
android:id="@+id/handleView"
|
||||
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" />
|
||||
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:adjustViewBounds="false"
|
||||
android:cropToPadding="false"
|
||||
android:scaleType="fitStart"
|
||||
card_view:srcCompat="@drawable/ic_reorder_gray_24dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -88,9 +115,9 @@
|
|||
android:textStyle="normal|bold" />
|
||||
|
||||
<TextView
|
||||
android:text="-"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content"
|
||||
android:text="-" />
|
||||
|
||||
<TextView
|
||||
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_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="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>
|
||||
|
|
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:pathPrefix="/openwearsettings"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/send_quick_wizard"
|
||||
android:scheme="wear" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/sendstatustowear"
|
||||
|
@ -544,6 +548,20 @@
|
|||
android:resource="@drawable/temp_target_tile_preview" />
|
||||
</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" />
|
||||
|
||||
<activity
|
||||
|
@ -595,6 +613,10 @@
|
|||
android:exported="true"
|
||||
android:label="@string/menu_tempt" />
|
||||
|
||||
<activity
|
||||
android:name=".interaction.actions.BackgroundActionActivity"
|
||||
android:exported="true" />
|
||||
|
||||
<activity android:name=".interaction.ConfigurationActivity">
|
||||
<intent-filter>
|
||||
<!-- 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.SystemClock;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
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.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.DataEvent;
|
||||
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.WearableListenerService;
|
||||
|
||||
import java.util.Set;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
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.CPPActivity;
|
||||
import info.nightscout.androidaps.interaction.utils.Persistence;
|
||||
import info.nightscout.androidaps.interaction.utils.WearUtil;
|
||||
import info.nightscout.androidaps.tile.ActionsTileService;
|
||||
import info.nightscout.androidaps.tile.QuickWizardTileService;
|
||||
import info.nightscout.androidaps.tile.TempTargetTileService;
|
||||
import info.nightscout.shared.SafeParse;
|
||||
import info.nightscout.androidaps.interaction.utils.WearUtil;
|
||||
|
||||
|
||||
/**
|
||||
* Created by emmablack on 12/26/14.
|
||||
|
@ -62,7 +60,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
@Inject WearUtil wearUtil;
|
||||
@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_CANCELBOLUS_PATH = "/nightscout_watch_cancel_bolus";
|
||||
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 NEW_STATUS_PATH = "/sendstatustowear";
|
||||
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 BOLUS_PROGRESS_PATH = "/nightscout_watch_bolusprogress";
|
||||
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 ACTION_CANCELNOTIFICATION_REQUEST_PATH = "/nightscout_watch_cancelnotificationrequest";
|
||||
|
||||
|
||||
public static final int BOLUS_PROGRESS_NOTIF_ID = 1;
|
||||
public static final int CONFIRM_NOTIF_ID = 2;
|
||||
public static final int CHANGE_NOTIF_ID = 556677;
|
||||
|
@ -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_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_BOLUSPROGRESS = "bolus progress vibration";
|
||||
private static final String AAPS_NOTIFY_CHANNEL_ID_BOLUSPROGRESS_SILENT = "bolus progress silent";
|
||||
|
||||
|
||||
GoogleApiClient googleApiClient;
|
||||
private long lastRequest = 0;
|
||||
|
||||
private DismissThread bolusprogressThread;
|
||||
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: "
|
||||
|
||||
// Not derived from DaggerService, do injection here
|
||||
|
@ -120,143 +103,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
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> {
|
||||
Context mContext;
|
||||
|
||||
|
@ -266,8 +112,11 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
|
||||
@Override
|
||||
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()) {
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
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);
|
||||
}
|
||||
|
||||
} 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;
|
||||
}
|
||||
|
@ -303,9 +142,12 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
|
||||
@Override
|
||||
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()) {
|
||||
NodeApi.GetConnectedNodesResult nodes =
|
||||
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());
|
||||
}
|
||||
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
sendData(WEARABLE_RESEND_PATH, null);
|
||||
new ResendDataTask(this).execute();
|
||||
}
|
||||
|
||||
public void cancelBolus() {
|
||||
|
@ -343,59 +205,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
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() {
|
||||
if (googleApiClient != null) {
|
||||
// Remove old listener(s)
|
||||
|
@ -419,20 +228,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
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
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
|
||||
|
@ -486,7 +281,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
return START_STICKY;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDataChanged(DataEventBuffer dataEvents) {
|
||||
|
||||
|
@ -548,10 +342,13 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
String keyControl = getString(R.string.key_wear_control);
|
||||
if (dataMap.containsKey(keyControl)) {
|
||||
boolean previousWearControl = sharedPreferences.getBoolean(keyControl, false);
|
||||
boolean wearControl = dataMap.getBoolean(keyControl, false);
|
||||
editor.putBoolean(keyControl, wearControl);
|
||||
editor.apply();
|
||||
updateTiles();
|
||||
if (wearControl != previousWearControl) {
|
||||
updateTiles();
|
||||
}
|
||||
}
|
||||
String keyPercentage = getString(R.string.key_boluswizard_percentage);
|
||||
if (dataMap.containsKey(keyPercentage)) {
|
||||
|
@ -565,6 +362,26 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
editor.putBoolean(keyUnits, mgdl);
|
||||
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)) {
|
||||
String title = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("title");
|
||||
String message = DataMapItem.fromDataItem(event.getDataItem()).getDataMap().getString("message");
|
||||
|
@ -592,6 +409,9 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
|
||||
TileService.getUpdater(this)
|
||||
.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);
|
||||
|
||||
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)
|
||||
.setContentTitle(getString(R.string.bolus_progress))
|
||||
.setContentText(progresspercent + "% - " + progresstatus)
|
||||
|
@ -723,7 +543,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
bolusprogressThread.start();
|
||||
}
|
||||
|
||||
|
||||
private class DismissThread extends Thread {
|
||||
private final int notificationID;
|
||||
private final int seconds;
|
||||
|
@ -757,7 +576,7 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
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.putExtra("actionstring", actionstring);
|
||||
intent.setAction(ACTION_INITIATE_ACTION);
|
||||
|
@ -780,18 +599,6 @@ public class ListenerService extends WearableListenerService implements GoogleAp
|
|||
public void onConnected(Bundle bundle) {
|
||||
// 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);
|
||||
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
|
||||
public void 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
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (executeInBackground()){
|
||||
return;
|
||||
}
|
||||
|
||||
setAdapter(new MyGridViewPagerAdapter());
|
||||
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
@ -41,21 +39,6 @@ public class TempTargetActivity extends ViewSelectorActivity {
|
|||
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
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.tile
|
||||
|
||||
import android.content.res.Resources
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interaction.actions.BolusActivity
|
||||
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.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(
|
||||
Action(
|
||||
id = 0,
|
||||
StaticAction(
|
||||
settingName = "wizard",
|
||||
nameRes = R.string.menu_wizard_short,
|
||||
buttonText = resources.getString(R.string.menu_wizard_short),
|
||||
iconRes = R.drawable.ic_calculator_green,
|
||||
activityClass = WizardActivity::class.java.name,
|
||||
),
|
||||
Action(
|
||||
id = 1,
|
||||
StaticAction(
|
||||
settingName = "treatment",
|
||||
nameRes = R.string.menu_treatment_short,
|
||||
buttonText = resources.getString(R.string.menu_treatment_short),
|
||||
iconRes = R.drawable.ic_bolus_carbs,
|
||||
activityClass = TreatmentActivity::class.java.name,
|
||||
),
|
||||
Action(
|
||||
id = 2,
|
||||
StaticAction(
|
||||
settingName = "bolus",
|
||||
nameRes = R.string.action_insulin,
|
||||
buttonText = resources.getString(R.string.action_insulin),
|
||||
iconRes = R.drawable.ic_bolus,
|
||||
activityClass = BolusActivity::class.java.name,
|
||||
),
|
||||
Action(
|
||||
id = 3,
|
||||
StaticAction(
|
||||
settingName = "carbs",
|
||||
nameRes = R.string.action_carbs,
|
||||
buttonText = resources.getString(R.string.action_carbs),
|
||||
iconRes = R.drawable.ic_carbs_orange,
|
||||
activityClass = ECarbActivity::class.java.name,
|
||||
),
|
||||
Action(
|
||||
id = 4,
|
||||
StaticAction(
|
||||
settingName = "temp_target",
|
||||
nameRes = R.string.menu_tempt,
|
||||
buttonText = resources.getString(R.string.menu_tempt),
|
||||
iconRes = R.drawable.ic_temptarget_flat,
|
||||
activityClass = TempTargetActivity::class.java.name,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getResourceReferences(resources: Resources): List<Int> {
|
||||
return getActions(resources).map { it.iconRes }
|
||||
}
|
||||
|
||||
override fun getDefaultConfig(): Map<String, String> {
|
||||
return mapOf(
|
||||
"tile_action_1" to "wizard",
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
package info.nightscout.androidaps.tile
|
||||
|
||||
class ActionsTileService : TileBase() {
|
||||
|
||||
override val preferencePrefix = "tile_action_"
|
||||
override val resourceVersion = "1"
|
||||
override val idIconActionPrefix = "ic_action_"
|
||||
override val resourceVersion = "ActionsTileService"
|
||||
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
|
||||
|
||||
import android.content.res.Resources
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interaction.actions.BackgroundActionActivity
|
||||
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(
|
||||
Action(
|
||||
id = 0,
|
||||
StaticAction(
|
||||
settingName = "activity",
|
||||
nameRes = R.string.temp_target_activity,
|
||||
buttonText = resources.getString(R.string.temp_target_activity),
|
||||
iconRes = R.drawable.ic_target_activity,
|
||||
activityClass = TempTargetActivity::class.java.name,
|
||||
background = true,
|
||||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
message = message,
|
||||
// actionString = "temptarget false 90 8.0 8.0",
|
||||
actionString = "temptarget preset activity",
|
||||
),
|
||||
Action(
|
||||
id = 1,
|
||||
StaticAction(
|
||||
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,
|
||||
activityClass = TempTargetActivity::class.java.name,
|
||||
background = true,
|
||||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
message = message,
|
||||
// actionString = "temptarget false 45 4.5 4.5",
|
||||
actionString = "temptarget preset eating",
|
||||
),
|
||||
Action(
|
||||
id = 2,
|
||||
StaticAction(
|
||||
settingName = "hypo",
|
||||
nameRes = R.string.temp_target_hypo,
|
||||
buttonText = resources.getString(R.string.temp_target_hypo),
|
||||
iconRes = R.drawable.ic_target_hypo,
|
||||
activityClass = TempTargetActivity::class.java.name,
|
||||
background = true,
|
||||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
message = message,
|
||||
// actionString = "temptarget false 45 7.0 7.0",
|
||||
actionString = "temptarget preset hypo",
|
||||
),
|
||||
Action(
|
||||
id = 3,
|
||||
StaticAction(
|
||||
settingName = "manual",
|
||||
nameRes = R.string.temp_target_manual,
|
||||
buttonText = resources.getString(R.string.temp_target_manual),
|
||||
iconRes = R.drawable.ic_target_manual,
|
||||
activityClass = TempTargetActivity::class.java.name,
|
||||
),
|
||||
Action(
|
||||
id = 4,
|
||||
StaticAction(
|
||||
settingName = "cancel",
|
||||
nameRes = R.string.generic_cancel,
|
||||
buttonText = resources.getString(R.string.generic_cancel),
|
||||
iconRes = R.drawable.ic_target_cancel,
|
||||
activityClass = TempTargetActivity::class.java.name,
|
||||
activityClass = BackgroundActionActivity::class.java.name,
|
||||
message = message,
|
||||
actionString = "temptarget cancel",
|
||||
background = true,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun getResourceReferences(resources: Resources): List<Int> {
|
||||
return getActions(resources).map { it.iconRes }
|
||||
}
|
||||
|
||||
override fun getDefaultConfig(): Map<String, String> {
|
||||
return mapOf(
|
||||
"tile_tempt_1" to "activity",
|
||||
|
|
|
@ -2,9 +2,7 @@ package info.nightscout.androidaps.tile
|
|||
|
||||
class TempTargetTileService : TileBase() {
|
||||
|
||||
override val preferencePrefix = "tile_tempt_"
|
||||
override val resourceVersion = "1"
|
||||
override val idIconActionPrefix = "ic_tempt_"
|
||||
override val resourceVersion = "TempTargetTileService"
|
||||
override val source = TempTargetSource;
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package info.nightscout.androidaps.tile
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.wear.tiles.ActionBuilders
|
||||
|
@ -42,18 +43,17 @@ private const val LARGE_SCREEN_WIDTH_DP = 210
|
|||
|
||||
interface TileSource {
|
||||
|
||||
fun getActions(): List<Action>
|
||||
fun getDefaultConfig(): Map<String, String>
|
||||
fun getResourceReferences(resources: android.content.res.Resources): List<Int>
|
||||
fun getSelectedActions(context: Context): List<Action>
|
||||
}
|
||||
|
||||
data class Action(
|
||||
val id: Int,
|
||||
val settingName: String,
|
||||
@StringRes val nameRes: Int,
|
||||
open class Action(
|
||||
val buttonText: String,
|
||||
val buttonTextSub: String? = null,
|
||||
val activityClass: String,
|
||||
@DrawableRes val iconRes: Int,
|
||||
val background: Boolean = false,
|
||||
val actionString: String? = null,
|
||||
val message: String? = null,
|
||||
)
|
||||
|
||||
enum class WearControl {
|
||||
|
@ -62,10 +62,7 @@ enum class WearControl {
|
|||
|
||||
abstract class TileBase : TileService() {
|
||||
|
||||
open val resourceVersion = "1"
|
||||
open val idIconActionPrefix = "ic_action_"
|
||||
|
||||
abstract val preferencePrefix: String
|
||||
abstract val resourceVersion: String
|
||||
abstract val source: TileSource
|
||||
|
||||
private val serviceJob = Job()
|
||||
|
@ -89,19 +86,25 @@ abstract class TileBase : TileService() {
|
|||
.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(
|
||||
requestParams: ResourcesRequest
|
||||
): ListenableFuture<Resources> = serviceScope.future {
|
||||
Resources.Builder()
|
||||
.setVersion(resourceVersion)
|
||||
.apply {
|
||||
source.getActions().mapNotNull { action ->
|
||||
source.getResourceReferences(resources).forEach { resourceId ->
|
||||
addIdToImageMapping(
|
||||
idIconActionPrefix + action.id,
|
||||
resourceId.toString(),
|
||||
ImageResource.Builder()
|
||||
.setAndroidResourceByResId(
|
||||
AndroidImageResourceByResId.Builder()
|
||||
.setResourceId(action.iconRes)
|
||||
.setResourceId(resourceId)
|
||||
.build()
|
||||
)
|
||||
.build()
|
||||
|
@ -157,15 +160,17 @@ abstract class TileBase : TileService() {
|
|||
.build()
|
||||
|
||||
private fun doAction(action: Action): ActionBuilders.Action {
|
||||
val inBackground = ActionBuilders.AndroidBooleanExtra.Builder().setValue(action.background).build()
|
||||
val builder = ActionBuilders.AndroidActivity.Builder()
|
||||
.setClassName(action.activityClass)
|
||||
.setPackageName(this.packageName)
|
||||
.addKeyToExtraMapping("inBackground", inBackground)
|
||||
if (action.actionString != null) {
|
||||
val actionString = ActionBuilders.AndroidStringExtra.Builder().setValue(action.actionString).build()
|
||||
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()
|
||||
.setAndroidActivity(builder.build())
|
||||
|
@ -174,8 +179,8 @@ abstract class TileBase : TileService() {
|
|||
|
||||
private fun action(action: Action, deviceParameters: DeviceParameters): LayoutElement {
|
||||
val circleDiameter = circleDiameter(deviceParameters)
|
||||
val iconSize = dp(circleDiameter * ICON_SIZE_FRACTION)
|
||||
val text = resources.getString(action.nameRes)
|
||||
val text = action.buttonText
|
||||
val textSub = action.buttonTextSub
|
||||
return Box.Builder()
|
||||
.setWidth(dp(circleDiameter))
|
||||
.setHeight(dp(circleDiameter))
|
||||
|
@ -193,7 +198,7 @@ abstract class TileBase : TileService() {
|
|||
)
|
||||
.setSemantics(
|
||||
Semantics.Builder()
|
||||
.setContentDescription(text)
|
||||
.setContentDescription("$text $textSub")
|
||||
.build()
|
||||
)
|
||||
.setClickable(
|
||||
|
@ -203,32 +208,55 @@ abstract class TileBase : TileService() {
|
|||
)
|
||||
.build()
|
||||
)
|
||||
.addContent(
|
||||
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()
|
||||
)
|
||||
.addContent(addTextContent(action, deviceParameters))
|
||||
.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) {
|
||||
SCREEN_SHAPE_ROUND -> ((sqrt(2f) - 1) * deviceParameters.screenHeightDp) - (2 * SPACING_ACTIONS)
|
||||
else -> 0.5f * deviceParameters.screenHeightDp - SPACING_ACTIONS
|
||||
|
@ -257,37 +285,4 @@ abstract class TileBase : TileService() {
|
|||
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"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="6.35"
|
||||
android:viewportHeight="6.3500004">
|
||||
<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_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_old">Old data!</string>
|
||||
|
@ -86,9 +87,11 @@
|
|||
<string name="menu_none">None</string>
|
||||
<string name="menu_default">Default</string>
|
||||
<string name="menu_menu">Menu</string>
|
||||
<string name="quick_wizard_short">XL</string>
|
||||
|
||||
<string name="action_duration">Duration</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_bolus_confirmation">Bolus 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_channel_description">Bolus progress and cancel</string>
|
||||
<string name="bolus_progress_silent_channel_description">Bolus progress and cancel with less vibrations</string>
|
||||
|
||||
<string name="key_quickwizard" translatable="false">QuickWizard</string>
|
||||
<string name="key_wear_control" translatable="false">wearcontrol</string>
|
||||
<string name="key_units_mgdl" translatable="false">units_mgdl</string>
|
||||
<string name="key_boluswizard_percentage" translatable="false">boluswizard_percentage</string>
|
||||
|
@ -182,5 +185,6 @@
|
|||
<string name="tile_no_config">No config available</string>
|
||||
<string name="wear_control_not_enabled">Wear controls disabled</string>
|
||||
<string name="wear_control_no_data">No data available</string>
|
||||
<string name="key_quick_wizard_data_map" translatable="false">quick_wizard_data_map</string>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue