Criar um aplicativo de telefone padrão

Um aplicativo de telefone padrão permite que a estrutura de telecomunicações do Android informe seu aplicativo sobre o estado da chamada usando o gerenciador de funções e o serviço de chamada para criar um substituto para o aplicativo de telefone padrão em um dispositivo Android e implementar a API InCallService. A implementação precisa atender aos seguintes requisitos:

Ele não pode ter recursos de chamada e precisa consistir apenas na interface do usuário para chamadas. Ele precisa lidar com todas as chamadas de que o framework de telecomunicações está ciente e não fazer suposições sobre a natureza delas. Por exemplo, ele não pode presumir que as chamadas são chamadas de telefonia com base no chip nem implementar restrições de chamada baseadas em qualquer ConnectionService, como a aplicação de restrições de telefonia para videochamadas.

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.

Exemplo de um app de chamadas
Exemplo de um app de chamadas usando a própria interface do usuário

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 a permissão MANAGE_OWN_CALLS, 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 classe Connection (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:

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ção Connection (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:

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, consulte InCallService.

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, consulte InCallService.

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, consulte onAnswer(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 especificar REJECTED como o parâmetro. Seu app precisa chamar o método destroy() 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. Depois que a chamada for encerrada, seu app precisará chamar o método setDisconnected(DisconnectCause) e especificar LOCAL 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étodo destroy() 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, consulte InCallService.

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:

  1. Seu app recebe uma nova chamada usando os mecanismos habituais.
  2. Use o método addNewIncomingCall(PhoneAccountHandle, Bundle) para informar ao subsistema de telecomunicações sobre a nova chamada recebida.
  3. O subsistema de telecomunicações será vinculado à implementação de ConnectionService no app e solicitará uma nova instância da classe Connection que representa a nova chamada recebida usando o método onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest).
  4. 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().
  5. Seu app mostra a IU de entrada usando uma notificação com uma intent de tela cheia associada. Para mais informações, consulte onShowIncomingCallUi().
  6. Chame o método setActive() se o usuário aceitar a chamada recebida. Se o usuário rejeitar a chamada, chame setDisconnected(DisconnectCause) especificando REJECTED como o parâmetro seguido por uma chamada para o método destroy().

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:

  1. Seu app recebe uma nova chamada usando os mecanismos habituais.
  2. Use o método addNewIncomingCall(PhoneAccountHandle, Bundle) para informar ao subsistema de telecomunicações sobre a nova chamada recebida.
  3. O subsistema de telecomunicações será vinculado à implementação de ConnectionService do seu app e solicitará uma nova instância do objeto Connection que representa a nova chamada recebida usando o método onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest).
  4. O subsistema de telecomunicações exibe a IU de chamada recebida para sua chamada.
  5. Se o usuário aceitar a chamada, o subsistema de telecomunicações chamará o método onAnswer(). Você precisa chamar o método setActive() para indicar ao subsistema de telecomunicações que a chamada está conectada.
  6. Se o usuário rejeitar a chamada, o subsistema de telecomunicações chamará o método onReject(). Você precisa chamar o método setDisconnected(DisconnectCause) especificando REJECTED como o parâmetro seguido por uma chamada para o método destroy().

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:

  1. O usuário inicia uma chamada realizada dentro do seu app.
  2. 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 URI tel:.
    • O parâmetro Bundle permite que você forneça informações sobre seu app de chamadas adicionando o objeto PhoneAccountHandle do seu app ao EXTRA_PHONE_ACCOUNT_HANDLE extra. Seu app precisa fornecer o objeto PhoneAccountHandle a todas as chamadas realizadas.
    • O Bundle também permite que você especifique se a chamada realizada inclui vídeo, especificando o valor STATE_BIDIRECTIONAL no EXTRA_START_CALL_WITH_VIDEO_STATE extra. Considere que, por padrão, o subsistema de telecomunicações direciona as videochamadas para o viva-voz.
  3. O subsistema de telecomunicações é vinculado à implementação de ConnectionService do seu app.
  4. 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.
  5. 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 classe Connection 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.
  6. 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:

  1. Chame setDisconnected(DisconnectCause) enviando LOCAL como o parâmetro se o usuário tiver finalizado a chamada ou envie REMOTE como o parâmetro se a outra parte tiver finalizado a chamada.
  2. 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 e CAPABILITY_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.

Tornar-se o aplicativo de telefone padrão

O app de telefone/telefone padrão é aquele que fornece a interface do usuário na chamada enquanto o dispositivo está em uma chamada. Ele também oferece ao usuário uma maneira de iniciar chamadas e ver um histórico de chamadas no dispositivo. Um dispositivo está incluído em um app de telefone/discador padrão fornecido pelo sistema. O usuário pode escolher um único app para assumir essa função no app do sistema. Um app que queira cumprir essa função usa o RoleManager para solicitar que preencha a função RoleManager.ROLE_DIALER.

O app de telefone padrão fornece uma interface do usuário enquanto o dispositivo está em uma chamada e o dispositivo não está no modo carro (ou seja, UiModeManager#getCurrentModeType() não é Configuration.UI_MODE_TYPE_CAR).

Para preencher o papel RoleManager.ROLE_DIALER, o app precisa atender a vários requisitos:

  • Ele precisa processar a intent Intent#ACTION_DIAL. Isso significa que o app precisa fornecer uma interface de teclado de discagem para que o usuário inicie chamadas.
  • Ele precisa implementar totalmente a API InCallService e fornecer uma IU de chamada recebida e uma de chamada em andamento.

Observação: se o app que preenche RoleManager.ROLE_DIALER retornar um null InCallService durante a vinculação, o framework de telecomunicações voltará automaticamente a usar o app discador pré-carregado no dispositivo. O sistema exibirá uma notificação ao usuário para informar que a chamada continuou usando o app discador pré-carregado. Seu app nunca pode retornar uma vinculação null, o que significa que ele não atende aos requisitos de RoleManager.ROLE_DIALER.

Observação: se o app preencher RoleManager.ROLE_DIALER e fizer mudanças no momento da execução que façam com que não atenda mais aos requisitos desse papel, o RoleManager vai remover seu app do papel e fechar o app automaticamente. Por exemplo, se você usar PackageManager.setComponentEnabledSetting(ComponentName, int, int) para desativar programaticamente a InCallService declarada no manifesto, o app não vai mais atender aos requisitos esperados de RoleManager.ROLE_DIALER.

O discador pré-carregado SEMPRE será usado quando o usuário fizer uma chamada de emergência, mesmo que o app preencha a função RoleManager.ROLE_DIALER. Para garantir uma experiência ideal ao fazer uma chamada de emergência, o discador padrão precisa usar SEMPRE usar TelecomManager.placeCall(Uri, Bundle) para fazer chamadas (incluindo chamadas de emergência). Isso garante que a plataforma possa verificar se a solicitação veio do discador padrão. Se um app de discador não pré-carregado usar Intent#ACTION_CALL para fazer uma chamada de emergência, ele será encaminhado para o app de discador pré-carregado usando Intent#ACTION_DIAL para confirmação. Essa não é uma experiência do usuário ideal.

Veja abaixo um exemplo de registro de manifesto para um InCallService. O TelecomManager#METADATA_IN_CALL_SERVICE_UI de metadados indica que essa implementação de InCallService específica pretende substituir a IU integrada na chamada. Os metadados TelecomManager#METADATA_IN_CALL_SERVICE_RINGING indicam que este InCallService vai tocar o toque de chamadas recebidas. Consulte abaixo para mais informações sobre como exibir a interface de chamada recebida e reproduzir o toque no seu app.

 <service android:name="your.package.YourInCallServiceImplementation"
          android:permission="android.permission.BIND_INCALL_SERVICE"
          android:exported="true">
      <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>

Observação: NÃO marque InCallService com o atributo android:exported="false". Isso pode resultar em uma falha de vinculação à implementação durante as chamadas.

Além de implementar a API InCallService, também é necessário declarar uma atividade no manifesto que processe a intent Intent#ACTION_DIAL. O exemplo abaixo ilustra como isso é feito:

 <activity android:name="your.package.YourDialerActivity"
           android:label="@string/yourDialerActivityLabel">
      <intent-filter>
           <action android:name="android.intent.action.DIAL" />
           <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
      <intent-filter>
           <action android:name="android.intent.action.DIAL" />
           <category android:name="android.intent.category.DEFAULT" />
           <data android:scheme="tel" />
      </intent-filter>
 </activity>

Quando um usuário instala seu aplicativo e o executa pela primeira vez, você precisa usar o RoleManager para solicitar que o usuário veja se quer que seu app seja o novo app para smartphones padrão.

O código abaixo mostra como o app pode pedir para se tornar o app de telefone/discador padrão:

 private static final int REQUEST_ID = 1;

 public void requestRole() {
     RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
     Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER);
     startActivityForResult(intent, REQUEST_ID);
 }

 public void onActivityResult(int requestCode, int resultCode, Intent data) {
     if (requestCode == REQUEST_ID) {
         if (resultCode == android.app.Activity.RESULT_OK) {
             // Your app is now the default dialer app
         } else {
             // Your app is not the default dialer app
         }
     }
 }

Acesso ao InCallService para dispositivos wearable

    Se seu app for um app complementar de terceiros e quiser acessar as APIs InCallService, ele poderá fazer o seguinte:

    1. Declarar a permissão MANAGE_ONGOING_CALLS no manifesto
    2. Associar um dispositivo wearable físico usando a API CompanionDeviceManager como um app complementar. Consulte: https://developer.android.com/guide/topics/connectivity/companion-device-pairing
    3. Implementar este InCallService com a permissão BIND_INCALL_SERVICE

Como mostrar a notificação de chamada recebida

Quando seu app recebe uma nova chamada por InCallService#onCallAdded(Call), ele é responsável por exibir uma IU para ela. Ele precisa fazer isso usando APIs NotificationManager para postar uma nova notificação de chamada recebida.

Quando o app declara os metadados TelecomManager#METADATA_IN_CALL_SERVICE_RINGING, ele é responsável por reproduzir o toque para chamadas recebidas. Seu app precisa criar um NotificationChannel que especifique o toque desejado. Por exemplo:

 NotificationChannel channel = new NotificationChannel(YOUR_CHANNEL_ID, "Incoming Calls",
          NotificationManager.IMPORTANCE_MAX);
 // other channel setup stuff goes here.

 // We'll use the default system ringtone for our incoming call notification channel.  You can
 // use your own audio resource here.
 Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
 channel.setSound(ringtoneUri, new AudioAttributes.Builder()
          // Setting the AudioAttributes is important as it identifies the purpose of your
          // notification sound.
          .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
          .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
      .build());

 NotificationManager mgr = getSystemService(NotificationManager.class);
 mgr.createNotificationChannel(channel);

Quando seu app recebe uma nova chamada, ele cria um Notification para a chamada recebida e o associa ao seu canal de notificação de chamadas recebidas. Você pode especificar um PendingIntent na notificação, que iniciará a interface de chamada recebida em tela cheia. O framework do gerenciador de notificações exibirá sua notificação como uma notificação de alerta se o usuário estiver usando o smartphone ativamente. Quando o usuário não está usando o smartphone, a interface de chamada recebida em tela cheia é usada. Por exemplo:

 // Create an intent which triggers your fullscreen incoming call user interface.
 Intent intent = new Intent(Intent.ACTION_MAIN, null);
 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
 intent.setClass(context, YourIncomingCallActivity.class);
 PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 // Build the notification as an ongoing high priority item; this ensures it will show as
 // a heads up notification which slides down over top of the current content.
 final Notification.Builder builder = new Notification.Builder(context);
 builder.setOngoing(true);
 builder.setPriority(Notification.PRIORITY_HIGH);
 // Set notification content intent to take user to the fullscreen UI if user taps on the
 // notification body.
 builder.setContentIntent(pendingIntent);
 // Set full screen intent to trigger display of the fullscreen UI when the notification
 // manager deems it appropriate.
 builder.setFullScreenIntent(pendingIntent, true);
 // Setup notification content.
 builder.setSmallIcon( yourIconResourceId );
 builder.setContentTitle("Your notification title");
 builder.setContentText("Your notification content.");
 // Use builder.addAction(..) to add buttons to answer or reject the call.
 NotificationManager notificationManager = mContext.getSystemService(
     NotificationManager.class);
 notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build());
```