Core-Telecom

Core-Telecom kitaplığı, sağlam ve tutarlı bir API grubu sağlayarak arama uygulamanızı Android platformuyla entegre etme sürecini kolaylaştırır.

Pratik uygulamaları incelemek isterseniz GitHub'da örnek uygulamalar bulabilirsiniz:

Core-Telecom'u kurma

Uygulamanızın build.gradle dosyasına androidx.core:core-telecom bağımlılığını ekleyin:

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

MANAGE_OWN_CALLS iznini AndroidManifest.xml dosyanızda tanımlayın:

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

Uygulamanızı kaydettirme

Sisteme görüşme eklemeye başlamak için CallsManager kullanarak görüşme uygulamanızı Android'e kaydedin. Kaydolurken uygulamanızın özelliklerini (ör. ses, video desteği) belirtin:

val callsManager = CallsManager(context)

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

callsManager.registerAppWithTelecom(capabilities)

Çağrı Yönetimi

Arama yaşam döngüsü oluşturmak ve yönetmek için Core-Telecom API'lerini kullanın.

Arama oluşturma

CallAttributesCompat nesnesi, aşağıdaki özelliklere sahip olabilen benzersiz bir görüşmenin özelliklerini tanımlar:

  • displayName: arayanın adı.
  • address: Arama adresi (örneğin, telefon numarası, toplantı bağlantısı).
  • direction: Gelen veya giden.
  • callType: Ses veya video.
  • callCapabilities: Aktarma ve bekletme işlemlerini destekler.

Aşağıda, gelen arama oluşturma örneği verilmiştir:

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
    )
}

Görüşme ekleme

Sisteme yeni bir arama eklemek ve uzaktan yüzey güncellemelerini yönetmek için callsManager.addCall ile CallAttributesCompat ve geri çağırmaları kullanın. callControlScope addCall bloğundaki, öncelikle uygulamanızın arama durumunu değiştirmesine ve ses güncellemeleri almasına olanak tanır:

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.
}

Çağrı yanıtlama

CallControlScope içinde gelen aramayı yanıtlama:

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

Aramayı reddetme

CallControlScope içinde disconnect() ile DisconnectCause.REJECTED kullanarak aramayı reddetme:

disconnect(DisconnectCause(DisconnectCause.REJECTED))

Giden aramayı etkinleştirme

Uzaktaki taraf yanıtladığında giden aramayı etkin olarak ayarlama:

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

Çağrıyı beklemeye alma

Aramayı bekletmek için setInactive() uygulamasını kullanma:

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

Aramanın bağlantısını kesme

DisconnectCause ile disconnect() kullanarak bir görüşmeyi sonlandırma:

disconnect(DisconnectCause(DisconnectCause.LOCAL))

Arama ses uç noktalarını yönetme

currentCallEndpoint, availableEndpoints ve isMuted Flow'lerini kullanarak CallControlScope içindeki ses uç noktalarını izleme ve yönetme

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

requestEndpointChange() simgesini kullanarak etkin ses sistemini değiştirme:

coroutineScope.launch {
     callControlScope.requestEndpointChange(callEndpoint)
}

Ön plan desteği

Kitaplık, ön plan desteği için ConnectionService (Android 13 API düzeyi 33 ve önceki sürümler) veya foregroundtypes (Android 14 API düzeyi 34 ve sonraki sürümler) kullanır.

Ön plan şartları kapsamında, uygulamanın ön planda çalıştığını kullanıcıların bilmesi için bildirim yayınlaması gerekir.

Uygulamanızın ön planda yürütme önceliği almasını sağlamak için platforma görüşme ekledikten sonra bir bildirim oluşturun. Uygulamanız aramayı sonlandırdığında veya bildiriminiz artık geçerli olmadığında ön plan önceliği kaldırılır.

Ön plan hizmetleri hakkında daha fazla bilgi edinin.

Uzaktan Surface desteği

Uzak cihazlar (akıllı saatler, Bluetooth kulaklıklar, Android Auto), doğrudan telefon etkileşimi olmadan çağrı yönetimi yapabilir. Uygulamanız, bu cihazlar tarafından başlatılan işlemleri yönetmek için CallsManager.addCall'e sağlanan geri çağırma lambda'larını (onAnswerCall, onSetCallDisconnected, onSetCallActive, onSetCallInactive) uygulamalıdır.

Uzaktan işlem gerçekleştiğinde ilgili lambda çağrılır.

Başarılı tamamlama, komutun işlendiğini gösterir. Komuta uyulamazsa lambda bir istisna oluşturmalıdır.

Doğru uygulama, farklı cihazlarda sorunsuz görüşme kontrolü sağlar. Çeşitli uzaktan yüzeylerle kapsamlı bir şekilde test edin.

Telefon uzantıları

Kitaplık, aramalarınızın arama durumunu ve ses rotasını yönetmenin yanı sıra, uygulamanızın Android Auto gibi uzak yüzeylerde daha zengin bir arama deneyimi için uygulayabileceği isteğe bağlı özellikler olan arama uzantılarını da destekler. Bu özellikler arasında toplantı odaları, görüşme sırasında sesi kapatma ve ek görüşme simgeleri yer alır. Uygulamanız bir uzantı uyguladığında, uygulamanın sağladığı bilgiler, bu uzantıların kullanıcı arayüzünde gösterilmesini destekleyen tüm bağlı cihazlarla senkronize edilir. Bu özellikler, kullanıcıların etkileşimde bulunması için uzak cihazlarda da kullanılabilecek.

