Getting photo dimension of locally stored photo - android

I'd like to know photos width and height before loading a bitmap. I'm using latest approach of ContentResolver to query locally stored photos.
contentResolver.query(
collection,
projection,
selection,
selectionArgs,
sortOrder
)!!.use { cursor ->
while (cursor.moveToNext()) {
// Use an ID column from the projection to get
// a URI representing the media item itself.
val idColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID)
val widthColumn = cursor.getColumnIndex(MediaStore.Images.Media.WIDTH)
val id: Long = cursor.getLong(idColumn)
val width: Int = cursor.getInt(widthColumn) //CRASH
}
Cursor is crashing on the selected line width:
IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
How am I supposed to do that then?

Try This
val projection = arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.WIDTH,
MediaStore.Images.Media.HEIGHT
)
val images: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
contentResolver.query(
images,
projection,
null,
null,
null
)!!.use { cursor ->
if (cursor.count > 0) {
val idColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID)
val widthColumn = cursor.getColumnIndex(MediaStore.Images.Media.WIDTH)
val heightColumn = cursor.getColumnIndex(MediaStore.Images.Media.HEIGHT)
while (cursor.moveToNext()) {
val id: Long = cursor.getLong(idColumn)
val width: Int = cursor.getInt(widthColumn)
val height: Int = cursor.getInt(heightColumn)
Log.e("tag", " width :: $width - height :: $height");
}
}
}

Related

Android contentResolver query with MediaStore returns empty cursor

I'm trying to get all the images on the device, for now my code is:
val imageProjection = arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.DATE_TAKEN,
)
val cursor = context.contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
imageProjection,
null,
null,
"${MediaStore.Images.Media.DATE_MODIFIED} DESC"
)
cursor?.use {
val idColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
val nameColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)
val sizeColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)
val dateColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_TAKEN)
while (it.moveToNext()) {
val id = it.getLong(idColumn)
val name = it.getString(nameColumn)
val size = it.getString(sizeColumn)
val date = it.getString(dateColumn)
Log.d("IMAGE", "$id $name $size $date")
}
}
The query does give me a Cursor, but the Cursor appears to be empty as the code never enter the while.
I've checked that i have the READ_EXTERNAL_STORAGE permission, and i do have it, but it still doesn't work, i also tried using MediaStore.Images.Media.INTERNAL_CONTENT_URI as the query uri, but that didn't change anything, the result is always an empty cursor.
Can someone give me an hint on what i'm doing wrong?

MEDIASTORE images, got nothing

I added the request premissions for reading files tried this method inside my activity but nothing shows,like there is no images in real devices and emulator,what am i doing wrong?
fun storaheread() {
val imageProjection = arrayOf(
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media._ID
)
val imageSortOrder = "${MediaStore.Images.Media.DATE_TAKEN} DESC"
val cursor = contentResolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
imageProjection,
null,
null,
imageSortOrder
)
cursor.use {
it?.let {
val idColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
val nameColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)
val sizeColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)
val dateColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_TAKEN)
while (it.moveToNext()) {
val id = it.getLong(idColumn)
val name = it.getString(nameColumn)
val size = it.getString(sizeColumn)
val date = it.getString(dateColumn)
val contentUri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
id
)
// add the URI to the list
// generate the thumbnail
// val thumbnail = (this as Context).contentResolver.loadThumbnail(contentUri, Size(480, 480), null)
Log.d("image name",name)
}
} ?: kotlin.run {
Log.e("TAG", "Cursor is null!")
}
}
}
you can check out this similar question, it may help you achieve this situation.
Loading all the images from gallery into the Application in android

Some devices like OPPO don't support reading contacts in pages (pagination) Android

I face an issues that some devices like OPPO don't support reading contacts in pages like if I make "LIMIT 100 OFFSET 0", it returns all rows in the contacts table.
val cursor = contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
null,
null,
null,
"${ContactsContract.Contacts._ID} desc LIMIT $PAGE_LIMIT OFFSET $offset"
)
I had to make a workaround by checking if the first page size equals to the all rows in the table size so I stop reading the contacts in pages to avoid infinite loop.
private fun isReadingContactsInPagesSupported(): Boolean {
val firstPageContactsSize = getQueryCount(" LIMIT $PAGE_LIMIT OFFSET 0")
val allContactsSize = getQueryCount(null)
return firstPageContactsSize != allContactsSize
}
#SuppressLint("Range")
private fun getQueryCount(sort: String?): Int {
val contentResolver: ContentResolver = context.contentResolver
val cursor = contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
null,
null,
null,
sort
)
val count = cursor?.count ?: 0
cursor?.close()
return count
}

