Nowa biblioteka Android Telecom Jetpack ułatwia poinformowanie platformy, stan połączenia. Kod źródłowy i przykładową aplikację znajdziesz na stronie GitHub
Zależności i uprawnienia
Najpierw otwórz plik build.gradle modułu aplikacji i dodaj zależność Moduł androidx Telecom:
dependencies {
implementation ("androidx.core:core-telecom:1.0.0-alpha02")
}
W manifeście aplikacji zadeklaruj, że aplikacja używa MANAGE_OWN_CALLS
uprawnienie:
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
Zarejestruj aplikację
Aby powiadomić Androida o aplikacji, musisz ją zarejestrować i jej funkcje. Informuje on Androida, jakie funkcje obsługuje Twoja aplikacja, np. rozmowy wideo, połączenia strumieniowanie i zatrzymywanie połączeń. Te informacje są ważne, ponieważ Android może skonfigurować do obsługi funkcji aplikacji.
private val callsManager = CallsManager(context)
var capabilities: @CallsManager.Companion.Capability Int =
CallsManager.CAPABILITY_BASELINE or
CallsManager.CAPABILITY_SUPPORTS_CALL_STREAMING or
CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING
callsManager.registerAppWithTelecom(capabilities)
Integracja platformy
2 najczęstsze scenariusze połączeń w przypadku każdej aplikacji do wykonywania połączeń to połączenia przychodzące i połączenia wychodzące. Aby prawidłowo zarejestrować kierunek rozmowy i odpowiednio powiadamia użytkownika za pomocą powiadomień, skorzystaj z poniższych interfejsów API.
Zarejestruj rozmowę
Ten przykład pokazuje, jak zarejestrować połączenie przychodzące:
companion object {
const val APP_SCHEME = "MyCustomScheme"
const val ALL_CALL_CAPABILITIES = (CallAttributes.SUPPORTS_SET_INACTIVE
or CallAttributes.SUPPORTS_STREAM or CallAttributes.SUPPORTS_TRANSFER)
const val INCOMING_NAME = "Luke"
val INCOMING_URI: Uri = Uri.fromParts(APP_SCHEME, "", "")
// Define all possible properties for CallAttributes
val INCOMING_CALL_ATTRIBUTES =
CallAttributes(
INCOMING_NAME,
INCOMING_URI,
DIRECTION_INCOMING,
CALL_TYPE_VIDEO_CALL,
ALL_CALL_CAPABILITIES)
}
Obiekt callAttributes
może mieć te właściwości:
displayName
: imię i nazwisko rozmówcy, spotkania lub sesji.address
: adres połączenia. Uwaga: tę opcję można wydłużyć do spotkania .direction
: kierunek połączenia, na przykład przychodzące lub wychodzące.callType
: informacje związane z przesyłanymi danymi, np. wideo. i dźwięk.callCapabilities
: obiekt określający możliwości wywołania.
Obiekt callCapabilities
może mieć te właściwości:
streaming
: wskazuje, czy rozmowa obsługuje strumieniowanie dźwięku na inne urządzenie Urządzenie z systemem Android.transfer
: wskazuje, czy połączenie można przekazać.hold
: wskazuje, czy połączenie można zawiesić.
Dodaj połączenie
Metoda addCall()
zwraca wyjątek, jeśli urządzenie nie obsługuje tej funkcji
telekomunikacji lub jeśli podczas konfigurowania połączenia wystąpił błąd.
try {
callsManager.addCall(
INCOMING_CALL_ATTRIBUTES,
onIsCallAnswered, // Watch needs to know if it can answer the call
onIsCallDisconnected,
onIsCallActive,
onIsCallInactive
) {
callControlScope = this
}
}
Odbieranie połączenia
Po nawiązaniu połączenia przychodzącego musisz je odebrać lub odrzucić. Ten przykład pokazuje, jak odebrać połączenie:
when (answer(CallAttributesCompat.CALL_TYPE_AUDIO_CALL)) {
is CallControlResult.Success -> {
}
is CallControlResult.Error -> {
}
}
Jeśli trwa inne połączenie, answer()
wróci
CallControlResult.Error
informujący, dlaczego nie udało się odebrać połączenia. W
w takim przypadku użytkownik musi zawiesić drugie połączenie.
Odrzucanie połączenia
Aby odrzucić połączenie, rozłącz się z firmą DisconnectCause.Rejected
.
fun onRejectCall(){
coroutineScope.launch {
callControlScope?.let {
it.disconnect(DisconnectCause(DisconnectCause.REJECTED))
}
}
}
Połączenie wychodzące
Podczas nawiązywania połączenia wychodzącego, gdy osoba zdalna odbierze połączenie, należy ustawić active to sygnał, aby poinformować platformę, że wywołanie jest w toku:
when (setActive()) {
is CallControlResult.Success -> {
onIsCallActive()
}
is CallControlResult.Error -> {
updateCurrentCall {
copy(errorCode = result.errorCode)
}
}
}
Przełączanie połączenia w stan oczekiwania
Jeśli aplikacja do rozmów obsługuje wstrzymywanie połączeń, użyj funkcji setInActive
, aby przekazać
który nie jest aktywny, a mikrofon i kamera mogą
mogą być wykorzystywane przez inne aplikacje:
when (setInActive()) {
is CallControlResult.Success -> {
}
is CallControlResult.Error -> {
updateCurrentCall {
copy(errorCode = result.errorCode)
}
}
}
Odłącz
Aby zakończyć połączenie, przekaż stosowi telekomunikacyjnemu prośbę o rozłączenie, podłączając właściwa przyczyna:
coroutineScope.launch {
callControlScope?.disconnect(DisconnectCause(DisconnectCause.LOCAL))
}
Kieruj dźwięk
Podczas połączenia użytkownicy czasami przełączają się między urządzeniami, takimi jak głośnik,
słuchawką lub urządzeniem Bluetooth. Korzystaj z dokumentów availableEndpoints
oraz
interfejsów API usługi currentCallEndpoint
, aby uzyskać listę wszystkich urządzeń dostępnych dla
użytkownika i urządzenie, które jest aktywne.
Ten przykład łączy oba procesy, tworząc obiekt UI, który pokazuje użytkownikowi listę urządzeń oraz informacje o tym, które z nich jest aktywne:
availableEndpoint = combine(callControlScope.availableEndpoints,
callControlScope.currentCallEndpoint) {
availableDevices: List<CallEndpoint>, activeDevice : CallEndpoint ->
availableDevices.map {
EndPointUI(
isActive = activeDevice.endpointName == it.endpointName, it
)
}
}
Aby zmienić aktywne urządzenie, użyj requestEndpointChange
z
CallEndpoint
, na które chcesz wprowadzić zmiany.
coroutineScope.launch {
callControlScope?.requestEndpointChange(callEndpoint)
}
Obsługa na pierwszym planie
Biblioteka Telecom obejmuje obsługę na pierwszym planie. Ta biblioteka używa
ConnectionService
na urządzeniach z Androidem 13 lub starszym. Android 14 i
wyżej używa mikrofonu i aparatu typu pierwszego planu,
i obsługują usługi na pierwszym planie. Więcej informacji o usługach na pierwszym planie
W ramach wymagań dotyczących pierwszego planu aplikacja musi opublikować powiadomienie aby użytkownicy wiedzieli, że aplikacja działa na pierwszym planie.
Aby mieć pewność, że aplikacja będzie miała priorytet wykonywania na pierwszym planie, utwórz powiadomienia po zarejestrowaniu połączenia na platformie. Priorytet na pierwszym planie zostanie usunięte, gdy aplikacja zakończy połączenie lub powiadomienie nie będzie już prawidłowe.
is TelecomCall.Registered -> {
val notification = createNotification(call)
notificationManager.notify(TELECOM_NOTIFICATION_ID, notification)
}
Obsługa powierzchni
Zegarki mają ogólną aplikację odbiornika punktu końcowego. Ta aplikacja zapewnia Użytkownik za pomocą podstawowego interfejsu do odbierania, odrzucania i rozłączania połączeń. Aplikacja obsługuje te działania dzięki wdrożeniu funkcji lambda które informują platformę, o której wykonano działanie na urządzeniu.
Każda funkcja lambda przekracza limit czasu po 5 sekundach z nieudaną transakcją, jeśli aplikacja nie odpowiada.
callsManager.addCall(
attributes,
onIsCallAnswered, // Watch/Auto need to know if they can answer the call
onIsCallDisconnected,
onIsCallActive,
onIsCallInactive
) {
//Call Scope
}
/**
* Can the call be successfully answered??
* TIP: Check the connection/call state to see if you can answer a call
* Example you may need to wait for another call to hold.
**/
val onIsCallAnswered: suspend(type: Int) -> Unit = {}
/**
* Can the call perform a disconnect
*/
val onIsCallDisconnected: suspend (cause: DisconnectCause) -> Unit = {}
/**
* Check is see if you can make the call active.
* Other calls and state might stop us from activating the call
*/
val onIsCallActive: suspend () -> Unit = {
updateCurrentCall {
}
}
/**
* Check to see if you can make the call inactivate
*/
val onIsCallInactive: suspend () -> Unit = {}