Présentation du framework de télécommunications

Le framework Android Telecom (également appelé "Telecom") gère les appels audio et vidéo sur un appareil Android. Cela inclut les appels basés sur la carte SIM, tels que les appels utilisant le framework de téléphonie, et les appels VoIP implémentant la bibliothèque Jetpack Core-Telecom.

Les principaux composants gérés par Telecom sont ConnectionService et InCallService.

Une implémentation ConnectionService s'appuie sur des technologies telles que le RNIS pour connecter les appels à d'autres parties. L'implémentation ConnectionService la plus courante sur un téléphone est la ConnectionService de téléphonie. Il connecte les appels de l'opérateur.

Une implémentation InCallService fournit une interface utilisateur aux appels gérés par Telecom et permet à l'utilisateur de contrôler et d'interagir avec ces appels. L'implémentation la plus courante d'un InCallService est l'application pour téléphone fournie avec un appareil.

Le télécom joue le rôle de standard. Il achemine les appels que les implémentations ConnectionService fournissent aux interfaces utilisateur appelantes que les implémentations InCallService fournissent.

Vous pouvez implémenter les API Telecom pour les raisons suivantes:

Créer une application de téléphone de remplacement

Pour remplacer l'application Téléphone par défaut sur un appareil Android, implémentez l'API InCallService. Votre implémentation doit répondre aux exigences suivantes:

  • Il ne doit pas avoir de fonctionnalité d'appel et doit se composer uniquement de l'interface utilisateur pour les appels.
  • Il doit gérer tous les appels dont le framework Telecom a connaissance et ne pas faire d'hypothèses sur la nature des appels. Par exemple, il ne doit pas supposer que les appels sont des appels téléphoniques basés sur une carte SIM, ni implémenter de restrictions d'appel basées sur un seul ConnectionService, comme l'application de restrictions de téléphonie pour les appels vidéo.

Pour en savoir plus, consultez InCallService.

Intégrer une solution d'appel

Pour intégrer votre solution d'appel dans Android, vous disposez des options suivantes:

  • Implémenter la bibliothèque Jetpack Core-Telecom autogérée:cette option est idéale pour les développeurs d'applications d'appel autonomes qui ne souhaitent pas afficher leurs appels dans l'application Téléphone par défaut, ni d'autres appels dans leur interface utilisateur.

    Lorsque vous vous intégrez à la bibliothèque Jetpack Core-Telecom, vous aidez votre application à interagir non seulement avec les appels téléphoniques du système sur l'appareil, mais aussi avec d'autres applications d'appel autonomes qui s'intègrent à Telecom. La bibliothèque Core-Telecom gère également le routage et la sélection audio. Pour en savoir plus, consultez Créer une application d'appel.

  • Implémenter l'API ConnectionService gérée:cette option facilite le développement d'une solution d'appel qui s'appuie sur l'application téléphonique existante de l'appareil pour fournir l'interface utilisateur des appels. Par exemple, une implémentation tierce des services d'appels SIP et VoIP. Pour en savoir plus, consultez getDefaultDialerPackage().

    Un ConnectionService seul ne fournit que les moyens de connecter les appels. Il n'a aucune interface utilisateur associée.

  • Implémenter à la fois l'API InCallService et l'API ConnectionService:cette option est idéale si vous souhaitez créer votre propre solution d'appel basée sur ConnectionService, avec sa propre interface utilisateur, et afficher tous les autres appels Android dans la même interface utilisateur. Lorsque vous utilisez cette approche, votre implémentation de InCallService ne doit faire aucune hypothèse sur les sources des appels qu'elle affiche. De plus, votre implémentation de ConnectionService doit continuer à fonctionner sans que l'application de téléphone par défaut ne soit définie sur votre InCallService personnalisée.

Identifier l'appelant

Les appareils équipés d'Android 10 (niveau d'API 29) ou version ultérieure permettent à votre application d'identifier les appels provenant de numéros qui ne figurent pas dans l'annuaire de l'utilisateur comme des appels potentiellement indésirables. Les utilisateurs peuvent choisir de rejeter automatiquement les appels indésirables. Pour offrir plus de transparence aux utilisateurs lorsqu'ils ne répondent pas à un appel, les informations sur ces appels bloqués sont enregistrées dans le journal des appels. L'utilisation de l'API Android 10 élimine l'obligation d'obtenir l'autorisation READ_CALL_LOG de l'utilisateur pour fournir la fonctionnalité de filtrage des appels et de l'appelant.

