Using TelephonyListener instead of PhoneStateListener that has been deprecated starting API 31

This commit is contained in:
Sylvain Berfini 2021-09-09 11:58:08 +02:00
parent e65957f047
commit 2f912828ee
5 changed files with 194 additions and 33 deletions

View file

@ -26,6 +26,7 @@ import android.content.pm.PackageManager
import android.graphics.Bitmap import android.graphics.Bitmap
import android.net.Uri import android.net.Uri
import android.os.Vibrator import android.os.Vibrator
import android.telephony.TelephonyManager
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
@ -50,6 +51,14 @@ class Compatibility {
} }
} }
fun createPhoneListener(telephonyManager: TelephonyManager): PhoneStateInterface {
return if (Version.sdkStrictlyBelow(Version.API31_ANDROID_12)) {
PhoneStateListener(telephonyManager)
} else {
TelephonyListener(telephonyManager)
}
}
/* UI */ /* UI */
fun setShowWhenLocked(activity: Activity, enable: Boolean) { fun setShowWhenLocked(activity: Activity, enable: Boolean) {

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2010-2021 Belledonne Communications SARL.
*
* This file is part of linphone-android
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.linphone.compatibility
interface PhoneStateInterface {
fun destroy()
fun isInCall(): Boolean
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2010-2021 Belledonne Communications SARL.
*
* This file is part of linphone-android
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.linphone.compatibility
import android.telephony.PhoneStateListener
import android.telephony.TelephonyManager
import org.linphone.core.tools.Log
class PhoneStateListener(private val telephonyManager: TelephonyManager) : PhoneStateInterface {
private var gsmCallActive = false
private val phoneStateListener = object : PhoneStateListener() {
override fun onCallStateChanged(state: Int, phoneNumber: String?) {
gsmCallActive = when (state) {
TelephonyManager.CALL_STATE_OFFHOOK -> {
Log.i("[Context] Phone state is off hook")
true
}
TelephonyManager.CALL_STATE_RINGING -> {
Log.i("[Context] Phone state is ringing")
true
}
TelephonyManager.CALL_STATE_IDLE -> {
Log.i("[Context] Phone state is idle")
false
}
else -> {
Log.w("[Context] Phone state is unexpected: $state")
false
}
}
}
}
init {
Log.i("[Phone State Listener] Registering phone state listener")
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE)
}
override fun destroy() {
Log.i("[Phone State Listener] Unregistering phone state listener")
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE)
}
override fun isInCall(): Boolean {
return gsmCallActive
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2010-2021 Belledonne Communications SARL.
*
* This file is part of linphone-android
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.linphone.compatibility
import android.annotation.TargetApi
import android.os.Handler
import android.os.Looper
import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager
import java.util.concurrent.Executor
import org.linphone.core.tools.Log
@TargetApi(31)
class TelephonyListener(private val telephonyManager: TelephonyManager) : PhoneStateInterface {
private var gsmCallActive = false
private fun runOnUiThreadExecutor(): Executor {
val handler = Handler(Looper.getMainLooper())
return Executor() {
handler.post(it)
}
}
inner class TelephonyListener : TelephonyCallback(), TelephonyCallback.CallStateListener {
override fun onCallStateChanged(state: Int) {
gsmCallActive = when (state) {
TelephonyManager.CALL_STATE_OFFHOOK -> {
Log.i("[Context] Phone state is off hook")
true
}
TelephonyManager.CALL_STATE_RINGING -> {
Log.i("[Context] Phone state is ringing")
true
}
TelephonyManager.CALL_STATE_IDLE -> {
Log.i("[Context] Phone state is idle")
false
}
else -> {
Log.w("[Context] Phone state is unexpected: $state")
false
}
}
}
}
private val telephonyListener = TelephonyListener()
init {
Log.i("[Telephony Listener] Registering telephony callback")
telephonyManager.registerTelephonyCallback(runOnUiThreadExecutor(), telephonyListener)
}
override fun destroy() {
Log.i("[Telephony Listener] Unregistering telephony callback")
telephonyManager.unregisterTelephonyCallback(telephonyListener)
}
override fun isInCall(): Boolean {
return gsmCallActive
}
}

View file

@ -27,7 +27,6 @@ import android.os.Handler
import android.os.Looper import android.os.Looper
import android.security.keystore.KeyGenParameterSpec import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties import android.security.keystore.KeyProperties
import android.telephony.PhoneStateListener
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import android.util.Base64 import android.util.Base64
import android.util.Pair import android.util.Pair
@ -56,6 +55,7 @@ import org.linphone.activities.call.CallActivity
import org.linphone.activities.call.IncomingCallActivity import org.linphone.activities.call.IncomingCallActivity
import org.linphone.activities.call.OutgoingCallActivity import org.linphone.activities.call.OutgoingCallActivity
import org.linphone.compatibility.Compatibility import org.linphone.compatibility.Compatibility
import org.linphone.compatibility.PhoneStateInterface
import org.linphone.contact.Contact import org.linphone.contact.Contact
import org.linphone.contact.ContactsManager import org.linphone.contact.ContactsManager
import org.linphone.core.tools.Log import org.linphone.core.tools.Log
@ -99,37 +99,13 @@ class CoreContext(val context: Context, coreConfig: Config) {
} }
private val loggingService = Factory.instance().loggingService private val loggingService = Factory.instance().loggingService
private val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob()) private val coroutineScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
private var gsmCallActive = false
private val phoneStateListener = object : PhoneStateListener() {
override fun onCallStateChanged(state: Int, phoneNumber: String?) {
gsmCallActive = when (state) {
TelephonyManager.CALL_STATE_OFFHOOK -> {
Log.i("[Context] Phone state is off hook")
true
}
TelephonyManager.CALL_STATE_RINGING -> {
Log.i("[Context] Phone state is ringing")
true
}
TelephonyManager.CALL_STATE_IDLE -> {
Log.i("[Context] Phone state is idle")
false
}
else -> {
Log.w("[Context] Phone state is unexpected: $state")
false
}
}
}
}
private var overlayX = 0f private var overlayX = 0f
private var overlayY = 0f private var overlayY = 0f
private var callOverlay: View? = null private var callOverlay: View? = null
private var previousCallState = Call.State.Idle private var previousCallState = Call.State.Idle
private lateinit var phoneStateListener: PhoneStateInterface
private val listener: CoreListenerStub = object : CoreListenerStub() { private val listener: CoreListenerStub = object : CoreListenerStub() {
override fun onGlobalStateChanged(core: Core, state: GlobalState, message: String) { override fun onGlobalStateChanged(core: Core, state: GlobalState, message: String) {
@ -159,6 +135,11 @@ class CoreContext(val context: Context, coreConfig: Config) {
) { ) {
Log.i("[Context] Call state changed [$state]") Log.i("[Context] Call state changed [$state]")
if (state == Call.State.IncomingReceived || state == Call.State.IncomingEarlyMedia) { if (state == Call.State.IncomingReceived || state == Call.State.IncomingEarlyMedia) {
var gsmCallActive = false
if (::phoneStateListener.isInitialized) {
gsmCallActive = phoneStateListener.isInCall()
}
if (gsmCallActive) { if (gsmCallActive) {
Log.w("[Context] Refusing the call with reason busy because a GSM call is active") Log.w("[Context] Refusing the call with reason busy because a GSM call is active")
call.decline(Reason.Busy) call.decline(Reason.Busy)
@ -324,9 +305,13 @@ class CoreContext(val context: Context, coreConfig: Config) {
configureCore() configureCore()
val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager try {
Log.i("[Context] Registering phone state listener") phoneStateListener =
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE) Compatibility.createPhoneListener(context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager)
} catch (exception: SecurityException) {
val hasReadPhoneStatePermission = PermissionHelper.get().hasReadPhoneState()
Log.e("[Context] Failed to create phone state listener: $exception, READ_PHONE_STATE permission status is $hasReadPhoneStatePermission")
}
EmojiCompat.init(BundledEmojiCompatConfig(context)) EmojiCompat.init(BundledEmojiCompatConfig(context))
collator.strength = Collator.NO_DECOMPOSITION collator.strength = Collator.NO_DECOMPOSITION
@ -336,10 +321,9 @@ class CoreContext(val context: Context, coreConfig: Config) {
Log.i("[Context] Stopping") Log.i("[Context] Stopping")
coroutineScope.cancel() coroutineScope.cancel()
val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager if (::phoneStateListener.isInitialized) {
Log.i("[Context] Unregistering phone state listener") phoneStateListener.destroy()
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE) }
notificationsManager.destroy() notificationsManager.destroy()
contactsManager.destroy() contactsManager.destroy()