From 13881c2d43d13d23fe2fd6bd8a5a484c608afa8b Mon Sep 17 00:00:00 2001 From: vfsfitvnm Date: Sun, 12 Jun 2022 22:25:01 +0200 Subject: [PATCH] Add equalizer shortcut --- .../vimusic/services/PlayerService.kt | 8 +++ .../vimusic/ui/screens/SettingsScreen.kt | 33 ++++++++---- .../screens/settings/PlayerSettingsScreen.kt | 54 ++++++++++++++++++- 3 files changed, 84 insertions(+), 11 deletions(-) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/services/PlayerService.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/services/PlayerService.kt index a4dc1fe..7aab940 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/services/PlayerService.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/services/PlayerService.kt @@ -58,6 +58,8 @@ val DeleteSongCacheCommand = SessionCommand("DeleteSongCacheCommand", Bundle.EMP val SetSkipSilenceCommand = SessionCommand("SetSkipSilenceCommand", Bundle.EMPTY) +val GetAudioSessionIdCommand = SessionCommand("GetAudioSessionIdCommand", Bundle.EMPTY) + @ExperimentalAnimationApi @ExperimentalFoundationApi class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller, @@ -107,6 +109,8 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller, ) .build() + + player.repeatMode = preferences.repeatMode player.skipSilenceEnabled = preferences.skipSilence player.playWhenReady = true @@ -189,6 +193,7 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller, .add(GetCacheSizeCommand) .add(DeleteSongCacheCommand) .add(SetSkipSilenceCommand) + .add(GetAudioSessionIdCommand) .build() val playerCommands = Player.Commands.Builder().addAllCommands().build() return MediaSession.ConnectionResult.accept(sessionCommands, playerCommands) @@ -230,6 +235,9 @@ class PlayerService : MediaSessionService(), MediaSession.MediaItemFiller, SetSkipSilenceCommand -> { player.skipSilenceEnabled = args.getBoolean("skipSilence") } + GetAudioSessionIdCommand -> { + return Futures.immediateFuture(SessionResult(SessionResult.RESULT_SUCCESS, bundleOf("audioSessionId" to player.audioSessionId))) + } } return super.onCustomCommand(session, controller, customCommand, args) diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/SettingsScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/SettingsScreen.kt index 8245459..15fda8d 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/SettingsScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/SettingsScreen.kt @@ -188,8 +188,8 @@ fun SettingsScreen() { Entry( color = colorPalette.magenta, icon = R.drawable.play, - title = "Player", - description = "Tune the player behavior", + title = "Player & Audio", + description = "Player and audio settings", route = playerSettingsRoute, ) @@ -311,23 +311,38 @@ fun SwitchSettingEntry( } @Composable -@NonRestartableComposable fun SettingsEntry( title: String, text: String, modifier: Modifier = Modifier, - onClick: () -> Unit + onClick: () -> Unit, + isEnabled: Boolean = true ) { - BaseSettingsEntry( - title = title, - text = text, + val typography = LocalTypography.current + val colorPalette = LocalColorPalette.current + + Column( modifier = modifier .clickable( indication = rememberRipple(bounded = true), interactionSource = remember { MutableInteractionSource() }, - onClick = onClick + onClick = onClick, + enabled = isEnabled ) - ) + .padding(start = 24.dp) + .padding(horizontal = 32.dp, vertical = 16.dp) + .fillMaxWidth() + ) { + BasicText( + text = title, + style = typography.xs.semiBold.copy(color = if (isEnabled) colorPalette.text else colorPalette.darkGray), + ) + + BasicText( + text = text, + style = typography.xs.semiBold.copy(color = if (isEnabled) colorPalette.textSecondary else colorPalette.darkGray), + ) + } } @Composable diff --git a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/PlayerSettingsScreen.kt b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/PlayerSettingsScreen.kt index 2dcbdcf..fe6bbf1 100644 --- a/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/PlayerSettingsScreen.kt +++ b/app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/screens/settings/PlayerSettingsScreen.kt @@ -1,17 +1,27 @@ package it.vfsfitvnm.vimusic.ui.screens.settings +import android.content.Intent +import android.media.audiofx.AudioEffect +import android.os.Bundle +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.* import androidx.compose.foundation.layout.* import androidx.compose.foundation.text.BasicText import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.produceState import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp import androidx.core.os.bundleOf +import androidx.media3.common.C import it.vfsfitvnm.route.RouteHandler import it.vfsfitvnm.vimusic.R +import it.vfsfitvnm.vimusic.services.GetAudioSessionIdCommand import it.vfsfitvnm.vimusic.services.SetSkipSilenceCommand import it.vfsfitvnm.vimusic.ui.components.TopAppBar import it.vfsfitvnm.vimusic.ui.screens.* @@ -20,6 +30,8 @@ import it.vfsfitvnm.vimusic.ui.styling.LocalTypography import it.vfsfitvnm.vimusic.utils.LocalPreferences import it.vfsfitvnm.vimusic.utils.LocalYoutubePlayer import it.vfsfitvnm.vimusic.utils.semiBold +import kotlinx.coroutines.guava.await + @ExperimentalAnimationApi @Composable @@ -43,11 +55,32 @@ fun PlayerSettingsScreen() { } host { + val context = LocalContext.current val colorPalette = LocalColorPalette.current val typography = LocalTypography.current val preferences = LocalPreferences.current val mediaController = LocalYoutubePlayer.current?.mediaController + val activityResultLauncher = + rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { + } + + val audioSessionId by produceState(initialValue = C.AUDIO_SESSION_ID_UNSET) { + val hasEqualizer = context.packageManager.resolveActivity( + Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL), + 0 + ) != null + + println("hasEqualizer? $hasEqualizer") + + if (hasEqualizer) { + value = + mediaController?.sendCustomCommand(GetAudioSessionIdCommand, Bundle.EMPTY) + ?.await()?.extras?.getInt("audioSessionId", C.AUDIO_SESSION_ID_UNSET) + ?: C.AUDIO_SESSION_ID_UNSET + } + } + Column( modifier = Modifier .background(colorPalette.background) @@ -70,7 +103,7 @@ fun PlayerSettingsScreen() { ) BasicText( - text = "Player", + text = "Player & Audio", style = typography.m.semiBold ) @@ -96,10 +129,27 @@ fun PlayerSettingsScreen() { text = "Skip silent parts during playback", isChecked = preferences.skipSilence, onCheckedChange = { - mediaController?.sendCustomCommand(SetSkipSilenceCommand, bundleOf("skipSilence" to it)) + mediaController?.sendCustomCommand( + SetSkipSilenceCommand, + bundleOf("skipSilence" to it) + ) preferences.skipSilence = it } ) + + SettingsEntry( + title = "Equalizer", + text = "Interact with the system equalizer", + onClick = { + activityResultLauncher.launch( + Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL).apply { + putExtra(AudioEffect.EXTRA_AUDIO_SESSION, audioSessionId) + putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC) + } + ) + }, + isEnabled = audioSessionId != C.AUDIO_SESSION_ID_UNSET && audioSessionId != AudioEffect.ERROR_BAD_VALUE + ) } } }