يدير إطار عمل Android Telecom (المعروف أيضًا باسم "Talecom") مكالمات الصوت
والفيديو على الجهاز الذي يعمل بنظام التشغيل Android. ويشمل ذلك المكالمات المستنِدة إلى شريحة SIM، مثل المكالمات التي تستخدم إطار عمل الاتصالات الهاتفية، ومكالمات بروتوكول الصوت على الإنترنت التي تستخدم واجهة برمجة التطبيقات ConnectionService
.
المكوّنات الرئيسية التي تديرها شركة Telecom هي ConnectionService
وInCallService
.
في عملية تنفيذ ConnectionService
، يتم استخدام تقنيات مثل بروتوكول الصوت على الإنترنت لتوصيل المكالمات
بالأطراف الأخرى. إنّ تطبيق ConnectionService
الأكثر شيوعًا على الهاتف
هو الاتصال الهاتفي ConnectionService
. وهي تربط بين مكالمات مشغّل شبكة الجوّال.
يوفر تنفيذ InCallService
واجهة مستخدم للمكالمات التي تديرها
شركة Telecom ويسمح للمستخدم بالتحكم في هذه المكالمات والتفاعل معها. وتُعدّ عملية تنفيذ InCallService
الأكثر شيوعًا
تطبيق الهاتف المضمّن مع جهاز.
تعمل الاتصالات كلوحة تبديل. وهي توجّه الطلبات التي توفّرها عمليات تنفيذ ConnectionService
إلى واجهات المستخدم الخاصة بالاتصال التي توفّرها تطبيقات InCallService
.
قد تحتاج إلى تنفيذ واجهات برمجة تطبيقات Telecom للأسباب التالية:
- لإنشاء بديل لتطبيق هاتف النظام.
- لدمج حل اتصال في تجربة الاتصال على Android.
إنشاء تطبيق هاتف بديل
لإنشاء بديل لتطبيق الهاتف التلقائي على جهاز Android،
يمكنك تنفيذ واجهة برمجة التطبيقات InCallService
. يجب أن تستوفي عملية التنفيذ المتطلّبات التالية:
- يجب ألا تتضمن هذه الشبكة أي إمكانية اتصال، ويجب أن تتكون فقط من واجهة المستخدم للاتصال.
- يجب أن يتعامل مع جميع المكالمات التي يدركها إطار عمل الاتصالات، وألا يضع افتراضات حول طبيعة المكالمات. على سبيل المثال، يجب ألا تفترض الميزة أنّ المكالمات هي مكالمات هاتفية مستنِدة إلى شريحة SIM، ولا تفرض قيودًا على الاتصال تستند إلى
ConnectionService
محدّد، مثل فرض قيود هاتفية على مكالمات الفيديو.
ولمزيد من المعلومات، يمكنك الاطّلاع على InCallService
.
دمج حل اتصال
لدمج حل الاتصال الذي تستخدمه في Android، لديك الخيارات التالية:
تنفيذ واجهة برمجة تطبيقات ConnectionService API التي تتم إدارتها ذاتيًا: يمثل هذا الخيار مثاليًا لمطوّري تطبيقات الاتصال المستقلة التي لا تريد إظهار مكالماتهم داخل تطبيق الهاتف التلقائي أو عرض المكالمات الأخرى في واجهة المستخدم لديهم.
عند استخدام
ConnectionService
مُدار ذاتيًا، يمكنك مساعدة تطبيقك في التفاعل، ليس فقط مع الاتصال الهاتفي المحلي على الجهاز، ولكن أيضًا مع تطبيقات الاتصال الأخرى التي تستخدم واجهة برمجة التطبيقات هذه. وتدير أيضًا واجهة برمجة التطبيقاتConnectionService
المُدارة ذاتيًا توجيه الصوت والتركيز. لمعرفة التفاصيل، يُرجى الاطّلاع على إنشاء تطبيق اتصال.تنفيذ واجهة برمجة تطبيقات ConnectionService API:يسهِّل هذا الخيار تطوير حل اتصال يعتمد على تطبيق هاتف الجهاز الحالي لتوفير واجهة المستخدم للمكالمات. تشمل الأمثلة تنفيذ جهات خارجية لخدمات مكالمات SIP والاتصال عبر بروتوكول الصوت عبر الإنترنت. ولمزيد من التفاصيل، يمكنك الاطّلاع على
getDefaultDialerPackage()
.توفِّر
ConnectionService
وحدها وسائل إجراء المكالمات فقط. ليس له واجهة مستخدم مرتبطة.تنفيذ كل من واجهة برمجة التطبيقات InCallService وConnectionService API: هذا الخيار مثالي إذا أردت إنشاء حل خاص بك للاتصال مستند إلى
ConnectionService
، مع استكمال واجهة المستخدم الخاصة به، وعرض جميع طلبات Android الأخرى في واجهة المستخدم نفسها. عند استخدام هذا النهج، يجب ألا تضع دالةInCallService
أي افتراضات حول مصادر الطلبات التي تعرضها. بالإضافة إلى ذلك، يجب أن يستمر تنفيذConnectionService
بدون ضبط تطبيق الهاتف التلقائي علىInCallService
.
تصفية المكالمات
إنّ الأجهزة التي تعمل بنظام التشغيل Android 10 (المستوى 29 لواجهة برمجة التطبيقات) أو الإصدارات الأحدث تسمح لتطبيقك بتمييز المكالمات الواردة من الأرقام غير المدرَجة في دفتر عناوين المستخدم باعتبارها مكالمات محتملة غير مرغوب فيها. يمكن للمستخدمين اختيار أن يتم رفض المكالمات غير المرغوب فيها تلقائيًا. لتوفير المزيد من الشفافية للمستخدمين عند تفويت مكالمات، يتم تسجيل معلومات عن هذه المكالمات المحظورة في سجلّ المكالمات. ويلغي استخدام واجهة برمجة التطبيقات Android 10 API شرط الحصول على إذن READ_CALL_LOG
من المستخدم لإتاحة وظائف فحص المكالمات وإظهار رقم المتّصل.
يمكنك استخدام تطبيق
CallScreeningService
لفحص المكالمات. استدعِ الدالة
onScreenCall()
لأي مكالمات واردة أو صادرة جديدة عندما لا يكون الرقم مدرَجًا في
قائمة جهات اتصال المستخدم. يمكنك الاطّلاع على الكائن Call.Details
للحصول على معلومات
عن المكالمة. على وجه التحديد، تشتمل دالة
getCallerNumberVerificationStatus()
على معلومات من مزوّد الشبكة حول الرقم الآخر.
إذا تعذّر إثبات صحة رقم التأمين الاجتماعي، هذا مؤشر جيد على أنّ المكالمة واردة من رقم غير صالح أو من مكالمة محتمَلة غير مرغوب فيها.
Kotlin
class ScreeningService : CallScreeningService() { // This function is called when an ingoing or outgoing call // is from a number not in the user's contacts list override fun onScreenCall(callDetails: Call.Details) { // Can check the direction of the call val isIncoming = callDetails.callDirection == Call.Details.DIRECTION_INCOMING if (isIncoming) { // the handle (e.g. phone number) that the Call is currently connected to val handle: Uri = callDetails.handle // determine if you want to allow or reject the call when (callDetails.callerNumberVerificationStatus) { Connection.VERIFICATION_STATUS_FAILED -> { // Network verification failed, likely an invalid/spam call. } Connection.VERIFICATION_STATUS_PASSED -> { // Network verification passed, likely a valid call. } else -> { // Network could not perform verification. // This branch matches Connection.VERIFICATION_STATUS_NOT_VERIFIED. } } } } }
Java
class ScreeningService extends CallScreeningService { @Override public void onScreenCall(@NonNull Call.Details callDetails) { boolean isIncoming = callDetails.getCallDirection() == Call.Details.DIRECTION_INCOMING; if (isIncoming) { Uri handle = callDetails.getHandle(); switch (callDetails.getCallerNumberVerificationStatus()) { case Connection.VERIFICATION_STATUS_FAILED: // Network verification failed, likely an invalid/spam call. break; case Connection.VERIFICATION_STATUS_PASSED: // Network verification passed, likely a valid call. break; default: // Network could not perform verification. // This branch matches Connection.VERIFICATION_STATUS_NOT_VERIFIED } } } }
يمكنك ضبط الدالة onScreenCall()
لطلب استدعاء
respondToCall()
لإخبار النظام بكيفية الاستجابة إلى الاستدعاء الجديد. تستخدِم هذه الدالة معلَمة
CallResponse
يمكنك استخدامها لتوجيه النظام بحظر المكالمة أو رفضها كما لو
كان المستخدم قد فعل ذلك أو كتم صوتها. يمكنك أيضًا مطالبة النظام بتخطي إضافة هذه
المكالمة إلى سجل مكالمات الجهاز تمامًا.
Kotlin
// Tell the system how to respond to the incoming call // and if it should notify the user of the call. val response = CallResponse.Builder() // Sets whether the incoming call should be blocked. .setDisallowCall(false) // Sets whether the incoming call should be rejected as if the user did so manually. .setRejectCall(false) // Sets whether ringing should be silenced for the incoming call. .setSilenceCall(false) // Sets whether the incoming call should not be displayed in the call log. .setSkipCallLog(false) // Sets whether a missed call notification should not be shown for the incoming call. .setSkipNotification(false) .build() // Call this function to provide your screening response. respondToCall(callDetails, response)
Java
// Tell the system how to respond to the incoming call // and if it should notify the user of the call. CallResponse.Builder response = new CallResponse.Builder(); // Sets whether the incoming call should be blocked. response.setDisallowCall(false); // Sets whether the incoming call should be rejected as if the user did so manually. response.setRejectCall(false); // Sets whether ringing should be silenced for the incoming call. response.setSilenceCall(false); // Sets whether the incoming call should not be displayed in the call log. response.setSkipCallLog(false); // Sets whether a missed call notification should not be shown for the incoming call. response.setSkipNotification(false); // Call this function to provide your screening response. respondToCall(callDetails, response.build());
يجب تسجيل تنفيذ CallScreeningService
في ملف البيان
باستخدام فلتر الأهداف المناسب والإذن المناسب حتى يتمكن النظام من تشغيله
بشكل صحيح.
<service
android:name=".ScreeningService"
android:permission="android.permission.BIND_SCREENING_SERVICE">
<intent-filter>
<action android:name="android.telecom.CallScreeningService" />
</intent-filter>
</service>
إعادة توجيه مكالمة
تعمل الأجهزة التي تعمل بالإصدار 10 من نظام التشغيل Android أو الإصدارات الأحدث على إدارة أهداف المكالمات بشكلٍ مختلف عن
الأجهزة التي تعمل بنظام التشغيل Android 9 أو بإصدار أقدم. على نظام التشغيل Android 10 والإصدارات الأحدث، تم إيقاف البث
ACTION_NEW_OUTGOING_CALL
نهائيًا واستبداله بواجهة برمجة التطبيقات
CallRedirectionService
. توفِّر CallRedirectionService
واجهات يمكنك استخدامها لتعديل المكالمات الصادرة التي يجريها نظام Android الأساسي. على سبيل المثال، قد تلغي التطبيقات
التابعة لجهات خارجية المكالمات وتعيد توجيهها عبر بروتوكول الصوت على الإنترنت (VoIP).
Kotlin
class RedirectionService : CallRedirectionService() { override fun onPlaceCall( handle: Uri, initialPhoneAccount: PhoneAccountHandle, allowInteractiveResponse: Boolean ) { // Determine if the call should proceed, be redirected, or cancelled. val callShouldProceed = true val callShouldRedirect = false when { callShouldProceed -> { placeCallUnmodified() } callShouldRedirect -> { // Update the URI to point to a different phone number or modify the // PhoneAccountHandle and redirect. redirectCall(handle, initialPhoneAccount, true) } else -> { cancelCall() } } } }
Java
class RedirectionService extends CallRedirectionService { @Override public void onPlaceCall( @NonNull Uri handle, @NonNull PhoneAccountHandle initialPhoneAccount, boolean allowInteractiveResponse ) { // Determine if the call should proceed, be redirected, or cancelled. // Your app should implement this logic to determine the redirection. boolean callShouldProceed = true; boolean callShouldRedirect = false; if (callShouldProceed) { placeCallUnmodified(); } else if (callShouldRedirect) { // Update the URI to point to a different phone number or modify the // PhoneAccountHandle and redirect. redirectCall(handle, initialPhoneAccount, true); } else { cancelCall(); } } }
يجب تسجيل هذه الخدمة في البيان حتى يتمكن النظام من تشغيلها بشكل صحيح.
<service
android:name=".RedirectionService"
android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
<intent-filter>
<action android:name="android.telecom.CallRedirectionService"/>
</intent-filter>
</service>
لاستخدام خدمة إعادة توجيه، يجب أن يطلب تطبيقك دور إعادة توجيه المكالمات من RoleManager
. سيسأل هذا المستخدم عما إذا كان يريد السماح لتطبيقك بالتعامل مع عمليات إعادة توجيه المكالمات. فإذا لم يتم منح تطبيقك هذا الدور،
لن يتم استخدام خدمة إعادة التوجيه.
يجب التحقق مما إذا كان هذا الدور مسندًا إلى تطبيقك عند تشغيل المستخدم للتطبيق حتى تتمكن من طلبه حسب الحاجة. أنت تطلق هدفًا تم إنشاؤه من خلال RoleManager
،
لذا احرص على إلغاء دالة
onActivityResult()
للتعامل مع اختيار المستخدم.
Kotlin
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // Tell the system that you want your app to handle call redirects. This // is done by using the RoleManager to register your app to handle redirects. if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { val roleManager = getSystemService(Context.ROLE_SERVICE) as RoleManager // Check if the app needs to register call redirection role. val shouldRequestRole = roleManager.isRoleAvailable(RoleManager.ROLE_CALL_REDIRECTION) && !roleManager.isRoleHeld(RoleManager.ROLE_CALL_REDIRECTION) if (shouldRequestRole) { val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_REDIRECTION) startActivityForResult(intent, REDIRECT_ROLE_REQUEST_CODE) } } } companion object { private const val REDIRECT_ROLE_REQUEST_CODE = 1 } }
Java
class MainActivity extends AppCompatActivity { private static final int REDIRECT_ROLE_REQUEST_CODE = 0; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Tell the system that you want your app to handle call redirects. This // is done by using the RoleManager to register your app to handle redirects. if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) { RoleManager roleManager = (RoleManager) getSystemService(Context.ROLE_SERVICE); // Check if the app needs to register call redirection role. boolean shouldRequestRole = roleManager.isRoleAvailable(RoleManager.ROLE_CALL_REDIRECTION) && !roleManager.isRoleHeld(RoleManager.ROLE_CALL_REDIRECTION); if (shouldRequestRole) { Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_REDIRECTION); startActivityForResult(intent, REDIRECT_ROLE_REQUEST_CODE); } } } }