Die Core-Telecom
-Bibliothek vereinfacht die Integration Ihrer anrufenden Anwendung in die Android-Plattform, da sie eine robuste und konsistente Reihe von APIs bietet.
Wenn Sie sich praktische Implementierungen ansehen möchten, finden Sie auf GitHub Beispielanwendungen:
- Leichte Beispiel-App: Ein minimales Beispiel, das die Verwendung der
Core-Telecom
API veranschaulicht. Ideal, um sich schnell grundlegende Konzepte anzueignen. - Umfassende Beispiel-App (vom Core-Telecom-Team entwickelt): Eine funktionsreichere Anwendung, die erweiterte Telekommunikationsfunktionen und Best Practices zeigt. Dies ist eine gute Ressource, um komplexe Integrationsszenarien zu verstehen.
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 dem System Anrufe 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 Anrufzyklus 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, Konferenzlink)direction
: Eingehend oder ausgehend.callType
: Audio oder Video.callCapabilities
: Unterstützt Weiterleiten 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 Rückrufen, um dem System einen neuen Aufruf hinzuzufügen und Remote-Oberflächenupdates zu verwalten. Mit dem callControlScope
innerhalb des addCall
-Blocks kann Ihre App hauptsächlich den Anrufstatus ändern und Audioupdates 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 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
Anruf mit disconnect()
und DisconnectCause.REJECTED
in CallControlScope
ablehnen:
disconnect(DisconnectCause(DisconnectCause.REJECTED))
Ausgehenden Anruf aktivieren
So legen Sie fest, dass ein ausgehender Anruf aktiv wird, sobald die andere Seite antwortet:
when (val result = setActive()) {
is CallControlResult.Success -> { /* Call active */ }
is CallControlResult.Error -> { /* Handle error */ }
}
Halten eines Anrufs
So halten Sie einen Anruf mit setInactive()
auf:
when (val result = setInactive()) {
is CallControlResult.Success -> { /* Call on hold */ }
is CallControlResult.Error -> { /* Handle error */ }
}
Anruf beenden
So trennen Sie einen Anruf mit disconnect()
und DisconnectCause
:
disconnect(DisconnectCause(DisconnectCause.LOCAL))
Audioendpunkte für Anrufe verwalten
Audioendpunkte mithilfe von currentCallEndpoint
-, availableEndpoints
- und isMuted
-Flow
s im CallControlScope
beobachten und verwalten
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
(Android 13 API-Level 33 und niedriger) oder foregroundtypes (Android 14 API-Level 34 und höher) für die Unterstützung im Vordergrund.
Gemäß den Anforderungen für den Vordergrund muss die Anwendung eine Benachrichtigung senden, damit Nutzer wissen, dass die Anwendung im Vordergrund ausgeführt wird.
Damit Ihre App die Ausführungspriorität im Vordergrund erhält, erstellen Sie eine Benachrichtigung, sobald Sie den Aufruf über die Plattform hinzugefügt haben. Die Priorität im Vordergrund wird aufgehoben, wenn Ihre App den Anruf beendet oder Ihre Benachrichtigung nicht mehr gültig ist.
Weitere Informationen zu Diensten im Vordergrund
Remote-Support für Surface
Auf Remote-Geräten (Smartwatches, Bluetooth-Headsets, Android Auto) können Anrufe ohne direkte Interaktion mit dem Smartphone verwaltet werden. Ihre App muss Rückruf-Lambdas (onAnswerCall
, onSetCallDisconnected
, onSetCallActive
, onSetCallInactive
) implementieren, die an CallsManager.addCall
übergeben werden, um von diesen Geräten initiierte Aktionen zu verarbeiten.
Wenn eine Remote-Aktion auftritt, wird das entsprechende Lambda aufgerufen.
Wenn der Lambda-Befehl erfolgreich abgeschlossen wurde, wird 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 gründlich mit verschiedenen Remote-Oberflächen.
Anruferweiterungen
Die Bibliothek unterstützt nicht nur den Anrufstatus und die Audioweiterleitung, sondern auch Anruferweiterungen. Das sind optionale Funktionen, die Ihre App implementieren kann, um die Anrufqualität auf Remote-Oberflächen wie Android Auto zu verbessern. Dazu gehören Konferenzräume, die Stummschaltung 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 auch die Anzeige dieser Erweiterungen in ihrer Benutzeroberfläche unterstützen. Das bedeutet, dass diese Funktionen auch auf Remote-Geräten verfügbar sind und Nutzer damit interagieren können.
Anruf mit Erweiterungen erstellen
Wenn Sie einen Anruf erstellen, können Sie anstelle von CallManager#addCall
die Funktion CallManager#addCallWithExtensions verwenden. Dadurch erhält die App Zugriff auf einen anderen Bereich namens ExtensionInitializationScope
. Mit diesem Umfang kann die Anwendung die von ihr unterstützten optionalen Erweiterungen initialisieren. Außerdem bietet dieser Bereich eine zusätzliche Methode, onCall
, die nach dem Austausch und der Initialisierung der Erweiterungsfunktionen eine 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...
}
}
}
Supportmitarbeiter anrufen
Wenn Ihre App Anrufteilnehmer für Besprechungen oder Gruppenanrufe unterstützt, deklarieren Sie mit addParticipantExtension
die Unterstützung für diese Erweiterung 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)
}
}
Mit ParticipantExtension#updateActiveParticipant
können Sie nicht nur andere Oberflächen darüber informieren, welche Teilnehmer am Anruf teilnehmen, sondern auch den aktiven Teilnehmer aktualisieren.
Außerdem werden optionale Aktionen für die Anrufteilnehmer unterstützt.
Mit ParticipantExtension#addRaiseHandSupport
können Teilnehmer in der App während eines Anrufs ihre Hand heben und sehen, welche anderen Teilnehmer ebenfalls ihre 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)
}
}
Supportanruf stummschalten
Mit der Stummschaltung von Anrufen kann ein Nutzer die App bitten, das ausgehende Audio eines Anrufs stummzuschalten, ohne das Mikrofon des Geräts physisch stummzuschalten. Diese Funktion wird pro Anruf verwaltet. Daher kümmert sich Jetpack um die komplexe Verwaltung des globalen Stummschaltungsstatus laufender Mobilfunkanrufe, während ein VOIP-Anruf aktiv ist. Dadurch ist das Stummschalten von ausgehendem Audio bei mehreren Anrufen weniger fehleranfällig und es können hilfreiche Funktionen wie die „Sind Sie am Sprechen?“-Anzeige verwendet werden, 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 angeben, 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)
}
}