Telecom-Framework – Übersicht

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-Aufrufe, bei denen die ConnectionService API implementiert ist.

Die Hauptkomponenten, die von Telecom verwaltet werden, sind ConnectionService und InCallService.

Eine ConnectionService-Implementierung verwendet Technologien wie VoIP, um Anrufe mit anderen Parteien zu verbinden. Die gängigste ConnectionService-Implementierung auf einem Telefon ist die Telefonie-ConnectionService. Es stellt Anrufe über Mobilfunkanbieter her.

Eine InCallService-Implementierung bietet eine Benutzeroberfläche für von der Telekommunikationsbranche verwaltete Anrufe und ermöglicht dem Nutzer, diese Aufrufe zu steuern und mit ihnen zu interagieren. Die gängigste Implementierung einer InCallService ist die in einem Gerät enthaltene Telefon-App.

Telekommunikation fungiert als Telefonzentrale. Sie leitet Aufrufe von ConnectionService-Implementierungen an die aufrufenden Benutzeroberflächen von InCallService-Implementierungen weiter.

Die Implementierung der Telecom APIs kann aus folgenden Gründen sinnvoll sein:

Ersatz-Telefon-App erstellen

Wenn du einen Ersatz für die Standard-Telefon-App auf einem Android-Gerät erstellen möchtest, implementiere die InCallService API. Ihre Implementierung muss die folgenden Anforderungen erfüllen:

  • Sie darf keine Aufruffunktion haben und darf ausschließlich die Benutzeroberfläche für den Aufruf umfassen.
  • Er muss alle Aufrufe verarbeiten, die dem Telekommunikations-Framework bekannt sind, und es darf keine Annahmen über die Art der Aufrufe getroffen werden. Es darf beispielsweise nicht davon ausgegangen werden, dass Anrufe SIM-basierte Telefonieanrufe sind, und es darf keine Anrufbeschränkungen implementiert werden, die auf einer ConnectionService basieren, wie die Erzwingung von Telefonieeinschränkungen für Videoanrufe.

Weitere Informationen findest du unter InCallService.

Anruflösung einbinden

Sie haben folgende Möglichkeiten, Ihre Anruflösung in Android zu integrieren:

  • Selbstverwaltete ConnectionService API implementieren:Diese Option ist ideal für Entwickler von eigenständigen Anruf-Apps, die ihre Anrufe weder in der standardmäßigen Telefon-App noch andere Anrufe auf der Benutzeroberfläche anzeigen möchten.

    Wenn Sie eine selbstverwaltete ConnectionService verwenden, unterstützt die Anwendung nicht nur die Interaktion mit nativen Telefonieaufrufen auf dem Gerät, sondern auch mit anderen eigenständigen Anrufanwendungen, die diese API implementieren. Über die selbstverwaltete ConnectionService API werden auch das Audiorouting und der Fokus verwaltet. Weitere Informationen finden Sie unter Anruf-App erstellen.

  • Managed ConnectionService API implementieren:Diese Option erleichtert die Entwicklung einer Anruflösung, die die Benutzeroberfläche für Anrufe über die vorhandene Telefonanwendung auf dem Gerät bereitstellt. Beispiele hierfür sind Implementierungen von SIP-Anruf- und VoIP-Anrufdiensten von Drittanbietern. Weitere Informationen findest du unter getDefaultDialerPackage().

    Ein ConnectionService allein ermöglicht nur die Verbindung von Anrufen. Sie hat keine zugehörige Benutzeroberfläche.

  • Implementiere sowohl die InCallService API als auch die ConnectionService API: Diese Option ist ideal, wenn du deine eigene ConnectionService-basierte Anruflösung mit eigener Benutzeroberfläche erstellen und auch alle anderen Android-Aufrufe in derselben Benutzeroberfläche anzeigen möchtest. Bei diesem Ansatz darf die Implementierung von InCallService keine Annahmen über die Quellen der angezeigten Aufrufe treffen. Außerdem muss die Implementierung von ConnectionService auch dann funktionieren, wenn die Standard-Telefon-App nicht auf den benutzerdefinierten InCallService festgelegt ist.

Anruf-Filter

Auf Geräten mit Android 10 (API-Level 29) oder höher kann deine App Anrufe von Nummern, die nicht im Adressbuch des Nutzers enthalten sind, als potenzielle Spamanrufe erkennen. Nutzer können Spamanrufe automatisch ablehnen lassen. Um Nutzern mehr Transparenz zu bieten, wenn Anrufe verpasst werden, werden Informationen zu diesen blockierten Anrufen in der Anrufliste gespeichert. Wenn du die Android 10 API verwendest, musst du nicht die Berechtigung READ_CALL_LOG vom Nutzer einholen, um Funktionen für den Anruf-Filter und die Anrufer-ID nutzen zu können.

Sie verwenden eine CallScreeningService-Implementierung, um Aufrufe zu filtern. Rufen Sie die Funktion onScreenCall() für alle neuen eingehenden oder ausgehenden Anrufe auf, wenn sich die Nummer nicht in der Kontaktliste des Nutzers befindet. Informationen zum Aufruf findest du im Objekt Call.Details. Konkret enthält die Funktion getCallerNumberVerificationStatus() vom Netzwerkanbieter Informationen zu der anderen Nummer. Wenn der Bestätigungsstatus fehlgeschlagen ist, weist dies darauf hin, dass der Anruf von einer ungültigen Nummer oder einem potenziellen Spamanruf stammt.

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 onScreenCall()-Funktion so fest, dass respondToCall() aufgerufen wird, um dem System mitzuteilen, wie der neue Aufruf beantwortet werden soll. Diese Funktion verwendet einen CallResponse-Parameter, mit dem Sie das System anweisen können, den Aufruf zu blockieren, ihn so abzulehnen, als er ihn der Nutzer tat, oder ihn stummzuschalten. Sie können das System auch anweisen, diesen Aufruf gar nicht zur Anrufliste des Geräts hinzuzufügen.

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

Du musst die CallScreeningService-Implementierung in der Manifestdatei mit dem entsprechenden Intent-Filter und der entsprechenden Berechtigung registrieren, damit das System sie korrekt 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>

Anrufe weiterleiten

Geräte mit Android 10 oder höher verwalten Anruf-Intents anders als Geräte mit Android 9 oder niedriger. Unter Android 10 und höher wurde die ACTION_NEW_OUTGOING_CALL-Übertragung eingestellt und durch die CallRedirectionService API ersetzt. CallRedirectionService stellt Schnittstellen bereit, mit denen Sie ausgehende Aufrufe der Android-Plattform ändern können. Drittanbieter-Apps können beispielsweise Anrufe abbrechen und über VoIP umleiten.

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 ordnungsgemäß 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>

Damit Sie einen Weiterleitungsdienst verwenden können, muss Ihre App die Rolle für die Anrufweiterleitung von RoleManager anfordern. Dadurch wird der Nutzer gefragt, ob er zulassen möchte, dass Ihre App Anrufweiterleitungen verarbeitet. Wenn Ihrer Anwendung diese Rolle nicht gewährt wird, wird der Weiterleitungsdienst nicht verwendet.

Sie sollten prüfen, ob Ihre Anwendung diese Rolle hat, wenn der Nutzer sie 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);
            }
        }
    }
}