Cómo compilar una aplicación para teléfonos predeterminada

Una aplicación telefónica predeterminada permite que el marco de trabajo de telecomunicaciones de Android informe a tu aplicación el estado de la llamada usando el administrador de roles y el servicio en llamada para crear un reemplazo para la app de teléfono predeterminada en un dispositivo Android. Además, implementa la API de InCallService. Tu implementación debe cumplir con los siguientes requisitos:

No debe tener capacidad de llamadas y debe incluir solo la interfaz de usuario para realizar llamadas. Debe administrar todas las llamadas que el marco de trabajo de telecomunicaciones conoce y no hacer suposiciones sobre la naturaleza de las llamadas. Por ejemplo, no se debe suponer que las llamadas son llamadas telefónicas basadas en SIM ni implementar restricciones de llamadas basadas en un ConnectionService, como la aplicación de restricciones de telefonía para las videollamadas.

Una app de llamadas permite a los usuarios usar su dispositivo para recibir o realizar llamadas de audio o videollamadas. Estas apps usan su propia interfaz de usuario para las llamadas en lugar de usar la interfaz predeterminada de la app de teléfono, como se muestra en la siguiente captura de pantalla.

Ejemplo de una app de llamadas
Ejemplo de una app de llamadas que usa su propia interfaz de usuario

El framework de Android incluye el paquete android.telecom, que contiene clases que te ayudan a crear una app de llamadas según el framework de las telecomunicaciones. Si creas tu app de acuerdo con el framework de telecomunicaciones, obtendrás los siguientes beneficios:

  • Tu app interoperará correctamente con el subsistema nativo de telecomunicaciones del dispositivo.
  • Tu app interoperará correctamente con otras apps de llamadas que también cumplan con las disposiciones del framework.
  • El framework ayuda a tu app a administrar el enrutamiento de audio y video.
  • El framework ayuda a tu app a determinar si sus llamadas tienen foco.

Permisos y declaraciones de manifiesto

En el manifiesto de tu app, declara que tu app usa MANAGE_OWN_CALLS permiso, como se muestra en el siguiente ejemplo:

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

Puedes obtener más información para declarar permisos de apps en la sección Permisos.

Debes declarar un servicio que especifique la clase que implementa la clase ConnectionService en tu app. El subsistema de telecomunicaciones requiere que el servicio declare el permiso BIND_TELECOM_CONNECTION_SERVICE para poder vincularse a él. En el siguiente ejemplo, se muestra cómo declarar el servicio en el manifiesto de la app:

<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>

Puedes obtener más información para declarar los componentes de la app, incluidos los servicios, en la sección Componentes de la app.

Cómo implementar el servicio de conexión

Tu app de llamadas debe proporcionar una implementación de la clase ConnectionService a la que se pueda vincular el subsistema de telecomunicaciones. Tu implementación de ConnectionService debe anular los siguientes métodos:

onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)

El subsistema de telecomunicaciones llama a este método en respuesta a la llamada que hace tu app a placeCall(Uri, Bundle) para crear una nueva llamada saliente. Tu app muestra una instancia nueva de la implementación de la clase Connection (para obtener más información, consulta la sección Cómo implementar la conexión) para representar la nueva llamada saliente. Puedes personalizar aún más la conexión saliente si realizas las siguientes acciones:

onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest)

El subsistema de telecomunicaciones llama a este método cuando tu app llama al método placeCall(Uri, Bundle) y no se puede realizar la llamada saliente. En respuesta a esta situación, tu app debe informar al usuario (por ejemplo, mediante un cuadro de alerta o un aviso) que no se pudo realizar la llamada saliente. Es posible que tu app no pueda realizar llamadas si, antes de hacerlo, hay una llamada de emergencia o algún otro tipo de llamada en curso que no se puede poner en espera en otra app.

onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)

El subsistema de telecomunicaciones llama a este método cuando tu app llama al método addNewIncomingCall(PhoneAccountHandle, Bundle) para informar al sistema sobre una nueva llamada entrante en la app. Esta muestra una nueva instancia de tu implementación de Connection (para obtener más información, consulta la sección Cómo implementar la conexión) para representar la nueva llamada entrante. Puedes personalizar aún más la conexión entrante si realizas las siguientes acciones:

onCreateIncomingConnectionFailed(PhoneAccountHandle, ConnectionRequest)

