mirror of
https://gitlab.linphone.org/BC/public/linphone-android.git
synced 2026-01-17 11:28:06 +00:00
Prototype to try InCallService APIs
This commit is contained in:
parent
fac6e42c22
commit
feda5bb5f7
3 changed files with 164 additions and 0 deletions
|
|
@ -121,6 +121,11 @@
|
|||
<data android:scheme="linphone-config" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.DIAL" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
|
|
@ -208,6 +213,16 @@
|
|||
</intent-filter>
|
||||
</service>-->
|
||||
|
||||
<service android:name=".telecom.TelecomInCallService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.BIND_INCALL_SERVICE">
|
||||
<meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
|
||||
<meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING" android:value="true" />
|
||||
<intent-filter>
|
||||
<action android:name="android.telecom.InCallService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- Receivers -->
|
||||
|
||||
<receiver android:name=".core.CorePushReceiver"
|
||||
|
|
|
|||
115
app/src/main/java/org/linphone/telecom/TelecomInCallService.kt
Normal file
115
app/src/main/java/org/linphone/telecom/TelecomInCallService.kt
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2025 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.telecom
|
||||
|
||||
import android.os.Build
|
||||
import android.telecom.Call
|
||||
import android.telecom.InCallService
|
||||
import android.telecom.VideoProfile
|
||||
import androidx.annotation.RequiresApi
|
||||
import org.linphone.LinphoneApplication.Companion.coreContext
|
||||
import org.linphone.core.tools.Log
|
||||
|
||||
class TelecomInCallService : InCallService() {
|
||||
companion object {
|
||||
private const val TAG = "[Telecom InCall Service]"
|
||||
}
|
||||
|
||||
private val callsList = arrayListOf<Call>()
|
||||
|
||||
private val callListener = object : Call.Callback() {
|
||||
override fun onStateChanged(call: Call, state: Int) {
|
||||
Log.i("$TAG Call state changed [${callStateToString(state)}]")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBringToForeground(showDialpad: Boolean) {
|
||||
Log.i("$TAG onBringToForeground, showDialpad: $showDialpad")
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.Q)
|
||||
override fun onCallAdded(call: Call) {
|
||||
super.onCallAdded(call)
|
||||
|
||||
val uri = call.details.handle
|
||||
val isIncoming = call.details.callDirection == Call.Details.DIRECTION_INCOMING
|
||||
val state = call.details.state
|
||||
Log.i("$TAG Added call direction is [${if (isIncoming) "incoming" else "outgoing"}], URI is [$uri], state [${callStateToString(state)}], call [$call]")
|
||||
|
||||
call.registerCallback(callListener)
|
||||
callsList.add(call)
|
||||
|
||||
if (uri.scheme == "tel") {
|
||||
val number = uri.schemeSpecificPart
|
||||
Log.i("$TAG Extract number [$number] from tel: URI")
|
||||
if (!isIncoming) {
|
||||
coreContext.postOnCoreThread { core ->
|
||||
val address = core.interpretUrl(number, true)
|
||||
if (address != null) {
|
||||
Log.i("$TAG Calling SIP URI [${address.asStringUriOnly()}]")
|
||||
if (call.details.videoState == VideoProfile.STATE_AUDIO_ONLY) {
|
||||
coreContext.startAudioCall(address)
|
||||
} else {
|
||||
coreContext.startVideoCall(address)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCallRemoved(call: Call) {
|
||||
super.onCallRemoved(call)
|
||||
|
||||
Log.i("$TAG onCallRemoved with call [$call]")
|
||||
call.unregisterCallback(callListener)
|
||||
callsList.remove(call)
|
||||
}
|
||||
|
||||
override fun onCanAddCallChanged(canAddCall: Boolean) {
|
||||
Log.i("$TAG onCanAddCallChanged: $canAddCall")
|
||||
}
|
||||
|
||||
override fun onMuteStateChanged(isMuted: Boolean) {
|
||||
Log.i("$TAG onMuteStateChanged: $isMuted")
|
||||
}
|
||||
|
||||
override fun onSilenceRinger() {
|
||||
Log.i("$TAG onSilenceRinger")
|
||||
}
|
||||
|
||||
private fun callStateToString(state: Int): String {
|
||||
return when (state) {
|
||||
Call.STATE_NEW -> "NEW"
|
||||
Call.STATE_DIALING -> "DIALING"
|
||||
Call.STATE_RINGING -> "RINGING"
|
||||
Call.STATE_HOLDING -> "HOLDING"
|
||||
Call.STATE_ACTIVE -> "ACTIVE"
|
||||
Call.STATE_DISCONNECTED -> "DISCONNECTED"
|
||||
Call.STATE_SELECT_PHONE_ACCOUNT -> "SELECT_PHONE_ACCOUNT"
|
||||
Call.STATE_CONNECTING -> "CONNECTING"
|
||||
Call.STATE_DISCONNECTING -> "DISCONNECTING"
|
||||
Call.STATE_PULLING_CALL -> "PULLING_CALL"
|
||||
Call.STATE_AUDIO_PROCESSING -> "AUDIO_PROCESSING"
|
||||
Call.STATE_SIMULATED_RINGING -> "SIMULATED_RINGING"
|
||||
else -> "UNKNOWN [$state]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,7 +21,10 @@ package org.linphone.ui.main
|
|||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.ComponentCaller
|
||||
import android.app.Dialog
|
||||
import android.app.role.RoleManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Color
|
||||
|
|
@ -89,6 +92,8 @@ class MainActivity : GenericActivity() {
|
|||
private const val CHAT_FRAGMENT_ID = 3
|
||||
private const val MEETINGS_FRAGMENT_ID = 4
|
||||
|
||||
private const val DIALER_ROLE_REQUEST_CODE = 1
|
||||
|
||||
const val ARGUMENTS_CHAT = "Chat"
|
||||
const val ARGUMENTS_CONVERSATION_ID = "ConversationId"
|
||||
}
|
||||
|
|
@ -391,6 +396,8 @@ class MainActivity : GenericActivity() {
|
|||
Log.d("$TAG savedInstanceState is null but intent isn't, handling it")
|
||||
handleIntent(intent)
|
||||
}
|
||||
|
||||
requestDialerRole()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
|
|
@ -438,6 +445,21 @@ class MainActivity : GenericActivity() {
|
|||
handleIntent(intent)
|
||||
}
|
||||
|
||||
override fun onActivityResult(
|
||||
requestCode: Int,
|
||||
resultCode: Int,
|
||||
data: Intent?,
|
||||
caller: ComponentCaller
|
||||
) {
|
||||
if (requestCode == DIALER_ROLE_REQUEST_CODE) {
|
||||
if (resultCode == RESULT_OK) {
|
||||
Log.i("$TAG Dialer role was granted!")
|
||||
} else {
|
||||
Log.w("$TAG Dialer role was denied!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("RtlHardcoded")
|
||||
fun toggleDrawerMenu() {
|
||||
if (binding.drawerMenu.isDrawerOpen(Gravity.LEFT)) {
|
||||
|
|
@ -849,4 +871,16 @@ class MainActivity : GenericActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestDialerRole() {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
|
||||
val roleManager: RoleManager = getSystemService(Context.ROLE_SERVICE) as RoleManager
|
||||
val shouldRequestRole = roleManager.isRoleAvailable(RoleManager.ROLE_DIALER) &&
|
||||
!roleManager.isRoleHeld(RoleManager.ROLE_DIALER)
|
||||
if (shouldRequestRole) {
|
||||
val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER)
|
||||
startActivityForResult(intent, DIALER_ROLE_REQUEST_CODE)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue