playback: rework audio focus
Rework audio focus to rely on the native ExoPlayer implementation instead of a custom implementation. Previously, we avoided ExoPlayer's AudioFocus system as it never played after a transient lost. A few versions later now through, now it does, so we may as well switch to it. This does introduce a bug where ReplayGain functionality will conflict with audio focus, but I hope to eliminate this with #115 as I switch to an AudioProcessor instead of a callback.
This commit is contained in:
parent
e54a58c612
commit
b748d73abb
37 changed files with 33 additions and 175 deletions
|
@ -5,10 +5,15 @@
|
|||
#### What's Fixed
|
||||
- Fixed incorrect ellipsizing on song items
|
||||
|
||||
#### What's Changed
|
||||
- Audio focus is no longer configurable
|
||||
|
||||
#### Dev/Meta
|
||||
- Updated translations [Konstantin Tutsch -> German, cccClyde -> Chinese ]
|
||||
- Switched to spotless and ktfmt instead of ktlint
|
||||
- Migrated constants to centralized table
|
||||
- Introduced new RecyclerView framework
|
||||
- Use native ExoPlayer AudioFocus implementation
|
||||
- Removed databinding [Greatly reduces compile times]
|
||||
- A bunch of internal view implementation improvements
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.oxycblt.auxio.coil.GenreImageFetcher
|
|||
import org.oxycblt.auxio.coil.MusicKeyer
|
||||
import org.oxycblt.auxio.settings.SettingsManager
|
||||
|
||||
/** TODO: Rework null-safety/usage of requireNotNull */
|
||||
@Suppress("UNUSED")
|
||||
class AuxioApp : Application(), ImageLoaderFactory {
|
||||
override fun onCreate() {
|
||||
|
|
|
@ -100,7 +100,7 @@ class DetailViewModel : ViewModel() {
|
|||
if (mCurrentAlbum.value?.id == id) return
|
||||
val musicStore = MusicStore.requireInstance()
|
||||
val album =
|
||||
requireNotNull(musicStore.albums.find { it.id == id }) { "Invalid album ID provided " }
|
||||
requireNotNull(musicStore.albums.find { it.id == id }) { "Invalid album id provided " }
|
||||
|
||||
mCurrentAlbum.value = album
|
||||
refreshAlbumData(album)
|
||||
|
@ -109,9 +109,7 @@ class DetailViewModel : ViewModel() {
|
|||
fun setArtistId(id: Long) {
|
||||
if (mCurrentArtist.value?.id == id) return
|
||||
val musicStore = MusicStore.requireInstance()
|
||||
val artist =
|
||||
requireNotNull(musicStore.artists.find { it.id == id }) { "Invalid artist ID provided" }
|
||||
|
||||
val artist = requireNotNull(musicStore.artists.find { it.id == id }) {}
|
||||
mCurrentArtist.value = artist
|
||||
refreshArtistData(artist)
|
||||
}
|
||||
|
@ -119,8 +117,7 @@ class DetailViewModel : ViewModel() {
|
|||
fun setGenreId(id: Long) {
|
||||
if (mCurrentGenre.value?.id == id) return
|
||||
val musicStore = MusicStore.requireInstance()
|
||||
val genre =
|
||||
requireNotNull(musicStore.genres.find { it.id == id }) { "Invalid genre ID provided" }
|
||||
val genre = requireNotNull(musicStore.genres.find { it.id == id })
|
||||
mCurrentGenre.value = genre
|
||||
refreshGenreData(genre)
|
||||
}
|
||||
|
|
|
@ -179,11 +179,12 @@ private constructor(
|
|||
override fun bind(item: Album, listener: MenuItemListener) {
|
||||
binding.parentImage.bindAlbumCover(item)
|
||||
binding.parentName.textSafe = item.resolvedName
|
||||
binding.parentInfo.textSafe = if (item.year != null) {
|
||||
binding.context.getString(R.string.fmt_number, item.year)
|
||||
} else {
|
||||
binding.context.getString(R.string.def_date)
|
||||
}
|
||||
binding.parentInfo.textSafe =
|
||||
if (item.year != null) {
|
||||
binding.context.getString(R.string.fmt_number, item.year)
|
||||
} else {
|
||||
binding.context.getString(R.string.def_date)
|
||||
}
|
||||
|
||||
binding.root.apply {
|
||||
setOnClickListener { listener.onItemClick(item) }
|
||||
|
|
|
@ -49,7 +49,7 @@ sealed class Tab(open val mode: DisplayMode) {
|
|||
|
||||
companion object {
|
||||
/** The length a well-formed tab sequence should be */
|
||||
const val SEQUENCE_LEN = 4
|
||||
private const val SEQUENCE_LEN = 4
|
||||
/** The default tab sequence, represented in integer form */
|
||||
const val SEQUENCE_DEFAULT = 0b1000_1001_1010_1011_0100
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ class PlaybackService :
|
|||
private lateinit var notificationManager: NotificationManager
|
||||
|
||||
// System backend components
|
||||
private lateinit var audioReactor: AudioReactor
|
||||
private lateinit var audioReactor: VolumeReactor
|
||||
private lateinit var widgets: WidgetController
|
||||
private val systemReceiver = PlaybackReceiver()
|
||||
|
||||
|
@ -130,10 +130,10 @@ class PlaybackService :
|
|||
.setUsage(C.USAGE_MEDIA)
|
||||
.setContentType(C.CONTENT_TYPE_MUSIC)
|
||||
.build(),
|
||||
false)
|
||||
true)
|
||||
|
||||
audioReactor =
|
||||
AudioReactor(this) { volume ->
|
||||
VolumeReactor { volume ->
|
||||
logD("Updating player volume to $volume")
|
||||
player.volume = volume
|
||||
}
|
||||
|
@ -191,7 +191,6 @@ class PlaybackService :
|
|||
player.release()
|
||||
connector.release()
|
||||
mediaSession.release()
|
||||
audioReactor.release()
|
||||
widgets.release()
|
||||
|
||||
playbackManager.removeCallback(this)
|
||||
|
@ -214,6 +213,13 @@ class PlaybackService :
|
|||
|
||||
// --- PLAYER EVENT LISTENER OVERRIDES ---
|
||||
|
||||
override fun onPlayWhenReadyChanged(playWhenReady: Boolean, reason: Int) {
|
||||
super.onPlayWhenReadyChanged(playWhenReady, reason)
|
||||
if (playbackManager.isPlaying != playWhenReady) {
|
||||
playbackManager.setPlaying(playWhenReady)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPlaybackStateChanged(state: Int) {
|
||||
when (state) {
|
||||
Player.STATE_READY -> startPolling()
|
||||
|
@ -281,7 +287,6 @@ class PlaybackService :
|
|||
override fun onPlayingUpdate(isPlaying: Boolean) {
|
||||
if (isPlaying && !player.isPlaying) {
|
||||
player.play()
|
||||
audioReactor.requestFocus()
|
||||
startPolling()
|
||||
} else {
|
||||
player.pause()
|
||||
|
|
|
@ -17,13 +17,7 @@
|
|||
|
||||
package org.oxycblt.auxio.playback.system
|
||||
|
||||
import android.content.Context
|
||||
import android.media.AudioManager
|
||||
import android.os.Build
|
||||
import androidx.core.math.MathUtils
|
||||
import androidx.media.AudioAttributesCompat
|
||||
import androidx.media.AudioFocusRequestCompat
|
||||
import androidx.media.AudioManagerCompat
|
||||
import com.google.android.exoplayer2.metadata.Metadata
|
||||
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame
|
||||
import com.google.android.exoplayer2.metadata.vorbis.VorbisComment
|
||||
|
@ -31,36 +25,24 @@ import kotlin.math.pow
|
|||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.settings.SettingsManager
|
||||
import org.oxycblt.auxio.util.getSystemServiceSafe
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
/**
|
||||
* Manages the current volume and playback state across ReplayGain and AudioFocus events.
|
||||
* Manages the current volume across ReplayGain and AudioFocus events.
|
||||
*
|
||||
* TODO: Add ReplayGain pre-amp
|
||||
*
|
||||
* TODO: Add positive ReplayGain
|
||||
* @author OxygenCobalt
|
||||
*/
|
||||
class AudioReactor(context: Context, private val callback: (Float) -> Unit) :
|
||||
AudioManager.OnAudioFocusChangeListener, SettingsManager.Callback {
|
||||
class VolumeReactor(private val callback: (Float) -> Unit) {
|
||||
private data class Gain(val track: Float, val album: Float)
|
||||
private data class GainTag(val key: String, val value: Float)
|
||||
|
||||
private val playbackManager = PlaybackStateManager.getInstance()
|
||||
private val settingsManager = SettingsManager.getInstance()
|
||||
private val audioManager = context.getSystemServiceSafe(AudioManager::class)
|
||||
|
||||
private val request =
|
||||
AudioFocusRequestCompat.Builder(AudioManagerCompat.AUDIOFOCUS_GAIN)
|
||||
.setWillPauseWhenDucked(false)
|
||||
.setAudioAttributes(
|
||||
AudioAttributesCompat.Builder()
|
||||
.setContentType(AudioAttributesCompat.CONTENT_TYPE_MUSIC)
|
||||
.setUsage(AudioAttributesCompat.USAGE_MEDIA)
|
||||
.build())
|
||||
.setOnAudioFocusChangeListener(this)
|
||||
.build()
|
||||
|
||||
private var pauseWasTransient = false
|
||||
|
||||
// It's good to keep the volume and the ducking multiplier separate so that we don't
|
||||
// lose information
|
||||
|
@ -77,23 +59,9 @@ class AudioReactor(context: Context, private val callback: (Float) -> Unit) :
|
|||
callback(volume)
|
||||
}
|
||||
|
||||
init {
|
||||
settingsManager.addCallback(this)
|
||||
}
|
||||
|
||||
/** Request the android system for audio focus */
|
||||
fun requestFocus() {
|
||||
logD("Requesting audio focus")
|
||||
AudioManagerCompat.requestAudioFocus(audioManager, request)
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the rough volume adjustment for [Metadata] with ReplayGain tags. This is based off
|
||||
* Vanilla Music's implementation.
|
||||
*
|
||||
* TODO: Add ReplayGain pre-amp
|
||||
*
|
||||
* TODO: Add positive ReplayGain
|
||||
*/
|
||||
fun applyReplayGain(metadata: Metadata?) {
|
||||
if (metadata == null) {
|
||||
|
@ -218,75 +186,9 @@ class AudioReactor(context: Context, private val callback: (Float) -> Unit) :
|
|||
}
|
||||
}
|
||||
|
||||
/** Abandon the current focus request and any callbacks */
|
||||
fun release() {
|
||||
AudioManagerCompat.abandonAudioFocusRequest(audioManager, request)
|
||||
settingsManager.removeCallback(this)
|
||||
}
|
||||
|
||||
// --- INTERNAL AUDIO FOCUS ---
|
||||
|
||||
override fun onAudioFocusChange(focusChange: Int) {
|
||||
if (!settingsManager.doAudioFocus && Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||
// Don't do audio focus if its not enabled
|
||||
return
|
||||
}
|
||||
|
||||
when (focusChange) {
|
||||
AudioManager.AUDIOFOCUS_GAIN -> onGain()
|
||||
AudioManager.AUDIOFOCUS_LOSS -> onLossPermanent()
|
||||
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> onLossTransient()
|
||||
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> onDuck()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onGain() {
|
||||
if (multiplier == MULTIPLIER_DUCK) {
|
||||
unduck()
|
||||
} else if (pauseWasTransient) {
|
||||
logD("Gained focus after transient loss")
|
||||
|
||||
// Play again if the pause was only temporary [AudioManager.AUDIOFOCUS_LOSS_TRANSIENT]
|
||||
playbackManager.setPlaying(true)
|
||||
pauseWasTransient = false
|
||||
}
|
||||
}
|
||||
|
||||
private fun onLossTransient() {
|
||||
// Since this loss is only temporary, mark it as such if we had to pause playback.
|
||||
if (playbackManager.isPlaying) {
|
||||
logD("Pausing for transient loss")
|
||||
playbackManager.setPlaying(false)
|
||||
pauseWasTransient = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun onLossPermanent() {
|
||||
logD("Pausing for permanent loss")
|
||||
playbackManager.setPlaying(false)
|
||||
}
|
||||
|
||||
private fun onDuck() {
|
||||
multiplier = MULTIPLIER_DUCK
|
||||
logD("Ducked volume, now $volume")
|
||||
}
|
||||
|
||||
private fun unduck() {
|
||||
multiplier = 1f
|
||||
logD("Unducked volume, now $volume")
|
||||
}
|
||||
|
||||
// --- SETTINGS MANAGEMENT ---
|
||||
|
||||
override fun onAudioFocusUpdate(focus: Boolean) {
|
||||
if (!focus) {
|
||||
onGain()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MULTIPLIER_DUCK = 0.2f
|
||||
|
||||
const val RG_TRACK = "REPLAYGAIN_TRACK_GAIN"
|
||||
const val RG_ALBUM = "REPLAYGAIN_ALBUM_GAIN"
|
||||
const val R128_TRACK = "R128_TRACK_GAIN"
|
|
@ -94,10 +94,6 @@ class SettingsManager private constructor(context: Context) :
|
|||
val roundCovers: Boolean
|
||||
get() = prefs.getBoolean(KEY_ROUND_COVERS, false)
|
||||
|
||||
/** Whether to do Audio focus. */
|
||||
val doAudioFocus: Boolean
|
||||
get() = prefs.getBoolean(KEY_AUDIO_FOCUS, true)
|
||||
|
||||
/** Whether to resume playback when a headset is connected (may not work well in all cases) */
|
||||
val headsetAutoplay: Boolean
|
||||
get() = prefs.getBoolean(KEY_HEADSET_AUTOPLAY, false)
|
||||
|
@ -239,7 +235,6 @@ class SettingsManager private constructor(context: Context) :
|
|||
KEY_SHOW_COVERS -> callbacks.forEach { it.onShowCoverUpdate(showCovers) }
|
||||
KEY_QUALITY_COVERS -> callbacks.forEach { it.onQualityCoverUpdate(useQualityCovers) }
|
||||
KEY_LIB_TABS -> callbacks.forEach { it.onLibTabsUpdate(libTabs) }
|
||||
KEY_AUDIO_FOCUS -> callbacks.forEach { it.onAudioFocusUpdate(doAudioFocus) }
|
||||
KEY_REPLAY_GAIN -> callbacks.forEach { it.onReplayGainUpdate(replayGainMode) }
|
||||
}
|
||||
}
|
||||
|
@ -255,7 +250,6 @@ class SettingsManager private constructor(context: Context) :
|
|||
fun onNotifActionUpdate(useAltAction: Boolean) {}
|
||||
fun onShowCoverUpdate(showCovers: Boolean) {}
|
||||
fun onQualityCoverUpdate(doQualityCovers: Boolean) {}
|
||||
fun onAudioFocusUpdate(focus: Boolean) {}
|
||||
fun onReplayGainUpdate(mode: ReplayGainMode) {}
|
||||
}
|
||||
|
||||
|
@ -272,7 +266,6 @@ class SettingsManager private constructor(context: Context) :
|
|||
const val KEY_ROUND_COVERS = "auxio_round_covers"
|
||||
const val KEY_USE_ALT_NOTIFICATION_ACTION = "KEY_ALT_NOTIF_ACTION"
|
||||
|
||||
const val KEY_AUDIO_FOCUS = "KEY_AUDIO_FOCUS"
|
||||
const val KEY_HEADSET_AUTOPLAY = "auxio_headset_autoplay"
|
||||
const val KEY_REPLAY_GAIN = "auxio_replay_gain"
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ val Drawable.isRtl: Boolean
|
|||
val ViewBinding.context: Context
|
||||
get() = root.context
|
||||
|
||||
var TextView.textSafe
|
||||
var TextView.textSafe: CharSequence
|
||||
get() = text
|
||||
set(value) {
|
||||
text = value
|
||||
|
|
|
@ -68,7 +68,6 @@ class WidgetProvider : AppWidgetProvider() {
|
|||
}
|
||||
|
||||
loadWidgetBitmap(context, song) { bitmap ->
|
||||
logD(bitmap == null)
|
||||
val state =
|
||||
WidgetState(
|
||||
song,
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorSurface"
|
||||
android:orientation="vertical"
|
||||
tools:context=".settings.AboutFragment">
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
android:id="@+id/queue_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.oxycblt.auxio.ui.EdgeAppBarLayout
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
android:id="@+id/settings_coordinator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/colorSurface"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.oxycblt.auxio.ui.EdgeAppBarLayout
|
||||
|
|
|
@ -2,10 +2,8 @@
|
|||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorSurface">
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<View
|
||||
android:id="@+id/background"
|
||||
|
|
|
@ -81,8 +81,6 @@
|
|||
<string name="set_alt_shuffle">تفضيل نشاط الخلط</string>
|
||||
|
||||
<string name="set_audio">صوتيات</string>
|
||||
<string name="set_focus">تركيز الصوت</string>
|
||||
<string name="set_focus_desc">ايقاف مؤقت عند تشغيل صوت آخر (كالمكالمات)</string>
|
||||
<string name="set_replay_gain">صخب الصوت (تجريبي)</string>
|
||||
<string name="set_off">اطفاء</string>
|
||||
<string name="set_replay_gain_track">تفضيل المقطع</string>
|
||||
|
|
|
@ -65,8 +65,6 @@
|
|||
<string name="set_alt_loop">"Preferovat akci režimu opakování"</string>
|
||||
<string name="set_alt_shuffle">"Preferovat akci náhodného přehrávání"</string>
|
||||
<string name="set_audio">"Zvuk"</string>
|
||||
<string name="set_focus">"Zaměření zvuku"</string>
|
||||
<string name="set_focus_desc">Pozastavit při přehrávání jiného zvuku (např. hovor)</string>
|
||||
<string name="set_behavior">"Chování"</string>
|
||||
<string name="set_song_mode">"Když je vybrána skladba"</string>
|
||||
<string name="set_keep_shuffle">"Zapamatovat si náhodné přehrávání"</string>
|
||||
|
|
|
@ -71,8 +71,6 @@
|
|||
<string name="set_alt_shuffle">Zufällig-Aktionstaste bevorzugen</string>
|
||||
|
||||
<string name="set_audio">Audio</string>
|
||||
<string name="set_focus">Audiofokus</string>
|
||||
<string name="set_focus_desc">Pausieren wenn andere Töne abspielt wird [Bsp. Anrufe]</string>
|
||||
<string name="set_headset_autoplay">Kopfhörer automatische Wiedergabe</string>
|
||||
<string name="set_headset_autoplay_desc">Beginne die Wiedergabe immer, wenn Kopfhörer verbunden sind (funktioniert nicht auf allen Geräten)</string>
|
||||
<string name="set_replay_gain">ReplayGain (Experimentell)</string>
|
||||
|
|
|
@ -81,8 +81,6 @@
|
|||
<string name="set_alt_shuffle">Preferir acción de mezcla</string>
|
||||
|
||||
<string name="set_audio">Sonido</string>
|
||||
<string name="set_focus">Enfoque de sonido</string>
|
||||
<string name="set_focus_desc">Pausar cuando se reproduce otro sonido (Ej: llamadas)</string>
|
||||
<string name="set_replay_gain">ReplayGain (Experimental)</string>
|
||||
<string name="set_off">Desactivado</string>
|
||||
<string name="set_replay_gain_track">Por pista</string>
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
<string name="set_quality_covers">Ignorer le stockage des pochettes</string>
|
||||
|
||||
<string name="set_audio">Audio</string>
|
||||
<string name="set_focus">Audio Focus</string>
|
||||
|
||||
<string name="set_behavior">Comportement</string>
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
<string name="set_accent">एक्सेंट</string>
|
||||
|
||||
<string name="set_audio">ऑडियो</string>
|
||||
<string name="set_focus">ऑडियो फोकस</string>
|
||||
|
||||
<string name="set_behavior">चाल चलन</string>
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
<string name="set_quality_covers">A médiatár albumborítók figyelmen kívül hagyása</string>
|
||||
|
||||
<string name="set_audio">Hang</string>
|
||||
<string name="set_focus">Hangfókusz</string>
|
||||
|
||||
<string name="set_behavior">Működés</string>
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
<string name="set_quality_covers">Abaikan sampul-sampul pada Media Penyimpanan</string>
|
||||
|
||||
<string name="set_audio">Audio</string>
|
||||
<string name="set_focus">Fokus audio</string>
|
||||
|
||||
<string name="set_behavior">Perilaku</string>
|
||||
<string name="set_keep_shuffle">Ingat putar acak</string>
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
<string name="set_quality_covers">Ignora le copertine del Media Store</string>
|
||||
|
||||
<string name="set_audio">Audio</string>
|
||||
<string name="set_focus">Focus audio</string>
|
||||
|
||||
<string name="set_behavior">Comportamento</string>
|
||||
<string name="set_keep_shuffle">Ricorda casuale</string>
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
<string name="set_quality_covers">미디어 스토어 앨범 커버 무시</string>
|
||||
|
||||
<string name="set_audio">오디오</string>
|
||||
<string name="set_focus">오디오 포커스</string>
|
||||
|
||||
<string name="set_behavior">동작</string>
|
||||
|
||||
|
|
|
@ -70,8 +70,6 @@
|
|||
<string name="set_alt_shuffle">Voorkeur aan shuffle actie</string>
|
||||
|
||||
<string name="set_audio">Audio</string>
|
||||
<string name="set_focus">Audiofocus</string>
|
||||
<string name="set_focus_desc">Pauze wanneer andere audio speelt (ex. Gesprekken)</string>
|
||||
|
||||
<string name="set_behavior">Gedrag</string>
|
||||
<string name="set_song_mode">Wanneer een liedje is geselecteerd</string>
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
<string name="set_quality_covers">Ignoruj okładki z Media Store</string>
|
||||
|
||||
<string name="set_audio">Dźwięk</string>
|
||||
<string name="set_focus">Wyciszanie otoczenia</string>
|
||||
|
||||
<string name="set_behavior">Zachowanie</string>
|
||||
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
<string name="set_quality_covers">Ignorar capas Media Store</string>
|
||||
|
||||
<string name="set_audio">Áudio</string>
|
||||
<string name="set_focus">Foco do áudio</string>
|
||||
|
||||
<string name="set_behavior">Comportamento</string>
|
||||
<string name="set_keep_shuffle">Memorizar aleatorização</string>
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
<string name="set_quality_covers">Ignorar capas Media Store</string>
|
||||
|
||||
<string name="set_audio">Áudio</string>
|
||||
<string name="set_focus">Foco de áudio</string>
|
||||
|
||||
<string name="set_behavior">Comportamento</string>
|
||||
<string name="set_keep_shuffle">Memorizar aleatorização</string>
|
||||
|
|
|
@ -49,7 +49,6 @@
|
|||
<string name="set_quality_covers">Ignoră coperțile Media Store</string>
|
||||
|
||||
<string name="set_audio">Audio</string>
|
||||
<string name="set_focus">Concentrare audio</string>
|
||||
|
||||
<string name="set_behavior">Comportament</string>
|
||||
|
||||
|
|
|
@ -81,8 +81,6 @@
|
|||
<string name="set_alt_shuffle">Режим перемешивания</string>
|
||||
|
||||
<string name="set_audio">Звук</string>
|
||||
<string name="set_focus">Аудио-фокус</string>
|
||||
<string name="set_focus_desc">Ставить на паузу при звонках</string>
|
||||
<string name="set_replay_gain">ReplayGain (экспериментально)</string>
|
||||
<string name="set_off">Выкл.</string>
|
||||
<string name="set_replay_gain_track">По треку</string>
|
||||
|
|
|
@ -48,7 +48,6 @@
|
|||
<string name="set_quality_covers">Medya Deposu albüm kapağını yoksay</string>
|
||||
|
||||
<string name="set_audio">Ses</string>
|
||||
<string name="set_focus">Ses odaklama</string>
|
||||
|
||||
<string name="set_behavior">Tercihler</string>
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<bool name="enable_theme_settings">false</bool>
|
||||
<bool name="enable_audio_focus_setting">false</bool>
|
||||
</resources>
|
|
@ -80,8 +80,6 @@
|
|||
<string name="set_alt_shuffle">偏好随机播放操作</string>
|
||||
|
||||
<string name="set_audio">音频</string>
|
||||
<string name="set_focus">音频焦点</string>
|
||||
<string name="set_focus_desc">有其它音频播放(比如电话)时暂停</string>
|
||||
<string name="set_headset_autoplay">自动播放</string>
|
||||
<string name="set_headset_autoplay_desc">连接至耳机时总是自动播放(并非在所有设备上都有用)</string>
|
||||
<string name="set_replay_gain">回放增益(实验性)</string>
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
<string name="set_quality_covers">忽略音訊檔內嵌的專輯封面</string>
|
||||
|
||||
<string name="set_audio">音訊</string>
|
||||
<string name="set_focus">音頻焦點</string>
|
||||
|
||||
<string name="set_behavior">行為</string>
|
||||
<string name="set_keep_shuffle">記住隨機播放</string>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<bool name="enable_theme_settings">true</bool>
|
||||
<bool name="enable_audio_focus_setting">true</bool>
|
||||
<integer name="recycler_spans">1</integer>
|
||||
</resources>
|
||||
|
|
|
@ -80,8 +80,6 @@
|
|||
<string name="set_alt_shuffle">Prefer shuffle action</string>
|
||||
|
||||
<string name="set_audio">Audio</string>
|
||||
<string name="set_focus">Audio focus</string>
|
||||
<string name="set_focus_desc">Pause when other audio plays (ex. Calls)</string>
|
||||
<string name="set_headset_autoplay">Headset autoplay</string>
|
||||
<string name="set_headset_autoplay_desc">Always start playing when a headset is connected (may not work on all devices)</string>
|
||||
<string name="set_replay_gain">ReplayGain (Experimental)</string>
|
||||
|
|
|
@ -78,14 +78,6 @@
|
|||
app:layout="@layout/item_header"
|
||||
app:title="@string/set_audio">
|
||||
|
||||
<org.oxycblt.auxio.settings.pref.M3SwitchPreference
|
||||
app:defaultValue="true"
|
||||
app:iconSpaceReserved="false"
|
||||
app:isPreferenceVisible="@bool/enable_audio_focus_setting"
|
||||
app:key="KEY_AUDIO_FOCUS"
|
||||
app:summary="@string/set_focus_desc"
|
||||
app:title="@string/set_focus" />
|
||||
|
||||
<org.oxycblt.auxio.settings.pref.M3SwitchPreference
|
||||
app:defaultValue="false"
|
||||
app:iconSpaceReserved="false"
|
||||
|
|
Loading…
Reference in a new issue