Um app de chamadas permite que os usuários recebam ou façam chamadas de áudio ou videochamadas no dispositivo. Os apps de chamadas usam a própria interface do usuário para as chamadas em vez de usar a interface padrão do app Telefone, conforme mostrado na captura de tela a seguir.
O framework do Android inclui o pacote android.telecom
, que
contém classes que ajudam a criar um app de chamadas de acordo com o framework
de telecomunicações. A criação do seu app de acordo com o framework de telecomunicações oferece os
seguintes benefícios:
- Interoperação correta do app com o subsistema de telecomunicações nativo no dispositivo.
- Interoperação correta do app com outros apps de chamadas que também aderem ao framework.
- O framework ajuda o app a gerenciar o roteamento de áudio e vídeo.
- O framework ajuda o app a determinar se as chamadas têm foco.
Declarações e permissões do manifesto
No manifesto do app, declare que ele usa o
MANAGE_OWN_CALLS
permissão, conforme mostrado no exemplo a seguir:
<manifest … >
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>
</manifest>
Para ver mais informações sobre como declarar permissões do app, consulte Permissões.
Você precisa declarar um serviço que especifica a classe que implementa a
classe ConnectionService
no seu app. O subsistema
de telecomunicações requer que o serviço declare a permissão BIND_TELECOM_CONNECTION_SERVICE
para ser
capaz de se vincular a ele. O exemplo a seguir mostra como declarar o serviço no
manifesto do aplicativo:
<service android:name="com.example.MyConnectionService"
android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
<intent-filter>
<action android:name="android.telecom.ConnectionService" />
</intent-filter>
</service>
Para ver mais informações sobre a declaração de componentes de app, incluindo serviços, consulte Componentes do app.
Implementar o serviço de conexão
Seu app de chamadas precisa fornecer uma implementação da classe ConnectionService
à qual o subsistema de telecomunicações pode se vincular.
A implementação ConnectionService
precisa modificar
os seguintes métodos:
onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)
Para realizar uma nova chamada, o subsistema de telecomunicações chama esse método em resposta à chamada de
placeCall(Uri, Bundle)
pelo app. Seu app retorna uma nova instância da implementação da classeConnection
(para ver mais informações, consulte Implementar a conexão) para representar a nova chamada realizada. Você pode personalizar ainda mais a conexão de saída realizando as seguintes ações:- Seu app precisa chamar o método
setConnectionProperties(int)
com a constantePROPERTY_SELF_MANAGED
como o argumento para indicar que a conexão se originou de um app de chamadas. - Caso seu app seja compatível com chamadas em espera, chame o método
setConnectionCapabilities(int)
e defina o argumento como o valor da bitmask das constantesCAPABILITY_HOLD
eCAPABILITY_SUPPORT_HOLD
. - Para definir o nome do autor da chamada, use o método
setCallerDisplayName(String, int)
que transmite a constantePRESENTATION_ALLOWED
como o parâmetroint
para indicar que o nome do autor da chamada precisa ser mostrado. - Para garantir que a chamada realizada tenha o estado de vídeo apropriado, chame o método
setVideoState(int)
do objetoConnection
e envie o valor retornado pelo métodogetVideoState()
do objetoConnectionRequest
.
- Seu app precisa chamar o método
onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest)
O subsistema de telecomunicações chama esse método quando seu app chama o
placeCall(Uri, Bundle)
, e a chamada não pode ser realizada. Em resposta a essa situação, seu app precisa informar ao usuário (por exemplo, usando uma caixa de alerta ou um aviso) que não foi possível realizar a chamada. Talvez seu app não consiga fazer uma chamada se houver uma chamada de emergência em andamento ou se houver outra chamada em andamento em outro app que não puder ser colocada em espera antes da sua chamada poder ser realizada.onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)
O subsistema de telecomunicações chama esse método quando seu app chama o método
addNewIncomingCall(PhoneAccountHandle, Bundle)
para informar ao sistema sobre uma nova chamada recebida no seu app. Seu app retorna uma nova instância da implementaçãoConnection
(para ver mais informações, consulte Implementar a conexão) para representar a nova chamada recebida. Você pode personalizar ainda mais a conexão de entrada realizando as seguintes ações:- Seu app precisa chamar o método
setConnectionProperties(int)
com a constantePROPERTY_SELF_MANAGED
como o argumento para indicar que a conexão se originou de um app de chamadas. - Caso seu app seja compatível com chamadas em espera, chame o método
setConnectionCapabilities(int)
e defina o argumento como o valor da bitmask das constantesCAPABILITY_HOLD
eCAPABILITY_SUPPORT_HOLD
. - Para definir o nome do autor da chamada, use o método
setCallerDisplayName(String, int)
que transmite a constantePRESENTATION_ALLOWED
como o parâmetroint
para indicar que o nome do autor da chamada precisa ser mostrado. - Para especificar o número de telefone ou o endereço da chamada recebida, use o método
setAddress(Uri, int)
do objetoConnection
. - Para garantir que a chamada realizada tenha o estado de vídeo apropriado, chame o método
setVideoState(int)
do objetoConnection
e envie o valor retornado pelo métodogetVideoState()
do objetoConnectionRequest
.
- Seu app precisa chamar o método
onCreateIncomingConnectionFailed(PhoneAccountHandle, ConnectionRequest)
O subsistema de telecomunicações chama esse método quando seu app chama o método
addNewIncomingCall(PhoneAccountHandle, Bundle)
para informar ao sistema de telecomunicações sobre uma nova chamada recebida, mas a chamada recebida não é permitida. Para ver mais informações, consulte Restrições de chamadas. Seu app precisa rejeitar silenciosamente a chamada recebida e, opcionalmente, postar uma notificação para informar ao usuário sobre a chamada perdida.
Implementar a conexão
Seu app precisa criar uma subclasse de Connection
para
representar as chamadas no seu app. É necessário modificar os seguintes métodos na
implementação:
onShowIncomingCallUi()
O subsistema de telecomunicações chama esse método quando uma chamada recebida é adicionada e seu app precisa mostrar a IU relacionada.
onCallAudioStateChanged(CallAudioState)
O subsistema de telecomunicações chama esse método para informar ao app que a rota ou modo de áudio atual mudou. Ele é chamado em resposta à mudança do modo áudio no seu app com o método
setAudioRoute(int)
. Esse método também poderá ser chamado se o sistema mudar a rota de áudio, por exemplo, quando um fone de ouvido Bluetooth for desconectado.onHold()
O subsistema de telecomunicações chama esse método para colocar uma chamada em espera. Em resposta a essa solicitação, seu app precisa reter a chamada e invocar o método
setOnHold()
para informar ao sistema que a chamada está sendo retida. O subsistema de telecomunicações pode chamar esse método quando um serviço em chamada, como o Android Auto, que está mostrando a chamada quer redirecionar uma solicitação de usuário para colocar a chamada em espera. O subsistema de telecomunicações também chamará esse método se o usuário fizer uma chamada em outro app. Para mais informações sobre os serviços de chamada recebida, consulteInCallService
.onUnhold()
O subsistema de telecomunicações chama esse método para retomar uma chamada que foi colocada em espera. Depois que seu app retomar a chamada, ele precisará invocar o método
setActive()
para informar ao sistema que a chamada não está mais em espera. O subsistema de telecomunicações pode chamar esse método quando um serviço de chamada que está mostrando a chamada, como o Android Auto, quer redirecionar uma solicitação para retomar a chamada. Para ver mais informações sobre os serviços de chamada, consulteInCallService
.onAnswer()
O subsistema de telecomunicações chama esse método para informar ao seu app que uma chamada recebida precisa ser atendida. Assim que seu app atender à chamada, ele precisará invocar o método
setActive()
para informar ao sistema que a chamada foi atendida. O subsistema de telecomunicações pode chamar esse método quando seu app adiciona uma nova chamada recebida e já há uma chamada em andamento em outro app que não pode ser colocada em espera. O subsistema de telecomunicações exibe a IU de chamada recebida em nome do seu app nessas situações. O framework fornece um método sobrecarregado que permite especificar o estado do vídeo em que a chamada será atendida. Para ver mais informações, consulteonAnswer(int)
.onReject()
O subsistema de telecomunicações chama esse método para rejeitar uma chamada recebida. Depois que seu app rejeitar a chamada, ele precisará chamar
setDisconnected(DisconnectCause)
e especificarREJECTED
como o parâmetro. Seu app precisa chamar o métododestroy()
para informar ao sistema que ele processou a chamada. O subsistema de telecomunicações chama esse método quando o usuário rejeita uma chamada recebida no seu app.onDisconnect()
O subsistema de telecomunicações chama esse método para desconectar uma chamada. Quando a chamada for encerrada, seu app precisará chamar o método
setDisconnected(DisconnectCause)
e especificarLOCAL
como o parâmetro para indicar que uma solicitação do usuário fez com que a chamada fosse desconectada. Seu app precisa chamar o métododestroy()
para informar ao subsistema de telecomunicações que o app processou a chamada. O sistema poderá chamar esse método quando o usuário desconectar uma chamada por meio de outro serviço, como o Android Auto. O sistema também chama esse método quando sua chamada precisa ser desconectada para permitir que outra seja feita, por exemplo, se o usuário quiser fazer uma chamada de emergência. Para ver mais informações sobre os serviços de chamada, consulteInCallService
.
Lidar com situações comuns de chamada
O uso da API ConnectionService
no seu fluxo
de chamadas envolve a interação com as outras classes no pacote
android.telecom
. As seções a seguir descrevem situações comuns de chamada e como seu
app precisa usar as APIs para lidar com elas.
Atender as chamadas recebidas
O fluxo para lidar com as chamadas recebidas muda de acordo com a presença de chamadas em outros apps . A razão para a diferença nos fluxos é que o framework de telecomunicações precisa estabelecer algumas restrições quando há chamadas ativas em outros apps para garantir um ambiente estável para todos os apps de chamada no dispositivo. Para ver mais informações, consulte Restrições de chamada.
Nenhuma chamada ativa em outros apps
Para atender chamadas recebidas quando não houver chamadas ativas em outros apps, siga estas etapas:
- Seu app recebe uma nova chamada usando os mecanismos habituais.
- Use o método
addNewIncomingCall(PhoneAccountHandle, Bundle)
para informar ao subsistema de telecomunicações sobre a nova chamada recebida. - O subsistema de telecomunicações será vinculado à implementação de
ConnectionService
no app e solicitará uma nova instância da classeConnection
que representa a nova chamada recebida usando o métodoonCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)
. - O subsistema de telecomunicações informa ao seu app que ele precisa mostrar a interface do usuário
de chamada recebida usando o método
onShowIncomingCallUi()
. - Seu app mostra a IU de entrada usando uma notificação com uma
intent de tela cheia associada. Para mais informações, consulte
onShowIncomingCallUi()
. - Chame o método
setActive()
se o usuário aceitar a chamada recebida. Se o usuário rejeitar a chamada, chamesetDisconnected(DisconnectCause)
especificandoREJECTED
como o parâmetro seguido por uma chamada para o métododestroy()
.
Chamadas ativas em outros apps que não podem ser colocadas em espera
Para atender a chamadas recebidas quando houver chamadas ativas em outros apps que não possam ser colocadas em espera, siga estas etapas:
- Seu app recebe uma nova chamada usando os mecanismos habituais.
- Use o método
addNewIncomingCall(PhoneAccountHandle, Bundle)
para informar ao subsistema de telecomunicações sobre a nova chamada recebida. - O subsistema de telecomunicações será vinculado à implementação de
ConnectionService
do seu app e solicitará uma nova instância do objetoConnection
que representa a nova chamada recebida usando o métodoonCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)
. - O subsistema de telecomunicações exibe a IU de chamada recebida para sua chamada.
- Se o usuário aceitar a chamada, o subsistema de telecomunicações chamará o método
onAnswer()
. Você precisa chamar o métodosetActive()
para indicar ao subsistema de telecomunicações que a chamada está conectada. - Se o usuário rejeitar a chamada, o subsistema de telecomunicações chamará o método
onReject()
. Você precisa chamar o métodosetDisconnected(DisconnectCause)
especificandoREJECTED
como o parâmetro seguido por uma chamada para o métododestroy()
.
Realizar chamadas
O fluxo para realizar uma chamada envolve lidar com a impossibilidade de fazer a chamada devido a restrições impostas pelo framework de telecomunicações. Para mais informações, consulte Restrições de chamada.
Para realizar uma chamada, siga estas etapas:
- O usuário inicia uma chamada realizada dentro do seu app.
- Use o método
placeCall(Uri, Bundle)
para informar ao subsistema de telecomunicações sobre a nova chamada realizada. Faça as seguintes considerações para os parâmetros do método:- O parâmetro
Uri
representa o endereço de destino da chamada. Para números de telefone normais, use o esquema de URItel:
. - O parâmetro
Bundle
permite que você forneça informações sobre seu app de chamadas adicionando o objetoPhoneAccountHandle
do seu app aoEXTRA_PHONE_ACCOUNT_HANDLE
extra. Seu app precisa fornecer o objetoPhoneAccountHandle
a todas as chamadas realizadas. - O
Bundle
também permite que você especifique se a chamada realizada inclui vídeo, especificando o valorSTATE_BIDIRECTIONAL
noEXTRA_START_CALL_WITH_VIDEO_STATE
extra. Considere que, por padrão, o subsistema de telecomunicações direciona as videochamadas para o viva-voz.
- O parâmetro
- O subsistema de telecomunicações é vinculado à implementação de
ConnectionService
do seu app. - Se o app não conseguir realizar uma chamada, o subsistema de telecomunicações chamará
o método
onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest)
para informar ao app que a chamada não pode ser feita naquele momento. Seu app precisa informar ao usuário que a chamada não pode ser feita. - Se o app conseguir realizar a chamada, o subsistema de telecomunicações chamará
o método
onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)
. Seu app precisa retornar uma instância da classeConnection
para representar a nova chamada realizada. Para ver mais informações sobre as propriedades que precisam ser definidas na conexão, consulte Implementar o serviço de conexão. - Quando a chamada realizada for conectada, chame o método
setActive()
para informar ao subsistema de telecomunicações que a chamada está ativa.
Finalizar uma chamada
Para finalizar uma chamada, siga estas etapas:
- Chame
setDisconnected(DisconnectCause)
enviandoLOCAL
como o parâmetro se o usuário tiver finalizado a chamada ou envieREMOTE
como o parâmetro se a outra parte tiver finalizado a chamada. - Chame o método
destroy()
.
Restrições de chamada
Para garantir uma experiência de chamada consistente e simples para os usuários, o framework
de telecomunicações impõe algumas restrições para o gerenciamento de chamadas no dispositivo. Por
exemplo, considere que o usuário instalou dois apps de chamada que implementam
a API ConnectionService
autogerenciada, o FooTalk e
o BarTalk. Nesse caso, as seguintes restrições se aplicam:
Em dispositivos no nível da API 27 ou anterior, somente um app pode manter uma chamada em andamento a qualquer momento. Essa restrição significa que, enquanto um usuário tem uma chamada em andamento usando o app FooTalk, o app BarTalk não pode iniciar ou receber uma nova chamada.
Em dispositivos nível da API 28 ou mais recente, se tanto o FooTalk quanto o BarTalk declararem as permissões
CAPABILITY_SUPPORT_HOLD
eCAPABILITY_HOLD
, o usuário poderá manter mais de uma chamada em andamento alternando entre os apps para iniciar ou atender outra chamada.Se o usuário estiver em chamadas gerenciadas normais, por exemplo, usando o app Telefone integrado, ele não poderá estar em chamadas originadas de apps de chamada. Isso significa que, se o usuário estiver em uma chamada normal usando a operadora de celular, ele não poderá estar em uma chamada do FooTalk ou BarTalk simultaneamente.
O subsistema de telecomunicações desconectará as chamadas do seu app se o usuário fizer uma chamada de emergência.
Seu app não pode receber ou fazer chamadas enquanto o usuário estiver em uma chamada de emergência.
Se houver uma chamada em andamento no outro app de chamadas quando seu app receber uma chamada, atender a chamada recebida finalizará todas as chamadas em andamento no outro app. Seu app não pode exibir a interface do usuário de chamada recebida. O framework de telecomunicações exibe a interface do usuário da chamada recebida e informa que atender à nova chamada finalizará as chamadas em andamento. Isso significa que se o usuário estiver em uma chamada do FooTalk e o app BarTalk receber uma chamada, o framework de telecomunicações informará que ele tem uma nova chamada recebida do BarTalk e que atender à chamada do BarTalk finalizará a chamada do FooTalk.