Uzantılarla görüşme oluşturma

Arama oluştururken aramayı oluşturmak için CallManager#addCall kullanmak yerine CallManager#addCallWithExtensions kullanabilirsiniz. Bu yöntem, uygulamaya ExtensionInitializationScope adlı farklı bir kapsamda erişim sağlar. Bu kapsam, uygulamanın desteklediği isteğe bağlı uzantıların kümesini başlatmasına olanak tanır. Ayrıca bu kapsam, uzantı özelliği değişimi ve başlatma işlemi tamamlandıktan sonra uygulamaya onCall sağlayan ek bir yöntem sunar.CallControlScope

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...
        }
    }
}

Destek görüşmesi katılımcıları

Uygulamanız toplantılar veya grup görüşmeleri için görüşme katılımcılarını destekliyorsa bu uzantı için desteği bildirmek üzere addParticipantExtension öğesini kullanın ve katılımcılar değiştiğinde uzak yüzeyleri güncellemek için ilgili API'leri kullanın.

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)
        }
    }

Etkin katılımcı, uzak yüzeylere aramadaki katılımcılar hakkında bildirim göndermenin yanı sıra ParticipantExtension#updateActiveParticipant kullanılarak da güncellenebilir.

Ayrıca, görüşme katılımcılarıyla ilgili isteğe bağlı işlemler de desteklenir. Uygulama, katılımcıların görüşmede söz isteme fikrini desteklemek ve söz isteyen diğer katılımcıları görmek için ParticipantExtension#addRaiseHandSupport özelliğini kullanabilir.

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)
        }
    }

Aramaları Sessize Alma Desteği

Aramayı sessize alma, kullanıcının, cihazın mikrofonunu fiziksel olarak kapatmadan uygulamanın aramanın giden sesini sessize almasını istemesine olanak tanır. Bu özellik arama bazında yönetilir. Bu nedenle, Jetpack, VOIP araması etkin durumdayken devam eden hücresel aramaların genel sessize alma durumunu yönetmenin karmaşıklığını ele alır. Bu sayede, çoklu görüşme senaryolarında giden sesin kapatılması daha az hataya neden olur. Ayrıca, kullanıcı görüşme sessizliğinin etkinleştirildiğini fark etmeden konuşurken "Konuşuyor musunuz?" gibi faydalı özellikler de kullanılabilir.

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)
        }
    }

Destek görüşmesi simgeleri

Arama simgesi, uygulamanın arama sırasında uzak yüzeylerde gösterilecek aramayı temsil eden özel bir simge belirtmesine olanak tanır. Bu simge, arama süresince de güncellenebilir.

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)
        }
    }

Sistem arama günlüğüyle entegrasyon

Core-Telecom, uygulamanızın sistem arama kaydıyla entegre olmasına olanak tanır. Bu özellik, VoIP uygulamanız kullanılarak yapılan veya alınan aramaların sistem çevirici arama geçmişinde görünmesini sağlar. Böylece kullanıcılar, geri arama başlatmak için çeviriciyi kullanabilir.

Arama günlüğü entegrasyonunu etkinleştirme

Bu özelliği etkinleştirmek için uygulamanızın TelecomManager.ACTION_CALL_BACK amacını AndroidManifest.xml içinde işleyecek şekilde kaydolması ve geri aramayı işlemek için Activity sağlaması gerekir. Örneğin, geri çağırmayı işleyen etkinliğin VoipCallbackActivity olduğunu varsayarsak manifestiniz şu şekilde görünmelidir:

Manifest dosyasında niyet kaydı oluşturma

<activity
    android:name=".VoipCallbackActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.telecom.action.CALL_BACK" />
    </intent-filter>
</activity>

Geri arama niyetini işleme

Kullanıcı, sistem numara çeviricisinden geri arama başlattığında, kayıtlı etkinliğiniz TelecomManager.ACTION_CALL_BACK işlemiyle başlatılır. Niyet, CallsManager kullanarak aramayı ilk eklediğinizde uygulamanıza sağlanan TelecomManager.EXTRA_UUID değerini içerir.

CallControlScope yöntemi getCallId, görüşme için bu benzersiz kimliği döndürür.

Geri çağırma tetiklendiğinde aramayı yeniden oluşturup yapabilmeniz için uygulamanızda UUID ile tanımlanan aramayı başlatmak için gereken tüm bilgileri (ör. grup görüşmesi için telefon numaraları listesi) kaydetmeniz gerekir.

class VoipCallbackActivity : Activity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (intent?.action == TelecomManager.ACTION_CALL_BACK) {
            val uuidString = intent.getStringExtra(TelecomManager.EXTRA_UUID)
            if (uuidString != null) {
                val uuid = UUID.fromString(uuidString)
                
                // Retrieve your persisted call info using the UUID
                val callData = CallRepository.getCallByUuid(uuid)
                
                if (callData != null) {
                    // Place the call again using your app's logic
                    // ...
                }
            }
        }
        finish()
    }
}

Arama kaydı entegrasyonunu devre dışı bırakma

Varsayılan olarak, aramalar sistem arama kaydına kaydedilir. CallAttributesCompat oluştururken isLogged parametresini false olarak ayarlayarak bu özelliği çağrı bazında devre dışı bırakabilirsiniz:

val callAttributes = CallAttributesCompat(
    displayName = callerName,
    address = addressUri,
    direction = CallAttributesCompat.DIRECTION_OUTGOING,
    isLogExcluded = true // Opt-out of system call logging
)