Merge branch 'dev' of https://github.com/MilosKozak/AndroidAPS into dev
This commit is contained in:
commit
92ed678b6e
|
@ -322,7 +322,9 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
|
|||
context?.let { context ->
|
||||
if (preference != null) {
|
||||
if (preference.key == resourceHelper.gs(R.string.key_master_password)) {
|
||||
passwordCheck.setPassword(context, R.string.master_password, R.string.key_master_password)
|
||||
passwordCheck.queryPassword(context, R.string.current_master_password, R.string.key_master_password, {
|
||||
passwordCheck.setPassword(context, R.string.master_password, R.string.key_master_password)
|
||||
})
|
||||
return true
|
||||
}
|
||||
if (preference.key == resourceHelper.gs(R.string.key_settings_password)) {
|
||||
|
|
|
@ -165,6 +165,7 @@ interface AppComponent : AndroidInjector<MainApp> {
|
|||
fun injectSWButton(swButton: SWButton)
|
||||
fun injectSWEditNumberWithUnits(swEditNumberWithUnits: SWEditNumberWithUnits)
|
||||
fun injectSWEditString(swEditString: SWEditString)
|
||||
fun injectSWEditEncryptedPassword(swSWEditEncryptedPassword: SWEditEncryptedPassword)
|
||||
fun injectSWEditUrl(swEditUrl: SWEditUrl)
|
||||
fun injectSWFragment(swFragment: SWFragment)
|
||||
fun injectSSWHtmlLink(swHtmlLink: SWHtmlLink)
|
||||
|
|
|
@ -246,6 +246,7 @@ open class AppModule {
|
|||
@ContributesAndroidInjector fun swButtonInjector(): SWButton
|
||||
@ContributesAndroidInjector fun swEditNumberWithUnitsInjector(): SWEditNumberWithUnits
|
||||
@ContributesAndroidInjector fun swEditStringInjector(): SWEditString
|
||||
@ContributesAndroidInjector fun swEditEncryptedPasswordInjector(): SWEditEncryptedPassword
|
||||
@ContributesAndroidInjector fun swEditUrlInjector(): SWEditUrl
|
||||
@ContributesAndroidInjector fun swFragmentInjector(): SWFragment
|
||||
@ContributesAndroidInjector fun swHtmlLinkInjector(): SWHtmlLink
|
||||
|
|
|
@ -15,5 +15,6 @@ abstract class ReceiversModule {
|
|||
@ContributesAndroidInjector abstract fun contributesKeepAliveReceiver(): KeepAliveReceiver
|
||||
@ContributesAndroidInjector abstract fun contributesNetworkChangeReceiver(): NetworkChangeReceiver
|
||||
@ContributesAndroidInjector abstract fun contributesRileyLinkBluetoothStateReceiver(): RileyLinkBluetoothStateReceiver
|
||||
@ContributesAndroidInjector abstract fun contributesSmsReceiver(): SmsReceiver
|
||||
@ContributesAndroidInjector abstract fun contributesTimeDateOrTZChangeReceiver(): TimeDateOrTZChangeReceiver
|
||||
}
|
|
@ -382,6 +382,7 @@ public class LoopPlugin extends PluginBase {
|
|||
if (lastRun == null) lastRun = new LastRun();
|
||||
lastRun.request = result;
|
||||
lastRun.constraintsProcessed = resultAfterConstraints;
|
||||
lastRun.lastAPSRun = DateUtil.now();
|
||||
lastRun.source = ((PluginBase) usedAPS).getName();
|
||||
lastRun.tbrSetByPump = null;
|
||||
lastRun.smbSetByPump = null;
|
||||
|
|
|
@ -165,7 +165,7 @@ public class NSUpload {
|
|||
Profile profile = profileFunction.getProfile();
|
||||
String profileName = profileFunction.getProfileName();
|
||||
|
||||
if (profile == null || profileName == null) {
|
||||
if (profile == null) {
|
||||
log.error("Profile is null. Skipping upload");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -755,6 +755,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
|
|||
|
||||
// ****** GRAPH *******
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
overview_bggraph?: return@launch
|
||||
val graphData = GraphData(injector, overview_bggraph, iobCobCalculatorPlugin)
|
||||
val secondaryGraphsData: ArrayList<GraphData> = ArrayList()
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ class NetworkChangeReceiver : DaggerBroadcastReceiver() {
|
|||
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
val networks: Array<Network> = cm.allNetworks
|
||||
networks.forEach {
|
||||
val capabilities = cm.getNetworkCapabilities(it)
|
||||
val capabilities = cm.getNetworkCapabilities(it) ?: return@forEach
|
||||
event.wifiConnected = event.wifiConnected || (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
|
||||
|| capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET))
|
||||
event.mobileConnected = event.mobileConnected || capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
|
||||
|
|
|
@ -33,6 +33,7 @@ import info.nightscout.androidaps.plugins.profile.ns.NSProfilePlugin
|
|||
import info.nightscout.androidaps.setupwizard.elements.*
|
||||
import info.nightscout.androidaps.setupwizard.events.EventSWUpdate
|
||||
import info.nightscout.androidaps.utils.AndroidPermission
|
||||
import info.nightscout.androidaps.utils.CryptoUtil
|
||||
import info.nightscout.androidaps.utils.LocaleHelper.update
|
||||
import info.nightscout.androidaps.utils.extensions.isRunningTest
|
||||
import info.nightscout.androidaps.utils.protection.ProtectionCheck
|
||||
|
@ -60,7 +61,8 @@ class SWDefinition @Inject constructor(
|
|||
private val nsProfilePlugin: NSProfilePlugin,
|
||||
private val protectionCheck: ProtectionCheck,
|
||||
private val importExportPrefs: ImportExportPrefs,
|
||||
private val androidPermission: AndroidPermission
|
||||
private val androidPermission: AndroidPermission,
|
||||
private val cryptoUtil: CryptoUtil
|
||||
) {
|
||||
|
||||
lateinit var activity: AppCompatActivity
|
||||
|
@ -203,9 +205,18 @@ class SWDefinition @Inject constructor(
|
|||
.add(SWInfotext(injector)
|
||||
.label(R.string.patient_name_summary))
|
||||
.add(SWEditString(injector)
|
||||
.validator(SWTextValidator { text: String -> text.length > 0 })
|
||||
.preferenceId(R.string.key_patient_name)
|
||||
.updateDelay(5))
|
||||
.validator(SWTextValidator(String::isNotEmpty))
|
||||
.preferenceId(R.string.key_patient_name))
|
||||
private val screenMasterPassword = SWScreen(injector, R.string.master_password)
|
||||
.skippable(false)
|
||||
.add(SWInfotext(injector)
|
||||
.label(R.string.master_password))
|
||||
.add(SWEditEncryptedPassword(injector, cryptoUtil)
|
||||
.preferenceId(R.string.key_master_password))
|
||||
.add(SWBreak(injector))
|
||||
.add(SWInfotext(injector)
|
||||
.label(R.string.master_password_summary))
|
||||
.validator(SWValidator { !cryptoUtil.checkPassword("", sp.getString(R.string.key_master_password, "")) })
|
||||
private val screenAge = SWScreen(injector, R.string.patientage)
|
||||
.skippable(false)
|
||||
.add(SWBreak(injector))
|
||||
|
@ -393,6 +404,7 @@ class SWDefinition @Inject constructor(
|
|||
.add(if (isRunningTest()) null else screenPermissionBattery) // cannot mock ask battery optimization
|
||||
.add(screenPermissionBt)
|
||||
.add(screenPermissionStore)
|
||||
.add(screenMasterPassword)
|
||||
.add(screenImport)
|
||||
.add(screenUnits)
|
||||
.add(displaySettings)
|
||||
|
@ -420,6 +432,7 @@ class SWDefinition @Inject constructor(
|
|||
.add(if (isRunningTest()) null else screenPermissionBattery) // cannot mock ask battery optimization
|
||||
.add(screenPermissionBt)
|
||||
.add(screenPermissionStore)
|
||||
.add(screenMasterPassword)
|
||||
.add(screenImport)
|
||||
.add(screenUnits)
|
||||
.add(displaySettings)
|
||||
|
@ -442,6 +455,7 @@ class SWDefinition @Inject constructor(
|
|||
.add(screenEula)
|
||||
.add(if (isRunningTest()) null else screenPermissionBattery) // cannot mock ask battery optimization
|
||||
.add(screenPermissionStore)
|
||||
.add(screenMasterPassword)
|
||||
.add(screenImport)
|
||||
.add(screenUnits)
|
||||
.add(displaySettings)
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package info.nightscout.androidaps.setupwizard.elements
|
||||
|
||||
import android.graphics.Typeface
|
||||
import android.text.Editable
|
||||
import android.text.InputType
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.setupwizard.SWTextValidator
|
||||
import info.nightscout.androidaps.utils.CryptoUtil
|
||||
|
||||
class SWEditEncryptedPassword(injector: HasAndroidInjector, private val cryptoUtil: CryptoUtil) : SWItem(injector, Type.STRING) {
|
||||
|
||||
private var validator: SWTextValidator = SWTextValidator(String::isNotEmpty)
|
||||
private var updateDelay = 0L
|
||||
|
||||
override fun generateDialog(layout: LinearLayout) {
|
||||
val context = layout.context
|
||||
val l = TextView(context)
|
||||
l.id = View.generateViewId()
|
||||
label?.let { l.setText(it) }
|
||||
l.setTypeface(l.typeface, Typeface.BOLD)
|
||||
layout.addView(l)
|
||||
val c = TextView(context)
|
||||
c.id = View.generateViewId()
|
||||
comment?.let { c.setText(it) }
|
||||
c.setTypeface(c.typeface, Typeface.ITALIC)
|
||||
layout.addView(c)
|
||||
val editText = EditText(context)
|
||||
editText.id = View.generateViewId()
|
||||
editText.inputType = InputType.TYPE_CLASS_TEXT
|
||||
editText.maxLines = 1
|
||||
editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||
layout.addView(editText)
|
||||
|
||||
val c2 = TextView(context)
|
||||
c2.id = View.generateViewId()
|
||||
c2.setText(R.string.confirm)
|
||||
layout.addView(c2)
|
||||
|
||||
val editText2 = EditText(context)
|
||||
editText2.id = View.generateViewId()
|
||||
editText2.inputType = InputType.TYPE_CLASS_TEXT
|
||||
editText2.maxLines = 1
|
||||
editText2.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||
layout.addView(editText2)
|
||||
|
||||
super.generateDialog(layout)
|
||||
val watcher = object : TextWatcher {
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
|
||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
||||
sp.remove(preferenceId)
|
||||
scheduleChange(updateDelay)
|
||||
if (validator.isValid(editText.text.toString()) && validator.isValid(editText2.text.toString()) && editText.text.toString() == editText2.text.toString())
|
||||
save(s.toString(), updateDelay)
|
||||
}
|
||||
|
||||
override fun afterTextChanged(s: Editable) {}
|
||||
}
|
||||
editText.addTextChangedListener(watcher)
|
||||
editText2.addTextChangedListener(watcher)
|
||||
}
|
||||
|
||||
fun preferenceId(preferenceId: Int): SWEditEncryptedPassword {
|
||||
this.preferenceId = preferenceId
|
||||
return this
|
||||
}
|
||||
|
||||
fun validator(validator: SWTextValidator): SWEditEncryptedPassword {
|
||||
this.validator = validator
|
||||
return this
|
||||
}
|
||||
|
||||
override fun save(value: String, updateDelay: Long) {
|
||||
sp.putString(preferenceId, cryptoUtil.hashPassword(value))
|
||||
scheduleChange(updateDelay)
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import info.nightscout.androidaps.logging.LTag
|
|||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||
import info.nightscout.androidaps.setupwizard.events.EventSWUpdate
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import java.util.concurrent.Executors
|
||||
import java.util.concurrent.ScheduledFuture
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -20,7 +21,7 @@ open class SWItem(val injector: HasAndroidInjector, var type: Type) {
|
|||
@Inject lateinit var aapsLogger: AAPSLogger
|
||||
@Inject lateinit var rxBus: RxBusWrapper
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var sp: info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
@Inject lateinit var sp: SP
|
||||
|
||||
private val eventWorker = Executors.newSingleThreadScheduledExecutor()
|
||||
private var scheduledEventPost: ScheduledFuture<*>? = null
|
||||
|
@ -55,7 +56,7 @@ open class SWItem(val injector: HasAndroidInjector, var type: Type) {
|
|||
return this
|
||||
}
|
||||
|
||||
fun save(value: String, updateDelay: Long) {
|
||||
open fun save(value: String, updateDelay: Long) {
|
||||
sp.putString(preferenceId, value)
|
||||
scheduleChange(updateDelay)
|
||||
}
|
||||
|
@ -69,7 +70,7 @@ open class SWItem(val injector: HasAndroidInjector, var type: Type) {
|
|||
open fun generateDialog(layout: LinearLayout) {}
|
||||
open fun processVisibility() {}
|
||||
|
||||
private fun scheduleChange(updateDelay: Long) {
|
||||
fun scheduleChange(updateDelay: Long) {
|
||||
class PostRunnable : Runnable {
|
||||
override fun run() {
|
||||
aapsLogger.debug(LTag.CORE, "Firing EventPreferenceChange")
|
||||
|
|
|
@ -5,10 +5,11 @@ import androidx.biometric.BiometricPrompt
|
|||
import androidx.fragment.app.FragmentActivity
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.extensions.runOnUiThread
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
object BiometricCheck {
|
||||
fun biometricPrompt(activity: FragmentActivity, title: Int, ok: Runnable?, cancel: Runnable? = null, fail: Runnable? = null) {
|
||||
fun biometricPrompt(activity: FragmentActivity, title: Int, ok: Runnable?, cancel: Runnable? = null, fail: Runnable? = null, passwordCheck: PasswordCheck) {
|
||||
val executor = Executors.newSingleThreadExecutor()
|
||||
|
||||
val biometricPrompt = BiometricPrompt(activity, executor, object : BiometricPrompt.AuthenticationCallback() {
|
||||
|
@ -23,24 +24,31 @@ object BiometricCheck {
|
|||
BiometricConstants.ERROR_LOCKOUT_PERMANENT,
|
||||
BiometricConstants.ERROR_USER_CANCELED -> {
|
||||
ToastUtils.showToastInUiThread(activity.baseContext, errString.toString())
|
||||
fail?.run()
|
||||
// fallback to master password
|
||||
runOnUiThread(Runnable {
|
||||
passwordCheck.queryPassword(activity, R.string.master_password, R.string.key_master_password, { ok?.run() }, { cancel?.run() }, { fail?.run() })
|
||||
})
|
||||
}
|
||||
|
||||
BiometricConstants.ERROR_NEGATIVE_BUTTON ->
|
||||
cancel?.run()
|
||||
|
||||
BiometricConstants.ERROR_NO_DEVICE_CREDENTIAL ->
|
||||
// call ok, because it's not possible to bypass it when biometrics is setup, hw not present and no pin set
|
||||
ok?.run()
|
||||
BiometricConstants.ERROR_NO_DEVICE_CREDENTIAL -> {
|
||||
ToastUtils.showToastInUiThread(activity.baseContext, errString.toString())
|
||||
// no pin set
|
||||
// fallback to master password
|
||||
runOnUiThread(Runnable {
|
||||
passwordCheck.queryPassword(activity, R.string.master_password, R.string.key_master_password, { ok?.run() }, { cancel?.run() }, { fail?.run() })
|
||||
})
|
||||
}
|
||||
|
||||
BiometricConstants.ERROR_NO_SPACE,
|
||||
BiometricConstants.ERROR_HW_UNAVAILABLE,
|
||||
BiometricConstants.ERROR_HW_NOT_PRESENT,
|
||||
BiometricConstants.ERROR_NO_BIOMETRICS ->
|
||||
// call ok, because it's not possible to bypass it when biometrics fail
|
||||
// ok?.run()
|
||||
// changed to fail as you can use PIN instead with setDeviceCredentialAllowed enabled
|
||||
fail?.run()
|
||||
runOnUiThread(Runnable {
|
||||
passwordCheck.queryPassword(activity, R.string.master_password, R.string.key_master_password, { ok?.run() }, { cancel?.run() }, { fail?.run() })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,8 +68,8 @@ object BiometricCheck {
|
|||
val promptInfo = BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(activity.getString(title))
|
||||
.setDescription(activity.getString(R.string.biometric_title))
|
||||
// .setNegativeButtonText(activity.getString(R.string.cancel)) // not possible with setDeviceCredentialAllowed
|
||||
.setDeviceCredentialAllowed(true)
|
||||
.setNegativeButtonText(activity.getString(R.string.cancel)) // not possible with setDeviceCredentialAllowed
|
||||
// .setDeviceCredentialAllowed(true) // setDeviceCredentialAllowed creates new activity when PIN is requested, activity.fragmentManager crash afterwards
|
||||
.build()
|
||||
|
||||
biometricPrompt.authenticate(promptInfo)
|
||||
|
|
|
@ -16,19 +16,19 @@ import javax.inject.Inject
|
|||
import javax.inject.Singleton
|
||||
|
||||
// since androidx.autofill.HintConstants are not available
|
||||
val AUTOFILL_HINT_NEW_PASSWORD = "newPassword"
|
||||
const val AUTOFILL_HINT_NEW_PASSWORD = "newPassword"
|
||||
|
||||
@Singleton
|
||||
class PasswordCheck @Inject constructor(
|
||||
val sp: SP,
|
||||
val cryptoUtil: CryptoUtil
|
||||
private val cryptoUtil: CryptoUtil
|
||||
) {
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
fun queryPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, ok: ( (String) -> Unit)?, cancel: (()->Unit)? = null, fail: (()->Unit)? = null) {
|
||||
fun queryPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, ok: ((String) -> Unit)?, cancel: (() -> Unit)? = null, fail: (() -> Unit)? = null) {
|
||||
val password = sp.getString(preference, "")
|
||||
if (password == "") {
|
||||
ok?.invoke("")
|
||||
ok?.invoke("")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,11 @@ class PasswordCheck @Inject constructor(
|
|||
val alertDialogBuilder = AlertDialogHelper.Builder(context)
|
||||
alertDialogBuilder.setView(promptsView)
|
||||
|
||||
val userInput = promptsView.findViewById<View>(R.id.passwordprompt_pass) as EditText
|
||||
val userInput = promptsView.findViewById<View>(R.id.password_prompt_pass) as EditText
|
||||
val userInput2 = promptsView.findViewById<View>(R.id.password_prompt_pass_confirm) as EditText
|
||||
|
||||
userInput2.visibility = View.GONE
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val autoFillHintPasswordKind = context.getString(preference)
|
||||
userInput.setAutofillHints(View.AUTOFILL_HINT_PASSWORD, "aaps_${autoFillHintPasswordKind}")
|
||||
|
@ -64,12 +68,13 @@ class PasswordCheck @Inject constructor(
|
|||
}
|
||||
|
||||
@SuppressLint("InflateParams")
|
||||
fun setPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, ok: ( (String) -> Unit)? = null, cancel: (()->Unit)? = null, clear: (()->Unit)? = null) {
|
||||
fun setPassword(context: Context, @StringRes labelId: Int, @StringRes preference: Int, ok: ((String) -> Unit)? = null, cancel: (() -> Unit)? = null, clear: (() -> Unit)? = null) {
|
||||
val promptsView = LayoutInflater.from(context).inflate(R.layout.passwordprompt, null)
|
||||
val alertDialogBuilder = AlertDialogHelper.Builder(context)
|
||||
alertDialogBuilder.setView(promptsView)
|
||||
|
||||
val userInput = promptsView.findViewById<View>(R.id.passwordprompt_pass) as EditText
|
||||
val userInput = promptsView.findViewById<View>(R.id.password_prompt_pass) as EditText
|
||||
val userInput2 = promptsView.findViewById<View>(R.id.password_prompt_pass_confirm) as EditText
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val autoFillHintPasswordKind = context.getString(preference)
|
||||
|
@ -82,7 +87,10 @@ class PasswordCheck @Inject constructor(
|
|||
.setCustomTitle(AlertDialogHelper.buildCustomTitle(context, context.getString(labelId), R.drawable.ic_header_key))
|
||||
.setPositiveButton(context.getString(R.string.ok)) { _, _ ->
|
||||
val enteredPassword = userInput.text.toString()
|
||||
if (enteredPassword.isNotEmpty()) {
|
||||
val enteredPassword2 = userInput2.text.toString()
|
||||
if (enteredPassword != enteredPassword2) {
|
||||
ToastUtils.errorToast(context, context.getString(R.string.passwords_dont_match))
|
||||
} else if (enteredPassword.isNotEmpty()) {
|
||||
sp.putString(preference, cryptoUtil.hashPassword(enteredPassword))
|
||||
ToastUtils.okToast(context, context.getString(R.string.password_set))
|
||||
ok?.invoke(enteredPassword)
|
||||
|
|
|
@ -56,7 +56,7 @@ class ProtectionCheck @Inject constructor(
|
|||
ProtectionType.NONE ->
|
||||
ok?.run()
|
||||
ProtectionType.BIOMETRIC ->
|
||||
BiometricCheck.biometricPrompt(activity, titleResourceIDs[protection.ordinal], ok, cancel, fail)
|
||||
BiometricCheck.biometricPrompt(activity, titleResourceIDs[protection.ordinal], ok, cancel, fail, passwordCheck)
|
||||
ProtectionType.MASTER_PASSWORD ->
|
||||
passwordCheck.queryPassword(activity, R.string.master_password, R.string.key_master_password, { ok?.run() }, { cancel?.run() }, { fail?.run() })
|
||||
ProtectionType.CUSTOM_PASSWORD ->
|
||||
|
|
|
@ -3,18 +3,23 @@
|
|||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp" >
|
||||
android:padding="10dp">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/passwordprompt_pass"
|
||||
android:id="@+id/password_prompt_pass"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/password_hint"
|
||||
android:inputType="textPassword"
|
||||
>
|
||||
android:inputType="textPassword">
|
||||
|
||||
<requestFocus />
|
||||
|
||||
</EditText>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password_prompt_pass_confirm"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/password_hint"
|
||||
android:inputType="textPassword"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -34,7 +34,7 @@
|
|||
<string name="objectives_smb_objective">Enabling additional features for daytime use, such as SMB</string>
|
||||
<string name="objectives_auto_objective">Enabling automation</string>
|
||||
<string name="objectives_smb_gate">You must read the wiki and rise maxIOB to get SMBs working fine! A good start is maxIOB=average mealbolus + 3 x max daily basal</string>
|
||||
<string name="objectives_auto_gate">Read the wiki how automation works. Setup your first simple rules. Instead of action let AAPS display only notification. When you are sure automation is triggered at the right time replace notification by real action.</string>
|
||||
<string name="objectives_auto_gate">Read the docs how automation works. Setup your first simple rules. Instead of action let AAPS display only notification. When you are sure automation is triggered at the right time replace notification by real action. (https://androidaps.readthedocs.io/en/latest/EN/Usage/Automation.html)</string>
|
||||
<string name="objectives_bgavailableinns">BG available in NS</string>
|
||||
<string name="objectives_pumpstatusavailableinns">Pump status available in NS</string>
|
||||
<string name="objectives_manualenacts">Manual enacts</string>
|
||||
|
|
|
@ -1805,4 +1805,7 @@
|
|||
<string name="key_graphconfig" translatable="false">graphconfig</string>
|
||||
<string name="authorizationfailed">Authorization failed</string>
|
||||
<string name="overview_show_absinsulin">Absolute insulin</string>
|
||||
<string name="master_password_summary">Master password is used for backup encryption and to override security in application. Remember it or store on a safe place.</string>
|
||||
<string name="passwords_dont_match">Passwords don\'t match</string>
|
||||
<string name="current_master_password">Current master password</string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue