mirror of
https://github.com/gedoor/legado.git
synced 2024-09-01 09:34:25 +08:00
Compare commits
5 Commits
4c6ec35d95
...
9247d56cbd
Author | SHA1 | Date | |
---|---|---|---|
|
9247d56cbd | ||
|
d774b2df7c | ||
|
17d187b4af | ||
|
df512234e6 | ||
|
065ac7e119 |
@ -33,7 +33,7 @@ abstract class BaseService : LifecycleService() {
|
|||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
LifecycleHelp.onServiceCreate(this)
|
LifecycleHelp.onServiceCreate(this)
|
||||||
checkNotificationPermission()
|
checkPermission()
|
||||||
}
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@ -71,9 +71,9 @@ abstract class BaseService : LifecycleService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 检测通知权限
|
* 检测通知权限和后台权限
|
||||||
*/
|
*/
|
||||||
private fun checkNotificationPermission() {
|
private fun checkPermission() {
|
||||||
PermissionsCompat.Builder()
|
PermissionsCompat.Builder()
|
||||||
.addPermissions(Permissions.POST_NOTIFICATIONS)
|
.addPermissions(Permissions.POST_NOTIFICATIONS)
|
||||||
.rationale(R.string.notification_permission_rationale)
|
.rationale(R.string.notification_permission_rationale)
|
||||||
@ -83,5 +83,9 @@ abstract class BaseService : LifecycleService() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.request()
|
.request()
|
||||||
|
PermissionsCompat.Builder()
|
||||||
|
.addPermissions(Permissions.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
|
||||||
|
.rationale(R.string.ignore_battery_permission_rationale)
|
||||||
|
.request()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
package io.legado.app.lib.permission
|
package io.legado.app.lib.permission
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
@ -24,6 +25,7 @@ class PermissionActivity : AppCompatActivity() {
|
|||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("BatteryLife")
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val rationale = intent.getStringExtra(KEY_RATIONALE)
|
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) {
|
onBackPressedDispatcher.addCallback(this) {
|
||||||
|
|
||||||
|
@ -43,6 +43,9 @@ object Permissions {
|
|||||||
|
|
||||||
const val ACCESS_MEDIA_LOCATION = "android.permission.ACCESS_MEDIA_LOCATION"
|
const val ACCESS_MEDIA_LOCATION = "android.permission.ACCESS_MEDIA_LOCATION"
|
||||||
|
|
||||||
|
const val REQUEST_IGNORE_BATTERY_OPTIMIZATIONS =
|
||||||
|
"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"
|
||||||
|
|
||||||
object Group {
|
object Group {
|
||||||
val STORAGE = if (isManageExternalStorage()) {
|
val STORAGE = if (isManageExternalStorage()) {
|
||||||
arrayOf(MANAGE_EXTERNAL_STORAGE)
|
arrayOf(MANAGE_EXTERNAL_STORAGE)
|
||||||
|
@ -9,6 +9,7 @@ import androidx.core.app.NotificationManagerCompat
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import io.legado.app.utils.startActivity
|
import io.legado.app.utils.startActivity
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
|
import splitties.systemservices.powerManager
|
||||||
|
|
||||||
@Suppress("MemberVisibilityCanBePrivate")
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
internal class Request : OnRequestPermissionsResultCallback {
|
internal class Request : OnRequestPermissionsResultCallback {
|
||||||
@ -73,6 +74,10 @@ internal class Request : OnRequestPermissionsResultCallback {
|
|||||||
}
|
}
|
||||||
} else if (deniedPermissions.contains(Permissions.POST_NOTIFICATIONS)) {
|
} else if (deniedPermissions.contains(Permissions.POST_NOTIFICATIONS)) {
|
||||||
toNotificationSetting()
|
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) {
|
} else if (deniedPermissions.size > 1) {
|
||||||
appCtx.startActivity<PermissionActivity> {
|
appCtx.startActivity<PermissionActivity> {
|
||||||
putExtra(PermissionActivity.KEY_RATIONALE, rationale)
|
putExtra(PermissionActivity.KEY_RATIONALE, rationale)
|
||||||
@ -98,6 +103,7 @@ internal class Request : OnRequestPermissionsResultCallback {
|
|||||||
deniedPermissionList.add(permission)
|
deniedPermissionList.add(permission)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Permissions.MANAGE_EXTERNAL_STORAGE -> {
|
Permissions.MANAGE_EXTERNAL_STORAGE -> {
|
||||||
if (Permissions.isManageExternalStorage()) {
|
if (Permissions.isManageExternalStorage()) {
|
||||||
if (!Environment.isExternalStorageManager()) {
|
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 -> {
|
else -> {
|
||||||
if (
|
if (
|
||||||
ContextCompat.checkSelfPermission(appCtx, permission)
|
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(
|
override fun onRequestPermissionsResult(
|
||||||
permissions: Array<String>,
|
permissions: Array<String>,
|
||||||
grantResults: IntArray
|
grantResults: IntArray
|
||||||
@ -196,5 +223,6 @@ internal class Request : OnRequestPermissionsResultCallback {
|
|||||||
const val TYPE_REQUEST_SETTING = 2
|
const val TYPE_REQUEST_SETTING = 2
|
||||||
const val TYPE_MANAGE_ALL_FILES_ACCESS = 3
|
const val TYPE_MANAGE_ALL_FILES_ACCESS = 3
|
||||||
const val TYPE_REQUEST_NOTIFICATIONS = 4
|
const val TYPE_REQUEST_NOTIFICATIONS = 4
|
||||||
|
const val TYPE_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = 5
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,7 +3,6 @@ package io.legado.app.model
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import io.legado.app.constant.AppLog
|
import io.legado.app.constant.AppLog
|
||||||
import io.legado.app.constant.EventBus
|
import io.legado.app.constant.EventBus
|
||||||
import io.legado.app.constant.IntentAction
|
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.LogUtils
|
||||||
import io.legado.app.utils.StringUtils
|
import io.legado.app.utils.StringUtils
|
||||||
import io.legado.app.utils.postEvent
|
import io.legado.app.utils.postEvent
|
||||||
|
import io.legado.app.utils.startForegroundServiceCompat
|
||||||
import io.legado.app.utils.toastOnUi
|
import io.legado.app.utils.toastOnUi
|
||||||
import splitties.init.appCtx
|
import splitties.init.appCtx
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ object ReadAloud {
|
|||||||
intent.putExtra("startPos", startPos)
|
intent.putExtra("startPos", startPos)
|
||||||
LogUtils.d("ReadAloud", intent.toString())
|
LogUtils.d("ReadAloud", intent.toString())
|
||||||
try {
|
try {
|
||||||
ContextCompat.startForegroundService(context, intent)
|
context.startForegroundServiceCompat(intent)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
val msg = "启动朗读服务出错\n${e.localizedMessage}"
|
val msg = "启动朗读服务出错\n${e.localizedMessage}"
|
||||||
AppLog.put(msg, e)
|
AppLog.put(msg, e)
|
||||||
@ -81,7 +81,7 @@ object ReadAloud {
|
|||||||
if (BaseReadAloudService.isRun) {
|
if (BaseReadAloudService.isRun) {
|
||||||
val intent = Intent(context, aloudClass)
|
val intent = Intent(context, aloudClass)
|
||||||
intent.action = IntentAction.pause
|
intent.action = IntentAction.pause
|
||||||
ContextCompat.startForegroundService(context, intent)
|
context.startForegroundServiceCompat(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ object ReadAloud {
|
|||||||
if (BaseReadAloudService.isRun) {
|
if (BaseReadAloudService.isRun) {
|
||||||
val intent = Intent(context, aloudClass)
|
val intent = Intent(context, aloudClass)
|
||||||
intent.action = IntentAction.resume
|
intent.action = IntentAction.resume
|
||||||
ContextCompat.startForegroundService(context, intent)
|
context.startForegroundServiceCompat(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ object ReadAloud {
|
|||||||
if (BaseReadAloudService.isRun) {
|
if (BaseReadAloudService.isRun) {
|
||||||
val intent = Intent(context, aloudClass)
|
val intent = Intent(context, aloudClass)
|
||||||
intent.action = IntentAction.stop
|
intent.action = IntentAction.stop
|
||||||
ContextCompat.startForegroundService(context, intent)
|
context.startForegroundServiceCompat(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ object ReadAloud {
|
|||||||
if (BaseReadAloudService.isRun) {
|
if (BaseReadAloudService.isRun) {
|
||||||
val intent = Intent(context, aloudClass)
|
val intent = Intent(context, aloudClass)
|
||||||
intent.action = IntentAction.prevParagraph
|
intent.action = IntentAction.prevParagraph
|
||||||
ContextCompat.startForegroundService(context, intent)
|
context.startForegroundServiceCompat(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +113,7 @@ object ReadAloud {
|
|||||||
if (BaseReadAloudService.isRun) {
|
if (BaseReadAloudService.isRun) {
|
||||||
val intent = Intent(context, aloudClass)
|
val intent = Intent(context, aloudClass)
|
||||||
intent.action = IntentAction.nextParagraph
|
intent.action = IntentAction.nextParagraph
|
||||||
ContextCompat.startForegroundService(context, intent)
|
context.startForegroundServiceCompat(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ object ReadAloud {
|
|||||||
if (BaseReadAloudService.isRun) {
|
if (BaseReadAloudService.isRun) {
|
||||||
val intent = Intent(context, aloudClass)
|
val intent = Intent(context, aloudClass)
|
||||||
intent.action = IntentAction.upTtsSpeechRate
|
intent.action = IntentAction.upTtsSpeechRate
|
||||||
ContextCompat.startForegroundService(context, intent)
|
context.startForegroundServiceCompat(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +130,7 @@ object ReadAloud {
|
|||||||
val intent = Intent(context, aloudClass)
|
val intent = Intent(context, aloudClass)
|
||||||
intent.action = IntentAction.setTimer
|
intent.action = IntentAction.setTimer
|
||||||
intent.putExtra("minute", minute)
|
intent.putExtra("minute", minute)
|
||||||
ContextCompat.startForegroundService(context, intent)
|
context.startForegroundServiceCompat(intent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +168,7 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
abandonFocus()
|
abandonFocus()
|
||||||
unregisterReceiver(broadcastReceiver)
|
unregisterReceiver(broadcastReceiver)
|
||||||
postEvent(EventBus.ALOUD_STATE, Status.STOP)
|
postEvent(EventBus.ALOUD_STATE, Status.STOP)
|
||||||
|
notificationManager.cancel(NotificationId.ReadAloudService)
|
||||||
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED)
|
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED)
|
||||||
mediaSessionCompat.release()
|
mediaSessionCompat.release()
|
||||||
ReadBook.uploadProgress()
|
ReadBook.uploadProgress()
|
||||||
@ -496,6 +497,8 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
nSubtitle = getString(R.string.read_aloud_s)
|
nSubtitle = getString(R.string.read_aloud_s)
|
||||||
val builder = NotificationCompat
|
val builder = NotificationCompat
|
||||||
.Builder(this@BaseReadAloudService, AppConst.channelIdReadAloud)
|
.Builder(this@BaseReadAloudService, AppConst.channelIdReadAloud)
|
||||||
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
|
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
|
||||||
.setSmallIcon(R.drawable.ic_volume_up)
|
.setSmallIcon(R.drawable.ic_volume_up)
|
||||||
.setSubText(getString(R.string.read_aloud))
|
.setSubText(getString(R.string.read_aloud))
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
@ -535,7 +538,7 @@ abstract class BaseReadAloudService : BaseService(),
|
|||||||
androidx.media.app.NotificationCompat.MediaStyle()
|
androidx.media.app.NotificationCompat.MediaStyle()
|
||||||
.setShowActionsInCompactView(0, 1, 2)
|
.setShowActionsInCompactView(0, 1, 2)
|
||||||
)
|
)
|
||||||
return builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
return builder
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -538,7 +538,7 @@ class ReadBookViewModel(application: Application) : BaseViewModel(application) {
|
|||||||
|
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
super.onCleared()
|
super.onCleared()
|
||||||
if (BaseReadAloudService.pause) {
|
if (BaseReadAloudService.isRun && BaseReadAloudService.pause) {
|
||||||
ReadAloud.stop(context)
|
ReadAloud.stop(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,6 +123,14 @@ inline fun <reified T : BroadcastReceiver> Context.broadcastPendingIntent(
|
|||||||
return getBroadcast(this, 0, intent, flags)
|
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
|
val Context.defaultSharedPreferences: SharedPreferences
|
||||||
get() = PreferenceManager.getDefaultSharedPreferences(this)
|
get() = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
|
||||||
|
@ -1147,4 +1147,5 @@
|
|||||||
<string name="font_weight_text">中/粗/细</string>
|
<string name="font_weight_text">中/粗/细</string>
|
||||||
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
||||||
<string name="enable_optimize_render">启用绘制优化</string>
|
<string name="enable_optimize_render">启用绘制优化</string>
|
||||||
|
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1150,4 +1150,5 @@
|
|||||||
<string name="font_weight_text">中/粗/细</string>
|
<string name="font_weight_text">中/粗/细</string>
|
||||||
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
||||||
<string name="enable_optimize_render">启用绘制优化</string>
|
<string name="enable_optimize_render">启用绘制优化</string>
|
||||||
|
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1150,4 +1150,5 @@
|
|||||||
<string name="font_weight_text">中/粗/细</string>
|
<string name="font_weight_text">中/粗/细</string>
|
||||||
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
||||||
<string name="enable_optimize_render">启用绘制优化</string>
|
<string name="enable_optimize_render">启用绘制优化</string>
|
||||||
|
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1146,4 +1146,5 @@ Còn </string>
|
|||||||
<string name="font_weight_text">中/粗/细</string>
|
<string name="font_weight_text">中/粗/细</string>
|
||||||
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
||||||
<string name="enable_optimize_render">启用绘制优化</string>
|
<string name="enable_optimize_render">启用绘制优化</string>
|
||||||
|
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1147,4 +1147,5 @@
|
|||||||
<string name="font_weight_text">中/粗/细</string>
|
<string name="font_weight_text">中/粗/细</string>
|
||||||
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
||||||
<string name="enable_optimize_render">启用绘制优化</string>
|
<string name="enable_optimize_render">启用绘制优化</string>
|
||||||
|
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1149,4 +1149,5 @@
|
|||||||
<string name="font_weight_text">中/粗/细</string>
|
<string name="font_weight_text">中/粗/细</string>
|
||||||
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
||||||
<string name="enable_optimize_render">启用绘制优化</string>
|
<string name="enable_optimize_render">启用绘制优化</string>
|
||||||
|
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1149,4 +1149,5 @@
|
|||||||
<string name="font_weight_text">中/粗/细</string>
|
<string name="font_weight_text">中/粗/细</string>
|
||||||
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
<string name="keep_swipe_tip">继续滑动以加载下一章…</string>
|
||||||
<string name="enable_optimize_render">启用绘制优化</string>
|
<string name="enable_optimize_render">启用绘制优化</string>
|
||||||
|
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -1150,4 +1150,5 @@
|
|||||||
<string name="font_weight_text">N/B/L</string>
|
<string name="font_weight_text">N/B/L</string>
|
||||||
<string name="keep_swipe_tip">Keep swiping to load the next chapter…</string>
|
<string name="keep_swipe_tip">Keep swiping to load the next chapter…</string>
|
||||||
<string name="enable_optimize_render">启用绘制优化</string>
|
<string name="enable_optimize_render">启用绘制优化</string>
|
||||||
|
<string name="ignore_battery_permission_rationale">阅读需要请求后台权限以保持服务正常运行</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user