refactor: rework password dialog to avoid memory leak

This commit is contained in:
Harsh Shandilya 2023-07-09 18:49:28 +05:30
parent 227a2bf174
commit 26abbbef97
No known key found for this signature in database
3 changed files with 21 additions and 19 deletions

View File

@ -11,6 +11,7 @@ import android.content.IntentSender
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.autofill.AutofillManager import android.view.autofill.AutofillManager
import androidx.fragment.app.setFragmentResultListener
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import app.passwordstore.R import app.passwordstore.R
import app.passwordstore.data.crypto.PGPPassphraseCache import app.passwordstore.data.crypto.PGPPassphraseCache
@ -35,7 +36,6 @@ import dagger.hilt.android.AndroidEntryPoint
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import logcat.LogPriority.ERROR import logcat.LogPriority.ERROR
@ -120,16 +120,15 @@ class AutofillDecryptActivity : BasePGPActivity() {
private fun askPassphrase(filePath: String, clientState: Bundle, action: AutofillAction) { private fun askPassphrase(filePath: String, clientState: Bundle, action: AutofillAction) {
val dialog = PasswordDialog() val dialog = PasswordDialog()
lifecycleScope.launch { dialog.show(supportFragmentManager, "PASSWORD_DIALOG")
withContext(dispatcherProvider.main()) { dialog.setFragmentResultListener(PasswordDialog.PASSWORD_RESULT_KEY) { key, bundle ->
dialog.password.collectLatest { value -> if (key == PasswordDialog.PASSWORD_RESULT_KEY) {
if (value != null) { val value = bundle.getString(PasswordDialog.PASSWORD_RESULT_KEY)!!
decryptWithPassphrase(File(filePath), clientState, action, value) lifecycleScope.launch(dispatcherProvider.main()) {
} decryptWithPassphrase(File(filePath), clientState, action, value)
} }
} }
} }
dialog.show(supportFragmentManager, "PASSWORD_DIALOG")
} }
private suspend fun decryptWithPassphrase( private suspend fun decryptWithPassphrase(

View File

@ -9,6 +9,7 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import androidx.fragment.app.setFragmentResultListener
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import app.passwordstore.R import app.passwordstore.R
import app.passwordstore.crypto.PGPIdentifier import app.passwordstore.crypto.PGPIdentifier
@ -35,7 +36,6 @@ import java.io.File
import javax.inject.Inject import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@ -189,9 +189,11 @@ class DecryptActivity : BasePGPActivity() {
if (isError) { if (isError) {
dialog.setError() dialog.setError()
} }
lifecycleScope.launch(dispatcherProvider.main()) { dialog.show(supportFragmentManager, "PASSWORD_DIALOG")
dialog.password.collectLatest { value -> dialog.setFragmentResultListener(PasswordDialog.PASSWORD_RESULT_KEY) { key, bundle ->
if (value != null) { if (key == PasswordDialog.PASSWORD_RESULT_KEY) {
val value = bundle.getString(PasswordDialog.PASSWORD_RESULT_KEY)!!
lifecycleScope.launch(dispatcherProvider.main()) {
when (val result = decryptWithPassphrase(value, gpgIdentifiers)) { when (val result = decryptWithPassphrase(value, gpgIdentifiers)) {
is Ok -> { is Ok -> {
val entry = passwordEntryFactory.create(result.value.toByteArray()) val entry = passwordEntryFactory.create(result.value.toByteArray())
@ -210,7 +212,6 @@ class DecryptActivity : BasePGPActivity() {
} }
} }
} }
dialog.show(supportFragmentManager, "PASSWORD_DIALOG")
} }
private suspend fun decryptWithCachedPassphrase( private suspend fun decryptWithCachedPassphrase(

View File

@ -10,24 +10,21 @@ import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.view.KeyEvent import android.view.KeyEvent
import android.view.WindowManager import android.view.WindowManager
import androidx.core.os.bundleOf
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.setFragmentResult
import app.passwordstore.R import app.passwordstore.R
import app.passwordstore.databinding.DialogPasswordEntryBinding import app.passwordstore.databinding.DialogPasswordEntryBinding
import app.passwordstore.util.extensions.finish import app.passwordstore.util.extensions.finish
import app.passwordstore.util.extensions.unsafeLazy import app.passwordstore.util.extensions.unsafeLazy
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
/** [DialogFragment] to request a password from the user and forward it along. */ /** [DialogFragment] to request a password from the user and forward it along. */
class PasswordDialog : DialogFragment() { class PasswordDialog : DialogFragment() {
private val binding by unsafeLazy { DialogPasswordEntryBinding.inflate(layoutInflater) } private val binding by unsafeLazy { DialogPasswordEntryBinding.inflate(layoutInflater) }
private var isError: Boolean = false private var isError: Boolean = false
private val _password = MutableStateFlow<String?>(null)
val password = _password.asStateFlow()
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = MaterialAlertDialogBuilder(requireContext()) val builder = MaterialAlertDialogBuilder(requireContext())
@ -66,7 +63,12 @@ class PasswordDialog : DialogFragment() {
} }
private fun setPasswordAndDismiss() { private fun setPasswordAndDismiss() {
_password.update { binding.passwordEditText.text.toString() } val password = binding.passwordEditText.text.toString()
setFragmentResult(PASSWORD_RESULT_KEY, bundleOf(PASSWORD_RESULT_KEY to password))
dismissAllowingStateLoss() dismissAllowingStateLoss()
} }
companion object {
const val PASSWORD_RESULT_KEY = "password_result"
}
} }