La nueva biblioteca de Android Telecom Jetpack facilita indicarle a la plataforma qué el estado en el que se encuentra la llamada. Puedes encontrar el código fuente y una app de ejemplo en GitHub:
Dependencias y permisos
Primero, abre el archivo build.gradle del módulo de tu app y agrega una dependencia para el archivo Módulo de androidx Telecom:
dependencies {
implementation ("androidx.core:core-telecom:1.0.0-alpha02")
}
En el manifiesto de tu app, declara que tu app usa el elemento MANAGE_OWN_CALLS
.
permiso:
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
Registra la aplicación
Para permitir que Android conozca tu app, debes registrarla y sus funciones. Esta función indica a Android qué funciones admite tu app, como videollamadas, llamadas transmitir y mantener llamadas. Esta información es importante para que Android pueda configurar para trabajar con las funciones de tu app.
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)
Integración en la plataforma
Las dos situaciones de llamada más comunes para cualquier aplicación de llamadas son las llamadas entrantes y llamadas salientes. Para registrar correctamente la dirección de la llamada y para notificar adecuadamente al usuario con notificaciones, usa las siguientes APIs.
Registra una llamada
En este ejemplo, se muestra cómo registrar una llamada entrante:
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)
}
El objeto callAttributes
puede tener las siguientes propiedades:
displayName
: Es el nombre del emisor, la reunión o la sesión.address
: Es la dirección de la llamada. Ten en cuenta que esto se puede extender a una reunión enlace.direction
: Indica la dirección de la llamada, como entrante o saliente.callType
: Información relacionada con los datos que se transmiten, como el video y audio.callCapabilities
: Es un objeto que especifica las capacidades de la llamada.
El objeto callCapabilities
puede tener las siguientes propiedades:
streaming
: Indica si la llamada admite transmisión de audio a otra. Dispositivo con Android.transfer
: Indica si se puede transferir la llamada.hold
: Indica si la llamada se puede poner en espera.
Agregar una llamada
El método addCall()
devuelve una excepción si el dispositivo no es compatible.
telecomunicaciones, o bien si se produjo un error al establecer la llamada.
try {
callsManager.addCall(
INCOMING_CALL_ATTRIBUTES,
onIsCallAnswered, // Watch needs to know if it can answer the call
onIsCallDisconnected,
onIsCallActive,
onIsCallInactive
) {
callControlScope = this
}
}
Cómo responder una llamada
Una vez que hayas realizado una llamada entrante, debes responderla o rechazarla. Esta Examle muestra cómo responder una llamada:
when (answer(CallAttributesCompat.CALL_TYPE_AUDIO_CALL)) {
is CallControlResult.Success -> {
}
is CallControlResult.Error -> {
}
}
Si hay otra llamada en curso, se mostrará answer()
CallControlResult.Error
, que informa por qué no se pudo responder la llamada En
este caso, el usuario deberá poner la otra llamada en espera.
Cómo rechazar una llamada
Para rechazar una llamada, desconéctala con DisconnectCause.Rejected
.
fun onRejectCall(){
coroutineScope.launch {
callControlScope?.let {
it.disconnect(DisconnectCause(DisconnectCause.REJECTED))
}
}
}
Llamada saliente
Al realizar una llamada saliente, una vez que el usuario remoto responda, deberás configurar el llamada a active para que la plataforma sepa que la llamada está en curso:
when (setActive()) {
is CallControlResult.Success -> {
onIsCallActive()
}
is CallControlResult.Error -> {
updateCurrentCall {
copy(errorCode = result.errorCode)
}
}
}
Coloca una llamada en espera
Si tu app de llamadas admite poner en espera llamadas, usa setInActive
para indicarle a la
plataforma a la que la llamada no esté activa y que el micrófono y la cámara puedan
que otras apps usarán:
when (setInActive()) {
is CallControlResult.Success -> {
}
is CallControlResult.Error -> {
updateCurrentCall {
copy(errorCode = result.errorCode)
}
}
}
Desconectar
Para desconectar una llamada, indícale a la pila de telecomunicaciones que se desconecte proporcionando un causa válida:
coroutineScope.launch {
callControlScope?.disconnect(DisconnectCause(DisconnectCause.LOCAL))
}
Enruta el audio
Durante una llamada, los usuarios a veces cambian de dispositivo, como una bocina,
un auricular o dispositivo Bluetooth. Usa availableEndpoints
y
APIs de currentCallEndpoint
para obtener una lista de todos los dispositivos disponibles para la
usuario y qué dispositivo está activo.
En este ejemplo, se combinan ambos flujos para crear un objeto de IU y mostrarle al usuario un lista de dispositivos y cuál está activo:
availableEndpoint = combine(callControlScope.availableEndpoints,
callControlScope.currentCallEndpoint) {
availableDevices: List<CallEndpoint>, activeDevice : CallEndpoint ->
availableDevices.map {
EndPointUI(
isActive = activeDevice.endpointName == it.endpointName, it
)
}
}
Para cambiar un dispositivo activo, usa el requestEndpointChange
con el
CallEndpoint
al que quieres cambiar.
coroutineScope.launch {
callControlScope?.requestEndpointChange(callEndpoint)
}
Asistencia en primer plano
La biblioteca de Telecom es compatible con el primer plano. Esta biblioteca usa
ConnectionService
para dispositivos que ejecutan Android 13 y versiones anteriores. En el caso de Android 14 y
más arriba, usa el micrófono y la cámara foregroundtypes para
admiten servicios en primer plano. Obtén más información sobre los servicios en primer plano.
Como parte de los requisitos en primer plano, la aplicación debe publicar una notificación para que los usuarios sepan que la aplicación se está ejecutando en primer plano.
Para asegurarte de que tu app obtenga la prioridad de ejecución en primer plano, crea una una vez que registres la llamada en la plataforma. Prioridad en primer plano se quita cuando tu app finaliza la llamada o cuando ya no se recibe la notificación. válido.
is TelecomCall.Registered -> {
val notification = createNotification(call)
notificationManager.notify(TELECOM_NOTIFICATION_ID, notification)
}
Compatibilidad con plataformas
Los relojes tienen una aplicación receptora de extremos genérica. Esta aplicación proporciona al usuario con una interfaz básica, como responder, rechazar y desconectarse llamadas. La aplicación admite estas acciones implementando funciones lambda. que informan a la plataforma que realizaste la acción en el dispositivo.
Cada función lambda agota el tiempo de espera después de 5 segundos con una transacción errónea si tu la aplicación no responde.
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 = {}