Add option to resume playback when a device is connected (#497)
This commit is contained in:
parent
bb4c9ada73
commit
fd54a4c483
4 changed files with 69 additions and 0 deletions
|
@ -1,6 +1,7 @@
|
|||
package it.vfsfitvnm.vimusic.service
|
||||
|
||||
import android.os.Binder as AndroidBinder
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Notification
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
|
@ -14,6 +15,9 @@ import android.content.res.Configuration
|
|||
import android.database.SQLException
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import android.media.AudioDeviceCallback
|
||||
import android.media.AudioDeviceInfo
|
||||
import android.media.AudioManager
|
||||
import android.media.MediaMetadata
|
||||
import android.media.audiofx.AudioEffect
|
||||
import android.media.session.MediaSession
|
||||
|
@ -87,12 +91,14 @@ import it.vfsfitvnm.vimusic.utils.forceSeekToPrevious
|
|||
import it.vfsfitvnm.vimusic.utils.getEnum
|
||||
import it.vfsfitvnm.vimusic.utils.intent
|
||||
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid13
|
||||
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid6
|
||||
import it.vfsfitvnm.vimusic.utils.isInvincibilityEnabledKey
|
||||
import it.vfsfitvnm.vimusic.utils.isShowingThumbnailInLockscreenKey
|
||||
import it.vfsfitvnm.vimusic.utils.mediaItems
|
||||
import it.vfsfitvnm.vimusic.utils.persistentQueueKey
|
||||
import it.vfsfitvnm.vimusic.utils.preferences
|
||||
import it.vfsfitvnm.vimusic.utils.queueLoopEnabledKey
|
||||
import it.vfsfitvnm.vimusic.utils.resumePlaybackWhenDeviceConnectedKey
|
||||
import it.vfsfitvnm.vimusic.utils.shouldBePlaying
|
||||
import it.vfsfitvnm.vimusic.utils.skipSilenceKey
|
||||
import it.vfsfitvnm.vimusic.utils.timer
|
||||
|
@ -148,6 +154,9 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
|||
private var isShowingThumbnailInLockscreen = true
|
||||
override var isInvincibilityEnabled = false
|
||||
|
||||
private var audioManager: AudioManager? = null
|
||||
private var audioDeviceCallback: AudioDeviceCallback? = null
|
||||
|
||||
private val binder = Binder()
|
||||
|
||||
private var isNotificationStarted = false
|
||||
|
@ -248,6 +257,8 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
|||
}
|
||||
|
||||
registerReceiver(notificationActionReceiver, filter)
|
||||
|
||||
maybeResumePlaybackWhenDeviceConnected()
|
||||
}
|
||||
|
||||
override fun onTaskRemoved(rootIntent: Intent?) {
|
||||
|
@ -443,6 +454,42 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
|||
mediaSession.setMetadata(metadataBuilder.build())
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private fun maybeResumePlaybackWhenDeviceConnected() {
|
||||
if (!isAtLeastAndroid6) return
|
||||
|
||||
if (preferences.getBoolean(resumePlaybackWhenDeviceConnectedKey, false)) {
|
||||
if (audioManager == null) {
|
||||
audioManager = getSystemService(AUDIO_SERVICE) as AudioManager?
|
||||
}
|
||||
|
||||
audioDeviceCallback = object : AudioDeviceCallback() {
|
||||
private fun canPlayMusic(audioDeviceInfo: AudioDeviceInfo): Boolean {
|
||||
if (!audioDeviceInfo.isSink) return false
|
||||
|
||||
return audioDeviceInfo.type == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP ||
|
||||
audioDeviceInfo.type == AudioDeviceInfo.TYPE_WIRED_HEADSET ||
|
||||
audioDeviceInfo.type == AudioDeviceInfo.TYPE_WIRED_HEADPHONES ||
|
||||
audioDeviceInfo.type == AudioDeviceInfo.TYPE_USB_HEADSET
|
||||
}
|
||||
|
||||
override fun onAudioDevicesAdded(addedDevices: Array<AudioDeviceInfo>) {
|
||||
if (!player.isPlaying && addedDevices.any(::canPlayMusic)) {
|
||||
player.play()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAudioDevicesRemoved(removedDevices: Array<AudioDeviceInfo>) = Unit
|
||||
}
|
||||
|
||||
audioManager?.registerAudioDeviceCallback(audioDeviceCallback, handler)
|
||||
|
||||
} else {
|
||||
audioManager?.unregisterAudioDeviceCallback(audioDeviceCallback)
|
||||
audioDeviceCallback = null
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendOpenEqualizerIntent() {
|
||||
sendBroadcast(
|
||||
Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION).apply {
|
||||
|
@ -535,6 +582,8 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
|||
maybeNormalizeVolume()
|
||||
}
|
||||
|
||||
resumePlaybackWhenDeviceConnectedKey -> maybeResumePlaybackWhenDeviceConnected()
|
||||
|
||||
isInvincibilityEnabledKey -> isInvincibilityEnabled =
|
||||
sharedPreferences.getBoolean(key, isInvincibilityEnabled)
|
||||
|
||||
|
@ -868,6 +917,7 @@ class PlayerService : InvincibleService(), Player.Listener, PlaybackStatsListene
|
|||
|
||||
private class NotificationActionReceiver(private val player: Player) : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
println(intent.action)
|
||||
when (intent.action) {
|
||||
Action.pause.value -> player.pause()
|
||||
Action.play.value -> player.play()
|
||||
|
|
|
@ -24,8 +24,11 @@ import androidx.compose.foundation.layout.only
|
|||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid13
|
||||
import it.vfsfitvnm.vimusic.utils.isAtLeastAndroid6
|
||||
import it.vfsfitvnm.vimusic.utils.persistentQueueKey
|
||||
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||
import it.vfsfitvnm.vimusic.utils.resumePlaybackWhenDeviceConnectedKey
|
||||
import it.vfsfitvnm.vimusic.utils.skipSilenceKey
|
||||
import it.vfsfitvnm.vimusic.utils.volumeNormalizationKey
|
||||
|
||||
|
@ -37,6 +40,7 @@ fun PlayerSettings() {
|
|||
val binder = LocalPlayerServiceBinder.current
|
||||
|
||||
var persistentQueue by rememberPreference(persistentQueueKey, false)
|
||||
var resumePlaybackWhenDeviceConnected by rememberPreference(resumePlaybackWhenDeviceConnectedKey, false)
|
||||
var skipSilence by rememberPreference(skipSilenceKey, false)
|
||||
var volumeNormalization by rememberPreference(volumeNormalizationKey, false)
|
||||
|
||||
|
@ -68,6 +72,17 @@ fun PlayerSettings() {
|
|||
}
|
||||
)
|
||||
|
||||
if (isAtLeastAndroid6) {
|
||||
SwitchSettingEntry(
|
||||
title = "Resume playback",
|
||||
text = "When a wired or bluetooth device is connected",
|
||||
isChecked = resumePlaybackWhenDeviceConnected,
|
||||
onCheckedChange = {
|
||||
resumePlaybackWhenDeviceConnected = it
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
SettingsGroupSpacer()
|
||||
|
||||
SettingsEntryGroupText(title = "AUDIO")
|
||||
|
|
|
@ -30,6 +30,7 @@ const val trackLoopEnabledKey = "trackLoopEnabled"
|
|||
const val queueLoopEnabledKey = "queueLoopEnabled"
|
||||
const val skipSilenceKey = "skipSilence"
|
||||
const val volumeNormalizationKey = "volumeNormalization"
|
||||
const val resumePlaybackWhenDeviceConnectedKey = "resumePlaybackWhenDeviceConnected"
|
||||
const val persistentQueueKey = "persistentQueue"
|
||||
const val isShowingSynchronizedLyricsKey = "isShowingSynchronizedLyrics"
|
||||
const val isShowingThumbnailInLockscreenKey = "isShowingThumbnailInLockscreen"
|
||||
|
|
|
@ -113,5 +113,8 @@ suspend fun Result<Innertube.PlaylistOrAlbumPage>.completed(): Result<Innertube.
|
|||
return Result.success(playlistPage)
|
||||
}
|
||||
|
||||
inline val isAtLeastAndroid6
|
||||
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||
|
||||
inline val isAtLeastAndroid13
|
||||
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
|
||||
|
|
Loading…
Reference in a new issue