Compare commits

...

12 Commits

Author SHA1 Message Date
dependabot[bot]
f21e5df7cd
Merge 1535b668ae into 72ff30b1ea 2024-05-31 22:54:32 +08:00
Horis
72ff30b1ea 优化 2024-05-31 19:04:36 +08:00
Horis
b30ef00307 优化 2024-05-31 18:53:02 +08:00
Horis
0cfd6ea46d 优化 2024-05-31 17:53:53 +08:00
Horis
96c76d74ba 优化 2024-05-31 17:51:28 +08:00
Horis
ed6f8e5e43 优化 2024-05-30 07:08:33 +08:00
Horis
9247d56cbd 优化 2024-05-27 16:13:29 +08:00
Horis
d774b2df7c 优化 2024-05-27 15:56:32 +08:00
Horis
17d187b4af 优化 2024-05-27 12:49:41 +08:00
Horis
df512234e6 优化 2024-05-27 10:59:54 +08:00
Horis
065ac7e119 优化 2024-05-27 10:38:04 +08:00
dependabot[bot]
1535b668ae
Bump org.apache.commons:commons-text from 1.11.0 to 1.12.0
Bumps org.apache.commons:commons-text from 1.11.0 to 1.12.0.

---
updated-dependencies:
- dependency-name: org.apache.commons:commons-text
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-06 04:22:15 +00:00
18 changed files with 97 additions and 22 deletions

View File

@ -1,6 +1,7 @@
package io.legado.app.base
import android.content.Intent
import android.os.Build
import android.os.IBinder
import androidx.annotation.CallSuper
import androidx.lifecycle.LifecycleService
@ -33,7 +34,7 @@ abstract class BaseService : LifecycleService() {
override fun onCreate() {
super.onCreate()
LifecycleHelp.onServiceCreate(this)
checkNotificationPermission()
checkPermission()
}
@CallSuper
@ -71,9 +72,9 @@ abstract class BaseService : LifecycleService() {
}
/**
* 检测通知权限
* 检测通知权限和后台权限
*/
private fun checkNotificationPermission() {
private fun checkPermission() {
PermissionsCompat.Builder()
.addPermissions(Permissions.POST_NOTIFICATIONS)
.rationale(R.string.notification_permission_rationale)
@ -83,5 +84,11 @@ abstract class BaseService : LifecycleService() {
}
}
.request()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PermissionsCompat.Builder()
.addPermissions(Permissions.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
.rationale(R.string.ignore_battery_permission_rationale)
.request()
}
}
}
}

View File

