Core-Telecom

A biblioteca Core-Telecom simplifica o processo de integração do seu aplicativo de chamada com a plataforma Android, fornecendo um conjunto robusto e consistente de APIs.

Se você quiser conferir implementações práticas, confira os exemplos de aplicativos no GitHub:

Configurar o Core-Telecom

Adicione a dependência androidx.core:core-telecom ao arquivo build.gradle do app:

dependencies {
    implementation ("androidx.core:core-telecom:1.0.0")
}

Declare a permissão MANAGE_OWN_CALLS no AndroidManifest.xml:

<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />

Registrar seu aplicativo

Registre seu app de chamada no Android usando CallsManager para começar a adicionar chamadas ao sistema. Ao fazer o registro, especifique os recursos do app (por exemplo, suporte a áudio e vídeo):

val callsManager = CallsManager(context)

val capabilities: @CallsManager.Companion.Capability Int =
    (CallsManager.CAPABILITY_BASELINE or
          CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING)

callsManager.registerAppWithTelecom(capabilities)

Gerenciamento de chamadas

Use as APIs Core-Telecom para criar e gerenciar o ciclo de vida de uma chamada.

Criar uma ligação

O objeto CallAttributesCompat define as propriedades de uma chamada única, que pode ter as seguintes características:

  • displayName: nome do autor da chamada.
  • address: endereço de chamada (por exemplo, número de telefone, link da reunião).
  • direction: entrada ou saída.
  • callType: áudio ou vídeo.
  • callCapabilities: oferece suporte a transferência e retenção.

Confira um exemplo de como criar uma chamada recebida:

fun createIncomingCallAttributes(
    callerName: String,
    callerNumber: String,
    isVideoCall: Boolean): CallAttributesCompat {
    val addressUri = Uri.parse("YourAppScheme:$callerNumber")

    // Define capabilities supported by your call.
    val callCapabilities = CallAttributesCompat.CallCapability(
        supportsSetInactive = CallAttributesCompat.SUPPORTS_SET_INACTIVE // Call can be made inactive (implies hold)
    )

    return CallAttributesCompat(
        displayName = callerName,
        address = addressUri,
        direction = CallAttributesCompat.DIRECTION_INCOMING,
        callType = if (isVideoCall) CallAttributesCompat.CALL_TYPE_VIDEO_CALL else CallAttributesCompat.CALL_TYPE_AUDIO_CALL,
        callCapabilitiesCompat = callCapabilities
    )
}

Adicionar uma ligação

Use callsManager.addCall com CallAttributesCompat e callbacks para adicionar uma nova chamada ao sistema e gerenciar atualizações de superfície remotas. O callControlScope no bloco addCall permite principalmente que o app faça a transição do estado da chamada e receba atualizações de áudio:

try {
    callsManager.addCall(
        INCOMING_CALL_ATTRIBUTES,
        onAnswerCall, // Watch needs to know if it can answer the call.
        onSetCallDisconnected,
        onSetCallActive,
        onSetCallInactive
    ) {
        // The call was successfully added once this scope runs.
        callControlScope = this
    }
}
catch(addCallException: Exception){
   // Handle the addCall failure.
}

Atender uma chamada

Atender uma ligação recebida no CallControlScope:

when (val result = answer(CallAttributesCompat.CALL_TYPE_AUDIO_CALL)) {
    is CallControlResult.Success -> { /* Call answered */ }
    is CallControlResult.Error -> { /* Handle error */ }
}

Rejeitar uma ligação

Rejeite uma chamada usando disconnect() com DisconnectCause.REJECTED no CallControlScope:

disconnect(DisconnectCause(DisconnectCause.REJECTED))

Ativar uma chamada de saída

Defina uma chamada de saída como ativa quando a parte remota atender:

when (val result = setActive()) {
    is CallControlResult.Success -> { /* Call active */ }
    is CallControlResult.Error -> { /* Handle error */ }
}

Colocar uma chamada em espera

Use setInactive() para colocar uma chamada em espera:

when (val result = setInactive()) {
    is CallControlResult.Success -> { /* Call on hold */ }
    is CallControlResult.Error -> { /* Handle error */ }
}

Desconectar uma chamada

Desconecte uma chamada usando disconnect() com um DisconnectCause:

disconnect(DisconnectCause(DisconnectCause.LOCAL))

Gerenciar endpoints de áudio de chamada

Observar e gerenciar endpoints de áudio usando currentCallEndpoint, availableEndpoints e isMuted Flows no CallControlScope

fun observeAudioStateChanges(callControlScope: CallControlScope) {
    with(callControlScope) {
        launch { currentCallEndpoint.collect { /* Update UI */ } }
        launch { availableEndpoints.collect { /* Update UI */ } }
        launch { isMuted.collect { /* Handle mute state */ } }
    }
}

Mude o dispositivo de áudio ativo usando requestEndpointChange():

coroutineScope.launch {
     callControlScope.requestEndpointChange(callEndpoint)
}

Suporte em primeiro plano

A biblioteca usa ConnectionService (Android 13 API de nível 33 e versões anteriores) ou foregroundtypes (Android 14 API de nível 34 e mais recentes) para oferecer suporte ao primeiro plano.

Como parte dos requisitos em primeiro plano, o aplicativo precisa postar uma notificação para que os usuários saibam que ele está em execução em primeiro plano.

Para garantir que o app tenha prioridade de execução em primeiro plano, crie uma notificação depois de adicionar a chamada com a plataforma. A prioridade em primeiro plano é removida quando o app encerra a chamada ou a notificação deixa de ser válida.

Saiba mais sobre os serviços em primeiro plano.

Suporte remoto ao Surface

Dispositivos remotos (smartwatches, fones de ouvido Bluetooth, Android Auto) podem gerenciar chamadas sem interação direta com o smartphone. O app precisa implementar lambdas de callback (onAnswerCall, onSetCallDisconnected, onSetCallActive, onSetCallInactive) fornecidos para CallsManager.addCall para processar ações iniciadas por esses dispositivos.

Quando uma ação remota ocorre, a lambda correspondente é invocada.

A conclusão bem-sucedida da lambda indica que o comando foi processado. Se o comando não puder ser obedecido, o lambda vai gerar uma exceção.

A implementação adequada garante o controle de chamadas perfeito em diferentes dispositivos. Teste completamente com várias superfícies remotas.