mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-23 09:56:00 +03:00
Pin: add settings to enable/disable
This commit is contained in:
parent
5426e43cbb
commit
37521d2d4f
14 changed files with 207 additions and 39 deletions
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 }
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
lifecycleScope.launch {
|
||||||
pinCodeStore.storeEncodedPin(encodedCode)
|
pinCodeStore.storeEncodedPin(encodedCode)
|
||||||
|
vectorBaseActivity.setResult(Activity.RESULT_OK)
|
||||||
vectorBaseActivity.finish()
|
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,12 +157,15 @@ 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)) { _, _ ->
|
||||||
|
lifecycleScope.launch {
|
||||||
pinCodeStore.deleteEncodedPin()
|
pinCodeStore.deleteEncodedPin()
|
||||||
|
vectorBaseActivity.setResult(PinActivity.PIN_RESULT_CODE_FORGOT)
|
||||||
vectorBaseActivity.finish()
|
vectorBaseActivity.finish()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
.setNegativeButton(R.string.cancel, null)
|
.setNegativeButton(R.string.cancel, null)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
23
vector/src/main/java/im/vector/riotx/features/pin/PinMode.kt
Normal file
23
vector/src/main/java/im/vector/riotx/features/pin/PinMode.kt
Normal 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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
when (requestCode) {
|
importKeys(data)
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
Loading…
Reference in a new issue