Page 1 of 1

Android intent to open playlist with Media Player

Posted: 2022-12-30, 23:03 UTC
by vault
Hello everyone,
I'd like to add a button to my app that tells TC's Media Player to immediately open the playlist at

Code: Select all

/sdcard/playlist.m3u8
I'd also ideally like to empty the queue before opening the playlist, but I can't make that work either.
Can you help me with the right Java code to achieve this?

E.g. I searched the forum without much success. I tried to put together this and this:

Code: Select all

var intent = new Intent("com.ghisler.android.TotalCommander.MediaPlayerActivity");
intent.setData(Uri.parse("uri:file://exit"));
but it's not working well.

Re: Android intent to open playlist with Media Player

Posted: 2023-01-03, 09:19 UTC
by ghisler(Author)
1. To send the playlist, use the following code:

Code: Select all

var intent = new Intent("com.ghisler.android.TotalCommander.MediaPlayerActivity");
intent.setData(Uri.parse("file:///storage/emulated/0/playlist.m3u8"));
startActivity(intent);
You need to call special functions to prevent a crash when using file URLs. If your app crashes, replace the file: prefix with something else, e.g.
intent.setData(Uri.parse("data:///storage/emulated/0/playlist.m3u8"));

2. You made a little mistake in the URL to exit the player. It should be

Code: Select all

intent.setData(Uri.parse("file://exit"));
or

Code: Select all

intent.setData(Uri.parse("data://exit"));
The url: prefix is only used in the Total Commander button parameter section to tell Total Commander to add an URL via setData. The actual URL comes after this url: prefix.

Re: Android intent to open playlist with Media Player

Posted: 2023-01-04, 01:23 UTC
by vault
Do you know how to deal with the new file providers?
I'm targeting android 33 and I've replaced READ_EXTERNAL_STORAGE with READ_MEDIA_AUDIO.
Then I declared a provider in the manifest and added res/xml/file_paths.xml:

Code: Select all

<paths><external-path name="external_storage" path="."/></paths>
In the activity, I'm calculating the URI with:

Code: Select all

Uri playlistUri() {
  var playlist = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC), "list.m3u8");
  return FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", playlist);
}
and launching the intent you suggested to me:

Code: Select all

Intent tcIntent() {
  return new Intent("com.ghisler.android.TotalCommander.MediaPlayerActivity")
      // .setData(playlistUri())
      .setDataAndType(playlistUri(), "audio/x-mpegurl")
      .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
I tried all the variations of the code above (data, dataAndType, with and without flag), but I always receive:

Code: Select all

android.content.ActivityNotFoundException: No Activity found to handle Intent { act=com.ghisler.android.TotalCommander.MediaPlayerActivity dat=content://{APPLICATION_ID}.fileprovider/... typ=audio/x-mpegurl flg=0x1 }

Re: Android intent to open playlist with Media Player

Posted: 2023-01-04, 08:41 UTC
by ghisler(Author)
That's not how it works. When you send a content: URL, you either need to implement your own content provider (either a file provider or raw content provider) and then return the data to the called app when it asks for it.

Or in case of Total Commander, you know that it has access to the file system, so you can send it the file:/// or data:/// URLs directly. You should specify both the app and class, though:

Code: Select all

var intent = new Intent("com.ghisler.android.TotalCommander", "com.ghisler.android.TotalCommander.MediaPlayerActivity");

Re: Android intent to open playlist with Media Player

Posted: 2023-01-04, 10:57 UTC
by vault
The constructor

Code: Select all

Intent(String, String)
doesn't exist, and

Code: Select all

Intent(String)
is meant for actions, not packages or classes.

Here's the fixed version that at least opens Total Commander Media Player:

Code: Select all

new Intent(Intent.ACTION_VIEW)
    .setClassName(
        "com.ghisler.android.TotalCommander",
        "com.ghisler.android.TotalCommander.MediaPlayerActivity")
    .setData(Uri.parse("file:///storage/emulated/0/Music/list.m3u8"));
But with recent Android versions, you cannot use setData as you suggested:

Code: Select all

android.os.FileUriExposedException: file:///storage/emulated/0/Music/list.m3u8 exposed beyond app through Intent.getData()
That's why I started implementing the FileProvider as suggested here (avoiding the hacky solutions that disable the exception), but then the media player has problems opening the files in the m3u:

Code: Select all

java.lang.SecurityException: Permission Denial: reading androidx.core.content.FileProvider uri content://{APPLICATION_ID}.fileprovider/external_storage/Music/01.opus from pid=24667, uid=10362 requires the provider be exported, or grantUriPermission()
A few additional findings:
  • "file://exit" also triggers FileUriExposedException
  • "data://exit" triggers ActivityNotFoundException: Unable to find explicit activity class {c.g.a.TotalCommander/c.g.a.TotalCommander.MediaPlayerActivity}
  • All actions other than Intent.ACTION_VIEW (e.g. ACTION_SEND which seems to be appropriate in this case) trigger ActivityNotFoundException

Re: Android intent to open playlist with Media Player

Posted: 2023-01-06, 15:33 UTC
by ghisler(Author)
Actually you can send file URLs, you just need to tell Android to not cause an exception:

Code: Select all

	public static void disableStrictMode() {
		StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
			builder.detectNonSdkApiUsage();
		StrictMode.setVmPolicy(builder.penaltyLog().build());
	}

Re: Android intent to open playlist with Media Player

Posted: 2023-01-06, 17:50 UTC
by vault
Yes, that's the hack that I linked and that I don't want to use (BTW I think the one I linked would be safer to use than yours).
It's not safe to rely on hacks, first because well, they are hacks, and second because they might suddenly disappear in future versions.
So I guess sooner or later TC must work with File Providers. Do you know how to make them work?

Re: Android intent to open playlist with Media Player

Posted: 2023-01-09, 10:56 UTC
by ghisler(Author)
Have you tried to replace the file: prefix with something else like data: as I suggested? Don't use content: because that's reserved for content URLs.

Re: Android intent to open playlist with Media Player

Posted: 2023-01-09, 10:59 UTC
by vault
As I wrote here, "data:" triggers ActivityNotFoundException.

Re: Android intent to open playlist with Media Player

Posted: 2023-01-09, 11:07 UTC
by ghisler(Author)
You can send the content with my plugin provider prefix, e.g.:
content://com.ghisler.files/storage/emulated/0/file.m3u

Re: Android intent to open playlist with Media Player

Posted: 2023-01-09, 11:47 UTC
by vault
Oh nice, this is perfect!

Re: Android intent to open playlist with Media Player

Posted: 2023-01-09, 13:43 UTC
by ghisler(Author)
Just make sure to properly encode characters not allowed in URLs, like % # etc.