Do not use deprecated Fragment.startActivityForResult anymore - step 2

This commit is contained in:
Benoit Marty 2020-10-07 17:21:05 +02:00
parent ff0f42900d
commit c53f79ca8b
12 changed files with 120 additions and 138 deletions

View File

@ -28,6 +28,7 @@ import android.os.Build
import android.os.PowerManager
import android.provider.Settings
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.getSystemService
@ -136,32 +137,37 @@ fun startAddGoogleAccountIntent(context: AppCompatActivity, requestCode: Int) {
}
}
fun startSharePlainTextIntent(fragment: Fragment, chooserTitle: String?, text: String, subject: String? = null, requestCode: Int? = null) {
fun startSharePlainTextIntent(fragment: Fragment,
activityResultLauncher: ActivityResultLauncher<Intent>?,
chooserTitle: String?,
text: String,
subject: String? = null) {
val share = Intent(Intent.ACTION_SEND)
share.type = "text/plain"
share.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
// Add data to the intent, the receiving app will decide what to do with it.
share.putExtra(Intent.EXTRA_SUBJECT, subject)
share.putExtra(Intent.EXTRA_TEXT, text)
val intent = Intent.createChooser(share, chooserTitle)
try {
if (requestCode != null) {
fragment.startActivityForResult(Intent.createChooser(share, chooserTitle), requestCode)
if (activityResultLauncher != null) {
activityResultLauncher.launch(intent)
} else {
fragment.startActivity(Intent.createChooser(share, chooserTitle))
fragment.startActivity(intent)
}
} catch (activityNotFoundException: ActivityNotFoundException) {
fragment.activity?.toast(R.string.error_no_external_application_found)
}
}
fun startImportTextFromFileIntent(fragment: Fragment, requestCode: Int) {
fun startImportTextFromFileIntent(context: Context, activityResultLauncher: ActivityResultLauncher<Intent>) {
val intent = Intent(Intent.ACTION_GET_CONTENT).apply {
type = "text/plain"
}
if (intent.resolveActivity(fragment.requireActivity().packageManager) != null) {
fragment.startActivityForResult(intent, requestCode)
if (intent.resolveActivity(context.packageManager) != null) {
activityResultLauncher.launch(intent)
} else {
fragment.activity?.toast(R.string.error_no_external_application_found)
context.toast(R.string.error_no_external_application_found)
}
}

View File

@ -16,7 +16,6 @@
package im.vector.app.features.crypto.keysbackup.restore
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.view.View
@ -28,19 +27,15 @@ import butterknife.OnClick
import butterknife.OnTextChanged
import com.google.android.material.textfield.TextInputLayout
import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.startImportTextFromFileIntent
import timber.log.Timber
import org.matrix.android.sdk.api.extensions.tryOrNull
import javax.inject.Inject
class KeysBackupRestoreFromKeyFragment @Inject constructor()
: VectorBaseFragment() {
companion object {
private const val REQUEST_TEXT_FILE_GET = 1
}
override fun getLayoutResId() = R.layout.fragment_keys_backup_restore_from_key
private lateinit var viewModel: KeysBackupRestoreFromKeyViewModel
@ -48,6 +43,7 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
@BindView(R.id.keys_backup_key_enter_til)
lateinit var mKeyInputLayout: TextInputLayout
@BindView(R.id.keys_restore_key_enter_edittext)
lateinit var mKeyTextEdit: EditText
@ -89,14 +85,13 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
@OnClick(R.id.keys_backup_import)
fun onImport() {
startImportTextFromFileIntent(this, REQUEST_TEXT_FILE_GET)
startImportTextFromFileIntent(requireContext(), textFileStartForActivityResult)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_TEXT_FILE_GET && resultCode == Activity.RESULT_OK) {
val dataURI = data?.data
if (dataURI != null) {
try {
private val textFileStartForActivityResult = registerStartForActivityResult { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
val dataURI = activityResult.data?.data ?: return@registerStartForActivityResult
tryOrNull(message = "Failed to read recovery kay from text") {
activity
?.contentResolver
?.openInputStream(dataURI)
@ -106,12 +101,7 @@ class KeysBackupRestoreFromKeyFragment @Inject constructor()
mKeyTextEdit.setText(it)
mKeyTextEdit.setSelection(it.length)
}
} catch (e: Exception) {
Timber.e(e, "Failed to read recovery kay from text")
}
}
return
}
super.onActivityResult(requestCode, resultCode, data)
}
}

View File

@ -144,10 +144,12 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment()
}
dialog.findViewById<View>(R.id.keys_backup_setup_share)?.setOnClickListener {
startSharePlainTextIntent(this,
context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
recoveryKey,
context?.getString(R.string.recovery_key))
startSharePlainTextIntent(
fragment = this,
activityResultLauncher = null,
chooserTitle = context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
text = recoveryKey,
subject = context?.getString(R.string.recovery_key))
viewModel.copyHasBeenMade = true
dialog.dismiss()
}

View File

@ -17,7 +17,6 @@
package im.vector.app.features.crypto.quads
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.inputmethod.EditorInfo
@ -25,6 +24,7 @@ import com.airbnb.mvrx.activityViewModel
import com.jakewharton.rxbinding3.widget.editorActionEvents
import com.jakewharton.rxbinding3.widget.textChanges
import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.startImportTextFromFileIntent
import io.reactivex.android.schedulers.AndroidSchedulers
@ -61,7 +61,7 @@ class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment
}
.disposeOnDestroyView()
ssss_key_use_file.debouncedClicks { startImportTextFromFileIntent(this, IMPORT_FILE_REQ) }
ssss_key_use_file.debouncedClicks { startImportTextFromFileIntent(requireContext(), importFileStartForActivityResult) }
ssss_key_reset.clickableView.debouncedClicks {
sharedViewModel.handle(SharedSecureStorageAction.ForgotResetAll)
@ -85,9 +85,9 @@ class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment
sharedViewModel.handle(SharedSecureStorageAction.SubmitKey(text))
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == IMPORT_FILE_REQ && resultCode == Activity.RESULT_OK) {
data?.data?.let { dataURI ->
private val importFileStartForActivityResult = registerStartForActivityResult { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
activityResult.data?.data?.let { dataURI ->
tryOrNull {
activity?.contentResolver?.openInputStream(dataURI)
?.bufferedReader()
@ -97,12 +97,6 @@ class SharedSecuredStorageKeyFragment @Inject constructor() : VectorBaseFragment
}
}
}
return
}
super.onActivityResult(requestCode, resultCode, data)
}
companion object {
private const val IMPORT_FILE_REQ = 0
}
}

View File

@ -17,7 +17,6 @@
package im.vector.app.features.crypto.recover
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.text.InputType.TYPE_CLASS_TEXT
import android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE
@ -32,6 +31,7 @@ import com.jakewharton.rxbinding3.widget.editorActionEvents
import com.jakewharton.rxbinding3.widget.textChanges
import im.vector.app.R
import im.vector.app.core.extensions.hideKeyboard
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.extensions.showPassword
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.resources.ColorProvider
@ -82,7 +82,7 @@ class BootstrapMigrateBackupFragment @Inject constructor(
bootstrapMigrateContinueButton.debouncedClicks { submit() }
bootstrapMigrateShowPassword.debouncedClicks { sharedViewModel.handle(BootstrapActions.TogglePasswordVisibility) }
bootstrapMigrateForgotPassphrase.debouncedClicks { sharedViewModel.handle(BootstrapActions.HandleForgotBackupPassphrase) }
bootstrapMigrateUseFile.debouncedClicks { startImportTextFromFileIntent(this, IMPORT_FILE_REQ) }
bootstrapMigrateUseFile.debouncedClicks { startImportTextFromFileIntent(requireContext(), importFileStartForActivityResult) }
}
private fun submit() = withState(sharedViewModel) { state ->
@ -147,9 +147,9 @@ class BootstrapMigrateBackupFragment @Inject constructor(
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == IMPORT_FILE_REQ && resultCode == Activity.RESULT_OK) {
data?.data?.let { dataURI ->
private val importFileStartForActivityResult = registerStartForActivityResult { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
activityResult.data?.data?.let { dataURI ->
tryOrNull {
activity?.contentResolver?.openInputStream(dataURI)
?.bufferedReader()
@ -159,12 +159,6 @@ class BootstrapMigrateBackupFragment @Inject constructor(
}
}
}
return
}
super.onActivityResult(requestCode, resultCode, data)
}
companion object {
private const val IMPORT_FILE_REQ = 0
}
}

View File

@ -16,7 +16,7 @@
package im.vector.app.features.crypto.recover
import android.app.Activity.RESULT_OK
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
@ -25,6 +25,7 @@ import androidx.core.view.isVisible
import com.airbnb.mvrx.parentFragmentViewModel
import com.airbnb.mvrx.withState
import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.utils.startSharePlainTextIntent
@ -65,17 +66,16 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
try {
sharedViewModel.handle(BootstrapActions.SaveReqQueryStarted)
startActivityForResult(Intent.createChooser(intent, getString(R.string.keys_backup_setup_step3_please_make_copy)), REQUEST_CODE_SAVE)
saveStartForActivityResult.launch(Intent.createChooser(intent, getString(R.string.keys_backup_setup_step3_please_make_copy)))
} catch (activityNotFoundException: ActivityNotFoundException) {
requireActivity().toast(R.string.error_no_external_application_found)
sharedViewModel.handle(BootstrapActions.SaveReqFailed)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_CODE_SAVE) {
val uri = data?.data
if (resultCode == RESULT_OK && uri != null) {
private val saveStartForActivityResult = registerStartForActivityResult { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
val uri = activityResult.data?.data ?: return@registerStartForActivityResult
GlobalScope.launch(Dispatchers.IO) {
try {
sharedViewModel.handle(BootstrapActions.SaveKeyToUri(requireContext().contentResolver!!.openOutputStream(uri)!!))
@ -87,21 +87,25 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
// result code seems to be always cancelled here.. so act as if it was saved
sharedViewModel.handle(BootstrapActions.SaveReqFailed)
}
return
} else if (requestCode == REQUEST_CODE_COPY) {
}
private val copyStartForActivityResult = registerStartForActivityResult { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
sharedViewModel.handle(BootstrapActions.RecoveryKeySaved)
}
super.onActivityResult(requestCode, resultCode, data)
}
private fun shareRecoveryKey() = withState(sharedViewModel) { state ->
val recoveryKey = state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey()
?: return@withState
startSharePlainTextIntent(this,
startSharePlainTextIntent(
this,
copyStartForActivityResult,
context?.getString(R.string.keys_backup_setup_step3_share_intent_chooser_title),
recoveryKey,
context?.getString(R.string.recovery_key), REQUEST_CODE_COPY)
context?.getString(R.string.recovery_key)
)
}
override fun invalidate() = withState(sharedViewModel) { state ->
@ -111,9 +115,4 @@ class BootstrapSaveRecoveryKeyFragment @Inject constructor(
recoveryContinue.isVisible = step.isSaved
bootstrapRecoveryKeyText.text = state.recoveryKeyCreationInfo?.recoveryKey?.formatRecoveryKey()
}
companion object {
const val REQUEST_CODE_SAVE = 123
const val REQUEST_CODE_COPY = 124
}
}

View File

@ -35,6 +35,7 @@ import im.vector.app.R
import im.vector.app.core.di.ScreenComponent
import im.vector.app.core.extensions.commitTransaction
import im.vector.app.core.extensions.exhaustive
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment
import im.vector.app.features.crypto.quads.SharedSecureStorageActivity
@ -108,12 +109,12 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
when (it) {
is VerificationBottomSheetViewEvents.Dismiss -> dismiss()
is VerificationBottomSheetViewEvents.AccessSecretStore -> {
startActivityForResult(SharedSecureStorageActivity.newIntent(
secretStartForActivityResult.launch(SharedSecureStorageActivity.newIntent(
requireContext(),
null, // use default key
listOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME, KEYBACKUP_SECRET_SSSS_NAME),
SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS
), SECRET_REQUEST_CODE)
))
}
is VerificationBottomSheetViewEvents.ModalError -> {
AlertDialog.Builder(requireContext())
@ -145,10 +146,10 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && requestCode == SECRET_REQUEST_CODE) {
val result = data?.getStringExtra(SharedSecureStorageActivity.EXTRA_DATA_RESULT)
val reset = data?.getBooleanExtra(SharedSecureStorageActivity.EXTRA_DATA_RESET, false) ?: false
private val secretStartForActivityResult = registerStartForActivityResult { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
val result = activityResult.data?.getStringExtra(SharedSecureStorageActivity.EXTRA_DATA_RESULT)
val reset = activityResult.data?.getBooleanExtra(SharedSecureStorageActivity.EXTRA_DATA_RESET, false) ?: false
if (result != null) {
viewModel.handle(VerificationAction.GotResultFromSsss(result, SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS))
} else if (reset) {
@ -156,11 +157,9 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
viewModel.handle(VerificationAction.SecuredStorageHasBeenReset)
}
}
super.onActivityResult(requestCode, resultCode, data)
}
override fun invalidate() = withState(viewModel) { state ->
state.otherUserMxItem?.let { matrixItem ->
if (state.isMe) {
avatarRenderer.render(matrixItem, otherUserAvatarImageView)
@ -347,9 +346,6 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
}
companion object {
const val SECRET_REQUEST_CODE = 101
fun withArgs(roomId: String?, otherUserId: String, transactionId: String? = null): VerificationBottomSheet {
return VerificationBottomSheet().apply {
arguments = Bundle().apply {

View File

@ -175,7 +175,6 @@ class BigImageViewerActivity : VectorBaseActivity() {
private const val EXTRA_TITLE = "EXTRA_TITLE"
private const val EXTRA_IMAGE_URL = "EXTRA_IMAGE_URL"
private const val EXTRA_CAN_EDIT_IMAGE = "EXTRA_CAN_EDIT_IMAGE"
const val REQUEST_CODE = 1000
fun newIntent(context: Context, title: String?, imageUrl: String, canEditImage: Boolean = false): Intent {
return Intent(context, BigImageViewerActivity::class.java).apply {

View File

@ -284,7 +284,12 @@ class RoomMemberProfileFragment @Inject constructor(
}
private fun handleShareRoomMemberProfile(permalink: String) {
startSharePlainTextIntent(fragment = this, chooserTitle = null, text = permalink)
startSharePlainTextIntent(
fragment = this,
activityResultLauncher = null,
chooserTitle = null,
text = permalink
)
}
private fun onAvatarClicked(view: View, userMatrixItem: MatrixItem) {

View File

@ -260,14 +260,19 @@ class RoomProfileFragment @Inject constructor(
}
private fun onShareRoomProfile(permalink: String) {
startSharePlainTextIntent(fragment = this, chooserTitle = null, text = permalink)
startSharePlainTextIntent(
fragment = this,
activityResultLauncher = null,
chooserTitle = null,
text = permalink
)
}
private fun onAvatarClicked(view: View, matrixItem: MatrixItem.RoomItem) = withState(roomProfileViewModel) {
if (matrixItem.avatarUrl?.isNotEmpty() == true) {
val intent = BigImageViewerActivity.newIntent(requireContext(), matrixItem.getBestName(), matrixItem.avatarUrl!!, it.canChangeAvatar)
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(requireActivity(), view, ViewCompat.getTransitionName(view) ?: "")
startActivityForResult(intent, BigImageViewerActivity.REQUEST_CODE, options.toBundle())
bigImageStartForActivityResult.launch(intent, options)
} else if (it.canChangeAvatar) {
showAvatarSelector()
}
@ -333,14 +338,20 @@ class RoomProfileFragment @Inject constructor(
}
}
private val bigImageStartForActivityResult = registerStartForActivityResult { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
activityResult.data?.let { onAvatarCropped(it.data) }
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) }
BigImageViewerActivity.REQUEST_CODE -> data?.let { onAvatarCropped(it.data) }
}
}
// TODO
// TODO handle this one (Ucrop lib)
@Suppress("DEPRECATION")
super.onActivityResult(requestCode, resultCode, data)
}

View File

@ -27,6 +27,7 @@ import androidx.preference.Preference
import androidx.preference.SwitchPreference
import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.preference.VectorEditTextPreference
import im.vector.app.core.preference.VectorPreference
import im.vector.app.core.preference.VectorPreferenceCategory
@ -210,18 +211,15 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, vectorPreferences.getNotificationRingTone())
}
startActivityForResult(intent, REQUEST_NOTIFICATION_RINGTONE)
ringtoneStartForActivityResult.launch(intent)
false
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
REQUEST_NOTIFICATION_RINGTONE -> {
vectorPreferences.setNotificationRingTone(data?.getParcelableExtra<Parcelable>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI) as Uri?)
private val ringtoneStartForActivityResult = registerStartForActivityResult { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
vectorPreferences.setNotificationRingTone(activityResult.data?.getParcelableExtra<Parcelable>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI) as Uri?)
// test if the selected ring tone can be played
val notificationRingToneName = vectorPreferences.getNotificationRingToneName()
@ -232,8 +230,6 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
}
}
}
}
}
override fun onResume() {
super.onResume()
@ -342,7 +338,6 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
}
companion object {
private const val REQUEST_NOTIFICATION_RINGTONE = 888
private const val REQUEST_BATTERY_OPTIMIZATION = 500
}
}

View File

@ -23,6 +23,7 @@ import android.net.Uri
import androidx.preference.Preference
import androidx.preference.SwitchPreference
import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.preference.VectorPreference
import im.vector.app.core.utils.getCallRingtoneName
import im.vector.app.core.utils.getCallRingtoneUri
@ -57,13 +58,9 @@ class VectorSettingsVoiceVideoFragment : VectorSettingsBaseFragment() {
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
REQUEST_CALL_RINGTONE -> {
val callRingtoneUri: Uri? = data?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
private val ringtoneStartForActivityResult = registerStartForActivityResult { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
val callRingtoneUri: Uri? = activityResult.data?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
val thisActivity = activity
if (callRingtoneUri != null && thisActivity != null) {
setCallRingtoneUri(thisActivity, callRingtoneUri)
@ -71,8 +68,6 @@ class VectorSettingsVoiceVideoFragment : VectorSettingsBaseFragment() {
}
}
}
}
}
private fun displayRingtonePicker() {
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply {
@ -82,10 +77,6 @@ class VectorSettingsVoiceVideoFragment : VectorSettingsBaseFragment() {
putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE)
activity?.let { putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, getCallRingtoneUri(it)) }
}
startActivityForResult(intent, REQUEST_CALL_RINGTONE)
}
companion object {
private const val REQUEST_CALL_RINGTONE = 999
ringtoneStartForActivityResult.launch(intent)
}
}