ContentResolver.query() method throws "Invalid token limit" error

The following error occurs on Pixel devices with build number RQ1A.201205.003 or later.
I would like to know the cause of the error and how to deal with it.
Is this a bug or a spec change?
■code
ContentResolver resolver = getContentResolver();
String order = "date ASC limit 100";
Cursor cursor = resolver.query(
CallLog.Calls.CONTENT_URI,
null,
null,
null,
order);
■error
"Invalid token limit,LINE:142,Method:readExceptionFromParcel Exception:Invalid token limit"
■Build number where the error occurs
https://support.google.com/pixelphone/thread/87641266
・RQ1A.201205.003
・RQ1A.201205.008
・RQ1A.201205.011
https://support.google.com/pixelphone/thread/93232095
・RQ1A.210105.002
・RQ1A.210105.003
https://support.google.com/pixelphone/thread/96244000
・RQ1A.210205.004
■If you replace it with the following code, no error will occur.
buildUpon().appendQueryParameter("limit", "100")
■Additional Information
When implemented using the official documentation method, no error occurred, but the LIMIT clause did not work (all records were retrieved).
ContentProvider - query
// Request 20 records starting at row index 30.
Bundle queryArgs = new Bundle();
queryArgs.putInt(ContentResolver.QUERY_ARG_OFFSET, 30);
queryArgs.putInt(ContentResolver.QUERY_ARG_LIMIT, 20);
Cursor cursor = getContentResolver().query(
contentUri, // Content Uri is specific to individual content providers.
projection, // String[] describing which columns to return.
queryArgs, // Query arguments.
null); // Cancellation signal.
From Android 11, LIMIT and OFFSET should be retrieved using Bundle by
public Cursor query (Uri uri,
String[] projection,
Bundle queryArgs,
CancellationSignal cancellationSignal)
I use such solution and it works for me:
import android.content.ContentResolver
import android.content.ContentUris
import android.content.Context
import android.database.Cursor
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import androidx.annotation.RequiresApi
import androidx.core.database.getLongOrNull
import androidx.core.database.getStringOrNull
data class MediaItem(
val id: Long,
val contentUri: Uri,
val data: String?,
val mimeType: String?,
val duration: Long?
)
private fun fetchGalleryImages(
context: Context,
orderBy: String,
orderAscending: Boolean,
limit: Int = 20,
offset: Int = 0
): List<MediaItem> {
val galleryImageUrls = mutableListOf<MediaItem>()
val collection = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(
MediaStore.Files.FileColumns._ID,
MediaStore.Files.FileColumns.DATA,
MediaStore.Files.FileColumns.DATE_ADDED,
MediaStore.Files.FileColumns.MEDIA_TYPE,
MediaStore.Files.FileColumns.MIME_TYPE,
MediaStore.Files.FileColumns.TITLE,
MediaStore.Video.Media.DURATION
)
val whereCondition = "${MediaStore.Files.FileColumns.MEDIA_TYPE} = ? OR ${MediaStore.Files.FileColumns.MEDIA_TYPE} = ?"
val selectionArgs = arrayOf(
MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE.toString(),
MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO.toString()
)
createCursor(
contentResolver = context.contentResolver,
collection = collection,
projection = projection,
whereCondition = whereCondition,
selectionArgs = selectionArgs,
orderBy = orderBy,
orderAscending = orderAscending,
limit = limit,
offset = offset
)?.use { cursor ->
while (cursor.moveToNext()) {
val idIndex = cursor.getColumnIndex(MediaStore.Audio.Media._ID)
if (idIndex < 0) continue
val id = cursor.getLong(idIndex)
galleryImageUrls.add(
MediaItem(
id = id,
contentUri = ContentUris.withAppendedId(collection, id),
data = cursor.getStringOrNull(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)),
mimeType = cursor.getStringOrNull(cursor.getColumnIndex(MediaStore.Files.FileColumns.MIME_TYPE)),
duration = cursor.getLongOrNull(cursor.getColumnIndex(MediaStore.Video.Media.DURATION))
)
)
}
}
return galleryImageUrls
}
private fun createCursor(
contentResolver: ContentResolver,
collection: Uri,
projection: Array<String>,
whereCondition: String,
selectionArgs: Array<String>,
orderBy: String,
orderAscending: Boolean,
limit: Int = 20,
offset: Int = 0
): Cursor? = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
val selection = createSelectionBundle(whereCondition, selectionArgs, orderBy, orderAscending, limit, offset)
contentResolver.query(collection, projection, selection, null)
}
else -> {
val orderDirection = if (orderAscending) "ASC" else "DESC"
var order = when (orderBy) {
"ALPHABET" -> "${MediaStore.Audio.Media.TITLE}, ${MediaStore.Audio.Media.ARTIST} $orderDirection"
else -> "${MediaStore.Audio.Media.DATE_ADDED} $orderDirection"
}
order += " LIMIT $limit OFFSET $offset"
contentResolver.query(collection, projection, whereCondition, selectionArgs, order)
}
}
#RequiresApi(Build.VERSION_CODES.O)
fun createSelectionBundle(
whereCondition: String,
selectionArgs: Array<String>,
orderBy: String,
orderAscending: Boolean,
limit: Int = 20,
offset: Int = 0
): Bundle = Bundle().apply {
// Limit & Offset
putInt(ContentResolver.QUERY_ARG_LIMIT, limit)
putInt(ContentResolver.QUERY_ARG_OFFSET, offset)
// Sort function
when (orderBy) {
"ALPHABET" -> putStringArray(ContentResolver.QUERY_ARG_SORT_COLUMNS, arrayOf(MediaStore.Files.FileColumns.TITLE))
else -> putStringArray(ContentResolver.QUERY_ARG_SORT_COLUMNS, arrayOf(MediaStore.Files.FileColumns.DATE_ADDED))
}
// Sorting direction
val orderDirection =
if (orderAscending) ContentResolver.QUERY_SORT_DIRECTION_ASCENDING else ContentResolver.QUERY_SORT_DIRECTION_DESCENDING
putInt(ContentResolver.QUERY_ARG_SORT_DIRECTION, orderDirection)
// Selection
putString(ContentResolver.QUERY_ARG_SQL_SELECTION, whereCondition)
putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs)
}

