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