pull/1282/head
gedoor 3 years ago
parent 531a3513d1
commit 2f638af692
  1. 11
      app/src/main/java/io/legado/app/help/IntentHelp.kt
  2. 99
      app/src/main/java/io/legado/app/service/AudioPlayService.kt
  3. 30
      app/src/main/java/io/legado/app/service/BaseReadAloudService.kt
  4. 22
      app/src/main/java/io/legado/app/service/CacheBookService.kt
  5. 19
      app/src/main/java/io/legado/app/service/DownloadService.kt
  6. 14
      app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt

@ -54,4 +54,15 @@ object IntentHelp {
configIntent.invoke(intent) configIntent.invoke(intent)
return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
} }
inline fun <reified T> broadcastPendingIntent(
context: Context,
action: String,
configIntent: Intent.() -> Unit = {}
): PendingIntent? {
val intent = Intent(context, T::class.java)
intent.action = action
configIntent.invoke(intent)
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT)
}
} }

@ -1,5 +1,6 @@
package io.legado.app.service package io.legado.app.service
import android.annotation.SuppressLint
import android.app.PendingIntent import android.app.PendingIntent
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
@ -10,8 +11,6 @@ import android.media.AudioManager
import android.media.MediaPlayer import android.media.MediaPlayer
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Handler
import android.os.Looper
import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.MediaSessionCompat
import android.support.v4.media.session.PlaybackStateCompat import android.support.v4.media.session.PlaybackStateCompat
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
@ -29,13 +28,12 @@ import io.legado.app.help.MediaHelp
import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.receiver.MediaButtonReceiver
import io.legado.app.service.help.AudioPlay import io.legado.app.service.help.AudioPlay
import io.legado.app.service.help.ReadAloud
import io.legado.app.ui.book.audio.AudioPlayActivity import io.legado.app.ui.book.audio.AudioPlayActivity
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.*
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import splitties.init.appCtx
class AudioPlayService : BaseService(), class AudioPlayService : BaseService(),
@ -50,7 +48,6 @@ class AudioPlayService : BaseService(),
var timeMinute: Int = 0 var timeMinute: Int = 0
} }
private val handler = Handler(Looper.getMainLooper())
private lateinit var audioManager: AudioManager private lateinit var audioManager: AudioManager
private var mFocusRequest: AudioFocusRequestCompat? = null private var mFocusRequest: AudioFocusRequestCompat? = null
private var title: String = "" private var title: String = ""
@ -60,8 +57,8 @@ class AudioPlayService : BaseService(),
private var broadcastReceiver: BroadcastReceiver? = null private var broadcastReceiver: BroadcastReceiver? = null
private var url: String = "" private var url: String = ""
private var position = 0 private var position = 0
private val dsRunnable: Runnable = Runnable { doDs() } private var dsJob: Job? = null
private var mpRunnable: Runnable = Runnable { upPlayProgress() } private var upPlayProgressJob: Job? = null
private var playSpeed: Float = 1f private var playSpeed: Float = 1f
override fun onCreate() { override fun onCreate() {
@ -108,8 +105,6 @@ class AudioPlayService : BaseService(),
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
isRun = false isRun = false
handler.removeCallbacks(dsRunnable)
handler.removeCallbacks(mpRunnable)
mediaPlayer.release() mediaPlayer.release()
mediaSessionCompat?.release() mediaSessionCompat?.release()
unregisterReceiver(broadcastReceiver) unregisterReceiver(broadcastReceiver)
@ -130,7 +125,7 @@ class AudioPlayService : BaseService(),
val uri = Uri.parse(analyzeUrl.url) val uri = Uri.parse(analyzeUrl.url)
mediaPlayer.setDataSource(this, uri, analyzeUrl.headerMap) mediaPlayer.setDataSource(this, uri, analyzeUrl.headerMap)
mediaPlayer.prepareAsync() mediaPlayer.prepareAsync()
handler.removeCallbacks(mpRunnable) upPlayProgressJob?.cancel()
}.onFailure { }.onFailure {
it.printStackTrace() it.printStackTrace()
launch { launch {
@ -147,7 +142,7 @@ class AudioPlayService : BaseService(),
} else { } else {
try { try {
AudioPlayService.pause = pause AudioPlayService.pause = pause
handler.removeCallbacks(mpRunnable) upPlayProgressJob?.cancel()
position = mediaPlayer.currentPosition position = mediaPlayer.currentPosition
if (mediaPlayer.isPlaying) mediaPlayer.pause() if (mediaPlayer.isPlaying) mediaPlayer.pause()
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED)
@ -167,8 +162,7 @@ class AudioPlayService : BaseService(),
mediaPlayer.start() mediaPlayer.start()
mediaPlayer.seekTo(position) mediaPlayer.seekTo(position)
} }
handler.removeCallbacks(mpRunnable) upPlayProgress()
handler.postDelayed(mpRunnable, 1000)
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING)
AudioPlay.status = Status.PLAY AudioPlay.status = Status.PLAY
postEvent(EventBus.AUDIO_STATE, Status.PLAY) postEvent(EventBus.AUDIO_STATE, Status.PLAY)
@ -213,8 +207,7 @@ class AudioPlayService : BaseService(),
AudioPlay.status = Status.PLAY AudioPlay.status = Status.PLAY
postEvent(EventBus.AUDIO_STATE, Status.PLAY) postEvent(EventBus.AUDIO_STATE, Status.PLAY)
postEvent(EventBus.AUDIO_SIZE, mediaPlayer.duration) postEvent(EventBus.AUDIO_SIZE, mediaPlayer.duration)
handler.removeCallbacks(mpRunnable) upPlayProgress()
handler.post(mpRunnable)
AudioPlay.saveDurChapter(mediaPlayer.duration.toLong()) AudioPlay.saveDurChapter(mediaPlayer.duration.toLong())
} }
@ -234,40 +227,61 @@ class AudioPlayService : BaseService(),
* 播放结束 * 播放结束
*/ */
override fun onCompletion(mp: MediaPlayer) { override fun onCompletion(mp: MediaPlayer) {
handler.removeCallbacks(mpRunnable) upPlayProgressJob?.cancel()
AudioPlay.next(this) AudioPlay.next(this)
} }
private fun setTimer(minute: Int) { private fun setTimer(minute: Int) {
timeMinute = minute timeMinute = minute
if (minute > 0) { doDs()
handler.removeCallbacks(dsRunnable)
handler.postDelayed(dsRunnable, 60000)
}
upNotification()
} }
private fun addTimer() { private fun addTimer() {
if (timeMinute == 60) { if (timeMinute == 60) {
timeMinute = 0 timeMinute = 0
handler.removeCallbacks(dsRunnable)
} else { } else {
timeMinute += 10 timeMinute += 10
if (timeMinute > 60) timeMinute = 60 if (timeMinute > 60) timeMinute = 60
handler.removeCallbacks(dsRunnable)
handler.postDelayed(dsRunnable, 60000)
} }
doDs()
}
/**
* 定时
*/
private fun doDs() {
postEvent(EventBus.TTS_DS, timeMinute) postEvent(EventBus.TTS_DS, timeMinute)
upNotification() upNotification()
dsJob?.cancel()
dsJob = launch {
while (isActive) {
delay(60000)
if (!pause) {
if (timeMinute >= 0) {
timeMinute--
}
if (timeMinute == 0) {
ReadAloud.stop(this@AudioPlayService)
}
}
postEvent(EventBus.TTS_DS, timeMinute)
upNotification()
}
}
} }
/** /**
* 更新播放进度 * 更新播放进度
*/ */
private fun upPlayProgress() { private fun upPlayProgress() {
saveProgress() upPlayProgressJob?.cancel()
postEvent(EventBus.AUDIO_PROGRESS, mediaPlayer.currentPosition) upPlayProgressJob = launch {
handler.postDelayed(mpRunnable, 1000) while (isActive) {
saveProgress()
postEvent(EventBus.AUDIO_PROGRESS, mediaPlayer.currentPosition)
delay(1000)
}
}
} }
private fun loadContent() = with(AudioPlay) { private fun loadContent() = with(AudioPlay) {
@ -332,22 +346,6 @@ class AudioPlayService : BaseService(),
} }
} }
/**
* 定时
*/
private fun doDs() {
if (!pause) {
timeMinute--
if (timeMinute == 0) {
stopSelf()
} else if (timeMinute > 0) {
handler.postDelayed(dsRunnable, 60000)
}
}
postEvent(EventBus.TTS_DS, timeMinute)
upNotification()
}
/** /**
* 更新媒体状态 * 更新媒体状态
*/ */
@ -363,6 +361,7 @@ class AudioPlayService : BaseService(),
/** /**
* 初始化MediaSession, 注册多媒体按钮 * 初始化MediaSession, 注册多媒体按钮
*/ */
@SuppressLint("UnspecifiedImmutableFlag")
private fun initMediaSession() { private fun initMediaSession() {
mediaSessionCompat = MediaSessionCompat(this, "readAloud") mediaSessionCompat = MediaSessionCompat(this, "readAloud")
mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() { mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() {
@ -371,15 +370,9 @@ class AudioPlayService : BaseService(),
} }
}) })
mediaSessionCompat?.setMediaButtonReceiver( mediaSessionCompat?.setMediaButtonReceiver(
PendingIntent.getBroadcast( IntentHelp.broadcastPendingIntent<MediaButtonReceiver>(
this, 0, this,
Intent( Intent.ACTION_MEDIA_BUTTON
Intent.ACTION_MEDIA_BUTTON,
null,
appCtx,
MediaButtonReceiver::class.java
),
PendingIntent.FLAG_CANCEL_CURRENT
) )
) )
mediaSessionCompat?.isActive = true mediaSessionCompat?.isActive = true

