diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.java b/app/src/main/java/info/nightscout/androidaps/MainActivity.java index feedfc0029..0d65cbb834 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.java @@ -87,6 +87,7 @@ public class MainActivity extends NoSplashAppCompatActivity { @Inject BuildHelper buildHelper; @Inject ActivePluginProvider activePlugin; @Inject FabricPrivacy fabricPrivacy; + @Inject ProtectionCheck protectionCheck; @Override @@ -192,7 +193,7 @@ public class MainActivity extends NoSplashAppCompatActivity { @Override protected void onResume() { super.onResume(); - ProtectionCheck.INSTANCE.queryProtection(this, ProtectionCheck.Protection.APPLICATION, null, this::finish, this::finish); + protectionCheck.queryProtection(this, ProtectionCheck.Protection.APPLICATION, null, this::finish, this::finish); } private void setWakeLock() { @@ -308,7 +309,7 @@ public class MainActivity extends NoSplashAppCompatActivity { int id = item.getItemId(); switch (id) { case R.id.nav_preferences: - ProtectionCheck.INSTANCE.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, () -> { + protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, () -> { Intent i = new Intent(this, PreferencesActivity.class); i.putExtra("id", -1); startActivity(i); @@ -348,7 +349,7 @@ public class MainActivity extends NoSplashAppCompatActivity { case R.id.nav_plugin_preferences: ViewPager viewPager = findViewById(R.id.pager); final PluginBase plugin = ((TabPageAdapter) viewPager.getAdapter()).getPluginAt(viewPager.getCurrentItem()); - ProtectionCheck.INSTANCE.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, () -> { + protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, () -> { Intent i = new Intent(this, PreferencesActivity.class); i.putExtra("id", plugin.getPreferencesId()); startActivity(i); diff --git a/app/src/main/java/info/nightscout/androidaps/activities/SingleFragmentActivity.kt b/app/src/main/java/info/nightscout/androidaps/activities/SingleFragmentActivity.kt index 2c3af71b66..9e62f16c97 100644 --- a/app/src/main/java/info/nightscout/androidaps/activities/SingleFragmentActivity.kt +++ b/app/src/main/java/info/nightscout/androidaps/activities/SingleFragmentActivity.kt @@ -15,6 +15,7 @@ import javax.inject.Inject class SingleFragmentActivity : DaggerAppCompatActivity() { @Inject lateinit var pluginStore: PluginStore + @Inject lateinit var protectionCheck: ProtectionCheck private var plugin: PluginBase? = null @@ -36,7 +37,7 @@ class SingleFragmentActivity : DaggerAppCompatActivity() { finish() return true } else if (item.itemId == R.id.nav_plugin_preferences) { - ProtectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, Runnable { + protectionCheck.queryProtection(this, ProtectionCheck.Protection.PREFERENCES, Runnable { val i = Intent(this, PreferencesActivity::class.java) i.putExtra("id", plugin?.preferencesId) startActivity(i) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt index 1766e733cd..f9cba58951 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/configBuilder/ConfigBuilderFragment.kt @@ -34,6 +34,7 @@ class ConfigBuilderFragment : DaggerFragment() { @Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin @Inject lateinit var fabricPrivacy: FabricPrivacy @Inject lateinit var activePlugin: ActivePluginProvider + @Inject lateinit var protectionCheck: ProtectionCheck private var disposable: CompositeDisposable = CompositeDisposable() private val pluginViewHolders = ArrayList() @@ -46,14 +47,14 @@ class ConfigBuilderFragment : DaggerFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - if (ProtectionCheck.isLocked(ProtectionCheck.Protection.PREFERENCES)) + if (protectionCheck.isLocked(ProtectionCheck.Protection.PREFERENCES)) configbuilder_main_layout.visibility = View.GONE else unlock.visibility = View.GONE unlock.setOnClickListener { activity?.let { activity -> - ProtectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { + protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { activity.runOnUiThread { configbuilder_main_layout.visibility = View.VISIBLE unlock.visibility = View.GONE @@ -148,7 +149,7 @@ class ConfigBuilderFragment : DaggerFragment() { pluginPreferences.setOnClickListener { fragment.activity?.let { activity -> - ProtectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { + protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { val i = Intent(fragment.context, PreferencesActivity::class.java) i.putExtra("id", plugin.preferencesId) fragment.startActivity(i) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt index 86b4e72164..3080c27b7f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/actions/ActionsFragment.kt @@ -52,6 +52,7 @@ class ActionsFragment : DaggerFragment() { @Inject lateinit var activePlugin: ActivePluginProvider @Inject lateinit var commandQueue: CommandQueueProvider @Inject lateinit var buildHelper: BuildHelper + @Inject lateinit var protectionCheck: ProtectionCheck private var disposable: CompositeDisposable = CompositeDisposable() @@ -74,7 +75,7 @@ class ActionsFragment : DaggerFragment() { } actions_extendedbolus.setOnClickListener { activity?.let { activity -> - ProtectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { + protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { OKDialog.showConfirmation(activity, resourceHelper.gs(R.string.extended_bolus), resourceHelper.gs(R.string.ebstopsloop), Runnable { fragmentManager?.let { ExtendedBolusDialog().show(it, "Actions") } @@ -121,7 +122,7 @@ class ActionsFragment : DaggerFragment() { } actions_fill.setOnClickListener { activity?.let { activity -> - ProtectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { fragmentManager?.let { FillDialog().show(it, "FillDialog") } }) + protectionCheck.queryProtection(activity, ProtectionCheck.Protection.BOLUS, Runnable { fragmentManager?.let { FillDialog().show(it, "FillDialog") } }) } } actions_historybrowser.setOnClickListener { startActivity(Intent(context, HistoryBrowseActivity::class.java)) } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java index 0519a35586..a192aa8526 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/overview/OverviewFragment.java @@ -117,12 +117,12 @@ import info.nightscout.androidaps.utils.SingleClickButton; import info.nightscout.androidaps.utils.T; import info.nightscout.androidaps.utils.ToastUtils; import info.nightscout.androidaps.utils.buildHelper.BuildHelper; +import info.nightscout.androidaps.utils.protection.ProtectionCheck; import info.nightscout.androidaps.utils.resources.ResourceHelper; import info.nightscout.androidaps.utils.sharedPreferences.SP; import info.nightscout.androidaps.utils.wizard.BolusWizard; import info.nightscout.androidaps.utils.wizard.QuickWizard; import info.nightscout.androidaps.utils.wizard.QuickWizardEntry; -import info.nightscout.androidaps.utils.protection.ProtectionCheck; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.disposables.CompositeDisposable; import io.reactivex.schedulers.Schedulers; @@ -153,6 +153,7 @@ public class OverviewFragment extends DaggerFragment implements View.OnClickList @Inject QuickWizard quickWizard; @Inject BuildHelper buildHelper; @Inject CommandQueue commandQueue; + @Inject ProtectionCheck protectionCheck; private CompositeDisposable disposable = new CompositeDisposable(); @@ -857,10 +858,10 @@ public class OverviewFragment extends DaggerFragment implements View.OnClickList onClickAcceptTemp(); break; case R.id.overview_quickwizardbutton: - ProtectionCheck.INSTANCE.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, this::onClickQuickwizard); + protectionCheck.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, this::onClickQuickwizard); break; case R.id.overview_wizardbutton: - ProtectionCheck.INSTANCE.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, () -> new WizardDialog().show(manager, "WizardDialog")); + protectionCheck.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, () -> new WizardDialog().show(manager, "WizardDialog")); break; case R.id.overview_calibrationbutton: if (xdrip) { @@ -894,13 +895,13 @@ public class OverviewFragment extends DaggerFragment implements View.OnClickList } break; case R.id.overview_treatmentbutton: - ProtectionCheck.INSTANCE.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, () -> new TreatmentDialog().show(manager, "Overview")); + protectionCheck.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, () -> new TreatmentDialog().show(manager, "Overview")); break; case R.id.overview_insulinbutton: - ProtectionCheck.INSTANCE.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, () -> new InsulinDialog().show(manager, "Overview")); + protectionCheck.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, () -> new InsulinDialog().show(manager, "Overview")); break; case R.id.overview_carbsbutton: - ProtectionCheck.INSTANCE.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, () -> new CarbsDialog().show(manager, "Overview")); + protectionCheck.queryProtection(getActivity(), ProtectionCheck.Protection.BOLUS, () -> new CarbsDialog().show(manager, "Overview")); break; case R.id.overview_pumpstatus: if (activePlugin.getActivePump().isSuspended() || !activePlugin.getActivePump().isInitialized()) diff --git a/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt b/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt index 167c3526c1..940635d555 100644 --- a/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt +++ b/app/src/main/java/info/nightscout/androidaps/setupwizard/SWDefinition.kt @@ -57,7 +57,8 @@ class SWDefinition @Inject constructor( private val configBuilderPlugin: ConfigBuilderPlugin, private val loopPlugin: LoopPlugin, private val nsClientPlugin: NSClientPlugin, - private val nsProfilePlugin: NSProfilePlugin + private val nsProfilePlugin: NSProfilePlugin, + private val protectionCheck: ProtectionCheck ) { var activity: AppCompatActivity? = null @@ -219,7 +220,7 @@ class SWDefinition @Inject constructor( .action(Runnable { val plugin = activePlugin.activeInsulin as PluginBase activity?.let { activity -> - ProtectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { + protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { val i = Intent(activity, PreferencesActivity::class.java) i.putExtra("id", plugin.preferencesId) activity.startActivity(i) @@ -238,7 +239,7 @@ class SWDefinition @Inject constructor( .action(Runnable { val plugin = activePlugin.activeBgSource as PluginBase activity?.let { activity -> - ProtectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { + protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { val i = Intent(activity, PreferencesActivity::class.java) i.putExtra("id", plugin.preferencesId) activity.startActivity(i) @@ -288,7 +289,7 @@ class SWDefinition @Inject constructor( .action(Runnable { val plugin = activePlugin.activePump as PluginBase activity?.let { activity -> - ProtectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { + protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { val i = Intent(activity, PreferencesActivity::class.java) i.putExtra("id", plugin.preferencesId) activity.startActivity(i) @@ -317,7 +318,7 @@ class SWDefinition @Inject constructor( .action(Runnable { val plugin = activePlugin.activeAPS as PluginBase activity?.let { activity -> - ProtectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { + protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { val i = Intent(activity, PreferencesActivity::class.java) i.putExtra("id", plugin.preferencesId) activity.startActivity(i) @@ -367,7 +368,7 @@ class SWDefinition @Inject constructor( .action(Runnable { val plugin = activePlugin.activeSensitivity as PluginBase activity?.let { activity -> - ProtectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { + protectionCheck.queryProtection(activity, ProtectionCheck.Protection.PREFERENCES, Runnable { val i = Intent(activity, PreferencesActivity::class.java) i.putExtra("id", plugin.preferencesId) activity.startActivity(i) diff --git a/app/src/main/java/info/nightscout/androidaps/utils/protection/BiometricCheck.kt b/app/src/main/java/info/nightscout/androidaps/utils/protection/BiometricCheck.kt index 5aba1cf12f..47d38be3d1 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/protection/BiometricCheck.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/protection/BiometricCheck.kt @@ -3,7 +3,6 @@ package info.nightscout.androidaps.utils.protection import androidx.biometric.BiometricConstants import androidx.biometric.BiometricPrompt import androidx.fragment.app.FragmentActivity -import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R import info.nightscout.androidaps.utils.ToastUtils import java.util.concurrent.Executors @@ -22,19 +21,22 @@ object BiometricCheck { BiometricConstants.ERROR_LOCKOUT, BiometricConstants.ERROR_VENDOR, BiometricConstants.ERROR_LOCKOUT_PERMANENT, - BiometricConstants.ERROR_USER_CANCELED -> { + BiometricConstants.ERROR_USER_CANCELED -> { ToastUtils.showToastInUiThread(activity.baseContext, errString.toString()) fail?.run() } + BiometricConstants.ERROR_NEGATIVE_BUTTON -> cancel?.run() BiometricConstants.ERROR_NO_SPACE, BiometricConstants.ERROR_HW_UNAVAILABLE, BiometricConstants.ERROR_HW_NOT_PRESENT, BiometricConstants.ERROR_NO_DEVICE_CREDENTIAL, - BiometricConstants.ERROR_NO_BIOMETRICS -> + BiometricConstants.ERROR_NO_BIOMETRICS -> // call ok, because it's not possible to bypass it when biometrics fail - ok?.run() + // ok?.run() + // changed to fail as you can use PIN instead with setDeviceCredentialAllowed enabled + fail?.run() } } @@ -52,10 +54,11 @@ object BiometricCheck { }) val promptInfo = BiometricPrompt.PromptInfo.Builder() - .setTitle(MainApp.gs(title)) - .setDescription(MainApp.gs(R.string.biometric_title)) - .setNegativeButtonText(MainApp.gs(R.string.cancel)) - .build() + .setTitle(activity.getString(title)) + .setDescription(activity.getString(R.string.biometric_title)) +// .setNegativeButtonText(activity.getString(R.string.cancel)) // not possible with setDeviceCredentialAllowed + .setDeviceCredentialAllowed(true) + .build() biometricPrompt.authenticate(promptInfo) } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/protection/PasswordCheck.kt b/app/src/main/java/info/nightscout/androidaps/utils/protection/PasswordCheck.kt index beeeef3add..6a2e18c732 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/protection/PasswordCheck.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/protection/PasswordCheck.kt @@ -1,5 +1,6 @@ package info.nightscout.androidaps.utils.protection +import android.annotation.SuppressLint import android.app.AlertDialog import android.view.LayoutInflater import android.view.View @@ -7,14 +8,18 @@ import android.widget.EditText import android.widget.TextView import androidx.annotation.StringRes import androidx.fragment.app.FragmentActivity -import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.R -import info.nightscout.androidaps.utils.SP import info.nightscout.androidaps.utils.ToastUtils +import info.nightscout.androidaps.utils.sharedPreferences.SP +import javax.inject.Inject +import javax.inject.Singleton -object PasswordCheck { +@Singleton +class PasswordCheck @Inject constructor(val sp: SP) { + + @SuppressLint("InflateParams") fun queryPassword(activity: FragmentActivity, @StringRes labelId: Int, @StringRes preference: Int, ok: Runnable?, cancel: Runnable? = null, fail: Runnable? = null) { - val password = SP.getString(preference, "") + val password = sp.getString(preference, "") if (password == "") { ok?.run() return @@ -25,24 +30,24 @@ object PasswordCheck { alertDialogBuilder.setView(promptsView) val label = promptsView.findViewById(R.id.passwordprompt_text) as TextView - label.text = MainApp.gs(labelId) + label.text = activity.getString(labelId) val userInput = promptsView.findViewById(R.id.passwordprompt_pass) as EditText alertDialogBuilder - .setCancelable(false) - .setPositiveButton(MainApp.gs(R.string.ok)) { _, _ -> - val enteredPassword = userInput.text.toString() - if (password == enteredPassword) ok?.run() - else { - ToastUtils.showToastInUiThread(activity, MainApp.gs(R.string.wrongpassword)) - fail?.run() - } - } - .setNegativeButton(MainApp.gs(R.string.cancel) - ) { dialog, _ -> - cancel?.run() - dialog.cancel() + .setCancelable(false) + .setPositiveButton(activity.getString(R.string.ok)) { _, _ -> + val enteredPassword = userInput.text.toString() + if (password == enteredPassword) ok?.run() + else { + ToastUtils.showToastInUiThread(activity, activity.getString(R.string.wrongpassword)) + fail?.run() } + } + .setNegativeButton(activity.getString(R.string.cancel) + ) { dialog, _ -> + cancel?.run() + dialog.cancel() + } alertDialogBuilder.create().show() } diff --git a/app/src/main/java/info/nightscout/androidaps/utils/protection/ProtectionCheck.kt b/app/src/main/java/info/nightscout/androidaps/utils/protection/ProtectionCheck.kt index c7880aee08..c4960f4999 100644 --- a/app/src/main/java/info/nightscout/androidaps/utils/protection/ProtectionCheck.kt +++ b/app/src/main/java/info/nightscout/androidaps/utils/protection/ProtectionCheck.kt @@ -2,9 +2,16 @@ package info.nightscout.androidaps.utils.protection import androidx.fragment.app.FragmentActivity import info.nightscout.androidaps.R -import info.nightscout.androidaps.utils.SP +import info.nightscout.androidaps.utils.sharedPreferences.SP +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class ProtectionCheck @Inject constructor( + val sp: SP, + val passwordCheck: PasswordCheck +) { -object ProtectionCheck { enum class Protection { PREFERENCES, APPLICATION, @@ -18,39 +25,38 @@ object ProtectionCheck { } private val passwordsResourceIDs = listOf( - R.string.key_settings_password, - R.string.key_application_password, - R.string.key_bolus_password) + R.string.key_settings_password, + R.string.key_application_password, + R.string.key_bolus_password) private val protectionTypeResourceIDs = listOf( - R.string.key_settings_protection, - R.string.key_application_protection, - R.string.key_bolus_protection) + R.string.key_settings_protection, + R.string.key_application_protection, + R.string.key_bolus_protection) private val titleResourceIDs = listOf( - R.string.settings_password, - R.string.application_password, - R.string.bolus_password) + R.string.settings_password, + R.string.application_password, + R.string.bolus_password) fun isLocked(protection: Protection): Boolean { - when (ProtectionType.values()[SP.getInt(protectionTypeResourceIDs[protection.ordinal], ProtectionType.NONE.ordinal)]) { - ProtectionType.NONE -> return false - ProtectionType.BIOMETRIC -> return true - ProtectionType.PASSWORD -> return SP.getString(passwordsResourceIDs[protection.ordinal], "") != "" + return when (ProtectionType.values()[sp.getInt(protectionTypeResourceIDs[protection.ordinal], ProtectionType.NONE.ordinal)]) { + ProtectionType.NONE -> false + ProtectionType.BIOMETRIC -> true + ProtectionType.PASSWORD -> sp.getString(passwordsResourceIDs[protection.ordinal], "") != "" } } @JvmOverloads fun queryProtection(activity: FragmentActivity, protection: Protection, ok: Runnable?, cancel: Runnable? = null, fail: Runnable? = null) { - when (ProtectionType.values()[SP.getInt(protectionTypeResourceIDs[protection.ordinal], ProtectionType.NONE.ordinal)]) { - ProtectionType.NONE -> + when (ProtectionType.values()[sp.getInt(protectionTypeResourceIDs[protection.ordinal], ProtectionType.NONE.ordinal)]) { + ProtectionType.NONE -> ok?.run() ProtectionType.BIOMETRIC -> BiometricCheck.biometricPrompt(activity, titleResourceIDs[protection.ordinal], ok, cancel, fail) - ProtectionType.PASSWORD -> - PasswordCheck.queryPassword(activity, titleResourceIDs[protection.ordinal], passwordsResourceIDs[protection.ordinal], ok, cancel, fail) + ProtectionType.PASSWORD -> + passwordCheck.queryPassword(activity, titleResourceIDs[protection.ordinal], passwordsResourceIDs[protection.ordinal], ok, cancel, fail) } } - } \ No newline at end of file