El subsistema de telecomunicaciones llama a este método cuando tu app llama al método addNewIncomingCall(PhoneAccountHandle, Bundle) para informar al sistema de telecomunicaciones sobre una nueva llamada entrante, pero esta no está permitida (para obtener más información, consulta la sección Restricciones de llamadas). Tu app debe rechazar de manera silenciosa la llamada entrante y, opcionalmente, publicar una notificación para informar al usuario sobre la llamada perdida.

Cómo implementar la conexión

Tu app debe crear una subclase de Connection para representar las llamadas en ella. Debes anular los siguientes métodos en tu implementación:

onShowIncomingCallUi()

El subsistema de telecomunicaciones llama a este método cuando agregas una nueva llamada entrante tu app debería mostrar su IU de llamada entrante.

onCallAudioStateChanged(CallAudioState)

El subsistema de telecomunicaciones llama a este método para informar a tu app que la ruta o el modo de audio actual ha cambiado. Se lo llama en respuesta al cambio que hizo tu app en el modo audio con el método setAudioRoute(int). También se puede llamar a este método si el sistema cambia la ruta del audio (por ejemplo, cuando se desconectan los auriculares Bluetooth).

onHold()

El subsistema de telecomunicaciones llama a este método cuando quiere poner una llamada en espera. En respuesta a esta solicitud, tu app debe retener la llamada y, luego, invocar el método setOnHold() para informar al sistema que la llamada está en espera. El subsistema de telecomunicaciones puede llamar a este método cuando un servicio en llamada, como Android Auto, muestra que tu llamada desea retransmitir la solicitud de un usuario para poner la llamada en espera. El subsistema de telecomunicaciones también llama a este método si el usuario hace que una llamada esté activa en otra app. Para obtener más información sobre los servicios en llamada, consulta la información sobre InCallService.

onUnhold()

El subsistema de telecomunicaciones llama a este método cuando desea reanudar una llamada que se puso en espera. Una vez que tu app ha reanudado la llamada, debe invocar el método setActive() para informar al sistema que la llamada ya no está en espera. El subsistema de telecomunicaciones puede llamar a este método cuando un servicio en llamada, como Android Auto, muestra que tu llamada desea retransmitir una solicitud para reanudar la llamada. Para obtener más información sobre los servicios en llamada, consulta la información sobre InCallService.

onAnswer()

El subsistema de telecomunicaciones llama a este método para informarle a tu app que se debe contestar una llamada entrante. Una vez que la app respondió la llamada, debe invocar el método setActive() para informar al sistema que se contestó la llamada. El subsistema de telecomunicaciones puede llamar a este método cuando tu app agrega una nueva llamada entrante y ya hay una llamada saliente en curso en otra app que no se puede poner en espera. En estos casos, el subsistema de telecomunicaciones muestra la IU de la llamada entrante en nombre de tu app. El framework proporciona un método con sobrecarga que brinda compatibilidad para especificar el estado de video en el cual se contesta la llamada. Para obtener más información, consulta la información sobre onAnswer(int).

onReject()

El subsistema de telecomunicaciones llama a este método cuando quiere rechazar una llamada entrante. Una vez que la app ha rechazado la llamada, debe llamar a setDisconnected(DisconnectCause) y especificar REJECTED como el parámetro. Luego, tu app debe llamar al método destroy() para informar al sistema que la app procesó la llamada. El subsistema de telecomunicaciones llama a este método cuando el usuario rechaza una llamada entrante de tu app.

onDisconnect()

El subsistema de telecomunicaciones llama a este método cuando quiere desconectar una llamada. Una vez que la llamada ha finalizado, la app debe llamar al método setDisconnected(DisconnectCause) y especificar LOCAL como parámetro para indicar que se solicitud de usuario hizo que la llamada se desconectara. Entonces, tu app debe llamar al método destroy() para informar al subsistema de telecomunicaciones que la app procesó la llamada. El sistema puede llamar a este método después de que el usuario interrumpe una llamada a través de otro servicio en llamada, como Android Auto. El sistema también llama a este método cuando tu llamada debe interrumpirse para permitir que se realice otra llamada; por ejemplo, si el usuario desea realizar una llamada de emergencia. Para obtener más información sobre los servicios en llamada, consulta la información sobre InCallService.

Cómo controlar situaciones de llamadas comunes

Utilizar la API de ConnectionService en tu flujo de llamadas implica interactuar con las otras clases del paquete android.telecom. En las siguientes secciones, se describen situaciones de llamadas comunes y cómo tu app debe controlarlas usando las API.