@ -31,7 +31,6 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import splitties.init.appCtx
abstract class BaseReadAloudService : BaseService(), abstract class BaseReadAloudService : BaseService(),
AudioManager.OnAudioFocusChangeListener { AudioManager.OnAudioFocusChangeListener {
@ -209,18 +208,16 @@ abstract class BaseReadAloudService : BaseService(),
dsJob = launch { dsJob = launch {
while (isActive) { while (isActive) {
delay(60000) delay(60000)
if (isActive) { if (!pause) {
if (!pause) { if (timeMinute >= 0) {
if (timeMinute >= 0) { timeMinute--
timeMinute-- }
} if (timeMinute == 0) {
if (timeMinute == 0) { ReadAloud.stop(this@BaseReadAloudService)
ReadAloud.stop(this@BaseReadAloudService)
}
} }
postEvent(EventBus.TTS_DS, timeMinute)
upNotification()
} }
postEvent(EventBus.TTS_DS, timeMinute)
upNotification()
} }
} }
} }
@ -259,16 +256,9 @@ abstract class BaseReadAloudService : BaseService(),
} }
}) })
mediaSessionCompat.setMediaButtonReceiver( mediaSessionCompat.setMediaButtonReceiver(
PendingIntent.getBroadcast( IntentHelp.broadcastPendingIntent<MediaButtonReceiver>(
this, this,
0, Intent.ACTION_MEDIA_BUTTON
Intent(
Intent.ACTION_MEDIA_BUTTON,
null,
appCtx,
MediaButtonReceiver::class.java
),
PendingIntent.FLAG_CANCEL_CURRENT
) )
) )
mediaSessionCompat.isActive = true mediaSessionCompat.isActive = true

