إنشاء تطبيق اتصال

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

مثال على تطبيق اتصال
مثال على تطبيق للاتصال يستخدم واجهة المستخدم الخاصة به

يتضمن إطار عمل Android حزمة android.telecom التي تحتوي على فئات تساعدك في إنشاء تطبيق اتصال وفقًا لإطار عمل الاتصالات. يوفّر إنشاء تطبيقك وفقًا لإطار عمل الاتصالات المزايا التالية:

  • يجب أن يعمل تطبيقك بشكل صحيح مع النظام الفرعي للاتصالات المحلية في الجهاز.
  • يتوافق تطبيقك بشكل صحيح مع تطبيقات الاتصال الأخرى التي تلتزم أيضًا بإطار العمل.
  • ويساعد إطار العمل تطبيقك في إدارة توجيه الصوت والفيديو.
  • ويساعد إطار العمل تطبيقك في تحديد ما إذا كان يتم التركيز على مكالماته.

بيانات البيان والأذونات

في بيان التطبيق، يجب الإقرار بأنّ تطبيقك يستخدم إذن MANAGE_OWN_CALLS، كما هو موضّح في المثال التالي:

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

لمزيد من المعلومات حول البيان بأذونات التطبيق، يُرجى الاطّلاع على الأذونات.

يجب الإفصاح عن خدمة تحدِّد الفئة التي تنفِّذ الفئة ConnectionService في تطبيقك. ويتطلب النظام الفرعي للاتصالات أن تعلن الخدمة عن إذن BIND_TELECOM_CONNECTION_SERVICE ليكون قادرًا على الربط به. يوضّح المثال التالي كيفية الإعلان عن الخدمة في بيان التطبيق:

<service android:name="com.example.MyConnectionService"
    android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE">
    <intent-filter>
        <action android:name="android.telecom.ConnectionService" />
    </intent-filter>
</service>

لمزيد من المعلومات عن الإعلان عن مكوّنات التطبيق، بما في ذلك الخدمات، يُرجى الاطّلاع على مكوّنات التطبيقات.

تنفيذ خدمة الربط

يجب أن يوفر تطبيق الاتصال إمكانية تنفيذ الفئة ConnectionService التي يمكن للنظام الفرعي للاتصالات الالتزام بها. يجب أن تلغي عملية تنفيذ ConnectionService الطرق التالية:

onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)

يستدعي النظام الفرعي للاتصالات هذه الطريقة استجابةً لاستدعاء تطبيقك placeCall(Uri, Bundle) لإنشاء مكالمة صادرة جديدة. يعرض تطبيقك مثيلاً جديدًا من عملية تنفيذ فئة Connection (لمزيد من المعلومات، يُرجى مراجعة تنفيذ عملية الربط) لتمثيل المكالمة الصادرة الجديدة. يمكنك تخصيص الاتصال الصادر بشكل أكبر عن طريق تنفيذ الإجراءات التالية:

onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest)

يستدعي النظام الفرعي للاتصالات هذه الطريقة عندما يستدعي تطبيقك طريقة placeCall(Uri, Bundle) ولا يمكن إجراء مكالمة صادرة. استجابةً لهذا الموقف، يجب أن يخبر تطبيقك المستخدم (على سبيل المثال، استخدام مربع تنبيه أو إشعار نخب) بتعذُّر إجراء المكالمة الصادرة. قد لا يتمكّن تطبيقك من إجراء مكالمة إذا كانت هناك مكالمة طارئة جارية أو إذا كانت هناك مكالمة جارية في تطبيق آخر لا يمكن تعليقها قبل إجراء مكالمتك.

onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)

يستدعي النظام الفرعي للاتصالات هذه الطريقة عندما يستدعي تطبيقك طريقة addNewIncomingCall(PhoneAccountHandle, Bundle) لإبلاغ النظام بمكالمة واردة جديدة في تطبيقك. يعرض تطبيقك مثيلاً جديدًا من تنفيذ Connection (لمزيد من المعلومات، راجِع تنفيذ الاتصال) لتمثيل المكالمة الواردة الجديدة. يمكنك تخصيص الاتصال الوارد بشكل أكبر عن طريق تنفيذ الإجراءات التالية:

onCreateIncomingConnectionFailed(PhoneAccountHandle, ConnectionRequest)