Cómo contestar las llamadas entrantes

El flujo para controlar las llamadas entrantes cambia si hay llamadas en otras apps. El motivo de la diferencia en los flujos es que el framework de las telecomunicaciones debe establecer algunas restricciones cuando hay llamadas activas en otras apps a fin de garantizar un entorno estable para todas las apps de llamadas en el dispositivo. Para obtener más información, consulta la sección Restricciones de llamadas.

No hay llamadas activas en otras apps

Para contestar llamadas entrantes cuando no hay llamadas activas en otras apps, sigue estos pasos:

  1. Tu app recibe una nueva llamada entrante utilizando sus mecanismos habituales.
  2. Usa el método addNewIncomingCall(PhoneAccountHandle, Bundle) para informar al subsistema de telecomunicaciones sobre la nueva llamada entrante.
  3. El subsistema de telecomunicaciones se vincula a la implementación de ConnectionService de tu app y solicita una nueva instancia de la clase Connection, que representa la nueva llamada entrante a través del método onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest).
  4. El subsistema de telecomunicaciones informa a tu app que debe mostrar su interfaz de usuario de llamada entrante con el método onShowIncomingCallUi().
  5. Tu app muestra su IU de llamada entrante mediante una notificación con un intent asociado en pantalla completa. Para obtener más información, consulta la información sobre onShowIncomingCallUi().
  6. Llama al método setActive() si el usuario acepta la llamada entrante, o llama a setDisconnected(DisconnectCause) y especifica REJECTED como el parámetro seguido de una llamada al método destroy() si el usuario rechaza la llamada entrante.

Llamadas activas en otras apps que no se pueden poner en espera

Para contestar llamadas entrantes cuando hay llamadas activas en otras apps que no se pueden poner en espera, sigue estos pasos:

  1. Tu app recibe una nueva llamada entrante utilizando sus mecanismos habituales.
  2. Usa el método addNewIncomingCall(PhoneAccountHandle, Bundle) para informar al subsistema de telecomunicaciones sobre la nueva llamada entrante.
  3. El subsistema de telecomunicaciones se vincula a la implementación de ConnectionService de tu app y solicita una nueva instancia del objeto Connection, que representa la nueva llamada entrante a través del método onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest).
  4. El subsistema de telecomunicaciones muestra la IU correspondiente para tu llamada entrante.
  5. Si el usuario acepta la llamada, el subsistema de telecomunicaciones llama al método onAnswer(). Debes llamar al método setActive() para indicar al subsistema de telecomunicaciones que la llamada se estableció.
  6. Si el usuario rechaza la llamada, el subsistema de telecomunicaciones llama al método onReject(). Debes llamar al método setDisconnected(DisconnectCause) y definir REJECTED como el parámetro seguido de una llamada al método destroy().

Cómo realizar llamadas salientes

En el flujo para realizar una llamada saliente, existe la posibilidad de que no se pueda realizar debido a restricciones que impone el framework de las telecomunicaciones. Para obtener más información, consulta la sección Restricciones de llamadas.

Para realizar una llamada saliente, sigue estos pasos:

  1. El usuario inicia una llamada saliente dentro de tu app.
  2. Usa el método placeCall(Uri, Bundle) para informar al subsistema de telecomunicaciones sobre la nueva llamada saliente. Ten en cuenta las siguientes consideraciones para los parámetros del método:
    • El parámetro Uri representa la dirección a la que se realiza la llamada. Para números de teléfono normales, usa el esquema de URI tel:.
    • El parámetro Bundle te permite brindar información sobre tu app de llamadas si agregas el objeto PhoneAccountHandle de la app al EXTRA_PHONE_ACCOUNT_HANDLE adicional. Tu app debe proporcionar el objeto PhoneAccountHandle a cada llamada saliente.
    • El parámetro Bundle también te permite especificar si la llamada saliente incluye video; establece el valor STATE_BIDIRECTIONAL en el EXTRA_START_CALL_WITH_VIDEO_STATE adicional. Ten en cuenta que, de forma predeterminada, el subsistema de telecomunicaciones enruta las videollamadas al altavoz.
  3. El subsistema de telecomunicaciones se vincula con la implementación de ConnectionService de tu app.
  4. Si esta no puede realizar una llamada saliente, el subsistema de telecomunicaciones llama al método onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest) para informar a la app que no es posible hacer la llamada en ese momento. Tu app debe informar al usuario que no se puede realizar la llamada.
  5. Si tu app puede realizar la llamada saliente, el subsistema de telecomunicaciones llama al método onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest). La app debe mostrar una instancia de tu clase Connection para representar la nueva llamada saliente. Si quieres obtener más información sobre las propiedades que debes establecer en la conexión, consulta Cómo implementar el servicio de conexión.
  6. Cuando se haya establecido la llamada saliente, llama al método setActive() para informar al subsistema de telecomunicaciones que la llamada está activa.