How to get images from phone on API below 29

I develop image gallery app for Android (min sdk 23, target sdk 29). And I trying to get list of photos from the phone. Here the code:
val list: MutableList<Photo> = mutableListOf()
val projection = arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media.ORIENTATION,
MediaStore.Images.Media.SIZE
)
val query = contentResolver?.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection,
null,
null,
MediaStore.Images.Media.DATE_TAKEN + " DESC"
)
query?.use { cursor ->
if (cursor.count != 0) {
val idIndex = cursor.getColumnIndex(MediaStore.Images.Media._ID)
val sizeIndex = cursor.getColumnIndex(MediaStore.Images.Media.SIZE)
while (cursor.moveToNext()) {
val id = cursor.getLong(idIndex)
val size = cursor.getInt(sizeIndex)
val contentUri: Uri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
id
)
val photo = Photo(contentUri, size)
list.add(photo)
}
}
}
But Android Studio says to me that some MediaStore fields requires API level 29+. (e.g. MediaStore.Images.Media.DATE_TAKEN, MediaStore.Images.Media.ORIENTATION, MediaStore.Images.Media.DATA, etc.).
Screen from AS.
So my question is how do I should get images list on APIs below 29?
Also studio says same about contentResolver.loadThumbnail() method.
And adjacent question: is it possible in Android to retrieve list of photo albums? Or I should get list of all images and then run over it and pick out albums?
Try this, it's work even with API 29 :
private fun getAllImages(activity: Activity): ArrayList<Photo>? {
var cursor: Cursor? = null
var i = 0
val arrayList: ArrayList<Photo> = ArrayList()
if (cursor == null) {
val resolver = activity.contentResolver
cursor = resolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null,
null,
null,
null
)
if (cursor != null) {
while (i < cursor.count) {
cursor.moveToPosition(i)
val fieldIndex: Int = cursor.getColumnIndex(MediaStore.Images.Media._ID)
val id: Long = cursor.getLong(fieldIndex)
val imageUri =
ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
arrayList.add(Photo("", imageUri))
i++
}
cursor.close()
}
}
return arrayList
}
data class Photo(var name: String, var uri: Uri)
Use any image loader library such as Glide or Picasso :
Glide.with(this).load(getAllImages(this)!![0].uri).into(imgView)
Add this permission to your manifest, and make sure it granted :
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

Categories

Resources