Rename file of the Mediastore which is created by app in android 10. Working on Android API 30 but shows error in API 29
Asked Answered
D

3

6

Here, this renameFile(..) func is working in Android API 30. But, it is not working in Android API 29 and shows the error like :

java.lang.IllegalArgumentException: Movement of content://media/external/file/116 which isn't part of well-defined collection not allowed

Update-Note:

---Begins---

In-order to work with sdk-29 we have to use Uri as extUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL) like:

private static Uri extUri = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL);

in place of below code. And also update MediaStore.Files.FileColumns to MediaStore.Downloads

---Ends---

Uri extUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
String relativeLocation = Environment.DIRECTORY_DOWNLOADS + File.separator + "AppFolder";

function renameFile(...)

boolean renameFile(Context context, String newName, String displayName) {

    try {
        Long id = getIdFromDisplayName(displayName);
        ContentResolver contentResolver = context.getContentResolver();
        Uri mUri = ContentUris.withAppendedId(extUri, id);
        ContentValues contentValues = new ContentValues();

        contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
        contentResolver.update(mUri, contentValues, null, null);

        contentValues.clear();
        contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, newName);
        // contentValues.put(MediaStore.Files.FileColumns.MIME_TYPE, "files/pdf");
        // contentValues.put(MediaStore.Files.FileColumns.RELATIVE_PATH, relativeLocation);
        // contentValues.put(MediaStore.Files.FileColumns.TITLE, "SomeName");
        // contentValues.put(MediaStore.Files.FileColumns.DATE_ADDED, System.currentTimeMillis() / 1000);
        // contentValues.put(MediaStore.Files.FileColumns.DATE_TAKEN, System.currentTimeMillis());
        contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
        contentResolver.update(mUri, contentValues, null, null);
        return true;
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return false;
}

function getIdFromDisplayName(...)

@RequiresApi(api = Build.VERSION_CODES.Q)
Long getIdFromDisplayName(String displayName) {
    String[] projection;
    projection = new String[]{MediaStore.Files.FileColumns._ID};

    // TODO This will break if we have no matching item in the MediaStore.
    Cursor cursor = getContentResolver().query(extUri, projection,
            MediaStore.Files.FileColumns.DISPLAY_NAME + " LIKE ?", new String[]{displayName}, null);
    assert cursor != null;
    cursor.moveToFirst();

    if (cursor.getCount() > 0) {
        int columnIndex = cursor.getColumnIndex(projection[0]);
        long fileId = cursor.getLong(columnIndex);

        cursor.close();
        return fileId;
    }
    return null;
}
Daviddavida answered 23/8, 2020 at 4:32 Comment(1)
Meanwhile you could read: #55314976Unbreathed
U
6

java.lang.IllegalArgumentException: Movement of content://media/external/file/116 which isn't part of well-defined collection not allowed

So it is for Android Q not allowed if you use the collection;

Uri extUri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);

But is is allowed for a 'well-defined collection' like:

Uri extUri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
// Use  "Pictures/MyFolder" for RELATIVE_PATH

I leave it to you to find other well-defined collections.

Why this is only for Android Q i dont know.

You can see the message in the java file: https://android.googlesource.com/platform/packages/providers/MediaProvider/+/refs/heads/master/src/com/android/providers/media/MediaProvider.java

Quote:

     // We only support movement under well-defined collections
        switch (match) {
            case AUDIO_MEDIA_ID:
            case VIDEO_MEDIA_ID:
            case IMAGES_MEDIA_ID:
            case DOWNLOADS_ID:
                break;
            default:
                throw new IllegalArgumentException("Movement of " + uri
                        + " which isn't part of well-defined collection not allowed");
        }

If the rename fails use SAF (as mentioned before). How to rename a file in Android knowing only its media content Uri

Unbreathed answered 26/8, 2020 at 14:18 Comment(0)
T
1

I think it's a system bug in Android 10 mediaprovider. In android 10,it is like this

       // We only support movement under well-defined collections
        switch (match) {
            case AUDIO_MEDIA_ID:
            case VIDEO_MEDIA_ID:
            case IMAGES_MEDIA_ID:
            case DOWNLOADS_ID:
                break;
            default:
                throw new IllegalArgumentException("Movement of " + uri
                        + " which isn't part of well-defined collection not allowed");
        }

in Android 11,it is like this

        final boolean allowMovement = extras.getBoolean(MediaStore.QUERY_ARG_ALLOW_MOVEMENT,
            !isCallingPackageSelf());
    if (containsAny(initialValues.keySet(), sPlacementColumns)
            && !initialValues.containsKey(MediaColumns.DATA)
            && !isThumbnail
            && allowMovement) {
        Trace.beginSection("movement");
        // We only support movement under well-defined collections
        switch (match) {
            case AUDIO_MEDIA_ID:
            case AUDIO_PLAYLISTS_ID:
            case VIDEO_MEDIA_ID:
            case IMAGES_MEDIA_ID:
            case DOWNLOADS_ID:
            case FILES_ID:
                break;
            default:
                throw new IllegalArgumentException("Movement of " + uri
                        + " which isn't part of well-defined collection not allowed");
        }
Tineid answered 20/3, 2023 at 7:23 Comment(0)
P
0

I had to face the rename problem myself (Android 29) and the solution above did not suffice.

This was because I had a physical SD card on which were located the files I wanted to rename.

Then, instruction:

extUri = MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);

did not work; instead,I had to:

  1. list the "external volumes"(according to Android terms)

    Set<String> lVls = MediaStore.getExternalVolumeNames(this);
    

    ..which gave me 2 volumes:

    "external_primary"    (the built-in external storage)
    "bc21-eafa"           (the SD card external storage)
    
  2. Initialize 'extUri' with that second value, like that:

    extUri = MediaStore.Audio.Media.getContentUri("bc21-eafa");
    
  3. Apply the rest of the procedure as described in this article. Thanks to all !

Pentylenetetrazol answered 17/1, 2022 at 15:12 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Oyler

© 2022 - 2024 — McMap. All rights reserved.