- extended pump-common package a little, so that in the future we can abstract some of stuff that is used by all (most) of drivers: History Dialog, BLE_Discovery, events and some other stuff (I used this with my new Ypso driver and I want to use the same with Tslim)
This commit is contained in:
parent
ad89d54319
commit
53c041f5cf
|
@ -194,7 +194,11 @@ class MedtronicPumpPlugin @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun onStartCustomActions() {
|
||||
override fun hasService(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onStartScheduledPumpActions() {
|
||||
|
||||
// check status every minute (if any status needs refresh we send readStatus command)
|
||||
Thread {
|
||||
|
@ -673,7 +677,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
|||
}
|
||||
|
||||
// if enforceNew===true current temp basal is canceled and new TBR set (duration is prolonged),
|
||||
// if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed
|
||||
// if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed
|
||||
@Synchronized
|
||||
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: TemporaryBasalType): PumpEnactResult {
|
||||
setRefreshButtonEnabled(false)
|
||||
|
@ -743,7 +747,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
|||
PumpEnactResult(injector).success(false).enacted(false) //
|
||||
.comment(R.string.medtronic_cmd_tbr_could_not_be_delivered)
|
||||
} else {
|
||||
medtronicPumpStatus.tempBasalStart = Date()
|
||||
medtronicPumpStatus.tempBasalStart = System.currentTimeMillis()
|
||||
medtronicPumpStatus.tempBasalAmount = absoluteRate
|
||||
medtronicPumpStatus.tempBasalLength = durationInMinutes
|
||||
|
||||
|
|
|
@ -122,7 +122,7 @@ class MedtronicPumpStatus @Inject constructor(private val rh: ResourceHelper,
|
|||
get() {
|
||||
if (tempBasalStart == null) return null
|
||||
if (tempBasalEnd == null) {
|
||||
val startTime = tempBasalStart!!.time
|
||||
val startTime = tempBasalStart!!
|
||||
tempBasalEnd = startTime + tempBasalLength!! * 60 * 1000
|
||||
}
|
||||
if (System.currentTimeMillis() > tempBasalEnd!!) {
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
<manifest>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="info.nightscout.androidaps.plugins.pump.common">
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name="info.nightscout.androidaps.plugins.pump.common.ui.PumpBLEConfigActivity"
|
||||
android:theme="@style/AppTheme"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="info.nightscout.androidaps.plugins.pump.common.ui.PumpBLEConfigActivity" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".ui.PumpHistoryActivity" />
|
||||
|
||||
</application>
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.text.format.DateFormat
|
||||
import com.google.gson.GsonBuilder
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.data.DetailedBolusInfo
|
||||
import info.nightscout.androidaps.data.PumpEnactResult
|
||||
|
@ -25,7 +26,6 @@ import info.nightscout.androidaps.utils.DateUtil
|
|||
import info.nightscout.androidaps.utils.DecimalFormatter.to0Decimal
|
||||
import info.nightscout.androidaps.utils.DecimalFormatter.to2Decimal
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
|
@ -56,7 +56,7 @@ abstract class PumpPluginAbstract protected constructor(
|
|||
var pumpSyncStorage: info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncStorage
|
||||
) : PumpPluginBase(pluginDescription!!, injector!!, aapsLogger, rh, commandQueue), Pump, Constraints, info.nightscout.androidaps.plugins.pump.common.sync.PumpSyncEntriesCreator {
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
val disposable = CompositeDisposable()
|
||||
|
||||
// Pump capabilities
|
||||
final override var pumpDescription = PumpDescription()
|
||||
|
@ -68,30 +68,41 @@ abstract class PumpPluginAbstract protected constructor(
|
|||
protected var displayConnectionMessages = false
|
||||
|
||||
var pumpType: PumpType = PumpType.GENERIC_AAPS
|
||||
get() = field
|
||||
set(value) {
|
||||
field = value
|
||||
pumpDescription.fillFor(value)
|
||||
}
|
||||
|
||||
protected var gson = GsonBuilder().excludeFieldsWithoutExposeAnnotation().create()
|
||||
|
||||
abstract fun initPumpStatusData()
|
||||
|
||||
open fun hasService(): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
initPumpStatusData()
|
||||
val intent = Intent(context, serviceClass)
|
||||
context.bindService(intent, serviceConnection!!, Context.BIND_AUTO_CREATE)
|
||||
if (hasService()) {
|
||||
val intent = Intent(context, serviceClass)
|
||||
context.bindService(intent, serviceConnection!!, Context.BIND_AUTO_CREATE)
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAppExit::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ _ -> context.unbindService(serviceConnection!!) }) { throwable: Throwable? -> fabricPrivacy.logException(throwable!!) }
|
||||
)
|
||||
}
|
||||
serviceRunning = true
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventAppExit::class.java)
|
||||
.observeOn(aapsSchedulers.io)
|
||||
.subscribe({ _ -> context.unbindService(serviceConnection!!) }) { throwable: Throwable? -> fabricPrivacy.logException(throwable!!) }
|
||||
)
|
||||
onStartCustomActions()
|
||||
onStartScheduledPumpActions()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
aapsLogger.debug(LTag.PUMP, deviceID() + " onStop()")
|
||||
context.unbindService(serviceConnection!!)
|
||||
aapsLogger.debug(LTag.PUMP, model().model + " onStop()")
|
||||
if (hasService()) {
|
||||
context.unbindService(serviceConnection!!)
|
||||
}
|
||||
serviceRunning = false
|
||||
disposable.clear()
|
||||
super.onStop()
|
||||
|
@ -100,7 +111,7 @@ abstract class PumpPluginAbstract protected constructor(
|
|||
/**
|
||||
* If we need to run any custom actions in onStart (triggering events, etc)
|
||||
*/
|
||||
abstract fun onStartCustomActions()
|
||||
abstract fun onStartScheduledPumpActions()
|
||||
|
||||
/**
|
||||
* Service class (same one you did serviceConnection for)
|
||||
|
@ -231,7 +242,8 @@ abstract class PumpPluginAbstract protected constructor(
|
|||
val extended = JSONObject()
|
||||
try {
|
||||
battery.put("percent", pumpStatusData.batteryRemaining)
|
||||
status.put("status", pumpStatusData.pumpStatusType.status)
|
||||
// TODO check this status.put("status", pumpStatusData.pumpStatusType.status)
|
||||
status.put("status", pumpStatusData.pumpRunningState.status)
|
||||
extended.put("Version", version)
|
||||
try {
|
||||
extended.put("ActiveProfile", profileName)
|
||||
|
@ -324,6 +336,7 @@ abstract class PumpPluginAbstract protected constructor(
|
|||
// bolus needed, ask pump to deliver it
|
||||
deliverBolus(detailedBolusInfo)
|
||||
} else {
|
||||
detailedBolusInfo.timestamp = System.currentTimeMillis()
|
||||
|
||||
// no bolus required, carb only treatment
|
||||
pumpSyncStorage.addCarbs(PumpDbEntryCarbs(detailedBolusInfo, this))
|
||||
|
@ -360,4 +373,4 @@ abstract class PumpPluginAbstract protected constructor(
|
|||
pumpDescription.fillFor(pumpType)
|
||||
this.pumpType = pumpType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.ble
|
||||
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.annotation.StringRes
|
||||
import com.google.gson.Gson
|
||||
import dagger.android.DaggerBroadcastReceiver
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.pump.common.events.EventPumpConnectionParametersChanged
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import javax.inject.Inject
|
||||
|
||||
class BondStateReceiver(
|
||||
@StringRes var deviceAddress: Int,
|
||||
@StringRes var bondedFlag: Int,
|
||||
var targetDevice: String,
|
||||
var targetState: Int
|
||||
) : DaggerBroadcastReceiver() {
|
||||
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var context: Context
|
||||
@Inject lateinit var rh: ResourceHelper
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
|
||||
var TAG = LTag.PUMPBTCOMM
|
||||
var gson = Gson()
|
||||
var applicationContext: Context? = null
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
super.onReceive(context, intent)
|
||||
val action = intent.action
|
||||
val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
|
||||
aapsLogger.info(TAG, "in onReceive: INTENT" + gson.toJson(intent))
|
||||
if (device == null) {
|
||||
aapsLogger.error(TAG, "onReceive. Device is null. Exiting.")
|
||||
return
|
||||
} else {
|
||||
if (device.address != targetDevice) {
|
||||
aapsLogger.error(TAG, "onReceive. Device is not the same as targetDevice. Exiting.")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Check if action is valid
|
||||
if (action == null) return
|
||||
|
||||
// Take action depending on new bond state
|
||||
if (action == BluetoothDevice.ACTION_BOND_STATE_CHANGED) {
|
||||
val bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR)
|
||||
val previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1)
|
||||
aapsLogger.info(TAG, "in onReceive: bondState=$bondState, previousBondState=$previousBondState")
|
||||
if (bondState == targetState) {
|
||||
aapsLogger.info(TAG, "onReceive: found targeted state: $targetState")
|
||||
val currentDeviceSettings = sp.getString(deviceAddress, "")
|
||||
if (currentDeviceSettings.equals(targetDevice)) {
|
||||
if (targetState == 12) {
|
||||
sp.putBoolean(bondedFlag, true)
|
||||
rxBus.send(EventPumpConnectionParametersChanged())
|
||||
} else if (targetState == 10) {
|
||||
sp.putBoolean(bondedFlag, false)
|
||||
rxBus.send(EventPumpConnectionParametersChanged())
|
||||
}
|
||||
context.unregisterReceiver(this)
|
||||
} else {
|
||||
aapsLogger.error(TAG, "onReceive: Device stored in SP is not the same as target device, process interrupted")
|
||||
}
|
||||
} else {
|
||||
aapsLogger.info(TAG, "onReceive: currentBondState=$bondState, targetBondState=$targetState")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.data
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpStatusType
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpRunningState
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
|
||||
import java.util.*
|
||||
|
||||
|
@ -33,12 +33,13 @@ abstract class PumpStatus(var pumpType: PumpType) {
|
|||
var dailyTotalUnits: Double? = null
|
||||
var maxDailyTotalUnits: String? = null
|
||||
var units: String? = null // Constants.MGDL or Constants.MMOL
|
||||
var pumpStatusType = PumpStatusType.Running
|
||||
var pumpRunningState = PumpRunningState.Running
|
||||
var basalsByHour: DoubleArray? = null
|
||||
var tempBasalStart: Date? = null
|
||||
var tempBasalStart: Long? = null
|
||||
var tempBasalAmount: Double? = 0.0
|
||||
var tempBasalLength: Int? = 0
|
||||
var tempBasalEnd: Long? = null
|
||||
var pumpTime: PumpTimeDifferenceDto? = null
|
||||
|
||||
abstract fun initSettings()
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.data
|
||||
|
||||
import org.joda.time.DateTime
|
||||
import org.joda.time.Seconds
|
||||
|
||||
/**
|
||||
* Created by andy on 28/05/2021.
|
||||
*/
|
||||
class PumpTimeDifferenceDto constructor(var localDeviceTime: DateTime,
|
||||
var pumpTime: DateTime) {
|
||||
|
||||
var timeDifference = 0
|
||||
|
||||
fun calculateDifference() {
|
||||
val secondsBetween = Seconds.secondsBetween(localDeviceTime, pumpTime)
|
||||
timeDifference = secondsBetween.seconds
|
||||
|
||||
// val diff = localDeviceTime - pumpTime
|
||||
// timeDifference = (diff / 1000.0).toInt()
|
||||
}
|
||||
|
||||
init {
|
||||
calculateDifference()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.defs;
|
||||
|
||||
/**
|
||||
* Created by andy on 1/20/19.
|
||||
*/
|
||||
|
||||
public enum BasalProfileStatus {
|
||||
|
||||
NotInitialized, //
|
||||
ProfileOK, //
|
||||
ProfileChanged, //
|
||||
;
|
||||
|
||||
}
|
|
@ -1,14 +1,26 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.defs
|
||||
|
||||
enum class PumpDriverState {
|
||||
import info.nightscout.androidaps.plugins.pump.common.R
|
||||
|
||||
NotInitialized,
|
||||
Connecting,
|
||||
Connected,
|
||||
Initialized,
|
||||
Ready, Busy,
|
||||
Suspended;
|
||||
// TODO there are 3 classes now, that do similar things, sort of, need to define exact rules: PumpDeviceState, PumpDriverState, PumpStatusState
|
||||
|
||||
// TODO split this enum into 2
|
||||
enum class PumpDriverState(var resourceId: Int) {
|
||||
|
||||
NotInitialized(R.string.pump_status_not_initialized), // this state should be set only when driver is created
|
||||
Connecting(R.string.connecting), //
|
||||
Connected(R.string.connected), //
|
||||
Initialized(R.string.pump_status_initialized), // this is weird state that probably won't be used, since its more driver centric that communication centric
|
||||
EncryptCommunication(R.string.pump_status_encrypt), //
|
||||
Ready(R.string.pump_status_ready),
|
||||
Busy(R.string.pump_status_busy), //
|
||||
Suspended(R.string.pump_status_suspended), //
|
||||
Sleeping(R.string.pump_status_sleeping),
|
||||
ExecutingCommand(R.string.pump_status_executing_command),
|
||||
Disconnecting(R.string.disconnecting),
|
||||
Disconnected(R.string.disconnected),
|
||||
ErrorCommunicatingWithPump(R.string.pump_status_error_comm);
|
||||
|
||||
fun isConnected(): Boolean = this == Connected || this == Initialized || this == Busy || this == Suspended
|
||||
fun isInitialized(): Boolean = this == Initialized || this == Busy || this == Suspended
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.pump.common.defs
|
|||
|
||||
import info.nightscout.androidaps.plugins.pump.common.R
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
import java.util.*
|
||||
import kotlin.streams.toList
|
||||
|
||||
/**
|
||||
* This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes
|
||||
|
@ -11,9 +11,10 @@ import java.util.*
|
|||
*
|
||||
* Author: Andy {andy.rozman@gmail.com}
|
||||
*/
|
||||
enum class PumpHistoryEntryGroup(val resourceId: Int) {
|
||||
enum class PumpHistoryEntryGroup(val resourceId: Int, val pumpTypeGroupConfig: PumpTypeGroupConfig = PumpTypeGroupConfig.All) {
|
||||
|
||||
All(R.string.history_group_all),
|
||||
Base(R.string.history_group_base),
|
||||
Bolus(R.string.history_group_bolus),
|
||||
Basal(R.string.history_group_basal),
|
||||
Prime(R.string.history_group_prime),
|
||||
|
@ -22,7 +23,14 @@ enum class PumpHistoryEntryGroup(val resourceId: Int) {
|
|||
Glucose(R.string.history_group_glucose),
|
||||
Notification(R.string.history_group_notification),
|
||||
Statistic(R.string.history_group_statistic),
|
||||
Unknown(R.string.history_group_unknown);
|
||||
Other(R.string.history_group_other),
|
||||
Unknown(R.string.history_group_unknown),
|
||||
|
||||
// Ypso
|
||||
EventsOnly(R.string.history_group_events),
|
||||
EventsNoStat(R.string.history_group_events_no_stat)
|
||||
|
||||
;
|
||||
|
||||
var translated: String? = null
|
||||
private set
|
||||
|
@ -33,9 +41,10 @@ enum class PumpHistoryEntryGroup(val resourceId: Int) {
|
|||
|
||||
companion object {
|
||||
|
||||
private var translatedList: MutableList<PumpHistoryEntryGroup>? = null
|
||||
@JvmStatic private var translatedList: MutableList<PumpHistoryEntryGroup>? = null
|
||||
|
||||
private fun doTranslation(rh: ResourceHelper) {
|
||||
fun doTranslation(rh: ResourceHelper) {
|
||||
if (translatedList != null) return
|
||||
translatedList = ArrayList()
|
||||
for (pumpHistoryEntryGroup in values()) {
|
||||
pumpHistoryEntryGroup.translated = rh.gs(pumpHistoryEntryGroup.resourceId)
|
||||
|
@ -43,9 +52,27 @@ enum class PumpHistoryEntryGroup(val resourceId: Int) {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME this is just for Java compatibility reasons (can be removed when all drivers using it are in Kotlin - OmnipodEros still in java)
|
||||
fun getTranslatedList(rh: ResourceHelper): List<PumpHistoryEntryGroup> {
|
||||
return getTranslatedList(rh, PumpTypeGroupConfig.All)
|
||||
}
|
||||
|
||||
fun getTranslatedList(rh: ResourceHelper, pumpTypeGroupConfig: PumpTypeGroupConfig = PumpTypeGroupConfig.All): List<PumpHistoryEntryGroup> {
|
||||
if (translatedList == null) doTranslation(rh)
|
||||
return translatedList!!
|
||||
|
||||
val outList: List<PumpHistoryEntryGroup>
|
||||
|
||||
if (pumpTypeGroupConfig == PumpTypeGroupConfig.All) {
|
||||
outList = translatedList!!.stream()
|
||||
.filter { pre -> pre.pumpTypeGroupConfig == PumpTypeGroupConfig.All }
|
||||
.toList();
|
||||
} else {
|
||||
outList = translatedList!!.stream()
|
||||
.filter { pre -> (pre.pumpTypeGroupConfig == PumpTypeGroupConfig.All || pre.pumpTypeGroupConfig == pumpTypeGroupConfig) }
|
||||
.toList();
|
||||
}
|
||||
|
||||
return outList
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.defs
|
||||
|
||||
// TODO there are 3 classes now, that do similar things, sort of, need to define exact rules: PumpDeviceState, PumpDriverState, PumpStatusState
|
||||
|
||||
enum class PumpRunningState(val status: String) {
|
||||
|
||||
Running("normal"),
|
||||
Suspended("suspended");
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.defs
|
||||
|
||||
enum class PumpTypeGroupConfig {
|
||||
All,
|
||||
Medtronic,
|
||||
OmnipodEros,
|
||||
YpsoPump
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.defs
|
||||
|
||||
import java.util.*
|
||||
|
||||
enum class PumpUpdateFragmentType {
|
||||
None,
|
||||
PumpStatus,
|
||||
DriverStatus,
|
||||
Queue,
|
||||
Bolus,
|
||||
TBR,
|
||||
ProfileChange,
|
||||
TBRCount,
|
||||
BolusCount,
|
||||
TreatmentValues(Arrays.asList(Bolus, TBR, TBRCount, BolusCount, ProfileChange)), // Last Bolus, TBR, Profile Change, TBR Count, Bolus Count
|
||||
Full,
|
||||
Configuration, // Firmware, Errors
|
||||
Battery,
|
||||
Reservoir,
|
||||
OtherValues(Arrays.asList(Battery, Reservoir)), // Battery, Reservoir
|
||||
Custom_1,
|
||||
Custom_2,
|
||||
Custom_3,
|
||||
Custom_4,
|
||||
Custom_5,
|
||||
Custom_6,
|
||||
Custom_7,
|
||||
Custom_8
|
||||
;
|
||||
|
||||
final var children: List<PumpUpdateFragmentType>? = null
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
constructor(children: List<PumpUpdateFragmentType>) {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
fun isOptionIncluded(type: PumpUpdateFragmentType): Boolean {
|
||||
if (this == type)
|
||||
return true
|
||||
else if (this.children != null && this.children!!.contains(type))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.driver
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.common.driver.history.PumpHistoryDataProvider
|
||||
|
||||
interface PumpDriverConfiguration {
|
||||
|
||||
fun getPumpBLESelector(): PumpBLESelector
|
||||
|
||||
fun getPumpHistoryDataProvider(): PumpHistoryDataProvider
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.driver
|
||||
|
||||
interface PumpDriverConfigurationCapable {
|
||||
|
||||
fun getPumpDriverConfiguration(): PumpDriverConfiguration
|
||||
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.driver
|
||||
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.bluetooth.le.ScanFilter
|
||||
import android.bluetooth.le.ScanSettings
|
||||
import android.content.Context
|
||||
|
||||
interface PumpBLESelector {
|
||||
|
||||
/**
|
||||
* Called on resume
|
||||
*/
|
||||
fun onResume()
|
||||
|
||||
/**
|
||||
* Called on destory
|
||||
*/
|
||||
fun onDestroy()
|
||||
|
||||
/**
|
||||
* This method is called when device is being removed (it can be empty if you don't need to do any special action, but if you
|
||||
* have to unbound (for example), then this is method where to call it. For unbounding removeBond is available
|
||||
*/
|
||||
fun removeDevice(device: BluetoothDevice)
|
||||
|
||||
/**
|
||||
* Cleanup method after device was removed
|
||||
*/
|
||||
fun cleanupAfterDeviceRemoved()
|
||||
|
||||
/**
|
||||
* operations when scan failed
|
||||
*/
|
||||
fun onScanFailed(context: Context, errorCode: Int)
|
||||
|
||||
/**
|
||||
* operations when scan starts
|
||||
*/
|
||||
fun onStartLeDeviceScan(context: Context)
|
||||
|
||||
/**
|
||||
* operations when scan stops
|
||||
*/
|
||||
fun onStopLeDeviceScan(context: Context)
|
||||
|
||||
/**
|
||||
* operations when scan was stopped manualy (press on button)
|
||||
*/
|
||||
fun onManualStopLeDeviceScan(context: Context)
|
||||
|
||||
/**
|
||||
* operations when on non manual stop of scan (on timeout)
|
||||
*/
|
||||
fun onNonManualStopLeDeviceScan(context: Context)
|
||||
|
||||
/**
|
||||
* get Scan Filters
|
||||
*/
|
||||
fun getScanFilters(): List<ScanFilter>?
|
||||
|
||||
/**
|
||||
* get Scan Settings
|
||||
*/
|
||||
fun getScanSettings(): ScanSettings?
|
||||
|
||||
/**
|
||||
* filter device on search (for cases where we can't do it with Scan Filters
|
||||
*/
|
||||
fun filterDevice(device: BluetoothDevice): BluetoothDevice?
|
||||
|
||||
/**
|
||||
* operations when device selected
|
||||
*/
|
||||
fun onDeviceSelected(bluetoothDevice: BluetoothDevice, bleAddress: String, deviceName: String)
|
||||
|
||||
/**
|
||||
* If pump has no name, this name will be used
|
||||
*/
|
||||
fun getUnknownPumpName(): String
|
||||
|
||||
/**
|
||||
* get Address of Currently selected pump, empty string if none
|
||||
*/
|
||||
fun currentlySelectedPumpAddress(): String
|
||||
|
||||
/**
|
||||
* get Name of Currently selected pump, getUnknownPumpName() string if none
|
||||
*/
|
||||
fun currentlySelectedPumpName(): String
|
||||
|
||||
/**
|
||||
* Get Translation Text
|
||||
*/
|
||||
fun getText(key: PumpBLESelectorText): String
|
||||
|
||||
}
|
||||
|
||||
enum class PumpBLESelectorText {
|
||||
SCAN_TITLE,
|
||||
SELECTED_PUMP_TITLE,
|
||||
REMOVE_TITLE,
|
||||
REMOVE_TEXT,
|
||||
NO_SELECTED_PUMP,
|
||||
PUMP_CONFIGURATION
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.driver.ble
|
||||
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.bluetooth.le.ScanFilter
|
||||
import android.bluetooth.le.ScanSettings
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.pump.common.R
|
||||
import info.nightscout.androidaps.plugins.pump.common.driver.PumpBLESelector
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
|
||||
abstract class PumpBLESelectorAbstract constructor(
|
||||
var resourceHelper: ResourceHelper,
|
||||
var aapsLogger: AAPSLogger,
|
||||
var sp: SP,
|
||||
var rxBus: RxBus,
|
||||
var context: Context
|
||||
) : PumpBLESelector {
|
||||
|
||||
protected val TAG = LTag.PUMPBTCOMM
|
||||
|
||||
override fun getScanSettings(): ScanSettings? {
|
||||
return ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build()
|
||||
}
|
||||
|
||||
override fun getScanFilters(): MutableList<ScanFilter>? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun filterDevice(device: BluetoothDevice): BluetoothDevice? {
|
||||
return device
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
}
|
||||
|
||||
override fun removeDevice(device: BluetoothDevice) {
|
||||
}
|
||||
|
||||
override fun cleanupAfterDeviceRemoved() {
|
||||
}
|
||||
|
||||
override fun onManualStopLeDeviceScan(context: Context) {
|
||||
}
|
||||
|
||||
override fun onNonManualStopLeDeviceScan(context: Context) {
|
||||
}
|
||||
|
||||
//fun onDeviceSelected(bluetoothDevice: BluetoothDevice, bleAddress: String, deviceName: String)
|
||||
|
||||
override fun onScanFailed(context: Context, errorCode: Int) {
|
||||
Toast.makeText(
|
||||
context, resourceHelper.gs(R.string.ble_config_scan_error, errorCode),
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
}
|
||||
|
||||
override fun onStartLeDeviceScan(context: Context) {
|
||||
Toast.makeText(context, R.string.ble_config_scan_scanning, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
override fun onStopLeDeviceScan(context: Context) {
|
||||
Toast.makeText(context, R.string.ble_config_scan_finished, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
protected fun removeBond(bluetoothDevice: BluetoothDevice): Boolean {
|
||||
return try {
|
||||
val method = bluetoothDevice.javaClass.getMethod("removeBond")
|
||||
val resultObject = method.invoke(bluetoothDevice)
|
||||
if (resultObject == null) {
|
||||
aapsLogger.error(TAG, "ERROR: result object is null")
|
||||
false
|
||||
} else {
|
||||
val result = resultObject as Boolean
|
||||
if (result) {
|
||||
aapsLogger.info(TAG, "Successfully removed bond")
|
||||
} else {
|
||||
aapsLogger.warn(TAG, "Bond was not removed")
|
||||
}
|
||||
result
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
aapsLogger.error(TAG, "ERROR: could not remove bond")
|
||||
e.printStackTrace()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
protected fun getBondingStatusDescription(state: Int): String {
|
||||
return if (state == 10) {
|
||||
"BOND_NONE"
|
||||
} else if (state == 11) {
|
||||
"BOND_BONDING"
|
||||
} else if (state == 12) {
|
||||
"BOND_BONDED"
|
||||
} else {
|
||||
"UNKNOWN BOND STATUS ($state)"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.driver.history
|
||||
|
||||
interface PumpDataConverter {
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.driver.history
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import info.nightscout.androidaps.plugins.pump.common.R
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup
|
||||
|
||||
interface PumpHistoryDataProvider {
|
||||
|
||||
/**
|
||||
* Get Data, specified with PumpHistoryPeriod
|
||||
*/
|
||||
fun getData(period: PumpHistoryPeriod): List<PumpHistoryEntry>
|
||||
|
||||
/**
|
||||
* Get Initial Period
|
||||
*/
|
||||
fun getInitialPeriod(): PumpHistoryPeriod
|
||||
|
||||
/**
|
||||
* Get InitialData
|
||||
*/
|
||||
fun getInitialData(): List<PumpHistoryEntry>
|
||||
|
||||
/**
|
||||
* Get Allowed Pump History Groups (for specific pump)
|
||||
*/
|
||||
fun getAllowedPumpHistoryGroups(): List<PumpHistoryEntryGroup>
|
||||
|
||||
/**
|
||||
* Get Spinner Width in pixels (same as specifying 150dp)
|
||||
*/
|
||||
fun getSpinnerWidthInPixels(): Int
|
||||
|
||||
/**
|
||||
* Get Translation Text
|
||||
*/
|
||||
fun getText(key: PumpHistoryText): String
|
||||
|
||||
/**
|
||||
* For filtering of items
|
||||
*/
|
||||
fun isItemInSelection(itemGroup: PumpHistoryEntryGroup, targetGroup: PumpHistoryEntryGroup): Boolean
|
||||
|
||||
}
|
||||
|
||||
enum class PumpHistoryPeriod constructor(
|
||||
@StringRes var stringId: Int,
|
||||
var isHours: Boolean = false
|
||||
) {
|
||||
|
||||
TODAY(R.string.time_today),
|
||||
LAST_HOUR(R.string.time_last_hour, true),
|
||||
LAST_3_HOURS(R.string.time_last_3_hours, true),
|
||||
LAST_6_HOURS(R.string.time_last_6_hours, true),
|
||||
LAST_12_HOURS(R.string.time_last_12_hours, true),
|
||||
LAST_2_DAYS(R.string.time_last_2_days),
|
||||
LAST_4_DAYS(R.string.time_last_4_days),
|
||||
LAST_WEEK(R.string.time_last_week),
|
||||
LAST_MONTH(R.string.time_last_month),
|
||||
ALL(R.string.history_group_all)
|
||||
|
||||
}
|
||||
|
||||
enum class PumpHistoryText {
|
||||
|
||||
PUMP_HISTORY,
|
||||
|
||||
// OLD ONES
|
||||
SCAN_TITLE,
|
||||
SELECTED_PUMP_TITLE,
|
||||
REMOVE_TITLE,
|
||||
REMOVE_TEXT,
|
||||
NO_SELECTED_PUMP,
|
||||
PUMP_CONFIGURATION
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.driver.history
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup
|
||||
import java.util.*
|
||||
|
||||
abstract class PumpHistoryDataProviderAbstract : PumpHistoryDataProvider {
|
||||
|
||||
override fun getInitialData(): List<PumpHistoryEntry> {
|
||||
return getData(getInitialPeriod());
|
||||
}
|
||||
|
||||
override fun getSpinnerWidthInPixels(): Int {
|
||||
return 150
|
||||
}
|
||||
|
||||
protected fun getStartingTimeForData(period: PumpHistoryPeriod): Long {
|
||||
val gregorianCalendar = GregorianCalendar()
|
||||
|
||||
if (!period.isHours) {
|
||||
gregorianCalendar.set(Calendar.HOUR_OF_DAY, 0)
|
||||
gregorianCalendar.set(Calendar.MINUTE, 0)
|
||||
gregorianCalendar.set(Calendar.SECOND, 0)
|
||||
gregorianCalendar.set(Calendar.MILLISECOND, 0)
|
||||
}
|
||||
|
||||
when (period) {
|
||||
PumpHistoryPeriod.TODAY -> return gregorianCalendar.timeInMillis
|
||||
PumpHistoryPeriod.ALL -> return 0L
|
||||
PumpHistoryPeriod.LAST_2_DAYS -> gregorianCalendar.add(Calendar.DAY_OF_MONTH, -1)
|
||||
PumpHistoryPeriod.LAST_4_DAYS -> gregorianCalendar.add(Calendar.DAY_OF_MONTH, -3)
|
||||
PumpHistoryPeriod.LAST_WEEK -> gregorianCalendar.add(Calendar.WEEK_OF_YEAR, -1)
|
||||
PumpHistoryPeriod.LAST_MONTH -> gregorianCalendar.add(Calendar.MONTH, -1)
|
||||
PumpHistoryPeriod.LAST_HOUR -> gregorianCalendar.add(Calendar.HOUR_OF_DAY, -1)
|
||||
PumpHistoryPeriod.LAST_3_HOURS -> gregorianCalendar.add(Calendar.HOUR_OF_DAY, -3)
|
||||
PumpHistoryPeriod.LAST_6_HOURS -> gregorianCalendar.add(Calendar.HOUR_OF_DAY, -6)
|
||||
PumpHistoryPeriod.LAST_12_HOURS -> gregorianCalendar.add(Calendar.HOUR_OF_DAY, -12)
|
||||
}
|
||||
|
||||
return gregorianCalendar.timeInMillis
|
||||
}
|
||||
|
||||
override fun isItemInSelection(itemGroup: PumpHistoryEntryGroup, targetGroup: PumpHistoryEntryGroup): Boolean {
|
||||
return itemGroup === targetGroup
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.driver.history
|
||||
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
|
||||
interface PumpHistoryEntry {
|
||||
|
||||
fun prepareEntryData(resourceHelper: ResourceHelper, pumpDataConverter: PumpDataConverter)
|
||||
|
||||
fun getEntryDateTime(): String
|
||||
|
||||
fun getEntryType(): String
|
||||
|
||||
fun getEntryValue(): String
|
||||
|
||||
fun getEntryTypeGroup(): PumpHistoryEntryGroup
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventBondChanged(
|
||||
var connectionAddress: String,
|
||||
var bondStatus: Boolean
|
||||
) : Event()
|
|
@ -0,0 +1,8 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventPumpChanged(var serialNumber: String,
|
||||
var connectionAddress: String,
|
||||
var parameters: MutableMap<String, Any>? = null) : Event() {
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventPumpConnectionParametersChanged : Event() {
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpUpdateFragmentType
|
||||
|
||||
class EventPumpFragmentValuesChanged : Event {
|
||||
|
||||
var updateType: PumpUpdateFragmentType = PumpUpdateFragmentType.None
|
||||
|
||||
constructor(updateType: PumpUpdateFragmentType) {
|
||||
this.updateType = updateType
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,338 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.ui
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.bluetooth.BluetoothAdapter
|
||||
import android.bluetooth.BluetoothDevice
|
||||
import android.bluetooth.BluetoothManager
|
||||
import android.bluetooth.le.BluetoothLeScanner
|
||||
import android.bluetooth.le.ScanCallback
|
||||
import android.bluetooth.le.ScanFilter
|
||||
import android.bluetooth.le.ScanResult
|
||||
import android.bluetooth.le.ScanSettings
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.AdapterView.OnItemClickListener
|
||||
import android.widget.BaseAdapter
|
||||
import android.widget.TextView
|
||||
import dagger.android.support.DaggerAppCompatActivity
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.pump.common.R
|
||||
import info.nightscout.androidaps.plugins.pump.common.ble.BlePreCheck
|
||||
import info.nightscout.androidaps.plugins.pump.common.databinding.PumpBleConfigActivityBinding
|
||||
import info.nightscout.androidaps.plugins.pump.common.driver.PumpBLESelector
|
||||
import info.nightscout.androidaps.plugins.pump.common.driver.PumpBLESelectorText
|
||||
import info.nightscout.androidaps.plugins.pump.common.driver.PumpDriverConfigurationCapable
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import org.apache.commons.lang3.StringUtils
|
||||
import javax.inject.Inject
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
class PumpBLEConfigActivity : DaggerAppCompatActivity() {
|
||||
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var blePreCheck: BlePreCheck
|
||||
@Inject lateinit var context: Context
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var rxBus: RxBus
|
||||
|
||||
private lateinit var binding: PumpBleConfigActivityBinding
|
||||
private lateinit var bleSelector: PumpBLESelector
|
||||
|
||||
private var settings: ScanSettings? = null
|
||||
private var filters: List<ScanFilter>? = null
|
||||
private var bleScanner: BluetoothLeScanner? = null
|
||||
private var deviceListAdapter = LeDeviceListAdapter()
|
||||
private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
|
||||
private val bluetoothAdapter: BluetoothAdapter? get() = (context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager?)?.adapter
|
||||
var scanning = false
|
||||
private val devicesMap: MutableMap<String, BluetoothDevice> = HashMap()
|
||||
|
||||
private val stopScanAfterTimeoutRunnable = Runnable {
|
||||
if (scanning) {
|
||||
stopLeDeviceScan(false)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = PumpBleConfigActivityBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
if (!blePreCheck.prerequisitesCheck(this)) {
|
||||
aapsLogger.error(TAG, "prerequisitesCheck failed.")
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
// Configuration
|
||||
val activePump = activePlugin.activePump
|
||||
|
||||
if (activePump is PumpDriverConfigurationCapable) {
|
||||
bleSelector = activePump.getPumpDriverConfiguration().getPumpBLESelector()
|
||||
} else {
|
||||
throw RuntimeException("PumpBLEConfigActivity can be used only with PumpDriverConfigurationCapable pump driver.")
|
||||
}
|
||||
|
||||
binding.pumpBleConfigCurrentlySelectedText.text = bleSelector.getText(PumpBLESelectorText.SELECTED_PUMP_TITLE)
|
||||
binding.pumpBleConfigScanTitle.text = bleSelector.getText(PumpBLESelectorText.SCAN_TITLE)
|
||||
|
||||
title = bleSelector.getText(PumpBLESelectorText.PUMP_CONFIGURATION)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
supportActionBar?.setDisplayShowHomeEnabled(true)
|
||||
|
||||
binding.pumpBleConfigScanDeviceList.adapter = deviceListAdapter
|
||||
binding.pumpBleConfigScanDeviceList.onItemClickListener = OnItemClickListener { _: AdapterView<*>?, view: View, _: Int, _: Long ->
|
||||
// stop scanning if still active
|
||||
if (scanning) {
|
||||
stopLeDeviceScan(true)
|
||||
}
|
||||
val bleAddress = (view.findViewById<View>(R.id.pump_ble_config_scan_item_device_address) as TextView).text.toString()
|
||||
val deviceName = (view.findViewById<View>(R.id.pump_ble_config_scan_item_device_name) as TextView).text.toString()
|
||||
|
||||
if (devicesMap.containsKey(bleAddress)) {
|
||||
aapsLogger.debug(TAG, "Device FOUND in deviceMap: $bleAddress")
|
||||
val bluetoothDevice = devicesMap[bleAddress]
|
||||
bleSelector.onDeviceSelected(bluetoothDevice!!, bleAddress, deviceName)
|
||||
} else {
|
||||
aapsLogger.debug(TAG, "Device NOT found in deviceMap: $bleAddress")
|
||||
}
|
||||
|
||||
finish()
|
||||
}
|
||||
binding.pumpBleConfigScanStart.setOnClickListener { startLeDeviceScan() }
|
||||
binding.pumpBleConfigButtonScanStop.setOnClickListener {
|
||||
if (scanning) {
|
||||
stopLeDeviceScan(true)
|
||||
}
|
||||
}
|
||||
|
||||
binding.pumpBleConfigButtonRemove.setOnClickListener {
|
||||
OKDialog.showConfirmation(
|
||||
this@PumpBLEConfigActivity,
|
||||
bleSelector.getText(PumpBLESelectorText.REMOVE_TITLE),
|
||||
bleSelector.getText(PumpBLESelectorText.REMOVE_TEXT),
|
||||
Runnable {
|
||||
val deviceAddress: String = binding.pumpBleConfigCurrentlySelectedPumpAddress.text.toString()
|
||||
aapsLogger.debug(TAG, "Removing device as selected: $deviceAddress")
|
||||
if (devicesMap.containsKey(deviceAddress)) {
|
||||
val bluetoothDevice = devicesMap[deviceAddress]
|
||||
aapsLogger.debug(TAG, "Device can be detected near, so trying to remove bond if possible.")
|
||||
bleSelector.removeDevice(bluetoothDevice!!)
|
||||
} else {
|
||||
val remoteDevice = bluetoothAdapter!!.getRemoteDevice(deviceAddress)
|
||||
if (remoteDevice != null) {
|
||||
bleSelector.removeDevice(remoteDevice)
|
||||
}
|
||||
}
|
||||
bleSelector.cleanupAfterDeviceRemoved()
|
||||
updateCurrentlySelectedBTDevice()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCurrentlySelectedBTDevice() {
|
||||
val address = bleSelector.currentlySelectedPumpAddress()
|
||||
if (StringUtils.isEmpty(address)) {
|
||||
binding.pumpBleConfigCurrentlySelectedPumpName.text = bleSelector.getText(PumpBLESelectorText.NO_SELECTED_PUMP)
|
||||
binding.pumpBleConfigCurrentlySelectedPumpAddress.visibility = View.GONE
|
||||
binding.pumpBleConfigButtonRemove.visibility = View.GONE
|
||||
} else {
|
||||
binding.pumpBleConfigCurrentlySelectedPumpAddress.visibility = View.VISIBLE
|
||||
binding.pumpBleConfigButtonRemove.visibility = View.VISIBLE
|
||||
binding.pumpBleConfigCurrentlySelectedPumpName.text = bleSelector.currentlySelectedPumpName()
|
||||
binding.pumpBleConfigCurrentlySelectedPumpAddress.text = address
|
||||
}
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean =
|
||||
when (item.itemId) {
|
||||
android.R.id.home -> {
|
||||
finish()
|
||||
true
|
||||
}
|
||||
|
||||
else -> false
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
bleSelector.onResume()
|
||||
prepareForScanning()
|
||||
updateCurrentlySelectedBTDevice()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
if (scanning) {
|
||||
stopLeDeviceScan(false)
|
||||
}
|
||||
bleSelector.onDestroy()
|
||||
}
|
||||
|
||||
private fun prepareForScanning() {
|
||||
bleScanner = bluetoothAdapter!!.bluetoothLeScanner
|
||||
settings = bleSelector.getScanSettings()
|
||||
filters = bleSelector.getScanFilters()
|
||||
}
|
||||
|
||||
private val bleScanCallback: ScanCallback = object : ScanCallback() {
|
||||
|
||||
override fun onScanResult(callbackType: Int, scanRecord: ScanResult) {
|
||||
aapsLogger.debug(TAG, scanRecord.toString())
|
||||
runOnUiThread { if (addDevice(scanRecord)) deviceListAdapter.notifyDataSetChanged() }
|
||||
}
|
||||
|
||||
override fun onBatchScanResults(results: List<ScanResult>) {
|
||||
runOnUiThread {
|
||||
var added = false
|
||||
for (result in results) {
|
||||
aapsLogger.debug(TAG, "SCAN: " + result.advertisingSid + " name=" + result.device.address)
|
||||
if (addDevice(result)) added = true
|
||||
}
|
||||
if (added)
|
||||
deviceListAdapter.notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
private fun addDevice(result: ScanResult): Boolean {
|
||||
var device = result.device
|
||||
|
||||
device = bleSelector.filterDevice(device)
|
||||
|
||||
if (device == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
deviceListAdapter.addDevice(result)
|
||||
if (!devicesMap.containsKey(device.address)) {
|
||||
devicesMap[device.address] = device
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onScanFailed(errorCode: Int) {
|
||||
aapsLogger.error(TAG, "Scan Failed - Error Code: $errorCode")
|
||||
bleSelector.onScanFailed(this@PumpBLEConfigActivity, errorCode)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startLeDeviceScan() {
|
||||
if (bleScanner == null) {
|
||||
aapsLogger.error(LTag.PUMPBTCOMM, "startLeDeviceScan failed: bleScanner is null")
|
||||
return
|
||||
}
|
||||
deviceListAdapter.clear()
|
||||
deviceListAdapter.notifyDataSetChanged()
|
||||
handler.postDelayed(stopScanAfterTimeoutRunnable, SCAN_PERIOD_MILLIS)
|
||||
runOnUiThread {
|
||||
binding.pumpBleConfigScanStart.isEnabled = false
|
||||
binding.pumpBleConfigButtonScanStop.visibility = View.VISIBLE
|
||||
}
|
||||
scanning = true
|
||||
bleScanner!!.startScan(filters, settings, bleScanCallback)
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "startLeDeviceScan: Scanning Start")
|
||||
bleSelector.onStartLeDeviceScan(this@PumpBLEConfigActivity)
|
||||
}
|
||||
|
||||
private fun stopLeDeviceScan(manualStop: Boolean) {
|
||||
if (scanning) {
|
||||
scanning = false
|
||||
bleScanner!!.stopScan(bleScanCallback)
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "stopLeDeviceScan: Scanning Stop")
|
||||
bleSelector.onStopLeDeviceScan(this@PumpBLEConfigActivity)
|
||||
handler.removeCallbacks(stopScanAfterTimeoutRunnable)
|
||||
}
|
||||
if (manualStop) {
|
||||
bleSelector.onManualStopLeDeviceScan(this@PumpBLEConfigActivity)
|
||||
} else {
|
||||
bleSelector.onNonManualStopLeDeviceScan(this@PumpBLEConfigActivity)
|
||||
}
|
||||
|
||||
runOnUiThread {
|
||||
binding.pumpBleConfigScanStart.isEnabled = true
|
||||
binding.pumpBleConfigButtonScanStop.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private inner class LeDeviceListAdapter : BaseAdapter() {
|
||||
|
||||
private var devicesList: ArrayList<BluetoothDevice> = arrayListOf()
|
||||
private var devicesMap: MutableMap<BluetoothDevice, Int> = mutableMapOf()
|
||||
|
||||
fun addDevice(result: ScanResult) {
|
||||
if (!devicesList.contains(result.device)) {
|
||||
devicesList.add(result.device)
|
||||
}
|
||||
devicesMap[result.device] = result.rssi
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
devicesList.clear()
|
||||
devicesMap.clear()
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun getCount(): Int {
|
||||
val c = devicesList.size
|
||||
aapsLogger.info(TAG, "D: count=$c")
|
||||
return c
|
||||
}
|
||||
|
||||
override fun getItem(i: Int): Any = devicesList[i]
|
||||
override fun getItemId(i: Int): Long = i.toLong()
|
||||
|
||||
override fun getView(i: Int, convertView: View?, viewGroup: ViewGroup?): View {
|
||||
var v = convertView
|
||||
val holder: ViewHolder
|
||||
if (v == null) {
|
||||
v = View.inflate(applicationContext, R.layout.pump_ble_config_scan_item, null)
|
||||
holder = ViewHolder()
|
||||
holder.deviceAddress = v.findViewById(R.id.pump_ble_config_scan_item_device_address)
|
||||
holder.deviceName = v.findViewById(R.id.pump_ble_config_scan_item_device_name)
|
||||
v.tag = holder
|
||||
} else {
|
||||
// reuse view if already exists
|
||||
holder = v.tag as ViewHolder
|
||||
}
|
||||
|
||||
val device = devicesList[i]
|
||||
var deviceName = device.name
|
||||
if (StringUtils.isBlank(deviceName)) {
|
||||
deviceName = bleSelector.getUnknownPumpName()
|
||||
}
|
||||
deviceName += " [" + devicesMap[device] + "]"
|
||||
val currentlySelectedAddress = bleSelector.currentlySelectedPumpAddress() // TODO
|
||||
if (currentlySelectedAddress == device.address) {
|
||||
deviceName += " (" + resources.getString(R.string.ble_config_scan_selected) + ")"
|
||||
}
|
||||
holder.deviceName!!.text = deviceName
|
||||
holder.deviceAddress!!.text = device.address
|
||||
return v!!
|
||||
}
|
||||
}
|
||||
|
||||
internal class ViewHolder {
|
||||
var deviceName: TextView? = null
|
||||
var deviceAddress: TextView? = null
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = LTag.PUMPBTCOMM
|
||||
private const val SCAN_PERIOD_MILLIS: Long = 15000
|
||||
}
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
package info.nightscout.androidaps.plugins.pump.common.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.os.SystemClock
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import dagger.android.support.DaggerAppCompatActivity
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.plugins.pump.common.R
|
||||
import info.nightscout.androidaps.plugins.pump.common.databinding.PumpHistoryActivityBinding
|
||||
import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup
|
||||
import info.nightscout.androidaps.plugins.pump.common.driver.PumpDriverConfigurationCapable
|
||||
import info.nightscout.androidaps.plugins.pump.common.driver.history.PumpHistoryDataProvider
|
||||
import info.nightscout.androidaps.plugins.pump.common.driver.history.PumpHistoryEntry
|
||||
import info.nightscout.androidaps.plugins.pump.common.driver.history.PumpHistoryText
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import javax.inject.Inject
|
||||
|
||||
class PumpHistoryActivity : DaggerAppCompatActivity() {
|
||||
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var context: Context
|
||||
|
||||
var filteredHistoryList: MutableList<PumpHistoryEntry> = mutableListOf()
|
||||
var typeListFull: List<TypeList>? = null
|
||||
var fullList: MutableList<PumpHistoryEntry> = mutableListOf()
|
||||
|
||||
private lateinit var historyDataProvider: PumpHistoryDataProvider
|
||||
private lateinit var binding: PumpHistoryActivityBinding
|
||||
|
||||
var manualChange = false
|
||||
|
||||
lateinit var recyclerViewAdapter: RecyclerViewAdapter
|
||||
|
||||
private fun prepareData() {
|
||||
|
||||
val allData = historyDataProvider.getInitialData()
|
||||
|
||||
aapsLogger.info(LTag.PUMP, "Loaded ${allData.size} items from database. [initialSize=${historyDataProvider.getInitialPeriod()}]")
|
||||
|
||||
this.fullList.addAll(allData)
|
||||
}
|
||||
|
||||
private fun filterHistory(group: PumpHistoryEntryGroup) {
|
||||
filteredHistoryList.clear()
|
||||
|
||||
if (group === PumpHistoryEntryGroup.All) {
|
||||
filteredHistoryList.addAll(fullList)
|
||||
} else {
|
||||
for (pumpHistoryEntry in fullList) {
|
||||
if (historyDataProvider.isItemInSelection(pumpHistoryEntry.getEntryTypeGroup(), group)) {
|
||||
filteredHistoryList.add(pumpHistoryEntry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aapsLogger.info(LTag.PUMP, "Filtered list ${filteredHistoryList.size} items (group ${group}), from full list (${fullList.size}).")
|
||||
|
||||
recyclerViewAdapter.setHistoryListInternal(filteredHistoryList)
|
||||
recyclerViewAdapter.notifyDataSetChanged()
|
||||
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
//filterHistory(selectedGroup)
|
||||
//setHistoryTypeSpinner()
|
||||
//aapsLogger.info(LTag.PUMP, "onResume")
|
||||
//binding.pumpHistoryRoot.requestLayout()
|
||||
}
|
||||
|
||||
private fun setHistoryTypeSpinner() {
|
||||
manualChange = true
|
||||
for (i in typeListFull!!.indices) {
|
||||
if (typeListFull!![i].entryGroup === selectedGroup) {
|
||||
binding.pumpHistoryType.setSelection(i)
|
||||
break
|
||||
}
|
||||
}
|
||||
SystemClock.sleep(200)
|
||||
manualChange = false
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = PumpHistoryActivityBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
// Configuration
|
||||
val activePump = activePlugin.activePump
|
||||
|
||||
if (activePump is PumpDriverConfigurationCapable) {
|
||||
historyDataProvider = activePump.getPumpDriverConfiguration().getPumpHistoryDataProvider()
|
||||
} else {
|
||||
throw RuntimeException("PumpHistoryActivity can be used only with PumpDriverConfigurationCapable pump driver.")
|
||||
}
|
||||
|
||||
prepareData()
|
||||
|
||||
binding.pumpHistoryRecyclerView.setHasFixedSize(true)
|
||||
binding.pumpHistoryRecyclerView.layoutManager = LinearLayoutManager(this)
|
||||
recyclerViewAdapter = RecyclerViewAdapter(filteredHistoryList)
|
||||
binding.pumpHistoryRecyclerView.adapter = recyclerViewAdapter
|
||||
binding.pumpHistoryStatus.visibility = View.GONE
|
||||
typeListFull = getTypeList(historyDataProvider.getAllowedPumpHistoryGroups())
|
||||
val spinnerAdapter = ArrayAdapter(this, R.layout.spinner_centered, typeListFull!!)
|
||||
|
||||
binding.pumpHistoryText.text = historyDataProvider.getText(PumpHistoryText.PUMP_HISTORY)
|
||||
|
||||
binding.pumpHistoryType.adapter = spinnerAdapter
|
||||
binding.pumpHistoryType.getLayoutParams().width = fromDpToSize(historyDataProvider.getSpinnerWidthInPixels())
|
||||
binding.pumpHistoryType.requestLayout();
|
||||
binding.pumpHistoryType.setOnItemSelectedListener(object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
|
||||
if (manualChange) return
|
||||
val selected = binding.pumpHistoryType.getSelectedItem() as TypeList
|
||||
showingType = selected
|
||||
selectedGroup = selected.entryGroup
|
||||
filterHistory(selectedGroup)
|
||||
val selectedText = parent!!.getChildAt(0) as TextView
|
||||
selectedText.textSize = 15.0f // FIXME hack for selected item, also concerns pump_type marginTop
|
||||
|
||||
binding.pumpHistoryTop.requestLayout()
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) {
|
||||
if (manualChange) return
|
||||
filterHistory(PumpHistoryEntryGroup.All)
|
||||
}
|
||||
})
|
||||
binding.pumpHistoryTypeText.requestLayout()
|
||||
}
|
||||
|
||||
private fun getTypeList(list: List<PumpHistoryEntryGroup>?): List<TypeList> {
|
||||
val typeList = ArrayList<TypeList>()
|
||||
for (pumpHistoryEntryGroup in list!!) {
|
||||
typeList.add(TypeList(pumpHistoryEntryGroup))
|
||||
}
|
||||
return typeList
|
||||
}
|
||||
|
||||
fun fromDpToSize(dpSize: Int): Int {
|
||||
val scale = context.resources.displayMetrics.density
|
||||
val pixelsFl = ((dpSize * scale) + 0.5f)
|
||||
return pixelsFl.toInt()
|
||||
}
|
||||
|
||||
class TypeList internal constructor(var entryGroup: PumpHistoryEntryGroup) {
|
||||
|
||||
var name: String
|
||||
override fun toString(): String {
|
||||
return name
|
||||
}
|
||||
|
||||
init {
|
||||
name = entryGroup.translated!!
|
||||
}
|
||||
}
|
||||
|
||||
class RecyclerViewAdapter internal constructor(
|
||||
var historyList: List<PumpHistoryEntry>
|
||||
) : RecyclerView.Adapter<RecyclerViewAdapter.HistoryViewHolder>() {
|
||||
|
||||
fun setHistoryListInternal(historyList: List<PumpHistoryEntry>) {
|
||||
this.historyList = historyList
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): HistoryViewHolder {
|
||||
val v = LayoutInflater.from(viewGroup.context).inflate(
|
||||
R.layout.pump_history_item, //
|
||||
viewGroup, false
|
||||
)
|
||||
return HistoryViewHolder(v)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: HistoryViewHolder, position: Int) {
|
||||
val record = historyList[position]
|
||||
holder.timeView.text = record.getEntryDateTime()
|
||||
holder.typeView.text = record.getEntryType()
|
||||
holder.valueView.text = record.getEntryValue()
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return historyList.size
|
||||
}
|
||||
|
||||
class HistoryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
|
||||
var timeView: TextView
|
||||
var typeView: TextView
|
||||
var valueView: TextView
|
||||
|
||||
init {
|
||||
timeView = itemView.findViewById(R.id.pump_history_time)
|
||||
typeView = itemView.findViewById(R.id.pump_history_source)
|
||||
valueView = itemView.findViewById(R.id.pump_history_description)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
var showingType: TypeList? = null
|
||||
var selectedGroup = PumpHistoryEntryGroup.All
|
||||
}
|
||||
}
|
82
pump-common/src/main/res/layout/pump_ble_config_activity.xml
Executable file
82
pump-common/src/main/res/layout/pump_ble_config_activity.xml
Executable file
|
@ -0,0 +1,82 @@
|
|||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="5dp">
|
||||
|
||||
<!-- Currently selected Pump -->
|
||||
<TextView
|
||||
style="@style/TextAppearance.AppCompat.Title"
|
||||
android:id="@+id/pump_ble_config_currently_selected_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pump_ble_config_currently_selected_pump_name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="10dp"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pump_ble_config_currently_selected_pump_address"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="10dp"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/pump_ble_config_button_remove"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/ble_config_remove"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Scan -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.AppCompat.Title"
|
||||
android:id="@+id/pump_ble_config_scan_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/pump_ble_config_scan_start"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/ble_config_button_scan_start" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/pump_ble_config_button_scan_stop"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/ble_config_scan_stop"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Scan results -->
|
||||
<ListView
|
||||
android:id="@+id/pump_ble_config_scan_device_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
24
pump-common/src/main/res/layout/pump_ble_config_scan_item.xml
Executable file
24
pump-common/src/main/res/layout/pump_ble_config_scan_item.xml
Executable file
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pump_ble_config_scan_item_device_name"
|
||||
style="@style/TextAppearance.AppCompat.Medium.Inverse"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pump_ble_config_scan_item_device_address"
|
||||
style="@style/TextAppearance.AppCompat.Medium.Inverse"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12sp" />
|
||||
|
||||
</LinearLayout>
|
67
pump-common/src/main/res/layout/pump_history_activity.xml
Executable file
67
pump-common/src/main/res/layout/pump_history_activity.xml
Executable file
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/pump_history_root"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:background="?attr/activity_title_backgroundColor"
|
||||
tools:context=".ui.PumpHistoryActivity">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/pump_history_top"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pump_history_type_text"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_marginTop="7dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/pump_history_type"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall" />
|
||||
|
||||
<Spinner
|
||||
android:theme="@style/YourSpinnerItemStyle"
|
||||
android:id="@+id/pump_history_type"
|
||||
android:layout_width="100dp"
|
||||
|
||||
android:textSize="13sp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="5dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pump_history_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="right"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/pillborder"
|
||||
android:gravity="center_horizontal" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pump_history_status"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/pump_history_top"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_horizontal" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/pump_history_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_below="@+id/pump_history_status" />
|
||||
|
||||
</RelativeLayout>
|
32
pump-common/src/main/res/layout/pump_history_item.xml
Executable file
32
pump-common/src/main/res/layout/pump_history_item.xml
Executable file
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="40dp"
|
||||
android:paddingStart="10dp"
|
||||
android:paddingEnd="10dp">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pump_history_time"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pump_history_source"
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/pump_history_description"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="5dp"
|
||||
android:textSize="12sp" />
|
||||
|
||||
</LinearLayout>
|
|
@ -6,7 +6,10 @@
|
|||
<string name="pump_operation_not_yet_supported_by_pump">Operation not YET supported by pump.</string>
|
||||
<string name="common_resultok">OK</string>
|
||||
|
||||
<!-- PumoCommon - Pump Status -->
|
||||
<string name="pump_serial_number">Pump Serial Number</string>
|
||||
|
||||
|
||||
<!-- PumpCommon - Pump Status -->
|
||||
<string name="pump_status_never_contacted">Never contacted</string>
|
||||
<string name="pump_status_waking_up">Waking up</string>
|
||||
<string name="pump_status_error_comm">Error with communication</string>
|
||||
|
@ -15,6 +18,13 @@
|
|||
<string name="pump_status_invalid_config">Invalid configuration</string>
|
||||
<string name="pump_status_active">Active</string>
|
||||
<string name="pump_status_sleeping">Sleeping</string>
|
||||
<string name="pump_status_not_initialized">Not initialized</string>
|
||||
<string name="pump_status_initialized">Initialized</string>
|
||||
<string name="pump_status_encrypt">Encrypting communication</string>
|
||||
<string name="pump_status_ready">Ready</string>
|
||||
<string name="pump_status_busy">Busy</string>
|
||||
<string name="pump_status_suspended">Suspended</string>
|
||||
<string name="pump_status_executing_command">Executing Command</string>
|
||||
|
||||
<!-- PumpCommon - History Group -->
|
||||
<string name="history_group_basal">Basals</string>
|
||||
|
@ -27,5 +37,67 @@
|
|||
<string name="history_group_prime">Prime</string>
|
||||
<string name="history_group_alarm">Alarms</string>
|
||||
<string name="history_group_glucose">Glucose</string>
|
||||
<string name="history_group_base">Base</string>
|
||||
<string name="history_group_other">Other</string>
|
||||
<string name="history_group_events">All Events</string>
|
||||
<string name="history_group_events_no_stat">Events (no Stat)</string>
|
||||
|
||||
<!-- Time -->
|
||||
<string name="time_today">Today</string>
|
||||
<string name="time_last_hour">Last Hour</string>
|
||||
<string name="time_last_3_hours">Last 3 hours</string>
|
||||
<string name="time_last_6_hours">Last 6 hours</string>
|
||||
<string name="time_last_12_hours">Last 12 hours</string>
|
||||
<string name="time_last_2_days">Last 2 days</string>
|
||||
<string name="time_last_4_days">Last 4 days</string>
|
||||
<string name="time_last_week">Last week</string>
|
||||
<string name="time_last_month">Last month</string>
|
||||
|
||||
<!-- BLE Config -->
|
||||
<string name="ble_config_button_scan_start">Scan</string>
|
||||
<string name="ble_config_scan_stop">Stop</string>
|
||||
<string name="ble_config_scan_selected">Selected</string>
|
||||
<string name="ble_config_scan_scanning">Scanning</string>
|
||||
<string name="ble_config_scan_finished">Scanning finished</string>
|
||||
<string name="ble_config_scan_error">Scanning error: %1$d</string>
|
||||
<string name="ble_config_connected_never">Never</string>
|
||||
<string name="ble_config_remove">Remove</string>
|
||||
|
||||
<!-- BLE Errors -->
|
||||
<string name="ble_error_bt_disabled">Bluetooth disabled</string>
|
||||
<string name="ble_error_no_bt_adapter">No Bluetooth Adapter</string>
|
||||
<string name="ble_error_configured_pump_not_found">Configured Pump Not Found</string>
|
||||
<string name="ble_error_pump_unreachable">Pump unreachable</string>
|
||||
<string name="ble_error_failed_to_conn_to_ble_device">Failed To Connect To BLE Device</string>
|
||||
<string name="ble_error_encryption_failed">Encryption Failed</string>
|
||||
<string name="ble_error_pump_found_unbonded">Found not Bonded Pump</string>
|
||||
|
||||
|
||||
<!-- Pump Error -->
|
||||
<string name="pump_settings_error_basal_profiles_not_enabled">Basal profiles/patterns setting is not enabled on pump. Enable it on the pump.</string>
|
||||
<string name="pump_settings_error_incorrect_basal_profile_selected">Basal profile set on pump is incorrect (must be %s).</string>
|
||||
<string name="pump_settings_error_wrong_tbr_type_set">Wrong TBR type set on pump (must be %s).</string>
|
||||
<string name="pump_settings_error_wrong_max_bolus_set">Wrong Max Bolus set on Pump (must be %1$.2f).</string>
|
||||
<string name="pump_settings_error_wrong_max_basal_set">Wrong Max Basal set on Pump (must be %1$.2f).</string>
|
||||
|
||||
<!-- Pump History -->
|
||||
<string name="pump_history_type">Type:</string>
|
||||
|
||||
|
||||
<plurals name="duration_days">
|
||||
<item quantity="one">%1$d day</item>
|
||||
<item quantity="other">%1$d days</item>
|
||||
</plurals>
|
||||
<plurals name="duration_hours">
|
||||
<item quantity="one">%1$d hour</item>
|
||||
<item quantity="other">%1$d hours</item>
|
||||
</plurals>
|
||||
<plurals name="hoursago">
|
||||
<item quantity="one">%1$d hour ago</item>
|
||||
<item quantity="other">%1$d hours ago</item>
|
||||
</plurals>
|
||||
<plurals name="daysago">
|
||||
<item quantity="one">%1$d day ago</item>
|
||||
<item quantity="other">%1$d days ago</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
|
18
pump-common/src/main/res/values/styles.xml
Normal file
18
pump-common/src/main/res/values/styles.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<resources>
|
||||
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<item name="android:spinnerItemStyle">@style/YourSpinnerItemStyle</item>
|
||||
</style>
|
||||
|
||||
<style name="YourSpinnerItemStyle" parent="Widget.AppCompat.TextView.SpinnerItem">
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
<item name="android:textSize">15sp</item>
|
||||
</style>
|
||||
|
||||
<style name="mySpinnerItemStyle" parent="ThemeOverlay.AppCompat.Dark">
|
||||
<item name="android:textSize">15sp</item>
|
||||
<item name="android:textColor">@color/white</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
Loading…
Reference in a new issue