Omówienie platformy telekomunikacyjnej

Platforma Android Telecom (nazywana też po prostu „Telecom”) zarządza usługami audio i wideo rozmowy wideo na urządzeniach z systemem Android. Obejmuje to połączenia przy użyciu karty SIM, na przykład: połączeń korzystające z platformy telefonicznej i rozmów VoIP ConnectionService API.

Głównymi komponentami zarządzanymi przez telekomunikację są ConnectionService oraz InCallService

Implementacja w ConnectionService korzysta z technologii takich jak VoIP do innych osób. Najczęstsza implementacja ConnectionService w Telefon to ConnectionService. Umożliwia prowadzenie połączeń telefonicznych.

Implementacja InCallService zapewnia interfejs użytkownika do wywołań zarządzanych przez Telecom oraz pozwala użytkownikowi kontrolować te połączenia i wchodzić z nimi w interakcję. Najbardziej typową implementacją InCallService jest aplikacja do obsługi telefonu dołączona do urządzenia.

Telekomunikacja działa jak centrala telekomunikacyjna. Przekierowuje połączenia, które ConnectionService które implementacje są dostępne dla interfejsów wywołujących, które InCallService co zapewnia ich implementacja.

Warto wdrożyć interfejsy Telecom API z następujących powodów:

Tworzenie zastępczej aplikacji na telefon

Aby utworzyć zastępczą aplikację telefoniczną na urządzeniu z Androidem, zaimplementuj interfejs API InCallService. Implementacja musi spełniać te wymagania wymagania:

  • Nie może umożliwiać nawiązywania połączeń i musi składać się wyłącznie z użytkownika do połączeń telefonicznych.
  • Musi obsługiwać wszystkie wywołania, o których rozumie platformę telekomunikacyjną, i nie może założeniami dotyczącymi charakteru wywołań. Nie wolno na przykład zakładać, do połączeń telefonicznych opartych na karcie SIM, ani nie stosować ograniczeń dotyczących połączeń, są oparte na dowolnych ConnectionService, np. dotyczące egzekwowania zasad telefonicznych ograniczeń w rozmowach wideo.

Więcej informacji: InCallService

Zintegruj rozwiązanie do rozmów

Aby zintegrować z Androidem rozwiązanie do wykonywania połączeń, musisz mieć następujące opcje:

  • Wdróż samodzielnie zarządzany interfejs ConnectionService API: Ta opcja jest idealna dla programistów samodzielnych aplikacji do połączeń, którzy nie chcą, aby pokazywać swoje połączenia w domyślnej aplikacji telefonicznej i inne rozmowy w ich interfejsie.

    Jeśli używasz samodzielnie zarządzanego konta ConnectionService, ułatwisz swojej aplikacji: współdziałają nie tylko z natywnymi połączeniami telefonicznymi, ale także z innymi samodzielnymi aplikacjami wywołującymi ten interfejs API. Zarządzane samodzielnie ConnectionService API zarządza też kierowaniem i fokusem audio. Więcej informacji: Utwórz aplikację do rozmów

  • Wdróż zarządzany interfejs ConnectionService API: Ta opcja ułatwia opracowanie rozwiązania do wykonywania połączeń, które opiera się na istniejąca aplikacja na telefon do obsługi połączeń telefonicznych. Może to być np. wdrożenie przez firmę zewnętrzną połączeń SIP lub VoIP usług Google. Więcej informacji: getDefaultDialerPackage()

    Sam identyfikator ConnectionService umożliwia tylko łączenie połączeń. it nie ma powiązanego interfejsu.

  • Zaimplementuj interfejsy InCallService i ConnectionService API: Ta opcja jest idealna, jeśli chcesz utworzyć Rozwiązanie do wykonywania połączeń oparte na ConnectionService, kompletne z własnym użytkownikiem interfejsu, a także wyświetlać wszystkie inne wywołania Androida w tym samym interfejsie. W przypadku tej metody implementacja InCallService nie może: żadnych założeń dotyczących źródeł wyświetlanych wywołań. Dodatkowo implementacja ConnectionService musi nadal działać bez InCallService została ustawiona jako domyślna aplikacja telefoniczna.

