新的 Android Telecom Jetpack 库可让您轻松告知平台 状态。您可以在 GitHub
依赖项和权限
首先,打开应用模块 build.gradle 文件,并为 androidx Telecom 模块:
dependencies {
implementation ("androidx.core:core-telecom:1.0.0-alpha02")
}
在应用清单中,声明您的应用使用 MANAGE_OWN_CALLS
权限:
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
注册应用
如需让 Android 知道您的应用,您必须注册该应用及其功能。 告知 Android 您的应用支持哪些功能,例如视频通话、通话、 流式传输和保持通话此信息很重要,因此 Android 可以 以便与应用的功能配合使用
private val callsManager = CallsManager(context)
var capabilities: @CallsManager.Companion.Capability Int =
CallsManager.CAPABILITY_BASELINE or
CallsManager.CAPABILITY_SUPPORTS_CALL_STREAMING or
CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING
callsManager.registerAppWithTelecom(capabilities)
平台集成
任何调用应用的两种最常见的通话场景是来电 和去电。要正确注册呼叫的方向和 使用下列 API 以适当的方式通知用户。
注册电话会议
以下示例演示了如何注册来电:
companion object {
const val APP_SCHEME = "MyCustomScheme"
const val ALL_CALL_CAPABILITIES = (CallAttributes.SUPPORTS_SET_INACTIVE
or CallAttributes.SUPPORTS_STREAM or CallAttributes.SUPPORTS_TRANSFER)
const val INCOMING_NAME = "Luke"
val INCOMING_URI: Uri = Uri.fromParts(APP_SCHEME, "", "")
// Define all possible properties for CallAttributes
val INCOMING_CALL_ATTRIBUTES =
CallAttributes(
INCOMING_NAME,
INCOMING_URI,
DIRECTION_INCOMING,
CALL_TYPE_VIDEO_CALL,
ALL_CALL_CAPABILITIES)
}
callAttributes
对象可以具有以下属性:
displayName
:来电者、会议或会话的名称。address
:调用的地址。请注意,此时间可扩展到会议 链接。direction
:通话的方向,例如来电或去电。callType
:与要传输的数据相关的信息,如视频 和音频。callCapabilities
:一个对象,用于指定调用的功能。
callCapabilities
对象可以具有以下属性:
streaming
:指示通话是否支持将音频流式传输到另一个通话 采用 Android 的手机。transfer
:指示是否可以转接来电。hold
:指示是否可以将通话置于保持状态。
添加通话
如果设备不支持,addCall()
方法会返回异常
还是在设置通话时出现错误。
try {
callsManager.addCall(
INCOMING_CALL_ATTRIBUTES,
onIsCallAnswered, // Watch needs to know if it can answer the call
onIsCallDisconnected,
onIsCallActive,
onIsCallInactive
) {
callControlScope = this
}
}
接听来电
拨出电话后,您必须接听或拒绝来电。这个 示例演示了如何接听来电:
when (answer(CallAttributesCompat.CALL_TYPE_AUDIO_CALL)) {
is CallControlResult.Success -> {
}
is CallControlResult.Error -> {
}
}
如果另一个调用正在进行中,answer()
将返回
CallControlResult.Error
,说明来电为何无人接听。在
在这种情况下,用户需要将另一个通话置于保持状态。
拒接来电
要拒接来电,请使用 DisconnectCause.Rejected
断开通话连接。
fun onRejectCall(){
coroutineScope.launch {
callControlScope?.let {
it.disconnect(DisconnectCause(DisconnectCause.REJECTED))
}
}
}
去电
拨出电话时,一旦远程方应答,您必须设置 调用 active,让平台知道调用正在进行中:
when (setActive()) {
is CallControlResult.Success -> {
onIsCallActive()
}
is CallControlResult.Error -> {
updateCurrentCall {
copy(errorCode = result.errorCode)
}
}
}
将通话置于保持状态
如果您的通话应用支持保持通话,请使用 setInActive
告知
您的通话处于非活动状态的平台,并且麦克风和摄像头可以自由
被其他应用使用:
when (setInActive()) {
is CallControlResult.Success -> {
}
is CallControlResult.Error -> {
updateCurrentCall {
copy(errorCode = result.errorCode)
}
}
}
断开连接
要断开通话连接,请通过提供 正当原因:
coroutineScope.launch {
callControlScope?.disconnect(DisconnectCause(DisconnectCause.LOCAL))
}
转接音频
在通话期间,用户有时会在设备(例如音箱)之间切换
手机听筒或蓝牙设备。使用 availableEndpoints
和
currentCallEndpoint
API,用于获取
以及哪台设备处于活动状态
此示例将两个流程相结合,以创建向用户显示 设备列表以及哪个处于活动状态:
availableEndpoint = combine(callControlScope.availableEndpoints,
callControlScope.currentCallEndpoint) {
availableDevices: List<CallEndpoint>, activeDevice : CallEndpoint ->
availableDevices.map {
EndPointUI(
isActive = activeDevice.endpointName == it.endpointName, it
)
}
}
如需更改活跃设备,请将 requestEndpointChange
与
“CallEndpoint
”。
coroutineScope.launch {
callControlScope?.requestEndpointChange(callEndpoint)
}
前台支持
Telecom 库支持前台。此库使用
ConnectionService
(适用于搭载 Android 13 及更低版本的设备)。对于 Android 14 及
则使用 foregroundtypes 麦克风和摄像头正确
支持前台服务详细了解前台服务。
根据前台要求,应用必须发布一条通知 以便用户知道应用正在前台运行。
为确保您的应用获得前台执行优先级,请创建一个 通知。前台优先级 在应用终止通话或通知不再有效时移除 有效。
is TelecomCall.Registered -> {
val notification = createNotification(call)
notificationManager.notify(TELECOM_NOTIFICATION_ID, notification)
}
Surface 支持
手表具有通用的端点接收器应用。此应用提供了 用户使用基本界面(例如接听、拒绝和断开连接) 调用。应用通过实现 lambda 函数来支持这些操作 用于告知平台您已对相应设备执行了相应操作。
如果您的 lambda 函数会在 5 秒后超时,并且事务会失败, 应用没有响应。
callsManager.addCall(
attributes,
onIsCallAnswered, // Watch/Auto need to know if they can answer the call
onIsCallDisconnected,
onIsCallActive,
onIsCallInactive
) {
//Call Scope
}
/**
* Can the call be successfully answered??
* TIP: Check the connection/call state to see if you can answer a call
* Example you may need to wait for another call to hold.
**/
val onIsCallAnswered: suspend(type: Int) -> Unit = {}
/**
* Can the call perform a disconnect
*/
val onIsCallDisconnected: suspend (cause: DisconnectCause) -> Unit = {}
/**
* Check is see if you can make the call active.
* Other calls and state might stop us from activating the call
*/
val onIsCallActive: suspend () -> Unit = {
updateCurrentCall {
}
}
/**
* Check to see if you can make the call inactivate
*/
val onIsCallInactive: suspend () -> Unit = {}