Core-Telecom

Die Core-Telecom-Bibliothek vereinfacht die Einbindung Ihrer Anruf-App in die Android-Plattform, da sie eine robuste und konsistente Reihe von APIs bietet.

Wenn Sie praktische Implementierungen kennenlernen möchten, finden Sie Beispiel-Apps auf GitHub:

Core-Telecom einrichten

Fügen Sie der build.gradle-Datei Ihrer App die Abhängigkeit androidx.core:core-telecom hinzu:

dependencies {
    implementation ("androidx.core:core-telecom:1.0.0")
}

Deklarieren Sie die Berechtigung MANAGE_OWN_CALLS in Ihrer AndroidManifest.xml:

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

App registrieren

Registrieren Sie Ihre Anruf-App mit CallsManager bei Android, um Anrufe dem System hinzuzufügen. Geben Sie bei der Registrierung die Funktionen Ihrer App an (z. B. Audio- und Videounterstützung):

val callsManager = CallsManager(context)

val capabilities: @CallsManager.Companion.Capability Int =
    (CallsManager.CAPABILITY_BASELINE or
          CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING)

callsManager.registerAppWithTelecom(capabilities)

Anrufverwaltung

Verwenden Sie Core-Telecom-APIs, um einen Anruflebenszyklus zu erstellen und zu verwalten.

Anruf erstellen

Das CallAttributesCompat-Objekt definiert die Eigenschaften eines eindeutigen Anrufs, der die folgenden Merkmale haben kann:

  • displayName: Name des Anrufers.
  • address: Anrufadresse (z. B. Telefonnummer, Besprechungslink).
  • direction: Eingehend oder ausgehend.
  • callType: Audio oder Video.
  • callCapabilities: Unterstützt Weiterleitung und Halten.

Hier ein Beispiel für das Erstellen eines eingehenden Anrufs:

fun createIncomingCallAttributes(
    callerName: String,
    callerNumber: String,
    isVideoCall: Boolean): CallAttributesCompat {
    val addressUri = Uri.parse("YourAppScheme:$callerNumber")

    // Define capabilities supported by your call.
    val callCapabilities = CallAttributesCompat.CallCapability(
        supportsSetInactive = CallAttributesCompat.SUPPORTS_SET_INACTIVE // Call can be made inactive (implies hold)
    )

    return CallAttributesCompat(
        displayName = callerName,
        address = addressUri,
        direction = CallAttributesCompat.DIRECTION_INCOMING,
        callType = if (isVideoCall) CallAttributesCompat.CALL_TYPE_VIDEO_CALL else CallAttributesCompat.CALL_TYPE_AUDIO_CALL,
        callCapabilitiesCompat = callCapabilities
    )
}

Anruf hinzufügen

Verwenden Sie callsManager.addCall mit CallAttributesCompat und Callbacks, um dem System einen neuen Anruf hinzuzufügen und Updates für Remote-Oberflächen zu verwalten. Mit callControlScope im addCall-Block kann Ihre App hauptsächlich den Anrufstatus ändern und Audio-Updates empfangen:

try {
    callsManager.addCall(
        INCOMING_CALL_ATTRIBUTES,
        onAnswerCall, // Watch needs to know if it can answer the call.
        onSetCallDisconnected,
        onSetCallActive,
        onSetCallInactive
    ) {
        // The call was successfully added once this scope runs.
        callControlScope = this
    }
}
catch(addCallException: Exception){
   // Handle the addCall failure.
}

Anruf entgegennehmen

Nehmen Sie einen eingehenden Anruf innerhalb von CallControlScope entgegen:

when (val result = answer(CallAttributesCompat.CALL_TYPE_AUDIO_CALL)) {
    is CallControlResult.Success -> { /* Call answered */ }
    is CallControlResult.Error -> { /* Handle error */ }
}

Anruf ablehnen

Lehnen Sie einen Anruf mit disconnect() und DisconnectCause.REJECTED innerhalb von CallControlScope ab:

disconnect(DisconnectCause(DisconnectCause.REJECTED))

Ausgehenden Anruf aktivieren

Legen Sie fest, dass ein ausgehender Anruf aktiv ist, sobald die andere Partei antwortet:

when (val result = setActive()) {
    is CallControlResult.Success -> { /* Call active */ }
    is CallControlResult.Error -> { /* Handle error */ }
}

Anruf halten

Verwenden Sie setInactive(), um einen Anruf zu halten:

when (val result = setInactive()) {
    is CallControlResult.Success -> { /* Call on hold */ }
    is CallControlResult.Error -> { /* Handle error */ }
}

Anruf trennen

Trennen Sie einen Anruf mit disconnect() und einem DisconnectCause:

disconnect(DisconnectCause(DisconnectCause.LOCAL))

Audio-Endpunkte für Anrufe verwalten

