How to rename image from gallery and save it? - android

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.

Related

Android fetch all music files And display in the list

I am having difficulty in importing music files in android. Problem is: I want to get all the music on the phone, but it doesn't work, only some of them are coming.
Hello, I am having difficulty in importing music files in android. Problem is: I want to get all the music on the phone, but it doesn't work, only some of them are coming.Why not coming ?
val arrayList: ArrayList<AudioModel> = ArrayList<AudioModel>()
val projection = arrayOf(
Audio.Media._ID,
Audio.Media.DISPLAY_NAME,
Audio.Media.DURATION,
Audio.Media.SIZE
)
val selection = Audio.Media.DISPLAY_NAME +
" >= ?"
val selectionArgs = arrayOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MINUTES).toString())
val sortOrder = Audio.Media.DISPLAY_NAME + " ASC"
val cursor: Cursor? = activity?.contentResolver?.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
)
val idColumn = cursor!!.getColumnIndexOrThrow(Audio.Media._ID)
val nameColumn = cursor!!.getColumnIndexOrThrow(Audio.Media.DISPLAY_NAME)
val durationColumn = cursor!!.getColumnIndexOrThrow(Audio.Media.DURATION)
val sizeColumn = cursor!!.getColumnIndexOrThrow(Audio.Media.SIZE)
while (cursor.moveToNext()) {
val id = cursor.getLong(idColumn)
val name = cursor.getString(nameColumn)
val duration = cursor.getInt(durationColumn)
val size = cursor.getInt(sizeColumn)
val contentUri = ContentUris.withAppendedId(
Audio.Media.EXTERNAL_CONTENT_URI, id
)
// Stores column values and the contentUri in a local object
// that represents the media file.
arrayList.add(AudioModel(contentUri.toString(),name,duration))
}

List all music files in all android devices with where, limit and offset clauses

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.

code 2067 SQLITE_CONSTRAINT_UNIQUE when working with Android MediaStorage

The following code is used to save files from the app to downloads:
Uri collection = MediaStore.Downloads.EXTERNAL_CONTENT_URI;
ContentValues values = new ContentValues();
values.put(MediaStore.Downloads.DISPLAY_NAME, filename);
values.put(MediaStore.Downloads.MIME_TYPE, mimeType);
values.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
ContentResolver contentResolver = context.getApplicationContext().getContentResolver();
Uri uri = contentResolver.insert(collection, values);
OutputStream outputStream = context.getApplicationContext().getContentResolver().openOutputStream(uri, "w");
Everything is saved, however, if you delete the file from downloads manually, and then try to download it again from the application, an error appears:
android.database.sqlite.SQLiteConstraintException: UNIQUE constraint failed: files._data (code 2067 SQLITE_CONSTRAINT_UNIQUE[2067])
Is there a way to fix this or will I have to use unique names for each download?
This error happens because the machanism of OS: if we delete manually a file (media), its database will not be deleted immediately. Until we restart device.
Have a approach for this problem (still not be optimized - hope receiving sharing from people), such as:
Step 1: Get info of file via its name
Step 2: Ask OS to update its database via MediaScannerConnection.scanFile
Step 3: Use current code that has above problem
Codes for steps (collected on internet)
Step 1:
fun findByFileName(fileName: String): MutableList<FileInfo> {
val files = mutableListOf<FileInfo>()
val collection =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
} else {
MediaStore.Video.Media.EXTERNAL_CONTENT_URI
}
val projection = arrayOf(
MediaStore.Video.Media._ID,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.DURATION,
MediaStore.Video.Media.SIZE,
MediaStore.Video.Media.DATA
)
val selection = "${MediaStore.Video.Media.DISPLAY_NAME} LIKE ?"
val selectionArgs = arrayOf(
fileName
)
// Display videos in alphabetical order based on their display name.
val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC"
val query = context.contentResolver.query(
collection,
projection,
selection,
selectionArgs,
sortOrder
)
query?.use { cursor ->
// Cache column indices.
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
val nameColumn =
cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
val durationColumn =
cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION)
val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)
val dataColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA)
while (cursor.moveToNext()) {
// Get values of columns for a given video.
val id = cursor.getLong(idColumn)
val name = cursor.getString(nameColumn)
val duration = cursor.getInt(durationColumn)
val size = cursor.getInt(sizeColumn)
val data = cursor.getStringOrNull(dataColumn)
val contentUri: Uri = ContentUris.withAppendedId(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
id
)
// Stores column values and the contentUri in a local object
// that represents the media file.
files += FileInfo(contentUri, name, duration, size, data)
}
}
return files
}
data class FileInfo(
val uri: Uri,
val name: String,
val duration: Int,
val size: Int,
val data: String? = null
)
Step 2 + Step 3:
val exitedData = findByFileName(fileName = name)
if (exitedData != null) {
MediaScannerConnection.scanFile(context, arrayOf(exitedData.first().data.toString()), null, object: MediaScannerConnection.OnScanCompletedListener {
override fun onScanCompleted(path: String?, uri: Uri?) {
// Step 3
// Use current code have this problem
...
}
}
} else {
// Save file normally
// Use current code have this problem
...
}

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

Unable to retrieve latest downloaded Video using MediaStore

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.

Categories

Resources