有声书媒体通知开关 #143

This commit is contained in:
HapeLee
2025-10-26 13:44:49 +08:00
parent ac46f22cdd
commit 9183d2fc48
6 changed files with 91 additions and 41 deletions
@@ -207,4 +207,5 @@ object PreferKey {
const val menuAlpha = "menuAlpha" const val menuAlpha = "menuAlpha"
const val colorImage = "colorImage" const val colorImage = "colorImage"
const val bookshelfRefreshingLimit = "bookshelfRefreshingLimit" const val bookshelfRefreshingLimit = "bookshelfRefreshingLimit"
const val systemMediaControlCompatibilityChange = "systemMediaControlCompatibilityChange"
} }
@@ -837,5 +837,11 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
set(value) { set(value) {
appCtx.putPrefInt(PreferKey.bookshelfRefreshingLimit, value) appCtx.putPrefInt(PreferKey.bookshelfRefreshingLimit, value)
} }
var systemMediaControlCompatibilityChange: Boolean
get() = appCtx.getPrefBoolean(PreferKey.systemMediaControlCompatibilityChange, true)
set(value) {
appCtx.putPrefBoolean(PreferKey.systemMediaControlCompatibilityChange, value)
}
} }
@@ -41,6 +41,7 @@ import io.legato.kazusa.receiver.MediaButtonReceiver
import io.legato.kazusa.ui.book.audio.AudioPlayActivity import io.legato.kazusa.ui.book.audio.AudioPlayActivity
import io.legato.kazusa.utils.activityPendingIntent import io.legato.kazusa.utils.activityPendingIntent
import io.legato.kazusa.utils.broadcastPendingIntent import io.legato.kazusa.utils.broadcastPendingIntent
import io.legato.kazusa.utils.getPrefBoolean
import io.legato.kazusa.utils.postEvent import io.legato.kazusa.utils.postEvent
import io.legato.kazusa.utils.printOnDebug import io.legato.kazusa.utils.printOnDebug
import io.legato.kazusa.utils.servicePendingIntent import io.legato.kazusa.utils.servicePendingIntent
@@ -81,7 +82,9 @@ class AudioPlayService : BaseService(),
private const val MEDIA_SESSION_ACTIONS = (PlaybackStateCompat.ACTION_PLAY private const val MEDIA_SESSION_ACTIONS = (PlaybackStateCompat.ACTION_PLAY
or PlaybackStateCompat.ACTION_PAUSE or PlaybackStateCompat.ACTION_PAUSE
or PlaybackStateCompat.ACTION_PLAY_PAUSE or PlaybackStateCompat.ACTION_PLAY_PAUSE
or PlaybackStateCompat.ACTION_SEEK_TO) or PlaybackStateCompat.ACTION_SEEK_TO
or PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS
or PlaybackStateCompat.ACTION_SKIP_TO_NEXT)
private const val APP_ACTION_STOP = "Stop" private const val APP_ACTION_STOP = "Stop"
private const val APP_ACTION_TIMER = "Timer" private const val APP_ACTION_TIMER = "Timer"
@@ -468,33 +471,50 @@ class AudioPlayService : BaseService(),
@SuppressLint("UnspecifiedImmutableFlag") @SuppressLint("UnspecifiedImmutableFlag")
private fun initMediaSession() { private fun initMediaSession() {
mediaSessionCompat = MediaSessionCompat(this, "readAloud") mediaSessionCompat = MediaSessionCompat(this, "readAloud")
mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() { if (AppConfig.systemMediaControlCompatibilityChange) {
override fun onSeekTo(pos: Long) { mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() {
position = pos.toInt() override fun onSeekTo(pos: Long) {
exoPlayer.seekTo(pos) position = pos.toInt()
} exoPlayer.seekTo(pos)
override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean {
return MediaButtonReceiver.handleIntent(this@AudioPlayService, mediaButtonEvent)
}
override fun onPlay() = resume()
override fun onPause() = pause()
override fun onCustomAction(action: String?, extras: Bundle?) {
action ?: return
when (action) {
APP_ACTION_STOP -> stopSelf()
APP_ACTION_TIMER -> addTimer()
} }
}
}) override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean {
mediaSessionCompat?.setMediaButtonReceiver( return MediaButtonReceiver.handleIntent(this@AudioPlayService, mediaButtonEvent)
broadcastPendingIntent<MediaButtonReceiver>(Intent.ACTION_MEDIA_BUTTON) }
)
mediaSessionCompat?.isActive = true override fun onPlay() = resume()
override fun onPause() = pause()
override fun onCustomAction(action: String?, extras: Bundle?) {
action ?: return
when (action) {
APP_ACTION_STOP -> stopSelf()
APP_ACTION_TIMER -> addTimer()
}
}
override fun onSkipToPrevious() {
super.onSkipToPrevious()
AudioPlay.prev()
}
override fun onSkipToNext() {
super.onSkipToNext()
AudioPlay.next()
}
})
} else {
mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() {
override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean {
return MediaButtonReceiver.handleIntent(
this@AudioPlayService, mediaButtonEvent
)
}
})
}
} }
/** /**
@@ -559,22 +579,23 @@ class AudioPlayService : BaseService(),
val nSubtitle = AudioPlay.durChapter?.title ?: getString(R.string.audio_play_s) val nSubtitle = AudioPlay.durChapter?.title ?: getString(R.string.audio_play_s)
val builder = NotificationCompat.Builder(this@AudioPlayService, AppConst.channelIdReadAloud) val builder = NotificationCompat
.Builder(this@AudioPlayService, AppConst.channelIdReadAloud)
.setSmallIcon(R.drawable.ic_volume_up) .setSmallIcon(R.drawable.ic_volume_up)
.setSubText(getString(R.string.audio)) .setSubText(getString(R.string.audio))
.setOngoing(true) .setOngoing(true)
.setOnlyAlertOnce(true) .setOnlyAlertOnce(true)
.setContentTitle(nTitle) .setContentTitle(nTitle)
.setContentText(nSubtitle) .setContentText(nSubtitle)
.setContentIntent(activityPendingIntent<AudioPlayActivity>("activity")) .setContentIntent(
.setLargeIcon(cover) activityPendingIntent<AudioPlayActivity>("activity")
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setStyle(
androidx.media.app.NotificationCompat.MediaStyle()
.setShowActionsInCompactView(0, 1, 2)
.setMediaSession(mediaSessionCompat?.sessionToken)
) )
builder.setLargeIcon(cover)
builder.addAction(
R.drawable.ic_skip_previous,
getString(R.string.prev_page),
servicePendingIntent<AudioPlayService>(IntentAction.prev)
)
if (pause) { if (pause) {
builder.addAction( builder.addAction(
R.drawable.ic_play, R.drawable.ic_play,
@@ -588,7 +609,11 @@ class AudioPlayService : BaseService(),
servicePendingIntent<AudioPlayService>(IntentAction.pause) servicePendingIntent<AudioPlayService>(IntentAction.pause)
) )
} }
builder.addAction(
R.drawable.ic_skip_next,
getString(R.string.next_page),
servicePendingIntent<AudioPlayService>(IntentAction.next)
)
builder.addAction( builder.addAction(
R.drawable.ic_stop_black_24dp, R.drawable.ic_stop_black_24dp,
getString(R.string.stop), getString(R.string.stop),
@@ -599,10 +624,21 @@ class AudioPlayService : BaseService(),
getString(R.string.set_timer), getString(R.string.set_timer),
servicePendingIntent<AudioPlayService>(IntentAction.addTimer) servicePendingIntent<AudioPlayService>(IntentAction.addTimer)
) )
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
builder.setStyle(choiceMediaStyle())
return builder return builder
} }
private fun choiceMediaStyle(): androidx.media.app.NotificationCompat.MediaStyle {
val mediaStyle = androidx.media.app.NotificationCompat.MediaStyle()
mediaStyle.setShowActionsInCompactView(1,2,4)
if (AppConfig.systemMediaControlCompatibilityChange) {
//fix #4090 android 14 can not show play control in lock screen
mediaStyle.setMediaSession(mediaSessionCompat?.sessionToken)
}
return mediaStyle
}
private fun upAudioPlayNotification() { private fun upAudioPlayNotification() {
upNotificationJob = execute { upNotificationJob = execute {
try { try {
@@ -466,7 +466,7 @@ abstract class BaseReadAloudService : BaseService(),
*/ */
@SuppressLint("UnspecifiedImmutableFlag") @SuppressLint("UnspecifiedImmutableFlag")
private fun initMediaSession() { private fun initMediaSession() {
if (getPrefBoolean("systemMediaControlCompatibilityChange")) { if (AppConfig.systemMediaControlCompatibilityChange) {
mediaSessionCompat.setCallback(object : MediaSessionCompat.Callback() { mediaSessionCompat.setCallback(object : MediaSessionCompat.Callback() {
override fun onPlay() { override fun onPlay() {
resumeReadAloud() resumeReadAloud()
@@ -577,7 +577,7 @@ abstract class BaseReadAloudService : BaseService(),
private fun choiceMediaStyle(): androidx.media.app.NotificationCompat.MediaStyle { private fun choiceMediaStyle(): androidx.media.app.NotificationCompat.MediaStyle {
val mediaStyle = androidx.media.app.NotificationCompat.MediaStyle() val mediaStyle = androidx.media.app.NotificationCompat.MediaStyle()
.setShowActionsInCompactView(1, 2, 4) .setShowActionsInCompactView(1, 2, 4)
if (getPrefBoolean("systemMediaControlCompatibilityChange")) { if (AppConfig.systemMediaControlCompatibilityChange) {
//fix #4090 android 14 can not show play control in lock screen //fix #4090 android 14 can not show play control in lock screen
mediaStyle.setMediaSession(mediaSessionCompat.sessionToken) mediaStyle.setMediaSession(mediaSessionCompat.sessionToken)
} }
@@ -33,6 +33,7 @@ import io.legato.kazusa.R
import io.legato.kazusa.base.VMBaseActivity import io.legato.kazusa.base.VMBaseActivity
import io.legato.kazusa.constant.BookType import io.legato.kazusa.constant.BookType
import io.legato.kazusa.constant.EventBus import io.legato.kazusa.constant.EventBus
import io.legato.kazusa.constant.PreferKey
import io.legato.kazusa.constant.Status import io.legato.kazusa.constant.Status
import io.legato.kazusa.constant.Theme import io.legato.kazusa.constant.Theme
import io.legato.kazusa.data.appDb import io.legato.kazusa.data.appDb
@@ -173,6 +174,7 @@ class AudioPlayActivity :
override fun onMenuOpened(featureId: Int, menu: Menu): Boolean { override fun onMenuOpened(featureId: Int, menu: Menu): Boolean {
menu.findItem(R.id.menu_login)?.isVisible = !AudioPlay.bookSource?.loginUrl.isNullOrBlank() menu.findItem(R.id.menu_login)?.isVisible = !AudioPlay.bookSource?.loginUrl.isNullOrBlank()
menu.findItem(R.id.menu_wake_lock)?.isChecked = AppConfig.audioPlayUseWakeLock menu.findItem(R.id.menu_wake_lock)?.isChecked = AppConfig.audioPlayUseWakeLock
menu.findItem(R.id.menu_media_control)?.isChecked = AppConfig.systemMediaControlCompatibilityChange
return super.onMenuOpened(featureId, menu) return super.onMenuOpened(featureId, menu)
} }
@@ -188,7 +190,7 @@ class AudioPlayActivity :
putExtra("key", it.bookSourceUrl) putExtra("key", it.bookSourceUrl)
} }
} }
R.id.menu_media_control -> AppConfig.systemMediaControlCompatibilityChange = !AppConfig.systemMediaControlCompatibilityChange
R.id.menu_wake_lock -> AppConfig.audioPlayUseWakeLock = !AppConfig.audioPlayUseWakeLock R.id.menu_wake_lock -> AppConfig.audioPlayUseWakeLock = !AppConfig.audioPlayUseWakeLock
R.id.menu_copy_audio_url -> sendToClip(AudioPlayService.url) R.id.menu_copy_audio_url -> sendToClip(AudioPlayService.url)
R.id.menu_edit_source -> AudioPlay.bookSource?.let { R.id.menu_edit_source -> AudioPlay.bookSource?.let {
+5
View File
@@ -31,6 +31,11 @@
android:checkable="true" android:checkable="true"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/menu_media_control"
android:title="@string/system_media_control_compatibility_change"
android:checkable="true"
app:showAsAction="never" />
<item <item
android:id="@+id/menu_log" android:id="@+id/menu_log"