12

In Android Q the MediaStore.Files.FileColumns.DATA field has been deprecated, and may be null or apps may not have the rights to read it, therefore is there a way to rename the filename section (not the path) of a file using only its media content Uri?

Until now the DATA field could be used to find the real path of a file from a known Uri, but since it has been deprecated then the idea is not to even try to find or resolve the real file path, and use only its content Uri.

Consider that the Uri will be in the standard media content format (not SAF format): content://media/external/images/media/123

The intention is to rename the name of the file that the Uri is pointing to.

I’m aware that I can update the MediaStore’s TITLE and DISPLAY_NAME fields, but this doesn’t change the file name, and if a user decides to move the file outside the device then this one will still have the old filename.

PerracoLabs
  • 16,449
  • 15
  • 74
  • 127
  • My guess is that this is not possible. Both with `MediaStore` and the Storage Access Framework, the filename is an implementation detail, not something that the developer sees or manipulates. The fact that the user happens to see the filename means the `MediaStore` and Storage Access Framework abstractions are a bit leaky. – CommonsWare Mar 23 '19 at 14:20
  • Tried it with [`DocumentFile.renameTo(String)`](https://developer.android.com/reference/android/support/v4/provider/DocumentFile), on a file in sdcard. It worked on emulator but implementation seems unstable, as it returned "false" despite file being renamed (or maybe it was copied and recreated with different name? - can't tell but documentation points out it might be the case). – Pawel Mar 23 '19 at 14:24
  • How did you create the DocumentFile? Please correct me if I'm wrong, but as far as I'm aware a DocumentFile can be created only from raw Files or using the fromSingleUri which requries a Uri created through SAF, and not from a media content Uri such as: content://media/external/images/media/123 – PerracoLabs Mar 23 '19 at 14:29

1 Answers1

4

Update

Hi, firstly apologies for my previous amateurish answer. But, I can't think of any direct approach to accomplish the requirement. However, there might be a workaround which, I think, is better than nothing.

The only way we can rename a file solely with a Uri is by DocumentsContract via SAF. What we've now in hand is the MediaStore Uri and We need to get the equivalent Document Uri of that file. For that we can use MediaStore.getDocumentUri( context , mediaUri ). The catch is, we need to have permission for the Document Uri before getting it, by calling this method. We can get a persistable Uri permission for the DocumentTree Uri of the mounted storage volume ( or any specific directory alone, which contains the media files we want to modify ). By doing so, now we'll have the permission for the Documents Uri of the media file and we can use DocumentsContract.renameDocument to rename that file.

Steps 1-4 will be one time things ( until manually revoked )

  1. Declare android.permission.READ_MEDIA_IMAGES permission in Manifest.
  2. Ask READ_MEDIA_IMAGES permission to the user.
  3. Ask Uri permission for DocumentTree of the storage volume which has the media file.

        StorageManager manager = getSystemService(StorageManager.class);
    
        StorageVolume primaryStorageVolume = manager.getPrimaryStorageVolume();
    
        startActivityForResult(primaryStorageVolume.createOpenDocumentTreeIntent(), STORAGE_PERMISSION_REQ_CODE);
    

But, please note that according to Android's documentation the user can select a location other than the one that we requested.

  1. onActivityResult take persistable permission of the result Uri

        if (resultCode == RESULT_OK) {
            getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        }
    
  2. Now get Documents Uri of the media file and rename it.

    Uri docUri = MediaStore.getDocumentUri( context , mediaUri );
    DocumentsContract.renameDocument(contentResolver, docUri, "newFileName.ext");
    

So basically we'll have to ask user permission twice, once for storage access and second for Uri access. Since we'll be getting a persistable Uri permission, this prompt will be a one time thing and it lasts until we revoke it. We can access all the files using it's Document Uri without having the user select it.


Previous Answer

I think we can make use of the DocumentsContract. But for that, you should request the file with Intent.ACTION_OPEN_DOCUMENT instead of Intent.GET_CONTENT. Once you have got the URI, you can rename that file using DocumentsContract.renameDocument

DocumentsContract.renameDocument(contentResolver, uri, "newFileName.ext");

But, the DocumentProvider which provided the URI should support rename function. For example, If I choose a file from Recents, rename is not supported. But, If I choose the same file with some other provider, say the default file manager, rename action will be supported. You can verify that by checking if the flag DocumentsContract.Document.FLAG_SUPPORTS_RENAME is set in the result intent.

  • Thank you for the answer. Yet it isn't the solution we are seeking for, as it would imply that besides asking for the READ_MEDIA_IMAGES permission, then we have to ask again a second time for the storage location. Nevertheless your code may be of good use to other developers seeking a different workflow, so we granted a +1 to the answer, yet we can't accept it as the solution. Thanks. – PerracoLabs Mar 27 '19 at 11:23
  • Also, Please see if [Roles](https://developer.android.com/preview/features/roles#check-default-app) could be a possibility. https://developer.android.com/preview/privacy/scoped-storage#write-to-files-created-by-other-apps – Maran Subburayan Mar 27 '19 at 13:11
  • We had a look to the Roles, but these are not shareable, meaning that only one app can be the owner of a specific Role, so giving all the broad privileges only to 1 app and leaving the rest of apps to handle as they can the new constrains. It seems like Android Q is going to be a difficult version for developers. Thank you anyway for the tip. – PerracoLabs Mar 29 '19 at 08:49
  • android.permission.READ_MEDIA_IMAGES does not exist! – Aristide13 Nov 02 '19 at 10:00
  • but android.permission.READ_EXTERNAL_STORAGE yes. – Aristide13 Nov 02 '19 at 10:00