Beobachten und verwalten Sie Audio-Endpunkte mit currentCallEndpoint, availableEndpoints und isMuted Flows innerhalb von CallControlScope. Verwenden Sie nicht die APIs AudioManager#setCommunicationDevice oder AudioManager#startBluetoothSco, um Audiowege zu verwalten, wenn Sie Telecom verwenden. Andernfalls treten Audioprobleme bei Ihrem Anruf auf.

fun observeAudioStateChanges(callControlScope: CallControlScope) {
    with(callControlScope) {
        launch { currentCallEndpoint.collect { /* Update UI */ } }
        launch { availableEndpoints.collect { /* Update UI */ } }
        launch { isMuted.collect { /* Handle mute state */ } }
    }
}

Ändern Sie das aktive Audiogerät mit requestEndpointChange():

coroutineScope.launch {
     callControlScope.requestEndpointChange(callEndpoint)
}

Unterstützung im Vordergrund

Die Bibliothek verwendet ConnectionService (Android 13, API-Level 33 und niedriger) oder foregroundtypes (Android 14, API-Level 34 und höher) für die Unterstützung im Vordergrund.

Im Rahmen der Anforderungen für den Vordergrund muss die App eine Benachrichtigung für Nutzer posten, damit sie wissen, dass die App im Vordergrund ausgeführt wird.

Damit Ihre App die Ausführungspriorität im Vordergrund erhält, erstellen Sie eine Benachrichtigung, sobald Sie den Anruf mit der Plattform hinzufügen. Die Priorität im Vordergrund wird entfernt, wenn Ihre App den Anruf beendet oder Ihre Benachrichtigung nicht mehr gültig ist.

Weitere Informationen zu Diensten im Vordergrund.

Unterstützung für Remote-Oberflächen

Remote-Geräte (Smartwatches, Bluetooth-Headsets, Android Auto) können Anrufe verwalten, ohne dass eine direkte Interaktion mit dem Smartphone erforderlich ist. Ihre App muss Callback-Lambdas (onAnswerCall, onSetCallDisconnected, onSetCallActive, onSetCallInactive) implementieren, die an CallsManager.addCall übergeben werden, um Aktionen zu verarbeiten, die von diesen Geräten initiiert werden.

Wenn eine Remote-Aktion ausgeführt wird, wird das entsprechende Lambda aufgerufen.

Der erfolgreiche Abschluss des Lambdas signalisiert, dass der Befehl verarbeitet wurde. Wenn der Befehl nicht ausgeführt werden kann, sollte das Lambda eine Ausnahme auslösen.

Eine korrekte Implementierung sorgt für eine nahtlose Anrufsteuerung auf verschiedenen Geräten. Testen Sie gründlich mit verschiedenen Remote-Oberflächen.

Anruferweiterungen

Neben der Verwaltung des Anrufstatus und des Audiowegs Ihrer Anrufe unterstützt die Bibliothek auch Anruferweiterungen. Das sind optionale Funktionen, die Ihre App implementieren kann, um die Anruferfahrung auf Remote-Oberflächen wie Android Auto zu verbessern. Zu diesen Funktionen gehören Besprechungsräume, Anruf stummschalten und zusätzliche Anrufsymbole. Wenn Ihre App eine Erweiterung implementiert, werden die von der App bereitgestellten Informationen mit allen verbundenen Geräten synchronisiert, die diese Erweiterungen ebenfalls in ihrer Benutzeroberfläche anzeigen können. Das bedeutet, dass diese Funktionen auch auf Remote-Geräten verfügbar sind, damit Nutzer mit ihnen interagieren können.

Anruf mit Erweiterungen erstellen

Wenn Sie einen Anruf erstellen, können Sie anstelle von CallManager#addCall zum Erstellen des Anrufs auch CallManager#addCallWithExtensions verwenden. Dadurch erhält die App Zugriff auf einen anderen Bereich namens ExtensionInitializationScope. In diesem Bereich kann die App die Gruppe der optionalen Erweiterungen initialisieren, die sie unterstützt. Außerdem bietet dieser Bereich eine zusätzliche Methode, onCall, die nach dem Austausch und der Initialisierung der Erweiterungsfunktionen einen CallControlScope an die App zurückgibt.

scope.launch {
    mCallsManager.addCallWithExtensions(
        attributes,
        onAnswer,
        onDisconnect,
        onSetActive,
        onSetInactive
    ) {
        // Initialize extension-specific code...

        // After the call has been initialized, perform in-call actions
        onCall {
            // Example: process call state updates
            callStateFlow.onEach { newState ->
                // handle call state updates and notify telecom
            }.launchIn(this)

            // Use initialized extensions...
        }
    }
}

Anrufteilnehmer unterstützen

Wenn Ihre App Anrufteilnehmer für Besprechungen oder Gruppenanrufe unterstützt, verwenden Sie addParticipantExtension, um die Unterstützung für diese Erweiterung zu deklarieren, und verwenden Sie die zugehörigen APIs, um Remote-Oberflächen zu aktualisieren, wenn sich die Teilnehmer ändern.

