I was trying to rename a photo file in android api level > 28 (Pie) and getting java.lang.IllegalArgumentException: Primary directory WhatsApp not allowed for content://media/external/images/media/296; allowed directories are [DCIM, Pictures] exception
Below is the code for fetching images from storage
private fun getAllImages(): List<ImageModel>? {
val allImagesUri = getExternalUriForImages()
val columns = arrayOf(
MediaStore.Images.Media._ID, MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATE_ADDED, MediaStore.Images.Media.DATE_MODIFIED,
MediaStore.Images.Media.HEIGHT, MediaStore.Images.Media.WIDTH)
val cursor = application.contentResolver.query(allImagesUri, columns, null, null, null)
return prepareImageModel(cursor)
}
private fun prepareImageModel(cursor: Cursor?):List<ImageModel>?{
var images :MutableList<ImageModel>? = null
if (cursor != null && cursor.count > 0) {
images = mutableListOf()
val idColumnIndex = cursor.getColumnIndex(MediaStore.Images.Media._ID)
val nameIndex = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
val dateAddedIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED)
val dateModifiedIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATE_MODIFIED)
for (i in 0 until cursor.count) {
cursor.moveToPosition(i)
val id = cursor.getLong(idColumnIndex)
if (id != -1L) {
val name = cursor.getString(nameIndex)
val dateAdded = cursor.getString(dateAddedIndex)
val dateModified = cursor.getString(dateModifiedIndex)
val uri = ContentUris.withAppendedId(getExternalUriForImages(), id)
val imageModel = ImageModel(id, name, dateAdded, dateModified, uri = uri)
images.add(imageModel)
}
}
}
return images
}
fun getExternalUriForImages(): Uri {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL) else {
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
}
}
data class ImageModel(var id: Long, var name: String?, var dateAdded: String? = "",
var dateModified: String? = "", var resolution: String? = "", var uri: Uri)
Below is the code for renaming a file
private fun renameFile(imageModel: ImageModel?) {
if(imageModel != null){
try {
// When performing a single item update, prefer using the ID
val selection = "${MediaStore.MediaColumns._ID} = ?"
// By using selection + args we protect against improper escaping of // values.
val selectionArgs = arrayOf(imageModel.id.toString())
// Update an existing file.
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, "New name ${System.currentTimeMillis()}")
}
// Use the individual song's URI to represent the collection that's
// updated.
val rowsUpdated = contentResolver.update(imageModel.uri, contentValues, selection, selectionArgs)
Toast.makeText(this, if(rowsUpdated > 0) "Rename success" else "Rename failed", Toast.LENGTH_SHORT).show()
} catch (securityException: SecurityException) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val recoverableSecurityException = securityException as?
RecoverableSecurityException ?:
throw RuntimeException(securityException.message, securityException)
val intentSender = recoverableSecurityException.userAction.actionIntent.intentSender
intentSender?.let {
pendingImageModel = imageModel
startIntentSenderForResult(intentSender, REQUEST_RENAME_FILE, null, 0, 0, 0, null)
}
} else {
throw RuntimeException(securityException.message, securityException)
}
}
}
}
AndroidManifest file
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/Theme.SimplePhotoApp">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>