This commit is contained in:
Horis
2024-08-23 17:41:14 +08:00
parent e48c2f5b36
commit 90a5f13df0
19 changed files with 204 additions and 18 deletions
+7 -1
View File
@@ -6,6 +6,7 @@ import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.content.Context import android.content.Context
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.pm.ApplicationInfo
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Build import android.os.Build
import com.github.liuyueyi.quick.transfer.constants.TransType import com.github.liuyueyi.quick.transfer.constants.TransType
@@ -129,8 +130,13 @@ class App : Application() {
*/ */
private fun installGmsTlsProvider(context: Context) { private fun installGmsTlsProvider(context: Context) {
try { try {
val gmsPackageName = "com.google.android.gms"
val appInfo = packageManager.getApplicationInfo(gmsPackageName, 0)
if ((appInfo.flags and ApplicationInfo.FLAG_SYSTEM) == 0) {
return
}
val gms = context.createPackageContext( val gms = context.createPackageContext(
"com.google.android.gms", gmsPackageName,
CONTEXT_INCLUDE_CODE or CONTEXT_IGNORE_SECURITY CONTEXT_INCLUDE_CODE or CONTEXT_IGNORE_SECURITY
) )
gms.classLoader gms.classLoader
@@ -147,6 +147,7 @@ object PreferKey {
const val optimizeRender = "optimizeRender" const val optimizeRender = "optimizeRender"
const val updateToVariant = "updateToVariant" const val updateToVariant = "updateToVariant"
const val streamReadAloudAudio = "streamReadAloudAudio" const val streamReadAloudAudio = "streamReadAloudAudio"
const val pauseReadAloudWhilePhoneCalls = "pauseReadAloudWhilePhoneCalls"
const val cPrimary = "colorPrimary" const val cPrimary = "colorPrimary"
const val cAccent = "colorAccent" const val cAccent = "colorAccent"
@@ -467,6 +467,10 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
val ignoreAudioFocus get() = appCtx.getPrefBoolean(PreferKey.ignoreAudioFocus, false) val ignoreAudioFocus get() = appCtx.getPrefBoolean(PreferKey.ignoreAudioFocus, false)
var pauseReadAloudWhilePhoneCalls
get() = appCtx.getPrefBoolean(PreferKey.pauseReadAloudWhilePhoneCalls, false)
set(value) = appCtx.putPrefBoolean(PreferKey.pauseReadAloudWhilePhoneCalls, value)
val onlyLatestBackup get() = appCtx.getPrefBoolean(PreferKey.onlyLatestBackup, true) val onlyLatestBackup get() = appCtx.getPrefBoolean(PreferKey.onlyLatestBackup, true)
val defaultHomePage get() = appCtx.getPrefString(PreferKey.defaultHomePage, "bookshelf") val defaultHomePage get() = appCtx.getPrefString(PreferKey.defaultHomePage, "bookshelf")
@@ -11,9 +11,9 @@ import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.AppLog
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.utils.registerForActivityResult import io.legado.app.utils.registerForActivityResult
import io.legado.app.utils.toastOnUi import io.legado.app.utils.toastOnUi
@@ -25,13 +25,14 @@ class PermissionActivity : AppCompatActivity() {
private val settingActivityResult = private val settingActivityResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
RequestPlugins.sRequestCallback?.onSettingActivityResult() onRequestPermissionFinish()
finish()
} }
private val settingActivityResultAwait = private val settingActivityResultAwait =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) registerForActivityResult(ActivityResultContracts.StartActivityForResult())
private val requestPermissionResult = private val requestPermissionResult =
registerForActivityResult(ActivityResultContracts.RequestPermission()) registerForActivityResult(ActivityResultContracts.RequestPermission())
private val requestPermissionsResult =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions())
@SuppressLint("BatteryLife") @SuppressLint("BatteryLife")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
@@ -42,7 +43,20 @@ class PermissionActivity : AppCompatActivity() {
when (intent.getIntExtra(KEY_INPUT_REQUEST_TYPE, Request.TYPE_REQUEST_PERMISSION)) { when (intent.getIntExtra(KEY_INPUT_REQUEST_TYPE, Request.TYPE_REQUEST_PERMISSION)) {
//权限请求 //权限请求
Request.TYPE_REQUEST_PERMISSION -> showSettingDialog(permissions, rationale) { Request.TYPE_REQUEST_PERMISSION -> showSettingDialog(permissions, rationale) {
ActivityCompat.requestPermissions(this, permissions, requestCode) lifecycleScope.launch {
try {
val result = requestPermissionsResult.launch(permissions)
if (result.values.all { it }) {
onRequestPermissionFinish()
} else {
openSettingsActivity()
}
} catch (e: Exception) {
AppLog.put("请求权限出错\n$e", e, true)
RequestPlugins.sRequestCallback?.onError(e)
finish()
}
}
} }
//跳转到设置界面 //跳转到设置界面
Request.TYPE_REQUEST_SETTING -> showSettingDialog(permissions, rationale) { Request.TYPE_REQUEST_SETTING -> showSettingDialog(permissions, rationale) {
@@ -62,7 +76,7 @@ class PermissionActivity : AppCompatActivity() {
throw NoStackTraceException("no MANAGE_ALL_FILES_ACCESS_PERMISSION") throw NoStackTraceException("no MANAGE_ALL_FILES_ACCESS_PERMISSION")
} }
} catch (e: Exception) { } catch (e: Exception) {
toastOnUi(e.localizedMessage) AppLog.put("请求所有文件的管理权限出错\n$e", e, true)
RequestPlugins.sRequestCallback?.onError(e) RequestPlugins.sRequestCallback?.onError(e)
finish() finish()
} }
@@ -70,12 +84,11 @@ class PermissionActivity : AppCompatActivity() {
Request.TYPE_REQUEST_NOTIFICATIONS -> showSettingDialog(permissions, rationale) { Request.TYPE_REQUEST_NOTIFICATIONS -> showSettingDialog(permissions, rationale) {
lifecycleScope.launch { lifecycleScope.launch {
kotlin.runCatching { try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
&& requestPermissionResult.launch(Permissions.POST_NOTIFICATIONS) && requestPermissionResult.launch(Permissions.POST_NOTIFICATIONS)
) { ) {
RequestPlugins.sRequestCallback?.onSettingActivityResult() onRequestPermissionFinish()
finish()
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//这种方案适用于 API 26, 即8.0(含8.0)以上可以用 //这种方案适用于 API 26, 即8.0(含8.0)以上可以用
val intent = Intent() val intent = Intent()
@@ -86,6 +99,10 @@ class PermissionActivity : AppCompatActivity() {
} else { } else {
openSettingsActivity() openSettingsActivity()
} }
} catch (e: Exception) {
AppLog.put("请求通知权限出错\n$e", e, true)
RequestPlugins.sRequestCallback?.onError(e)
finish()
} }
} }
} }
@@ -94,7 +111,7 @@ class PermissionActivity : AppCompatActivity() {
permissions, rationale permissions, rationale
) { ) {
lifecycleScope.launch { lifecycleScope.launch {
kotlin.runCatching { try {
val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS) val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
intent.setData(Uri.parse("package:$packageName")) intent.setData(Uri.parse("package:$packageName"))
val className = val className =
@@ -115,6 +132,10 @@ class PermissionActivity : AppCompatActivity() {
} }
intent.component = null intent.component = null
settingActivityResult.launch(intent) settingActivityResult.launch(intent)
} catch (e: Exception) {
AppLog.put("请求后台权限出错\n$e", e, true)
RequestPlugins.sRequestCallback?.onError(e)
finish()
} }
} }
} }
@@ -124,6 +145,11 @@ class PermissionActivity : AppCompatActivity() {
} }
} }
private fun onRequestPermissionFinish() {
RequestPlugins.sRequestCallback?.onSettingActivityResult()
finish()
}
private fun openSettingsActivity() { private fun openSettingsActivity() {
try { try {
val settingIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) val settingIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
@@ -78,7 +78,7 @@ internal class Request : OnRequestPermissionsResultCallback {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
toIgnoreBatterySetting() toIgnoreBatterySetting()
} }
} else if (deniedPermissions.size > 1) { } else if (deniedPermissions.isNotEmpty()) {
appCtx.startActivity<PermissionActivity> { appCtx.startActivity<PermissionActivity> {
putExtra(PermissionActivity.KEY_RATIONALE, rationale) putExtra(PermissionActivity.KEY_RATIONALE, rationale)
putExtra(PermissionActivity.KEY_INPUT_REQUEST_TYPE, TYPE_REQUEST_PERMISSION) putExtra(PermissionActivity.KEY_INPUT_REQUEST_TYPE, TYPE_REQUEST_PERMISSION)
@@ -14,6 +14,8 @@ import android.os.Bundle
import android.os.PowerManager import android.os.PowerManager
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 android.telephony.PhoneStateListener
import android.telephony.TelephonyManager
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
@@ -31,6 +33,8 @@ import io.legado.app.constant.Status
import io.legado.app.help.MediaHelp import io.legado.app.help.MediaHelp
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.glide.ImageLoader import io.legado.app.help.glide.ImageLoader
import io.legado.app.lib.permission.Permissions
import io.legado.app.lib.permission.PermissionsCompat
import io.legado.app.model.ReadAloud import io.legado.app.model.ReadAloud
import io.legado.app.model.ReadBook import io.legado.app.model.ReadBook
import io.legado.app.receiver.MediaButtonReceiver import io.legado.app.receiver.MediaButtonReceiver
@@ -41,6 +45,7 @@ import io.legado.app.utils.broadcastPendingIntent
import io.legado.app.utils.getPrefBoolean import io.legado.app.utils.getPrefBoolean
import io.legado.app.utils.isVivoDevice import io.legado.app.utils.isVivoDevice
import io.legado.app.utils.observeEvent import io.legado.app.utils.observeEvent
import io.legado.app.utils.observeSharedPreferences
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.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
@@ -53,6 +58,7 @@ import splitties.init.appCtx
import splitties.systemservices.audioManager import splitties.systemservices.audioManager
import splitties.systemservices.notificationManager import splitties.systemservices.notificationManager
import splitties.systemservices.powerManager import splitties.systemservices.powerManager
import splitties.systemservices.telephonyManager
import splitties.systemservices.wifiManager import splitties.systemservices.wifiManager
/** /**
@@ -102,12 +108,16 @@ abstract class BaseReadAloudService : BaseService(),
private val mediaSessionCompat: MediaSessionCompat by lazy { private val mediaSessionCompat: MediaSessionCompat by lazy {
MediaSessionCompat(this, "readAloud") MediaSessionCompat(this, "readAloud")
} }
private val phoneStateListener by lazy {
ReadAloudPhoneStateListener()
}
internal var contentList = emptyList<String>() internal var contentList = emptyList<String>()
internal var nowSpeak: Int = 0 internal var nowSpeak: Int = 0
internal var readAloudNumber: Int = 0 internal var readAloudNumber: Int = 0
internal var textChapter: TextChapter? = null internal var textChapter: TextChapter? = null
internal var pageIndex = 0 internal var pageIndex = 0
private var needResumeOnAudioFocusGain = false private var needResumeOnAudioFocusGain = false
private var registeredPhoneStateListener = false
private var dsJob: Job? = null private var dsJob: Job? = null
private var cover: Bitmap = private var cover: Bitmap =
BitmapFactory.decodeResource(appCtx.resources, R.drawable.icon_read_book) BitmapFactory.decodeResource(appCtx.resources, R.drawable.icon_read_book)
@@ -133,6 +143,7 @@ abstract class BaseReadAloudService : BaseService(),
observeLiveBus() observeLiveBus()
initMediaSession() initMediaSession()
initBroadcastReceiver() initBroadcastReceiver()
initPhoneStateListener()
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING) upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING)
setTimer(AppConfig.ttsTimer) setTimer(AppConfig.ttsTimer)
if (AppConfig.ttsTimer > 0) { if (AppConfig.ttsTimer > 0) {
@@ -157,6 +168,13 @@ abstract class BaseReadAloudService : BaseService(),
val startPos = it.getInt("startPos") val startPos = it.getInt("startPos")
newReadAloud(play, pageIndex, startPos) newReadAloud(play, pageIndex, startPos)
} }
observeSharedPreferences { _, key ->
when (key) {
PreferKey.pauseReadAloudWhilePhoneCalls -> {
initPhoneStateListener()
}
}
}
} }
override fun onDestroy() { override fun onDestroy() {
@@ -174,6 +192,7 @@ abstract class BaseReadAloudService : BaseService(),
upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED) upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED)
mediaSessionCompat.release() mediaSessionCompat.release()
ReadBook.uploadProgress() ReadBook.uploadProgress()
unregisterPhoneStateListener(phoneStateListener)
} }
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
@@ -596,4 +615,66 @@ abstract class BaseReadAloudService : BaseService(),
} }
} }
private fun initPhoneStateListener() {
val needRegister = AppConfig.ignoreAudioFocus && AppConfig.pauseReadAloudWhilePhoneCalls
if (needRegister && registeredPhoneStateListener) {
return
}
if (needRegister) {
registerPhoneStateListener(phoneStateListener)
} else {
unregisterPhoneStateListener(phoneStateListener)
}
}
@Suppress("DEPRECATION")
private fun unregisterPhoneStateListener(l: PhoneStateListener) {
if (registeredPhoneStateListener) {
registerPhoneStateListener(l, true)
}
}
@Suppress("DEPRECATION")
private fun registerPhoneStateListener(l: PhoneStateListener, unregister: Boolean = false) {
try {
if (unregister) {
telephonyManager.listen(l, PhoneStateListener.LISTEN_NONE)
registeredPhoneStateListener = false
} else {
telephonyManager.listen(l, PhoneStateListener.LISTEN_CALL_STATE)
registeredPhoneStateListener = true
}
} catch (e: SecurityException) {
PermissionsCompat.Builder()
.addPermissions(Permissions.READ_PHONE_STATE)
.rationale(R.string.read_aloud_read_phone_state_permission_rationale)
.onGranted {
registerPhoneStateListener(l, unregister)
}
.request()
}
}
@Suppress("DEPRECATION", "OVERRIDE_DEPRECATION")
inner class ReadAloudPhoneStateListener : PhoneStateListener() {
override fun onCallStateChanged(state: Int, phoneNumber: String?) {
super.onCallStateChanged(state, phoneNumber)
when (state) {
TelephonyManager.CALL_STATE_IDLE -> {
AppLog.put("来电结束,继续朗读")
resumeReadAloud()
}
TelephonyManager.CALL_STATE_RINGING -> {
AppLog.put("来电响铃,暂停朗读")
pauseReadAloud()
}
TelephonyManager.CALL_STATE_OFFHOOK -> {
AppLog.put("来电接听,不做处理")
}
}
}
}
} }
@@ -164,12 +164,11 @@ class AboutFragment : PreferenceFragmentCompat() {
} }
private fun copyLogs(doc: FileDoc) { private fun copyLogs(doc: FileDoc) {
val files = File(appCtx.externalCacheDir, "logs").listFiles()?.toList() val logFiles = File(appCtx.externalCacheDir, "logs")
if (files.isNullOrEmpty()) { val crashFiles = File(appCtx.externalCacheDir, "crash")
return
}
val zipFile = File(appCtx.externalCacheDir, "logs.zip") val zipFile = File(appCtx.externalCacheDir, "logs.zip")
ZipUtils.zipFiles(files.filter { it.name.endsWith(".txt") }, zipFile) ZipUtils.zipFiles(arrayListOf(logFiles, crashFiles), zipFile)
doc.find("logs.zip")?.delete() doc.find("logs.zip")?.delete()
@@ -14,7 +14,9 @@ import io.legado.app.constant.EventBus
import io.legado.app.constant.PreferKey import io.legado.app.constant.PreferKey
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.help.IntentHelp import io.legado.app.help.IntentHelp
import io.legado.app.help.config.AppConfig
import io.legado.app.lib.dialogs.SelectItem import io.legado.app.lib.dialogs.SelectItem
import io.legado.app.lib.prefs.SwitchPreference
import io.legado.app.lib.prefs.fragment.PreferenceFragment import io.legado.app.lib.prefs.fragment.PreferenceFragment
import io.legado.app.lib.theme.backgroundColor import io.legado.app.lib.theme.backgroundColor
import io.legado.app.lib.theme.primaryColor import io.legado.app.lib.theme.primaryColor
@@ -79,6 +81,9 @@ class ReadAloudConfigDialog : DialogFragment() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_config_aloud) addPreferencesFromResource(R.xml.pref_config_aloud)
upSpeakEngineSummary() upSpeakEngineSummary()
findPreference<SwitchPreference>(PreferKey.pauseReadAloudWhilePhoneCalls)?.let {
it.isEnabled = AppConfig.ignoreAudioFocus
}
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -114,6 +119,12 @@ class ReadAloudConfigDialog : DialogFragment() {
postEvent(EventBus.MEDIA_BUTTON, false) postEvent(EventBus.MEDIA_BUTTON, false)
} }
} }
PreferKey.ignoreAudioFocus -> {
findPreference<SwitchPreference>(PreferKey.pauseReadAloudWhilePhoneCalls)?.let {
it.isEnabled = AppConfig.ignoreAudioFocus
}
}
} }
} }
@@ -53,7 +53,7 @@ object LogUtils {
val logFolder = FileUtils.createFolderIfNotExist(root, "logs") val logFolder = FileUtils.createFolderIfNotExist(root, "logs")
val expiredTime = System.currentTimeMillis() - 7.days.inWholeMilliseconds val expiredTime = System.currentTimeMillis() - 7.days.inWholeMilliseconds
logFolder.listFiles()?.forEach { logFolder.listFiles()?.forEach {
if (it.lastModified() < expiredTime) { if (it.lastModified() < expiredTime || it.name.endsWith(".lck")) {
it.delete() it.delete()
} }
} }
@@ -8,6 +8,9 @@ import android.content.Context
import android.content.ContextWrapper import android.content.ContextWrapper
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit import androidx.core.content.edit
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import splitties.init.appCtx
import java.io.File import java.io.File
/** /**
@@ -100,4 +103,29 @@ fun SharedPreferences.remove(key: String) {
edit { edit {
remove(key) remove(key)
} }
} }
fun LifecycleOwner.observeSharedPreferences(
prefs: SharedPreferences = appCtx.defaultSharedPreferences,
l: SharedPreferences.OnSharedPreferenceChangeListener
) {
val observer = object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
prefs.registerOnSharedPreferenceChangeListener(l)
}
override fun onDestroy(owner: LifecycleOwner) {
prefs.unregisterOnSharedPreferenceChangeListener(l)
lifecycle.removeObserver(this)
}
override fun onPause(owner: LifecycleOwner) {
prefs.unregisterOnSharedPreferenceChangeListener(l)
}
override fun onResume(owner: LifecycleOwner) {
prefs.registerOnSharedPreferenceChangeListener(l)
}
}
lifecycle.addObserver(observer)
}
@@ -1161,4 +1161,7 @@
<string name="beta_releaseA_version">共存版</string> <string name="beta_releaseA_version">共存版</string>
<string name="stream_read_aloud_audio">流式播放音频</string> <string name="stream_read_aloud_audio">流式播放音频</string>
<string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string> <string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string>
<string name="pause_read_aloud_while_phone_calls_title">来电期间暂停朗读</string>
<string name="pause_read_aloud_while_phone_calls_summary">在通话期间暂停朗读,需要读取手机状态权限</string>
<string name="read_aloud_read_phone_state_permission_rationale">阅读需要读取手机状态实现来电期间暂停朗读功能</string>
</resources> </resources>
@@ -1164,4 +1164,7 @@
<string name="beta_releaseA_version">共存版</string> <string name="beta_releaseA_version">共存版</string>
<string name="stream_read_aloud_audio">流式播放音频</string> <string name="stream_read_aloud_audio">流式播放音频</string>
<string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string> <string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string>
<string name="pause_read_aloud_while_phone_calls_title">来电期间暂停朗读</string>
<string name="pause_read_aloud_while_phone_calls_summary">在通话期间暂停朗读,需要读取手机状态权限</string>
<string name="read_aloud_read_phone_state_permission_rationale">阅读需要读取手机状态实现来电期间暂停朗读功能</string>
</resources> </resources>
@@ -1164,4 +1164,7 @@
<string name="beta_releaseA_version">共存版</string> <string name="beta_releaseA_version">共存版</string>
<string name="stream_read_aloud_audio">流式播放音频</string> <string name="stream_read_aloud_audio">流式播放音频</string>
<string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string> <string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string>
<string name="pause_read_aloud_while_phone_calls_title">来电期间暂停朗读</string>
<string name="pause_read_aloud_while_phone_calls_summary">在通话期间暂停朗读,需要读取手机状态权限</string>
<string name="read_aloud_read_phone_state_permission_rationale">阅读需要读取手机状态实现来电期间暂停朗读功能</string>
</resources> </resources>
+3
View File
@@ -1160,4 +1160,7 @@ Còn </string>
<string name="beta_releaseA_version">共存版</string> <string name="beta_releaseA_version">共存版</string>
<string name="stream_read_aloud_audio">流式播放音频</string> <string name="stream_read_aloud_audio">流式播放音频</string>
<string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string> <string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string>
<string name="pause_read_aloud_while_phone_calls_title">来电期间暂停朗读</string>
<string name="pause_read_aloud_while_phone_calls_summary">在通话期间暂停朗读,需要读取手机状态权限</string>
<string name="read_aloud_read_phone_state_permission_rationale">阅读需要读取手机状态实现来电期间暂停朗读功能</string>
</resources> </resources>
@@ -1161,4 +1161,7 @@
<string name="beta_releaseA_version">共存版</string> <string name="beta_releaseA_version">共存版</string>
<string name="stream_read_aloud_audio">流式播放音频</string> <string name="stream_read_aloud_audio">流式播放音频</string>
<string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string> <string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string>
<string name="pause_read_aloud_while_phone_calls_title">来电期间暂停朗读</string>
<string name="pause_read_aloud_while_phone_calls_summary">在通话期间暂停朗读,需要读取手机状态权限</string>
<string name="read_aloud_read_phone_state_permission_rationale">阅读需要读取手机状态实现来电期间暂停朗读功能</string>
</resources> </resources>
@@ -1163,4 +1163,7 @@
<string name="beta_releaseA_version">共存版</string> <string name="beta_releaseA_version">共存版</string>
<string name="stream_read_aloud_audio">流式播放音频</string> <string name="stream_read_aloud_audio">流式播放音频</string>
<string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string> <string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string>
<string name="pause_read_aloud_while_phone_calls_title">来电期间暂停朗读</string>
<string name="pause_read_aloud_while_phone_calls_summary">在通话期间暂停朗读,需要读取手机状态权限</string>
<string name="read_aloud_read_phone_state_permission_rationale">阅读需要读取手机状态实现来电期间暂停朗读功能</string>
</resources> </resources>
+3
View File
@@ -1163,4 +1163,7 @@
<string name="beta_releaseA_version">共存版</string> <string name="beta_releaseA_version">共存版</string>
<string name="stream_read_aloud_audio">流式播放音频</string> <string name="stream_read_aloud_audio">流式播放音频</string>
<string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string> <string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string>
<string name="pause_read_aloud_while_phone_calls_title">来电期间暂停朗读</string>
<string name="pause_read_aloud_while_phone_calls_summary">在通话期间暂停朗读,需要读取手机状态权限</string>
<string name="read_aloud_read_phone_state_permission_rationale">阅读需要读取手机状态实现来电期间暂停朗读功能</string>
</resources> </resources>
+3
View File
@@ -1164,4 +1164,7 @@
<string name="beta_releaseA_version">共存版</string> <string name="beta_releaseA_version">共存版</string>
<string name="stream_read_aloud_audio">流式播放音频</string> <string name="stream_read_aloud_audio">流式播放音频</string>
<string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string> <string name="stream_read_aloud_audio_summary">即边下边播,网络不好时播放会断断续续,仅TTS源有效</string>
<string name="pause_read_aloud_while_phone_calls_title">来电期间暂停朗读</string>
<string name="pause_read_aloud_while_phone_calls_summary">在通话期间暂停朗读,需要读取手机状态权限</string>
<string name="read_aloud_read_phone_state_permission_rationale">阅读需要读取手机状态实现来电期间暂停朗读功能</string>
</resources> </resources>
@@ -14,6 +14,12 @@
android:summary="@string/ignore_audio_focus_summary" android:summary="@string/ignore_audio_focus_summary"
android:title="@string/ignore_audio_focus_title" /> android:title="@string/ignore_audio_focus_title" />
<io.legado.app.lib.prefs.SwitchPreference
android:defaultValue="false"
android:key="pauseReadAloudWhilePhoneCalls"
android:summary="@string/pause_read_aloud_while_phone_calls_summary"
android:title="@string/pause_read_aloud_while_phone_calls_title" />
<io.legado.app.lib.prefs.SwitchPreference <io.legado.app.lib.prefs.SwitchPreference
android:defaultValue="false" android:defaultValue="false"
android:title="@string/read_aloud_wake_lock" android:title="@string/read_aloud_wake_lock"