From 84f7eb29e064d125d2e6b674d28d02df83f275b8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Dec 2021 16:09:12 +0100 Subject: [PATCH] Add robustness when getting data from cursors. Use androidx.core.database extension for better nullability check, and ignore uncomplete data. --- changelog.d/4605.bugfix | 1 + .../vector/lib/multipicker/ContactPicker.kt | 14 +++++++------ .../im/vector/lib/multipicker/FilePicker.kt | 6 ++++-- .../multipicker/utils/ContentResolverUtil.kt | 14 +++++++------ .../app/core/contacts/ContactsDataSource.kt | 20 ++++++++++--------- .../im/vector/app/core/intent/Filename.kt | 3 ++- 6 files changed, 34 insertions(+), 24 deletions(-) create mode 100644 changelog.d/4605.bugfix diff --git a/changelog.d/4605.bugfix b/changelog.d/4605.bugfix new file mode 100644 index 0000000000..ee0152ed10 --- /dev/null +++ b/changelog.d/4605.bugfix @@ -0,0 +1 @@ +Add robustness when getting data from cursors \ No newline at end of file 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 2b8c1d11e6..bb21196858 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/ContactPicker.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/ContactPicker.kt @@ -20,6 +20,8 @@ import android.content.ContentResolver import android.content.Context import android.content.Intent 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.utils.getColumnIndexOrNull @@ -54,9 +56,9 @@ class ContactPicker : Picker() { val nameColumn = cursor.getColumnIndexOrNull(ContactsContract.Contacts.DISPLAY_NAME) ?: return@use val photoUriColumn = cursor.getColumnIndexOrNull(ContactsContract.Contacts.PHOTO_URI) ?: return@use - val contactId = cursor.getInt(idColumn) - var name = cursor.getString(nameColumn) - val photoUri = cursor.getString(photoUriColumn) + val contactId = cursor.getIntOrNull(idColumn) ?: return@use + var name = cursor.getStringOrNull(nameColumn) ?: return@use + val photoUri = cursor.getStringOrNull(photoUriColumn) val phoneNumberList = mutableListOf() val emailList = mutableListOf() @@ -78,8 +80,8 @@ class ContactPicker : Picker() { val data1ColumnIndex = innerCursor.getColumnIndexOrNull(ContactsContract.Data.DATA1) ?: return@inner while (innerCursor.moveToNext()) { - val mimeType = innerCursor.getString(mimeTypeColumnIndex) - val contactData = innerCursor.getString(data1ColumnIndex) + val mimeType = innerCursor.getStringOrNull(mimeTypeColumnIndex) + val contactData = innerCursor.getStringOrNull(data1ColumnIndex) ?: continue if (mimeType == ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE) { name = contactData @@ -121,7 +123,7 @@ class ContactPicker : Picker() { )?.use { cursor -> return if (cursor.moveToFirst()) { cursor.getColumnIndexOrNull(ContactsContract.RawContacts._ID) - ?.let { cursor.getInt(it) } + ?.let { cursor.getIntOrNull(it) } } else null } } 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 8e6c97f2f8..2e3148c9de 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/FilePicker.kt @@ -19,6 +19,8 @@ package im.vector.lib.multipicker import android.content.Context import android.content.Intent 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.MultiPickerFileType import im.vector.lib.multipicker.utils.getColumnIndexOrNull @@ -53,8 +55,8 @@ class FilePicker : Picker() { val nameColumn = cursor.getColumnIndexOrNull(OpenableColumns.DISPLAY_NAME) ?: return@use null val sizeColumn = cursor.getColumnIndexOrNull(OpenableColumns.SIZE) ?: return@use null if (cursor.moveToFirst()) { - val name = cursor.getString(nameColumn) - val size = cursor.getLong(sizeColumn) + val name = cursor.getStringOrNull(nameColumn) + val size = cursor.getLongOrNull(sizeColumn) ?: 0 MultiPickerFileType( name, diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/utils/ContentResolverUtil.kt b/multipicker/src/main/java/im/vector/lib/multipicker/utils/ContentResolverUtil.kt index 55c0010afd..6114a82122 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/utils/ContentResolverUtil.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/utils/ContentResolverUtil.kt @@ -20,6 +20,8 @@ import android.content.Context import android.media.MediaMetadataRetriever import android.net.Uri 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.MultiPickerImageType 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 if (cursor.moveToNext()) { - val name = cursor.getString(nameColumn) - val size = cursor.getLong(sizeColumn) + val name = cursor.getStringOrNull(nameColumn) + val size = cursor.getLongOrNull(sizeColumn) ?: 0 val bitmap = ImageUtils.getBitmap(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 if (cursor.moveToNext()) { - val name = cursor.getString(nameColumn) - val size = cursor.getLong(sizeColumn) + val name = cursor.getStringOrNull(nameColumn) + val size = cursor.getLongOrNull(sizeColumn) ?: 0 var duration = 0L var width = 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 if (cursor.moveToNext()) { - val name = cursor.getString(nameColumn) - val size = cursor.getLong(sizeColumn) + val name = cursor.getStringOrNull(nameColumn) + val size = cursor.getLongOrNull(sizeColumn) ?: 0 var duration = 0L context.contentResolver.openFileDescriptor(this, "r")?.use { pfd -> diff --git a/vector/src/main/java/im/vector/app/core/contacts/ContactsDataSource.kt b/vector/src/main/java/im/vector/app/core/contacts/ContactsDataSource.kt index f99048501d..db0fab9c42 100644 --- a/vector/src/main/java/im/vector/app/core/contacts/ContactsDataSource.kt +++ b/vector/src/main/java/im/vector/app/core/contacts/ContactsDataSource.kt @@ -20,6 +20,8 @@ import android.content.Context import android.net.Uri import android.provider.ContactsContract import androidx.annotation.WorkerThread +import androidx.core.database.getLongOrNull +import androidx.core.database.getStringOrNull import im.vector.lib.multipicker.utils.getColumnIndexOrNull import timber.log.Timber import javax.inject.Inject @@ -61,8 +63,8 @@ class ContactsDataSource @Inject constructor( val displayNameColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.Contacts.DISPLAY_NAME) ?: return@use val photoUriColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.Data.PHOTO_URI) while (cursor.moveToNext()) { - val id = cursor.getLong(idColumnIndex) - val displayName = cursor.getString(displayNameColumnIndex) + val id = cursor.getLongOrNull(idColumnIndex) ?: continue + val displayName = cursor.getStringOrNull(displayNameColumnIndex) ?: continue val mappedContactBuilder = MappedContactBuilder( id = id, @@ -70,7 +72,7 @@ class ContactsDataSource @Inject constructor( ) photoUriColumnIndex - ?.let { cursor.getString(it) } + ?.let { cursor.getStringOrNull(it) } ?.let { Uri.parse(it) } ?.let { mappedContactBuilder.photoURI = it } @@ -94,10 +96,10 @@ class ContactsDataSource @Inject constructor( val phoneNumberColumnIndex = cursor.getColumnIndexOrNull(ContactsContract.CommonDataKinds.Phone.NUMBER) ?: return@use while (cursor.moveToNext()) { - val mappedContactBuilder = cursor.getLong(idColumnIndex) - .let { map[it] } + val mappedContactBuilder = cursor.getLongOrNull(idColumnIndex) + ?.let { map[it] } ?: continue - cursor.getString(phoneNumberColumnIndex) + cursor.getStringOrNull(phoneNumberColumnIndex) ?.let { mappedContactBuilder.msisdns.add( MappedMsisdn( @@ -128,10 +130,10 @@ class ContactsDataSource @Inject constructor( while (cursor.moveToNext()) { // This would allow you get several email addresses // if the email addresses were stored in an array - val mappedContactBuilder = cursor.getLong(idColumnIndex) - .let { map[it] } + val mappedContactBuilder = cursor.getLongOrNull(idColumnIndex) + ?.let { map[it] } ?: continue - cursor.getString(emailColumnIndex) + cursor.getStringOrNull(emailColumnIndex) ?.let { mappedContactBuilder.emails.add( MappedEmail( diff --git a/vector/src/main/java/im/vector/app/core/intent/Filename.kt b/vector/src/main/java/im/vector/app/core/intent/Filename.kt index a38602e4a5..14a0dfc3b6 100644 --- a/vector/src/main/java/im/vector/app/core/intent/Filename.kt +++ b/vector/src/main/java/im/vector/app/core/intent/Filename.kt @@ -19,6 +19,7 @@ package im.vector.app.core.intent import android.content.Context import android.net.Uri import android.provider.OpenableColumns +import androidx.core.database.getStringOrNull import im.vector.lib.multipicker.utils.getColumnIndexOrNull fun getFilenameFromUri(context: Context?, uri: Uri): String? { @@ -27,7 +28,7 @@ fun getFilenameFromUri(context: Context?, uri: Uri): String? { ?.use { cursor -> if (cursor.moveToFirst()) { return cursor.getColumnIndexOrNull(OpenableColumns.DISPLAY_NAME) - ?.let { cursor.getString(it) } + ?.let { cursor.getStringOrNull(it) } } } }