Merge pull request #4607 from vector-im/feature/bma/cursor_crash

Add robustness when getting data from cursors.
This commit is contained in:
Benoit Marty 2021-12-01 16:48:50 +01:00 committed by GitHub
commit 9253a3664b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 34 additions and 24 deletions

1
changelog.d/4605.bugfix Normal file
View File

@ -0,0 +1 @@
Add robustness when getting data from cursors

View File

@ -20,6 +20,8 @@ import android.content.ContentResolver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.provider.ContactsContract import android.provider.ContactsContract
import androidx.core.database.getIntOrNull
import androidx.core.database.getStringOrNull
import im.vector.lib.multipicker.entity.MultiPickerContactType import im.vector.lib.multipicker.entity.MultiPickerContactType
import im.vector.lib.multipicker.utils.getColumnIndexOrNull import im.vector.lib.multipicker.utils.getColumnIndexOrNull
@ -54,9 +56,9 @@ class ContactPicker : Picker<MultiPickerContactType>() {
val nameColumn = cursor.getColumnIndexOrNull(ContactsContract.Contacts.DISPLAY_NAME) ?: return@use val nameColumn = cursor.getColumnIndexOrNull(ContactsContract.Contacts.DISPLAY_NAME) ?: return@use
val photoUriColumn = cursor.getColumnIndexOrNull(ContactsContract.Contacts.PHOTO_URI) ?: return@use val photoUriColumn = cursor.getColumnIndexOrNull(ContactsContract.Contacts.PHOTO_URI) ?: return@use
val contactId = cursor.getInt(idColumn) val contactId = cursor.getIntOrNull(idColumn) ?: return@use
var name = cursor.getString(nameColumn) var name = cursor.getStringOrNull(nameColumn) ?: return@use
val photoUri = cursor.getString(photoUriColumn) val photoUri = cursor.getStringOrNull(photoUriColumn)
val phoneNumberList = mutableListOf<String>() val phoneNumberList = mutableListOf<String>()
val emailList = mutableListOf<String>() val emailList = mutableListOf<String>()
@ -78,8 +80,8 @@ class ContactPicker : Picker<MultiPickerContactType>() {
val data1ColumnIndex = innerCursor.getColumnIndexOrNull(ContactsContract.Data.DATA1) ?: return@inner val data1ColumnIndex = innerCursor.getColumnIndexOrNull(ContactsContract.Data.DATA1) ?: return@inner
while (innerCursor.moveToNext()) { while (innerCursor.moveToNext()) {
val mimeType = innerCursor.getString(mimeTypeColumnIndex) val mimeType = innerCursor.getStringOrNull(mimeTypeColumnIndex)
val contactData = innerCursor.getString(data1ColumnIndex) val contactData = innerCursor.getStringOrNull(data1ColumnIndex) ?: continue
if (mimeType == ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) { if (mimeType == ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) {
name = contactData name = contactData
@ -121,7 +123,7 @@ class ContactPicker : Picker<MultiPickerContactType>() {
)?.use { cursor -> )?.use { cursor ->
return if (cursor.moveToFirst()) { return if (cursor.moveToFirst()) {
cursor.getColumnIndexOrNull(ContactsContract.RawContacts._ID) cursor.getColumnIndexOrNull(ContactsContract.RawContacts._ID)
?.let { cursor.getInt(it) } ?.let { cursor.getIntOrNull(it) }
} else null } else null
} }
} }

View File

@ -19,6 +19,8 @@ package im.vector.lib.multipicker
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.provider.OpenableColumns import android.provider.OpenableColumns
import androidx.core.database.getLongOrNull
import androidx.core.database.getStringOrNull
import im.vector.lib.multipicker.entity.MultiPickerBaseType import im.vector.lib.multipicker.entity.MultiPickerBaseType
import im.vector.lib.multipicker.entity.MultiPickerFileType import im.vector.lib.multipicker.entity.MultiPickerFileType
import im.vector.lib.multipicker.utils.getColumnIndexOrNull import im.vector.lib.multipicker.utils.getColumnIndexOrNull
@ -53,8 +55,8 @@ class FilePicker : Picker<MultiPickerBaseType>() {
val nameColumn = cursor.getColumnIndexOrNull(OpenableColumns.DISPLAY_NAME) ?: return@use null val nameColumn = cursor.getColumnIndexOrNull(OpenableColumns.DISPLAY_NAME) ?: return@use null
val sizeColumn = cursor.getColumnIndexOrNull(OpenableColumns.SIZE) ?: return@use null val sizeColumn = cursor.getColumnIndexOrNull(OpenableColumns.SIZE) ?: return@use null
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
val name = cursor.getString(nameColumn) val name = cursor.getStringOrNull(nameColumn)
val size = cursor.getLong(sizeColumn) val size = cursor.getLongOrNull(sizeColumn) ?: 0
MultiPickerFileType( MultiPickerFileType(
name, name,

View File

@ -20,6 +20,8 @@ import android.content.Context
import android.media.MediaMetadataRetriever import android.media.MediaMetadataRetriever
import android.net.Uri import android.net.Uri
import android.provider.MediaStore import android.provider.MediaStore
import androidx.core.database.getLongOrNull
import androidx.core.database.getStringOrNull
import im.vector.lib.multipicker.entity.MultiPickerAudioType import im.vector.lib.multipicker.entity.MultiPickerAudioType
import im.vector.lib.multipicker.entity.MultiPickerImageType import im.vector.lib.multipicker.entity.MultiPickerImageType
import im.vector.lib.multipicker.entity.MultiPickerVideoType import im.vector.lib.multipicker.entity.MultiPickerVideoType
@ -41,8 +43,8 @@ internal fun Uri.toMultiPickerImageType(context: Context): MultiPickerImageType?
val sizeColumn = cursor.getColumnIndexOrNull(MediaStore.Images.Media.SIZE) ?: return@use null val sizeColumn = cursor.getColumnIndexOrNull(MediaStore.Images.Media.SIZE) ?: return@use null
if (cursor.moveToNext()) { if (cursor.moveToNext()) {
val name = cursor.getString(nameColumn) val name = cursor.getStringOrNull(nameColumn)
val size = cursor.getLong(sizeColumn) val size = cursor.getLongOrNull(sizeColumn) ?: 0
val bitmap = ImageUtils.getBitmap(context, this) val bitmap = ImageUtils.getBitmap(context, this)
val orientation = ImageUtils.getOrientation(context, this) val orientation = ImageUtils.getOrientation(context, this)
@ -79,8 +81,8 @@ internal fun Uri.toMultiPickerVideoType(context: Context): MultiPickerVideoType?
val sizeColumn = cursor.getColumnIndexOrNull(MediaStore.Video.Media.SIZE) ?: return@use null val sizeColumn = cursor.getColumnIndexOrNull(MediaStore.Video.Media.SIZE) ?: return@use null
if (cursor.moveToNext()) { if (cursor.moveToNext()) {
val name = cursor.getString(nameColumn) val name = cursor.getStringOrNull(nameColumn)
val size = cursor.getLong(sizeColumn) val size = cursor.getLongOrNull(sizeColumn) ?: 0
var duration = 0L var duration = 0L
var width = 0 var width = 0
var height = 0 var height = 0
@ -128,8 +130,8 @@ fun Uri.toMultiPickerAudioType(context: Context): MultiPickerAudioType? {
val sizeColumn = cursor.getColumnIndexOrNull(MediaStore.Audio.Media.SIZE) ?: return@use null val sizeColumn = cursor.getColumnIndexOrNull(MediaStore.Audio.Media.SIZE) ?: return@use null
if (cursor.moveToNext()) { if (cursor.moveToNext()) {
val name = cursor.getString(nameColumn) val name = cursor.getStringOrNull(nameColumn)
val size = cursor.getLong(sizeColumn) val size = cursor.getLongOrNull(sizeColumn) ?: 0
var duration = 0L var duration = 0L
context.contentResolver.openFileDescriptor(this, "r")?.use { pfd -> context.contentResolver.openFileDescriptor(this, "r")?.use { pfd ->

View File

@ -20,6 +20,8 @@ import android.content.Context
import android.net.Uri import android.net.Uri
import android.provider.ContactsContract import android.provider.ContactsContract
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import androidx.core.database.getLongOrNull
import androidx.core.database.getStringOrNull
import im.vector.lib.multipicker.utils.getColumnIndexOrNull import im.vector.lib.multipicker.utils.getColumnIndexOrNull
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -61,8 +63,8 @@ class ContactsDataSource @Inject constructor(
val displayNameColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.Contacts.DISPLAY_NAME) ?: return@use val displayNameColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.Contacts.DISPLAY_NAME) ?: return@use
val photoUriColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.Data.PHOTO_URI) val photoUriColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.Data.PHOTO_URI)
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
val id = cursor.getLong(idColumnIndex) val id = cursor.getLongOrNull(idColumnIndex) ?: continue
val displayName = cursor.getString(displayNameColumnIndex) val displayName = cursor.getStringOrNull(displayNameColumnIndex) ?: continue
val mappedContactBuilder = MappedContactBuilder( val mappedContactBuilder = MappedContactBuilder(
id = id, id = id,
@ -70,7 +72,7 @@ class ContactsDataSource @Inject constructor(
) )
photoUriColumnIndex photoUriColumnIndex
?.let { cursor.getString(it) } ?.let { cursor.getStringOrNull(it) }
?.let { Uri.parse(it) } ?.let { Uri.parse(it) }
?.let { mappedContactBuilder.photoURI = it } ?.let { mappedContactBuilder.photoURI = it }
@ -94,10 +96,10 @@ class ContactsDataSource @Inject constructor(
val phoneNumberColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.CommonDataKinds.Phone.NUMBER) ?: return@use val phoneNumberColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.CommonDataKinds.Phone.NUMBER) ?: return@use
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
val mappedContactBuilder = cursor.getLong(idColumnIndex) val mappedContactBuilder = cursor.getLongOrNull(idColumnIndex)
.let { map[it] } ?.let { map[it] }
?: continue ?: continue
cursor.getString(phoneNumberColumnIndex) cursor.getStringOrNull(phoneNumberColumnIndex)
?.let { ?.let {
mappedContactBuilder.msisdns.add( mappedContactBuilder.msisdns.add(
MappedMsisdn( MappedMsisdn(
@ -128,10 +130,10 @@ class ContactsDataSource @Inject constructor(
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
// This would allow you get several email addresses // This would allow you get several email addresses
// if the email addresses were stored in an array // if the email addresses were stored in an array
val mappedContactBuilder = cursor.getLong(idColumnIndex) val mappedContactBuilder = cursor.getLongOrNull(idColumnIndex)
.let { map[it] } ?.let { map[it] }
?: continue ?: continue
cursor.getString(emailColumnIndex) cursor.getStringOrNull(emailColumnIndex)
?.let { ?.let {
mappedContactBuilder.emails.add( mappedContactBuilder.emails.add(
MappedEmail( MappedEmail(

View File

@ -19,6 +19,7 @@ package im.vector.app.core.intent
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.provider.OpenableColumns import android.provider.OpenableColumns
import androidx.core.database.getStringOrNull
import im.vector.lib.multipicker.utils.getColumnIndexOrNull import im.vector.lib.multipicker.utils.getColumnIndexOrNull
fun getFilenameFromUri(context: Context?, uri: Uri): String? { fun getFilenameFromUri(context: Context?, uri: Uri): String? {
@ -27,7 +28,7 @@ fun getFilenameFromUri(context: Context?, uri: Uri): String? {
?.use { cursor -> ?.use { cursor ->
if (cursor.moveToFirst()) { if (cursor.moveToFirst()) {
return cursor.getColumnIndexOrNull(OpenableColumns.DISPLAY_NAME) return cursor.getColumnIndexOrNull(OpenableColumns.DISPLAY_NAME)
?.let { cursor.getString(it) } ?.let { cursor.getStringOrNull(it) }
} }
} }
} }