يستدعي النظام الفرعي للاتصالات هذه الطريقة عندما يتصل تطبيقك بطريقة addNewIncomingCall(PhoneAccountHandle, Bundle) لإبلاغ شركة Telecom بمكالمة واردة جديدة، ولكن لا يُسمح بالمكالمة الواردة (لمعرفة مزيد من المعلومات، يُرجى الاطّلاع على قيود الاتصال). من المفترض أن يرفض تطبيقك المكالمة الواردة بدون تنبيه صوتي، وأن يتضمّن إشعارًا اختياريًا لإعلام المستخدم بالمكالمة الفائتة.

تنفيذ عملية الربط

يجب أن يُنشئ تطبيقك فئة فرعية من Connection لتمثيل الطلبات في تطبيقك. ويجب إلغاء الطرق التالية في عملية التنفيذ:

onShowIncomingCallUi()

يستدعي النظام الفرعي للاتصالات هذه الطريقة عند إضافة مكالمة واردة جديدة ويجب أن يعرض تطبيقك واجهة المستخدم للمكالمات الواردة.

onCallAudioStateChanged(CallAudioState)

يستدعي النظام الفرعي للاتصالات هذه الطريقة لإبلاغ تطبيقك بتغيير المسار أو الوضع الصوتي الحالي. ويتم استدعاء هذه العملية استجابة لتغيير تطبيقك لوضع الصوت باستخدام الطريقة setAudioRoute(int). قد يُطلق على هذه الطريقة أيضًا اسم إذا غيّر النظام مسار الصوت (على سبيل المثال، عند فصل سماعة رأس بلوتوث).

onHold()

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

onUnhold()

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

onAnswer()

يستدعي النظام الفرعي للاتصالات هذه الطريقة لإبلاغ تطبيقك بضرورة الرد على المكالمة الواردة. بعد أن يردّ التطبيق على المكالمة، يجب أن يستدعي طريقة setActive() لإبلاغ النظام بأنّه قد تم الرد على المكالمة. قد يتّصل النظام الفرعي للاتصالات بهذه الطريقة عندما يضيف تطبيقك مكالمة واردة جديدة، وتكون هناك مكالمة جارية في تطبيق آخر لا يمكن تعليقها. يعرض النظام الفرعي للاتصالات واجهة المستخدم للمكالمات الواردة نيابةً عن تطبيقك في هذه الحالات. يوفر إطار العمل طريقة تحميل زائد توفر الدعم لتحديد حالة الفيديو التي يتم الرد على المكالمة بها. لمزيد من المعلومات، يُرجى الاطّلاع على "onAnswer(int)".

onReject()

يستدعي النظام الفرعي للاتصالات هذه الطريقة عندما يريد رفض مكالمة واردة. بعد أن يرفض تطبيقك الاستدعاء، يجب أن يستدعي setDisconnected(DisconnectCause) ويحدِّد REJECTED باعتباره المعلَمة. من المفترض أن يستدعي تطبيقك طريقة destroy() لإبلاغ النظام أنّ التطبيق قد عالج المكالمة. يستدعي النظام الفرعي للاتصالات هذه الطريقة عندما يرفض المستخدم مكالمة واردة من تطبيقك.

onDisconnect()

يستدعي النظام الفرعي للاتصالات هذه الطريقة عندما يريد قطع مكالمة. بعد انتهاء المكالمة، يجب أن يستدعي تطبيقك الطريقة setDisconnected(DisconnectCause) وأن يحدِّد LOCAL كمَعلمة للإشارة إلى أنّ طلب المستخدم قد تسبّب في انقطاع الاتصال. من المفترض أن يستدعي تطبيقك طريقة destroy() لإبلاغ النظام الفرعي للاتصالات بأنّ التطبيق قد عالج المكالمة. قد يستدعي النظام هذه الطريقة عندما ينقطع المستخدم مكالمة من خلال خدمة أخرى أثناء المكالمة، مثل Android Auto. يستدعي النظام أيضًا هذه الطريقة عندما يجب قطع اتصالك للسماح بإجراء مكالمة أخرى، على سبيل المثال، إذا أراد المستخدم إجراء مكالمة طوارئ. لمزيد من المعلومات عن الخدمات أثناء المكالمة، يُرجى الاطّلاع على InCallService.

التعامل مع السيناريوهات الشائعة للاتصال

إنّ الاستفادة من واجهة برمجة التطبيقات ConnectionService API في مسار الاستدعاءات ينطوي على التفاعل مع الفئات الأخرى في حزمة android.telecom. تصف الأقسام التالية سيناريوهات الاتصال الشائعة وكيف يجب أن يستخدم تطبيقك واجهات برمجة التطبيقات للتعامل معها.

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

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

ما مِن مكالمات نشطة في التطبيقات الأخرى

للردّ على المكالمات الواردة في حال عدم توفّر مكالمات نشطة في التطبيقات الأخرى، يُرجى اتّباع الخطوات التالية:

  1. يتلقّى تطبيقك مكالمة واردة جديدة باستخدام الآليات المعتادة.
  2. استخدِم طريقة addNewIncomingCall(PhoneAccountHandle, Bundle) لإعلام النظام الفرعي للاتصالات بالمكالمة الواردة الجديدة.
  3. يرتبط النظام الفرعي للاتصالات بتطبيق ConnectionService لتطبيقك ويطلب مثيلاً جديدًا من الفئة Connection يمثل المكالمة الواردة الجديدة باستخدام طريقة onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest).
  4. يُبلغ النظام الفرعي للاتصالات تطبيقك بأنه يجب أن يعرض واجهة مستخدم المكالمات الواردة باستخدام طريقة onShowIncomingCallUi().
  5. يعرض تطبيقك واجهة المستخدم الواردة باستخدام إشعار مرتبط بملء الشاشة. لمزيد من المعلومات، يُرجى الاطّلاع على "onShowIncomingCallUi()".
  6. يمكنك استدعاء الإجراء setActive() إذا قبل المستخدم المكالمة الواردة، أو setDisconnected(DisconnectCause) مع تحديد REJECTED كمَعلمة متبوعة باستدعاء الطريقة destroy() إذا رفض المستخدم المكالمة الواردة.

المكالمات النشطة في التطبيقات الأخرى والتي لا يمكن تعليقها

للرد على المكالمات الواردة عند وجود مكالمات نشطة في التطبيقات الأخرى والتي لا يمكن تعليقها، اتبع الخطوات التالية:

  1. يتلقّى تطبيقك مكالمة واردة جديدة باستخدام الآليات المعتادة.
  2. استخدِم طريقة addNewIncomingCall(PhoneAccountHandle, Bundle) لإعلام النظام الفرعي للاتصالات بالمكالمة الواردة الجديدة.
  3. يرتبط النظام الفرعي للاتصالات بتطبيق ConnectionService في تطبيقك ويطلب مثيلاً جديدًا للكائن Connection الذي يمثّل المكالمة الواردة الجديدة باستخدام طريقة onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest).
  4. يعرض النظام الفرعي للاتصالات واجهة المستخدم للمكالمات الواردة.
  5. إذا قَبِل المستخدم المكالمة، يستدعي النظام الفرعي للاتصالات طريقة onAnswer(). يجب استدعاء الإجراء setActive() للإشارة إلى النظام الفرعي للاتصالات أنّ المكالمة متصلة الآن.
  6. إذا رفض المستخدم المكالمة، يستدعي النظام الفرعي للاتصالات طريقة onReject(). يجب استدعاء الإجراء setDisconnected(DisconnectCause) مع تحديد REJECTED كمَعلمة متبوعة باستدعاء الطريقة destroy().

إجراء مكالمات صادرة

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

لإجراء مكالمة صادرة، اتّبِع الخطوات التالية:

  1. يبدأ المستخدم مكالمة صادرة داخل تطبيقك.
  2. استخدِم طريقة placeCall(Uri, Bundle) لإبلاغ النظام الفرعي للاتصالات بالمكالمة الصادرة الجديدة. يُرجى مراعاة الاعتبارات التالية لمَعلمات الطريقة:
    • تمثل المعلمة Uri العنوان الذي يجري إجراء الاستدعاء عليه. بالنسبة إلى أرقام الهواتف العادية، استخدِم نظام معرِّف الموارد المنتظم (URI) tel:.
    • تسمح لك المعلَمة Bundle بتقديم معلومات عن تطبيق الاتصال من خلال إضافة الكائن PhoneAccountHandle في تطبيقك إلى العنصر الإضافي EXTRA_PHONE_ACCOUNT_HANDLE. يجب أن يوفّر تطبيقك الكائن PhoneAccountHandle لكل مكالمة صادرة.
    • تسمح لك المَعلمة Bundle أيضًا بتحديد ما إذا كانت المكالمة الصادرة تتضمّن فيديو من خلال تحديد القيمة STATE_BIDIRECTIONAL في علامة EXTRA_START_CALL_WITH_VIDEO_STATE الإضافية. ضع في اعتبارك ذلك افتراضيًا، أن النظام الفرعي للاتصالات يوجِّه مكالمات الفيديو إلى مكبر الصوت.
  3. يرتبط النظام الفرعي للاتصالات بتطبيق ConnectionService في تطبيقك.
  4. إذا لم يتمكّن تطبيقك من إجراء مكالمة صادرة، يستدعي النظام الفرعي للاتصالات طريقة onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest) لإبلاغ تطبيقك بأنّه لا يمكن إجراء المكالمة في الوقت الحالي. يجب أن يخبر تطبيقك المستخدم بأنه لا يمكن إجراء المكالمة.
  5. إذا كان تطبيقك قادرًا على إجراء المكالمة الصادرة، يستدعي النظام الفرعي للاتصالات طريقة onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest). يجب أن يعرض تطبيقك مثيلاً من فئة Connection لتمثيل المكالمة الصادرة الجديدة. لمزيد من المعلومات حول الخصائص التي يجب ضبطها في الاتصال، يمكنك الاطّلاع على تنفيذ خدمة الربط.
  6. عند إجراء المكالمة الصادرة، يمكنك استدعاء الطريقة setActive() لإبلاغ النظام الفرعي للاتصالات بأنّ المكالمة نشطة.

إنهاء مكالمة

لإنهاء مكالمة، اتّبِع الخطوات التالية:

  1. يمكنك استدعاء setDisconnected(DisconnectCause) التي ترسل LOCAL كمَعلمة إذا أنهى المستخدم المكالمة، أو إرسال REMOTE كمَعلمة إذا أنهى الطرف الآخر المكالمة.
  2. عليك استدعاء الإجراء destroy().

قيود الاتصال

لضمان تجربة اتصال متسقة وبسيطة للمستخدمين، يفرض إطار عمل الاتصالات بعض القيود على إدارة المكالمات على الجهاز. على سبيل المثال، قد يكون المستخدم قد ثبَّت تطبيقَين للاتصال يستخدمان واجهة برمجة تطبيقات ConnectionService المُدارة ذاتيًا، وهما FooTalk وBarTalk. في هذه الحالة، تنطبق القيود التالية:

  • بالنسبة إلى الأجهزة التي تعمل بالمستوى 27 من واجهة برمجة التطبيقات أو الإصدارات الأدنى، يمكن لتطبيق واحد فقط مواصلة الطلب في أي وقت محدّد. يعني هذا القيد أنه بينما يجري المستخدم مكالمة جارية باستخدام تطبيق FooTalk، لا يمكن لتطبيق BarTalk بدء أو تلقي مكالمة جديدة.

    في الأجهزة التي تعمل بالمستوى 28 من واجهة برمجة التطبيقات أو مستوى أعلى، إذا أعلن كل من FooTalk وBarTalk عن أذونات CAPABILITY_SUPPORT_HOLD وCAPABILITY_HOLD، يمكن للمستخدم الاحتفاظ بأكثر من مكالمة جارية واحدة من خلال التبديل بين التطبيقَين لبدء مكالمة أخرى أو الرد عليها.

  • إذا كان المستخدم مشاركًا في مكالمات مُدارة عادية (على سبيل المثال، باستخدام تطبيق الهاتف أو برنامج الاتصال المدمج)، لا يمكن للمستخدم المشاركة في المكالمات التي تنشأ من تطبيقات الاتصال. وهذا يعني أنه إذا كان المستخدم في مكالمة عادية باستخدام مشغّل شبكة الجوّال، لا يمكنه أيضًا أن يشارك في مكالمة FooTalk أو BarTalk بشكلٍ متزامن.

  • ينهي النظام الفرعي للاتصالات مكالمات تطبيقك إذا اتصل المستخدم بمكالمة طوارئ.

  • لا يمكن لتطبيقك تلقّي مكالمات أو إجراؤها أثناء إجراء المستخدم لمكالمة طوارئ.

  • إذا كانت هناك مكالمة جارية في تطبيق آخر للاتصال عند تلقّي مكالمة واردة، سيؤدي الرد على المكالمات الواردة إلى إنهاء أي مكالمات جارية في التطبيق الآخر. ويجب ألا يعرض التطبيق واجهة المستخدم المعتادة للمكالمات الواردة. يعرض إطار عمل الاتصالات واجهة مستخدم المكالمات الواردة ويُعلِم المستخدم بأنّ الرد على المكالمة الجديدة سيؤدي إلى إنهاء مكالماته الجارية. ويعني هذا أنّه إذا كان المستخدم في مكالمة FooTalk وتلقّى تطبيق BarTalk مكالمة واردة، يُعلم إطار عمل الاتصالات المستخدم بأنّ لديه مكالمة BarTalk واردة وأن الرد على مكالمة BarTalk سيؤدي إلى إنهاء مكالمةFooTalk.