API 29 Mediastore Access
Asked Answered
N

8

18

My app creates playlists in the android mediastore. All is well for api's including 28 however, api 29 seems to require additional permissions. Inserting a new playlist name and id works without issue. When it comes to inserting track id and play order, an access permission exception is thrown. In verifying the Uri, i found that when resolver.insert for API 29 the exception error is:

java.lang.SecurityException: myapp_name has no access to content://media/external_primary/audio/media/146

The code:

Uri exturi = MediaStore.Audio.Playlists.Members.getContentUri("external", playlist_id);
// exturi : content://media/external/audio/playlists/227/members

// values : audio_id=146 play_order=0
values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, play_order);
values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, audio_id);

try {
    resolver.insert(exturi, values);
} catch (Exception e) {
    e.printStackTrace();
}

Strange thing is that although inserting a new playlist into Mediastore works but adding tracks (track_id, play order) gives an access permission error

How to resolve this exception error for API 29?

Update Feb 2021: a small step forward, I am pretty sure I need to get Documenturi for the original uri but still gives me the access error. So the issue does not lie with accessing the tracks but with the uri itself.

doc_uri = MediaStore.getDocumentUri(context,playlist_members_uri);
java.lang.SecurityException: com.flyingdutchman.newplaylistmanager has no access to content://media/external/audio/playlists/130/members
Nowhither answered 7/8, 2019 at 16:4 Comment(9)
don't use just external hard-coded, use the volume external primary.Somali
developer.android.com/training/data-storage/shared/media Try to use MediaStore.VOLUME_EXTERNAL_PRIMARY (On API <= 28, use VOLUME_EXTERNAL instead)Corbeil
@Khoa Nguyễn tried this to no availNowhither
@Nowhither Any luck? Does your phone have an SD card? (I have crash reports of this, but can't reproduce)Expectorant
I have the same issue. I can delete tracks from a playlist, but when adding I get the same exception on API 29. Have you found a solution yet? I would be very happy for help on this.Dissection
It actually seems to be a known bug in Android 10: issuetracker.google.com/issues/139964268. Starring it may help in a faster fix... it still might take a long time until it is fixed though. Does anyone know if creating playlists via m3u is affected too?Dissection
This happens to me as well when creating a new playlist. The playlist gets created, tho!Cooky
Hey @morja, I am having exact same issue. Did you found a solution to that? I can delete songs, but when I try to add I get SecurityException. Thanks!Inchon
@Inchon Hi. At the moment I do a workaround with file based m3u playlists. The system scans those and creates the playlists. The mayor downside is that the ids change every time the playlists are recreated. Thus some apps using the playlists need to be updated every time they change.Dissection
E
8

I think this is an Android 10 bug, so I've filed a report here: https://issuetracker.google.com/issues/147619577 (includes instructions for an emulator test case to reproduce it if that interests you). Please consider starring it to let the Android team know that it affects you.

From what I can tell, it only affects files on 'external' storage, like sdcards mounted on /storage/XXXX-XXXX

In the meantime, the only fix that some of my users were able to successfully apply is to move their music files to the internal storage (reboot and wait for the media scan to finish to be sure that MediaStore is up-to-date).

Expectorant answered 14/1, 2020 at 15:14 Comment(6)
Thanks i will try music on internal memoryNowhither
android 10 introduces a new storage concept: Scoped storage, If you are not comfortable with the Scoped Storage, add this flag to your manifestfile (but it's not recomanded, becuase it is going to be compulsory in next release of Android): <application android:requestLegacyExternalStorage="true"></application>Electret
@Electret The bug also affect apps targeting API 28 or using requestLegacyExternalStorage="true", so this doesn't help.Expectorant
@Expectorant not bug but this behavior affects apps targeting API 29 or +, API 28 and below works normally for me.Electret
I'd be curious to see it. Could you share a project that works?Expectorant
In API level 29, user needs to grant any actions regarding files that have been created by other apps. developer.android.com/training/data-storage/shared/mediaMahoney
N
1

in my further research for the answer, I came across this;

All about the media database (Mediastore) with android 11

Nowhither answered 16/3, 2021 at 17:2 Comment(0)
N
1

Update for android 11. Worth noting that the media database has moved from

/data/data/com.android.providers.media

to

/data/data/com.google.android.providers.media.module

also the structures have changes significantly

before android 10/11 and android 11

Nowhither answered 23/3, 2021 at 14:28 Comment(1)
I tried everything and it still won't work this way above API 28. I gave up and just made my own database using Room with Playlist and Song table. ScopedStorage ruined everything.Dewayne
S
1
  1. Create playlist with uri "MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI", and the date row in external.db for the playlist is:
_id _display_name volume_name
308 New playlist.m3u external_primary

The playlist's volume name is "external_primary".

2.

  • Music file is under flash card
  • Music file's id in external.db is 278
  • The volume name of flash card is "1EDD-DDE0"

When add this music file to playlist, got below exception:
Exception message: java.lang.SecurityException: has no access to content://media/external_primary/audio/media/278

If I create playlist with uri MediaStore.Audio.Playlists.getContentUri("1edd-dde0"), then music can be successfully added to the playlist.

It seems that the reason is the mismatch of volume name between playlist and the music file to be added. Only when playlist's volume name is same to music file's, inserting operation can be complete.

Shaveling answered 8/4, 2021 at 10:49 Comment(3)
I applied the suggestion but .... Uri uri_to_use = MediaStore.Audio.Playlists.getContentUri("0F16-2701"); -gives : content://media/0F16-2701/audio/playlists, and results in java.lang.IllegalArgumentException: Volume 0F16-2701 not foundNowhither
I mean, you should make the playlist on the same volume as the song you want to add. In your case, you should create your playlist on "0F16-2701", then you can add the songs located in "0F16-2701" to the playlist.Shaveling
I appreciate your interest. I think I did as you suggested as shown in my uri_to_use example. What I do not understand is why you would need the volume name at all as an android playlist is simply an entry with an entry_id and name in the files table with media_type=4. I started with a clean emulator, createe 1 android playlist, inspected the database. Outcome 1 entry in files but _DATA detail has .m3u appended and in the Music folder there is an empty .m3u file. If you got this to work, perhaps you have a worked example?Nowhither
L
1

I came across the same issue. As the MediaProvider changes to Google's MediaProvider, the Scoped Storage feature is activated. When you try to modify a playlist file, but it's not created by your app (or it did be created by your app, but after OTA to new Android version, which changes to use Google's MediaProvider, it scans your playlist file and put a record to its database, but leaves the owner_package_name colume empty, it's a new colume, the old MediaProvider database has no owner_package_name colume, so no one could tell this playlist file was created by you), you will get a SecurityException says you have no access to this file.

You can check if the playlist file was owned by your app before doing the 'insert' operation:

Uri uri = MediaStore.Audio.Playlists.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
String[] projection = new String[] {
        MediaStore.Audio.Playlists._ID,
        MediaStore.Audio.Playlists.NAME,
        MediaStore.Audio.Playlists.OWNER_PACKAGE_NAME,
};
String where = MediaStore.Audio.Playlists._ID + "=?";
String[] args = new String[] {playlistFileId};
Cursor cursor = resolver.query(uri, projection, where, args, null);
if (cursor != null) {
    cursor.moveToFirst();
    if (!cursor.isAfterLast()) {
        String ownerPkg = cursor.getString(
                cursor.getColumnIndex(MediaStore.Audio.Playlists.OWNER_PACKAGE_NAME));
        // print ownerPkg here
    }
}

If the owner package name of this playlist file is empty or other app's package name, that you probably have no access to write this playlist file due to the scoped storage feature limit.

According to this document, we can consider using MediaStore.createWriteRequest() method to prompt user to grant write permission to playlist file for our own app, but this request only available to certain kind of files, like images, audios, videos etc, but not for some other kinds like playlist files which ends in .m3u suffix.

Also, according to this, when you try to operate some image or audio files that's not created by your app in public storage, you will get a RecoverableSecurityException and you can use this exception to prompt user to get user consent to modify the file, but for playlist kind files, you will just get SecurityException instead of RecoverableSecurityException.

So the result is, you may never be able to access to that playlist file again, you can not modify it, and you can not delete it too. My solution is just create a new playlist file, so it's owned by my app, now I finally have full access to it. You may need to migrate your old playlist data to the new one.

Limiter answered 22/10, 2021 at 10:4 Comment(1)
"My solution is just create a new playlist file, so it's owned by my app". All playlists are created by may app but inserting into this playlist fails. I can create/delete them without any issue, inserting is the problemNowhither
N
1

AND FINALLY I FIND THIS MediaStore.Audio.Playlists This class was deprecated in API level 31. Android playlists are now deprecated. We (Google) will keep the current functionality for compatibility resons, but we will no longer take feature request. We do not advise adding new usages of Android Playlists. M3U files can be used as an alternative.

In conclusion, no longer a relevant post

Nowhither answered 30/3, 2022 at 19:19 Comment(1)
They created the bug and now won't fix it. What a surprise.Hamnet
N
0

I have implemented the SAF so do not use scopedStorage and have access once the user accepts. The fact that I can insert new playlist entries clearly shows access to MediaStore, I can also delete these. However trying to add tracks to these playlists does not work for api29. Inserting/deleting a new playlist does not involve any files located on internal or external sdcards as it is simply adding values.

the permissions for both internal and external sdcard:

2020-07-12 14:39:04.435 11858-11858/com.flyingdutchman.newplaylistmanager E/onCreate:: uriPermission: UriPermission {uri=content://com.android.externalstorage.documents/tree/17F5-240A%3A, modeFlags=3, persistedTime=1594551961263}
2020-07-12 14:39:04.435 11858-11858/com.flyingdutchman.newplaylistmanager E/onCreate:: uriPermission: UriPermission {uri=content://com.android.externalstorage.documents/tree/primary%3A, modeFlags=3, persistedTime=1594551926876}

The question now becomes

How do I ensure saf permissions are recognised by the resolver.insert method when inserting/modify tracks into the Media database

Nowhither answered 18/2, 2020 at 12:14 Comment(3)
I also have SAF implemented but when i call update on a contentresolver eg. contentResolver.update(mediaFileUri, values, null, null); it still throws a RecoverableSecurityException did you find a way that we don't need to catch that exception and request permission for each file individually? That's what i'm doing right now but i really hate it and it's a real hassle.Dewayne
@Vince VD, not any further forward. It is unbelievable that there appears to be nobody creating playlists in android 10. In the meantime android11 is around the corner and more things get deprecated. Tempting just to give upNowhither
Creating playlists seem to work on alot of mp3 players apps on the Play Store but what i noticed is that they don't insert a new playlist in the MediaStore. So i think they manage their own database with playlists and it looks like its our only option right now.Dewayne
N
0

Update May 2020

Stepping through the resolver code with debug F7

Scenario 1 results in permission error (incorrect MediaStore.VOLUME_EXTERNAL).

 playlist_uri = MediaStore.Audio.Playlists.getContentUri(MediaStore.VOLUME_EXTERNAL);
 playlist_members_uri  = MediaStore.Audio.Playlists.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)
                    .buildUpon()
                    .appendEncodedPath(Long.toString(playlist_id))
                    .appendEncodedPath("members")
                    .build();

acquireProvider(mContext, auth); = media

Uri createdRow = provider.insert(mPackageName, mAttributionTag, url, values, extras); = null

mPackageName=com.flyingdutchman.newplaylistmanager

mAttributionTag=null

values[0] = 206 values[1]=69 values[2]=1

extras=null

DatabaseUtils.java

   public static final void readExceptionFromParcel(Parcel reply) {
        int code = reply.readExceptionCode();
        if (code == 0) return;
        String msg = reply.readString();
        DatabaseUtils.readExceptionFromParcel(reply, msg, code);
    }

msg = com.flyingdutchman.newplaylistmanager has no access to content://media/external_primary/audio/playlists/206

Scenario 2 results in NO permission error BUT no tracks added to audio_playlists_map table.

 playlist_uri = MediaStore.Audio.Playlists.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
url=content://media/external_primary/audio/playlists/206/members
Nowhither answered 12/5, 2021 at 14:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.