diff --git a/app/src/main/java/io/legado/app/help/IntentHelp.kt b/app/src/main/java/io/legado/app/help/IntentHelp.kt index 64192b124..2fac83577 100644 --- a/app/src/main/java/io/legado/app/help/IntentHelp.kt +++ b/app/src/main/java/io/legado/app/help/IntentHelp.kt @@ -54,4 +54,15 @@ object IntentHelp { configIntent.invoke(intent) return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) } + + inline fun 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) + } } \ No newline at end of file diff --git a/app/src/main/java/io/legado/app/service/AudioPlayService.kt b/app/src/main/java/io/legado/app/service/AudioPlayService.kt index 3611280ce..ebb087ee6 100644 --- a/app/src/main/java/io/legado/app/service/AudioPlayService.kt +++ b/app/src/main/java/io/legado/app/service/AudioPlayService.kt @@ -1,5 +1,6 @@ package io.legado.app.service +import android.annotation.SuppressLint import android.app.PendingIntent import android.content.BroadcastReceiver import android.content.Context @@ -10,8 +11,6 @@ import android.media.AudioManager import android.media.MediaPlayer import android.net.Uri 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.PlaybackStateCompat 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.receiver.MediaButtonReceiver 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.utils.postEvent import io.legado.app.utils.toastOnUi +import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers.Main -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import splitties.init.appCtx class AudioPlayService : BaseService(), @@ -50,7 +48,6 @@ class AudioPlayService : BaseService(), var timeMinute: Int = 0 } - private val handler = Handler(Looper.getMainLooper()) private lateinit var audioManager: AudioManager private var mFocusRequest: AudioFocusRequestCompat? = null private var title: String = "" @@ -60,8 +57,8 @@ class AudioPlayService : BaseService(), private var broadcastReceiver: BroadcastReceiver? = null private var url: String = "" private var position = 0 - private val dsRunnable: Runnable = Runnable { doDs() } - private var mpRunnable: Runnable = Runnable { upPlayProgress() } + private var dsJob: Job? = null + private var upPlayProgressJob: Job? = null private var playSpeed: Float = 1f override fun onCreate() { @@ -108,8 +105,6 @@ class AudioPlayService : BaseService(), override fun onDestroy() { super.onDestroy() isRun = false - handler.removeCallbacks(dsRunnable) - handler.removeCallbacks(mpRunnable) mediaPlayer.release() mediaSessionCompat?.release() unregisterReceiver(broadcastReceiver) @@ -130,7 +125,7 @@ class AudioPlayService : BaseService(), val uri = Uri.parse(analyzeUrl.url) mediaPlayer.setDataSource(this, uri, analyzeUrl.headerMap) mediaPlayer.prepareAsync() - handler.removeCallbacks(mpRunnable) + upPlayProgressJob?.cancel() }.onFailure { it.printStackTrace() launch { @@ -147,7 +142,7 @@ class AudioPlayService : BaseService(), } else { try { AudioPlayService.pause = pause - handler.removeCallbacks(mpRunnable) + upPlayProgressJob?.cancel() position = mediaPlayer.currentPosition if (mediaPlayer.isPlaying) mediaPlayer.pause() upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PAUSED) @@ -167,8 +162,7 @@ class AudioPlayService : BaseService(), mediaPlayer.start() mediaPlayer.seekTo(position) } - handler.removeCallbacks(mpRunnable) - handler.postDelayed(mpRunnable, 1000) + upPlayProgress() upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) AudioPlay.status = Status.PLAY postEvent(EventBus.AUDIO_STATE, Status.PLAY) @@ -213,8 +207,7 @@ class AudioPlayService : BaseService(), AudioPlay.status = Status.PLAY postEvent(EventBus.AUDIO_STATE, Status.PLAY) postEvent(EventBus.AUDIO_SIZE, mediaPlayer.duration) - handler.removeCallbacks(mpRunnable) - handler.post(mpRunnable) + upPlayProgress() AudioPlay.saveDurChapter(mediaPlayer.duration.toLong()) } @@ -234,40 +227,61 @@ class AudioPlayService : BaseService(), * 播放结束 */ override fun onCompletion(mp: MediaPlayer) { - handler.removeCallbacks(mpRunnable) + upPlayProgressJob?.cancel() AudioPlay.next(this) } private fun setTimer(minute: Int) { timeMinute = minute - if (minute > 0) { - handler.removeCallbacks(dsRunnable) - handler.postDelayed(dsRunnable, 60000) - } - upNotification() + doDs() } private fun addTimer() { if (timeMinute == 60) { timeMinute = 0 - handler.removeCallbacks(dsRunnable) } else { timeMinute += 10 if (timeMinute > 60) timeMinute = 60 - handler.removeCallbacks(dsRunnable) - handler.postDelayed(dsRunnable, 60000) } + doDs() + } + + /** + * 定时 + */ + private fun doDs() { postEvent(EventBus.TTS_DS, timeMinute) 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() { - saveProgress() - postEvent(EventBus.AUDIO_PROGRESS, mediaPlayer.currentPosition) - handler.postDelayed(mpRunnable, 1000) + upPlayProgressJob?.cancel() + upPlayProgressJob = launch { + while (isActive) { + saveProgress() + postEvent(EventBus.AUDIO_PROGRESS, mediaPlayer.currentPosition) + delay(1000) + } + } } 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, 注册多媒体按钮 */ + @SuppressLint("UnspecifiedImmutableFlag") private fun initMediaSession() { mediaSessionCompat = MediaSessionCompat(this, "readAloud") mediaSessionCompat?.setCallback(object : MediaSessionCompat.Callback() { @@ -371,15 +370,9 @@ class AudioPlayService : BaseService(), } }) mediaSessionCompat?.setMediaButtonReceiver( - PendingIntent.getBroadcast( - this, 0, - Intent( - Intent.ACTION_MEDIA_BUTTON, - null, - appCtx, - MediaButtonReceiver::class.java - ), - PendingIntent.FLAG_CANCEL_CURRENT + IntentHelp.broadcastPendingIntent( + this, + Intent.ACTION_MEDIA_BUTTON ) ) mediaSessionCompat?.isActive = true diff --git a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt index d31efc649..b554e0891 100644 --- a/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt +++ b/app/src/main/java/io/legado/app/service/BaseReadAloudService.kt @@ -31,7 +31,6 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.isActive import kotlinx.coroutines.launch -import splitties.init.appCtx abstract class BaseReadAloudService : BaseService(), AudioManager.OnAudioFocusChangeListener { @@ -209,18 +208,16 @@ abstract class BaseReadAloudService : BaseService(), dsJob = launch { while (isActive) { delay(60000) - if (isActive) { - if (!pause) { - if (timeMinute >= 0) { - timeMinute-- - } - if (timeMinute == 0) { - ReadAloud.stop(this@BaseReadAloudService) - } + if (!pause) { + if (timeMinute >= 0) { + timeMinute-- + } + if (timeMinute == 0) { + 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( - PendingIntent.getBroadcast( + IntentHelp.broadcastPendingIntent( this, - 0, - Intent( - Intent.ACTION_MEDIA_BUTTON, - null, - appCtx, - MediaButtonReceiver::class.java - ), - PendingIntent.FLAG_CANCEL_CURRENT + Intent.ACTION_MEDIA_BUTTON ) ) mediaSessionCompat.isActive = true diff --git a/app/src/main/java/io/legado/app/service/CacheBookService.kt b/app/src/main/java/io/legado/app/service/CacheBookService.kt index 7e592f545..7ab3c49a1 100644 --- a/app/src/main/java/io/legado/app/service/CacheBookService.kt +++ b/app/src/main/java/io/legado/app/service/CacheBookService.kt @@ -1,8 +1,6 @@ package io.legado.app.service import android.content.Intent -import android.os.Handler -import android.os.Looper import androidx.core.app.NotificationCompat import io.legado.app.R 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.toastOnUi import kotlinx.coroutines.asCoroutineDispatcher +import kotlinx.coroutines.delay import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch import splitties.init.appCtx import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.CopyOnWriteArraySet @@ -34,8 +34,6 @@ class CacheBookService : BaseService() { private var cachePool = Executors.newFixedThreadPool(min(threadCount, 8)).asCoroutineDispatcher() private var tasks = CompositeCoroutine() - private val handler = Handler(Looper.getMainLooper()) - private var runnable: Runnable = Runnable { upDownload() } private val bookMap = ConcurrentHashMap() private val webBookMap = ConcurrentHashMap() private val downloadMap = ConcurrentHashMap>() @@ -63,7 +61,13 @@ class CacheBookService : BaseService() { override fun onCreate() { super.onCreate() 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 { @@ -84,7 +88,6 @@ class CacheBookService : BaseService() { override fun onDestroy() { tasks.clear() cachePool.close() - handler.removeCallbacks(runnable) downloadMap.clear() finalMap.clear() super.onDestroy() @@ -252,13 +255,6 @@ class CacheBookService : BaseService() { stopSelf() } - private fun upDownload() { - upNotification() - postEvent(EventBus.UP_DOWNLOAD, downloadMap) - handler.removeCallbacks(runnable) - handler.postDelayed(runnable, 1000) - } - private fun upNotification( downloadCount: DownloadCount, totalCount: Int?, diff --git a/app/src/main/java/io/legado/app/service/DownloadService.kt b/app/src/main/java/io/legado/app/service/DownloadService.kt index d3c7af5ef..c5cc3c3a7 100644 --- a/app/src/main/java/io/legado/app/service/DownloadService.kt +++ b/app/src/main/java/io/legado/app/service/DownloadService.kt @@ -7,8 +7,6 @@ import android.content.Intent import android.content.IntentFilter import android.net.Uri import android.os.Build -import android.os.Handler -import android.os.Looper import androidx.core.app.NotificationCompat import androidx.core.content.FileProvider 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.msg import io.legado.app.utils.toastOnUi +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch import splitties.systemservices.downloadManager import java.io.File @@ -27,11 +28,7 @@ class DownloadService : BaseService() { private val downloads = hashMapOf() private val completeDownloads = hashSetOf() - private val handler = Handler(Looper.getMainLooper()) - private val runnable = Runnable { - checkDownloadState() - } - + private var upStateJob: Job? = null private val downloadReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { queryState() @@ -78,9 +75,11 @@ class DownloadService : BaseService() { } private fun checkDownloadState() { - handler.removeCallbacks(runnable) - queryState() - handler.postDelayed(runnable, 1000) + upStateJob?.cancel() + upStateJob = launch { + queryState() + delay(1000) + } } //查询下载进度 diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt index 0e7ad7e1f..13e56b894 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookActivity.kt @@ -707,7 +707,7 @@ class ReadBookActivity : ReadBookBaseActivity(), delayMillis = 20 } delay(delayMillis) - if (!menuLayoutIsVisible && isActive) { + if (!menuLayoutIsVisible) { if (binding.readView.isScroll) { binding.readView.curPage.scroll(-scrollOffset) } else { @@ -882,11 +882,9 @@ class ReadBookActivity : ReadBookBaseActivity(), backupJob?.cancel() backupJob = launch { delay(120000) - if (isActive) { - ReadBook.book?.let { - AppWebDav.uploadBookProgress(it) - Backup.autoBack(this@ReadBookActivity) - } + ReadBook.book?.let { + AppWebDav.uploadBookProgress(it) + Backup.autoBack(this@ReadBookActivity) } } } @@ -997,9 +995,7 @@ class ReadBookActivity : ReadBookBaseActivity(), if (t > 0) { keepScreenOn(true) delay(screenTimeOut) - if (isActive) { - keepScreenOn(false) - } + keepScreenOn(false) } else { keepScreenOn(false) }