diff --git a/demos/effect/build.gradle b/demos/effect/build.gradle
index beca6c5686..aef25c1342 100644
--- a/demos/effect/build.gradle
+++ b/demos/effect/build.gradle
@@ -74,6 +74,7 @@ dependencies {
implementation 'androidx.compose.material3:material3'
implementation 'com.google.android.material:material:' + androidxMaterialVersion
+ implementation project(modulePrefix + 'lib-exoplayer')
implementation project(modulePrefix + 'lib-ui')
// For detecting and debugging leaks only. LeakCanary is not needed for demo app to work.
diff --git a/demos/effect/src/main/AndroidManifest.xml b/demos/effect/src/main/AndroidManifest.xml
index f85a8a2ec7..5d8f7a560a 100644
--- a/demos/effect/src/main/AndroidManifest.xml
+++ b/demos/effect/src/main/AndroidManifest.xml
@@ -19,6 +19,8 @@
+
+
+ exoPlayer.apply {
+ setMediaItem(MediaItem.fromUri(uri))
+ prepare()
}
- )
- PlayerScreen()
+ }
+ PlayerScreen(exoPlayer)
Effects(
- onButtonClick = {
- coroutineScope.launch {
- snackbarHostState.showSnackbar(message = "Button is not yet implemented.")
- }
+ onException = { message ->
+ coroutineScope.launch { snackbarHostState.showSnackbar(message) }
}
)
}
@@ -83,25 +100,76 @@ class EffectActivity : ComponentActivity() {
}
@Composable
- fun InputChooser(onButtonClick: () -> Unit) {
+ fun InputChooser(onException: (String) -> Unit, onNewUri: (Uri) -> Unit) {
+ var showLocalFilePicker by remember { mutableStateOf(false) }
Row(
modifier = Modifier.padding(vertical = dimensionResource(id = R.dimen.small_padding)),
horizontalArrangement = Arrangement.spacedBy(dimensionResource(id = R.dimen.small_padding)),
) {
- Button(onClick = onButtonClick) {
+ Button(onClick = { onException("Button is not yet implemented.") }) {
Text(text = stringResource(id = R.string.choose_preset_input))
}
- Button(onClick = onButtonClick) {
+ Button(onClick = { showLocalFilePicker = true }) {
Text(text = stringResource(id = R.string.choose_local_file))
}
}
+ if (showLocalFilePicker) {
+ LocalFilePicker(
+ onException = {
+ onException(it)
+ showLocalFilePicker = false
+ }
+ ) { uri ->
+ onNewUri(uri)
+ showLocalFilePicker = false
+ }
+ }
+ }
+
+ @OptIn(UnstableApi::class)
+ @Composable
+ fun LocalFilePicker(onException: (String) -> Unit, onFileSelected: (Uri) -> Unit) {
+ val context = LocalContext.current
+ val localFilePickerLauncher =
+ rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.OpenDocument(),
+ onResult = { uri: Uri? ->
+ if (uri != null) {
+ onFileSelected(uri)
+ } else {
+ onException("File couldn't be opened. Please try again.")
+ }
+ },
+ )
+ val permissionLauncher =
+ rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.RequestPermission(),
+ onResult = { isGranted: Boolean ->
+ if (isGranted) {
+ localFilePickerLauncher.launch(arrayOf("video/*"))
+ } else {
+ onException("Permission was not granted.")
+ }
+ },
+ )
+ LaunchedEffect(Unit) {
+ val permission =
+ if (SDK_INT >= 33) Manifest.permission.READ_MEDIA_VIDEO
+ else Manifest.permission.READ_EXTERNAL_STORAGE
+ val permissionCheck = ContextCompat.checkSelfPermission(context, permission)
+ if (permissionCheck == android.content.pm.PackageManager.PERMISSION_GRANTED) {
+ localFilePickerLauncher.launch(arrayOf("video/*"))
+ } else {
+ permissionLauncher.launch(permission)
+ }
+ }
}
@Composable
- fun PlayerScreen() {
+ fun PlayerScreen(exoPlayer: ExoPlayer) {
val context = LocalContext.current
AndroidView(
- factory = { PlayerView(context).apply {} },
+ factory = { PlayerView(context).apply { player = exoPlayer } },
modifier =
Modifier.height(dimensionResource(id = R.dimen.android_view_height))
.padding(all = dimensionResource(id = R.dimen.small_padding)),
@@ -109,7 +177,9 @@ class EffectActivity : ComponentActivity() {
}
@Composable
- fun Effects(onButtonClick: () -> Unit) {
- Button(onClick = onButtonClick) { Text(text = stringResource(id = R.string.apply_effects)) }
+ fun Effects(onException: (String) -> Unit) {
+ Button(onClick = { onException("Button is not yet implemented.") }) {
+ Text(text = stringResource(id = R.string.apply_effects))
+ }
}
}