Core-Telecom

تُبسّط مكتبة Core-Telecom عملية دمج تطبيق الاتصال الخاص بك مع نظام Android الأساسي من خلال توفير مجموعة قوية ومتّسقة من واجهات برمجة التطبيقات.

إذا أردت استكشاف عمليات التنفيذ العملية، يمكنك العثور على نماذج التطبيقات على GitHub:

إعداد Core-Telecom

أضِف التبعية androidx.core:core-telecom إلى ملف build.gradle في تطبيقك:

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

أدرِج إذن MANAGE_OWN_CALLS في ملف AndroidManifest.xml:

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

تسجيل التطبيق

سجِّل تطبيق الاتصال الخاص بك على Android باستخدام CallsManager لبدء إضافة المكالمات إلى النظام. عند التسجيل، حدِّد إمكانات تطبيقك (على سبيل المثال، دعم الصوت والفيديو):

val callsManager = CallsManager(context)

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

callsManager.registerAppWithTelecom(capabilities)

إدارة المكالمات

استخدِم واجهات برمجة التطبيقات Core-Telecom لإنشاء دورة حياة مكالمة وإدارتها.

إنشاء مكالمة

يحدّد العنصر CallAttributesCompat خصائص مكالمة فريدة، يمكن أن تتضمّن الخصائص التالية:

  • displayName: اسم المتصل
  • address: عنوان المكالمة (على سبيل المثال، رقم الهاتف أو رابط الاجتماع)
  • direction: واردة أو صادرة
  • callType: صوتية أو فيديو
  • callCapabilities: تتيح نقل المكالمة ووضعها في حالة الانتظار

في ما يلي مثال على كيفية إنشاء مكالمة واردة:

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

إضافة مكالمة

استخدِم callsManager.addCall مع CallAttributesCompat وطلبات معاودة الاتصال لإضافة مكالمة جديدة إلى النظام وإدارة عمليات تعديل مساحة العرض عن بُعد. يسمح callControlScope ضمن كتلة addCall لتطبيقك في المقام الأول بتغيير حالة المكالمة وتلقّي تعديلات الصوت:

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

الرد على مكالمة

يمكنك الرد على مكالمة واردة ضمن CallControlScope:

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

رفض مكالمة

يمكنك رفض مكالمة باستخدام disconnect() مع DisconnectCause.REJECTED ضمن CallControlScope:

disconnect(DisconnectCause(DisconnectCause.REJECTED))

تفعيل مكالمة صادرة

يمكنك ضبط مكالمة صادرة على نشطة بعد أن يرد الطرف الآخر:

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

وضع مكالمة في حالة الانتظار

استخدِم setInactive() لوضع مكالمة في حالة الانتظار:

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

قطع المكالمة

يمكنك قطع مكالمة باستخدام disconnect() مع DisconnectCause:

disconnect(DisconnectCause(DisconnectCause.LOCAL))

إدارة نقاط نهاية الصوت للمكالمة

يمكنك مراقبة نقاط نهاية الصوت وإدارتها باستخدام currentCallEndpoint وavailableEndpoints وisMuted Flow ضمن CallControlScope

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

يمكنك تغيير جهاز الصوت النشط باستخدام requestEndpointChange():

coroutineScope.launch {
     callControlScope.requestEndpointChange(callEndpoint)
}

الدعم في المقدّمة

تستخدم المكتبة ConnectionService (المستوى 33 لواجهة برمجة التطبيقات Android 13 والإصدارات الأقدم) أو foregroundtypes (المستوى 34 لواجهة برمجة التطبيقات Android 14 والإصدارات الأحدث) للدعم في المقدّمة.

كجزء من متطلبات المقدّمة، يجب أن ينشر التطبيق إشعارًا للمستخدمين لإعلامهم بأنّ التطبيق قيد التشغيل في المقدّمة.

لضمان حصول تطبيقك على أولوية التنفيذ في المقدّمة، أنشئ إشعارًا بعد إضافة المكالمة إلى المنصة. تتم إزالة أولوية المقدّمة عندما ينهي تطبيقك المكالمة أو عندما يصبح إشعارك غير صالح.

مزيد من المعلومات عن الخدمات التي تعمل في المقدّمة.

دعم السطح عن بُعد

يمكن للأجهزة عن بُعد (الساعات الذكية وسماعات الرأس التي تعمل بالبلوتوث وAndroid Auto) إدارة المكالمات بدون تفاعل مباشر مع الهاتف. يجب أن ينفّذ تطبيقك تعبيرات لامدا لطلبات معاودة الاتصال (onAnswerCall وonSetCallDisconnected وonSetCallActive وonSetCallInactive) المقدَّمة إلى CallsManager.addCall للتعامل مع الإجراءات التي تبدأها هذه الأجهزة.

