Horis 2 лет назад
Родитель
Сommit
90a5f13df0

+ 7 - 1
app/src/main/java/io/legado/app/App.kt

@@ -6,6 +6,7 @@ import android.app.NotificationChannel
 import android.app.NotificationManager
 import android.content.Context
 import android.content.pm.ActivityInfo
+import android.content.pm.ApplicationInfo
 import android.content.res.Configuration
 import android.os.Build
 import com.github.liuyueyi.quick.transfer.constants.TransType
@@ -129,8 +130,13 @@ class App : Application() {
      */
     private fun installGmsTlsProvider(context: Context) {
         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(
-                "com.google.android.gms",
+                gmsPackageName,
                 CONTEXT_INCLUDE_CODE or CONTEXT_IGNORE_SECURITY
             )
             gms.classLoader

+ 1 - 0
app/src/main/java/io/legado/app/constant/PreferKey.kt

@@ -147,6 +147,7 @@ object PreferKey {
     const val optimizeRender = "optimizeRender"
     const val updateToVariant = "updateToVariant"
     const val streamReadAloudAudio = "streamReadAloudAudio"
+    const val pauseReadAloudWhilePhoneCalls = "pauseReadAloudWhilePhoneCalls"
 
     const val cPrimary = "colorPrimary"
     const val cAccent = "colorAccent"

+ 4 - 0
app/src/main/java/io/legado/app/help/config/AppConfig.kt

@@ -467,6 +467,10 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
 
     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 defaultHomePage get() = appCtx.getPrefString(PreferKey.defaultHomePage, "bookshelf")

+ 35 - 9
app/src/main/java/io/legado/app/lib/permission/PermissionActivity.kt

@@ -11,9 +11,9 @@ import androidx.activity.addCallback
 import androidx.activity.result.contract.ActivityResultContracts
 import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.app.AppCompatActivity
-import androidx.core.app.ActivityCompat
 import androidx.lifecycle.lifecycleScope
 import io.legado.app.R
+import io.legado.app.constant.AppLog
 import io.legado.app.exception.NoStackTraceException
 import io.legado.app.utils.registerForActivityResult
 import io.legado.app.utils.toastOnUi
@@ -25,13 +25,14 @@ class PermissionActivity : AppCompatActivity() {
 
     private val settingActivityResult =
         registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
-            RequestPlugins.sRequestCallback?.onSettingActivityResult()
-            finish()
+            onRequestPermissionFinish()
         }
     private val settingActivityResultAwait =
         registerForActivityResult(ActivityResultContracts.StartActivityForResult())
     private val requestPermissionResult =
         registerForActivityResult(ActivityResultContracts.RequestPermission())
+    private val requestPermissionsResult =
+        registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions())
 
     @SuppressLint("BatteryLife")
     override fun onCreate(savedInstanceState: Bundle?) {
@@ -42,7 +43,20 @@ class PermissionActivity : AppCompatActivity() {
         when (intent.getIntExtra(KEY_INPUT_REQUEST_TYPE, Request.TYPE_REQUEST_PERMISSION)) {
             //权限请求
             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) {
@@ -62,7 +76,7 @@ class PermissionActivity : AppCompatActivity() {
                         throw NoStackTraceException("no MANAGE_ALL_FILES_ACCESS_PERMISSION")
                     }
                 } catch (e: Exception) {
-                    toastOnUi(e.localizedMessage)
+                    AppLog.put("请求所有文件的管理权限出错\n$e", e, true)
                     RequestPlugins.sRequestCallback?.onError(e)
                     finish()
                 }
@@ -70,12 +84,11 @@ class PermissionActivity : AppCompatActivity() {
 
             Request.TYPE_REQUEST_NOTIFICATIONS -> showSettingDialog(permissions, rationale) {
                 lifecycleScope.launch {
-                    kotlin.runCatching {
+                    try {
                         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
                             && requestPermissionResult.launch(Permissions.POST_NOTIFICATIONS)
                         ) {
-                            RequestPlugins.sRequestCallback?.onSettingActivityResult()
-                            finish()
+                            onRequestPermissionFinish()
                         } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                             //这种方案适用于 API 26, 即8.0(含8.0)以上可以用
                             val intent = Intent()
@@ -86,6 +99,10 @@ class PermissionActivity : AppCompatActivity() {
                         } else {
                             openSettingsActivity()
                         }
+                    } catch (e: Exception) {
+                        AppLog.put("请求通知权限出错\n$e", e, true)
+                        RequestPlugins.sRequestCallback?.onError(e)
+                        finish()
                     }
                 }
             }
@@ -94,7 +111,7 @@ class PermissionActivity : AppCompatActivity() {
                 permissions, rationale
             ) {
                 lifecycleScope.launch {
-                    kotlin.runCatching {
+                    try {
                         val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
                         intent.setData(Uri.parse("package:$packageName"))
                         val className =
@@ -115,6 +132,10 @@ class PermissionActivity : AppCompatActivity() {
                         }
                         intent.component = null
                         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() {
         try {
             val settingIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)

+ 1 - 1
app/src/main/java/io/legado/app/lib/permission/Request.kt

@@ -78,7 +78,7 @@ internal class Request : OnRequestPermissionsResultCallback {
                 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                     toIgnoreBatterySetting()
                 }
-            } else if (deniedPermissions.size > 1) {
+            } else if (deniedPermissions.isNotEmpty()) {
                 appCtx.startActivity<PermissionActivity> {
                     putExtra(PermissionActivity.KEY_RATIONALE, rationale)
                     putExtra(PermissionActivity.KEY_INPUT_REQUEST_TYPE, TYPE_REQUEST_PERMISSION)

+ 81 - 0
app/src/main/java/io/legado/app/service/BaseReadAloudService.kt

@@ -14,6 +14,8 @@ import android.os.Bundle
 import android.os.PowerManager
 import android.support.v4.media.session.MediaSessionCompat
 import android.support.v4.media.session.PlaybackStateCompat
+import android.telephony.PhoneStateListener
+import android.telephony.TelephonyManager
 import androidx.annotation.CallSuper
 import androidx.core.app.NotificationCompat
 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.config.AppConfig
 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.ReadBook
 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.isVivoDevice
 import io.legado.app.utils.observeEvent
+import io.legado.app.utils.observeSharedPreferences
 import io.legado.app.utils.postEvent
 import io.legado.app.utils.toastOnUi
 import kotlinx.coroutines.Dispatchers.IO
@@ -53,6 +58,7 @@ import splitties.init.appCtx
 import splitties.systemservices.audioManager
 import splitties.systemservices.notificationManager
 import splitties.systemservices.powerManager
+import splitties.systemservices.telephonyManager
 import splitties.systemservices.wifiManager
 
 /**
@@ -102,12 +108,16 @@ abstract class BaseReadAloudService : BaseService(),
     private val mediaSessionCompat: MediaSessionCompat by lazy {
         MediaSessionCompat(this, "readAloud")
     }
+    private val phoneStateListener by lazy {
+        ReadAloudPhoneStateListener()
+    }
     internal var contentList = emptyList<String>()
     internal var nowSpeak: Int = 0
     internal var readAloudNumber: Int = 0
     internal var textChapter: TextChapter? = null
     internal var pageIndex = 0
     private var needResumeOnAudioFocusGain = false
+    private var registeredPhoneStateListener = false
     private var dsJob: Job? = null
     private var cover: Bitmap =
         BitmapFactory.decodeResource(appCtx.resources, R.drawable.icon_read_book)
@@ -133,6 +143,7 @@ abstract class BaseReadAloudService : BaseService(),
         observeLiveBus()
         initMediaSession()
         initBroadcastReceiver()
+        initPhoneStateListener()
         upMediaSessionPlaybackState(PlaybackStateCompat.STATE_PLAYING)
         setTimer(AppConfig.ttsTimer)
         if (AppConfig.ttsTimer > 0) {
@@ -157,6 +168,13 @@ abstract class BaseReadAloudService : BaseService(),
             val startPos = it.getInt("startPos")
             newReadAloud(play, pageIndex, startPos)
         }
+        observeSharedPreferences { _, key ->
+            when (key) {
+                PreferKey.pauseReadAloudWhilePhoneCalls -> {
+                    initPhoneStateListener()
+                }
+            }
+        }
     }
 
     override fun onDestroy() {
@@ -174,6 +192,7 @@ abstract class BaseReadAloudService : BaseService(),
         upMediaSessionPlaybackState(PlaybackStateCompat.STATE_STOPPED)
         mediaSessionCompat.release()
         ReadBook.uploadProgress()
+        unregisterPhoneStateListener(phoneStateListener)
     }
 
     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("来电接听,不做处理")
+                }
+            }
+        }
+    }
+
 }

+ 4 - 5
app/src/main/java/io/legado/app/ui/about/AboutFragment.kt

@@ -164,12 +164,11 @@ class AboutFragment : PreferenceFragmentCompat() {
     }
 
     private fun copyLogs(doc: FileDoc) {
-        val files = File(appCtx.externalCacheDir, "logs").listFiles()?.toList()
-        if (files.isNullOrEmpty()) {
-            return
-        }
+        val logFiles = File(appCtx.externalCacheDir, "logs")
+        val crashFiles = File(appCtx.externalCacheDir, "crash")
+
         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()
 

+ 11 - 0
app/src/main/java/io/legado/app/ui/book/read/config/ReadAloudConfigDialog.kt

@@ -14,7 +14,9 @@ import io.legado.app.constant.EventBus
 import io.legado.app.constant.PreferKey
 import io.legado.app.data.appDb
 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.prefs.SwitchPreference
 import io.legado.app.lib.prefs.fragment.PreferenceFragment
 import io.legado.app.lib.theme.backgroundColor
 import io.legado.app.lib.theme.primaryColor
@@ -79,6 +81,9 @@ class ReadAloudConfigDialog : DialogFragment() {
         override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
             addPreferencesFromResource(R.xml.pref_config_aloud)
             upSpeakEngineSummary()
+            findPreference<SwitchPreference>(PreferKey.pauseReadAloudWhilePhoneCalls)?.let {
+                it.isEnabled = AppConfig.ignoreAudioFocus
+            }
         }
 
         override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -114,6 +119,12 @@ class ReadAloudConfigDialog : DialogFragment() {
                         postEvent(EventBus.MEDIA_BUTTON, false)
                     }
                 }
+
+                PreferKey.ignoreAudioFocus -> {
+                    findPreference<SwitchPreference>(PreferKey.pauseReadAloudWhilePhoneCalls)?.let {
+                        it.isEnabled = AppConfig.ignoreAudioFocus
+                    }
+                }
             }
         }
 

+ 1 - 1
app/src/main/java/io/legado/app/utils/LogUtils.kt

@@ -53,7 +53,7 @@ object LogUtils {
             val logFolder = FileUtils.createFolderIfNotExist(root, "logs")
             val expiredTime = System.currentTimeMillis() - 7.days.inWholeMilliseconds
             logFolder.listFiles()?.forEach {
-                if (it.lastModified() < expiredTime) {
+                if (it.lastModified() < expiredTime || it.name.endsWith(".lck")) {
                     it.delete()
                 }
             }

+ 29 - 1
app/src/main/java/io/legado/app/utils/PreferencesExtensions.kt

@@ -8,6 +8,9 @@ import android.content.Context
 import android.content.ContextWrapper
 import android.content.SharedPreferences
 import androidx.core.content.edit
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
+import splitties.init.appCtx
 import java.io.File
 
 /**
@@ -100,4 +103,29 @@ fun SharedPreferences.remove(key: String) {
     edit {
         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)
+}

+ 3 - 0
app/src/main/res/values-es-rES/strings.xml

@@ -1161,4 +1161,7 @@
     <string name="beta_releaseA_version">共存版</string>
     <string name="stream_read_aloud_audio">流式播放音频</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>

+ 3 - 0
app/src/main/res/values-ja-rJP/strings.xml

@@ -1164,4 +1164,7 @@
     <string name="beta_releaseA_version">共存版</string>
     <string name="stream_read_aloud_audio">流式播放音频</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>

+ 3 - 0
app/src/main/res/values-pt-rBR/strings.xml

@@ -1164,4 +1164,7 @@
     <string name="beta_releaseA_version">共存版</string>
     <string name="stream_read_aloud_audio">流式播放音频</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>

+ 3 - 0
app/src/main/res/values-vi/strings.xml

@@ -1160,4 +1160,7 @@ Còn </string>
     <string name="beta_releaseA_version">共存版</string>
     <string name="stream_read_aloud_audio">流式播放音频</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>

+ 3 - 0
app/src/main/res/values-zh-rHK/strings.xml

@@ -1161,4 +1161,7 @@
     <string name="beta_releaseA_version">共存版</string>
     <string name="stream_read_aloud_audio">流式播放音频</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>

+ 3 - 0
app/src/main/res/values-zh-rTW/strings.xml

@@ -1163,4 +1163,7 @@
     <string name="beta_releaseA_version">共存版</string>
     <string name="stream_read_aloud_audio">流式播放音频</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>

+ 3 - 0
app/src/main/res/values-zh/strings.xml

@@ -1163,4 +1163,7 @@
     <string name="beta_releaseA_version">共存版</string>
     <string name="stream_read_aloud_audio">流式播放音频</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>

+ 3 - 0
app/src/main/res/values/strings.xml

@@ -1164,4 +1164,7 @@
     <string name="beta_releaseA_version">共存版</string>
     <string name="stream_read_aloud_audio">流式播放音频</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>

+ 6 - 0
app/src/main/res/xml/pref_config_aloud.xml

@@ -14,6 +14,12 @@
             android:summary="@string/ignore_audio_focus_summary"
             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
             android:defaultValue="false"
             android:title="@string/read_aloud_wake_lock"