@ -1,8 +1,6 @@
package io.legado.app.service package io.legado.app.service
import android.content.Intent import android.content.Intent
import android.os.Handler
import android.os.Looper
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import io.legado.app.R import io.legado.app.R
import io.legado.app.base.BaseService import io.legado.app.base.BaseService
@ -22,7 +20,9 @@ import io.legado.app.service.help.CacheBook
import io.legado.app.utils.postEvent import io.legado.app.utils.postEvent
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.asCoroutineDispatcher
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import splitties.init.appCtx import splitties.init.appCtx
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArraySet import java.util.concurrent.CopyOnWriteArraySet
@ -34,8 +34,6 @@ class CacheBookService : BaseService() {
private var cachePool = private var cachePool =
Executors.newFixedThreadPool(min(threadCount, 8)).asCoroutineDispatcher() Executors.newFixedThreadPool(min(threadCount, 8)).asCoroutineDispatcher()
private var tasks = CompositeCoroutine() private var tasks = CompositeCoroutine()
private val handler = Handler(Looper.getMainLooper())
private var runnable: Runnable = Runnable { upDownload() }
private val bookMap = ConcurrentHashMap<String, Book>() private val bookMap = ConcurrentHashMap<String, Book>()
private val webBookMap = ConcurrentHashMap<String, WebBook>() private val webBookMap = ConcurrentHashMap<String, WebBook>()
private val downloadMap = ConcurrentHashMap<String, CopyOnWriteArraySet<BookChapter>>() private val downloadMap = ConcurrentHashMap<String, CopyOnWriteArraySet<BookChapter>>()
@ -63,7 +61,13 @@ class CacheBookService : BaseService() {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
upNotification() upNotification()
handler.postDelayed(runnable, 1000) launch {
while (isActive) {
delay(1000)
upNotification()
postEvent(EventBus.UP_DOWNLOAD, downloadMap)
}
}
} }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@ -84,7 +88,6 @@ class CacheBookService : BaseService() {
override fun onDestroy() { override fun onDestroy() {
tasks.clear() tasks.clear()
cachePool.close() cachePool.close()
handler.removeCallbacks(runnable)
downloadMap.clear() downloadMap.clear()
finalMap.clear() finalMap.clear()
super.onDestroy() super.onDestroy()
@ -252,13 +255,6 @@ class CacheBookService : BaseService() {
stopSelf() stopSelf()
} }
private fun upDownload() {
upNotification()
postEvent(EventBus.UP_DOWNLOAD, downloadMap)
handler.removeCallbacks(runnable)
handler.postDelayed(runnable, 1000)
}
private fun upNotification( private fun upNotification(
downloadCount: DownloadCount, downloadCount: DownloadCount,
totalCount: Int?, totalCount: Int?,

@ -7,8 +7,6 @@ import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Handler
import android.os.Looper
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import io.legado.app.R import io.legado.app.R
@ -19,6 +17,9 @@ import io.legado.app.help.IntentHelp
import io.legado.app.utils.RealPathUtil import io.legado.app.utils.RealPathUtil
import io.legado.app.utils.msg import io.legado.app.utils.msg
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import splitties.systemservices.downloadManager import splitties.systemservices.downloadManager
import java.io.File import java.io.File
@ -27,11 +28,7 @@ class DownloadService : BaseService() {
private val downloads = hashMapOf<Long, String>() private val downloads = hashMapOf<Long, String>()
private val completeDownloads = hashSetOf<Long>() private val completeDownloads = hashSetOf<Long>()
private val handler = Handler(Looper.getMainLooper()) private var upStateJob: Job? = null
private val runnable = Runnable {
checkDownloadState()
}
private val downloadReceiver = object : BroadcastReceiver() { private val downloadReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
queryState() queryState()
@ -78,9 +75,11 @@ class DownloadService : BaseService() {
} }
private fun checkDownloadState() { private fun checkDownloadState() {
handler.removeCallbacks(runnable) upStateJob?.cancel()
queryState() upStateJob = launch {
handler.postDelayed(runnable, 1000) queryState()
delay(1000)
}
} }
//查询下载进度 //查询下载进度

@ -707,7 +707,7 @@ class ReadBookActivity : ReadBookBaseActivity(),
delayMillis = 20 delayMillis = 20
} }
delay(delayMillis) delay(delayMillis)
if (!menuLayoutIsVisible && isActive) { if (!menuLayoutIsVisible) {
if (binding.readView.isScroll) { if (binding.readView.isScroll) {
binding.readView.curPage.scroll(-scrollOffset) binding.readView.curPage.scroll(-scrollOffset)
} else { } else {
@ -882,11 +882,9 @@ class ReadBookActivity : ReadBookBaseActivity(),
backupJob?.cancel() backupJob?.cancel()
backupJob = launch { backupJob = launch {
delay(120000) delay(120000)
if (isActive) { ReadBook.book?.let {
ReadBook.book?.let { AppWebDav.uploadBookProgress(it)
AppWebDav.uploadBookProgress(it) Backup.autoBack(this@ReadBookActivity)
Backup.autoBack(this@ReadBookActivity)
}
} }
} }
} }
@ -997,9 +995,7 @@ class ReadBookActivity : ReadBookBaseActivity(),
if (t > 0) { if (t > 0) {
keepScreenOn(true) keepScreenOn(true)
delay(screenTimeOut) delay(screenTimeOut)
if (isActive) { keepScreenOn(false)
keepScreenOn(false)
}
} else { } else {
keepScreenOn(false) keepScreenOn(false)
} }

Loading…
Cancel
Save