Le framework Android Telecom (également appelé simplement "Telecom") gère les appels audio et vidéo sur un appareil Android. Cela inclut les appels basés sur une carte SIM, tels que les appels qui utilisent le framework de téléphonie et les appels VoIP qui implémentent l'API ConnectionService
.
Les principaux composants gérés par Telecom sont ConnectionService
et InCallService
.
Une implémentation ConnectionService
utilise des technologies telles que la VoIP pour connecter les appels à d'autres parties. L'implémentation ConnectionService
la plus courante sur un téléphone est l'ConnectionService
de téléphonie. Elle connecte les appels via l'opérateur.
Une implémentation InCallService
fournit une interface utilisateur aux appels gérés par Telecom et permet à l'utilisateur de les 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.
Les télécommunications font office de standard. Elle achemine les appels fournis par les implémentations ConnectionService
vers les interfaces utilisateur appelantes fournies par les implémentations InCallService
.
Vous pouvez implémenter les API Telecom pour les raisons suivantes:
- Pour créer un remplacement de l'application de téléphone système.
- Intégrer une solution d'appel à l'expérience d'appel Android
Créer une application pour téléphone de remplacement
Pour créer un remplacement de l'application pour téléphone par défaut sur un appareil Android, implémentez l'API InCallService
. Votre mise en œuvre doit répondre aux exigences suivantes:
- Elle ne doit pas comporter de capacité d'appel et doit se composer uniquement de l'interface utilisateur permettant d'effectuer des appels.
- Il doit gérer tous les appels dont le framework de télécommunications a connaissance et ne pas émettre d'hypothèses sur la nature de ces appels. Par exemple, il ne doit pas supposer que les appels sont des appels de téléphonie basés sur une carte SIM ni implémenter des restrictions d'appel basées sur un seul
ConnectionService
, telles que l'application des 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 à Android, vous disposez des options suivantes:
Implémenter l'API ConnectionService 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 de téléphone par défaut ni afficher d'autres appels dans leur interface utilisateur.
Lorsque vous utilisez un
ConnectionService
autogéré, vous aidez votre application à interagir non seulement avec les appels de téléphonie natifs sur l'appareil, mais également avec d'autres applications d'appel autonomes qui implémentent cette API. L'APIConnectionService
autogérée gère également le routage et la sélection audio. Pour en savoir plus, consultez Créer une application appelante.Implémenter l'API ConnectionService gérée:cette option facilite le développement d'une solution d'appel qui repose sur l'application de téléphonie d'appareil existante pour fournir l'interface utilisateur pour les appels. Il peut s'agir, par exemple, d'une implémentation tierce de services d'appel SIP et de VoIP. Pour en savoir plus, consultez
getDefaultDialerPackage()
.À lui seul, un
ConnectionService
ne permet que de connecter des appels. Elle n'est associée à aucune interface utilisateur.Implémentez à 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
, dotée de sa propre interface utilisateur, ou afficher tous les autres appels Android dans la même interface utilisateur. Lorsque vous utilisez cette approche, l'implémentation deInCallService
ne doit faire aucune hypothèse concernant les sources des appels qu'il affiche. En outre, votre implémentation deConnectionService
doit continuer à fonctionner si l'application pour téléphone par défaut n'est pas définie sur votreInCallService
personnalisé.
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 ne figurant pas dans le carnet d'adresses de l'utilisateur comme des appels potentiellement indésirables. Les utilisateurs peuvent faire en sorte que les appels indésirables soient rejetés en mode silencieux. Pour assurer une plus grande transparence aux utilisateurs lorsqu'ils manquent des appels, les informations sur ces appels bloqués sont consignées dans le journal d'appels. Avec l'API Android 10, il n'est pas nécessaire d'obtenir l'autorisation READ_CALL_LOG
de la part de l'utilisateur pour permettre le filtrage des appels et l'affichage du numéro de l'appelant.
Vous utilisez une implémentation CallScreeningService
pour filtrer les appels. Appelez la fonction onScreenCall()
pour tout nouvel appel entrant ou sortant 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 de la part du fournisseur d'accès sur l'autre numéro.
Si l'état de la validation a échoué, cela signifie que l'appel provient d'un numéro non valide ou est 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 qu'elle appelle respondToCall()
afin d'indiquer au système comment répondre au nouvel appel. Cette fonction utilise un paramètre CallResponse
que vous pouvez utiliser pour indiquer au système de bloquer l'appel, de le rejeter comme si l'utilisateur l'avait fait ou de le mettre sous silence. Vous pouvez également demander au système d'ignorer l'ajout de cet appel au journal d'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 de 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 de ceux équipés d'Android 9 ou version antérieure. Sur Android 10 ou version ultérieure, 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, des applications tierces peuvent annuler des appels et les réacheminer 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 à partir de RoleManager
. Celle-ci demandera à l'utilisateur s'il souhaite autoriser votre application à gérer les redirections d'appel. Si ce rôle ne lui est pas attribué, 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
. Assurez-vous donc de 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); } } } }