TL;DR: I get the following error when I try to read a file (Uri) in a service I get the following error:
java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider
What I am trying to do:
a) read an audio file at specific time
b) have the option to stop the Media Player using the app interface (stopService())
c) make sure that even if the app is closed, the audio still gets played
How I am trying to do it:
- Select an audio file using ACTION_GET_CONTENT in Main Activity
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{ result ->if (result.resultCode == RESULT_OK) {
val data: Intent? = result.data
fileUri = data?.data!!
}
}
val intent = Intent()
.setType("audio/*")
.setAction(Intent.ACTION_GET_CONTENT)
Set an alarm using a pending intent AlarmManager, and pass the Uri (as a string) using extras to the AlarmManager
val alarmIntent = Intent(context,AlarmSetter::class.java) alarmIntent.action = "SET_ALARM" alarmIntent.putExtra("audio_path",fileUri.toString()) alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager var pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, 0) alarmManager.setAndAllowWhileIdle( AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
Call the service in the receiver and pass the Uri to the service in the intent override fun onReceive(context: Context?, intent: Intent?) {
val filePath = intent?.getStringExtra("audio_path") val musicIntent = Intent(context, MusicService::class.java) musicIntent.putExtra("audio_path",filePath) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context?.startForegroundService(musicIntent)} else{ context?.startService(musicIntent) }
Read the file in the service
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
...
notification()
...
val mp = MediaPlayer.create(this, Uri.parse(intent?.getStringExtra("audio_path")))
...
Problem:
When the App is still running, the service sends the notification is sent and the audio file is read by the media player.
However, when the app is killed/exited, the notification is sent but the file can't be read because the service does not have permission to open it.
Update: I accepted CommonsWare's answer, however I'll add the code that worked for me for clarity:
In step 2) Instead of
alarmIntent.putExtra("audio_path",fileUri.toString())
do
alarmIntent.data = fileUri
In step 3) do:
val fileUri = intent?.data
val musicIntent = Intent(context, MusicService::class.java)
musicIntent.data = fileUri
musicIntent.addFlags(FLAG_GRANT_READ_URI_PERMISSION)
musicIntent.addFlags(FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
CodePudding user response:
Replace your putExtra()
calls with setData()
calls and add addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
to each of those outbound Intent
objects. And, replace your getStringExtra()
calls with getData()
calls.
This will pass your Uri
as an actual Uri
in the "data" facet of the Intent
, and it will pass along the read permission as you traverse process and component boundaries.
See this blog post for more.