mCallsManager.addCallWithExtensions(...) {
        // Initialize extensions...

        // Notifies Jetpack that this app supports the participant
        // extension and provides the initial participants state in the call.
        val participantExtension = addParticipantExtension(
            initialParticipants,
            initialActiveParticipant
        )

        // After the call has been initialized, perform in-call control actions
        onCall {
            // other in-call control and extension actions...

            // Example: update remote surfaces when the call participants change
            participantsFlow.onEach { newParticipants ->
                participantExtension.updateParticipants(newParticipants)
            }.launchIn(this)
        }
    }

Neben der Benachrichtigung von Remote-Oberflächen darüber, welche Teilnehmer am Anruf teilnehmen, kann der aktive Teilnehmer auch mit ParticipantExtension#updateActiveParticipant aktualisiert werden.

Es gibt auch Unterstützung für optionale Aktionen im Zusammenhang mit den Anrufteilnehmern. Die App kann ParticipantExtension#addRaiseHandSupport verwenden, um die Funktion zu unterstützen, dass Teilnehmer im Anruf die Hand heben können, und um zu sehen, welche anderen Teilnehmer ebenfalls die Hand gehoben haben.

mCallsManager.addCallWithExtensions(...) {
        // Initialize extensions...

        // Notifies Jetpack that this app supports the participant
        // extension and provides the initial list of participants in the call.
        val participantExtension = addParticipantExtension(initialParticipants)
        // Notifies Jetpack that this app supports the notion of participants
        // being able to raise and lower their hands.
        val raiseHandState = participantExtension.addRaiseHandSupport(
                initialRaisedHands
            ) { onHandRaisedStateChanged ->
                // handle this user's raised hand state changed updates from
                // remote surfaces.
            }

        // After the call has been initialized, perform in-call control actions
        onCall {
            // other in-call control and extension actions...

            // Example: update remote surfaces when the call participants change
            participantsFlow.onEach { newParticipants ->
                participantExtension.updateParticipants(newParticipants)
            }.launchIn(this)
            // notify remote surfaces of which of the participants have their
            // hands raised
            raisedHandsFlow.onEach { newRaisedHands ->
                raiseHandState.updateRaisedHands(newRaisedHands)
            }.launchIn(this)
        }
    }

Anruf stummschalten unterstützen

Mit der Funktion „Anruf stummschalten“ kann ein Nutzer anfordern, dass die App die ausgehende Audioausgabe eines Anrufs stummschaltet, ohne das Mikrofon des Geräts physisch stummzuschalten. Diese Funktion wird pro Anruf verwaltet. Jetpack übernimmt die Komplexität der Verwaltung des globalen Stummschaltungsstatus laufender Mobilfunkanrufe, während ein VoIP-Anruf aktiv ist. Dadurch ist das Stummschalten der ausgehenden Audioausgabe in Szenarien mit mehreren Anrufen weniger fehleranfällig. Außerdem sind hilfreiche Funktionen wie Hinweise darauf, ob der Nutzer spricht, verfügbar, wenn der Nutzer spricht, ohne zu bemerken, dass die Funktion „Anruf stummschalten“ aktiviert ist.

mCallsManager.addCallWithExtensions(...) {
        // Initialize extensions...

        // Add support for locally silencing the call's outgoing audio and
        // register a handler for when the user changes the call silence state
        // from a remote surface.
        val callSilenceExtension = addLocalCallSilenceExtension(
            initialCallSilenceState = false
        ) { newCallSilenceStateRequest ->
            // handle the user's request to enable/disable call silence from
            // a remote surface
        }

        // After the call has been initialized, perform in-call control actions
        onCall {
            // other in-call control and extension actions...

            // When the call's call silence state changes, update remote
            // surfaces of the new state.
            callSilenceState.onEach { isSilenced ->
                callSilenceExtension.updateIsLocallySilenced(isSilenced)
            }.launchIn(this)
        }
    }

Anrufsymbole unterstützen

Mit einem Anrufsymbol kann die App ein benutzerdefiniertes Symbol angeben, das den Anruf darstellt und während des Anrufs auf Remote-Oberflächen angezeigt wird. Dieses Symbol kann auch während der Lebensdauer des Anrufs aktualisiert werden.

mCallsManager.addCallWithExtensions(...) {
        // Initialize extensions...

        // Add support for a custom call icon to be displayed during the
        // lifetime of the call.
        val callIconExtension = addCallIconExtension(
            initialCallIconUri = initialUri
        )

        // After the call has been initialized, perform in-call control actions
        onCall {
            // other in-call control and extension actions...

            // When the call's icon changes, update remote surfaces by providing
            // the new URI.
            callIconUri.onEach { newIconUri ->
                callIconExtension.updateCallIconUri(newIconUri)
            }.launchIn(this)
        }
    }

Dem Anrufprotokoll des Systems hinzufügen

Sie können die VoIP-Anrufe Ihrer App dem Anrufprotokoll des Systems hinzufügen, damit sie im System-Dialer angezeigt werden und Nutzer von dort aus zurückrufen können. Weitere Informationen finden Sie unter Einheitliche Anrufliste.