Core-Telecom

کتابخانه Core-Telecom با ارائه مجموعه‌ای قوی و یکپارچه از میاناهای برنامه‌سازی کاربردی، فرایند یکپارچه‌سازی برنامه تماس با پلاتفرم Android را ساده می‌کند

اگر می‌خواهید پیاده‌سازی‌های عملی را کاوش کنید، می‌توانید برنامه‌های نمونه را در GitHub پیدا کنید:

  • برنامه نمونه سبک — نمونه‌ای حداقلی که نحوه استفاده از Core-Telecom API را نشان می‌دهد. برای درک سریع مفاهیم بنیادین ایده‌آل است.
  • برنامه نمونه جامع (توسعه‌یافته توسط تیم Core-Telecom) — برنامه‌ای با ویژگی‌های بیشتر که عملکردهای پیشرفته Telecom و روال‌های مطلوب را نمایش می‌دهد. این منبعی عالی برای درک سناریوهای یکپارچه‌سازی پیچیده است.

راه‌اندازی 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" />

ثبت برنامه

برنامه تماس خود را بااستفاده از CallsManager در Android ثبت کنید تا بتوانید تماس‌ها را به سیستم اضافه کنید. هنگام ثبت، قابلیت‌های برنامه‌تان را مشخص کنید (برای مثال، پشتیبانی از صدا، ویدیو):

val callsManager = CallsManager(context)

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

callsManager.registerAppWithTelecom(capabilities)

مدیریت تماس

از «میاناهای برنامه‌سازی کاربردی مخابرات اصلی» برای ایجاد و مدیریت چرخه عمر تماس استفاده کنید.

ایجاد تماس

شیء CallAttributesCompat ویژگی‌های تماس یکتا را تعریف می‌کند، که می‌تواند ویژگی‌های زیر را داشته باشد:

  • ‫displayName: نام تماس‌گیرنده.
  • address: نشانی تماس (برای نمونه، شماره تلفن، پیوند جلسه).
  • ‫direction: ورودی یا خروجی.
  • ‫callType: صدا یا ویدیو.
  • ‫callCapabilities: از انتقال و تعلیق پرداخت پشتیبانی می‌کند.

در اینجا نمونه‌ای از نحوه ایجاد تماس ورودی آورده شده است:

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

افزودن تماس

از 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، نقاط پایانی صوتی را مشاهده و مدیریت کنید. هنگام استفاده از Telecom، از میاناهای برنامه‌سازی کاربردی AudioManager#setCommunicationDevice یا AudioManager#startBluetoothSco برای مدیریت مسیرهای صوتی استفاده نکنید؛ انجام این کار باعث بروز مشکلات صوتی در تماس شما خواهد شد.

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

پشتیبانی پیش‌زمینه‌ای

این کتابخانه در Android 13 (میانای برنامه کاربردی سطح ۳۳) و پایین‌تر از ConnectionService، یا در Android 14 (میانای برنامه کاربردی سطح ۳۴) و بالاتر از انواع سرویس‌های پیش‌زمینه‌ای برای پشتیبانی پیش‌زمینه‌ای استفاده می‌کند.

برای اینکه تماس‌ها وقتی برنامه‌تان در پس‌زمینه است فعال بماند، CallsManager را در پیش‌زمینه‌ای Service (مثل LifecycleService) میزبانی کنید و نوع سرویس پیش‌زمینه‌ای phoneCall را در AndroidManifest.xml اعلام کنید:

<service
    android:name=".TelecomVoipService"
    android:foregroundServiceType="phoneCall" />

به‌عنوان بخشی از الزامات پیش‌زمینه، برنامه‌تان باید اعلان NotificationCompat.CallStyle ارسال کند تا کاربران بدانند که تماسی در پیش‌زمینه فعال است. برای اطمینان از اینکه برنامه‌تان اولویت اجرای پیش‌زمینه‌ای را دریافت می‌کند، پس‌از افزودن تماس با پلاتفرم، سرویس خود را بااستفاده از startForeground به پیش‌زمینه ارتقا دهید:

startForeground(
    notificationId,
    notification,
    ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL
)

درباره خدمات پیش‌زمینه‌ای بیشتر بدانید.

پشتیبانی ازراه‌دور Surface

دستگاه‌های راه دور (ساعت‌های هوشمند، هدست‌های بلوتوث، Android Auto) می‌توانند تماس‌ها را بدون تعامل مستقیم با تلفن مدیریت کنند. برنامه شما باید لامبداهای تماس برگشتی (onAnswerCall، onSetCallDisconnected، onSetCallActive، onSetCallInactive) ارائه‌شده به CallsManager.addCall را برای مدیریت کنش‌های آغازشده توسط این دستگاه‌ها پیاده‌سازی کند.

وقتی کنش ازراه‌دوری رخ می‌دهد، لامبدای مربوطه فراخوانده می‌شود.

تکمیل موفقیت‌آمیز تابع لامبدا نشان می‌دهد که فرمان پردازش شده است. اگر فرمان قابل اجرا نباشد، تابع باید استثنایی ایجاد کند.

پیاده‌سازی صحیح کنترل تماس یکپارچه در دستگاه‌های مختلف را تضمین می‌کند. با سطوح مختلف کنترل از دور به‌طور کامل آزمایش کنید.

افزونه‌های تماس

علاوه‌بر مدیریت وضعیت تماس و مسیر صوتی تماس‌ها، کتابخانه از افزونه‌های تماس نیز پشتیبانی می‌کند. افزونه‌های تماس ویژگی‌های اختیاری هستند که برنامه شما می‌تواند برای تجربه تماس غنی‌تر در سطوح راه دور، مانند Android Auto، پیاده‌سازی کند. این ویژگی‌ها شامل اتاق‌های جلسه، بی‌صدا کردن تماس، و نمادهای تماس اضافی است. وقتی برنامه‌تان افزونه‌ای را پیاده‌سازی می‌کند، اطلاعاتی که برنامه ارائه می‌دهد با همه دستگاه‌های متصل که از نمایش این افزونه‌ها در رابط کاربری‌شان پشتیبانی می‌کنند همگام‌سازی می‌شود. این یعنی این ویژگی‌ها در دستگاه‌های راه دور نیز دردسترس کاربران قرار می‌گیرد تا با آن‌ها تعامل داشته باشند.

ساختن «تماس با افزونه‌ها»

هنگام ایجاد تماس، به‌جای استفاده از CallsManager.addCall برای ایجاد تماس، می‌توانید از CallsManager.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 پیچیدگی مدیریت وضعیت بی‌صدای جهانی تماس‌های سلولی درحال انجام را درحالی‌که تماس VOIP فعال است مدیریت می‌کند. این کار باعث می‌شود خاموش کردن صدای خروجی در سناریوهای چندتماسی کمتر دچار خطا شود و درعین‌حال ویژگی‌های مفیدی مثل نشانگرهای «آیا صحبت می‌کنید» وقتی کاربر درحالی‌که متوجه نیست سکوت تماس فعال است صحبت می‌کند امکان‌پذیر شود.

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

افزودن به گزارش تماس سیستم

می‌توانید تماس‌های «پروتکل صدا ازطریق اینترنت» برنامه‌تان را به گزارش تماس سیستم اضافه کنید تا در شماره‌گیر سیستم نشان داده شوند و کاربران بتوانند از آنجا تماس بگیرند. برای جزئیات، به سابقه تماس یکپارچه مراجعه کنید.