diff --git a/attachment-viewer/build.gradle b/attachment-viewer/build.gradle index 59ba6c4500..91ddd519df 100644 --- a/attachment-viewer/build.gradle +++ b/attachment-viewer/build.gradle @@ -66,6 +66,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.3.2' implementation 'androidx.appcompat:appcompat:1.2.0' + implementation "androidx.fragment:fragment:1.3.0-beta01" implementation "androidx.recyclerview:recyclerview:1.1.0" implementation 'com.google.android.material:material:1.2.1' diff --git a/matrix-sdk-android-rx/build.gradle b/matrix-sdk-android-rx/build.gradle index 03b60bbcf7..3d62758065 100644 --- a/matrix-sdk-android-rx/build.gradle +++ b/matrix-sdk-android-rx/build.gradle @@ -36,6 +36,7 @@ android { dependencies { implementation project(":matrix-sdk-android") implementation 'androidx.appcompat:appcompat:1.2.0' + implementation "androidx.fragment:fragment:1.3.0-beta01" implementation 'io.reactivex.rxjava2:rxkotlin:2.3.0' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' // Paging diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index c0030cca3d..0bf4819d25 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -121,6 +121,7 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" implementation "androidx.appcompat:appcompat:1.2.0" + implementation "androidx.fragment:fragment:1.3.0-beta01" implementation "androidx.core:core-ktx:1.3.2" implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" diff --git a/multipicker/build.gradle b/multipicker/build.gradle index 0eb38c23dd..b6e500e493 100644 --- a/multipicker/build.gradle +++ b/multipicker/build.gradle @@ -41,9 +41,9 @@ android { } dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.2.0' + implementation "androidx.fragment:fragment:1.3.0-beta01" implementation 'androidx.exifinterface:exifinterface:1.3.0' // Log diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/AudioPicker.kt b/multipicker/src/main/java/im/vector/lib/multipicker/AudioPicker.kt index c51084dd39..e796137af2 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/AudioPicker.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/AudioPicker.kt @@ -16,7 +16,6 @@ package im.vector.lib.multipicker -import android.app.Activity import android.content.Context import android.content.Intent import android.media.MediaMetadataRetriever @@ -30,15 +29,9 @@ class AudioPicker(override val requestCode: Int) : Picker( /** * Call this function from onActivityResult(int, int, Intent). - * Returns selected audio files or empty list if request code is wrong - * or result code is not Activity.RESULT_OK - * or user did not select any files. + * Returns selected audio files or empty list if user did not select any files. */ - override fun getSelectedFiles(context: Context, requestCode: Int, resultCode: Int, data: Intent?): List { - if (requestCode != this.requestCode && resultCode != Activity.RESULT_OK) { - return emptyList() - } - + override fun getSelectedFiles(context: Context, data: Intent?): List { val audioList = mutableListOf() getSelectedUriList(data).forEach { selectedUri -> diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/CameraPicker.kt b/multipicker/src/main/java/im/vector/lib/multipicker/CameraPicker.kt index be6fdb5ee8..319bc31af9 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/CameraPicker.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/CameraPicker.kt @@ -21,8 +21,8 @@ import android.content.Context import android.content.Intent import android.net.Uri import android.provider.MediaStore +import androidx.activity.result.ActivityResultLauncher import androidx.core.content.FileProvider -import androidx.fragment.app.Fragment import im.vector.lib.multipicker.entity.MultiPickerImageType import im.vector.lib.multipicker.utils.ImageUtils import java.io.File @@ -51,15 +51,14 @@ class CameraPicker(val requestCode: Int) { /** * Start camera by using a Fragment - * @param fragment Fragment to handle onActivityResult(). * @return Uri of taken photo or null if the operation is cancelled. */ - fun startWithExpectingFile(fragment: Fragment): Uri? { - val photoUri = createPhotoUri(fragment.requireContext()) + fun startWithExpectingFile(context: Context, activityResultLauncher: ActivityResultLauncher): Uri? { + val photoUri = createPhotoUri(context) val intent = createIntent().apply { putExtra(MediaStore.EXTRA_OUTPUT, photoUri) } - fragment.startActivityForResult(intent, requestCode) + activityResultLauncher.launch(intent) return photoUri } @@ -69,40 +68,38 @@ class CameraPicker(val requestCode: Int) { * or result code is not Activity.RESULT_OK * or user cancelled the operation. */ - fun getTakenPhoto(context: Context, requestCode: Int, resultCode: Int, photoUri: Uri): MultiPickerImageType? { - if (requestCode == this.requestCode && resultCode == Activity.RESULT_OK) { - val projection = arrayOf( - MediaStore.Images.Media.DISPLAY_NAME, - MediaStore.Images.Media.SIZE - ) + fun getTakenPhoto(context: Context, photoUri: Uri): MultiPickerImageType? { + val projection = arrayOf( + MediaStore.Images.Media.DISPLAY_NAME, + MediaStore.Images.Media.SIZE + ) - context.contentResolver.query( - photoUri, - projection, - null, - null, - null - )?.use { cursor -> - val nameColumn = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME) - val sizeColumn = cursor.getColumnIndex(MediaStore.Images.Media.SIZE) + context.contentResolver.query( + photoUri, + projection, + null, + null, + null + )?.use { cursor -> + val nameColumn = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME) + val sizeColumn = cursor.getColumnIndex(MediaStore.Images.Media.SIZE) - if (cursor.moveToNext()) { - val name = cursor.getString(nameColumn) - val size = cursor.getLong(sizeColumn) + if (cursor.moveToNext()) { + val name = cursor.getString(nameColumn) + val size = cursor.getLong(sizeColumn) - val bitmap = ImageUtils.getBitmap(context, photoUri) - val orientation = ImageUtils.getOrientation(context, photoUri) + val bitmap = ImageUtils.getBitmap(context, photoUri) + val orientation = ImageUtils.getOrientation(context, photoUri) - return MultiPickerImageType( - name, - size, - context.contentResolver.getType(photoUri), - photoUri, - bitmap?.width ?: 0, - bitmap?.height ?: 0, - orientation - ) - } + return MultiPickerImageType( + name, + size, + context.contentResolver.getType(photoUri), + photoUri, + bitmap?.width ?: 0, + bitmap?.height ?: 0, + orientation + ) } } return null diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/ContactPicker.kt b/multipicker/src/main/java/im/vector/lib/multipicker/ContactPicker.kt index e9ae096174..5eb8a98999 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/ContactPicker.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/ContactPicker.kt @@ -16,7 +16,6 @@ package im.vector.lib.multipicker -import android.app.Activity import android.content.ContentResolver import android.content.Context import android.content.Intent @@ -30,15 +29,9 @@ class ContactPicker(override val requestCode: Int) : Picker { - if (requestCode != this.requestCode && resultCode != Activity.RESULT_OK) { - return emptyList() - } - + override fun getSelectedFiles(context: Context, data: Intent?): List { val contactList = mutableListOf() data?.data?.let { selectedUri -> diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt b/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt index d5718b9951..7510d06b2b 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt @@ -16,7 +16,6 @@ package im.vector.lib.multipicker -import android.app.Activity import android.content.Context import android.content.Intent import android.provider.OpenableColumns @@ -29,15 +28,9 @@ class FilePicker(override val requestCode: Int) : Picker(re /** * Call this function from onActivityResult(int, int, Intent). - * Returns selected files or empty list if request code is wrong - * or result code is not Activity.RESULT_OK - * or user did not select any files. + * Returns selected files or empty list if user did not select any files. */ - override fun getSelectedFiles(context: Context, requestCode: Int, resultCode: Int, data: Intent?): List { - if (requestCode != this.requestCode && resultCode != Activity.RESULT_OK) { - return emptyList() - } - + override fun getSelectedFiles(context: Context, data: Intent?): List { val fileList = mutableListOf() getSelectedUriList(data).forEach { selectedUri -> diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/ImagePicker.kt b/multipicker/src/main/java/im/vector/lib/multipicker/ImagePicker.kt index ec87e027f9..054bfba365 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/ImagePicker.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/ImagePicker.kt @@ -16,7 +16,6 @@ package im.vector.lib.multipicker -import android.app.Activity import android.content.Context import android.content.Intent import android.provider.MediaStore @@ -30,15 +29,9 @@ class ImagePicker(override val requestCode: Int) : Picker( /** * Call this function from onActivityResult(int, int, Intent). - * Returns selected image files or empty list if request code is wrong - * or result code is not Activity.RESULT_OK - * or user did not select any files. + * Returns selected image files or empty list if user did not select any files. */ - override fun getSelectedFiles(context: Context, requestCode: Int, resultCode: Int, data: Intent?): List { - if (requestCode != this.requestCode && resultCode != Activity.RESULT_OK) { - return emptyList() - } - + override fun getSelectedFiles(context: Context, data: Intent?): List { val imageList = mutableListOf() getSelectedUriList(data).forEach { selectedUri -> diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/Picker.kt b/multipicker/src/main/java/im/vector/lib/multipicker/Picker.kt index 65ec77e02a..33da23e2b6 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/Picker.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/Picker.kt @@ -22,7 +22,7 @@ import android.content.Intent import android.content.pm.PackageManager import android.content.pm.ResolveInfo import android.net.Uri -import androidx.fragment.app.Fragment +import androidx.activity.result.ActivityResultLauncher /** * Abstract class to provide all types of Pickers @@ -33,11 +33,9 @@ abstract class Picker(open val requestCode: Int) { /** * Call this function from onActivityResult(int, int, Intent). - * @return selected files or empty list if request code is wrong - * or result code is not Activity.RESULT_OK - * or user did not select any files. + * @return selected files or empty list if user did not select any files. */ - abstract fun getSelectedFiles(context: Context, requestCode: Int, resultCode: Int, data: Intent?): List + abstract fun getSelectedFiles(context: Context, data: Intent?): List /** * Use this function to retrieve files which are shared from another application or internally @@ -61,7 +59,7 @@ abstract class Picker(open val requestCode: Int) { context.grantUriPermission(packageName, it, Intent.FLAG_GRANT_READ_URI_PERMISSION) } } - return getSelectedFiles(context, requestCode, Activity.RESULT_OK, data) + return getSelectedFiles(context, data) } /** @@ -84,10 +82,10 @@ abstract class Picker(open val requestCode: Int) { /** * Start Storage Access Framework UI by using a Fragment. - * @param fragment Fragment to handle onActivityResult(). + * @param activityResultLauncher to handle the result. */ - fun startWith(fragment: Fragment) { - fragment.startActivityForResult(createIntent().apply { addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) }, requestCode) + fun startWith(activityResultLauncher: ActivityResultLauncher) { + activityResultLauncher.launch(createIntent().apply { addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) }) } protected fun getSelectedUriList(data: Intent?): List { diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/VideoPicker.kt b/multipicker/src/main/java/im/vector/lib/multipicker/VideoPicker.kt index 965c8e08e0..c1d1f74aab 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/VideoPicker.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/VideoPicker.kt @@ -16,7 +16,6 @@ package im.vector.lib.multipicker -import android.app.Activity import android.content.Context import android.content.Intent import android.media.MediaMetadataRetriever @@ -30,15 +29,9 @@ class VideoPicker(override val requestCode: Int) : Picker( /** * Call this function from onActivityResult(int, int, Intent). - * Returns selected video files or empty list if request code is wrong - * or result code is not Activity.RESULT_OK - * or user did not select any files. + * Returns selected video files or empty list if user did not select any files. */ - override fun getSelectedFiles(context: Context, requestCode: Int, resultCode: Int, data: Intent?): List { - if (requestCode != this.requestCode && resultCode != Activity.RESULT_OK) { - return emptyList() - } - + override fun getSelectedFiles(context: Context, data: Intent?): List { val videoList = mutableListOf() getSelectedUriList(data).forEach { selectedUri -> diff --git a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt index fbcd6900c1..80be149711 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Fragment.kt @@ -17,7 +17,11 @@ package im.vector.app.core.extensions import android.app.Activity +import android.content.Intent import android.os.Parcelable +import androidx.activity.result.ActivityResult +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.Fragment import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment @@ -26,6 +30,10 @@ import java.text.SimpleDateFormat import java.util.Date import java.util.Locale +fun Fragment.registerStartForActivityResult(onResult: (ActivityResult) -> Unit): ActivityResultLauncher { + return registerForActivityResult(ActivityResultContracts.StartActivityForResult(), onResult) +} + fun VectorBaseFragment.addFragment( frameId: Int, fragment: Fragment, @@ -160,15 +168,15 @@ fun Fragment.getAllChildFragments(): List { // Define a missing constant const val POP_BACK_STACK_EXCLUSIVE = 0 -fun Fragment.queryExportKeys(userId: String, requestCode: Int) { +fun Fragment.queryExportKeys(userId: String, activityResultLauncher: ActivityResultLauncher) { val timestamp = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date()) selectTxtFileToWrite( activity = requireActivity(), - fragment = this, + activityResultLauncher = activityResultLauncher, defaultFileName = "element-megolm-export-$userId-$timestamp.txt", chooserHint = getString(R.string.keys_backup_setup_step1_manual_export), - requestCode = requestCode + requestCode = 0 ) } @@ -177,7 +185,7 @@ fun Activity.queryExportKeys(userId: String, requestCode: Int) { selectTxtFileToWrite( activity = this, - fragment = null, + activityResultLauncher = null, defaultFileName = "element-megolm-export-$userId-$timestamp.txt", chooserHint = getString(R.string.keys_backup_setup_step1_manual_export), requestCode = requestCode diff --git a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt index d28f6749a6..750c4e071b 100644 --- a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt +++ b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt @@ -31,6 +31,7 @@ import android.provider.Browser import android.provider.MediaStore import android.webkit.MimeTypeMap import android.widget.Toast +import androidx.activity.result.ActivityResultLauncher import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsSession import androidx.core.content.ContextCompat @@ -130,7 +131,7 @@ fun openSoundRecorder(activity: Activity, requestCode: Int) { * Open file selection activity */ fun openFileSelection(activity: Activity, - fragment: Fragment?, + activityResultLauncher: ActivityResultLauncher?, allowMultipleSelection: Boolean, requestCode: Int) { val fileIntent = Intent(Intent.ACTION_GET_CONTENT) @@ -140,8 +141,8 @@ fun openFileSelection(activity: Activity, fileIntent.type = "*/*" try { - fragment - ?.startActivityForResult(fileIntent, requestCode) + activityResultLauncher + ?.launch(fileIntent) ?: run { activity.startActivityForResult(fileIntent, requestCode) } @@ -440,7 +441,7 @@ fun openPlayStore(activity: Activity, appId: String = BuildConfig.APPLICATION_ID */ fun selectTxtFileToWrite( activity: Activity, - fragment: Fragment?, + activityResultLauncher: ActivityResultLauncher?, defaultFileName: String, chooserHint: String, requestCode: Int @@ -452,8 +453,8 @@ fun selectTxtFileToWrite( try { val chooserIntent = Intent.createChooser(intent, chooserHint) - if (fragment != null) { - fragment.startActivityForResult(chooserIntent, requestCode) + if (activityResultLauncher != null) { + activityResultLauncher.launch(chooserIntent) } else { activity.startActivityForResult(chooserIntent, requestCode) } diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentsHelper.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentsHelper.kt index 1d7c67b046..d4efb22eb8 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/AttachmentsHelper.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentsHelper.kt @@ -15,12 +15,11 @@ */ package im.vector.app.features.attachments -import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri import android.os.Bundle -import androidx.fragment.app.Fragment +import androidx.activity.result.ActivityResultLauncher import im.vector.app.core.platform.Restorable import im.vector.lib.multipicker.MultiPicker import org.matrix.android.sdk.BuildConfig @@ -48,6 +47,7 @@ class AttachmentsHelper(val context: Context, val callback: Callback) : Restorab // Capture path allows to handle camera image picking. It must be restored if the activity gets killed. private var captureUri: Uri? = null + // The pending type is set if we have to handle permission request. It must be restored if the activity gets killed. var pendingType: AttachmentTypeSelectorView.Type? = null @@ -72,99 +72,93 @@ class AttachmentsHelper(val context: Context, val callback: Callback) : Restorab /** * Starts the process for handling file picking */ - fun selectFile(fragment: Fragment) { - MultiPicker.get(MultiPicker.FILE).startWith(fragment) + fun selectFile(activityResultLauncher: ActivityResultLauncher) { + MultiPicker.get(MultiPicker.FILE).startWith(activityResultLauncher) } /** * Starts the process for handling image picking */ - fun selectGallery(fragment: Fragment) { - MultiPicker.get(MultiPicker.IMAGE).startWith(fragment) + fun selectGallery(activityResultLauncher: ActivityResultLauncher) { + MultiPicker.get(MultiPicker.IMAGE).startWith(activityResultLauncher) } /** * Starts the process for handling audio picking */ - fun selectAudio(fragment: Fragment) { - MultiPicker.get(MultiPicker.AUDIO).startWith(fragment) + fun selectAudio(activityResultLauncher: ActivityResultLauncher) { + MultiPicker.get(MultiPicker.AUDIO).startWith(activityResultLauncher) } /** * Starts the process for handling capture image picking */ - fun openCamera(fragment: Fragment) { - captureUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(fragment) + fun openCamera(context: Context, activityResultLauncher: ActivityResultLauncher) { + captureUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(context, activityResultLauncher) } /** * Starts the process for handling contact picking */ - fun selectContact(fragment: Fragment) { - MultiPicker.get(MultiPicker.CONTACT).startWith(fragment) + fun selectContact(activityResultLauncher: ActivityResultLauncher) { + MultiPicker.get(MultiPicker.CONTACT).startWith(activityResultLauncher) } /** - * This methods aims to handle on activity result data. - * - * @return true if it can handle the data, false otherwise + * This methods aims to handle the result data. */ - fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { - if (resultCode == Activity.RESULT_OK) { - when (requestCode) { - MultiPicker.REQUEST_CODE_PICK_FILE -> { - callback.onContentAttachmentsReady( - MultiPicker.get(MultiPicker.FILE) - .getSelectedFiles(context, requestCode, resultCode, data) - .map { it.toContentAttachmentData() } - ) + fun onFileResult(data: Intent?) { + callback.onContentAttachmentsReady( + MultiPicker.get(MultiPicker.FILE) + .getSelectedFiles(context, data) + .map { it.toContentAttachmentData() } + ) + } + + fun onAudioResult(data: Intent?) { + callback.onContentAttachmentsReady( + MultiPicker.get(MultiPicker.AUDIO) + .getSelectedFiles(context, data) + .map { it.toContentAttachmentData() } + ) + } + + fun onContactResult(data: Intent?) { + MultiPicker.get(MultiPicker.CONTACT) + .getSelectedFiles(context, data) + .firstOrNull() + ?.toContactAttachment() + ?.let { + callback.onContactAttachmentReady(it) } - MultiPicker.REQUEST_CODE_PICK_AUDIO -> { - callback.onContentAttachmentsReady( - MultiPicker.get(MultiPicker.AUDIO) - .getSelectedFiles(context, requestCode, resultCode, data) - .map { it.toContentAttachmentData() } - ) - } - MultiPicker.REQUEST_CODE_PICK_CONTACT -> { - MultiPicker.get(MultiPicker.CONTACT) - .getSelectedFiles(context, requestCode, resultCode, data) - .firstOrNull() - ?.toContactAttachment() - ?.let { - callback.onContactAttachmentReady(it) - } - } - MultiPicker.REQUEST_CODE_PICK_IMAGE -> { - callback.onContentAttachmentsReady( - MultiPicker.get(MultiPicker.IMAGE) - .getSelectedFiles(context, requestCode, resultCode, data) - .map { it.toContentAttachmentData() } - ) - } - MultiPicker.REQUEST_CODE_TAKE_PHOTO -> { - captureUri?.let { captureUri -> - MultiPicker.get(MultiPicker.CAMERA) - .getTakenPhoto(context, requestCode, resultCode, captureUri) - ?.let { - callback.onContentAttachmentsReady( - listOf(it).map { it.toContentAttachmentData() } - ) - } + } + + fun onImageResult(data: Intent?) { + callback.onContentAttachmentsReady( + MultiPicker.get(MultiPicker.IMAGE) + .getSelectedFiles(context, data) + .map { it.toContentAttachmentData() } + ) + } + + fun onPhotoResult() { + captureUri?.let { captureUri -> + MultiPicker.get(MultiPicker.CAMERA) + .getTakenPhoto(context, captureUri) + ?.let { + callback.onContentAttachmentsReady( + listOf(it).map { it.toContentAttachmentData() } + ) } - } - MultiPicker.REQUEST_CODE_PICK_VIDEO -> { - callback.onContentAttachmentsReady( - MultiPicker.get(MultiPicker.VIDEO) - .getSelectedFiles(context, requestCode, resultCode, data) - .map { it.toContentAttachmentData() } - ) - } - else -> return false - } - return true } - return false + } + + fun onVideoResult(data: Intent?) { + callback.onContentAttachmentsReady( + MultiPicker.get(MultiPicker.VIDEO) + .getSelectedFiles(context, data) + .map { it.toContentAttachmentData() } + ) } /** diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt index bfa44a7a70..8e830d00a4 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt @@ -30,8 +30,6 @@ import org.matrix.android.sdk.api.session.content.ContentAttachmentData class AttachmentsPreviewActivity : VectorBaseActivity(), ToolbarConfigurable { companion object { - const val REQUEST_CODE = 55 - private const val EXTRA_FRAGMENT_ARGS = "EXTRA_FRAGMENT_ARGS" private const val ATTACHMENTS_PREVIEW_RESULT = "ATTACHMENTS_PREVIEW_RESULT" private const val KEEP_ORIGINAL_IMAGES_SIZE = "KEEP_ORIGINAL_IMAGES_SIZE" diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt index 4d6c4e3add..44c440c0d1 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt @@ -298,6 +298,7 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == CAPTURE_PERMISSION_REQUEST_CODE && allGranted(grantResults)) { start() } else { diff --git a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt index 5a4c25a8ad..1ab6fb6363 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt @@ -150,6 +150,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMeetActivityInterface, Ji } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) JitsiMeetActivityDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults) } diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index 27ca636142..501d0fdbb7 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -111,6 +111,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (allGranted(grantResults)) { if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) { doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) } diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt index e508f06e4d..03ad5d5d9f 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep3Fragment.kt @@ -31,6 +31,7 @@ import butterknife.BindView import butterknife.OnClick import com.google.android.material.bottomsheet.BottomSheetDialog 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.LiveEvent import im.vector.app.core.utils.copyToClipboard @@ -48,10 +49,6 @@ import javax.inject.Inject class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() { - companion object { - private const val SAVE_RECOVERY_KEY_REQUEST_CODE = 2754 - } - override fun getLayoutResId() = R.layout.fragment_keys_backup_setup_step3 @BindView(R.id.keys_backup_setup_step3_button) @@ -138,10 +135,10 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() val timestamp = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date()) selectTxtFileToWrite( activity = requireActivity(), - fragment = this, + activityResultLauncher = saveRecoveryActivityResultLauncher, defaultFileName = "recovery-key-$userId-$timestamp.txt", chooserHint = getString(R.string.save_recovery_key_chooser_hint), - requestCode = SAVE_RECOVERY_KEY_REQUEST_CODE + requestCode = 0 ) dialog.dismiss() } @@ -202,15 +199,11 @@ class KeysBackupSetupStep3Fragment @Inject constructor() : VectorBaseFragment() } } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - when (requestCode) { - SAVE_RECOVERY_KEY_REQUEST_CODE -> { - val uri = data?.data - if (resultCode == Activity.RESULT_OK && uri != null) { - viewModel.recoveryKey.value?.let { - exportRecoveryKeyToFile(uri, it) - } - } + private val saveRecoveryActivityResultLauncher = registerStartForActivityResult { activityRessult -> + val uri = activityRessult.data?.data ?: return@registerStartForActivityResult + if (activityRessult.resultCode == Activity.RESULT_OK) { + viewModel.recoveryKey.value?.let { + exportRecoveryKeyToFile(uri, it) } } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt index a1ce84e2f4..72cd063bbd 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/verification/choose/VerificationChooseMethodFragment.kt @@ -16,7 +16,6 @@ package im.vector.app.features.crypto.verification.choose import android.app.Activity -import android.content.Intent import android.os.Bundle import android.view.View import com.airbnb.mvrx.fragmentViewModel @@ -25,6 +24,7 @@ import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith +import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO import im.vector.app.core.utils.checkPermissions @@ -91,24 +91,18 @@ class VerificationChooseMethodFragment @Inject constructor( } private fun doOpenQRCodeScanner() { - QrCodeScannerActivity.startForResult(this) + QrCodeScannerActivity.startForResult(requireActivity(), scanActivityResultLauncher) } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) + private val scanActivityResultLauncher = registerStartForActivityResult { activityResult -> + if (activityResult.resultCode == Activity.RESULT_OK) { + val scannedQrCode = QrCodeScannerActivity.getResultText(activityResult.data) + val wasQrCode = QrCodeScannerActivity.getResultIsQrCode(activityResult.data) - if (resultCode == Activity.RESULT_OK) { - when (requestCode) { - QrCodeScannerActivity.QR_CODE_SCANNER_REQUEST_CODE -> { - val scannedQrCode = QrCodeScannerActivity.getResultText(data) - val wasQrCode = QrCodeScannerActivity.getResultIsQrCode(data) - - if (wasQrCode && !scannedQrCode.isNullOrBlank()) { - onRemoteQrCodeScanned(scannedQrCode) - } else { - Timber.w("It was not a QR code, or empty result") - } - } + if (wasQrCode && !scannedQrCode.isNullOrBlank()) { + onRemoteQrCodeScanned(scannedQrCode) + } else { + Timber.w("It was not a QR code, or empty result") } } } diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt index 21f65ec9ef..7dd32a7cd0 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt @@ -16,7 +16,6 @@ package im.vector.app.features.discovery import android.app.Activity -import android.content.Intent import android.os.Bundle import android.view.View import androidx.appcompat.app.AlertDialog @@ -27,16 +26,17 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.observeEvent +import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.ensureProtocol import im.vector.app.features.discovery.change.SetIdentityServerFragment import im.vector.app.features.settings.VectorSettingsActivity -import im.vector.app.features.terms.ReviewTermsActivity import org.matrix.android.sdk.api.session.identity.SharedState import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.terms.TermsService import kotlinx.android.synthetic.main.fragment_generic_recycler.* +import timber.log.Timber import javax.inject.Inject class DiscoverySettingsFragment @Inject constructor( @@ -92,22 +92,19 @@ class DiscoverySettingsFragment @Inject constructor( viewModel.handle(DiscoverySettingsAction.Refresh) } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (requestCode == ReviewTermsActivity.TERMS_REQUEST_CODE) { - if (Activity.RESULT_OK == resultCode) { - viewModel.handle(DiscoverySettingsAction.RetrieveBinding) - } else { - // add some error? - } + private val termsActivityResultLauncher = registerStartForActivityResult { + if (it.resultCode == Activity.RESULT_OK) { + viewModel.handle(DiscoverySettingsAction.RetrieveBinding) + } else { + // add some error? } - - super.onActivityResult(requestCode, resultCode, data) } override fun openIdentityServerTerms() = withState(viewModel) { state -> if (state.termsNotSigned) { navigator.openTerms( - this, + requireContext(), + termsActivityResultLauncher, TermsService.ServiceType.IdentityService, state.identityServer()?.ensureProtocol() ?: "", null) diff --git a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt index 863270b762..05708089ea 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/change/SetIdentityServerFragment.kt @@ -16,7 +16,6 @@ package im.vector.app.features.discovery.change import android.app.Activity -import android.content.Intent import android.os.Bundle import android.view.View import android.view.inputmethod.EditorInfo @@ -28,13 +27,13 @@ import com.airbnb.mvrx.withState import com.jakewharton.rxbinding3.widget.textChanges import im.vector.app.R import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.extensions.toReducedUrl import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.core.utils.colorizeMatchingText import im.vector.app.features.discovery.DiscoverySharedViewModel -import im.vector.app.features.terms.ReviewTermsActivity import org.matrix.android.sdk.api.session.terms.TermsService import kotlinx.android.synthetic.main.fragment_set_identity_server.* import javax.inject.Inject @@ -121,7 +120,8 @@ class SetIdentityServerFragment @Inject constructor( is SetIdentityServerViewEvents.TermsAccepted -> processIdentityServerChange() is SetIdentityServerViewEvents.ShowTerms -> { navigator.openTerms( - this, + requireContext(), + termsActivityResultLauncher, TermsService.ServiceType.IdentityService, it.identityServerUrl, null) @@ -150,15 +150,12 @@ class SetIdentityServerFragment @Inject constructor( (activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.identity_server) } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (requestCode == ReviewTermsActivity.TERMS_REQUEST_CODE) { - if (Activity.RESULT_OK == resultCode) { - processIdentityServerChange() - } else { - // add some error? - } + private val termsActivityResultLauncher = registerStartForActivityResult { + if (it.resultCode == Activity.RESULT_OK) { + processIdentityServerChange() + } else { + // add some error? } - super.onActivityResult(requestCode, resultCode, data) } private fun processIdentityServerChange() { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index c861e5ce73..61041aa70f 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -17,7 +17,7 @@ package im.vector.app.features.home.room.detail import android.annotation.SuppressLint -import android.app.Activity.RESULT_OK +import android.app.Activity import android.content.DialogInterface import android.content.Intent import android.graphics.Typeface @@ -73,6 +73,7 @@ import im.vector.app.core.epoxy.LayoutManagerStateRestorer import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.hideKeyboard +import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.extensions.showKeyboard import im.vector.app.core.extensions.trackItemsVisibilityChange @@ -134,7 +135,6 @@ import im.vector.app.features.home.room.detail.timeline.item.MessageTextItem import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData import im.vector.app.features.home.room.detail.timeline.reactions.ViewReactionsBottomSheet import im.vector.app.features.home.room.detail.widget.RoomWidgetsBottomSheet -import im.vector.app.features.home.room.detail.widget.WidgetRequestCodes import im.vector.app.features.html.EventHtmlRenderer import im.vector.app.features.html.PillImageSpan import im.vector.app.features.invite.VectorInviteView @@ -202,8 +202,6 @@ data class RoomDetailArgs( val sharedData: SharedData? = null ) : Parcelable -private const val REACTION_SELECT_REQUEST_CODE = 0 - class RoomDetailFragment @Inject constructor( private val session: Session, private val avatarRenderer: AvatarRenderer, @@ -396,9 +394,14 @@ class RoomDetailFragment @Inject constructor( } } + private val integrationManagerActivityResultLauncher = registerStartForActivityResult { + // Noop + } + private fun openIntegrationManager(screen: String? = null) { navigator.openIntegrationManager( - fragment = this, + context = requireContext(), + activityResultLauncher = integrationManagerActivityResultLauncher, roomId = roomDetailArgs.roomId, integId = null, screen = screen @@ -435,7 +438,7 @@ class RoomDetailFragment @Inject constructor( } private fun openStickerPicker(event: RoomDetailViewEvents.OpenStickerPicker) { - navigator.openStickerPicker(this, roomDetailArgs.roomId, event.widget) + navigator.openStickerPicker(requireContext(), stickerActivityResultLauncher, roomDetailArgs.roomId, event.widget) } private fun startOpenFileIntent(action: RoomDetailViewEvents.OpenFile) { @@ -886,27 +889,63 @@ class RoomDetailFragment @Inject constructor( roomDetailViewModel.handle(RoomDetailAction.SaveDraft(composerLayout.composerEditText.text.toString())) } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - val hasBeenHandled = attachmentsHelper.onActivityResult(requestCode, resultCode, data) - if (!hasBeenHandled && resultCode == RESULT_OK && data != null) { - when (requestCode) { - AttachmentsPreviewActivity.REQUEST_CODE -> { - val sendData = AttachmentsPreviewActivity.getOutput(data) - val keepOriginalSize = AttachmentsPreviewActivity.getKeepOriginalSize(data) - roomDetailViewModel.handle(RoomDetailAction.SendMedia(sendData, !keepOriginalSize)) - } - REACTION_SELECT_REQUEST_CODE -> { - val (eventId, reaction) = EmojiReactionPickerActivity.getOutput(data) ?: return - roomDetailViewModel.handle(RoomDetailAction.SendReaction(eventId, reaction)) - } - WidgetRequestCodes.STICKER_PICKER_REQUEST_CODE -> { - val content = WidgetActivity.getOutput(data).toModel() ?: return - roomDetailViewModel.handle(RoomDetailAction.SendSticker(content)) - } + private val attachmentFileActivityResultLauncher = registerStartForActivityResult { + if (it.resultCode == Activity.RESULT_OK) { + attachmentsHelper.onImageResult(it.data) + } + } + + private val attachmentAudioActivityResultLauncher = registerStartForActivityResult { + if (it.resultCode == Activity.RESULT_OK) { + attachmentsHelper.onAudioResult(it.data) + } + } + + private val attachmentContactActivityResultLauncher = registerStartForActivityResult { + if (it.resultCode == Activity.RESULT_OK) { + attachmentsHelper.onContactResult(it.data) + } + } + + private val attachmentImageActivityResultLauncher = registerStartForActivityResult { + if (it.resultCode == Activity.RESULT_OK) { + attachmentsHelper.onImageResult(it.data) + } + } + + private val attachmentPhotoActivityResultLauncher = registerStartForActivityResult { + if (it.resultCode == Activity.RESULT_OK) { + attachmentsHelper.onPhotoResult() + } + } + + private val contentAttachmentActivityResultLauncher = registerStartForActivityResult { activityResult -> + val data = activityResult.data ?: return@registerStartForActivityResult + if (activityResult.resultCode == Activity.RESULT_OK) { + val sendData = AttachmentsPreviewActivity.getOutput(data) + val keepOriginalSize = AttachmentsPreviewActivity.getKeepOriginalSize(data) + roomDetailViewModel.handle(RoomDetailAction.SendMedia(sendData, !keepOriginalSize)) + } + } + + private val emojiActivityResultLauncher = registerStartForActivityResult { activityResult -> + if (activityResult.resultCode == Activity.RESULT_OK) { + val eventId = EmojiReactionPickerActivity.getOutputEventId(activityResult.data) + val reaction = EmojiReactionPickerActivity.getOutputReaction(activityResult.data) + if (eventId != null && reaction != null) { + roomDetailViewModel.handle(RoomDetailAction.SendReaction(eventId, reaction)) } } - // TODO why don't we call super here? - // super.onActivityResult(requestCode, resultCode, data) + } + + private val stickerActivityResultLauncher = registerStartForActivityResult { activityResult -> + val data = activityResult.data ?: return@registerStartForActivityResult + if (activityResult.resultCode == Activity.RESULT_OK) { + WidgetActivity.getOutput(data).toModel() + ?.let { content -> + roomDetailViewModel.handle(RoomDetailAction.SendSticker(content)) + } + } } // PRIVATE METHODS ***************************************************************************** @@ -1600,7 +1639,7 @@ class RoomDetailFragment @Inject constructor( openRoomMemberProfile(action.userId) } is EventSharedAction.AddReaction -> { - startActivityForResult(EmojiReactionPickerActivity.intent(requireContext(), action.eventId), REACTION_SELECT_REQUEST_CODE) + emojiActivityResultLauncher.launch(EmojiReactionPickerActivity.intent(requireContext(), action.eventId)) } is EventSharedAction.ViewReactions -> { ViewReactionsBottomSheet.newInstance(roomDetailArgs.roomId, action.messageInformationData) @@ -1827,11 +1866,11 @@ class RoomDetailFragment @Inject constructor( private fun launchAttachmentProcess(type: AttachmentTypeSelectorView.Type) { when (type) { - AttachmentTypeSelectorView.Type.CAMERA -> attachmentsHelper.openCamera(this) - AttachmentTypeSelectorView.Type.FILE -> attachmentsHelper.selectFile(this) - AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(this) - AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(this) - AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(this) + AttachmentTypeSelectorView.Type.CAMERA -> attachmentsHelper.openCamera(requireContext(), attachmentPhotoActivityResultLauncher) + AttachmentTypeSelectorView.Type.FILE -> attachmentsHelper.selectFile(attachmentFileActivityResultLauncher) + AttachmentTypeSelectorView.Type.GALLERY -> attachmentsHelper.selectGallery(attachmentImageActivityResultLauncher) + AttachmentTypeSelectorView.Type.AUDIO -> attachmentsHelper.selectAudio(attachmentAudioActivityResultLauncher) + AttachmentTypeSelectorView.Type.CONTACT -> attachmentsHelper.selectContact(attachmentContactActivityResultLauncher) AttachmentTypeSelectorView.Type.STICKER -> roomDetailViewModel.handle(RoomDetailAction.SelectStickerAttachment) }.exhaustive } @@ -1850,7 +1889,7 @@ class RoomDetailFragment @Inject constructor( } if (grouped.previewables.isNotEmpty()) { val intent = AttachmentsPreviewActivity.newIntent(requireContext(), AttachmentsPreviewArgs(grouped.previewables)) - startActivityForResult(intent, AttachmentsPreviewActivity.REQUEST_CODE) + contentAttachmentActivityResultLauncher.launch(intent) } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/WidgetRequestCodes.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/widget/WidgetRequestCodes.kt deleted file mode 100644 index 5f0e6866db..0000000000 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/widget/WidgetRequestCodes.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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.app.features.home.room.detail.widget - -object WidgetRequestCodes { - const val STICKER_PICKER_REQUEST_CODE = 16000 - const val INTEGRATION_MANAGER_REQUEST_CODE = 16001 -} diff --git a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt index b4f0aabea5..8f3e11453e 100644 --- a/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/invite/InviteUsersToRoomActivity.kt @@ -112,6 +112,7 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity() { } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (allGranted(grantResults)) { if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) { doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) } diff --git a/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt b/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt index c619b4aa92..144b9739da 100644 --- a/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt @@ -133,7 +133,7 @@ class BigImageViewerActivity : VectorBaseActivity() { MultiPicker.REQUEST_CODE_TAKE_PHOTO -> { avatarCameraUri?.let { uri -> MultiPicker.get(MultiPicker.CAMERA) - .getTakenPhoto(this, requestCode, resultCode, uri) + .getTakenPhoto(this, uri) ?.let { onRoomAvatarSelected(it) } @@ -142,7 +142,7 @@ class BigImageViewerActivity : VectorBaseActivity() { MultiPicker.REQUEST_CODE_PICK_IMAGE -> { MultiPicker .get(MultiPicker.IMAGE) - .getSelectedFiles(this, requestCode, resultCode, data) + .getSelectedFiles(this, data) .firstOrNull()?.let { onRoomAvatarSelected(it) } @@ -154,6 +154,7 @@ class BigImageViewerActivity : VectorBaseActivity() { } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (allGranted(grantResults)) { when (requestCode) { PERMISSION_REQUEST_CODE_LAUNCH_CAMERA -> onAvatarTypeSelected(true) diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index 5ad600dfff..237fa4f65d 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -21,11 +21,11 @@ import android.content.Context import android.content.Intent import android.view.View import android.view.Window +import androidx.activity.result.ActivityResultLauncher import androidx.core.app.ActivityOptionsCompat import androidx.core.app.TaskStackBuilder import androidx.core.util.Pair import androidx.core.view.ViewCompat -import androidx.fragment.app.Fragment import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.error.fatalError @@ -45,7 +45,6 @@ import im.vector.app.features.home.room.detail.RoomDetailActivity import im.vector.app.features.home.room.detail.RoomDetailArgs import im.vector.app.features.home.room.detail.search.SearchActivity import im.vector.app.features.home.room.detail.search.SearchArgs -import im.vector.app.features.home.room.detail.widget.WidgetRequestCodes import im.vector.app.features.home.room.filtered.FilteredRoomsActivity import im.vector.app.features.invite.InviteUsersToRoomActivity import im.vector.app.features.media.AttachmentData @@ -266,21 +265,32 @@ class DefaultNavigator @Inject constructor( } } - override fun openTerms(fragment: Fragment, serviceType: TermsService.ServiceType, baseUrl: String, token: String?, requestCode: Int) { - val intent = ReviewTermsActivity.intent(fragment.requireContext(), serviceType, baseUrl, token) - fragment.startActivityForResult(intent, requestCode) + override fun openTerms(context: Context, + activityResultLauncher: ActivityResultLauncher, + serviceType: TermsService.ServiceType, + baseUrl: String, + token: String?) { + val intent = ReviewTermsActivity.intent(context, serviceType, baseUrl, token) + activityResultLauncher.launch(intent) } - override fun openStickerPicker(fragment: Fragment, roomId: String, widget: Widget, requestCode: Int) { + override fun openStickerPicker(context: Context, + activityResultLauncher: ActivityResultLauncher, + roomId: String, + widget: Widget) { val widgetArgs = widgetArgsBuilder.buildStickerPickerArgs(roomId, widget) - val intent = WidgetActivity.newIntent(fragment.requireContext(), widgetArgs) - fragment.startActivityForResult(intent, WidgetRequestCodes.STICKER_PICKER_REQUEST_CODE) + val intent = WidgetActivity.newIntent(context, widgetArgs) + activityResultLauncher.launch(intent) } - override fun openIntegrationManager(fragment: Fragment, roomId: String, integId: String?, screen: String?) { + override fun openIntegrationManager(context: Context, + activityResultLauncher: ActivityResultLauncher, + roomId: String, + integId: String?, + screen: String?) { val widgetArgs = widgetArgsBuilder.buildIntegrationManagerArgs(roomId, integId, screen) - val intent = WidgetActivity.newIntent(fragment.requireContext(), widgetArgs) - fragment.startActivityForResult(intent, WidgetRequestCodes.INTEGRATION_MANAGER_REQUEST_CODE) + val intent = WidgetActivity.newIntent(context, widgetArgs) + activityResultLauncher.launch(intent) } override fun openRoomWidget(context: Context, roomId: String, widget: Widget, options: Map?) { @@ -293,9 +303,11 @@ class DefaultNavigator @Inject constructor( } } - override fun openPinCode(fragment: Fragment, pinMode: PinMode, requestCode: Int) { - val intent = PinActivity.newIntent(fragment.requireContext(), PinArgs(pinMode)) - fragment.startActivityForResult(intent, requestCode) + override fun openPinCode(context: Context, + activityResultLauncher: ActivityResultLauncher, + pinMode: PinMode) { + val intent = PinActivity.newIntent(context, PinArgs(pinMode)) + activityResultLauncher.launch(intent) } override fun openPinCode(activity: Activity, pinMode: PinMode, requestCode: Int) { diff --git a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt index b2efb1e931..4344f918ce 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt @@ -18,18 +18,17 @@ package im.vector.app.features.navigation import android.app.Activity import android.content.Context +import android.content.Intent import android.view.View +import androidx.activity.result.ActivityResultLauncher import androidx.core.util.Pair -import androidx.fragment.app.Fragment import im.vector.app.features.crypto.recover.SetupMode -import im.vector.app.features.home.room.detail.widget.WidgetRequestCodes import im.vector.app.features.media.AttachmentData import im.vector.app.features.pin.PinActivity import im.vector.app.features.pin.PinMode import im.vector.app.features.roomdirectory.roompreview.RoomPreviewData import im.vector.app.features.settings.VectorSettingsActivity import im.vector.app.features.share.SharedData -import im.vector.app.features.terms.ReviewTermsActivity import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData import org.matrix.android.sdk.api.session.terms.TermsService @@ -84,22 +83,28 @@ interface Navigator { fun openBigImageViewer(activity: Activity, sharedElement: View?, matrixItem: MatrixItem) - fun openPinCode(fragment: Fragment, pinMode: PinMode, requestCode: Int = PinActivity.PIN_REQUEST_CODE) + fun openPinCode(context: Context, + activityResultLauncher: ActivityResultLauncher, + pinMode: PinMode) fun openPinCode(activity: Activity, pinMode: PinMode, requestCode: Int = PinActivity.PIN_REQUEST_CODE) - fun openTerms(fragment: Fragment, + fun openTerms(context: Context, + activityResultLauncher: ActivityResultLauncher, serviceType: TermsService.ServiceType, baseUrl: String, - token: String?, - requestCode: Int = ReviewTermsActivity.TERMS_REQUEST_CODE) + token: String?) - fun openStickerPicker(fragment: Fragment, + fun openStickerPicker(context: Context, + activityResultLauncher: ActivityResultLauncher, roomId: String, - widget: Widget, - requestCode: Int = WidgetRequestCodes.STICKER_PICKER_REQUEST_CODE) + widget: Widget) - fun openIntegrationManager(fragment: Fragment, roomId: String, integId: String?, screen: String?) + fun openIntegrationManager(context: Context, + activityResultLauncher: ActivityResultLauncher, + roomId: String, + integId: String?, + screen: String?) fun openRoomWidget(context: Context, roomId: String, widget: Widget, options: Map? = null) diff --git a/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt b/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt index 616da791d3..563f9c65fa 100644 --- a/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt @@ -19,7 +19,7 @@ package im.vector.app.features.qrcode import android.app.Activity import android.content.Intent import android.os.Bundle -import androidx.fragment.app.Fragment +import androidx.activity.result.ActivityResultLauncher import com.google.zxing.BarcodeFormat import com.google.zxing.Result import com.google.zxing.ResultMetadataType @@ -82,8 +82,8 @@ class QrCodeScannerActivity : VectorBaseActivity() { activity.startActivityForResult(Intent(activity, QrCodeScannerActivity::class.java), requestCode) } - fun startForResult(fragment: Fragment, requestCode: Int = QR_CODE_SCANNER_REQUEST_CODE) { - fragment.startActivityForResult(Intent(fragment.requireActivity(), QrCodeScannerActivity::class.java), requestCode) + fun startForResult(activity: Activity, activityResultLauncher: ActivityResultLauncher) { + activityResultLauncher.launch(Intent(activity, QrCodeScannerActivity::class.java)) } fun getResultText(data: Intent?): String? { diff --git a/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt b/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt index 4fe74c2bcc..25cb90d3a4 100644 --- a/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt @@ -212,10 +212,8 @@ class EmojiReactionPickerActivity : VectorBaseActivity(), return intent } - fun getOutput(data: Intent): Pair? { - val eventId = data.getStringExtra(EXTRA_EVENT_ID) ?: return null - val reaction = data.getStringExtra(EXTRA_REACTION_RESULT) ?: return null - return eventId to reaction - } + fun getOutputEventId(data: Intent?): String? = data?.getStringExtra(EXTRA_EVENT_ID) + + fun getOutputReaction(data: Intent?): String? = data?.getStringExtra(EXTRA_REACTION_RESULT) } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index a6e1fda793..82c16db5ee 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -42,6 +42,7 @@ import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.copyOnLongClick import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.extensions.setTextOrHide import im.vector.app.core.intent.getFilenameFromUri import im.vector.app.core.platform.VectorBaseFragment @@ -284,7 +285,7 @@ class RoomProfileFragment @Inject constructor( .show() } - private val takePhotoActivityResultLauncher = registerForPermissionsResult { allGranted -> + private val takePhotoPermissionActivityResultLauncher = registerForPermissionsResult { allGranted -> if (allGranted) { onAvatarTypeSelected(true) } @@ -293,11 +294,11 @@ class RoomProfileFragment @Inject constructor( private var avatarCameraUri: Uri? = null private fun onAvatarTypeSelected(isCamera: Boolean) { if (isCamera) { - if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), takePhotoActivityResultLauncher)) { - avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(this) + if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), takePhotoPermissionActivityResultLauncher)) { + avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(requireActivity(), takePhotoActivityResultLauncher) } } else { - MultiPicker.get(MultiPicker.IMAGE).single().startWith(this) + MultiPicker.get(MultiPicker.IMAGE).single().startWith(pickImageActivityResultLauncher) } } @@ -309,30 +310,37 @@ class RoomProfileFragment @Inject constructor( .start(requireContext(), this) } + private val takePhotoActivityResultLauncher = registerStartForActivityResult { activityResult -> + if (activityResult.resultCode == Activity.RESULT_OK) { + avatarCameraUri?.let { uri -> + MultiPicker.get(MultiPicker.CAMERA) + .getTakenPhoto(requireContext(), uri) + ?.let { + onRoomAvatarSelected(it) + } + } + } + } + + private val pickImageActivityResultLauncher = registerStartForActivityResult { activityResult -> + if (activityResult.resultCode == Activity.RESULT_OK) { + MultiPicker + .get(MultiPicker.IMAGE) + .getSelectedFiles(requireContext(), activityResult.data) + .firstOrNull()?.let { + onRoomAvatarSelected(it) + } + } + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK) { when (requestCode) { - MultiPicker.REQUEST_CODE_TAKE_PHOTO -> { - avatarCameraUri?.let { uri -> - MultiPicker.get(MultiPicker.CAMERA) - .getTakenPhoto(requireContext(), requestCode, resultCode, uri) - ?.let { - onRoomAvatarSelected(it) - } - } - } - MultiPicker.REQUEST_CODE_PICK_IMAGE -> { - MultiPicker - .get(MultiPicker.IMAGE) - .getSelectedFiles(requireContext(), requestCode, resultCode, data) - .firstOrNull()?.let { - onRoomAvatarSelected(it) - } - } UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) } BigImageViewerActivity.REQUEST_CODE -> data?.let { onAvatarCropped(it.data) } } } + // TODO super.onActivityResult(requestCode, resultCode, data) } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt index c1d8eb1abe..9928325289 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsGeneralFragment.kt @@ -41,6 +41,7 @@ import com.google.android.material.textfield.TextInputLayout import com.yalantis.ucrop.UCrop 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.intent.getFilenameFromUri import im.vector.app.core.platform.SimpleTextWatcher @@ -278,81 +279,38 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() { session.integrationManagerService().removeListener(integrationServiceListener) } + private val attachmentPhotoActivityResultLauncher = registerStartForActivityResult {activityResult -> + if (activityResult.resultCode == Activity.RESULT_OK) { + avatarCameraUri?.let { uri -> + MultiPicker.get(MultiPicker.CAMERA) + .getTakenPhoto(requireContext(), uri) + ?.let { + onAvatarSelected(it) + } + } + } + } + + private val attachmentImageActivityResultLauncher = registerStartForActivityResult {activityResult -> + val data = activityResult.data ?: return@registerStartForActivityResult + if (activityResult.resultCode == Activity.RESULT_OK) { + MultiPicker + .get(MultiPicker.IMAGE) + .getSelectedFiles(requireContext(), data) + .firstOrNull()?.let { + onAvatarSelected(it) + } + } + } + override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + @Suppress("DEPRECATION") super.onActivityResult(requestCode, resultCode, data) if (resultCode == Activity.RESULT_OK) { when (requestCode) { - REQUEST_NEW_PHONE_NUMBER -> refreshPhoneNumbersList() - REQUEST_PHONEBOOK_COUNTRY -> onPhonebookCountryUpdate(data) - MultiPicker.REQUEST_CODE_TAKE_PHOTO -> { - avatarCameraUri?.let { uri -> - MultiPicker.get(MultiPicker.CAMERA) - .getTakenPhoto(requireContext(), requestCode, resultCode, uri) - ?.let { - onAvatarSelected(it) - } - } - } - MultiPicker.REQUEST_CODE_PICK_IMAGE -> { - MultiPicker - .get(MultiPicker.IMAGE) - .getSelectedFiles(requireContext(), requestCode, resultCode, data) - .firstOrNull()?.let { - onAvatarSelected(it) - } - } - UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) } - /* TODO - VectorUtils.TAKE_IMAGE -> { - val thumbnailUri = VectorUtils.getThumbnailUriFromIntent(activity, data, session.mediaCache) - - if (null != thumbnailUri) { - displayLoadingView() - - val resource = ResourceUtils.openResource(activity, thumbnailUri, null) - - if (null != resource) { - session.mediaCache.uploadContent(resource.mContentStream, null, resource.mMimeType, null, object : MXMediaUploadListener() { - - override fun onUploadError(uploadId: String?, serverResponseCode: Int, serverErrorMessage: String?) { - activity?.runOnUiThread { onCommonDone(serverResponseCode.toString() + " : " + serverErrorMessage) } - } - - override fun onUploadComplete(uploadId: String?, contentUri: String?) { - activity?.runOnUiThread { - session.myUser.updateAvatarUrl(contentUri, object : MatrixCallback { - override fun onSuccess(info: Void?) { - onCommonDone(null) - refreshDisplay() - } - - override fun onNetworkError(e: Exception) { - onCommonDone(e.localizedMessage) - } - - override fun onMatrixError(e: MatrixError) { - if (MatrixError.M_CONSENT_NOT_GIVEN == e.errcode) { - activity?.runOnUiThread { - hideLoadingView() - (activity as VectorAppCompatActivity).consentNotGivenHelper.displayDialog(e) - } - } else { - onCommonDone(e.localizedMessage) - } - } - - override fun onUnexpectedError(e: Exception) { - onCommonDone(e.localizedMessage) - } - }) - } - } - }) - } - } - } - */ + // TODO Migrate this too + UCrop.REQUEST_CROP -> data?.let { onAvatarCropped(UCrop.getOutput(it)) } } } } @@ -400,10 +358,10 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() { private fun onAvatarTypeSelected(isCamera: Boolean) { if (isCamera) { if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), takePhotoActivityResultLauncher)) { - avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(this) + avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(requireActivity(), attachmentPhotoActivityResultLauncher) } } else { - MultiPicker.get(MultiPicker.IMAGE).single().startWith(this) + MultiPicker.get(MultiPicker.IMAGE).single().startWith(attachmentImageActivityResultLauncher) } } @@ -461,29 +419,10 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() { */ } - private fun onPhonebookCountryUpdate(data: Intent?) { - /* TODO - if (data != null && data.hasExtra(CountryPickerActivity.EXTRA_OUT_COUNTRY_NAME) - && data.hasExtra(CountryPickerActivity.EXTRA_OUT_COUNTRY_CODE)) { - val countryCode = data.getStringExtra(CountryPickerActivity.EXTRA_OUT_COUNTRY_CODE) - if (!TextUtils.equals(countryCode, PhoneNumberUtils.getCountryCode(activity))) { - PhoneNumberUtils.setCountryCode(activity, countryCode) - mContactPhonebookCountryPreference.summary = data.getStringExtra(CountryPickerActivity.EXTRA_OUT_COUNTRY_NAME) - } - } - */ - } - // ============================================================================================================== // Phone number management // ============================================================================================================== - /** - * Refresh phone number list - */ - private fun refreshPhoneNumbersList() { - } - /** * Update the password. */ @@ -643,9 +582,4 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() { }) } } - - companion object { - private const val REQUEST_NEW_PHONE_NUMBER = 456 - private const val REQUEST_PHONEBOOK_COUNTRY = 789 - } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPinFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPinFragment.kt index 4a6965618e..37465258f6 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPinFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPinFragment.kt @@ -16,14 +16,13 @@ package im.vector.app.features.settings -import android.content.Intent import androidx.lifecycle.lifecycleScope import androidx.preference.Preference import androidx.preference.SwitchPreference import im.vector.app.R +import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.features.navigation.Navigator import im.vector.app.features.notifications.NotificationDrawerManager -import im.vector.app.features.pin.PinActivity import im.vector.app.features.pin.PinCodeStore import im.vector.app.features.pin.PinMode import kotlinx.coroutines.launch @@ -67,17 +66,18 @@ class VectorSettingsPinFragment @Inject constructor( refreshPinCodeStatus() } } else { - navigator.openPinCode(this@VectorSettingsPinFragment, PinMode.CREATE) + navigator.openPinCode( + requireContext(), + pinActivityResultLauncher, + PinMode.CREATE + ) } true } } } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - if (requestCode == PinActivity.PIN_REQUEST_CODE) { - refreshPinCodeStatus() - } + private val pinActivityResultLauncher = registerStartForActivityResult { + refreshPinCodeStatus() } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt index b0ec7426a7..39120f1157 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -39,6 +39,7 @@ import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.dialogs.ExportKeysDialog import im.vector.app.core.extensions.queryExportKeys +import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.extensions.showPassword import im.vector.app.core.intent.ExternalIntentData import im.vector.app.core.intent.analyseIntent @@ -55,7 +56,6 @@ import im.vector.app.features.crypto.keysbackup.settings.KeysBackupManageActivit import im.vector.app.features.crypto.recover.BootstrapBottomSheet import im.vector.app.features.crypto.recover.SetupMode import im.vector.app.features.navigation.Navigator -import im.vector.app.features.pin.PinActivity import im.vector.app.features.pin.PinCodeStore import im.vector.app.features.pin.PinMode import im.vector.app.features.raw.wellknown.getElementWellknown @@ -320,48 +320,45 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( } } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - if (resultCode == Activity.RESULT_OK) { - when (requestCode) { - REQUEST_CODE_SAVE_MEGOLM_EXPORT -> { - val uri = data?.data - if (uri != null) { - activity?.let { activity -> - ExportKeysDialog().show(activity, object : ExportKeysDialog.ExportKeyDialogListener { - override fun onPassphrase(passphrase: String) { - displayLoadingView() + private val saveMegolmStartForActivityResult = registerStartForActivityResult { + val uri = it.data?.data ?: return@registerStartForActivityResult + if (it.resultCode == Activity.RESULT_OK) + ExportKeysDialog().show(requireActivity(), object : ExportKeysDialog.ExportKeyDialogListener { + override fun onPassphrase(passphrase: String) { + displayLoadingView() - KeysExporter(session) - .export(requireContext(), - passphrase, - uri, - object : MatrixCallback { - override fun onSuccess(data: Boolean) { - if (data) { - requireActivity().toast(getString(R.string.encryption_exported_successfully)) - } else { - requireActivity().toast(getString(R.string.unexpected_error)) - } - hideLoadingView() - } + KeysExporter(session) + .export(requireContext(), + passphrase, + uri, + object : MatrixCallback { + override fun onSuccess(data: Boolean) { + if (data) { + requireActivity().toast(getString(R.string.encryption_exported_successfully)) + } else { + requireActivity().toast(getString(R.string.unexpected_error)) + } + hideLoadingView() + } - override fun onFailure(failure: Throwable) { - onCommonDone(failure.localizedMessage) - } - }) - } - }) - } - } + override fun onFailure(failure: Throwable) { + onCommonDone(failure.localizedMessage) + } + }) } - PinActivity.PIN_REQUEST_CODE -> { - doOpenPinCodePreferenceScreen() - } - REQUEST_E2E_FILE_REQUEST_CODE -> { - importKeys(data) - } - } + }) + } + + private val pinActivityResultLauncher = registerStartForActivityResult { + if (it.resultCode == Activity.RESULT_OK) { + doOpenPinCodePreferenceScreen() + } + } + + private val importKeysActivityResultLauncher = registerStartForActivityResult { + val data = it.data ?: return@registerStartForActivityResult + if (it.resultCode == Activity.RESULT_OK) { + importKeys(data) } } @@ -369,7 +366,10 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( lifecycleScope.launchWhenResumed { val hasPinCode = pinCodeStore.hasEncodedPin() if (hasPinCode) { - navigator.openPinCode(this@VectorSettingsSecurityPrivacyFragment, PinMode.AUTH) + navigator.openPinCode( + requireContext(), + pinActivityResultLauncher, + PinMode.AUTH) } else { doOpenPinCodePreferenceScreen() } @@ -391,7 +391,7 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( } exportPref.onPreferenceClickListener = Preference.OnPreferenceClickListener { - queryExportKeys(activeSessionHolder.getSafeActiveSession()?.myUserId ?: "", REQUEST_CODE_SAVE_MEGOLM_EXPORT) + queryExportKeys(activeSessionHolder.getSafeActiveSession()?.myUserId ?: "", saveMegolmStartForActivityResult) true } @@ -406,7 +406,12 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( */ @SuppressLint("NewApi") private fun importKeys() { - activity?.let { openFileSelection(it, this, false, REQUEST_E2E_FILE_REQUEST_CODE) } + openFileSelection( + requireActivity(), + importKeysActivityResultLauncher, + false, + 0 + ) } /** @@ -414,12 +419,7 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( * * @param intent the intent result */ - private fun importKeys(intent: Intent?) { - // sanity check - if (null == intent) { - return - } - + private fun importKeys(intent: Intent) { val sharedDataItems = analyseIntent(intent) val thisActivity = activity @@ -605,9 +605,4 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( } }) } - - companion object { - private const val REQUEST_E2E_FILE_REQUEST_CODE = 123 - private const val REQUEST_CODE_SAVE_MEGOLM_EXPORT = 124 - } } diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt index a75cfa4304..5e776fb17a 100644 --- a/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt +++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareFragment.kt @@ -33,6 +33,7 @@ import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.features.attachments.AttachmentsHelper import im.vector.app.features.attachments.preview.AttachmentsPreviewActivity @@ -118,20 +119,16 @@ class IncomingShareFragment @Inject constructor( private fun handleEditMediaBeforeSending(event: IncomingShareViewEvents.EditMediaBeforeSending) { val intent = AttachmentsPreviewActivity.newIntent(requireContext(), AttachmentsPreviewArgs(event.contentAttachmentData)) - startActivityForResult(intent, AttachmentsPreviewActivity.REQUEST_CODE) + attachmentPreviewActivityResultLauncher.launch(intent) } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - val hasBeenHandled = attachmentsHelper.onActivityResult(requestCode, resultCode, data) - if (!hasBeenHandled && resultCode == Activity.RESULT_OK && data != null) { - when (requestCode) { - AttachmentsPreviewActivity.REQUEST_CODE -> { - val sendData = AttachmentsPreviewActivity.getOutput(data) - val keepOriginalSize = AttachmentsPreviewActivity.getKeepOriginalSize(data) - viewModel.handle(IncomingShareAction.UpdateSharedData(SharedData.Attachments(sendData))) - viewModel.handle(IncomingShareAction.ShareMedia(keepOriginalSize)) - } - } + private val attachmentPreviewActivityResultLauncher = registerStartForActivityResult { + val data = it.data ?: return@registerStartForActivityResult + if (it.resultCode == Activity.RESULT_OK) { + val sendData = AttachmentsPreviewActivity.getOutput(data) + val keepOriginalSize = AttachmentsPreviewActivity.getKeepOriginalSize(data) + viewModel.handle(IncomingShareAction.UpdateSharedData(SharedData.Attachments(sendData))) + viewModel.handle(IncomingShareAction.ShareMedia(keepOriginalSize)) } } diff --git a/vector/src/main/java/im/vector/app/features/terms/ReviewTermsActivity.kt b/vector/src/main/java/im/vector/app/features/terms/ReviewTermsActivity.kt index 4fea176249..9d1f10f39e 100644 --- a/vector/src/main/java/im/vector/app/features/terms/ReviewTermsActivity.kt +++ b/vector/src/main/java/im/vector/app/features/terms/ReviewTermsActivity.kt @@ -73,7 +73,6 @@ class ReviewTermsActivity : SimpleFragmentActivity() { } companion object { - const val TERMS_REQUEST_CODE = 15000 private const val EXTRA_INFO = "EXTRA_INFO" fun intent(context: Context, serviceType: TermsService.ServiceType, baseUrl: String, token: String?): Intent { diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetFragment.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetFragment.kt index 37ae89ab36..2d3e5e4e69 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/WidgetFragment.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetFragment.kt @@ -37,11 +37,10 @@ import com.airbnb.mvrx.args import com.airbnb.mvrx.withState import org.matrix.android.sdk.api.session.terms.TermsService import im.vector.app.R +import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.openUrlInExternalBrowser -import im.vector.app.features.home.room.detail.widget.WidgetRequestCodes -import im.vector.app.features.terms.ReviewTermsActivity import im.vector.app.features.webview.WebViewEventListener import im.vector.app.features.widgets.webview.clearAfterWidget import im.vector.app.features.widgets.webview.setupForWidget @@ -86,19 +85,18 @@ class WidgetFragment @Inject constructor() : VectorBaseFragment(), WebViewEventL viewModel.handle(WidgetAction.LoadFormattedUrl) } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - when (requestCode) { - ReviewTermsActivity.TERMS_REQUEST_CODE -> { - Timber.v("On terms results") - if (resultCode == Activity.RESULT_OK) { - viewModel.handle(WidgetAction.OnTermsReviewed) - } else { - vectorBaseActivity.finish() - } - } - WidgetRequestCodes.INTEGRATION_MANAGER_REQUEST_CODE -> { - viewModel.handle(WidgetAction.LoadFormattedUrl) - } + private val termsActivityResultLauncher = registerStartForActivityResult { + Timber.v("On terms results") + if (it.resultCode == Activity.RESULT_OK) { + viewModel.handle(WidgetAction.OnTermsReviewed) + } else { + vectorBaseActivity.finish() + } + } + + private val integrationManagerActivityResultLauncher = registerStartForActivityResult { + if (it.resultCode == Activity.RESULT_OK) { + viewModel.handle(WidgetAction.LoadFormattedUrl) } } @@ -146,7 +144,12 @@ class WidgetFragment @Inject constructor() : VectorBaseFragment(), WebViewEventL override fun onOptionsItemSelected(item: MenuItem): Boolean = withState(viewModel) { state -> when (item.itemId) { R.id.action_edit -> { - navigator.openIntegrationManager(this, state.roomId, state.widgetId, state.widgetKind.screenId) + navigator.openIntegrationManager( + requireContext(), + integrationManagerActivityResultLauncher, + state.roomId, + state.widgetId, + state.widgetKind.screenId) return@withState true } R.id.action_delete -> { @@ -261,7 +264,8 @@ class WidgetFragment @Inject constructor() : VectorBaseFragment(), WebViewEventL private fun displayTerms(displayTerms: WidgetViewEvents.DisplayTerms) { navigator.openTerms( - fragment = this, + context = requireContext(), + activityResultLauncher = termsActivityResultLauncher, serviceType = TermsService.ServiceType.IntegrationManager, baseUrl = displayTerms.url, token = displayTerms.token @@ -287,7 +291,8 @@ class WidgetFragment @Inject constructor() : VectorBaseFragment(), WebViewEventL private fun displayIntegrationManager(event: WidgetViewEvents.DisplayIntegrationManager) { navigator.openIntegrationManager( - fragment = this, + context = requireContext(), + activityResultLauncher = integrationManagerActivityResultLauncher, roomId = fragmentArgs.roomId, integId = event.integId, screen = event.integType diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt index 756aa3cbac..2fe984dfc7 100644 --- a/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt +++ b/vector/src/main/java/im/vector/app/features/workers/signout/SignOutBottomSheetDialogFragment.kt @@ -18,7 +18,6 @@ package im.vector.app.features.workers.signout import android.app.Activity import android.app.Dialog -import android.content.Intent import android.os.Bundle import android.view.View import android.view.ViewGroup @@ -39,6 +38,7 @@ import im.vector.app.R import im.vector.app.core.di.ScreenComponent import im.vector.app.core.dialogs.ExportKeysDialog import im.vector.app.core.extensions.queryExportKeys +import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment import im.vector.app.features.crypto.keysbackup.setup.KeysBackupSetupActivity import im.vector.app.features.crypto.recover.BootstrapBottomSheet @@ -77,9 +77,6 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), companion object { fun newInstance() = SignOutBottomSheetDialogFragment() - - private const val EXPORT_REQ = 0 - private const val QUERY_EXPORT_KEYS = 1 } init { @@ -130,12 +127,12 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), exportManuallyButton.action = { withState(viewModel) { state -> - queryExportKeys(state.userId, QUERY_EXPORT_KEYS) + queryExportKeys(state.userId, manualExportKeysActivityResultLauncher) } } setupMegolmBackupButton.action = { - startActivityForResult(KeysBackupSetupActivity.intent(requireContext(), true), EXPORT_REQ) + setupBackupActivityResultLauncher.launch(KeysBackupSetupActivity.intent(requireContext(), true)) } viewModel.observeViewEvents { @@ -289,26 +286,26 @@ class SignOutBottomSheetDialogFragment : VectorBaseBottomSheetDialogFragment(), return dialog } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - - if (resultCode == Activity.RESULT_OK) { - if (requestCode == QUERY_EXPORT_KEYS) { - val uri = data?.data - if (resultCode == Activity.RESULT_OK && uri != null) { - activity?.let { activity -> - ExportKeysDialog().show(activity, object : ExportKeysDialog.ExportKeyDialogListener { - override fun onPassphrase(passphrase: String) { - viewModel.handle(SignoutCheckViewModel.Actions.ExportKeys(passphrase, uri)) - } - }) - } - } - } else if (requestCode == EXPORT_REQ) { - if (data?.getBooleanExtra(KeysBackupSetupActivity.MANUAL_EXPORT, false) == true) { - viewModel.handle(SignoutCheckViewModel.Actions.KeySuccessfullyManuallyExported) + private val manualExportKeysActivityResultLauncher = registerStartForActivityResult { + if (it.resultCode == Activity.RESULT_OK) { + val uri = it.data?.data + if (uri != null) { + activity?.let { activity -> + ExportKeysDialog().show(activity, object : ExportKeysDialog.ExportKeyDialogListener { + override fun onPassphrase(passphrase: String) { + viewModel.handle(SignoutCheckViewModel.Actions.ExportKeys(passphrase, uri)) + } + }) } } } } + + private val setupBackupActivityResultLauncher = registerStartForActivityResult { + if (it.resultCode == Activity.RESULT_OK) { + if (it.data?.getBooleanExtra(KeysBackupSetupActivity.MANUAL_EXPORT, false) == true) { + viewModel.handle(SignoutCheckViewModel.Actions.KeySuccessfullyManuallyExported) + } + } + } }