pull/46/head
parent
07dc68c3f7
commit
d4f44e77cb
@ -0,0 +1,220 @@ |
|||||||
|
package io.legado.app.service |
||||||
|
|
||||||
|
import android.app.PendingIntent |
||||||
|
import android.content.BroadcastReceiver |
||||||
|
import android.content.Context |
||||||
|
import android.content.Intent |
||||||
|
import android.content.IntentFilter |
||||||
|
import android.graphics.BitmapFactory |
||||||
|
import android.media.AudioFocusRequest |
||||||
|
import android.media.AudioManager |
||||||
|
import android.media.MediaPlayer |
||||||
|
import android.os.Build |
||||||
|
import android.support.v4.media.session.MediaSessionCompat |
||||||
|
import android.support.v4.media.session.PlaybackStateCompat |
||||||
|
import androidx.core.app.NotificationCompat |
||||||
|
import io.legado.app.App |
||||||
|
import io.legado.app.R |
||||||
|
import io.legado.app.base.BaseService |
||||||
|
import io.legado.app.constant.Action |
||||||
|
import io.legado.app.constant.AppConst |
||||||
|
import io.legado.app.help.IntentHelp |
||||||
|
import io.legado.app.help.MediaHelp |
||||||
|
import io.legado.app.receiver.MediaButtonReceiver |
||||||
|
import io.legado.app.ui.book.read.ReadBookActivity |
||||||
|
|
||||||
|
|
||||||
|
class AudioPlayService : BaseService(), AudioManager.OnAudioFocusChangeListener { |
||||||
|
|
||||||
|
var pause = false |
||||||
|
private lateinit var audioManager: AudioManager |
||||||
|
private lateinit var mFocusRequest: AudioFocusRequest |
||||||
|
private var title: String = "" |
||||||
|
private var subtitle: String = "" |
||||||
|
private val mediaPlayer = MediaPlayer() |
||||||
|
private var mediaSessionCompat: MediaSessionCompat? = null |
||||||
|
private var broadcastReceiver: BroadcastReceiver? = null |
||||||
|
private var position = 0 |
||||||
|
|
||||||
|
override fun onCreate() { |
||||||
|
super.onCreate() |
||||||
|
audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
||||||
|
mFocusRequest = MediaHelp.getFocusRequest(this) |
||||||
|
} |
||||||
|
initMediaSession() |
||||||
|
initBroadcastReceiver() |
||||||
|
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { |
||||||
|
return super.onStartCommand(intent, flags, startId) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onDestroy() { |
||||||
|
super.onDestroy() |
||||||
|
mediaSessionCompat?.release() |
||||||
|
} |
||||||
|
|
||||||
|
private fun pause() { |
||||||
|
mediaPlayer.pause() |
||||||
|
} |
||||||
|
|
||||||
|
private fun resume() { |
||||||
|
mediaPlayer.start() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @return 音频焦点 |
||||||
|
*/ |
||||||
|
fun requestFocus(): Boolean { |
||||||
|
val request: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
||||||
|
audioManager.requestAudioFocus(mFocusRequest) |
||||||
|
} else { |
||||||
|
@Suppress("DEPRECATION") |
||||||
|
audioManager.requestAudioFocus( |
||||||
|
this, |
||||||
|
AudioManager.STREAM_MUSIC, |
||||||
|
AudioManager.AUDIOFOCUS_GAIN |
||||||
|
) |
||||||
|
} |
||||||
|
return request == AudioManager.AUDIOFOCUS_REQUEST_GRANTED |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 更新媒体状态 |
||||||
|
*/ |
||||||
|
private fun upMediaSessionPlaybackState(state: Int) { |
||||||
|
mediaSessionCompat?.setPlaybackState( |
||||||
|
PlaybackStateCompat.Builder() |
||||||
|
.setActions(MediaHelp.MEDIA_SESSION_ACTIONS) |
||||||
|
.setState(state, position.toLong(), 1f) |
||||||
|
.build() |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 初始化MediaSession, 注册多媒体按钮 |
||||||
|
*/ |
||||||
|
private fun initMediaSession() { |
||||||
|
mediaSessionCompat = MediaSessionCompat(this, "readAloud") |
||||||
|
mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() { |
||||||
|
override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean { |
||||||
|
return MediaButtonReceiver.handleIntent(this@AudioPlayService, mediaButtonEvent) |
||||||
|
} |
||||||
|
}) |
||||||
|
mediaSessionCompat?.setMediaButtonReceiver( |
||||||
|
PendingIntent.getBroadcast( |
||||||
|
this, |
||||||
|
0, |
||||||
|
Intent( |
||||||
|
Intent.ACTION_MEDIA_BUTTON, |
||||||
|
null, |
||||||
|
App.INSTANCE, |
||||||
|
MediaButtonReceiver::class.java |
||||||
|
), |
||||||
|
PendingIntent.FLAG_CANCEL_CURRENT |
||||||
|
) |
||||||
|
) |
||||||
|
mediaSessionCompat?.isActive = true |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 断开耳机监听 |
||||||
|
*/ |
||||||
|
private fun initBroadcastReceiver() { |
||||||
|
broadcastReceiver = object : BroadcastReceiver() { |
||||||
|
override fun onReceive(context: Context, intent: Intent) { |
||||||
|
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY == intent.action) { |
||||||
|
pause() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
val intentFilter = IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY) |
||||||
|
registerReceiver(broadcastReceiver, intentFilter) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 音频焦点变化 |
||||||
|
*/ |
||||||
|
override fun onAudioFocusChange(focusChange: Int) { |
||||||
|
when (focusChange) { |
||||||
|
AudioManager.AUDIOFOCUS_GAIN -> { |
||||||
|
// 重新获得焦点, 可做恢复播放,恢复后台音量的操作 |
||||||
|
if (!pause) resume() |
||||||
|
} |
||||||
|
AudioManager.AUDIOFOCUS_LOSS -> { |
||||||
|
// 永久丢失焦点除非重新主动获取,这种情况是被其他播放器抢去了焦点, 为避免与其他播放器混音,可将音乐暂停 |
||||||
|
} |
||||||
|
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> { |
||||||
|
// 暂时丢失焦点,这种情况是被其他应用申请了短暂的焦点,可压低后台音量 |
||||||
|
if (!pause) pause() |
||||||
|
} |
||||||
|
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> { |
||||||
|
// 短暂丢失焦点,这种情况是被其他应用申请了短暂的焦点希望其他声音能压低音量(或者关闭声音)凸显这个声音(比如短信提示音), |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 更新通知 |
||||||
|
*/ |
||||||
|
private fun upNotification() { |
||||||
|
var nTitle: String = when { |
||||||
|
pause -> getString(R.string.read_aloud_pause) |
||||||
|
BaseReadAloudService.timeMinute in 1..60 -> getString( |
||||||
|
R.string.read_aloud_timer, |
||||||
|
BaseReadAloudService.timeMinute |
||||||
|
) |
||||||
|
else -> getString(R.string.read_aloud_t) |
||||||
|
} |
||||||
|
nTitle += ": $title" |
||||||
|
var nSubtitle = subtitle |
||||||
|
if (subtitle.isEmpty()) |
||||||
|
nSubtitle = getString(R.string.read_aloud_s) |
||||||
|
val builder = NotificationCompat.Builder(this, AppConst.channelIdReadAloud) |
||||||
|
.setSmallIcon(R.drawable.ic_volume_up) |
||||||
|
.setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.icon_read_book)) |
||||||
|
.setOngoing(true) |
||||||
|
.setContentTitle(nTitle) |
||||||
|
.setContentText(nSubtitle) |
||||||
|
.setContentIntent( |
||||||
|
IntentHelp.activityPendingIntent<ReadBookActivity>(this, "activity") |
||||||
|
) |
||||||
|
if (pause) { |
||||||
|
builder.addAction( |
||||||
|
R.drawable.ic_play_24dp, |
||||||
|
getString(R.string.resume), |
||||||
|
thisPendingIntent(Action.resume) |
||||||
|
) |
||||||
|
} else { |
||||||
|
builder.addAction( |
||||||
|
R.drawable.ic_pause_24dp, |
||||||
|
getString(R.string.pause), |
||||||
|
thisPendingIntent(Action.pause) |
||||||
|
) |
||||||
|
} |
||||||
|
builder.addAction( |
||||||
|
R.drawable.ic_stop_black_24dp, |
||||||
|
getString(R.string.stop), |
||||||
|
thisPendingIntent(Action.stop) |
||||||
|
) |
||||||
|
builder.addAction( |
||||||
|
R.drawable.ic_time_add_24dp, |
||||||
|
getString(R.string.set_timer), |
||||||
|
thisPendingIntent(Action.addTimer) |
||||||
|
) |
||||||
|
builder.setStyle( |
||||||
|
androidx.media.app.NotificationCompat.MediaStyle() |
||||||
|
.setMediaSession(mediaSessionCompat?.sessionToken) |
||||||
|
.setShowActionsInCompactView(0, 1, 2) |
||||||
|
) |
||||||
|
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) |
||||||
|
val notification = builder.build() |
||||||
|
startForeground(112201, notification) |
||||||
|
} |
||||||
|
|
||||||
|
private fun thisPendingIntent(action: String): PendingIntent? { |
||||||
|
return IntentHelp.servicePendingIntent<AudioPlayService>(this, action) |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue