Pin: add settings to enable/disable

This commit is contained in:
ganfra 2020-07-29 16:11:57 +02:00
parent 5426e43cbb
commit 37521d2d4f
14 changed files with 207 additions and 39 deletions

View file

@ -84,7 +84,7 @@ class DebugMenuActivity : VectorBaseActivity() {
@OnClick(R.id.debug_open_pin_code) @OnClick(R.id.debug_open_pin_code)
fun openPinCode() { fun openPinCode() {
startActivity(PinActivity.newIntent(this)) //startActivity(PinActivity.newIntent(this))
} }
@OnClick(R.id.debug_test_notification) @OnClick(R.id.debug_test_notification)

View file

@ -35,6 +35,7 @@ import com.gabrielittner.threetenbp.LazyThreeTen
import im.vector.matrix.android.api.Matrix import im.vector.matrix.android.api.Matrix
import im.vector.matrix.android.api.MatrixConfiguration import im.vector.matrix.android.api.MatrixConfiguration
import im.vector.matrix.android.api.auth.AuthenticationService import im.vector.matrix.android.api.auth.AuthenticationService
import im.vector.matrix.android.api.extensions.orFalse
import im.vector.matrix.android.api.legacy.LegacySessionImporter import im.vector.matrix.android.api.legacy.LegacySessionImporter
import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.core.di.ActiveSessionHolder
import im.vector.riotx.core.di.DaggerVectorComponent import im.vector.riotx.core.di.DaggerVectorComponent
@ -47,6 +48,7 @@ import im.vector.riotx.features.disclaimer.doNotShowDisclaimerDialog
import im.vector.riotx.features.lifecycle.VectorActivityLifecycleCallbacks import im.vector.riotx.features.lifecycle.VectorActivityLifecycleCallbacks
import im.vector.riotx.features.notifications.NotificationDrawerManager import im.vector.riotx.features.notifications.NotificationDrawerManager
import im.vector.riotx.features.notifications.NotificationUtils import im.vector.riotx.features.notifications.NotificationUtils
import im.vector.riotx.features.pin.PinCodeStore
import im.vector.riotx.features.popup.PopupAlertManager import im.vector.riotx.features.popup.PopupAlertManager
import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler import im.vector.riotx.features.rageshake.VectorUncaughtExceptionHandler
import im.vector.riotx.features.settings.VectorPreferences import im.vector.riotx.features.settings.VectorPreferences
@ -82,6 +84,7 @@ class VectorApplication :
@Inject lateinit var appStateHandler: AppStateHandler @Inject lateinit var appStateHandler: AppStateHandler
@Inject lateinit var rxConfig: RxConfig @Inject lateinit var rxConfig: RxConfig
@Inject lateinit var popupAlertManager: PopupAlertManager @Inject lateinit var popupAlertManager: PopupAlertManager
@Inject lateinit var pinCodeStore: PinCodeStore
lateinit var vectorComponent: VectorComponent lateinit var vectorComponent: VectorComponent

View file

@ -294,7 +294,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScreenInjector {
if (this !is BugReportActivity && vectorPreferences.useRageshake()) { if (this !is BugReportActivity && vectorPreferences.useRageshake()) {
rageShake.start() rageShake.start()
} }
DebugReceiver DebugReceiver
.getIntentFilter(this) .getIntentFilter(this)
.takeIf { BuildConfig.DEBUG } .takeIf { BuildConfig.DEBUG }

View file

@ -53,6 +53,8 @@ import im.vector.riotx.features.media.AttachmentData
import im.vector.riotx.features.media.BigImageViewerActivity import im.vector.riotx.features.media.BigImageViewerActivity
import im.vector.riotx.features.media.VectorAttachmentViewerActivity import im.vector.riotx.features.media.VectorAttachmentViewerActivity
import im.vector.riotx.features.pin.PinActivity import im.vector.riotx.features.pin.PinActivity
import im.vector.riotx.features.pin.PinArgs
import im.vector.riotx.features.pin.PinMode
import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity import im.vector.riotx.features.roomdirectory.RoomDirectoryActivity
import im.vector.riotx.features.roomdirectory.createroom.CreateRoomActivity import im.vector.riotx.features.roomdirectory.createroom.CreateRoomActivity
import im.vector.riotx.features.roomdirectory.roompreview.RoomPreviewActivity import im.vector.riotx.features.roomdirectory.roompreview.RoomPreviewActivity
@ -251,7 +253,6 @@ class DefaultNavigator @Inject constructor(
} }
} }
override fun openTerms(fragment: Fragment, serviceType: TermsService.ServiceType, baseUrl: String, token: String?, requestCode: Int) { override fun openTerms(fragment: Fragment, serviceType: TermsService.ServiceType, baseUrl: String, token: String?, requestCode: Int) {
val intent = ReviewTermsActivity.intent(fragment.requireContext(), serviceType, baseUrl, token) val intent = ReviewTermsActivity.intent(fragment.requireContext(), serviceType, baseUrl, token)
fragment.startActivityForResult(intent, requestCode) fragment.startActivityForResult(intent, requestCode)
@ -274,9 +275,9 @@ class DefaultNavigator @Inject constructor(
context.startActivity(WidgetActivity.newIntent(context, widgetArgs)) context.startActivity(WidgetActivity.newIntent(context, widgetArgs))
} }
override fun openPinCode(activity: Activity, requestCode: Int) { override fun openPinCode(fragment: Fragment, pinMode: PinMode, requestCode: Int) {
val intent = PinActivity.newIntent(activity) val intent = PinActivity.newIntent(fragment.requireContext(), PinArgs(pinMode))
activity.startActivity(intent) fragment.startActivityForResult(intent, requestCode)
} }
override fun openMediaViewer(activity: Activity, override fun openMediaViewer(activity: Activity,

View file

@ -28,6 +28,8 @@ import im.vector.matrix.android.api.session.widgets.model.Widget
import im.vector.matrix.android.api.util.MatrixItem import im.vector.matrix.android.api.util.MatrixItem
import im.vector.riotx.features.home.room.detail.widget.WidgetRequestCodes import im.vector.riotx.features.home.room.detail.widget.WidgetRequestCodes
import im.vector.riotx.features.media.AttachmentData import im.vector.riotx.features.media.AttachmentData
import im.vector.riotx.features.pin.PinActivity
import im.vector.riotx.features.pin.PinMode
import im.vector.riotx.features.settings.VectorSettingsActivity import im.vector.riotx.features.settings.VectorSettingsActivity
import im.vector.riotx.features.share.SharedData import im.vector.riotx.features.share.SharedData
import im.vector.riotx.features.terms.ReviewTermsActivity import im.vector.riotx.features.terms.ReviewTermsActivity
@ -78,7 +80,7 @@ interface Navigator {
fun openBigImageViewer(activity: Activity, sharedElement: View?, matrixItem: MatrixItem) fun openBigImageViewer(activity: Activity, sharedElement: View?, matrixItem: MatrixItem)
fun openPinCode(activity: Activity, requestCode: Int = ReviewTermsActivity.TERMS_REQUEST_CODE) fun openPinCode(fragment: Fragment, pinMode: PinMode, requestCode: Int = PinActivity.PIN_REQUEST_CODE)
fun openTerms(fragment: Fragment, fun openTerms(fragment: Fragment,
serviceType: TermsService.ServiceType, serviceType: TermsService.ServiceType,

View file

@ -19,6 +19,7 @@ package im.vector.riotx.features.pin
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import com.airbnb.mvrx.MvRx
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.extensions.addFragment import im.vector.riotx.core.extensions.addFragment
import im.vector.riotx.core.platform.ToolbarConfigurable import im.vector.riotx.core.platform.ToolbarConfigurable
@ -28,8 +29,13 @@ class PinActivity : VectorBaseActivity(), ToolbarConfigurable {
companion object { companion object {
fun newIntent(context: Context): Intent { const val PIN_REQUEST_CODE = 17890
return Intent(context, PinActivity::class.java) const val PIN_RESULT_CODE_FORGOT = 17891
fun newIntent(context: Context, args: PinArgs): Intent {
return Intent(context, PinActivity::class.java).apply {
putExtra(MvRx.KEY_ARG, args)
}
} }
} }
@ -37,7 +43,8 @@ class PinActivity : VectorBaseActivity(), ToolbarConfigurable {
override fun initUiAndData() { override fun initUiAndData() {
if (isFirstCreation()) { if (isFirstCreation()) {
addFragment(R.id.simpleFragmentContainer, PinFragment::class.java) val fragmentArgs: PinArgs = intent?.extras?.getParcelable(MvRx.KEY_ARG) ?: return
addFragment(R.id.simpleFragmentContainer, PinFragment::class.java, fragmentArgs)
} }
} }

View file

@ -18,35 +18,64 @@ package im.vector.riotx.features.pin
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit import androidx.core.content.edit
import com.beautycoder.pflockscreen.security.PFResult
import com.beautycoder.pflockscreen.security.PFSecurityManager
import com.beautycoder.pflockscreen.security.callbacks.PFPinCodeHelperCallback
import im.vector.matrix.android.api.extensions.orFalse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import javax.inject.Inject import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
interface PinCodeStore { interface PinCodeStore {
fun storeEncodedPin(encodePin: String) suspend fun storeEncodedPin(encodePin: String)
fun deleteEncodedPin() suspend fun deleteEncodedPin()
fun getEncodedPin(): String? fun getEncodedPin(): String?
suspend fun hasEncodedPin(): Boolean
} }
class SharedPrefPinCodeStore @Inject constructor(private val sharedPreferences: SharedPreferences) : PinCodeStore { class SharedPrefPinCodeStore @Inject constructor(private val sharedPreferences: SharedPreferences) : PinCodeStore {
override fun storeEncodedPin(encodePin: String) { override suspend fun storeEncodedPin(encodePin: String) = withContext(Dispatchers.IO) {
sharedPreferences.edit { sharedPreferences.edit {
putString(ENCODED_PIN_CODE_KEY, encodePin) putString(ENCODED_PIN_CODE_KEY, encodePin)
} }
} }
override fun deleteEncodedPin() { override suspend fun deleteEncodedPin() = withContext(Dispatchers.IO) {
sharedPreferences.edit { sharedPreferences.edit {
remove(ENCODED_PIN_CODE_KEY) remove(ENCODED_PIN_CODE_KEY)
} }
awaitPinCodeCallback<Boolean> {
PFSecurityManager.getInstance().pinCodeHelper.delete(it)
}
return@withContext
} }
override fun getEncodedPin(): String? { override fun getEncodedPin(): String? {
return sharedPreferences.getString(ENCODED_PIN_CODE_KEY, null) return sharedPreferences.getString(ENCODED_PIN_CODE_KEY, null)
} }
override suspend fun hasEncodedPin(): Boolean = withContext(Dispatchers.IO) {
val hasEncodedPin = getEncodedPin()?.isNotBlank().orFalse()
if (!hasEncodedPin) {
return@withContext false
}
val result = awaitPinCodeCallback<Boolean> {
PFSecurityManager.getInstance().pinCodeHelper.isPinCodeEncryptionKeyExist(it)
}
result.error == null && result.result
}
private suspend inline fun <T> awaitPinCodeCallback(crossinline callback: (PFPinCodeHelperCallback<T>) -> Unit) = suspendCoroutine<PFResult<T>> { cont ->
callback(PFPinCodeHelperCallback<T> { result -> cont.resume(result) })
}
companion object { companion object {
const val ENCODED_PIN_CODE_KEY = "ENCODED_PIN_CODE_KEY" const val ENCODED_PIN_CODE_KEY = "ENCODED_PIN_CODE_KEY"
} }

View file

@ -16,10 +16,14 @@
package im.vector.riotx.features.pin package im.vector.riotx.features.pin
import android.app.Activity
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.args
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import com.beautycoder.pflockscreen.PFFLockScreenConfiguration import com.beautycoder.pflockscreen.PFFLockScreenConfiguration
@ -27,60 +31,107 @@ import com.beautycoder.pflockscreen.fragments.PFLockScreenFragment
import im.vector.riotx.R import im.vector.riotx.R
import im.vector.riotx.core.extensions.replaceFragment import im.vector.riotx.core.extensions.replaceFragment
import im.vector.riotx.core.platform.VectorBaseFragment import im.vector.riotx.core.platform.VectorBaseFragment
import kotlinx.android.parcel.Parcelize
import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@Parcelize
data class PinArgs(
val pinMode: PinMode
) : Parcelable
class PinFragment @Inject constructor( class PinFragment @Inject constructor(
private val pinCodeStore: PinCodeStore, private val pinCodeStore: PinCodeStore,
private val viewModelFactory: PinViewModel.Factory private val viewModelFactory: PinViewModel.Factory
) : VectorBaseFragment(), PinViewModel.Factory by viewModelFactory { ) : VectorBaseFragment(), PinViewModel.Factory by viewModelFactory {
private val viewModel: PinViewModel by fragmentViewModel() private val viewModel: PinViewModel by fragmentViewModel()
private val fragmentArgs: PinArgs by args()
override fun getLayoutResId() = R.layout.fragment_pin override fun getLayoutResId() = R.layout.fragment_pin
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val encodedPinCode = pinCodeStore.getEncodedPin() when (fragmentArgs.pinMode) {
if (encodedPinCode.isNullOrBlank()) { PinMode.CREATE -> showCreateFragment()
showCreateFragment() PinMode.DELETE -> showDeleteFragment()
} else { PinMode.AUTH -> showAuthFragment()
showAuthFragment(encodedPinCode)
} }
} }
private fun showDeleteFragment() {
val encodedPin = pinCodeStore.getEncodedPin() ?: return
val authFragment = PFLockScreenFragment()
val builder = PFFLockScreenConfiguration.Builder(requireContext())
.setUseFingerprint(true)
.setTitle(getString(R.string.auth_pin_confirm_to_disable_title))
.setClearCodeOnError(true)
.setMode(PFFLockScreenConfiguration.MODE_AUTH)
authFragment.setConfiguration(builder.build())
authFragment.setEncodedPinCode(encodedPin)
authFragment.setLoginListener(object : PFLockScreenFragment.OnPFLockScreenLoginListener {
override fun onPinLoginFailed() {
}
override fun onFingerprintSuccessful() {
lifecycleScope.launch {
pinCodeStore.deleteEncodedPin()
vectorBaseActivity.setResult(Activity.RESULT_OK)
vectorBaseActivity.finish()
}
}
override fun onFingerprintLoginFailed() {
}
override fun onCodeInputSuccessful() {
lifecycleScope.launch {
pinCodeStore.deleteEncodedPin()
vectorBaseActivity.setResult(Activity.RESULT_OK)
vectorBaseActivity.finish()
}
}
})
replaceFragment(R.id.pinFragmentContainer, authFragment)
}
private fun showCreateFragment() { private fun showCreateFragment() {
val createFragment = PFLockScreenFragment() val createFragment = PFLockScreenFragment()
val builder = PFFLockScreenConfiguration.Builder(requireContext()) val builder = PFFLockScreenConfiguration.Builder(requireContext())
.setNewCodeValidation(true) .setNewCodeValidation(true)
.setTitle("Choose a PIN for security") .setTitle(getString(R.string.create_pin_title))
.setNewCodeValidationTitle("Confirm PIN") .setNewCodeValidationTitle(getString(R.string.create_pin_confirm_title))
.setMode(PFFLockScreenConfiguration.MODE_CREATE) .setMode(PFFLockScreenConfiguration.MODE_CREATE)
createFragment.setConfiguration(builder.build()) createFragment.setConfiguration(builder.build())
createFragment.setCodeCreateListener(object : PFLockScreenFragment.OnPFLockScreenCodeCreateListener { createFragment.setCodeCreateListener(object : PFLockScreenFragment.OnPFLockScreenCodeCreateListener {
override fun onNewCodeValidationFailed() { override fun onNewCodeValidationFailed() {
Toast.makeText(requireContext(), "Failed to validate pin, please tap a new one.", Toast.LENGTH_SHORT).show() Toast.makeText(requireContext(), getString(R.string.create_pin_confirm_failure), Toast.LENGTH_SHORT).show()
} }
override fun onCodeCreated(encodedCode: String) { override fun onCodeCreated(encodedCode: String) {
pinCodeStore.storeEncodedPin(encodedCode) lifecycleScope.launch {
vectorBaseActivity.finish() pinCodeStore.storeEncodedPin(encodedCode)
vectorBaseActivity.setResult(Activity.RESULT_OK)
vectorBaseActivity.finish()
}
} }
}) })
replaceFragment(R.id.pinFragmentContainer, createFragment) replaceFragment(R.id.pinFragmentContainer, createFragment)
} }
private fun showAuthFragment(encodedCode: String) { private fun showAuthFragment() {
val encodedPin = pinCodeStore.getEncodedPin() ?: return
val authFragment = PFLockScreenFragment() val authFragment = PFLockScreenFragment()
val builder = PFFLockScreenConfiguration.Builder(requireContext()) val builder = PFFLockScreenConfiguration.Builder(requireContext())
.setUseFingerprint(true) .setUseFingerprint(true)
.setTitle("Enter your PIN") .setTitle(getString(R.string.auth_pin_title))
.setLeftButton("Forgot PIN?") .setLeftButton(getString(R.string.auth_pin_forgot))
.setClearCodeOnError(true) .setClearCodeOnError(true)
.setMode(PFFLockScreenConfiguration.MODE_AUTH) .setMode(PFFLockScreenConfiguration.MODE_AUTH)
authFragment.setConfiguration(builder.build()) authFragment.setConfiguration(builder.build())
authFragment.setEncodedPinCode(encodedCode) authFragment.setEncodedPinCode(encodedPin)
authFragment.setOnLeftButtonClickListener { authFragment.setOnLeftButtonClickListener {
displayForgotPinWarningDialog() displayForgotPinWarningDialog()
} }
@ -106,11 +157,14 @@ class PinFragment @Inject constructor(
private fun displayForgotPinWarningDialog() { private fun displayForgotPinWarningDialog() {
AlertDialog.Builder(requireContext()) AlertDialog.Builder(requireContext())
.setTitle("Reset pin") .setTitle(getString(R.string.auth_pin_reset_title))
.setMessage("To reset your PIN, you'll need to re-login and create a new one.") .setMessage(getString(R.string.auth_pin_reset_content))
.setPositiveButton("Reset pin") { _, _ -> .setPositiveButton(getString(R.string.auth_pin_reset_title)) { _, _ ->
pinCodeStore.deleteEncodedPin() lifecycleScope.launch {
vectorBaseActivity.finish() pinCodeStore.deleteEncodedPin()
vectorBaseActivity.setResult(PinActivity.PIN_RESULT_CODE_FORGOT)
vectorBaseActivity.finish()
}
} }
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.show() .show()

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2020 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.riotx.features.pin
enum class PinMode {
CREATE,
DELETE,
AUTH
}

View file

@ -18,4 +18,7 @@ package im.vector.riotx.features.pin
import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxState
data class PinViewState(val flag: Boolean = false) : MvRxState data class PinViewState(val mode: PinMode) : MvRxState {
constructor(args: PinArgs) : this(mode = args.pinMode)
}

View file

@ -816,6 +816,6 @@ class VectorPreferences @Inject constructor(private val context: Context) {
* The user enable protecting app access with pin code * The user enable protecting app access with pin code
*/ */
fun useFlagPinCode(): Boolean { fun useFlagPinCode(): Boolean {
return defaultPrefs.getBoolean(SETTINGS_SECURITY_USE_FLAG_SECURE, false) return defaultPrefs.getBoolean(SETTINGS_SECURITY_USE_PIN_CODE_FLAG, false)
} }
} }

View file

@ -25,6 +25,7 @@ import android.widget.TextView
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceCategory import androidx.preference.PreferenceCategory
import androidx.preference.SwitchPreference import androidx.preference.SwitchPreference
@ -52,14 +53,21 @@ import im.vector.riotx.features.crypto.keys.KeysExporter
import im.vector.riotx.features.crypto.keys.KeysImporter import im.vector.riotx.features.crypto.keys.KeysImporter
import im.vector.riotx.features.crypto.keysbackup.settings.KeysBackupManageActivity import im.vector.riotx.features.crypto.keysbackup.settings.KeysBackupManageActivity
import im.vector.riotx.features.crypto.recover.BootstrapBottomSheet import im.vector.riotx.features.crypto.recover.BootstrapBottomSheet
import im.vector.riotx.features.navigation.Navigator
import im.vector.riotx.features.pin.PinActivity
import im.vector.riotx.features.pin.PinCodeStore
import im.vector.riotx.features.pin.PinMode
import im.vector.riotx.features.themes.ThemeUtils import im.vector.riotx.features.themes.ThemeUtils
import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
class VectorSettingsSecurityPrivacyFragment @Inject constructor( class VectorSettingsSecurityPrivacyFragment @Inject constructor(
private val vectorPreferences: VectorPreferences, private val vectorPreferences: VectorPreferences,
private val activeSessionHolder: ActiveSessionHolder private val activeSessionHolder: ActiveSessionHolder,
private val pinCodeStore: PinCodeStore,
private val navigator: Navigator
) : VectorSettingsBaseFragment() { ) : VectorSettingsBaseFragment() {
override var titleRes = R.string.settings_security_and_privacy override var titleRes = R.string.settings_security_and_privacy
@ -96,6 +104,10 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
findPreference<SwitchPreference>(VectorPreferences.SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY)!! findPreference<SwitchPreference>(VectorPreferences.SETTINGS_ENCRYPTION_NEVER_SENT_TO_PREFERENCE_KEY)!!
} }
private val usePinCodePref by lazy {
findPreference<SwitchPreference>(VectorPreferences.SETTINGS_SECURITY_USE_PIN_CODE_FLAG)!!
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
// My device name may have been updated // My device name may have been updated
@ -214,6 +226,8 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
} }
} }
refreshPinCodeStatus()
refreshXSigningStatus() refreshXSigningStatus()
secureBackupPreference.icon = activity?.let { secureBackupPreference.icon = activity?.let {
@ -283,10 +297,27 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor(
}) })
} }
} }
} else if (requestCode == PinActivity.PIN_REQUEST_CODE) {
refreshPinCodeStatus()
} else if (requestCode == REQUEST_E2E_FILE_REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
importKeys(data)
}
} }
if (resultCode == Activity.RESULT_OK) { }
when (requestCode) {
REQUEST_E2E_FILE_REQUEST_CODE -> importKeys(data) private fun refreshPinCodeStatus() {
lifecycleScope.launchWhenResumed {
val hasPinCode = pinCodeStore.hasEncodedPin()
usePinCodePref.isChecked = hasPinCode
usePinCodePref.onPreferenceClickListener = Preference.OnPreferenceClickListener {
val pinMode = if (hasPinCode) {
PinMode.DELETE
} else {
PinMode.CREATE
}
navigator.openPinCode(this@VectorSettingsSecurityPrivacyFragment, pinMode)
true
} }
} }
} }

View file

@ -2572,4 +2572,14 @@ Not all features in Riot are implemented in Element yet. Main missing (and comin
<string name="alert_push_are_disabled_title">Push notifications are disabled</string> <string name="alert_push_are_disabled_title">Push notifications are disabled</string>
<string name="alert_push_are_disabled_description">Review your settings to enable push notifications</string> <string name="alert_push_are_disabled_description">Review your settings to enable push notifications</string>
<string name="create_pin_title">Choose a PIN for security</string>
<string name="create_pin_confirm_title">Confirm PIN</string>
<string name="create_pin_confirm_failure">Failed to validate pin, please tap a new one.</string>
<string name="auth_pin_title">Enter your PIN</string>
<string name="auth_pin_forgot">Forgot PIN?</string>
<string name="auth_pin_reset_title">Reset pin</string>
<string name="auth_pin_reset_content">To reset your PIN, you\'ll need to re-login and create a new one.</string>
<string name="settings_security_pin_code_title">Enable PIN</string>
<string name="settings_security_pin_code_summary">If you want to reset your PIN, tap Forgot PIN to logout and reset.</string>
<string name="auth_pin_confirm_to_disable_title">Confirm PIN to disable PIN</string>
</resources> </resources>

View file

@ -108,6 +108,12 @@
android:summary="@string/settings_security_prevent_screenshots_summary" android:summary="@string/settings_security_prevent_screenshots_summary"
android:title="@string/settings_security_prevent_screenshots_title" /> android:title="@string/settings_security_prevent_screenshots_title" />
<im.vector.riotx.core.preference.VectorSwitchPreference
android:defaultValue="false"
android:key="SETTINGS_SECURITY_USE_PIN_CODE_FLAG"
android:summary="@string/settings_security_pin_code_summary"
android:title="@string/settings_security_pin_code_title" />
</im.vector.riotx.core.preference.VectorPreferenceCategory> </im.vector.riotx.core.preference.VectorPreferenceCategory>
</androidx.preference.PreferenceScreen> </androidx.preference.PreferenceScreen>