عند حدوث إجراء عن بُعد، يتم استدعاء تعبير لامدا المقابل.

يشير إكمال تعبير لامدا بنجاح إلى أنّه تمت معالجة الأمر. إذا تعذّر تنفيذ الأمر، يجب أن يطرح تعبير لامدا استثناءً.

يضمن التنفيذ السليم التحكّم السلس في المكالمات على الأجهزة المختلفة. اختبِر بدقة باستخدام أسطح مختلفة عن بُعد.

إضافات المكالمات

بالإضافة إلى إدارة حالة المكالمة ومسار الصوت لمكالماتك، تتيح المكتبة أيضًا إضافات المكالمات، وهي ميزات اختيارية يمكن لتطبيقك تنفيذها للحصول على تجربة اتصال أكثر ثراءً على مساحات العرض عن بُعد، مثل Android Auto. تشمل هذه الميزات غرف الاجتماعات وتجاهل المكالمات ورموز المكالمات الإضافية. عندما ينفّذ تطبيقك إضافة، ستتم مزامنة المعلومات التي يقدّمها التطبيق مع جميع الأجهزة المتصلة التي تتيح أيضًا عرض هذه الإضافات في واجهة المستخدم. وهذا يعني أنّ هذه الميزات ستتوفّر أيضًا على الأجهزة عن بُعد ليتفاعل معها المستخدمون.

إنشاء مكالمة باستخدام الإضافات

عند إنشاء مكالمة، بدلاً من استخدام CallManager#addCall لإنشاء المكالمة، يمكنك بدلاً من ذلك استخدام CallManager#addCallWithExtensions، ما يمنح التطبيق إمكانية الوصول إلى نطاق مختلف يُسمى ExtensionInitializationScope. يسمح هذا النطاق للتطبيق بتهيئة مجموعة الإضافات الاختيارية التي يتيحها. بالإضافة إلى ذلك، يوفّر هذا النطاق طريقة إضافية، هي onCall، التي توفّر 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...
        }
    }
}

دعم المشاركين في المكالمة

إذا كان تطبيقك يتيح المشاركين في المكالمة للاجتماعات أو المكالمات الجماعية، استخدِم addParticipantExtension للإعلان عن دعم هذه الإضافة واستخدِم واجهات برمجة التطبيقات ذات الصلة لتعديل الأسطح عن بُعد عند تغيير المشاركين.

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

بالإضافة إلى إشعار الأسطح عن بُعد بالمشاركين في المكالمة، يمكن أيضًا تعديل المشارك النشط باستخدام ParticipantExtension#updateActiveParticipant.

يتوفّر أيضًا دعم للإجراءات الاختيارية المتعلقة بالمشاركين في المكالمة. يمكن للتطبيق استخدام ParticipantExtension#addRaiseHandSupport لدعم فكرة رفع المشاركين أيديهم في المكالمة والاطّلاع على المشاركين الآخرين الذين رفعوا أيديهم أيضًا.

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

دعم تجاهل المكالمات

تتيح ميزة تجاهل المكالمات للمستخدم أن يطلب من التطبيق تجاهل الصوت الصادر من مكالمة بدون كتم صوت ميكروفون الجهاز فعليًا. تتم إدارة هذه الميزة لكل مكالمة، لذا يعالج Jetpack تعقيد إدارة حالة الكتم العامة للمكالمات الخلوية الجارية أثناء تفعيل مكالمة عبر بروتوكول نقل الصوت عبر الإنترنت. يؤدي ذلك إلى تقليل احتمالية حدوث أخطاء عند تجاهل الصوت الصادر في سيناريوهات المكالمات المتعددة، مع السماح أيضًا بميزات مفيدة مثل مؤشرات "هل تتحدث؟" عندما يتحدث المستخدم بدون أن يدرك أنّه تم تفعيل ميزة تجاهل المكالمات.

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

دعم رموز المكالمات

يسمح رمز المكالمة للتطبيق بتحديد رمز مخصّص يمثّل المكالمة ليتم عرضه على الأسطح عن بُعد أثناء المكالمة. يمكن أيضًا تعديل هذا الرمز خلال فترة المكالمة.

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

الإضافة إلى سجلّ المكالمات في النظام

يمكنك إضافة مكالمات بروتوكول نقل الصوت عبر الإنترنت التي يجريها تطبيقك إلى سجلّ المكالمات في النظام، بحيث تظهر في أداة الاتصال في النظام ويمكن للمستخدمين معاودة الاتصال من هناك. لمزيد من التفاصيل، راجِع سجلّ المكالمات الموحّد.