registerForActivityResult has to be called at Fragment creation

This commit is contained in:
Benoit Marty 2020-10-07 11:52:29 +02:00 committed by Benoit Marty
parent a7f034f500
commit 05950ec1c8
5 changed files with 101 additions and 91 deletions

View File

@ -22,6 +22,7 @@ import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
@ -95,6 +96,12 @@ fun logPermissionStatuses(context: Context) {
}
}
fun Fragment.registerForPermissionsResult(allGranted: (Boolean) -> Unit): ActivityResultLauncher<Array<String>> {
return registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
allGranted.invoke(result.keys.all { result[it] == true })
}
}
/**
* See [.checkPermissions]
*
@ -106,21 +113,21 @@ fun checkPermissions(permissionsToBeGrantedBitMap: Int,
activity: Activity,
requestCode: Int,
@StringRes rationaleMessage: Int = 0): Boolean {
return checkPermissions(permissionsToBeGrantedBitMap, activity, null, null, requestCode, rationaleMessage)
return checkPermissions(permissionsToBeGrantedBitMap, activity, null, requestCode, rationaleMessage)
}
/**
* See [.checkPermissions]
*
* @param permissionsToBeGrantedBitMap
* @param fragment
* @param activityResultLauncher from the calling fragment that is requesting the permissions
* @return true if the permissions are granted (synchronous flow), false otherwise (asynchronous flow)
*/
fun checkPermissions(permissionsToBeGrantedBitMap: Int,
fragment: Fragment,
@StringRes rationaleMessage: Int = 0,
allGranted: (Boolean) -> Unit): Boolean {
return checkPermissions(permissionsToBeGrantedBitMap, fragment.activity, fragment, allGranted, 0, rationaleMessage)
activity: Activity,
activityResultLauncher: ActivityResultLauncher<Array<String>>,
@StringRes rationaleMessage: Int = 0): Boolean {
return checkPermissions(permissionsToBeGrantedBitMap, activity, activityResultLauncher, 0, rationaleMessage)
}
/**
@ -138,23 +145,19 @@ fun checkPermissions(permissionsToBeGrantedBitMap: Int,
*
* @param permissionsToBeGrantedBitMap the permissions bit map to be granted
* @param activity the calling Activity that is requesting the permissions (or fragment parent)
* @param fragment the calling fragment that is requesting the permissions
* @param activityResultLauncher from the calling fragment that is requesting the permissions
* @return true if the permissions are granted (synchronous flow), false otherwise (asynchronous flow)
*/
private fun checkPermissions(permissionsToBeGrantedBitMap: Int,
activity: Activity?,
fragment: Fragment?,
allGranted: ((Boolean) -> Unit)?,
activity: Activity,
activityResultLauncher: ActivityResultLauncher<Array<String>>?,
requestCode: Int,
@StringRes rationaleMessage: Int
): Boolean {
var isPermissionGranted = false
// sanity check
if (null == activity) {
Timber.w("## checkPermissions(): invalid input data")
isPermissionGranted = false
} else if (PERMISSIONS_EMPTY == permissionsToBeGrantedBitMap) {
if (PERMISSIONS_EMPTY == permissionsToBeGrantedBitMap) {
isPermissionGranted = true
} else if (PERMISSIONS_FOR_AUDIO_IP_CALL != permissionsToBeGrantedBitMap
&& PERMISSIONS_FOR_VIDEO_IP_CALL != permissionsToBeGrantedBitMap
@ -224,9 +227,7 @@ private fun checkPermissions(permissionsToBeGrantedBitMap: Int,
.setOnCancelListener { Toast.makeText(activity, R.string.missing_permissions_warning, Toast.LENGTH_SHORT).show() }
.setPositiveButton(R.string.ok) { _, _ ->
if (permissionsListToBeGranted.isNotEmpty()) {
fragment?.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
allGranted?.invoke(result.keys.all { result[it] == true })
}
activityResultLauncher
?.launch(permissionsListToBeGranted.toTypedArray())
?: run {
ActivityCompat.requestPermissions(activity, permissionsListToBeGranted.toTypedArray(), requestCode)
@ -267,9 +268,7 @@ private fun checkPermissions(permissionsToBeGrantedBitMap: Int,
.show()
*/
} else {
fragment?.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result ->
allGranted?.invoke(result.keys.all { result[it] == true })
}
activityResultLauncher
?.launch(permissionsArrayToBeGranted)
?: run {
ActivityCompat.requestPermissions(activity, permissionsArrayToBeGranted, requestCode)

View File

@ -28,6 +28,7 @@ import im.vector.app.core.extensions.configureWith
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
import im.vector.app.core.utils.checkPermissions
import im.vector.app.core.utils.registerForPermissionsResult
import im.vector.app.features.crypto.verification.VerificationAction
import im.vector.app.features.crypto.verification.VerificationBottomSheetViewModel
import im.vector.app.features.qrcode.QrCodeScannerActivity
@ -73,12 +74,14 @@ class VerificationChooseMethodFragment @Inject constructor(
state.pendingRequest.invoke()?.transactionId ?: ""))
}
override fun openCamera() {
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this) { allGranted ->
private val openCameraActivityResultLauncher = registerForPermissionsResult { allGranted ->
if (allGranted) {
doOpenQRCodeScanner()
}
}) {
}
override fun openCamera() {
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), openCameraActivityResultLauncher)) {
doOpenQRCodeScanner()
}
}

View File

@ -99,6 +99,7 @@ import im.vector.app.core.utils.createJSonViewerStyleProvider
import im.vector.app.core.utils.createUIHandler
import im.vector.app.core.utils.isValidUrl
import im.vector.app.core.utils.openUrlInExternalBrowser
import im.vector.app.core.utils.registerForPermissionsResult
import im.vector.app.core.utils.saveMedia
import im.vector.app.core.utils.shareMedia
import im.vector.app.core.utils.toast
@ -782,40 +783,35 @@ class RoomDetailFragment @Inject constructor(
}
}
private val startCallActivityResultLauncher = registerForPermissionsResult { allGranted ->
if (allGranted) {
(roomDetailViewModel.pendingAction as? RoomDetailAction.StartCall)?.let {
roomDetailViewModel.pendingAction = null
roomDetailViewModel.handle(it)
}
} else {
context?.toast(R.string.permissions_action_not_performed_missing_permissions)
cleanUpAfterPermissionNotGranted()
}
}
private fun safeStartCall2(isVideoCall: Boolean) {
val startCallAction = RoomDetailAction.StartCall(isVideoCall)
roomDetailViewModel.pendingAction = startCallAction
if (isVideoCall) {
if (checkPermissions(PERMISSIONS_FOR_VIDEO_IP_CALL,
this,
R.string.permissions_rationale_msg_camera_and_audio) { allGranted ->
if (allGranted) {
(roomDetailViewModel.pendingAction as? RoomDetailAction.StartCall)?.let {
roomDetailViewModel.pendingAction = null
roomDetailViewModel.handle(it)
}
} else {
context?.toast(R.string.permissions_action_not_performed_missing_permissions)
cleanUpAfterPermissionNotGranted()
}
}) {
requireActivity(),
startCallActivityResultLauncher,
R.string.permissions_rationale_msg_camera_and_audio)) {
roomDetailViewModel.pendingAction = null
roomDetailViewModel.handle(startCallAction)
}
} else {
if (checkPermissions(PERMISSIONS_FOR_AUDIO_IP_CALL,
this,
R.string.permissions_rationale_msg_record_audio) { allGranted ->
if (allGranted) {
(roomDetailViewModel.pendingAction as? RoomDetailAction.StartCall)?.let {
roomDetailViewModel.pendingAction = null
roomDetailViewModel.handle(it)
}
} else {
context?.toast(R.string.permissions_action_not_performed_missing_permissions)
cleanUpAfterPermissionNotGranted()
}
}) {
requireActivity(),
startCallActivityResultLauncher,
R.string.permissions_rationale_msg_record_audio)) {
roomDetailViewModel.pendingAction = null
roomDetailViewModel.handle(startCallAction)
}
@ -1005,6 +1001,18 @@ class RoomDetailFragment @Inject constructor(
}
}
private val writingFileActivityResultLauncher = registerForPermissionsResult { allGranted ->
if (allGranted) {
val pendingUri = roomDetailViewModel.pendingUri
if (pendingUri != null) {
roomDetailViewModel.pendingUri = null
sendUri(pendingUri)
}
} else {
cleanUpAfterPermissionNotGranted()
}
}
private fun setupComposer() {
autoCompleter.setup(composerLayout.composerEditText)
@ -1037,17 +1045,7 @@ class RoomDetailFragment @Inject constructor(
override fun onRichContentSelected(contentUri: Uri): Boolean {
// We need WRITE_EXTERNAL permission
return if (checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this@RoomDetailFragment) { allGranted ->
if (allGranted) {
val pendingUri = roomDetailViewModel.pendingUri
if (pendingUri != null) {
roomDetailViewModel.pendingUri = null
sendUri(pendingUri)
}
} else {
cleanUpAfterPermissionNotGranted()
}
}) {
return if (checkPermissions(PERMISSIONS_FOR_WRITING_FILES, requireActivity(), writingFileActivityResultLauncher)) {
sendUri(contentUri)
} else {
roomDetailViewModel.pendingUri = contentUri
@ -1556,9 +1554,7 @@ class RoomDetailFragment @Inject constructor(
)
}
private fun onSaveActionClicked(action: EventSharedAction.Save) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
&& !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this) { allGranted ->
private val saveActionActivityResultLauncher = registerForPermissionsResult { allGranted ->
if (allGranted) {
sharedActionViewModel.pendingAction?.let {
handleActions(it)
@ -1567,7 +1563,11 @@ class RoomDetailFragment @Inject constructor(
} else {
cleanUpAfterPermissionNotGranted()
}
}) {
}
private fun onSaveActionClicked(action: EventSharedAction.Save) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
&& !checkPermissions(PERMISSIONS_FOR_WRITING_FILES, requireActivity(), saveActionActivityResultLauncher)) {
sharedActionViewModel.pendingAction = action
return
}
@ -1805,8 +1805,7 @@ class RoomDetailFragment @Inject constructor(
// AttachmentTypeSelectorView.Callback
override fun onTypeSelected(type: AttachmentTypeSelectorView.Type) {
if (checkPermissions(type.permissionsBit, this) { allGranted ->
private val typeSelectedActivityResultLauncher = registerForPermissionsResult { allGranted ->
if (allGranted) {
val pendingType = attachmentsHelper.pendingType
if (pendingType != null) {
@ -1816,7 +1815,10 @@ class RoomDetailFragment @Inject constructor(
} else {
cleanUpAfterPermissionNotGranted()
}
}) {
}
override fun onTypeSelected(type: AttachmentTypeSelectorView.Type) {
if (checkPermissions(type.permissionsBit, requireActivity(), typeSelectedActivityResultLauncher)) {
launchAttachmentProcess(type)
} else {
attachmentsHelper.pendingType = type

View File

@ -48,6 +48,7 @@ import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
import im.vector.app.core.utils.checkPermissions
import im.vector.app.core.utils.copyToClipboard
import im.vector.app.core.utils.registerForPermissionsResult
import im.vector.app.core.utils.startSharePlainTextIntent
import im.vector.app.features.crypto.util.toImageRes
import im.vector.app.features.home.AvatarRenderer
@ -283,14 +284,16 @@ class RoomProfileFragment @Inject constructor(
.show()
}
private var avatarCameraUri: Uri? = null
private fun onAvatarTypeSelected(isCamera: Boolean) {
if (isCamera) {
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this) { allGranted ->
private val takePhotoActivityResultLauncher = registerForPermissionsResult { allGranted ->
if (allGranted) {
onAvatarTypeSelected(true)
}
}) {
}
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)
}
} else {

View File

@ -51,6 +51,7 @@ import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
import im.vector.app.core.utils.TextUtils
import im.vector.app.core.utils.checkPermissions
import im.vector.app.core.utils.getSizeOfFiles
import im.vector.app.core.utils.registerForPermissionsResult
import im.vector.app.core.utils.toast
import im.vector.app.features.MainActivity
import im.vector.app.features.MainActivityArgs
@ -390,13 +391,15 @@ class VectorSettingsGeneralFragment : VectorSettingsBaseFragment() {
}.show()
}
private fun onAvatarTypeSelected(isCamera: Boolean) {
if (isCamera) {
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this) { allGranted ->
private val takePhotoActivityResultLauncher = registerForPermissionsResult { allGranted ->
if (allGranted) {
onAvatarTypeSelected(true)
}
}) {
}
private fun onAvatarTypeSelected(isCamera: Boolean) {
if (isCamera) {
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), takePhotoActivityResultLauncher)) {
avatarCameraUri = MultiPicker.get(MultiPicker.CAMERA).startWithExpectingFile(this)
}
} else {