نظرة عامة على إطار عمل الاتصالات

يدير إطار عمل Android Telecom (المعروف أيضًا باسم "Telecom") الصوت إجراء مكالمات فيديو على جهاز يعمل بنظام التشغيل Android. ويتضمن ذلك المكالمات المستنِدة إلى شريحة SIM، مثل مكالمتان التي تستخدم إطار عمل الاتصال الهاتفي، ومكالمات VoIP التي تنفذ ConnectionService API.

تشمل المكونات الرئيسية التي تديرها الاتصالات ConnectionService InCallService

تستخدم آلية ConnectionService تقنيات مثل بروتوكول الصوت على الإنترنت (VoIP) للربط. أو مكالماتهم بأطراف أخرى. عملية تنفيذ ConnectionService الأكثر شيوعًا على الهاتف هو رقم الاتصال الهاتفي ConnectionService. فهو يربط مكالمات مشغّل شبكة الجوّال.

توفّر عملية تنفيذ InCallService واجهة مستخدم للمكالمات المُدارة من خلال الاتصالات والسماح للمستخدم بالتحكم في هذه المكالمات والتفاعل معها. الأكثر والتنفيذ الشائع لـ InCallService هو تطبيق الهاتف المرفق مع أحد الأجهزة.

تعمل الاتصالات كلوحة تبديل. يوجِّه هذا التطبيق المكالمات التي يتم إجراؤها باستخدام "ConnectionService" من التطبيقات التي توفر واجهات المستخدم للاتصال والتي InCallService من التنفيذات التي تقدمها.

قد تحتاج إلى تنفيذ واجهات برمجة التطبيقات Telecom للأسباب التالية:

إنشاء تطبيق هاتف بديل

لإنشاء بديل لتطبيق الهاتف التلقائي على جهاز Android، يُرجى اتّباع الخطوات التالية: تنفيذ واجهة برمجة تطبيقات InCallService. يجب أن تستوفي عملية التنفيذ ما يلي: المتطلبات:

  • ويجب ألا تتضمّن أي إمكانية اتصال، ويجب أن تتكون من بيانات المستخدم فقط واجهة الاتصال.
  • ويجب أن يتعامل مع جميع الاتصالات التي يعلمها إطار عمل الاتصالات، ولا افتراضات حول طبيعة المكالمات. على سبيل المثال، يجب ألا يفترض المكالمات الهاتفية التي تستند إلى شريحة SIM، ولا يتم تطبيق قيود على الاتصال تستند إلى أي ConnectionService، مثل تنفيذ الاتصال الهاتفي القيود المفروضة على مكالمات الفيديو.

لمزيد من المعلومات، يُرجى مراجعة InCallService

دمج حلّ للاتصال

لدمج حل الاتصال الذي تستخدمه في Android، يجب أن يكون لديك الخيارات التالية:

  • تنفيذ واجهة برمجة تطبيقات ConnectionService API المُدارة ذاتيًا: يُعد هذا الخيار مثاليًا لمطوِّري تطبيقات الاتصال المستقلة التي لا تريد لعرض مكالماتهم داخل تطبيق الهاتف التلقائي، أو عرض مكالمات أخرى في واجهة المستخدم لديهم.

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

  • تنفيذ واجهة برمجة تطبيقات ConnectionService API المُدارة: ويُسهِّل هذا الخيار تطوير حل للاتصال يعتمد على تطبيق هاتف حالي للأجهزة لتقديم واجهة مستخدم لإجراء المكالمات. تشمل الأمثلة استخدام تطبيق تابع لجهة خارجية لمكالمات SIP ومكالمات VoIP لمزيد من التفاصيل، يُرجى مراجعة 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>

إعادة توجيه مكالمة

إنّ الأجهزة التي تعمل بنظام التشغيل Android 10 أو الإصدارات الأحدث تُدير نوايا المكالمة على نحو مختلف عن أجهزة تعمل بالإصدار 9 من نظام التشغيل Android أو الإصدارات الأقدم في نظام التشغيل 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);
            }
        }
    }
}