Finalizar una llamada

Para finalizar una llamada, sigue estos pasos:

  1. Llama a setDisconnected(DisconnectCause) enviando LOCAL como parámetro si el usuario finalizó la llamada o REMOTE si la otra parte finalizó la llamada.
  2. Llama al método destroy().

Restricciones de llamadas

A fin de garantizar una experiencia de llamada consistente y sencilla para tus usuarios, el framework de las telecomunicaciones aplica algunas restricciones a la hora de administrar las llamadas en el dispositivo. Supongamos que el usuario instaló dos apps de llamadas que implementan la API autoadministrada de ConnectionService, FooTalk y BarTalk. En este caso, se aplican las siguientes restricciones:

  • En dispositivos que ejecutan el nivel de API 27 o versiones anteriores, solo una app puede mantener una llamada en curso en cualquier momento. Esta restricción significa que, mientras un usuario está en una llamada mediante la app FooTalk, la app BarTalk no puede iniciar ni recibir llamadas.

    En los dispositivos que ejecutan el nivel de API 28 o versiones posteriores, si FooTalk y BarTalk declaran los permisos de CAPABILITY_SUPPORT_HOLD y CAPABILITY_HOLD, el usuario puede mantener más de una llamada en curso si alterna entre las apps para iniciar o responder otra llamada.

  • Si el usuario participa en llamadas administradas regulares (por ejemplo, con la app de Teléfono integrada), no puede llevar a cabo llamadas que se originaron a partir de apps de llamadas. Esto significa que, si el usuario está en una llamada normal usando su proveedor de telefonía celular, tampoco puede estar en una llamada de FooTalk o BarTalk de forma simultánea.

  • El subsistema de telecomunicaciones desconecta las llamadas de tu app si el usuario realiza una llamada de emergencia.

  • Tu app no puede recibir ni realizar llamadas mientras el usuario está en una llamada de emergencia.

  • Si contestas una llamada entrante en tu app mientras hay una llamada en curso en la otra app de llamadas, la llamada en curso finalizará. Tu app no debería mostrar su interfaz de usuario común de llamada entrante. El framework de las telecomunicaciones muestra la interfaz de usuario de llamada entrante y comunica al usuario que contestar la nueva llamada finalizará la que está en curso. Esto significa que, si el usuario está en una llamada de FooTalk, y la app de BarTalk recibe una llamada entrante, el framework de las telecomunicaciones informará al usuario que tiene una nueva llamada entrante de BarTalk y que responder la llamada de BarTalk finalizará su llamada de FooTalk.

Convertirse en la app de teléfono predeterminada

La aplicación de teléfono o marcador predeterminada es la que proporciona la interfaz de usuario durante la llamada mientras el dispositivo está en modo en una llamada. También proporciona al usuario un medio para iniciar llamadas y ver un historial de llamadas. en su dispositivo. Un dispositivo se incluye en un paquete con una app de teléfono o marcador predeterminada que proporciona el sistema. El usuario puede elegir una sola app para que asuma esta función desde la app del sistema. Una aplicación que desea que cumplir esta función usa el RoleManager para solicitar que completen el Rol RoleManager.ROLE_DIALER.

