Die Core-Telecom-Bibliothek vereinfacht die Integration Ihrer Anrufanwendung in die Android-Plattform, da sie eine robuste und konsistente Reihe von APIs bietet.
Wenn Sie sich praktische Implementierungen ansehen möchten, finden Sie Beispielanwendungen auf GitHub:
- Lightweight Sample App: Ein minimales Beispiel für die Verwendung der
Core-TelecomAPI. Ideal, um sich schnell einen Überblick über grundlegende Konzepte zu verschaffen. - Umfassende Beispiel-App (entwickelt vom Core-Telecom-Team): Eine funktionsreiche Anwendung, die erweiterte Telekommunikationsfunktionen und Best Practices demonstriert. Hier finden Sie Informationen zu komplexen Integrationsszenarien.
Core-Telecom einrichten
Fügen Sie der Datei build.gradle 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 Ihrem 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 den Lebenszyklus eines Anrufs 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, Videokonferenzlink).direction: Eingehend oder ausgehend.callType: Audio oder Video.callCapabilities: Unterstützt die Funktion „Transfer and Hold“.
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")
return CallAttributesCompat(
displayName = callerName,
address = addressUri,
direction = CallAttributesCompat.DIRECTION_INCOMING,
callType = if (isVideoCall) {
CallAttributesCompat.CALL_TYPE_VIDEO_CALL
} else {
CallAttributesCompat.CALL_TYPE_AUDIO_CALL
},
callCapabilities = CallAttributesCompat.SUPPORTS_SET_INACTIVE
)
}
Anruf hinzufügen
Verwenden Sie callsManager.addCall mit CallAttributesCompat und Rückrufen, um dem System einen neuen Anruf hinzuzufügen und Updates für die Remote-Oberfläche zu verwalten. Mit dem callControlScope-Block innerhalb des addCall-Blocks kann Ihre App in erster Linie 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
So nehmen Sie einen eingehenden Anruf in der CallControlScope an:
when (val result = answer(CallAttributesCompat.CALL_TYPE_AUDIO_CALL)) {
is CallControlResult.Success -> { /* Call answered */ }
is CallControlResult.Error -> { /* Handle error */ }
}
Anruf ablehnen
So lehnen Sie einen Anruf mit disconnect() und DisconnectCause.REJECTED innerhalb von CallControlScope ab:
disconnect(DisconnectCause(DisconnectCause.REJECTED))
Ausgehenden Anruf aktivieren
Ausgehenden Anruf als aktiv festlegen, sobald die Gegenstelle antwortet:
when (val result = setActive()) {
is CallControlResult.Success -> { /* Call active */ }
is CallControlResult.Error -> { /* Handle error */ }
}
Halten eines Anrufs
So schalten Sie einen Anruf mit setInactive() auf „Halten“:
when (val result = setInactive()) {
is CallControlResult.Success -> { /* Call on hold */ }
is CallControlResult.Error -> { /* Handle error */ }
}
Anruf beenden
So trennen Sie einen Anruf mit disconnect() über ein DisconnectCause:
disconnect(DisconnectCause(DisconnectCause.LOCAL))
Audio-Endpunkte für Anrufe verwalten
Audio-Endpunkte mit currentCallEndpoint, availableEndpoints und isMuted Flows in der CallControlScope beobachten und verwalten. Verwenden Sie die APIs AudioManager#setCommunicationDevice oder AudioManager#startBluetoothSco nicht, um Audio-Routen zu verwalten, wenn Sie Telecom verwenden. Andernfalls treten bei Ihrem Anruf Audioprobleme auf.
fun observeAudioStateChanges(callControlScope: CallControlScope) {
with(callControlScope) {
launch { currentCallEndpoint.collect { /* Update UI */ } }
launch { availableEndpoints.collect { /* Update UI */ } }
launch { isMuted.collect { /* Handle mute state */ } }
}
}
So ändern Sie das aktive Audiogerät mit requestEndpointChange():
coroutineScope.launch {
callControlScope.requestEndpointChange(callEndpoint)
}
Unterstützung im Vordergrund
Die Bibliothek verwendet ConnectionService unter Android 13 (API‑Level 33) und niedriger oder Vordergrunddiensttypen unter Android 14 (API‑Level 34) und höher für die Vordergrundunterstützung.
Damit Anrufe aktiv bleiben, wenn Ihre App im Hintergrund ausgeführt wird, hosten Sie CallsManager in einem Service im Vordergrund (z. B. LifecycleService) und deklarieren Sie den phoneCall-Vordergrunddiensttyp in Ihrem AndroidManifest.xml:
<service
android:name=".TelecomVoipService"
android:foregroundServiceType="phoneCall" />
Im Rahmen der Anforderungen für den Vordergrund muss Ihre App eine NotificationCompat.CallStyle-Benachrichtigung posten, damit Nutzer wissen, dass ein Anruf im Vordergrund aktiv ist. Damit Ihre App die Priorität für die Ausführung im Vordergrund erhält, müssen Sie Ihren Dienst mit startForeground in den Vordergrund verschieben, sobald Sie den Aufruf mit der Plattform hinzufügen:
startForeground(
notificationId,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL
)
Weitere Informationen zu Vordergrunddiensten
Remotesupport für Surface
Auf Remote-Geräten (Smartwatches, Bluetooth-Headsets, Android Auto) können Anrufe verwaltet werden, 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 der Lambda-Funktion signalisiert, dass der Befehl verarbeitet wurde. Wenn der Befehl nicht ausgeführt werden kann, sollte die Lambda-Funktion eine Ausnahme auslösen.
Eine korrekte Implementierung sorgt für eine nahtlose Anrufsteuerung auf verschiedenen Geräten. Testen Sie die Funktion gründlich mit verschiedenen Oberflächen der Fernbedienung.
Anruferweiterungen
Neben der Verwaltung des Anrufstatus und der Audioausgabe Ihrer Anrufe unterstützt die Bibliothek auch Anruferweiterungen. Das sind optionale Funktionen, die Ihre App implementieren kann, um die Anrufe auf Remote-Oberflächen wie Android Auto zu optimieren. Dazu gehören Konferenzräume, das Stummschalten von Anrufen 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 auch in ihrer Benutzeroberfläche unterstützen. 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 CallsManager.addCall CallsManager.addCallWithExtensions verwenden. Dadurch erhält die App Zugriff auf einen anderen Bereich namens ExtensionInitializationScope. Mit diesem Bereich kann die Anwendung die Gruppe der optionalen Erweiterungen initialisieren, die sie unterstützt. Außerdem bietet dieser Bereich eine zusätzliche Methode, onCall, die nach Abschluss des Austauschs und der Initialisierung der Erweiterungsfunktion 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...
}
}
}
Teilnehmer an Supportanrufen
Wenn Ihre App Anrufteilnehmer für Videokonferenzen oder Gruppenanrufe unterstützt, deklarieren Sie die Unterstützung für diese Erweiterung mit addParticipantExtension 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.
Außerdem werden optionale Aktionen im Zusammenhang mit den Anrufteilnehmern unterstützt.
Die App kann ParticipantExtension#addRaiseHandSupport verwenden, um die Funktion „Melden“ im Anruf zu unterstützen und zu sehen, welche anderen Teilnehmer sich ebenfalls gemeldet 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)
}
}
Supportanrufe stummschalten
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 von ausgehendem Audio in Szenarien mit mehreren Anrufen weniger fehleranfällig. Außerdem sind hilfreiche Funktionen wie die Anzeige „Sprichst du gerade?“ möglich, wenn der Nutzer spricht, ohne zu wissen, dass die Stummschaltung 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)
}
}
Symbole für Supportanrufe
Mit einem Anrufsymbol kann die App ein benutzerdefiniertes Symbol für den Anruf festlegen, das während des Anrufs auf Remote-Oberflächen angezeigt wird. Dieses Symbol kann auch während 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)
}
}
Zur Systemanrufliste hinzufügen
Sie können die VoIP-Anrufe Ihrer App der Systemanrufliste hinzufügen, damit sie in der Systemwählhilfe angezeigt werden und Nutzer von dort aus zurückrufen können. Weitere Informationen finden Sie unter Einheitliche Anrufliste.