0

I am trying to play a video which user selects from file explorer. Then it should open and start video as expected and as shown in below tutorial. But there is below error just after it. Can anyone help me out?

Tutorial: https://proandroiddev.com/learn-with-code-jetpack-compose-playing-media-part-3-3792bdfbe1ea

Code:

@Composable
fun VideoView(context: Context, mediaUri: Uri) {
    val exoPlayer = remember(context) {
        SimpleExoPlayer.Builder(context).build().apply {
            val dataSourceFactory: DataSource.Factory = DefaultDataSourceFactory(context,
                Util.getUserAgent(context, context.packageName))

            val source = ProgressiveMediaSource.Factory(dataSourceFactory)
                .createMediaSource(mediaUri)
            this.prepare(source)
            this.playWhenReady = true
        }
    }

    DisposableEffect(
        AndroidView(
            modifier =
            Modifier.testTag("VideoPlayer"),
            factory = {
                PlayerView(context).apply {
                    player = exoPlayer
                    layoutParams =
                        FrameLayout.LayoutParams(
                            ViewGroup.LayoutParams
                                .MATCH_PARENT,
                            ViewGroup.LayoutParams
                                .WRAP_CONTENT
                        )
                }
            }
        )
    ) {
        onDispose {
            // relase player when no longer needed
            exoPlayer.release()
        }
    }

}

Manifest:

<activity
 android:name=".MainActivity"
 android:exported="true"
 android:label="@string/app_name"
 android:theme="@style/Theme.Photoeditorjetpack.NoActionBar">

Error:

022-01-09 16:46:55.247 9796-10228/android.process.media E/DatabaseUtils: Writing exception to parcel
    java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaDocumentsProvider uri content://com.android.providers.media.documents/document/video:114 from pid=13515, uid=10098 requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs
        at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:634)
        at com.android.providers.media.MediaDocumentsProvider.enforceReadPermissionInner(MediaDocumentsProvider.java:184)
        at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:503)
        at android.content.ContentProvider$Transport.enforceFilePermission(ContentProvider.java:494)
        at android.content.ContentProvider$Transport.openTypedAssetFile(ContentProvider.java:422)
        at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:302)
        at android.os.Binder.execTransact(Binder.java:731)

Update: I got to know, we can't pass mediaUri since there are special characters in URI which creates issue with the passing data from one View to another while using Navigation or NavigationHost

  • How did you get the `Uri`, and what did you do with the `Uri` between when you got it and when you tried running this code? – CommonsWare Jan 09 '22 at 12:49
  • Uri is for sharing video on snapchat, but first I want to show user a preview, that's why I need it. I got it via `rememberLauncherForActivityResult` – Dishant Gandhi Jan 09 '22 at 15:13
  • Are you using the `Uri` in the same activity instance where you received it? If you passed it to another activity, or you persisted it and loaded it in a later run of your app, that would explain the problem. – CommonsWare Jan 09 '22 at 15:38
  • It is passed via Navcontroller to another screen – Dishant Gandhi Jan 09 '22 at 15:45
  • What `Intent` are you using with `rememberLauncherForActivityResult()`? – CommonsWare Jan 09 '22 at 15:47
  • `ActivityResultContracts.GetContent()` – Dishant Gandhi Jan 09 '22 at 15:48
  • Try `OpenDocument` and see if you have better luck. That is what the error message suggests (via `ACTION_OPEN_DOCUMENT`). – CommonsWare Jan 09 '22 at 15:54
  • But i just need video from there, so document intent will also allow documents – Dishant Gandhi Jan 09 '22 at 15:58
  • Supply a MIME type to limit the selection to videos, the way that (presumably) you are doing with `GetContent`. – CommonsWare Jan 09 '22 at 16:00
  • Thanks but I did tried that, below is the error code that I still receive. `java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaDocumentsProvider uri content://com.android.providers.media.documents/document/video:114 from pid=6524, uid=10098 requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs ` – Dishant Gandhi Jan 09 '22 at 16:33
  • It is not a problem compose [You need to set android:exported="true" in your AndroidManifest.xml](https://stackoverflow.com/questions/19829507/android-java-lang-securityexception-permission-denial-starting-intent) Your sample – Alexander Jan 09 '22 at 21:19
  • Does this answer your question? [Having trouble implementing ACTION\_OPEN\_DOCUMENT to my project](https://stackoverflow.com/questions/46916992/having-trouble-implementing-action-open-document-to-my-project) – Dmytro Rostopira Jan 10 '22 at 10:31
  • @DimaRostopira no that doesn't answer I had checked earlier – Dishant Gandhi Jan 11 '22 at 06:00
  • @Alexander it is already present inside the activity – Dishant Gandhi Jan 11 '22 at 06:03
  • @DishantGandhi Could you add the code with "android:export=true" to your question? – Alexander Jan 11 '22 at 10:20

3 Answers3

2

Use below method to call video in ExoPlayer and when Exit from screen then onDispose() call to stop your existing video :

@Composable
fun VideoPlayerScreen() {
    val context = LocalContext.current
    var playWhenReady by remember { mutableStateOf(true) }
    val exoPlayer = remember {
        ExoPlayer.Builder(context).build().apply {
            setMediaItem(MediaItem.fromUri("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"))
            repeatMode = ExoPlayer.REPEAT_MODE_ALL
            playWhenReady = playWhenReady
            prepare()
            play()
        }
    }
    DisposableEffect(
        AndroidView(
            modifier = Modifier.fillMaxSize(),
            factory = {
                PlayerView(context).apply {
                    player = exoPlayer
                    useController = true
                    FrameLayout.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT
                    )
                }
            }
        )
    ) {
        onDispose {
            exoPlayer.release()
        }
    }
}

If you wants to hide controls then use: useController = false

// Exoplayer Dependency
implementation 'com.google.android.exoplayer:exoplayer:2.16.1'
InsaneCat
  • 2,115
  • 5
  • 21
  • 40
0

I tried one solution/hack, the main problem was I don't know why this happens, when I pass Uri from One screen to another screen via Navigation & navController.

I used mutableStateOf() as string on first screen and then using it in another screen by updating when I am getting Uri from Action Open document.

First Screen:

val videoValue = mutableStateOf("")

Second Screen:

Uri.parse(videoValue.value)

This way I was able to get access it properly

0

How to add rotation icon in exoplayer in jetpack compose?? Or how to enable full screen mode via minimize and maximize icon in exoplayer using jetpack compose??

kshitij
  • 135
  • 1
  • 1
  • 8