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
Related
I use this function to show images from specific album in gallery:
fun findImagesInAlbum(albumId: String): List<Image> {
val contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projections = arrayOf(
MediaStore.Images.ImageColumns._ID,
MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
MediaStore.Images.ImageColumns.DATE_TAKEN,
MediaStore.Images.ImageColumns.DISPLAY_NAME
)
val selection = "${MediaStore.Images.ImageColumns.BUCKET_ID} == ?"
val selectionArgs = arrayOf(albumId)
val findImages = HashMap<String, Image>()
contentResolver.query(contentUri, projections, selection, selectionArgs,
"${MediaStore.Images.ImageColumns.DATE_TAKEN} ASC")?.use { cursor ->
if (cursor.moveToFirst()) {
val idIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns._ID)
val displayNameIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.ImageColumns.DISPLAY_NAME)
do {
val mediaId = cursor.getLong(idIndex)
val filename = cursor.getString(displayNameIndex)
val uri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
mediaId
)
val image = Image(
id = mediaId.toString(),
name = filename,
uri = uri,
count = 0,
)
findImages[mediaId.toString()] = image
image.count++
} while (cursor.moveToNext())
}
}
return findImages.values.toList().sortedByDescending { it.name }
}
I show the List<Image> at the RecyclerView and it works fine. After clicking on image it opens on fullscreen. What functions can i use to rename an opened image and save its name in the phone storage?
I tried to solve this problem with DocumentsContract.renameDocument, but it throws error: java.lang.UnsupportedOperationException: Unsupported call: android:renameDocument.
This code is working fine when images read from gallery but when my phone reset and I recovered images from Google photos. It recovered to my gallery, but when I fetch images from gallery programmatically, it doesn't work properly. it just fetched 2 months images. I have used this code, Using Date_added meta data, but I have already tested date_taken and date_modified but it doesn't work.
val collection =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
/* MediaStore.Images.Media.getContentUri(
MediaStore.VOLUME_EXTERNAL
)*/
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
} else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
val projection = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media.DATE_MODIFIED,
MediaStore.Images.Media.DATE_ADDED,
MediaStore.Images.Media.SIZE,
MediaStore.MediaColumns.DATA,
MediaStore.Images.Media.IS_FAVORITE
)
} else {
arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATE_TAKEN,
MediaStore.Images.Media.DATE_MODIFIED,
MediaStore.Images.Media.DATE_ADDED,
MediaStore.Images.Media.SIZE,
MediaStore.MediaColumns.DATA
)
}
// Show only images that are at least 5 minutes in duration.
// val selection = MediaStore.Images.Media.DATE_TAKEN + ">=? and " + MediaStore.Images.Media.DATE_TAKEN + "<=?"
// val selectionArgs = arrayOf(
// "" + startDateTimeStamp, "" + endDateTimestamp
// )
// Display images in alphabetical order based on their display name.
val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} ASC"
val query = contentResolver.query(
collection,
projection,
null,
null,
sortOrder
)
query?.use {
cursor ->
// Cache column indices.
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
val nameColumn =
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME)
val dateModifiedColumn =
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_ADDED)
val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.SIZE)
val relativePath = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)
val isFav = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
cursor.getColumnIndexOrThrow(MediaStore.Images.Media.IS_FAVORITE)
} else {
0
}
/*
val relativePathColumn =
cursor.getColumnIndex(MediaStore.Images.Media.RELATIVE_PATH)
*/
while (cursor.moveToNext()) {
// Get values of columns for a given Image.
val id = cursor.getLong(idColumn)
val name = cursor.getString(nameColumn)
val date = cursor.getString(dateModifiedColumn)
val size = cursor.getInt(sizeColumn)
val relativePath = cursor.getString(relativePath);//cursor.getInt(isFav)
val isFav = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
cursor.getInt(isFav)
}else{
0
}
/*
val album1 = cursor.getInt(album)
val albumArtist = cursor.getInt(albumArtist)
*/
val contentUri: Uri = ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
id
)
val dateTakenCalendar = date?.toLongOrNull()?.let {
val calendar = Calendar.getInstance()
calendar
}?: kotlin.run {
Calendar.getInstance()
}
I am trying to implement a recyclerview which will show all the music files in my android device with a 10 per page pagination and contains a search text. I am using content resolver for this. My application is targeting till android 12. So my existing code is like:
fun getAllMusicFilesInDevice(offset: Int, searchText: String){
val tempAudioList: MutableList<Album> = ArrayList()
val uri: Uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
else
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(
MediaStore.Audio.AudioColumns.DATA,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.AudioColumns.ALBUM,
MediaStore.Audio.ArtistColumns.ARTIST,
)
val selection = MediaStore.Audio.Media.DISPLAY_NAME + " LIKE ?"
val selectionArgs = arrayOf(searchText)
val sortOrder =
"${MediaStore.Audio.Media.DISPLAY_NAME} ASC LIMIT $PAGE_SIZE OFFSET $offset"
val c = mContext.contentResolver.query(
uri,
projection,
selection,
selectionArgs,
sortOrder
)
if (c != null) {
while (c.moveToNext()) {
try {
val path: String = c.getString(0)
val songName = c.getString(1)
val album: String = c.getString(2)
val artist: String = c.getString(3)
val extension = File(path).extension
if (isMusicFile(extension)) {
isMusicPresentInPlaylist(path, playlistDb) {
val audioModel =
Album(
name = songName,
path = path,
artist = artist,
album = album
)
tempAudioList.add(audioModel)
}
}
} catch (ex: Exception) {
}
}
c.close()
}}
This code does not give back any result and makes the app behave like its stuck. Please help me out on the mistakes I am making and anything I am doing wrong out here so that I get this function working.
UPDATE CURSOR CODE
val c = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val limit = Bundle().apply {
// Limit & Offset
putInt(ContentResolver.QUERY_ARG_LIMIT, AUDIO_PAGE_SIZE)
putInt(ContentResolver.QUERY_ARG_OFFSET, offset)
}
mContext.contentResolver.query(uri, projection, limit, null)
} else
mContext.contentResolver.query(
uri,
projection,
null,
null,
"${MediaStore.Audio.Media.DISPLAY_NAME} ASC LIMIT $AUDIO_PAGE_SIZE OFFSET $offset"
)
Note: this code is running in a background thread.
I am using DownloadManager to download a video in the Downloads directory. Once the video is downloaded, I query the download directory using MediaStore. The problem is that I am getting the video that was downloaded last to second instead of the latest one.
Video Download Code
val request = DownloadManager.Request(Uri.parse(downloadUrl))
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)
.setDestinationInExternalPublicDir(
Environment.DIRECTORY_DOWNLOADS,
"MyApp/CategoryOne/123.mp4"
)
.setTitle(fileName)
.setDescription(context.getString(R.string.all_text_downloading))
val downloadManager =
context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadID = downloadManager.enqueue(request)
var isDownloadFinished = false
var downloadProgress: Int
while (!isDownloadFinished) {
val cursor: Cursor =
downloadManager.query(DownloadManager.Query().setFilterById(downloadID))
if (cursor.moveToFirst()) {
when (cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))) {
DownloadManager.STATUS_FAILED -> {
isDownloadFinished = true
emit(State.error(context.getString(R.string.all_error_download_failed)))
}
DownloadManager.STATUS_PAUSED -> {
}
DownloadManager.STATUS_PENDING -> {
}
DownloadManager.STATUS_RUNNING -> {
val totalSizeInBytes: Long =
cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
if (totalSizeInBytes >= 0) {
val downloadedBytes: Long =
cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
downloadProgress =
(downloadedBytes * 100L / totalSizeInBytes).toInt()
emit(State.downloading(downloadProgress))
}
}
DownloadManager.STATUS_SUCCESSFUL -> {
downloadProgress = 100
emit(State.downloading(downloadProgress))
isDownloadFinished = true
val downloadedVideo = getDownloadedVideo()
emit(State.success(true))
}
}
}
}
MediaStore Code
fun getDownloadedVideo(): MediaStoreVideo {
lateinit var mediaStoreVideo: MediaStoreVideo
val projection = arrayOf(
MediaStore.Video.Media._ID,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.SIZE,
MediaStore.Video.Media.DATE_ADDED
)
val selection =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) "${MediaStore.Video.Media.RELATIVE_PATH} like ? " else "${MediaStore.Video.Media.DATA} like ? "
val selectionArgs =
arrayOf("%MyApp/CategoryOne%")
val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC"
context.contentResolver.query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
)?.use { cursor ->
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
val dateAddedColumn =
cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATE_ADDED)
val displayNameColumn =
cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)
if (cursor.moveToFirst()) {
val id = cursor.getLong(idColumn)
val contentUri = ContentUris.withAppendedId(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
id
)
val displayName = cursor.getString(displayNameColumn)
val size = cursor.getLong(sizeColumn)
val dateAdded =
Date(TimeUnit.SECONDS.toMillis(cursor.getLong(dateAddedColumn)))
mediaStoreVideo = MediaStoreVideo(id, contentUri, displayName, size, dateAdded)
}
}
return mediaStoreVideo
}
This is the approach that I have followed to get the info of the video that is last downloaded by my app using DownloadManager. Also, I am not sure if this is the best approach to do the same. Any help will be appreciated. Thanks
After a bit of testing, I think it takes a few milliseconds before the entry is added to the MediaStore. I added a delay of 1000 ms and everything works now as expected.
However, this is a temporary solution and if someone can suggest a better approach, it would be more helpful.
I am currently using the following code to load all images from the Android contentProvider in my repository:
override suspend fun getLocalImagePaths() = SuspendableResult.of<List<String>, Exception> {
val result = mutableListOf<String>()
val uri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(MediaStore.MediaColumns.DATA)
contentResolver.query(uri, projection, null, null, null)?.use {
val dataIndex = it.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA)
while (it.moveToNext()) {
result.add(it.getString(dataIndex))
}
}
result
}
This gets the absolute paths to all available images and it seems to work in Android 9, allthough some images can't be loaded (I am using Glide), but in Android 10 I can't load any of the image paths that are returned from the mentioned method. How could I do this?
override suspend fun getLocalImagePaths() = SuspendableResult.of<List<Uri>, Exception> {
val result = mutableListOf<Uri>()
val uri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(MediaStore.Images.Media._ID)
contentResolver.query(uri, projection, null, null, null)?.use {
while (it.moveToNext()) {
result.add(
ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
it.getLong(0)
)
)
}
}
result
}