有声书媒体通知开关 #143
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user