RS v3 encryption
This commit is contained in:
parent
d1d49a8db2
commit
5ce8b998d9
18 changed files with 549 additions and 108 deletions
|
@ -84,6 +84,8 @@
|
|||
<activity
|
||||
android:name=".plugins.pump.danaRS.activities.PairingHelperActivity"
|
||||
android:launchMode="singleTask" />
|
||||
<activity android:name=".plugins.pump.danaRS.activities.EnterPinActivity"
|
||||
android:launchMode="singleTask" />
|
||||
<activity android:name=".historyBrowser.HistoryBrowseActivity" />
|
||||
<activity android:name=".activities.SurveyActivity" />
|
||||
<activity android:name=".activities.StatsActivity" />
|
||||
|
|
|
@ -13,6 +13,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.dialog.RileyL
|
|||
import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRHistoryActivity
|
||||
import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRUserOptionsActivity
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.activities.BLEScanActivity
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.activities.EnterPinActivity
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.activities.PairingHelperActivity
|
||||
import info.nightscout.androidaps.plugins.pump.insight.activities.InsightAlertActivity
|
||||
import info.nightscout.androidaps.plugins.pump.insight.activities.InsightPairingActivity
|
||||
|
@ -28,6 +29,7 @@ abstract class ActivitiesModule {
|
|||
@ContributesAndroidInjector abstract fun contributeBolusProgressHelperActivity(): BolusProgressHelperActivity
|
||||
@ContributesAndroidInjector abstract fun contributeDanaRHistoryActivity(): DanaRHistoryActivity
|
||||
@ContributesAndroidInjector abstract fun contributeDanaRUserOptionsActivity(): DanaRUserOptionsActivity
|
||||
@ContributesAndroidInjector abstract fun contributeEnterPinActivity(): EnterPinActivity
|
||||
@ContributesAndroidInjector abstract fun contributeErrorHelperActivity(): ErrorHelperActivity
|
||||
@ContributesAndroidInjector abstract fun contributesHistoryBrowseActivity(): HistoryBrowseActivity
|
||||
@ContributesAndroidInjector abstract fun contributesInsightAlertActivity(): InsightAlertActivity
|
||||
|
|
|
@ -15,6 +15,8 @@ import info.nightscout.androidaps.data.Profile;
|
|||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.db.ExtendedBolus;
|
||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
||||
import info.nightscout.androidaps.events.EventConfigBuilderChange;
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
|
||||
import info.nightscout.androidaps.interfaces.Constraint;
|
||||
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
|
||||
|
@ -42,6 +44,8 @@ import info.nightscout.androidaps.utils.DecimalFormatter;
|
|||
import info.nightscout.androidaps.utils.Round;
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||
import io.reactivex.disposables.CompositeDisposable;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
/**
|
||||
* Created by mike on 28.01.2018.
|
||||
|
@ -50,6 +54,8 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
|||
public abstract class AbstractDanaRPlugin extends PumpPluginBase implements PumpInterface, DanaRInterface, ConstraintsInterface {
|
||||
protected AbstractDanaRExecutionService sExecutionService;
|
||||
|
||||
protected CompositeDisposable disposable = new CompositeDisposable();
|
||||
|
||||
protected boolean useExtendedBoluses = false;
|
||||
|
||||
protected PumpDescription pumpDescription = new PumpDescription();
|
||||
|
@ -86,6 +92,28 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
|
|||
this.sp = sp;
|
||||
}
|
||||
|
||||
@Override protected void onStart() {
|
||||
super.onStart();
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventConfigBuilderChange.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> danaRPump.setLastConnection(0))
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventPreferenceChange.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> {
|
||||
if (event.isChanged(getResourceHelper(), R.string.key_danar_bt_name))
|
||||
danaRPump.setLastConnection(0);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@Override protected void onStop() {
|
||||
super.onStop();
|
||||
disposable.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuspended() {
|
||||
return danaRPump.getPumpSuspended();
|
||||
|
@ -488,6 +516,4 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
|
|||
public void timeDateOrTimeZoneChanged() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import info.nightscout.androidaps.R
|
|||
import info.nightscout.androidaps.activities.TDDStatsActivity
|
||||
import info.nightscout.androidaps.dialogs.ProfileViewerDialog
|
||||
import info.nightscout.androidaps.events.EventExtendedBolusChange
|
||||
import info.nightscout.androidaps.events.EventInitializationChanged
|
||||
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
||||
import info.nightscout.androidaps.events.EventTempBasalChange
|
||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||
|
@ -24,13 +25,16 @@ import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRHistoryActi
|
|||
import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRUserOptionsActivity
|
||||
import info.nightscout.androidaps.plugins.pump.danaR.events.EventDanaRNewStatus
|
||||
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin
|
||||
import info.nightscout.androidaps.queue.events.EventQueueChanged
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.OKDialog
|
||||
import info.nightscout.androidaps.utils.SetWarnColor
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import kotlinx.android.synthetic.main.danar_fragment.*
|
||||
|
@ -43,8 +47,10 @@ class DanaRFragment : DaggerFragment() {
|
|||
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||
@Inject lateinit var danaRKoreanPlugin: DanaRKoreanPlugin
|
||||
@Inject lateinit var danaRSPlugin: DanaRSPlugin
|
||||
@Inject lateinit var danaRPump: DanaRPump
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var sp: SP
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
|
@ -93,12 +99,28 @@ class DanaRFragment : DaggerFragment() {
|
|||
danaRPump.lastConnection = 0
|
||||
commandQueue.readStatus("Clicked connect to pump", null)
|
||||
}
|
||||
if (danaRSPlugin.isEnabled())
|
||||
danar_btconnection.setOnLongClickListener {
|
||||
activity?.let {
|
||||
OKDialog.showConfirmation(it, resourceHelper.gs(R.string.resetpairing), Runnable {
|
||||
sp.remove(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName)
|
||||
sp.remove(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName)
|
||||
sp.remove(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName)
|
||||
sp.remove(resourceHelper.gs(R.string.key_danars_v3_randomsynckey) + danaRSPlugin.mDeviceName)
|
||||
})
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
loopHandler.postDelayed(refreshLoop, T.mins(1).msecs())
|
||||
disposable += rxBus
|
||||
.toObservable(EventInitializationChanged::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ updateGUI() }, { fabricPrivacy.logException(it) })
|
||||
disposable += rxBus
|
||||
.toObservable(EventDanaRNewStatus::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
|
|
@ -27,6 +27,7 @@ import info.nightscout.androidaps.data.PumpEnactResult;
|
|||
import info.nightscout.androidaps.db.ExtendedBolus;
|
||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
||||
import info.nightscout.androidaps.events.EventAppExit;
|
||||
import info.nightscout.androidaps.events.EventConfigBuilderChange;
|
||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
|
||||
import info.nightscout.androidaps.interfaces.Constraint;
|
||||
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
|
||||
|
@ -157,6 +158,11 @@ public class DanaRSPlugin extends PumpPluginBase implements PumpInterface, DanaR
|
|||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> context.unbindService(mConnection), fabricPrivacy::logException)
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventConfigBuilderChange.class)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe(event -> danaRPump.setLastConnection(0))
|
||||
);
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventDanaRSDeviceChange.class)
|
||||
.observeOn(Schedulers.io())
|
||||
|
@ -191,6 +197,7 @@ public class DanaRSPlugin extends PumpPluginBase implements PumpInterface, DanaR
|
|||
private void loadAddress() {
|
||||
mDeviceAddress = sp.getString(R.string.key_danars_address, "");
|
||||
mDeviceName = sp.getString(R.string.key_danars_name, "");
|
||||
danaRPump.setLastConnection(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
package info.nightscout.androidaps.plugins.pump.danaRS.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Base64
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
|
||||
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.services.BLEComm
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.OKDialog
|
||||
import info.nightscout.androidaps.utils.extensions.hexStringToByteArray
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import info.nightscout.androidaps.utils.textValidator.DefaultEditTextValidator
|
||||
import info.nightscout.androidaps.utils.textValidator.EditTextValidator
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import kotlinx.android.synthetic.main.danars_enter_pin_activity.*
|
||||
import kotlinx.android.synthetic.main.okcancel.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.experimental.xor
|
||||
|
||||
class EnterPinActivity : NoSplashAppCompatActivity() {
|
||||
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var danaRSPlugin: DanaRSPlugin
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var bleComm: BLEComm
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.danars_enter_pin_activity)
|
||||
|
||||
val p1 = DefaultEditTextValidator(rs_v3_pin1, this)
|
||||
.setTestErrorString(resourceHelper.gs(R.string.error_mustbe12hexadidits), this)
|
||||
.setCustomRegexp(resourceHelper.gs(R.string.twelvehexanumber), this)
|
||||
.setTestType(EditTextValidator.TEST_REGEXP, this)
|
||||
val p2 = DefaultEditTextValidator(rs_v3_pin2, this)
|
||||
.setTestErrorString(resourceHelper.gs(R.string.error_mustbe8hexadidits), this)
|
||||
.setCustomRegexp(resourceHelper.gs(R.string.eighthexanumber), this)
|
||||
.setTestType(EditTextValidator.TEST_REGEXP, this)
|
||||
|
||||
ok.setOnClickListener {
|
||||
if (p1.testValidity(false) && p2.testValidity(false)) {
|
||||
val result = checkPairingCheckSum(
|
||||
rs_v3_pin1.text.toString().hexStringToByteArray(),
|
||||
rs_v3_pin2.text.toString().substring(0..5).hexStringToByteArray(),
|
||||
rs_v3_pin2.text.toString().substring(6..7).hexStringToByteArray())
|
||||
if (result) {
|
||||
bleComm.finishV3Pairing()
|
||||
finish()
|
||||
}
|
||||
else OKDialog.show(this, resourceHelper.gs(R.string.error), resourceHelper.gs(R.string.danar_invalidinput))
|
||||
}
|
||||
}
|
||||
cancel.setOnClickListener { finish() }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
disposable.add(rxBus
|
||||
.toObservable(EventPumpStatusChanged::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ if (it.status == EventPumpStatusChanged.Status.DISCONNECTED) finish() }) { fabricPrivacy.logException(it) }
|
||||
)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
private fun checkPairingCheckSum(pairingKey: ByteArray, randomPairingKey: ByteArray, checksum: ByteArray): Boolean {
|
||||
|
||||
// pairingKey ByteArray(6)
|
||||
// randomPairingKey ByteArray(3)
|
||||
// checksum ByteArray(1)
|
||||
|
||||
var pairingKeyCheckSum: Byte = 0
|
||||
for (i in pairingKey.indices)
|
||||
pairingKeyCheckSum = pairingKeyCheckSum xor pairingKey[i]
|
||||
|
||||
sp.putString(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName, Base64.encodeToString(pairingKey, Base64.DEFAULT))
|
||||
|
||||
for (i in randomPairingKey.indices)
|
||||
pairingKeyCheckSum = pairingKeyCheckSum xor randomPairingKey[i]
|
||||
|
||||
sp.putString(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName, Base64.encodeToString(randomPairingKey, Base64.DEFAULT))
|
||||
|
||||
return checksum[0] == pairingKeyCheckSum
|
||||
}
|
||||
|
||||
}
|
|
@ -69,7 +69,7 @@ class DanaRSMessageHashTable @Inject constructor(
|
|||
put(DanaRS_Packet_General_Delivery_Status(aapsLogger))
|
||||
put(DanaRS_Packet_General_Get_Password(aapsLogger, danaRPump))
|
||||
put(DanaRS_Packet_General_Initial_Screen_Information(aapsLogger, danaRPump))
|
||||
put(DanaRS_Packet_Notify_Alarm(aapsLogger, resourceHelper))
|
||||
put(DanaRS_Packet_Notify_Alarm(aapsLogger, resourceHelper, rxBus))
|
||||
put(DanaRS_Packet_Notify_Delivery_Complete(aapsLogger, rxBus, resourceHelper, danaRSPlugin))
|
||||
put(DanaRS_Packet_Notify_Delivery_Rate_Display(aapsLogger, rxBus, resourceHelper, danaRSPlugin))
|
||||
put(DanaRS_Packet_Notify_Missed_Bolus_Alarm(aapsLogger))
|
||||
|
|
|
@ -11,7 +11,6 @@ class DanaRS_Packet_General_Initial_Screen_Information(
|
|||
) : DanaRS_Packet() {
|
||||
|
||||
init {
|
||||
type = BleEncryption.DANAR_PACKET__TYPE_RESPONSE
|
||||
opCode = BleEncryption.DANAR_PACKET__OPCODE_REVIEW__INITIAL_SCREEN_INFORMATION
|
||||
aapsLogger.debug(LTag.PUMPCOMM, "New message")
|
||||
}
|
||||
|
|
|
@ -4,12 +4,16 @@ import info.nightscout.androidaps.plugins.pump.danaRS.encryption.BleEncryption
|
|||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
|
||||
class DanaRS_Packet_Notify_Alarm(
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val resourceHelper: ResourceHelper
|
||||
private val resourceHelper: ResourceHelper,
|
||||
private val rxBus: RxBusWrapper
|
||||
) : DanaRS_Packet() {
|
||||
|
||||
init {
|
||||
|
@ -29,11 +33,11 @@ class DanaRS_Packet_Notify_Alarm(
|
|||
0x03 -> // Occlusion
|
||||
errorString = resourceHelper.gs(R.string.occlusion)
|
||||
0x04 -> // LOW BATTERY
|
||||
errorString = resourceHelper.gs(R.string.lowbattery)
|
||||
errorString = resourceHelper.gs(R.string.pumpshutdown)
|
||||
0x05 -> // Shutdown
|
||||
errorString = resourceHelper.gs(R.string.lowbattery)
|
||||
0x06 -> // Basal Compare
|
||||
errorString = "BasalCompare ????"
|
||||
errorString = resourceHelper.gs(R.string.basalcompare)
|
||||
0x09 -> // Empty Reservoir
|
||||
errorString = resourceHelper.gs(R.string.emptyreservoir)
|
||||
0x07, 0xFF -> // Blood sugar measurement alert
|
||||
|
@ -41,7 +45,7 @@ class DanaRS_Packet_Notify_Alarm(
|
|||
0x08, 0xFE -> // Remaining insulin level
|
||||
errorString = resourceHelper.gs(R.string.remaininsulinalert)
|
||||
0xFD -> // Blood sugar check miss alarm
|
||||
errorString = "Blood sugar check miss alarm ???"
|
||||
errorString = resourceHelper.gs(R.string.missedbolus)
|
||||
}
|
||||
// No error no need to upload anything
|
||||
if (errorString == "") {
|
||||
|
@ -49,6 +53,8 @@ class DanaRS_Packet_Notify_Alarm(
|
|||
aapsLogger.debug(LTag.PUMPCOMM, "Error detected: $errorString")
|
||||
return
|
||||
}
|
||||
val notification = Notification(Notification.USERMESSAGE, errorString, Notification.URGENT)
|
||||
rxBus.send(EventNewNotification(notification))
|
||||
NSUpload.uploadError(errorString)
|
||||
}
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ public class BleEncryption {
|
|||
return encryptSecondLevelPacketJni(context, bytes);
|
||||
}
|
||||
|
||||
public byte[] ecryptSecondLevelPacket(byte[] bytes) {
|
||||
public byte[] decryptSecondLevelPacket(byte[] bytes) {
|
||||
return decryptSecondLevelPacketJni(context, bytes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.bluetooth.*
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.SystemClock
|
||||
import android.util.Base64
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
||||
import info.nightscout.androidaps.logging.AAPSLogger
|
||||
|
@ -14,11 +15,13 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotifi
|
|||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPump
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.activities.EnterPinActivity
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.activities.PairingHelperActivity
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.comm.DanaRSMessageHashTable
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.comm.DanaRS_Packet
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.encryption.BleEncryption
|
||||
import info.nightscout.androidaps.plugins.pump.danaRS.events.EventDanaRSPairingSuccess
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import okhttp3.internal.notify
|
||||
|
@ -58,8 +61,17 @@ class BLEComm @Inject internal constructor(
|
|||
private var connectDeviceName: String? = null
|
||||
private var bluetoothGatt: BluetoothGatt? = null
|
||||
|
||||
private var v3Encryption: Boolean = false
|
||||
set(newValue) {
|
||||
bleEncryption.setEnhancedEncryption(newValue)
|
||||
field = newValue
|
||||
}
|
||||
private var isEasyMode: Boolean = false
|
||||
private var isUnitUD: Boolean = false
|
||||
|
||||
var isConnected = false
|
||||
var isConnecting = false
|
||||
private var encryptedDataRead = false
|
||||
private var uartRead: BluetoothGattCharacteristic? = null
|
||||
private var uartWrite: BluetoothGattCharacteristic? = null
|
||||
|
||||
|
@ -106,6 +118,14 @@ class BLEComm @Inject internal constructor(
|
|||
fun disconnect(from: String) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "disconnect from: $from")
|
||||
|
||||
if (!encryptedDataRead) {
|
||||
// there was no response from pump after started encryption
|
||||
// assume pairing keys are invalid
|
||||
sp.remove(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName)
|
||||
sp.remove(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName)
|
||||
sp.remove(resourceHelper.gs(R.string.key_danars_v3_randomsynckey) + danaRSPlugin.mDeviceName)
|
||||
ToastUtils.showToastInUiThread(context, R.string.invalidpairing)
|
||||
}
|
||||
// cancel previous scheduled disconnection to prevent closing upcoming connection
|
||||
scheduledDisconnection?.cancel(false)
|
||||
scheduledDisconnection = null
|
||||
|
@ -118,6 +138,7 @@ class BLEComm @Inject internal constructor(
|
|||
setCharacteristicNotification(uartReadBTGattChar, false)
|
||||
bluetoothGatt?.disconnect()
|
||||
isConnected = false
|
||||
encryptedDataRead = false
|
||||
SystemClock.sleep(2000)
|
||||
}
|
||||
|
||||
|
@ -142,19 +163,20 @@ class BLEComm @Inject internal constructor(
|
|||
}
|
||||
|
||||
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicRead: " + DanaRS_Packet.toHexString(characteristic.value))
|
||||
addToReadBuffer(characteristic.value)
|
||||
readDataParsing()
|
||||
// for v3 after initial handshake it's encrypted - useless
|
||||
// aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicRead: " + DanaRS_Packet.toHexString(characteristic.value))
|
||||
readDataParsing(characteristic.value)
|
||||
}
|
||||
|
||||
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicChanged: " + DanaRS_Packet.toHexString(characteristic.value))
|
||||
addToReadBuffer(characteristic.value)
|
||||
Thread(Runnable { readDataParsing() }).start()
|
||||
// for v3 after initial handshake it's encrypted - useless
|
||||
// aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicChanged: " + DanaRS_Packet.toHexString(characteristic.value))
|
||||
readDataParsing(characteristic.value)
|
||||
}
|
||||
|
||||
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicWrite: " + DanaRS_Packet.toHexString(characteristic.value))
|
||||
// for v3 after initial handshake it's encrypted - useless
|
||||
// aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicWrite: " + DanaRS_Packet.toHexString(characteristic.value))
|
||||
Thread(Runnable {
|
||||
synchronized(mSendQueue) {
|
||||
// after message sent, check if there is the rest of the message waiting and send it
|
||||
|
@ -175,9 +197,10 @@ class BLEComm @Inject internal constructor(
|
|||
aapsLogger.error("BluetoothAdapter not initialized_ERROR")
|
||||
isConnecting = false
|
||||
isConnected = false
|
||||
encryptedDataRead = false
|
||||
return
|
||||
}
|
||||
bluetoothGatt!!.setCharacteristicNotification(characteristic, enabled)
|
||||
bluetoothGatt?.setCharacteristicNotification(characteristic, enabled)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
@ -188,13 +211,15 @@ class BLEComm @Inject internal constructor(
|
|||
aapsLogger.error("BluetoothAdapter not initialized_ERROR")
|
||||
isConnecting = false
|
||||
isConnected = false
|
||||
encryptedDataRead = false
|
||||
return@Runnable
|
||||
}
|
||||
characteristic.value = data
|
||||
characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
|
||||
aapsLogger.debug("writeCharacteristic:" + DanaRS_Packet.toHexString(data))
|
||||
bluetoothGatt!!.writeCharacteristic(characteristic)
|
||||
//aapsLogger.debug("writeCharacteristic:" + DanaRS_Packet.toHexString(data))
|
||||
bluetoothGatt?.writeCharacteristic(characteristic)
|
||||
}).start()
|
||||
waitMillis(50)
|
||||
}
|
||||
|
||||
private val uartReadBTGattChar: BluetoothGattCharacteristic
|
||||
|
@ -211,6 +236,7 @@ class BLEComm @Inject internal constructor(
|
|||
aapsLogger.error("BluetoothAdapter not initialized_ERROR")
|
||||
isConnecting = false
|
||||
isConnected = false
|
||||
encryptedDataRead = false
|
||||
return null
|
||||
}
|
||||
return bluetoothGatt?.services
|
||||
|
@ -243,6 +269,8 @@ class BLEComm @Inject internal constructor(
|
|||
close()
|
||||
isConnected = false
|
||||
isConnecting = false
|
||||
v3Encryption = false
|
||||
encryptedDataRead = false
|
||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Device was disconnected " + gatt.device.name) //Device was disconnected
|
||||
}
|
||||
|
@ -263,13 +291,20 @@ class BLEComm @Inject internal constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun readDataParsing() {
|
||||
private fun readDataParsing(receviedData: ByteArray) {
|
||||
//aapsLogger.debug(LTag.PUMPBTCOMM, "readDataParsing")
|
||||
var startSignatureFound = false
|
||||
var packetIsValid = false
|
||||
var isProcessing: Boolean
|
||||
isProcessing = true
|
||||
var inputBuffer: ByteArray? = null
|
||||
|
||||
// decrypt 2nd level after successful connection
|
||||
val incomingBuffer = if (v3Encryption && isConnected)
|
||||
bleEncryption.decryptSecondLevelPacket(receviedData).also { encryptedDataRead = true }
|
||||
else receviedData
|
||||
addToReadBuffer(incomingBuffer)
|
||||
|
||||
while (isProcessing) {
|
||||
var length = 0
|
||||
synchronized(readBuffer) {
|
||||
|
@ -321,9 +356,12 @@ class BLEComm @Inject internal constructor(
|
|||
// decrypt the packet
|
||||
bleEncryption.getDecryptedPacket(inputBuffer)?.let { decryptedBuffer ->
|
||||
when (decryptedBuffer[0]) {
|
||||
BleEncryption.DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE.toByte() -> when (decryptedBuffer[1]) {
|
||||
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK.toByte() -> if (decryptedBuffer.size == 4 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) {
|
||||
BleEncryption.DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE.toByte() ->
|
||||
when (decryptedBuffer[1]) {
|
||||
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK.toByte() ->
|
||||
if (decryptedBuffer.size == 4 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (OK)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||
v3Encryption = false
|
||||
// Grab pairing key from preferences if exists
|
||||
val pairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName, "")
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Using stored pairing key: $pairingKey")
|
||||
|
@ -336,6 +374,36 @@ class BLEComm @Inject internal constructor(
|
|||
// Stored pairing key does not exists, request pairing
|
||||
sendPairingRequest()
|
||||
}
|
||||
} else if (decryptedBuffer.size == 9 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) {
|
||||
// v3 2nd layer encryption
|
||||
v3Encryption = true
|
||||
val model = decryptedBuffer[5]
|
||||
// val protocol = decryptedBuffer[7]
|
||||
if (model == 0x05.toByte()) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK V3 (OK)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||
// Dana RS Pump
|
||||
val randomPairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName, "")
|
||||
val pairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName, "")
|
||||
if (randomPairingKey.isNotEmpty() && pairingKey.isNotEmpty()) {
|
||||
val randomSyncKey = String.format("%02x", decryptedBuffer[decryptedBuffer.size - 1])
|
||||
sp.putString(resourceHelper.gs(R.string.key_danars_v3_randomsynckey) + danaRSPlugin.mDeviceName, randomSyncKey)
|
||||
val tPairingKey = Base64.decode(pairingKey, Base64.DEFAULT)
|
||||
val tRandomPairingKey = Base64.decode(randomPairingKey, Base64.DEFAULT)
|
||||
var tRandomSyncKey: Byte = 0
|
||||
if (randomSyncKey.isNotEmpty()) {
|
||||
tRandomSyncKey = randomSyncKey.toInt(16).toByte()
|
||||
}
|
||||
bleEncryption.setPairingKeys(tPairingKey, tRandomPairingKey, tRandomSyncKey)
|
||||
sendV3PairingInformation(0)
|
||||
} else {
|
||||
sendV3PairingInformation(1)
|
||||
}
|
||||
} else if (model == 0x06.toByte()) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK V3 EASY (OK)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||
// Dana RS Easy
|
||||
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__GET_EASYMENU_CHECK, null, null)
|
||||
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||
}
|
||||
} else if (decryptedBuffer.size == 6 && decryptedBuffer[2] == 'P'.toByte() && decryptedBuffer[3] == 'U'.toByte() && decryptedBuffer[4] == 'M'.toByte() && decryptedBuffer[5] == 'P'.toByte()) {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (PUMP)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||
mSendQueue.clear()
|
||||
|
@ -357,6 +425,39 @@ class BLEComm @Inject internal constructor(
|
|||
rxBus.send(EventNewNotification(n))
|
||||
}
|
||||
|
||||
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION.toByte() -> {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__TIME_INFORMATION " + /*message.getMessageName() + " " + */DanaRS_Packet.toHexString(decryptedBuffer))
|
||||
if (v3Encryption) {
|
||||
// decryptedBuffer[2] : 0x00 OK 0x01 Error, No pairing
|
||||
if (decryptedBuffer[2] == 0x00.toByte()) {
|
||||
val randomPairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName, "")
|
||||
val pairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName, "")
|
||||
if (randomPairingKey.isNotEmpty() && pairingKey.isNotEmpty()) {
|
||||
// expecting successful connect
|
||||
isConnected = true
|
||||
isConnecting = false
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Connect !!")
|
||||
} else {
|
||||
context.startActivity(Intent(context, EnterPinActivity::class.java).also { it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Request pairing keys !!")
|
||||
}
|
||||
} else {
|
||||
sendV3PairingInformation(1)
|
||||
}
|
||||
|
||||
} else {
|
||||
val size = decryptedBuffer.size
|
||||
var pass: Int = (decryptedBuffer[size - 1].toInt() and 0x000000FF shl 8) + (decryptedBuffer[size - 2].toInt() and 0x000000FF)
|
||||
pass = pass xor 3463
|
||||
danaRPump.rsPassword = Integer.toHexString(pass)
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Pump user password: " + Integer.toHexString(pass))
|
||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
|
||||
isConnected = true
|
||||
isConnecting = false
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "RS connected and status read")
|
||||
}
|
||||
}
|
||||
|
||||
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__CHECK_PASSKEY.toByte() -> {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__CHECK_PASSKEY" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||
if (decryptedBuffer[2] == 0x00.toByte()) {
|
||||
|
@ -386,17 +487,29 @@ class BLEComm @Inject internal constructor(
|
|||
aapsLogger.debug(LTag.PUMPBTCOMM, "Got pairing key: " + DanaRS_Packet.bytesToHex(pairingKey))
|
||||
}
|
||||
|
||||
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION.toByte() -> {
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__TIME_INFORMATION " + /*message.getMessageName() + " " + */DanaRS_Packet.toHexString(decryptedBuffer))
|
||||
val size = decryptedBuffer.size
|
||||
var pass: Int = (decryptedBuffer[size - 1].toInt() and 0x000000FF shl 8) + (decryptedBuffer[size - 2].toInt() and 0x000000FF)
|
||||
pass = pass xor 3463
|
||||
danaRPump.rsPassword = Integer.toHexString(pass)
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Pump user password: " + Integer.toHexString(pass))
|
||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
|
||||
isConnected = true
|
||||
isConnecting = false
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, "RS connected and status read")
|
||||
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__GET_PUMP_CHECK.toByte() -> {
|
||||
if (decryptedBuffer[2] == 0x05.toByte()) {
|
||||
// not easy mode, request time info
|
||||
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION, null, null)
|
||||
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||
} else {
|
||||
// easy mode
|
||||
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__GET_EASYMENU_CHECK, null, null)
|
||||
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__GET_EASYMENU_CHECK.toByte() -> {
|
||||
isEasyMode = decryptedBuffer[2] == 0x01.toByte()
|
||||
isUnitUD = decryptedBuffer[3] == 0x01.toByte()
|
||||
|
||||
// request time information
|
||||
if (v3Encryption) {
|
||||
sendV3PairingInformation(1)
|
||||
} else {
|
||||
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION, null, null)
|
||||
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -449,6 +562,8 @@ class BLEComm @Inject internal constructor(
|
|||
val params = message.requestParams
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + message.friendlyName + " " + DanaRS_Packet.toHexString(command) + " " + DanaRS_Packet.toHexString(params))
|
||||
var bytes = bleEncryption.getEncryptedPacket(message.opCode, params, null)
|
||||
if (v3Encryption)
|
||||
bytes = bleEncryption.encryptSecondLevelPacket(bytes)
|
||||
// If there is another message not completely sent, add to queue only
|
||||
if (mSendQueue.size > 0) {
|
||||
// Split to parts per 20 bytes max
|
||||
|
@ -509,13 +624,30 @@ class BLEComm @Inject internal constructor(
|
|||
}
|
||||
}
|
||||
|
||||
fun finishV3Pairing() {
|
||||
val randomPairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName, "")
|
||||
val pairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName, "")
|
||||
if (randomPairingKey.isNotEmpty() && pairingKey.isNotEmpty()) {
|
||||
val tPairingKey = Base64.decode(pairingKey, Base64.DEFAULT)
|
||||
val tRandomPairingKey = Base64.decode(randomPairingKey, Base64.DEFAULT)
|
||||
val tRandomSyncKey: Byte = 0
|
||||
bleEncryption.setPairingKeys(tPairingKey, tRandomPairingKey, tRandomSyncKey)
|
||||
sendV3PairingInformation(0)
|
||||
}
|
||||
}
|
||||
|
||||
// 0x00 Start encryption, 0x01 Request pairing
|
||||
private fun sendV3PairingInformation(requestNewPairing: Int) {
|
||||
val params = byteArrayOf(requestNewPairing.toByte())
|
||||
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION, params, null)
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + "ENCRYPTION__TIME_INFORMATION" + " " + DanaRS_Packet.toHexString(bytes))
|
||||
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||
}
|
||||
|
||||
private fun sendPairingRequest() {
|
||||
// Start activity which is waiting 20sec
|
||||
// On pump pairing request is displayed and is waiting for conformation
|
||||
val i = Intent()
|
||||
i.setClass(context, PairingHelperActivity::class.java)
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
context.startActivity(i)
|
||||
context.startActivity(Intent(context, PairingHelperActivity::class.java).also { it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||
val bytes = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_REQUEST, null, null)
|
||||
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + "ENCRYPTION__PASSKEY_REQUEST" + " " + DanaRS_Packet.toHexString(bytes))
|
||||
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
package info.nightscout.androidaps.utils.extensions
|
||||
|
||||
private val HEX_CHARS = "0123456789ABCDEF".toCharArray()
|
||||
|
||||
fun ByteArray.toHex() : String{
|
||||
val result = StringBuffer()
|
||||
|
||||
forEach {
|
||||
val octet = it.toInt()
|
||||
val firstIndex = (octet and 0xF0).ushr(4)
|
||||
val secondIndex = octet and 0x0F
|
||||
result.append(HEX_CHARS[firstIndex])
|
||||
result.append(HEX_CHARS[secondIndex])
|
||||
}
|
||||
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
fun String.hexStringToByteArray() : ByteArray {
|
||||
|
||||
val result = ByteArray(length / 2)
|
||||
|
||||
for (i in 0 until length step 2) {
|
||||
val firstIndex = HEX_CHARS.indexOf(this[i]);
|
||||
val secondIndex = HEX_CHARS.indexOf(this[i + 1]);
|
||||
|
||||
val octet = firstIndex.shl(4).or(secondIndex)
|
||||
result.set(i.shr(1), octet.toByte())
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
|
@ -15,6 +15,9 @@ class DefaultEditTextValidator : EditTextValidator {
|
|||
protected var testErrorString: String? = null
|
||||
protected var emptyAllowed = false
|
||||
protected lateinit var editTextView: EditText
|
||||
private var tw: TextWatcher? = null
|
||||
private var defaultEmptyErrorString: String? = null
|
||||
|
||||
protected var testType: Int
|
||||
protected var classType: String? = null
|
||||
protected var customRegexp: String? = null
|
||||
|
@ -26,8 +29,6 @@ class DefaultEditTextValidator : EditTextValidator {
|
|||
protected var maxNumber = 0
|
||||
protected var floatminNumber = 0f
|
||||
protected var floatmaxNumber = 0f
|
||||
private var tw: TextWatcher? = null
|
||||
private var defaultEmptyErrorString: String? = null
|
||||
|
||||
@Suppress("unused")
|
||||
constructor(editTextView: EditText, context: Context) {
|
||||
|
@ -167,44 +168,50 @@ class DefaultEditTextValidator : EditTextValidator {
|
|||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun setClassType(classType: String?, testErrorString: String?, context: Context) {
|
||||
fun setClassType(classType: String?, testErrorString: String?, context: Context) : DefaultEditTextValidator{
|
||||
testType = EditTextValidator.TEST_CUSTOM
|
||||
this.classType = classType
|
||||
this.testErrorString = testErrorString
|
||||
resetValidators(context)
|
||||
return this
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun setCustomRegexp(customRegexp: String?, context: Context) {
|
||||
fun setCustomRegexp(customRegexp: String?, context: Context) : DefaultEditTextValidator {
|
||||
testType = EditTextValidator.TEST_REGEXP
|
||||
this.customRegexp = customRegexp
|
||||
resetValidators(context)
|
||||
return this
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun setEmptyAllowed(emptyAllowed: Boolean, context: Context) {
|
||||
fun setEmptyAllowed(emptyAllowed: Boolean, context: Context) : DefaultEditTextValidator {
|
||||
this.emptyAllowed = emptyAllowed
|
||||
resetValidators(context)
|
||||
return this
|
||||
}
|
||||
|
||||
fun setEmptyErrorString(emptyErrorString: String?) {
|
||||
fun setEmptyErrorString(emptyErrorString: String?) : DefaultEditTextValidator {
|
||||
emptyErrorStringActual = if (!TextUtils.isEmpty(emptyErrorString)) {
|
||||
emptyErrorString
|
||||
} else {
|
||||
defaultEmptyErrorString
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun setTestErrorString(testErrorString: String?, context: Context) {
|
||||
fun setTestErrorString(testErrorString: String?, context: Context) : DefaultEditTextValidator {
|
||||
this.testErrorString = testErrorString
|
||||
resetValidators(context)
|
||||
return this
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun setTestType(testType: Int, context: Context) {
|
||||
fun setTestType(testType: Int, context: Context) : DefaultEditTextValidator {
|
||||
this.testType = testType
|
||||
resetValidators(context)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun testValidity(): Boolean {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.utils.textValidator
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.core.content.res.TypedArrayUtils
|
||||
|
@ -22,7 +23,7 @@ class ValidatingEditTextPreference(ctx: Context, attrs: AttributeSet, defStyleAt
|
|||
constructor(ctx: Context, attrs: AttributeSet, defStyle: Int)
|
||||
: this(ctx, attrs, defStyle, 0)
|
||||
|
||||
constructor(ctx: Context, attrs: AttributeSet)
|
||||
@SuppressLint("RestrictedApi") constructor(ctx: Context, attrs: AttributeSet)
|
||||
: this(ctx, attrs, TypedArrayUtils.getAttr(ctx, R.attr.editTextPreferenceStyle,
|
||||
R.attr.editTextPreferenceStyle))
|
||||
|
||||
|
|
90
app/src/main/res/layout/danars_enter_pin_activity.xml
Normal file
90
app/src/main/res/layout/danars_enter_pin_activity.xml
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".plugins.pump.danaRS.activities.EnterPinActivity">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:background="@color/activity_title_background"
|
||||
android:orientation="horizontal"
|
||||
android:padding="5dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/pairing"
|
||||
android:src="@drawable/ic_bluetooth_white_48dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:text="@string/pairing"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:labelFor="@+id/rs_v3_pin1"
|
||||
android:text="@string/num1pin"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/rs_v3_pin1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autofillHints="@string/pin1"
|
||||
android:digits="0123456789ABCDEF"
|
||||
android:gravity="center_horizontal"
|
||||
android:inputType="textCapCharacters"
|
||||
android:text=""
|
||||
android:textSize="25sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:labelFor="@+id/rs_v3_pin2"
|
||||
android:text="@string/num2pin"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
|
||||
|
||||
|
||||
<EditText
|
||||
android:id="@+id/rs_v3_pin2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:autofillHints="@string/pin2"
|
||||
android:digits="0123456789ABCDEF"
|
||||
android:gravity="center_horizontal"
|
||||
android:inputType="textCapCharacters"
|
||||
android:text=""
|
||||
android:textSize="25sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/press_ok_on_the_pump"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
|
||||
|
||||
<include layout="@layout/okcancel" />
|
||||
|
||||
</LinearLayout>
|
|
@ -417,6 +417,7 @@
|
|||
<string name="open_settings_on_wear">Open Settings on Wear</string>
|
||||
<string name="pumperror">Pump Error</string>
|
||||
<string name="lowbattery">Low Battery</string>
|
||||
<string name="basalcompare">Delivering less than preset basal rate</string>
|
||||
<string name="pumpshutdown">Pump Shutdown</string>
|
||||
<string name="batterydischarged">Pump Battery Discharged</string>
|
||||
<string name="danarkoreanpump">DanaR Korean</string>
|
||||
|
@ -731,12 +732,16 @@
|
|||
<string name="pairingtimedout">Pairing timed out</string>
|
||||
<string name="pairing">Pairing</string>
|
||||
<string name="key_danars_pairingkey" translatable="false">danars_pairing_key_</string>
|
||||
<string name="key_danars_v3_randompairingkey" translatable="false">danars_v3_randompairing_key_</string>
|
||||
<string name="key_danars_v3_pairingkey" translatable="false">danars_v3_pairing_key_</string>
|
||||
<string name="key_danars_v3_randomsynckey" translatable="false">danars_v3_randomsync_key_</string>
|
||||
<string name="key_danars_address" translatable="false">danars_address</string>
|
||||
<string name="key_danars_name" translatable="false">danars_name</string>
|
||||
<string name="danars_nodeviceavailable">No device found so far</string>
|
||||
<string name="emptyreservoir">Empty reservoir</string>
|
||||
<string name="bloodsugarmeasurementalert">Blood sugar measurement alert</string>
|
||||
<string name="remaininsulinalert">Remaining insulin level</string>
|
||||
<string name="missedbolus">Missed bolus</string>
|
||||
<string name="danarspump">DanaRS</string>
|
||||
<string name="danarspump_shortname">Dana</string>
|
||||
<string name="selectedpump">Selected pump</string>
|
||||
|
@ -1736,4 +1741,11 @@
|
|||
<string name="smscommunicator_otp_install_info">On each follower phone install Authenticator app that support RFC 6238 TOTP tokens. Popular free apps are:\n • Authy\n • Google Authenticator\n • LastPass Authenticator\n • FreeOTP Authenticator</string>
|
||||
<string name="smscommunicator_otp_provisioning_warning">DO NOT SHARE this code online!\nUse it only to setup Authenticator App on follower phones.</string>
|
||||
<string name="smscommunicator_otp_reset_warning">By reseting authenticator you make all already provisioned authenticators invalid. You will need to set up them again!</string>
|
||||
<string name="pin1">PIN1</string>
|
||||
<string name="pin2">PIN2</string>
|
||||
<string name="press_ok_on_the_pump">Press OK on the pump\nand enter 2 displayed numbers\nKeep display on pump ON by pressing minus button until you finish entering code.</string>
|
||||
<string name="num1pin">1: (12 digits)</string>
|
||||
<string name="num2pin">2: (8 digits)</string>
|
||||
<string name="resetpairing">Reset pairing information?</string>
|
||||
<string name="invalidpairing">Invalid pairing information. Requesting new pairing</string>
|
||||
</resources>
|
||||
|
|
|
@ -16,9 +16,13 @@
|
|||
<string name="error_date_not_valid">Format not valid</string>
|
||||
<string name="error_mustbe4digitnumber">Must be 4 digit number</string>
|
||||
<string name="error_mustbe6digitnumber">Must be 6 digit number</string>
|
||||
<string name="error_mustbe12hexadidits">Must be 12 characters of ABCDEF0123456789</string>
|
||||
<string name="error_mustbe8hexadidits">Must be 8 characters of ABCDEF0123456789</string>
|
||||
<string name="error_not_a_minimum_length">Not a minimum length</string>
|
||||
<string name="error_pin_not_valid">Pin should be 3 to 6 digits, not same or in series</string>
|
||||
|
||||
<string name="fourdigitnumber" translatable="false">^\\d{4}</string>
|
||||
<string name="twelvehexanumber" translatable="false">^[A-F0-9]{12}$</string>
|
||||
<string name="eighthexanumber" translatable="false">^[A-F0-9]{8}$</string>
|
||||
|
||||
</resources>
|
|
@ -14,7 +14,7 @@ import org.powermock.modules.junit4.PowerMockRunner
|
|||
class DanaRS_Packet_Notify_AlarmTest : DanaRSTestBase() {
|
||||
|
||||
@Test fun runTest() {
|
||||
val packet = DanaRS_Packet_Notify_Alarm(aapsLogger, resourceHelper)
|
||||
val packet = DanaRS_Packet_Notify_Alarm(aapsLogger, resourceHelper, rxBus)
|
||||
// test params
|
||||
Assert.assertEquals(null, packet.requestParams)
|
||||
// test message decoding
|
||||
|
|
Loading…
Reference in a new issue