Das Android Telecom-Framework (auch einfach als „Telecom“ bezeichnet) verwaltet Audio- und Videoanrufe auf einem Android-Gerät. Dazu gehören SIM-basierte Anrufe, z. B. Anrufe, die das Telefonie-Framework verwenden, und VoIP-Anrufe, die die Core-Telecom
Jetpack-Bibliothek implementieren.
Die wichtigsten Komponenten, die von Telecom verwaltet werden, sind ConnectionService
und InCallService
.
Bei einer ConnectionService
-Implementierung werden Technologien wie das PSTN verwendet, um Anrufe mit anderen Parteien zu verbinden. Die gängigste ConnectionService
-Implementierung auf einem Smartphone ist die Telefonie-ConnectionService
. Es stellt Anrufe über den Mobilfunkanbieter her.
Eine InCallService
-Implementierung bietet eine Benutzeroberfläche für von Telecom verwaltete Anrufe und ermöglicht es dem Nutzer, diese Anrufe zu steuern und mit ihnen zu interagieren. Die gängigste Implementierung einer InCallService
ist die Telefon-App, die im Lieferumfang eines Geräts enthalten ist.
Telecom fungiert als Vermittlung. Es leitet Aufrufe, die von ConnectionService
-Implementierungen bereitgestellt werden, an die aufrufenden Benutzeroberflächen weiter, die von InCallService
-Implementierungen bereitgestellt werden.
Es gibt folgende Gründe, die für die Implementierung der Telecom APIs sprechen:
- Erstellen Sie einen Ersatz für die Telefon-App des Systems.
- Eine Anruflösung in die Android-Anruffunktionen integrieren
Ersatz-Telefon-App erstellen
Wenn Sie einen Ersatz für die Standard-Telefonie-App auf einem Android-Gerät erstellen möchten, implementieren Sie die InCallService
API. Ihre Implementierung muss die folgenden Anforderungen erfüllen:
- Es darf keine Anruffunktionen haben und muss ausschließlich aus der Benutzeroberfläche für Anrufe bestehen.
- Es muss alle Anrufe verarbeiten, die dem Telecom-Framework bekannt sind, und darf keine Annahmen über die Art der Anrufe treffen. Es darf beispielsweise nicht davon ausgegangen werden, dass Anrufe SIM-basierte Telefonanrufe sind, und es dürfen keine Anrufbeschränkungen implementiert werden, die auf einer einzelnen
ConnectionService
basieren, z. B. die Durchsetzung von Telefonbeschränkungen für Videoanrufe.
Weitere Informationen finden Sie unter InCallService
.
Anruflösung integrieren
Sie haben folgende Möglichkeiten, Ihre Anruflösung in Android zu integrieren:
Die selbstverwaltete Core-Telecom Jetpack-Bibliothek implementieren:Diese Option eignet sich ideal für Entwickler von eigenständigen Anruf-Apps, die ihre Anrufe nicht in der Standardtelefon-App und auch keine anderen Anrufe in ihrer Benutzeroberfläche anzeigen lassen möchten.
Wenn Sie die
Core-Telecom
Jetpack-Bibliothek einbinden, kann Ihre App nicht nur mit der Systemtelefonie auf dem Gerät, sondern auch mit anderen eigenständigen Anruf-Apps interagieren, die in Telecom eingebunden sind. Die BibliothekCore-Telecom
verwaltet auch das Audio-Routing und den Audiofokus. Weitere Informationen finden Sie unter Anruf-App erstellen.Verwaltete ConnectionService API implementieren:Mit dieser Option können Sie eine Anruflösung entwickeln, die die vorhandene Telefonanwendung des Geräts als Benutzeroberfläche für Anrufe nutzt. Beispiele hierfür sind die Implementierung von SIP- und VoIP-Anrufdiensten durch Drittanbieter. Weitere Informationen finden Sie unter
getDefaultDialerPackage()
.Ein
ConnectionService
allein bietet nur die Möglichkeit, Anrufe zu verbinden. Es hat keine Benutzeroberfläche.Sowohl die InCallService API als auch die ConnectionService API implementieren:Diese Option eignet sich ideal, wenn Sie eine eigene
ConnectionService
-basierte Anruflösung mit eigener Benutzeroberfläche erstellen und alle anderen Android-Anrufe in derselben Benutzeroberfläche anzeigen möchten. Bei diesem Ansatz darf Ihre Implementierung vonInCallService
keine Annahmen über die Quellen der angezeigten Aufrufe treffen. Außerdem muss Ihre Implementierung vonConnectionService
weiterhin funktionieren, ohne dass die Standard-Telefon-App auf Ihre benutzerdefinierteInCallService
festgelegt ist.
Anruf-Filter
Auf Geräten mit Android 10 (API-Level 29) oder höher kann Ihre App Anrufe von Nummern, die nicht im Adressbuch des Nutzers stehen, als potenzielle Spamanrufe erkennen. Nutzer können festlegen, dass Spamanrufe stumm abgelehnt werden. Um Nutzern mehr Transparenz zu bieten, wenn sie Anrufe verpassen, werden Informationen zu diesen blockierten Anrufen im Anrufprotokoll protokolliert. Wenn Sie die Android 10 API verwenden, müssen Sie die Berechtigung READ_CALL_LOG
nicht mehr vom Nutzer einholen, um Anruffilter und Anruferidentität bereitzustellen.
Sie verwenden eine CallScreeningService
-Implementierung, um Anrufe zu filtern. Rufen Sie die Funktion onScreenCall()
für alle neuen eingehenden oder ausgehenden Anrufe auf, wenn die Nummer nicht in der Kontaktliste des Nutzers enthalten ist. Informationen zum Anruf finden Sie im Call.Details
-Objekt. Die Funktion getCallerNumberVerificationStatus()
enthält insbesondere Informationen des Mobilfunkanbieters zur anderen Nummer.
Wenn der Überprüfungsstatus „Fehlgeschlagen“ lautet, ist das ein guter Hinweis darauf, dass es sich bei dem Anruf um eine ungültige Nummer oder einen potenziellen Spamanruf handelt.
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 } } } }
Legen Sie die Funktion onScreenCall()
so fest, dass respondToCall()
aufgerufen wird, um dem System mitzuteilen, wie es auf den neuen Anruf reagieren soll. Diese Funktion verwendet einen CallResponse
-Parameter, mit dem Sie dem System mitteilen können, den Anruf zu blockieren, abzulehnen, als würde der Nutzer dies tun, oder stummzuschalten. Sie können dem System auch mitteilen, dass dieser Anruf dem Anrufprotokoll des Geräts nicht hinzugefügt werden soll.
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());
Sie müssen die CallScreeningService
-Implementierung in der Manifestdatei mit dem entsprechenden Intent-Filter und der entsprechenden Berechtigung registrieren, damit das System sie richtig auslösen kann.
<service
android:name=".ScreeningService"
android:permission="android.permission.BIND_SCREENING_SERVICE">
<intent-filter>
<action android:name="android.telecom.CallScreeningService" />
</intent-filter>
</service>
Anruf weiterleiten
Auf Geräten mit Android 10 oder höher werden Anrufabsichten anders verwaltet als auf Geräten mit Android 9 oder niedriger. Unter Android 10 und höher wird der ACTION_NEW_OUTGOING_CALL
-Broadcast eingestellt und durch die CallRedirectionService
-API ersetzt. Die CallRedirectionService
bietet Schnittstellen, mit denen Sie ausgehende Anrufe ändern können, die über die Android-Plattform getätigt werden. So können Drittanbieter-Apps Anrufe beispielsweise abbrechen und über VoIP weiterleiten.
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(); } } }
Sie müssen diesen Dienst im Manifest registrieren, damit das System ihn richtig starten kann.
<service
android:name=".RedirectionService"
android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
<intent-filter>
<action android:name="android.telecom.CallRedirectionService"/>
</intent-filter>
</service>
Wenn Sie einen Weiterleitungsdienst verwenden möchten, muss Ihre App die Rolle „Anrufweiterleitung“ von der RoleManager
anfordern. Der Nutzer wird gefragt, ob er Ihrer App erlauben möchte, Anrufweiterleitungen zu verarbeiten. Wenn Ihrer App diese Rolle nicht gewährt wird, wird Ihr Weiterleitungsdienst nicht verwendet.
Sie sollten prüfen, ob Ihre App diese Rolle hat, wenn der Nutzer Ihre App startet, damit Sie sie bei Bedarf anfordern können. Sie starten einen Intent, der von RoleManager
erstellt wurde. Überschreiben Sie daher die Funktion onActivityResult()
, um die Auswahl des Nutzers zu verarbeiten.
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); } } } }