From e61fc1a935c6928b5383b794a39f8b861b93db8d Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Sat, 10 Jul 2021 10:45:37 +0200 Subject: [PATCH 01/13] Fix unread messages marker being hidden in collapsed membership item Scenario: the last read event in a chat is a membership change. After that, at least two new membership changes were added, followed by normal messages. Due to the membership changes being collapsed by default, in this scenario the read marker would not show, since in the loop, we would overwrite the appendReadMarker with the value for the last eventId of the merged item, instead of showing it if any of the items matched. --- .../timeline/helper/TimelineControllerInterceptorHelper.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt index 389dd15413..3121f031e2 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/TimelineControllerInterceptorHelper.kt @@ -73,7 +73,8 @@ class TimelineControllerInterceptorHelper(private val positionOfReadMarker: KMut } epoxyModel.getEventIds().forEach { eventId -> adapterPositionMapping[eventId] = index - appendReadMarker = epoxyModel.canAppendReadMarker() && eventId == firstUnreadEventId && atLeastOneVisibleItemsBeforeReadMarker + appendReadMarker = appendReadMarker + || (epoxyModel.canAppendReadMarker() && eventId == firstUnreadEventId && atLeastOneVisibleItemsBeforeReadMarker) } } if (epoxyModel is DaySeparatorItem) { From a52d1e4312a4165c0e5ca2ecaf003134dcbd07d6 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Sat, 10 Jul 2021 11:07:21 +0200 Subject: [PATCH 02/13] Add changelog.d/3655.bugfix --- changelog.d/3655.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/3655.bugfix diff --git a/changelog.d/3655.bugfix b/changelog.d/3655.bugfix new file mode 100644 index 0000000000..c7e805ab84 --- /dev/null +++ b/changelog.d/3655.bugfix @@ -0,0 +1 @@ +Fix unread messages marker being hidden in collapsed membership item From 995f9d87bb8252beaa6dd17480d8d534bdc05a75 Mon Sep 17 00:00:00 2001 From: TheWayOfTheWarrior <87245511+TheWayOfTheWarrior@users.noreply.github.com> Date: Sat, 10 Jul 2021 22:17:17 +0200 Subject: [PATCH 03/13] Typo in InitializeCrossSigningTask.kt Typo in comment. Was "userSigningKey" instead of "selfSigningKey". --- .../sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt index f8a8354e48..1d40e5defd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/InitializeCrossSigningTask.kt @@ -97,7 +97,7 @@ internal class DefaultInitializeCrossSigningTask @Inject constructor( Timber.v("## CrossSigning - sskPublicKey:$sskPublicKey") - // Sign userSigningKey with master + // Sign selfSigningKey with master val signedSSK = CryptoCrossSigningKey.Builder(userId, KeyUsage.SELF_SIGNING) .key(sskPublicKey) .build() From 9aa37dfbe9e58555e7af30cdb4d9ace5edc9a757 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Sun, 11 Jul 2021 11:11:41 +0200 Subject: [PATCH 04/13] Fix top row of emoji reaction picker on small displays Emojis were not showing if not enough space, so allow scrolling there. --- changelog.d/3661.bugfix | 1 + .../src/main/res/layout/activity_emoji_reaction_picker.xml | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 changelog.d/3661.bugfix diff --git a/changelog.d/3661.bugfix b/changelog.d/3661.bugfix new file mode 100644 index 0000000000..9ca6b7d188 --- /dev/null +++ b/changelog.d/3661.bugfix @@ -0,0 +1 @@ +Ensure reaction emoji picker tabs look fine on small displays diff --git a/vector/src/main/res/layout/activity_emoji_reaction_picker.xml b/vector/src/main/res/layout/activity_emoji_reaction_picker.xml index 3e8f604d74..2e95fe7f7e 100644 --- a/vector/src/main/res/layout/activity_emoji_reaction_picker.xml +++ b/vector/src/main/res/layout/activity_emoji_reaction_picker.xml @@ -39,8 +39,10 @@ + android:layout_height="40dp" + app:tabPaddingEnd="0dp" + app:tabPaddingStart="0dp" /> - \ No newline at end of file + From cca9a8007c26a2a8893fb1bf91e93a945c608423 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 12 Jul 2021 21:18:01 +0200 Subject: [PATCH 05/13] Use new permission request management I do not know why all has not been migrated in the previous rework --- .../app/features/debug/DebugMenuActivity.kt | 12 +- .../vector/app/core/utils/PermissionsTools.kt | 215 +++--------------- .../attachments/AttachmentTypeSelectorView.kt | 2 +- .../app/features/call/VectorCallActivity.kt | 13 +- .../createdirect/CreateDirectRoomActivity.kt | 37 ++- .../home/room/detail/RoomDetailFragment.kt | 2 +- .../invite/InviteUsersToRoomActivity.kt | 17 +- 7 files changed, 61 insertions(+), 237 deletions(-) diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt index 539091c7ce..aa871c5fb5 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt @@ -30,9 +30,8 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO -import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA -import im.vector.app.core.utils.allGranted import im.vector.app.core.utils.checkPermissions +import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.core.utils.toast import im.vector.app.databinding.ActivityDebugMenuBinding import im.vector.app.features.debug.sas.DebugSasEmojiActivity @@ -48,7 +47,6 @@ import im.vector.lib.ui.styles.debug.DebugVectorButtonStylesLightActivity import im.vector.lib.ui.styles.debug.DebugVectorTextViewDarkActivity import im.vector.lib.ui.styles.debug.DebugVectorTextViewLightActivity import org.matrix.android.sdk.internal.crypto.verification.qrcode.toQrCodeData - import timber.log.Timber import javax.inject.Inject @@ -217,15 +215,13 @@ class DebugMenuActivity : VectorBaseActivity() { } private fun scanQRCode() { - if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) { + if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, permissionCamera)) { doScanQRCode() } } - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - - if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA && allGranted(grantResults)) { + private val permissionCamera = registerForPermissionsResult { allGranted -> + if (allGranted) { doScanQRCode() } } diff --git a/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt b/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt index b6566b4ce9..879a53f0ae 100644 --- a/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt +++ b/vector/src/main/java/im/vector/app/core/utils/PermissionsTools.kt @@ -22,6 +22,7 @@ import android.content.Context import android.content.pm.PackageManager import android.os.Build import android.widget.Toast +import androidx.activity.ComponentActivity import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.StringRes @@ -33,44 +34,16 @@ import im.vector.app.R import im.vector.app.core.platform.VectorBaseActivity import timber.log.Timber -// Android M permission request code management -private const val PERMISSIONS_GRANTED = true -private const val PERMISSIONS_DENIED = !PERMISSIONS_GRANTED - -// Permission bit -private const val PERMISSION_BYPASSED = 0x0 -const val PERMISSION_CAMERA = 0x1 -private const val PERMISSION_WRITE_EXTERNAL_STORAGE = 0x1 shl 1 -private const val PERMISSION_RECORD_AUDIO = 0x1 shl 2 -private const val PERMISSION_READ_CONTACTS = 0x1 shl 3 -private const val PERMISSION_READ_EXTERNAL_STORAGE = 0x1 shl 4 - // Permissions sets -const val PERMISSIONS_FOR_AUDIO_IP_CALL = PERMISSION_RECORD_AUDIO -const val PERMISSIONS_FOR_VIDEO_IP_CALL = PERMISSION_CAMERA or PERMISSION_RECORD_AUDIO -const val PERMISSIONS_FOR_TAKING_PHOTO = PERMISSION_CAMERA -const val PERMISSIONS_FOR_MEMBERS_SEARCH = PERMISSION_READ_CONTACTS -const val PERMISSIONS_FOR_MEMBER_DETAILS = PERMISSION_READ_CONTACTS -const val PERMISSIONS_FOR_ROOM_AVATAR = PERMISSION_CAMERA -const val PERMISSIONS_FOR_VIDEO_RECORDING = PERMISSION_CAMERA or PERMISSION_RECORD_AUDIO -const val PERMISSIONS_FOR_WRITING_FILES = PERMISSION_WRITE_EXTERNAL_STORAGE -const val PERMISSIONS_FOR_READING_FILES = PERMISSION_READ_EXTERNAL_STORAGE -const val PERMISSIONS_FOR_PICKING_CONTACT = PERMISSION_READ_CONTACTS +val PERMISSIONS_FOR_AUDIO_IP_CALL = listOf(Manifest.permission.RECORD_AUDIO) +val PERMISSIONS_FOR_VIDEO_IP_CALL = listOf(Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA) +val PERMISSIONS_FOR_TAKING_PHOTO = listOf(Manifest.permission.CAMERA) +val PERMISSIONS_FOR_MEMBERS_SEARCH = listOf(Manifest.permission.READ_CONTACTS) +val PERMISSIONS_FOR_ROOM_AVATAR = listOf(Manifest.permission.CAMERA) +val PERMISSIONS_FOR_WRITING_FILES = listOf(Manifest.permission.WRITE_EXTERNAL_STORAGE) +val PERMISSIONS_FOR_PICKING_CONTACT = listOf(Manifest.permission.READ_CONTACTS) -const val PERMISSIONS_EMPTY = PERMISSION_BYPASSED - -// Request code to ask permission to the system (arbitrary values) -const val PERMISSION_REQUEST_CODE = 567 -const val PERMISSION_REQUEST_CODE_LAUNCH_CAMERA = 568 -const val PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_CAMERA = 569 -const val PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_VIDEO_CAMERA = 570 -const val PERMISSION_REQUEST_CODE_AUDIO_CALL = 571 -const val PERMISSION_REQUEST_CODE_VIDEO_CALL = 572 -const val PERMISSION_REQUEST_CODE_CHANGE_AVATAR = 574 -const val PERMISSION_REQUEST_CODE_DOWNLOAD_FILE = 575 -const val PERMISSION_REQUEST_CODE_PICK_ATTACHMENT = 576 -const val PERMISSION_REQUEST_CODE_INCOMING_URI = 577 -const val PERMISSION_REQUEST_CODE_READ_CONTACTS = 579 +val PERMISSIONS_EMPTY = emptyList() /** * Log the used permissions statuses. @@ -97,38 +70,16 @@ fun logPermissionStatuses(context: Context) { } } -fun Fragment.registerForPermissionsResult(allGranted: (Boolean) -> Unit): ActivityResultLauncher> { +fun ComponentActivity.registerForPermissionsResult(allGranted: (Boolean) -> Unit): ActivityResultLauncher> { return registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result -> allGranted.invoke(result.keys.all { result[it] == true }) } } -/** - * See [.checkPermissions] - * - * @param permissionsToBeGrantedBitMap - * @param activity - * @return true if the permissions are granted (synchronous flow), false otherwise (asynchronous flow) - */ -fun checkPermissions(permissionsToBeGrantedBitMap: Int, - activity: Activity, - requestCode: Int, - @StringRes rationaleMessage: Int = 0): Boolean { - return checkPermissions(permissionsToBeGrantedBitMap, activity, null, requestCode, rationaleMessage) -} - -/** - * See [.checkPermissions] - * - * @param permissionsToBeGrantedBitMap - * @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, - activity: Activity, - activityResultLauncher: ActivityResultLauncher>, - @StringRes rationaleMessage: Int = 0): Boolean { - return checkPermissions(permissionsToBeGrantedBitMap, activity, activityResultLauncher, 0, rationaleMessage) +fun Fragment.registerForPermissionsResult(allGranted: (Boolean) -> Unit): ActivityResultLauncher> { + return registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result -> + allGranted.invoke(result.keys.all { result[it] == true }) + } } /** @@ -144,78 +95,29 @@ fun checkPermissions(permissionsToBeGrantedBitMap: Int, * If a permission was already denied by the user, a popup is displayed to * explain why vector needs the corresponding permission. * - * @param permissionsToBeGrantedBitMap the permissions bit map to be granted - * @param activity the calling Activity that is requesting the permissions (or fragment parent) - * @param activityResultLauncher from the calling fragment that is requesting the permissions + * @param permissionsToBeGranted the permissions to be granted + * @param activity the calling Activity that is requesting the permissions (or fragment parent) + * @param activityResultLauncher from the calling fragment/Activity 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, - activityResultLauncher: ActivityResultLauncher>?, - requestCode: Int, - @StringRes rationaleMessage: Int -): Boolean { +fun checkPermissions(permissionsToBeGranted: List, + activity: Activity, + activityResultLauncher: ActivityResultLauncher>, + @StringRes rationaleMessage: Int = 0): Boolean { var isPermissionGranted = false // sanity check - if (PERMISSIONS_EMPTY == permissionsToBeGrantedBitMap) { + if (permissionsToBeGranted.isEmpty()) { isPermissionGranted = true - } else if (PERMISSIONS_FOR_AUDIO_IP_CALL != permissionsToBeGrantedBitMap - && PERMISSIONS_FOR_VIDEO_IP_CALL != permissionsToBeGrantedBitMap - && PERMISSIONS_FOR_TAKING_PHOTO != permissionsToBeGrantedBitMap - && PERMISSIONS_FOR_MEMBERS_SEARCH != permissionsToBeGrantedBitMap - && PERMISSIONS_FOR_MEMBER_DETAILS != permissionsToBeGrantedBitMap - && PERMISSIONS_FOR_ROOM_AVATAR != permissionsToBeGrantedBitMap - && PERMISSIONS_FOR_VIDEO_RECORDING != permissionsToBeGrantedBitMap - && PERMISSIONS_FOR_WRITING_FILES != permissionsToBeGrantedBitMap - && PERMISSIONS_FOR_READING_FILES != permissionsToBeGrantedBitMap) { - Timber.w("## checkPermissions(): permissions to be granted are not supported") - isPermissionGranted = false } else { - val permissionListAlreadyDenied = ArrayList() - val permissionsListToBeGranted = ArrayList() + val permissionListAlreadyDenied = mutableListOf() + val permissionsListToBeGranted = mutableListOf() var isRequestPermissionRequired = false - // retrieve the permissions to be granted according to the request code bit map - if (PERMISSION_CAMERA == permissionsToBeGrantedBitMap and PERMISSION_CAMERA) { - val permissionType = Manifest.permission.CAMERA - isRequestPermissionRequired = isRequestPermissionRequired or - updatePermissionsToBeGranted(activity, permissionListAlreadyDenied, permissionsListToBeGranted, permissionType) - } - - if (PERMISSION_RECORD_AUDIO == permissionsToBeGrantedBitMap and PERMISSION_RECORD_AUDIO) { - val permissionType = Manifest.permission.RECORD_AUDIO - isRequestPermissionRequired = isRequestPermissionRequired or - updatePermissionsToBeGranted(activity, permissionListAlreadyDenied, permissionsListToBeGranted, permissionType) - } - - if (PERMISSION_WRITE_EXTERNAL_STORAGE == permissionsToBeGrantedBitMap and PERMISSION_WRITE_EXTERNAL_STORAGE) { - val permissionType = Manifest.permission.WRITE_EXTERNAL_STORAGE - isRequestPermissionRequired = isRequestPermissionRequired or - updatePermissionsToBeGranted(activity, permissionListAlreadyDenied, permissionsListToBeGranted, permissionType) - } - - if (PERMISSION_READ_EXTERNAL_STORAGE == permissionsToBeGrantedBitMap and PERMISSION_READ_EXTERNAL_STORAGE) { - val permissionType = Manifest.permission.READ_EXTERNAL_STORAGE - isRequestPermissionRequired = isRequestPermissionRequired or - updatePermissionsToBeGranted(activity, permissionListAlreadyDenied, permissionsListToBeGranted, permissionType) - } - - // the contact book access is requested for any android platforms - // for android M, we use the system preferences - // for android < M, we use a dedicated settings - if (PERMISSION_READ_CONTACTS == permissionsToBeGrantedBitMap and PERMISSION_READ_CONTACTS) { - val permissionType = Manifest.permission.READ_CONTACTS - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - isRequestPermissionRequired = isRequestPermissionRequired or - updatePermissionsToBeGranted(activity, permissionListAlreadyDenied, permissionsListToBeGranted, permissionType) - } else { - // TODO uncomment - /*if (!ContactsManager.getInstance().isContactBookAccessRequested) { - isRequestPermissionRequired = true - permissionsListToBeGranted.add(permissionType) - }*/ + // retrieve the permissions to be granted according to the permission list + permissionsToBeGranted.forEach { permission -> + if (updatePermissionsToBeGranted(activity, permissionListAlreadyDenied, permissionsListToBeGranted, permission)) { + isRequestPermissionRequired = true } } @@ -228,53 +130,14 @@ 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()) { - activityResultLauncher - ?.launch(permissionsListToBeGranted.toTypedArray()) - ?: run { - ActivityCompat.requestPermissions(activity, permissionsListToBeGranted.toTypedArray(), requestCode) - } + activityResultLauncher.launch(permissionsListToBeGranted.toTypedArray()) } } .show() } else { // some permissions are not granted, ask permissions if (isRequestPermissionRequired) { - val permissionsArrayToBeGranted = permissionsListToBeGranted.toTypedArray() - - // for android < M, we use a custom dialog to request the contacts book access. - if (permissionsListToBeGranted.contains(Manifest.permission.READ_CONTACTS) - && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - TODO() - /* - MaterialAlertDialogBuilder(activity) - .setIcon(android.R.drawable.ic_dialog_info) - .setTitle(R.string.permissions_rationale_popup_title) - .setMessage(R.string.permissions_msg_contacts_warning_other_androids) - // gives the contacts book access - .setPositiveButton(R.string.yes) { _, _ -> - ContactsManager.getInstance().setIsContactBookAccessAllowed(true) - fragment?.requestPermissions(permissionsArrayToBeGranted, requestCode) - ?: run { - ActivityCompat.requestPermissions(activity, permissionsArrayToBeGranted, requestCode) - } - } - // or reject it - .setNegativeButton(R.string.no) { _, _ -> - ContactsManager.getInstance().setIsContactBookAccessAllowed(false) - fragment?.requestPermissions(permissionsArrayToBeGranted, requestCode) - ?: run { - ActivityCompat.requestPermissions(activity, permissionsArrayToBeGranted, requestCode) - } - } - .show() - */ - } else { - activityResultLauncher - ?.launch(permissionsArrayToBeGranted) - ?: run { - ActivityCompat.requestPermissions(activity, permissionsArrayToBeGranted, requestCode) - } - } + activityResultLauncher.launch(permissionsListToBeGranted.toTypedArray()) } else { // permissions were granted, start now. isPermissionGranted = true @@ -320,21 +183,3 @@ private fun updatePermissionsToBeGranted(activity: Activity, } return isRequestPermissionRequested } - -/** - * Return true if all permissions are granted, false if not or if permission request has been cancelled - */ -fun allGranted(grantResults: IntArray): Boolean { - if (grantResults.isEmpty()) { - // A cancellation occurred - return false - } - - var granted = true - - grantResults.forEach { - granted = granted && PackageManager.PERMISSION_GRANTED == it - } - - return granted -} diff --git a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorView.kt b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorView.kt index cf7270225d..c0d4669108 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorView.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/AttachmentTypeSelectorView.kt @@ -206,7 +206,7 @@ class AttachmentTypeSelectorView(context: Context, /** * The all possible types to pick with their required permissions. */ - enum class Type(val permissionsBit: Int) { + enum class Type(val permissions: List) { CAMERA(PERMISSIONS_FOR_TAKING_PHOTO), GALLERY(PERMISSIONS_EMPTY), FILE(PERMISSIONS_EMPTY), 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 21939bd42b..cbe2733134 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 @@ -40,8 +40,8 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.utils.PERMISSIONS_FOR_AUDIO_IP_CALL import im.vector.app.core.utils.PERMISSIONS_FOR_VIDEO_IP_CALL -import im.vector.app.core.utils.allGranted import im.vector.app.core.utils.checkPermissions +import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.databinding.ActivityCallBinding import im.vector.app.features.call.dialpad.CallDialPadBottomSheet import im.vector.app.features.call.dialpad.DialPadFragment @@ -139,11 +139,11 @@ class VectorCallActivity : VectorBaseActivity(), CallContro .disposeOnDestroy() if (callArgs.isVideoCall) { - if (checkPermissions(PERMISSIONS_FOR_VIDEO_IP_CALL, this, CAPTURE_PERMISSION_REQUEST_CODE, R.string.permissions_rationale_msg_camera_and_audio)) { + if (checkPermissions(PERMISSIONS_FOR_VIDEO_IP_CALL, this, permissionCameraLauncher, R.string.permissions_rationale_msg_camera_and_audio)) { start() } } else { - if (checkPermissions(PERMISSIONS_FOR_AUDIO_IP_CALL, this, CAPTURE_PERMISSION_REQUEST_CODE, R.string.permissions_rationale_msg_record_audio)) { + if (checkPermissions(PERMISSIONS_FOR_AUDIO_IP_CALL, this, permissionCameraLauncher, R.string.permissions_rationale_msg_record_audio)) { start() } } @@ -298,9 +298,8 @@ class VectorCallActivity : VectorBaseActivity(), CallContro } } - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - if (requestCode == CAPTURE_PERMISSION_REQUEST_CODE && allGranted(grantResults)) { + private val permissionCameraLauncher = registerForPermissionsResult { allGranted -> + if (allGranted) { start() } else { // TODO display something @@ -370,8 +369,6 @@ class VectorCallActivity : VectorBaseActivity(), CallContro } companion object { - - private const val CAPTURE_PERMISSION_REQUEST_CODE = 1 private const val EXTRA_MODE = "EXTRA_MODE" private const val FRAGMENT_DIAL_PAD_TAG = "FRAGMENT_DIAL_PAD_TAG" 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 4aa5f023c4..c2d323ff64 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 @@ -38,11 +38,9 @@ import im.vector.app.core.platform.SimpleFragmentActivity import im.vector.app.core.platform.WaitingViewData import im.vector.app.core.utils.PERMISSIONS_FOR_MEMBERS_SEARCH import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO -import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA -import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_READ_CONTACTS -import im.vector.app.core.utils.allGranted import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.onPermissionDeniedSnackbar +import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.features.contactsbook.ContactsBookFragment import im.vector.app.features.contactsbook.ContactsBookViewModel import im.vector.app.features.contactsbook.ContactsBookViewState @@ -52,7 +50,6 @@ import im.vector.app.features.userdirectory.UserListSharedAction import im.vector.app.features.userdirectory.UserListSharedActionViewModel import im.vector.app.features.userdirectory.UserListViewModel import im.vector.app.features.userdirectory.UserListViewState - import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.session.room.failure.CreateRoomFailure import java.net.HttpURLConnection @@ -111,35 +108,31 @@ class CreateDirectRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fac } private fun openAddByQrCode() { - if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA, 0)) { + if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, permissionCameraLauncher, 0)) { addFragment(R.id.container, CreateDirectRoomByQrCodeFragment::class.java) } } private fun openPhoneBook() { // Check permission first - if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH, - this, - PERMISSION_REQUEST_CODE_READ_CONTACTS, - 0)) { + if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH, this, permissionReadContactLauncher, 0)) { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) } } - 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) } - } else if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA) { - addFragment(R.id.container, CreateDirectRoomByQrCodeFragment::class.java) - } + private val permissionReadContactLauncher = registerForPermissionsResult { allGranted -> + if (allGranted) { + doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) } } else { - if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA) { - onPermissionDeniedSnackbar(R.string.permissions_denied_qr_code) - } else if (requestCode == PERMISSION_REQUEST_CODE_READ_CONTACTS) { - onPermissionDeniedSnackbar(R.string.permissions_denied_add_contact) - } + onPermissionDeniedSnackbar(R.string.permissions_denied_add_contact) + } + } + + private val permissionCameraLauncher = registerForPermissionsResult { allGranted -> + if (allGranted) { + addFragment(R.id.container, CreateDirectRoomByQrCodeFragment::class.java) + } else { + onPermissionDeniedSnackbar(R.string.permissions_denied_qr_code) } } 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 c4caff025b..f7fd4026b0 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 @@ -1990,7 +1990,7 @@ class RoomDetailFragment @Inject constructor( } override fun onTypeSelected(type: AttachmentTypeSelectorView.Type) { - if (checkPermissions(type.permissionsBit, requireActivity(), typeSelectedActivityResultLauncher)) { + if (checkPermissions(type.permissions, requireActivity(), typeSelectedActivityResultLauncher)) { launchAttachmentProcess(type) } else { attachmentsHelper.pendingType = type 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 142498e031..0f3e3c57d2 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 @@ -33,9 +33,8 @@ import im.vector.app.core.extensions.addFragmentToBackstack import im.vector.app.core.platform.SimpleFragmentActivity import im.vector.app.core.platform.WaitingViewData import im.vector.app.core.utils.PERMISSIONS_FOR_MEMBERS_SEARCH -import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_READ_CONTACTS -import im.vector.app.core.utils.allGranted import im.vector.app.core.utils.checkPermissions +import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.core.utils.toast import im.vector.app.features.contactsbook.ContactsBookFragment import im.vector.app.features.contactsbook.ContactsBookViewModel @@ -118,20 +117,14 @@ class InviteUsersToRoomActivity : SimpleFragmentActivity(), UserListViewModel.Fa private fun openPhoneBook() { // Check permission first - if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH, - this, - PERMISSION_REQUEST_CODE_READ_CONTACTS, - 0)) { + if (checkPermissions(PERMISSIONS_FOR_MEMBERS_SEARCH, this, permissionContactLauncher)) { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) } } - 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) } - } + private val permissionContactLauncher = registerForPermissionsResult { allGranted -> + if (allGranted) { + doOnPostResume { addFragmentToBackstack(R.id.container, ContactsBookFragment::class.java) } } else { Toast.makeText(baseContext, R.string.missing_permissions_error, Toast.LENGTH_SHORT).show() } From fabbd6da9e4597acdd80b1d4bb94bb84e42afcdf Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 12 Jul 2021 21:33:15 +0200 Subject: [PATCH 06/13] Add action to see permission status in the DebugActivity --- vector/src/debug/AndroidManifest.xml | 1 + .../app/features/debug/DebugMenuActivity.kt | 8 ++ .../features/debug/DebugPermissionActivity.kt | 91 +++++++++++++++++++ .../debug/res/layout/activity_debug_menu.xml | 6 ++ .../res/layout/activity_debug_permission.xml | 68 ++++++++++++++ vector/src/debug/res/values/strings.xml | 4 + .../vector/app/core/utils/PermissionsTools.kt | 32 ++----- 7 files changed, 185 insertions(+), 25 deletions(-) create mode 100644 vector/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt create mode 100644 vector/src/debug/res/layout/activity_debug_permission.xml create mode 100644 vector/src/debug/res/values/strings.xml diff --git a/vector/src/debug/AndroidManifest.xml b/vector/src/debug/AndroidManifest.xml index b97384099f..8ffcec6bc1 100644 --- a/vector/src/debug/AndroidManifest.xml +++ b/vector/src/debug/AndroidManifest.xml @@ -4,6 +4,7 @@ + diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt index aa871c5fb5..5d94f312b2 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt @@ -20,15 +20,20 @@ import android.app.Activity import android.app.NotificationChannel import android.app.NotificationManager import android.content.Intent +import android.content.pm.PackageManager import android.os.Build +import androidx.core.app.ActivityCompat import androidx.core.app.NotificationCompat import androidx.core.app.Person +import androidx.core.content.ContextCompat import androidx.core.content.getSystemService +import com.google.android.material.dialog.MaterialAlertDialogBuilder import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.core.utils.PERMISSIONS_ALL import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.registerForPermissionsResult @@ -113,6 +118,9 @@ class DebugMenuActivity : VectorBaseActivity() { } views.debugTestCrash.setOnClickListener { testCrash() } views.debugScanQrCode.setOnClickListener { scanQRCode() } + views.debugPermission.setOnClickListener { + startActivity(Intent(this, DebugPermissionActivity::class.java)) + } } private fun renderQrCode(text: String) { diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt new file mode 100644 index 0000000000..660e6c4312 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt @@ -0,0 +1,91 @@ +/* + * Copyright 2019 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.debug + +import android.content.pm.PackageManager +import android.os.Build +import android.widget.Toast +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import im.vector.app.R +import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.core.utils.PERMISSIONS_ALL +import im.vector.app.core.utils.checkPermissions +import im.vector.app.core.utils.registerForPermissionsResult +import im.vector.app.databinding.ActivityDebugPermissionBinding +import timber.log.Timber + +class DebugPermissionActivity : VectorBaseActivity() { + + override fun getBinding() = ActivityDebugPermissionBinding.inflate(layoutInflater) + + override fun initUiAndData() { + views.status.setOnClickListener { refresh() } + + listOf( + views.audio, + views.camera, + views.write, + views.read, + views.contact + ).forEach { button -> + button.setOnClickListener { + checkPermissions(listOf(button.text.toString()), this, launcher, R.string.debug_rationale) + } + } + } + + private val launcher = registerForPermissionsResult { allGranted -> + if (allGranted) { + Toast.makeText(this, "All granted", Toast.LENGTH_SHORT).show() + } else { + Toast.makeText(this, "Denied", Toast.LENGTH_SHORT).show() + } + } + + override fun onResume() { + super.onResume() + refresh() + } + + private fun refresh() { + views.status.text = getStatus() + } + + private fun getStatus(): String { + return buildString { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + Timber.v("## debugPermission() : log the permissions status used by the app") + PERMISSIONS_ALL.forEach { permission -> + append("[$permission] : ") + if (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(this@DebugPermissionActivity, permission)) { + append("PERMISSION_GRANTED") + } else { + append("PERMISSION_DENIED") + } + append(" show rational: ") + append(ActivityCompat.shouldShowRequestPermissionRationale(this@DebugPermissionActivity, permission)) + append("\n") + } + } else { + append("Before M!") + } + append("\n") + append("(Click to refresh)") + } + } +} diff --git a/vector/src/debug/res/layout/activity_debug_menu.xml b/vector/src/debug/res/layout/activity_debug_menu.xml index a83f61266a..976fe625e5 100644 --- a/vector/src/debug/res/layout/activity_debug_menu.xml +++ b/vector/src/debug/res/layout/activity_debug_menu.xml @@ -152,6 +152,12 @@ android:layout_height="200dp" tools:src="@drawable/ic_qr_code_add" /> +