La aplicación de teléfono predeterminada proporciona una interfaz de usuario mientras el dispositivo está en una llamada. no está en modo auto (es decir, UiModeManager#getCurrentModeType() no está Configuration.UI_MODE_TYPE_CAR).

Para cumplir el rol RoleManager.ROLE_DIALER, una app debe cumplir con un cantidad de requisitos:

  • Debe controlar el intent Intent#ACTION_DIAL. Esto significa que la app debe proporcionar una IU de teclado para que el usuario inicie llamadas salientes
  • Debe implementar por completo la API de InCallService y proporcionar una llamada entrante de Google, así como una IU de llamada en curso.

Nota: Si la app que completa el RoleManager.ROLE_DIALER muestra un null InCallService durante la vinculación, el framework de telecomunicaciones disminuirá automáticamente para volver a usar la app de Teléfono precargada en el dispositivo. El sistema mostrará una notificación a al usuario para informarle que la llamada continuó usando la app de Teléfono precargada. Tu La app nunca debe mostrar una vinculación null. hacerlo significa que no cumple con los requisitos de RoleManager.ROLE_DIALER.

Nota: Si tu aplicación ocupa RoleManager.ROLE_DIALER y realiza cambios en entorno de ejecución, lo que provoca que ya no cumpla con los requisitos de este rol, RoleManager quitará automáticamente tu app del rol y cerrará tu app. Por ejemplo, si utilizas De PackageManager.setComponentEnabledSetting(ComponentName, int, int) a inhabilita de manera programática el InCallService que tu app declara en su manifiesto, tu app ya no cumplirá con los requisitos esperados RoleManager.ROLE_DIALER

El marcador precargado SIEMPRE se usará cuando el usuario realice una llamada de emergencia, incluso si tu la app cumple la función RoleManager.ROLE_DIALER. Para garantizar una relación al realizar una llamada de emergencia, el marcador predeterminado SIEMPRE debe usar TelecomManager.placeCall(Uri, Bundle) para realizar llamadas (incluidas las llamadas de emergencia). Esto garantiza que la plataforma pueda verificar que la solicitud provenga de el marcador predeterminado. Si una app de Teléfono no precargada usa Intent#ACTION_CALL para colocar un llamada de emergencia, se enviará a la app de marcador precargado con Intent#ACTION_DIAL para confirmarlo; esta experiencia del usuario no es óptima.

A continuación, se muestra un ejemplo de registro de manifiesto para un InCallService. Los metadatos TelecomManager#METADATA_IN_CALL_SERVICE_UI indica que este campo La implementación de InCallService tiene como objetivo reemplazar la IU integrada en la llamada. El metadato TelecomManager#METADATA_IN_CALL_SERVICE_RINGING indica que este InCallService reproducirá el tono de las llamadas entrantes. Consulta más abajo para obtener más información sobre cómo mostrar la llamada entrante IU y reproduciendo el tono en tu 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>

Nota: NO debes marcar el InCallService con el atributo android:exported="false"; Hacerlo puede generar una falla en la vinculación a tu implementación. durante las llamadas.

Además de implementar la API de InCallService, también debes declarar una actividad en tu manifiesto, que controla el intent Intent#ACTION_DIAL. En el siguiente ejemplo, se ilustra cómo se hace esto:

 <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>

Cuando un usuario instala tu aplicación y la ejecuta por primera vez, debes usar el RoleManager para solicitar al usuario que vea si quiere que tu app será la nueva app de teléfono predeterminada.

En el siguiente código, se muestra cómo tu app puede solicitar convertirse en la app predeterminada para teléfonos o marcadores:

 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
         }
     }
 }

Acceso a InCallService para dispositivos wearable

    Si tu aplicación es una complementaria de terceros y quiere acceder a las APIs de InCallService, ¿cuál será tu que la app podría hacer son:

    1. Declara el permiso MANAGE_ONGOING_CALLS en tu manifiesto
    2. Asociar con un dispositivo wearable físico a través del API de CompanionDeviceManager como aplicación complementaria. Consulta lo siguiente: https://developer.android.com/guide/topics/connectivity/companion-device-pairing
    3. Implementa este InCallService con el permiso BIND_INCALL_SERVICE

Cómo mostrar la notificación de llamada entrante

Cuando tu app recibe una nueva llamada entrante a través de InCallService#onCallAdded(Call), se responsable de mostrar una IU de llamada entrante para la llamada entrante. Debe hacerlo con APIs de NotificationManager para publicar una nueva notificación de llamada entrante

Cuando tu app declara el TelecomManager#METADATA_IN_CALL_SERVICE_RINGING de metadatos, es responsable de reproducir el tono de las llamadas entrantes. Tu app debe crear una NotificationChannel, que especifica el tono deseado. Por ejemplo:

 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);

Cuando tu app recibe una nueva llamada entrante, crea un Notification para la llamada entrante y la asocia con tu canal de notificaciones de llamadas entrantes. Puedes especificar PendingIntent en la notificación que iniciará la pantalla completa IU de llamada entrante. El framework del administrador de notificaciones mostrará tu notificación como un una notificación de atención si el usuario está usando el teléfono de forma activa. Cuando el usuario no usa el teléfono, se usará la IU de llamada entrante en pantalla completa. Por ejemplo:

 // 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());
```