Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Cómo crear una app de llamadas

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 marco de trabajo de Android incluye el paquete android.telecom, el cual contiene clases que te ayudan a crear una app de llamadas según el marco de trabajo de las telecomunicaciones. Si creas tu aplicación de acuerdo con el marco de trabajo de las telecomunicaciones, obtendrás las siguientes ventajas:

  • Tu app interopera correctamente con el subsistema nativo de telecomunicaciones del dispositivo.
  • Tu app interopera correctamente con otras aplicaciones de llamadas que también cumplen con las disposiciones del marco de trabajo.
  • El marco de trabajo ayuda a tu app a administrar el enrutamiento de audio y video.
  • El marco de trabajo ayuda a tu app a determinar si sus llamadas tienen foco.

Permisos y declaraciones de manifiesto

En el manifiesto de la app, declara que tu aplicación utiliza los permisos MANAGE_OWN_CALLS, READ_CALL_LOG y READ_PHONE_STATE, como se muestra en el siguiente ejemplo:

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

        <!-- Needed only if your calling app reads numbers from the `PHONE_STATE`
             intent action. -->
        <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
        …
    </manifest>
    

Para obtener más información sobre cómo declarar permisos de apps, consulta 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>
    

Para obtener más información sobre cómo declarar los componentes de la aplicación, incluidos los servicios, consulta 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 una notificación) 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 aplicación.

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 y tu app debe mostrar la IU de dicha llamada.

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 de audio con el método setAudioRoute(int). También se puede llamar a este método si el sistema cambia la ruta de 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 ha respondido 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 marco de trabajo 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, debe llamar al método destroy() para informar al sistema que se 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, tu app debe llamar al método setDisconnected(DisconnectCause) y especificar LOCAL como el parámetro para indicar que una solicitud del usuario provocó la desconexión de la llamada. Entonces, tu app debe llamar al método destroy() para informar al subsistema de telecomunicaciones que se 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 manejar 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 manejarlas usando las API.

Cómo contestar las llamadas entrantes

El flujo para manejar las llamadas entrantes cambia si hay llamadas en otras apps. El motivo de la diferencia en los flujos es que el marco de trabajo 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 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 marco de trabajo 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 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 manera 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.

Cómo 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 marco de trabajo 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 la API nivel 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 la API nivel 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 marca el número de 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 aplicación 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 marco de trabajo 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 marco de trabajo de las telecomunicaciones informará al usuario que tiene una nueva llamada entrante de BarTalk y que responderá la llamada de BarTalk.