Vous utilisez une implémentation de CallScreeningService pour filtrer les appels. Appelez la fonction onScreenCall() pour tous les nouveaux appels entrants ou sortants lorsque le numéro ne figure pas dans la liste de contacts de l'utilisateur. Vous pouvez consulter l'objet Call.Details pour obtenir des informations sur l'appel. Plus précisément, la fonction getCallerNumberVerificationStatus() inclut des informations du fournisseur de réseau sur l'autre numéro. Si l'état de validation indique un échec, cela signifie probablement que l'appel provient d'un numéro incorrect ou d'un appel potentiellement indésirable.

Kotlin

class ScreeningService : CallScreeningService() {
    // This function is called when an ingoing or outgoing call
    // is from a number not in the user's contacts list
    override fun onScreenCall(callDetails: Call.Details) {
        // Can check the direction of the call
        val isIncoming = callDetails.callDirection == Call.Details.DIRECTION_INCOMING

        if (isIncoming) {
            // the handle (e.g. phone number) that the Call is currently connected to
            val handle: Uri = callDetails.handle

            // determine if you want to allow or reject the call
            when (callDetails.callerNumberVerificationStatus) {
                Connection.VERIFICATION_STATUS_FAILED -> {
                    // Network verification failed, likely an invalid/spam call.
                }
                Connection.VERIFICATION_STATUS_PASSED -> {
                    // Network verification passed, likely a valid call.
                }
                else -> {
                    // Network could not perform verification.
                    // This branch matches Connection.VERIFICATION_STATUS_NOT_VERIFIED.
                }
            }
        }
    }
}

Java

class ScreeningService extends CallScreeningService {
    @Override
    public void onScreenCall(@NonNull Call.Details callDetails) {
        boolean isIncoming = callDetails.getCallDirection() == Call.Details.DIRECTION_INCOMING;

        if (isIncoming) {
            Uri handle = callDetails.getHandle();

            switch (callDetails.getCallerNumberVerificationStatus()) {
                case Connection.VERIFICATION_STATUS_FAILED:
                    // Network verification failed, likely an invalid/spam call.
                    break;
                case Connection.VERIFICATION_STATUS_PASSED:
                    // Network verification passed, likely a valid call.
                    break;
                default:
                    // Network could not perform verification.
                    // This branch matches Connection.VERIFICATION_STATUS_NOT_VERIFIED
            }
        }
    }
}

Définissez la fonction onScreenCall() pour appeler respondToCall() afin d'indiquer au système comment répondre au nouvel appel. Cette fonction prend un paramètre CallResponse que vous pouvez utiliser pour indiquer au système de bloquer l'appel, de le refuser comme si l'utilisateur l'avait fait ou de le couper. Vous pouvez également demander au système de ne pas ajouter cet appel au journal des appels de l'appareil.

Kotlin

// Tell the system how to respond to the incoming call
// and if it should notify the user of the call.
val response = CallResponse.Builder()
    // Sets whether the incoming call should be blocked.
    .setDisallowCall(false)
    // Sets whether the incoming call should be rejected as if the user did so manually.
    .setRejectCall(false)
    // Sets whether ringing should be silenced for the incoming call.
    .setSilenceCall(false)
    // Sets whether the incoming call should not be displayed in the call log.
    .setSkipCallLog(false)
    // Sets whether a missed call notification should not be shown for the incoming call.
    .setSkipNotification(false)
    .build()

// Call this function to provide your screening response.
respondToCall(callDetails, response)

Java

// Tell the system how to respond to the incoming call
// and if it should notify the user of the call.
CallResponse.Builder response = new CallResponse.Builder();
// Sets whether the incoming call should be blocked.
response.setDisallowCall(false);
// Sets whether the incoming call should be rejected as if the user did so manually.
response.setRejectCall(false);
// Sets whether ringing should be silenced for the incoming call.
response.setSilenceCall(false);
// Sets whether the incoming call should not be displayed in the call log.
response.setSkipCallLog(false);
// Sets whether a missed call notification should not be shown for the incoming call.
response.setSkipNotification(false);

// Call this function to provide your screening response.
respondToCall(callDetails, response.build());

Vous devez enregistrer l'implémentation CallScreeningService dans le fichier manifeste avec le filtre d'intent et l'autorisation appropriés pour que le système puisse la déclencher correctement.

<service
    android:name=".ScreeningService"
    android:permission="android.permission.BIND_SCREENING_SERVICE">
    <intent-filter>
        <action android:name="android.telecom.CallScreeningService" />
    </intent-filter>
