Merge pull request #2152 from vector-im/feature/various_fixes
Redcude requested permission to access file on the phone
This commit is contained in:
commit
34d2c3d391
|
@ -7,6 +7,7 @@ Features ✨:
|
||||||
Improvements 🙌:
|
Improvements 🙌:
|
||||||
- Add "show password" in import Megolm keys dialog
|
- Add "show password" in import Megolm keys dialog
|
||||||
- Visually disable call buttons in menu and prohibit calling when permissions are insufficient (#2112)
|
- Visually disable call buttons in menu and prohibit calling when permissions are insufficient (#2112)
|
||||||
|
- Better management of requested permissions (#2048)
|
||||||
- Add a setting to show timestamp for all messages (#2123)
|
- Add a setting to show timestamp for all messages (#2123)
|
||||||
- Use cache for user color
|
- Use cache for user color
|
||||||
- Allow using an outdated homeserver, at user's risk (#1972)
|
- Allow using an outdated homeserver, at user's risk (#1972)
|
||||||
|
|
|
@ -30,8 +30,6 @@ import androidx.fragment.app.Fragment
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
private const val LOG_TAG = "PermissionUtils"
|
|
||||||
|
|
||||||
// Android M permission request code management
|
// Android M permission request code management
|
||||||
private const val PERMISSIONS_GRANTED = true
|
private const val PERMISSIONS_GRANTED = true
|
||||||
private const val PERMISSIONS_DENIED = !PERMISSIONS_GRANTED
|
private const val PERMISSIONS_DENIED = !PERMISSIONS_GRANTED
|
||||||
|
@ -42,16 +40,18 @@ const val PERMISSION_CAMERA = 0x1
|
||||||
private const val PERMISSION_WRITE_EXTERNAL_STORAGE = 0x1 shl 1
|
private const val PERMISSION_WRITE_EXTERNAL_STORAGE = 0x1 shl 1
|
||||||
private const val PERMISSION_RECORD_AUDIO = 0x1 shl 2
|
private const val PERMISSION_RECORD_AUDIO = 0x1 shl 2
|
||||||
private const val PERMISSION_READ_CONTACTS = 0x1 shl 3
|
private const val PERMISSION_READ_CONTACTS = 0x1 shl 3
|
||||||
|
private const val PERMISSION_READ_EXTERNAL_STORAGE = 0x1 shl 4
|
||||||
|
|
||||||
// Permissions sets
|
// Permissions sets
|
||||||
const val PERMISSIONS_FOR_AUDIO_IP_CALL = PERMISSION_RECORD_AUDIO
|
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_VIDEO_IP_CALL = PERMISSION_CAMERA or PERMISSION_RECORD_AUDIO
|
||||||
const val PERMISSIONS_FOR_TAKING_PHOTO = PERMISSION_CAMERA or PERMISSION_WRITE_EXTERNAL_STORAGE
|
const val PERMISSIONS_FOR_TAKING_PHOTO = PERMISSION_CAMERA
|
||||||
const val PERMISSIONS_FOR_MEMBERS_SEARCH = PERMISSION_READ_CONTACTS
|
const val PERMISSIONS_FOR_MEMBERS_SEARCH = PERMISSION_READ_CONTACTS
|
||||||
const val PERMISSIONS_FOR_MEMBER_DETAILS = PERMISSION_READ_CONTACTS
|
const val PERMISSIONS_FOR_MEMBER_DETAILS = PERMISSION_READ_CONTACTS
|
||||||
const val PERMISSIONS_FOR_ROOM_AVATAR = PERMISSION_CAMERA
|
const val PERMISSIONS_FOR_ROOM_AVATAR = PERMISSION_CAMERA
|
||||||
const val PERMISSIONS_FOR_VIDEO_RECORDING = PERMISSION_CAMERA or PERMISSION_RECORD_AUDIO
|
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_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
|
const val PERMISSIONS_FOR_PICKING_CONTACT = PERMISSION_READ_CONTACTS
|
||||||
|
|
||||||
const val PERMISSIONS_EMPTY = PERMISSION_BYPASSED
|
const val PERMISSIONS_EMPTY = PERMISSION_BYPASSED
|
||||||
|
@ -67,7 +67,6 @@ const val PERMISSION_REQUEST_CODE_CHANGE_AVATAR = 574
|
||||||
const val PERMISSION_REQUEST_CODE_DOWNLOAD_FILE = 575
|
const val PERMISSION_REQUEST_CODE_DOWNLOAD_FILE = 575
|
||||||
const val PERMISSION_REQUEST_CODE_PICK_ATTACHMENT = 576
|
const val PERMISSION_REQUEST_CODE_PICK_ATTACHMENT = 576
|
||||||
const val PERMISSION_REQUEST_CODE_INCOMING_URI = 577
|
const val PERMISSION_REQUEST_CODE_INCOMING_URI = 577
|
||||||
const val PERMISSION_REQUEST_CODE_PREVIEW_FRAGMENT = 578
|
|
||||||
const val PERMISSION_REQUEST_CODE_READ_CONTACTS = 579
|
const val PERMISSION_REQUEST_CODE_READ_CONTACTS = 579
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,6 +78,7 @@ fun logPermissionStatuses(context: Context) {
|
||||||
Manifest.permission.CAMERA,
|
Manifest.permission.CAMERA,
|
||||||
Manifest.permission.RECORD_AUDIO,
|
Manifest.permission.RECORD_AUDIO,
|
||||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||||
|
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||||
Manifest.permission.READ_CONTACTS)
|
Manifest.permission.READ_CONTACTS)
|
||||||
|
|
||||||
Timber.v("## logPermissionStatuses() : log the permissions status used by the app")
|
Timber.v("## logPermissionStatuses() : log the permissions status used by the app")
|
||||||
|
@ -145,7 +145,7 @@ private fun checkPermissions(permissionsToBeGrantedBitMap: Int,
|
||||||
fragment: Fragment?,
|
fragment: Fragment?,
|
||||||
requestCode: Int,
|
requestCode: Int,
|
||||||
@StringRes rationaleMessage: Int
|
@StringRes rationaleMessage: Int
|
||||||
): Boolean {
|
): Boolean {
|
||||||
var isPermissionGranted = false
|
var isPermissionGranted = false
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
|
@ -161,7 +161,8 @@ private fun checkPermissions(permissionsToBeGrantedBitMap: Int,
|
||||||
&& PERMISSIONS_FOR_MEMBER_DETAILS != permissionsToBeGrantedBitMap
|
&& PERMISSIONS_FOR_MEMBER_DETAILS != permissionsToBeGrantedBitMap
|
||||||
&& PERMISSIONS_FOR_ROOM_AVATAR != permissionsToBeGrantedBitMap
|
&& PERMISSIONS_FOR_ROOM_AVATAR != permissionsToBeGrantedBitMap
|
||||||
&& PERMISSIONS_FOR_VIDEO_RECORDING != permissionsToBeGrantedBitMap
|
&& PERMISSIONS_FOR_VIDEO_RECORDING != permissionsToBeGrantedBitMap
|
||||||
&& PERMISSIONS_FOR_WRITING_FILES != permissionsToBeGrantedBitMap) {
|
&& PERMISSIONS_FOR_WRITING_FILES != permissionsToBeGrantedBitMap
|
||||||
|
&& PERMISSIONS_FOR_READING_FILES != permissionsToBeGrantedBitMap) {
|
||||||
Timber.w("## checkPermissions(): permissions to be granted are not supported")
|
Timber.w("## checkPermissions(): permissions to be granted are not supported")
|
||||||
isPermissionGranted = false
|
isPermissionGranted = false
|
||||||
} else {
|
} else {
|
||||||
|
@ -188,6 +189,12 @@ private fun checkPermissions(permissionsToBeGrantedBitMap: Int,
|
||||||
updatePermissionsToBeGranted(activity, permissionListAlreadyDenied, permissionsListToBeGranted, permissionType)
|
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
|
// the contact book access is requested for any android platforms
|
||||||
// for android M, we use the system preferences
|
// for android M, we use the system preferences
|
||||||
// for android < M, we use a dedicated settings
|
// for android < M, we use a dedicated settings
|
||||||
|
|
|
@ -42,7 +42,6 @@ import im.vector.app.core.extensions.getMeasurements
|
||||||
import im.vector.app.core.utils.PERMISSIONS_EMPTY
|
import im.vector.app.core.utils.PERMISSIONS_EMPTY
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_PICKING_CONTACT
|
import im.vector.app.core.utils.PERMISSIONS_FOR_PICKING_CONTACT
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_WRITING_FILES
|
|
||||||
import im.vector.app.features.attachments.AttachmentTypeSelectorView.Callback
|
import im.vector.app.features.attachments.AttachmentTypeSelectorView.Callback
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
|
@ -215,10 +214,10 @@ class AttachmentTypeSelectorView(context: Context,
|
||||||
*/
|
*/
|
||||||
enum class Type(val permissionsBit: Int) {
|
enum class Type(val permissionsBit: Int) {
|
||||||
CAMERA(PERMISSIONS_FOR_TAKING_PHOTO),
|
CAMERA(PERMISSIONS_FOR_TAKING_PHOTO),
|
||||||
GALLERY(PERMISSIONS_FOR_WRITING_FILES),
|
GALLERY(PERMISSIONS_EMPTY),
|
||||||
FILE(PERMISSIONS_FOR_WRITING_FILES),
|
FILE(PERMISSIONS_EMPTY),
|
||||||
STICKER(PERMISSIONS_EMPTY),
|
STICKER(PERMISSIONS_EMPTY),
|
||||||
AUDIO(PERMISSIONS_FOR_WRITING_FILES),
|
AUDIO(PERMISSIONS_EMPTY),
|
||||||
CONTACT(PERMISSIONS_FOR_PICKING_CONTACT)
|
CONTACT(PERMISSIONS_FOR_PICKING_CONTACT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,17 +42,13 @@ import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.resources.ColorProvider
|
import im.vector.app.core.resources.ColorProvider
|
||||||
import im.vector.app.core.utils.OnSnapPositionChangeListener
|
import im.vector.app.core.utils.OnSnapPositionChangeListener
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_WRITING_FILES
|
|
||||||
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_PREVIEW_FRAGMENT
|
|
||||||
import im.vector.app.core.utils.SnapOnScrollListener
|
import im.vector.app.core.utils.SnapOnScrollListener
|
||||||
import im.vector.app.core.utils.allGranted
|
|
||||||
import im.vector.app.core.utils.attachSnapHelperWithListener
|
import im.vector.app.core.utils.attachSnapHelperWithListener
|
||||||
import im.vector.app.core.utils.checkPermissions
|
|
||||||
import im.vector.app.features.media.createUCropWithDefaultSettings
|
import im.vector.app.features.media.createUCropWithDefaultSettings
|
||||||
import org.matrix.android.sdk.api.extensions.orFalse
|
|
||||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import kotlinx.android.synthetic.main.fragment_attachments_preview.*
|
import kotlinx.android.synthetic.main.fragment_attachments_preview.*
|
||||||
|
import org.matrix.android.sdk.api.extensions.orFalse
|
||||||
|
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -102,7 +98,7 @@ class AttachmentsPreviewFragment @Inject constructor(
|
||||||
handleRemoveAction()
|
handleRemoveAction()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
R.id.attachmentsPreviewEditAction -> {
|
R.id.attachmentsPreviewEditAction -> {
|
||||||
handleEditAction()
|
handleEditAction()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -183,22 +179,7 @@ class AttachmentsPreviewFragment @Inject constructor(
|
||||||
viewModel.handle(AttachmentsPreviewAction.RemoveCurrentAttachment)
|
viewModel.handle(AttachmentsPreviewAction.RemoveCurrentAttachment)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleEditAction() {
|
private fun handleEditAction() = withState(viewModel) {
|
||||||
// check permissions
|
|
||||||
if (checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, PERMISSION_REQUEST_CODE_PREVIEW_FRAGMENT)) {
|
|
||||||
doHandleEditAction()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
||||||
|
|
||||||
if (requestCode == PERMISSION_REQUEST_CODE_PREVIEW_FRAGMENT && allGranted(grantResults)) {
|
|
||||||
doHandleEditAction()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun doHandleEditAction() = withState(viewModel) {
|
|
||||||
val currentAttachment = it.attachments.getOrNull(it.currentAttachmentIndex) ?: return@withState
|
val currentAttachment = it.attachments.getOrNull(it.currentAttachmentIndex) ?: return@withState
|
||||||
val destinationFile = File(requireContext().cacheDir, "${currentAttachment.name}_edited_image_${System.currentTimeMillis()}")
|
val destinationFile = File(requireContext().cacheDir, "${currentAttachment.name}_edited_image_${System.currentTimeMillis()}")
|
||||||
val uri = currentAttachment.queryUri
|
val uri = currentAttachment.queryUri
|
||||||
|
|
|
@ -28,23 +28,19 @@ import androidx.appcompat.widget.SearchView
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.extensions.cleanup
|
import im.vector.app.core.extensions.cleanup
|
||||||
import im.vector.app.core.extensions.configureWith
|
import im.vector.app.core.extensions.configureWith
|
||||||
import im.vector.app.core.extensions.exhaustive
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.utils.PERMISSIONS_FOR_WRITING_FILES
|
|
||||||
import im.vector.app.core.utils.PERMISSION_REQUEST_CODE_PICK_ATTACHMENT
|
|
||||||
import im.vector.app.core.utils.allGranted
|
|
||||||
import im.vector.app.core.utils.checkPermissions
|
|
||||||
import im.vector.app.features.attachments.AttachmentsHelper
|
import im.vector.app.features.attachments.AttachmentsHelper
|
||||||
import im.vector.app.features.attachments.preview.AttachmentsPreviewActivity
|
import im.vector.app.features.attachments.preview.AttachmentsPreviewActivity
|
||||||
import im.vector.app.features.attachments.preview.AttachmentsPreviewArgs
|
import im.vector.app.features.attachments.preview.AttachmentsPreviewArgs
|
||||||
import im.vector.app.features.login.LoginActivity
|
import im.vector.app.features.login.LoginActivity
|
||||||
import kotlinx.android.synthetic.main.fragment_incoming_share.*
|
import kotlinx.android.synthetic.main.fragment_incoming_share.*
|
||||||
|
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||||
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -76,7 +72,7 @@ class IncomingShareFragment @Inject constructor(
|
||||||
|
|
||||||
val intent = vectorBaseActivity.intent
|
val intent = vectorBaseActivity.intent
|
||||||
val isShareManaged = when (intent?.action) {
|
val isShareManaged = when (intent?.action) {
|
||||||
Intent.ACTION_SEND -> {
|
Intent.ACTION_SEND -> {
|
||||||
var isShareManaged = attachmentsHelper.handleShareIntent(requireContext(), intent)
|
var isShareManaged = attachmentsHelper.handleShareIntent(requireContext(), intent)
|
||||||
if (!isShareManaged) {
|
if (!isShareManaged) {
|
||||||
isShareManaged = handleTextShare(intent)
|
isShareManaged = handleTextShare(intent)
|
||||||
|
@ -106,7 +102,7 @@ class IncomingShareFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
viewModel.observeViewEvents {
|
viewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
is IncomingShareViewEvents.ShareToRoom -> handleShareToRoom(it)
|
is IncomingShareViewEvents.ShareToRoom -> handleShareToRoom(it)
|
||||||
is IncomingShareViewEvents.EditMediaBeforeSending -> handleEditMediaBeforeSending(it)
|
is IncomingShareViewEvents.EditMediaBeforeSending -> handleEditMediaBeforeSending(it)
|
||||||
is IncomingShareViewEvents.MultipleRoomsShareDone -> handleMultipleRoomsShareDone(it)
|
is IncomingShareViewEvents.MultipleRoomsShareDone -> handleMultipleRoomsShareDone(it)
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
|
@ -139,22 +135,6 @@ class IncomingShareFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
|
|
||||||
// We need the read file permission
|
|
||||||
checkPermissions(PERMISSIONS_FOR_WRITING_FILES, this, PERMISSION_REQUEST_CODE_PICK_ATTACHMENT)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
|
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
|
||||||
|
|
||||||
if (requestCode == PERMISSION_REQUEST_CODE_PICK_ATTACHMENT && !allGranted(grantResults)) {
|
|
||||||
// Permission is mandatory
|
|
||||||
cannotManageShare(R.string.missing_permissions_error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleShareToRoom(event: IncomingShareViewEvents.ShareToRoom) {
|
private fun handleShareToRoom(event: IncomingShareViewEvents.ShareToRoom) {
|
||||||
if (event.showAlert) {
|
if (event.showAlert) {
|
||||||
showConfirmationDialog(event.roomSummary, event.sharedData)
|
showConfirmationDialog(event.roomSummary, event.sharedData)
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/riot_desktop_web"
|
android:id="@+id/app_desktop_web"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
app:layout_constraintTop_toBottomOf="@id/monitorIcon" />
|
app:layout_constraintTop_toBottomOf="@id/monitorIcon" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/riot_ios_android"
|
android:id="@+id/app_ios_android"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
|
@ -75,7 +75,7 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:barrierDirection="bottom"
|
app:barrierDirection="bottom"
|
||||||
app:constraint_referenced_ids="riot_ios_android,riot_desktop_web" />
|
app:constraint_referenced_ids="app_ios_android,app_desktop_web" />
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
Loading…
Reference in New Issue