Filtrowanie połączeń

Urządzenia z Androidem 10 (poziom interfejsu API 29) lub nowszym umożliwiają aplikacji identyfikowanie połączenia z numerów spoza książki adresowej użytkownika jako potencjalny spam połączeń. Użytkownicy mogą dyskretnie odrzucać połączenia spamowe. W celu zapewnienia większej dostęp do informacji o nieodebranych połączeniach, informacje o zablokowanych są rejestrowane w rejestrze połączeń. Korzystanie z interfejsu API Androida 10 eliminuje wymagane do uzyskania READ_CALL_LOG zgody użytkownika w celu udostępniania funkcji filtrowania połączeń i identyfikacji rozmówcy funkcji.

Używasz CallScreeningService do filtrowania połączeń. Wywołaj funkcję onScreenCall() dla wszystkich nowych połączeń przychodzących lub wychodzących, gdy numeru nie ma w z listy kontaktów użytkownika. Informacje na temat Call.Details – obiekt z informacjami o rozmowie. Mówiąc konkretnie, getCallerNumberVerificationStatus() zawiera informacje od dostawcy sieci o innym numerze. Jeśli stan weryfikacji się nie powiódł, jest to dobrą wskazówką, że połączenie zostało z nieprawidłowego numeru lub połączenia, które może być spamem.

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

Ustaw funkcję onScreenCall() do wywoływania respondToCall(). aby poinformować system, jak ma zareagować na nowe połączenie. Ta funkcja przyjmuje CallResponse za pomocą którego można przekazać systemowi zablokowanie połączenia, odrzucanie go tak, jakby zrobić to przez użytkownika, lub je wyciszyć. Możesz też ustawić pominięcie dodawania do rejestru połączeń urządzenia.

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());

Musisz zarejestrować implementację CallScreeningService w pliku manifestu z odpowiednim filtrem intencji i uprawnieniami, aby system mógł aktywować i poprawne dane.

<service
    android:name=".ScreeningService"
    android:permission="android.permission.BIND_SCREENING_SERVICE">
    <intent-filter>
        <action android:name="android.telecom.CallScreeningService" />
    </intent-filter>
</service>

Przekierowywanie połączenia

Urządzenia z Androidem 10 lub nowszym zarządzają intencjami połączeń w inny sposób niż na urządzeniach z Androidem 9 lub starszym. W Androidzie 10 i nowszych parametr ACTION_NEW_OUTGOING_CALL komunikat jest wycofany i zastąpiony przez CallRedirectionService API. CallRedirectionService udostępnia interfejsy, których możesz używać do: modyfikować połączenia wychodzące wykonywane przez platformę Android. Na przykład, jeśli firma zewnętrzna aplikacje mogą anulować połączenia i przekierowywać je przez 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();
        }
    }
}

Musisz zarejestrować tę usługę w pliku manifestu, aby system mógł ją uruchomić .

<service
    android:name=".RedirectionService"
    android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
    <intent-filter>
        <action android:name="android.telecom.CallRedirectionService"/>
    </intent-filter>
</service>

Aby można było korzystać z usługi przekierowania, aplikacja musi prosić o przyznanie roli przekierowywania połączeń z RoleManager. Zostanie wyświetlone pytanie użytkownika, jeśli chce on zezwolić aplikacji na obsługę przekierowań połączeń. Jeśli Twoja aplikacja nie ma przypisanej tej roli, usługa przekierowująca nie jest używana.

Sprawdzaj, czy Twoja aplikacja ma tę rolę, kiedy użytkownik ją uruchamia. możesz o niego poprosić. Uruchamiasz intencję utworzoną przez RoleManager, więc koniecznie zastąp onActivityResult(). do obsługi wyboru użytkownika.

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