@ -1,5 +1,6 @@
package io.legado.app.lib.permission
import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
import android.os.Build
@ -24,6 +25,7 @@ class PermissionActivity : AppCompatActivity() {
finish()
}
@SuppressLint("BatteryLife")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val rationale = intent.getStringExtra(KEY_RATIONALE)
@ -72,6 +74,16 @@ class PermissionActivity : AppCompatActivity() {
}
}
}
Request.TYPE_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS -> showSettingDialog(
permissions, rationale
) {
kotlin.runCatching {
val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
intent.setData(Uri.parse("package:$packageName"))
settingActivityResult.launch(intent)
}
}
}
onBackPressedDispatcher.addCallback(this) {

View File

@ -43,6 +43,9 @@ object Permissions {
const val ACCESS_MEDIA_LOCATION = "android.permission.ACCESS_MEDIA_LOCATION"
const val REQUEST_IGNORE_BATTERY_OPTIMIZATIONS =
"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"
object Group {
val STORAGE = if (isManageExternalStorage()) {
arrayOf(MANAGE_EXTERNAL_STORAGE)

View File

@ -9,6 +9,7 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import io.legado.app.utils.startActivity
import splitties.init.appCtx
import splitties.systemservices.powerManager
@Suppress("MemberVisibilityCanBePrivate")
internal class Request : OnRequestPermissionsResultCallback {
@ -73,6 +74,10 @@ internal class Request : OnRequestPermissionsResultCallback {
}
} else if (deniedPermissions.contains(Permissions.POST_NOTIFICATIONS)) {
toNotificationSetting()
} else if (deniedPermissions.contains(Permissions.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
toIgnoreBatterySetting()
}
} else if (deniedPermissions.size > 1) {
appCtx.startActivity<PermissionActivity> {
putExtra(PermissionActivity.KEY_RATIONALE, rationale)
@ -98,6 +103,7 @@ internal class Request : OnRequestPermissionsResultCallback {
deniedPermissionList.add(permission)
}
}
Permissions.MANAGE_EXTERNAL_STORAGE -> {
if (Permissions.isManageExternalStorage()) {
if (!Environment.isExternalStorageManager()) {
@ -105,6 +111,15 @@ internal class Request : OnRequestPermissionsResultCallback {
}
}
}
Permissions.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!powerManager.isIgnoringBatteryOptimizations(appCtx.packageName)) {
deniedPermissionList.add(permission)
}
}
}
else -> {
if (
ContextCompat.checkSelfPermission(appCtx, permission)
@ -165,6 +180,18 @@ internal class Request : OnRequestPermissionsResultCallback {
}
}
private fun toIgnoreBatterySetting() {
appCtx.startActivity<PermissionActivity> {
putExtra(PermissionActivity.KEY_RATIONALE, rationale)
putExtra(
PermissionActivity.KEY_INPUT_REQUEST_TYPE,
TYPE_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS
)
putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS_CODE, requestCode)
putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS, deniedPermissions)
}
}
override fun onRequestPermissionsResult(
permissions: Array<String>,
grantResults: IntArray
@ -196,5 +223,6 @@ internal class Request : OnRequestPermissionsResultCallback {
const val TYPE_REQUEST_SETTING = 2
const val TYPE_MANAGE_ALL_FILES_ACCESS = 3
const val TYPE_REQUEST_NOTIFICATIONS = 4
const val TYPE_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = 5
}
}

View File

@ -3,7 +3,6 @@ package io.legado.app.model
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.core.content.ContextCompat
import io.legado.app.constant.AppLog
import io.legado.app.constant.EventBus
import io.legado.app.constant.IntentAction
@ -16,6 +15,7 @@ import io.legado.app.service.TTSReadAloudService
import io.legado.app.utils.LogUtils
import io.legado.app.utils.StringUtils
import io.legado.app.utils.postEvent
import io.legado.app.utils.startForegroundServiceCompat
import io.legado.app.utils.toastOnUi
import splitties.init.appCtx
@ -56,7 +56,7 @@ object ReadAloud {
intent.putExtra("startPos", startPos)
LogUtils.d("ReadAloud", intent.toString())
try {
ContextCompat.startForegroundService(context, intent)
context.startForegroundServiceCompat(intent)
} catch (e: Exception) {
val msg = "启动朗读服务出错\n${e.localizedMessage}"
AppLog.put(msg, e)
@ -81,7 +81,7 @@ object ReadAloud {
if (BaseReadAloudService.isRun) {
val intent = Intent(context, aloudClass)
intent.action = IntentAction.pause
ContextCompat.startForegroundService(context, intent)
context.startForegroundServiceCompat(intent)
}
}
@ -89,7 +89,7 @@ object ReadAloud {
if (BaseReadAloudService.isRun) {
val intent = Intent(context, aloudClass)
intent.action = IntentAction.resume
ContextCompat.startForegroundService(context, intent)
context.startForegroundServiceCompat(intent)
}
}
@ -97,7 +97,7 @@ object ReadAloud {
if (BaseReadAloudService.isRun) {
val intent = Intent(context, aloudClass)
intent.action = IntentAction.stop
ContextCompat.startForegroundService(context, intent)
context.startForegroundServiceCompat(intent)
}
}
@ -105,7 +105,7 @@ object ReadAloud {
if (BaseReadAloudService.isRun) {
val intent = Intent(context, aloudClass)
intent.action = IntentAction.prevParagraph
ContextCompat.startForegroundService(context, intent)
context.startForegroundServiceCompat(intent)
}
}
@ -113,7 +113,7 @@ object ReadAloud {
if (BaseReadAloudService.isRun) {
val intent = Intent(context, aloudClass)
intent.action = IntentAction.nextParagraph
ContextCompat.startForegroundService(context, intent)
context.startForegroundServiceCompat(intent)
}
}
@ -121,7 +121,7 @@ object ReadAloud {
if (BaseReadAloudService.isRun) {
val intent = Intent(context, aloudClass)
intent.action = IntentAction.upTtsSpeechRate
ContextCompat.startForegroundService(context, intent)
context.startForegroundServiceCompat(intent)
}
}
@ -130,7 +130,7 @@ object ReadAloud {
val intent = Intent(context, aloudClass)
intent.action = IntentAction.setTimer
intent.putExtra("minute", minute)
ContextCompat.startForegroundService(context, intent)
context.startForegroundServiceCompat(intent)
}
}

View File

@ -168,6 +168,7 @@ abstract class BaseReadAloudService : BaseService(),
abandonFocus()
unregisterReceiver(broadcastReceiver)
postEvent(EventBus.ALOUD_STATE, Status.STOP)
notificationManager.cancel(NotificationId.ReadAloudService)
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED)
mediaSessionCompat.release()
ReadBook.uploadProgress()
@ -496,6 +497,8 @@ abstract class BaseReadAloudService : BaseService(),
nSubtitle = getString(R.string.read_aloud_s)
val builder = NotificationCompat
.Builder(this@BaseReadAloudService, AppConst.channelIdReadAloud)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
.setSmallIcon(R.drawable.ic_volume_up)
.setSubText(getString(R.string.read_aloud))
.setOngoing(true)
@ -535,7 +538,7 @@ abstract class BaseReadAloudService : BaseService(),
androidx.media.app.NotificationCompat.MediaStyle()
.setShowActionsInCompactView(0, 1, 2)
)
return builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
return builder
}
/**

View File

@ -27,6 +27,7 @@ import io.legado.app.help.book.BookHelp
import io.legado.app.help.book.ContentProcessor
import io.legado.app.help.book.getExportFileName
import io.legado.app.help.book.isLocal
import io.legado.app.help.book.isLocalModified
import io.legado.app.help.config.AppConfig
import io.legado.app.model.localBook.LocalBook
import io.legado.app.ui.book.cache.CacheActivity
@ -57,6 +58,7 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.flow.collectIndexed
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import me.ag2s.epublib.domain.Author
import me.ag2s.epublib.domain.Date
@ -121,7 +123,10 @@ class ExportBookService : BaseService() {
toastOnUi(it.localizedMessage)
}
IntentAction.stop -> stopSelf()
IntentAction.stop -> {
notificationManager.cancel(NotificationId.ExportBook)
stopSelf()
}
}
return super.onStartCommand(intent, flags, startId)
}
@ -130,6 +135,9 @@ class ExportBookService : BaseService() {
super.onDestroy()
exportProgress.clear()
exportMsg.clear()
waitExportBooks.keys.forEach {
postEvent(EventBus.EXPORT_BOOK, it)
}
}
@SuppressLint("MissingPermission")
@ -168,7 +176,7 @@ class ExportBookService : BaseService() {
return
}
exportJob = lifecycleScope.launch(IO) {
while (true) {
while (isActive) {
val (bookUrl, exportConfig) = waitExportBooks.entries.firstOrNull() ?: let {
notificationContentText = "导出完成"
upExportNotification(true)
@ -200,6 +208,7 @@ class ExportBookService : BaseService() {
}
exportMsg[book.bookUrl] = getString(R.string.export_success)
} catch (e: Throwable) {
ensureActive()
exportMsg[bookUrl] = e.localizedMessage ?: "ERROR"
AppLog.put("导出书籍<${book?.name ?: bookUrl}>出错", e)
} finally {
@ -211,10 +220,7 @@ class ExportBookService : BaseService() {
}
private fun refreshChapterList(book: Book) {
if (!book.isLocal) {
return
}
if (LocalBook.getLastModified(book).getOrDefault(0L) < book.latestChapterTime) {
if (!book.isLocal || !book.isLocalModified()) {
return
}
kotlin.runCatching {

View File

@ -538,7 +538,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
override fun onCleared() {
super.onCleared()
if (BaseReadAloudService.pause) {
if (BaseReadAloudService.isRun && BaseReadAloudService.pause) {
ReadAloud.stop(context)
}
}

View File

@ -123,6 +123,14 @@ inline fun <reified T : BroadcastReceiver> Context.broadcastPendingIntent(
return getBroadcast(this, 0, intent, flags)
}
fun Context.startForegroundServiceCompat(intent: Intent) {
try {
startService(intent)
} catch (e: IllegalStateException) {
ContextCompat.startForegroundService(this, intent)
}
}
val Context.defaultSharedPreferences: SharedPreferences
get() = PreferenceManager.getDefaultSharedPreferences(this)

View File

@ -1147,4 +1147,5 @@
<string name="font_weight_text">中/粗/细</string>
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
<string name="enable_optimize_render">启用绘制优化</string>
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
</resources>

View File

@ -1150,4 +1150,5 @@
<string name="font_weight_text">中/粗/细</string>
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
<string name="enable_optimize_render">启用绘制优化</string>
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
</resources>

View File

@ -1150,4 +1150,5 @@
<string name="font_weight_text">中/粗/细</string>
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
<string name="enable_optimize_render">启用绘制优化</string>
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
</resources>

View File

@ -1146,4 +1146,5 @@ Còn </string>
<string name="font_weight_text">中/粗/细</string>
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
<string name="enable_optimize_render">启用绘制优化</string>
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
</resources>

View File

@ -1147,4 +1147,5 @@
<string name="font_weight_text">中/粗/细</string>
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
<string name="enable_optimize_render">启用绘制优化</string>
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
</resources>

View File

@ -1149,4 +1149,5 @@
<string name="font_weight_text">中/粗/细</string>
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
<string name="enable_optimize_render">启用绘制优化</string>
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
</resources>

View File

@ -1149,4 +1149,5 @@
<string name="font_weight_text">中/粗/细</string>
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
<string name="enable_optimize_render">启用绘制优化</string>
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
</resources>

View File

@ -1150,4 +1150,5 @@
<string name="font_weight_text">N/B/L</string>
<string name="keep_swipe_tip">Keep swiping to load the next chapter…</string>
<string name="enable_optimize_render">启用绘制优化</string>
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
</resources>

View File

@ -5,7 +5,7 @@ ksp = "1.9.23-1.0.20"
agp = "8.3.2"
appcompat = "1.6.1"
colorpicker = "1.1.0"
commonsText = "1.11.0"
commonsText = "1.12.0"
constraintlayout = "2.1.4"
core = "1.12.0"
firebaseBom = "32.8.1"