</service>

Rediriger un appel

Les appareils équipés d'Android 10 ou version ultérieure gèrent les intents d'appel différemment que les appareils équipés d'Android 9 ou version antérieure. Sous Android 10 et versions ultérieures, la diffusion ACTION_NEW_OUTGOING_CALL est obsolète et remplacée par l'API CallRedirectionService. CallRedirectionService fournit des interfaces que vous pouvez utiliser pour modifier les appels sortants effectués par la plate-forme Android. Par exemple, les applications tierces peuvent annuler des appels et les rediriger via VoIP.

Kotlin

class RedirectionService : CallRedirectionService() {
    override fun onPlaceCall(
        handle: Uri,
        initialPhoneAccount: PhoneAccountHandle,
        allowInteractiveResponse: Boolean
    ) {
        // Determine if the call should proceed, be redirected, or cancelled.
        val callShouldProceed = true
        val callShouldRedirect = false
        when {
            callShouldProceed -> {
                placeCallUnmodified()
            }
            callShouldRedirect -> {
                // Update the URI to point to a different phone number or modify the
                // PhoneAccountHandle and redirect.
                redirectCall(handle, initialPhoneAccount, true)
            }
            else -> {
                cancelCall()
            }
        }
    }
}

Java

class RedirectionService extends CallRedirectionService {
    @Override
    public void onPlaceCall(
            @NonNull Uri handle,
            @NonNull PhoneAccountHandle initialPhoneAccount,
            boolean allowInteractiveResponse
    ) {
        // Determine if the call should proceed, be redirected, or cancelled.
        // Your app should implement this logic to determine the redirection.
        boolean callShouldProceed = true;
        boolean callShouldRedirect = false;
        if (callShouldProceed) {
            placeCallUnmodified();
        } else if (callShouldRedirect) {
            // Update the URI to point to a different phone number or modify the
            // PhoneAccountHandle and redirect.
            redirectCall(handle, initialPhoneAccount, true);
        } else {
            cancelCall();
        }
    }
}

Vous devez enregistrer ce service dans le fichier manifeste pour que le système puisse le démarrer correctement.

<service
    android:name=".RedirectionService"
    android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
    <intent-filter>
        <action android:name="android.telecom.CallRedirectionService"/>
    </intent-filter>
</service>

Pour utiliser un service de redirection, votre application doit demander le rôle de redirection des appels à RoleManager. L'utilisateur sera alors invité à autoriser votre application à gérer les redirections d'appel. Si ce rôle n'est pas attribué à votre application, votre service de redirection n'est pas utilisé.

Vous devez vérifier si votre application dispose de ce rôle lorsque l'utilisateur la lance afin de pouvoir le demander si nécessaire. Vous lancez un intent créé par RoleManager. Veillez donc à remplacer la fonction onActivityResult() pour gérer la sélection de l'utilisateur.

Kotlin

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Tell the system that you want your app to handle call redirects. This
        // is done by using the RoleManager to register your app to handle redirects.
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
            val roleManager = getSystemService(Context.ROLE_SERVICE) as RoleManager
            // Check if the app needs to register call redirection role.
            val shouldRequestRole = roleManager.isRoleAvailable(RoleManager.ROLE_CALL_REDIRECTION) &&
                    !roleManager.isRoleHeld(RoleManager.ROLE_CALL_REDIRECTION)
            if (shouldRequestRole) {
                val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_REDIRECTION)
                startActivityForResult(intent, REDIRECT_ROLE_REQUEST_CODE)
            }
        }
    }

    companion object {
        private const val REDIRECT_ROLE_REQUEST_CODE = 1
    }
}

Java

class MainActivity extends AppCompatActivity {
    private static final int REDIRECT_ROLE_REQUEST_CODE = 0;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Tell the system that you want your app to handle call redirects. This
        // is done by using the RoleManager to register your app to handle redirects.
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
            RoleManager roleManager = (RoleManager) getSystemService(Context.ROLE_SERVICE);
            // Check if the app needs to register call redirection role.
            boolean shouldRequestRole = roleManager.isRoleAvailable(RoleManager.ROLE_CALL_REDIRECTION) &&
                    !roleManager.isRoleHeld(RoleManager.ROLE_CALL_REDIRECTION);
            if (shouldRequestRole) {
                Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_REDIRECTION);
                startActivityForResult(intent, REDIRECT_ROLE_REQUEST_CODE);
            }
        }
    }
}