Tworzenie domyślnej aplikacji telefonicznej

Domyślna aplikacja telefoniczna pozwala platformie Android Telecom informować Twoją aplikację o stanie wywołania. W tym celu zaimplementuj interfejs InCallService API za pomocą menedżera ról i usługi połączenia, aby utworzyć zastępczą aplikację telefoniczną na urządzeniu z Androidem. Implementacja musi spełniać te wymagania:

Nie może on mieć żadnej funkcji nawiązywania połączeń i musi składać się wyłącznie z interfejsu użytkownika. Musi obsługiwać wszystkie połączenia, o których wieża platforma telekomunikacyjna, i nie może wyciągać wniosków co do ich charakteru. Na przykład nie może zakładać, że połączenia są wykonywane na podstawie karty SIM, ani wprowadzać ograniczeń połączeń opartych na dowolnej usłudze ConnectionService, takim jak egzekwowanie ograniczeń telefonicznych w przypadku rozmów wideo.

Aplikacja do rozmów pozwala użytkownikom odbierać i nawiązywać połączenia audio i wideo na urządzeniu. Aplikacje do wykonywania połączeń korzystają z własnego interfejsu użytkownika, a nie z domyślnego interfejsu aplikacji Telefon, jak widać na tym zrzucie ekranu.

Przykład aplikacji do rozmów
Przykład aplikacji do połączeń korzystających z własnego interfejsu

Platforma Androida zawiera pakiet android.telecom, który zawiera klasy pomagające utworzyć aplikację do rozmów zgodnie z platformą telekomunikacyjną. Tworzenie aplikacji zgodnie z zasadami telekomunikacji przynosi takie korzyści:

  • Twoja aplikacja prawidłowo współpracuje z natywnym podsystemem telekomunikacyjnym na urządzeniu.
  • Twoja aplikacja prawidłowo współpracuje z innymi aplikacjami do połączeń, które również są zgodne z tą platformą.
  • Platforma pomaga aplikacji zarządzać routingiem audio i wideo.
  • Platforma pomaga aplikacji określić, czy jej wywołania są najważniejsze.

Deklaracje i uprawnienia w pliku manifestu

W manifeście aplikacji zadeklaruj, że używa ona uprawnienia MANAGE_OWN_CALLS, jak pokazano w tym przykładzie:

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

Więcej informacji na temat deklarowania uprawnień aplikacji znajdziesz w sekcji Uprawnienia.

Musisz zadeklarować usługę, która określa klasę implementującą w Twojej aplikacji klasę ConnectionService. Podsystem telekomunikacyjny wymaga, aby usługa zadeklarowała uprawnienie BIND_TELECOM_CONNECTION_SERVICE, aby mogła się z nią powiązać. Ten przykład pokazuje, jak zadeklarować usługę w manifeście aplikacji:

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

Więcej informacji o deklarowaniu komponentów aplikacji, w tym usług, znajdziesz w artykule Komponenty aplikacji.

Wdrażanie usługi połączenia

Aplikacja wywołująca musi udostępniać implementację klasy ConnectionService, z którą może powiązać podsystem telekomunikacyjny. Twoja implementacja ConnectionService powinna zastąpić te metody:

onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)

Podsystem telekomunikacyjny wywołuje tę metodę w odpowiedzi na wywołanie aplikacji placeCall(Uri, Bundle), by utworzyć nowe połączenie wychodzące. Aplikacja zwraca nowe wystąpienie klasy Connection (więcej informacji znajdziesz w artykule Wdrażanie połączenia), które jest reprezentowane przez nowe połączenie wychodzące. Połączenie wychodzące możesz dostosować, wykonując te czynności:

onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest)

Podsystem telekomunikacyjny wywołuje tę metodę, gdy aplikacja wywołuje metodę placeCall(Uri, Bundle), a nie można nawiązać połączenia wychodzącego. W takiej sytuacji aplikacja powinna poinformować użytkownika (np. za pomocą pola z alertem lub komunikatu toastu), że nie można nawiązać połączenia wychodzącego. Aplikacja może nie być w stanie nawiązać połączenia, jeśli trwa połączenie alarmowe lub jeśli w innej aplikacji trwa połączenie, którego nie można wstrzymać przed nawiązaniem połączenia.

onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)

Podsystem telekomunikacyjny wywołuje tę metodę, gdy aplikacja wywołuje metodę addNewIncomingCall(PhoneAccountHandle, Bundle), by poinformować system o nowym wywołaniu przychodzącym. Aplikacja zwraca nowe wystąpienie implementacji Connection (więcej informacji znajdziesz w sekcji Wdrażanie połączenia), która będzie reprezentować nowe wywołanie przychodzące. Możesz jeszcze bardziej dostosować połączenie przychodzące, wykonując te czynności:

onCreateIncomingConnectionFailed(PhoneAccountHandle, ConnectionRequest)

Podsystem telekomunikacyjny wywołuje tę metodę, gdy aplikacja wywołuje metodę addNewIncomingCall(PhoneAccountHandle, Bundle), aby poinformować Telecom o nowym połączeniu przychodzącym, ale takie połączenie jest niedozwolone (więcej informacji znajdziesz w artykule o ograniczeniach dotyczących połączeń). Aplikacja powinna dyskretnie odrzucać połączenie przychodzące, opcjonalnie publikując powiadomienie informujące użytkownika o nieodebranym połączeniu.

Wdrażanie połączenia

Aplikacja powinna utworzyć podklasę klasy Connection do reprezentowania wywołań w aplikacji. Zastąp te metody w swojej implementacji:

onShowIncomingCallUi()

Podsystem telekomunikacyjny wywołuje tę metodę, gdy dodajesz nowe połączenie przychodzące, a aplikacja powinna pokazywać interfejs połączeń przychodzących.

onCallAudioStateChanged(CallAudioState)

Podsystem telekomunikacyjny wywołuje tę metodę, aby poinformować aplikację o zmianie aktualnej trasy lub trybu dźwięku. Jest ono wywoływane w odpowiedzi na zmianę trybu dźwięku przez aplikację za pomocą metody setAudioRoute(int). Ta metoda może być też wywoływana, gdy system zmieni trasę dźwięku (np. po rozłączeniu zestawu słuchawkowego Bluetooth).

onHold()

Podsystem telekomunikacyjny wywołuje tę metodę, gdy chce wstrzymać połączenie. W odpowiedzi na to żądanie aplikacja powinna wstrzymać wywołanie, a następnie wywołać metodę setOnHold(), aby poinformować system o tym, że jest ono wstrzymywane. Podsystem telekomunikacyjny może wywołać tę metodę, gdy usługa w trakcie rozmowy, np. Android Auto, która pokazuje, że połączenie chce przekazać użytkownikowi prośbę o zawieszenie połączenia. Podsystem telekomunikacyjny wywołuje tę metodę również wtedy, gdy użytkownik aktywuje połączenie w innej aplikacji. Więcej informacji o usługach dostępnych w ramach rozmowy znajdziesz tutaj: InCallService.

onUnhold()

Podsystem telekomunikacyjny wywołuje tę metodę, gdy chce wznowić zawieszone połączenie. Po wznowieniu wywołania aplikacja powinna wywołać metodę setActive(), aby poinformować system, że wywołanie nie jest już wstrzymane. Podsystem telekomunikacyjny może wywołać tę metodę, gdy usługa w trakcie rozmowy, np. Android Auto, która pokazuje, że połączenie chce przekazać prośbę o jego wznowienie. Więcej informacji o usługach dostępnych w trakcie rozmowy znajdziesz tutaj: InCallService.

onAnswer()

Podsystem telekomunikacyjny wywołuje tę metodę, aby poinformować aplikację, że powinno zostać odebrane połączenie przychodzące. Gdy aplikacja odbierze wywołanie, powinna wywołać metodę setActive(), aby poinformować system, że wywołanie zostało odebrane. Podsystem telekomunikacyjny może wywołać tę metodę, gdy aplikacja doda nowe połączenie przychodzące, a w innej aplikacji trwa już połączenie, którego nie można wstrzymać. Podsystem telekomunikacyjny w tych instancjach wyświetla interfejs połączeń przychodzących w imieniu Twojej aplikacji. Platforma udostępnia metodę przeciążoną, która umożliwia określenie stanu wideo, w którym ma zostać odebrane połączenie. Więcej informacji: onAnswer(int).

onReject()

Podsystem telekomunikacyjny wywołuje tę metodę, gdy chce odrzucić połączenie przychodzące. Gdy aplikacja odrzuci wywołanie, powinna wywołać setDisconnected(DisconnectCause) i określić REJECTED jako parametr. Aplikacja powinna wywołać metodę destroy(), aby poinformować system, że aplikacja przetworzyła wywołanie. Podsystem telekomunikacyjny wywołuje tę metodę, gdy użytkownik odrzucił połączenie przychodzące z aplikacji.

onDisconnect()

Podsystem telekomunikacyjny wywołuje tę metodę, gdy chce zakończyć połączenie. Po zakończeniu wywołania aplikacja powinna wywołać metodę setDisconnected(DisconnectCause) i określić LOCAL jako parametr wskazujący, że żądanie użytkownika spowodowało rozłączenie połączenia. Aplikacja powinna następnie wywołać metodę destroy(), aby poinformować podsystem telekomunikacyjny, że aplikacja przetworzyła połączenie. System może wywołać tę metodę, gdy użytkownik rozłączy się, korzystając z innej usługi w trakcie rozmowy, na przykład Androida Auto. System wywołuje tę metodę również wtedy, gdy połączenie musi zostać rozłączone, aby można było nawiązać inne połączenie, np. gdy użytkownik chce nawiązać połączenie alarmowe. Więcej informacji o usługach dostępnych w trakcie rozmowy znajdziesz tutaj: InCallService.

Typowe scenariusze rozmów

Wykorzystanie interfejsu ConnectionService API w przepływie wywołań wymaga interakcji z innymi klasami w pakiecie android.telecom. W kolejnych sekcjach opisano typowe scenariusze wywołań i sposób, w jaki aplikacja powinna używać interfejsów API do ich obsługi.

Odbieranie połączeń przychodzących

Sposób obsługi połączeń przychodzących zmienia się niezależnie od tego, czy są realizowane połączenia w innych aplikacjach. Powodem różnic w procesach jest to, że platforma telekomunikacyjna musi wprowadzić pewne ograniczenia w przypadku aktywnych połączeń w innych aplikacjach, aby zapewnić stabilne środowisko dla wszystkich aplikacji do rozmów na urządzeniu. Więcej informacji znajdziesz w artykule Ograniczenia dotyczące połączeń.

Brak aktywnych połączeń w innych aplikacjach

Aby odbierać połączenia przychodzące, gdy w innych aplikacjach nie ma aktywnych połączeń, wykonaj te czynności:

  1. Aplikacja odbiera nowe połączenie przychodzące za pomocą zwykłych mechanizmów.
  2. Użyj metody addNewIncomingCall(PhoneAccountHandle, Bundle), aby poinformować podsystem telekomunikacyjny o nowym połączeniu przychodzącym.
  3. Podsystem telekomunikacyjny wiąże się z implementacją ConnectionService Twojej aplikacji i żąda nowej instancji klasy Connection reprezentującej nowe wywołanie przychodzące za pomocą metody onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest).
  4. Podsystem telekomunikacyjny informuje aplikację, że powinien wyświetlać interfejs połączeń przychodzących za pomocą metody onShowIncomingCallUi().
  5. Aplikacja wyświetla przychodzący interfejs za pomocą powiadomienia z powiązaną intencją pełnoekranową. Więcej informacji: onShowIncomingCallUi().
  6. Wywołaj metodę setActive(), jeśli użytkownik zaakceptuje wywołanie przychodzące, lub setDisconnected(DisconnectCause), podając jako parametr REJECTED, a następnie wywołanie metody destroy(), jeśli użytkownik odrzuci połączenie przychodzące.

Aktywne połączenia w innych aplikacjach, których nie można wstrzymać

Aby odbierać połączenia przychodzące, gdy w innych aplikacjach są aktywne połączenia, których nie można wstrzymać, wykonaj te czynności:

  1. Aplikacja odbiera nowe połączenie przychodzące za pomocą zwykłych mechanizmów.
  2. Użyj metody addNewIncomingCall(PhoneAccountHandle, Bundle), aby poinformować podsystem telekomunikacyjny o nowym połączeniu przychodzącym.
  3. Podsystem telekomunikacyjny wiąże się z implementacją ConnectionService Twojej aplikacji i żąda nowej instancji obiektu Connection reprezentującego nowe wywołanie przychodzące za pomocą metody onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest).
  4. Podsystem telekomunikacyjny wyświetla interfejs połączenia przychodzącego.
  5. Jeśli użytkownik zaakceptuje wywołanie, podsystem telekomunikacyjny wywołuje metodę onAnswer(). Wywołaj metodę setActive(), aby wskazać podsystemowi telekomunikacyjnemu, że połączenie zostało nawiązane.
  6. Jeśli użytkownik odrzuci połączenie, podsystem telekomunikacyjny wywołuje metodę onReject(). Wywołaj metodę setDisconnected(DisconnectCause), podając jako parametr REJECTED, a po nim wywołanie metody destroy().

Nawiązywanie połączeń wychodzących

Proces nawiązywania połączenia wychodzącego obejmuje radzenie sobie z możliwością nawiązania połączenia z powodu ograniczeń nałożonych przez platformę telekomunikacyjną. Więcej informacji znajdziesz w artykule Ograniczenia dotyczące połączeń.

Aby nawiązać połączenie wychodzące, wykonaj te czynności:

  1. Użytkownik inicjuje połączenie wychodzące w Twojej aplikacji.
  2. Użyj metody placeCall(Uri, Bundle), aby poinformować podsystem telekomunikacyjny o nowym połączeniu wychodzącym. Weź pod uwagę te kwestie związane z parametrami metody:
    • Parametr Uri podaje adres, pod który jest wykonywane wywołanie. W przypadku zwykłych numerów telefonu użyj schematu identyfikatora URI tel:.
    • Parametr Bundle umożliwia podawanie informacji o aplikacji wywołującej poprzez dodanie obiektu PhoneAccountHandle aplikacji do dodatku EXTRA_PHONE_ACCOUNT_HANDLE. Aplikacja musi dostarczać obiekt PhoneAccountHandle przy każdym wywołaniu wychodzącym.
    • Parametr Bundle pozwala też określić, czy połączenie wychodzące zawiera wideo przez podanie wartości STATE_BIDIRECTIONAL w dodatkowym EXTRA_START_CALL_WITH_VIDEO_STATE. Pamiętaj, że podsystem telekomunikacyjny domyślnie kieruje połączenia wideo na głośnik.
  3. Podsystem telekomunikacyjny jest powiązany z implementacją ConnectionService Twojej aplikacji.
  4. Jeśli aplikacja nie może nawiązać połączenia wychodzącego, podsystem telekomunikacyjny wywołuje metodę onCreateOutgoingConnectionFailed(PhoneAccountHandle, ConnectionRequest), aby poinformować aplikację, że nie można obecnie nawiązać połączenia. Aplikacja powinna informować użytkownika, że nie można nawiązać połączenia.
  5. Jeśli Twoja aplikacja może nawiązać połączenie wychodzące, podsystem telekomunikacyjny wywołuje metodę onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest). Aplikacja powinna zwrócić wystąpienie klasy Connection reprezentujące nowe połączenie wychodzące. Więcej informacji o właściwościach, które należy ustawić w połączeniu, znajdziesz w artykule o implementowaniu usługi połączenia.
  6. Po nawiązaniu połączenia wywołaj metodę setActive(), aby poinformować podsystem telekomunikacyjny, że połączenie jest aktywne.

Kończenie połączenia

Aby zakończyć połączenie, wykonaj te czynności:

  1. Wywołaj parametr setDisconnected(DisconnectCause), który wysyła LOCAL jako parametr, jeśli użytkownik zakończył połączenie, lub wyślij REMOTE jako parametr, jeśli druga strona zakończyła połączenie.
  2. Wywołaj metodę destroy().

Ograniczenia dotyczące połączeń

Aby zapewnić użytkownikom spójną i prostą obsługę połączeń, platforma telekomunikacyjna wymusza pewne ograniczenia dotyczące zarządzania połączeniami na urządzeniu. Załóżmy na przykład, że użytkownik zainstalował 2 aplikacje wywołujące, które implementują samodzielnie zarządzany interfejs API ConnectionService: FooTalk i BarTalk. W takim przypadku obowiązują te ograniczenia:

  • Na urządzeniach z interfejsem API na poziomie 27 lub niższym tylko jedna aplikacja może prowadzić trwające wywołanie w danym momencie. To ograniczenie oznacza, że gdy użytkownik prowadzi rozmowę za pomocą aplikacji FooTalk, aplikacja BarTalk nie może zainicjować ani odebrać nowego połączenia.

    Na urządzeniach z interfejsem API na poziomie 28 lub wyższym, jeśli zarówno FooTalk i BarTalk deklarują uprawnienia CAPABILITY_SUPPORT_HOLD, jak i CAPABILITY_HOLD, użytkownik może utrzymywać więcej niż jedno trwające wywołanie, przełączając się między aplikacjami, aby zainicjować kolejne wywołanie lub je odebrać.

  • Jeśli użytkownik wykonuje zwykłe połączenia zarządzane (np. we wbudowanej aplikacji Telefon lub Telefon), nie może uczestniczyć w połączeniach z aplikacji do wykonywania połączeń. Oznacza to, że jeśli użytkownik regularnie rozmawia przez operatora komórkowego, nie może jednocześnie uczestniczyć w rozmowach FooTalk ani BarTalk.

  • Gdy użytkownik wybierze połączenie alarmowe, podsystem telekomunikacyjny rozłączy się z aplikacją.

  • Aplikacja nie może odbierać ani nawiązywać połączeń, gdy użytkownik dzwoni w trakcie połączenia alarmowego.

  • Jeśli w aplikacji do rozmów przychodzących jest inne połączenie przychodzące, odebranie tego spowoduje zakończenie trwającego połączenia w innej aplikacji. Aplikacja nie powinna wyświetlać interfejsu użytkownika do wykonywania połączeń przychodzących. Platforma telekomunikacyjna wyświetla interfejs połączeń przychodzących i informuje użytkownika, że odebranie nowego połączenia spowoduje zakończenie trwającej rozmowy. Oznacza to, że jeśli użytkownik będzie w trakcie rozmowy w FooTalk, a aplikacja BarTalk odbiera połączenie przychodzące, platforma telekomunikacyjna informuje użytkownika o nowym połączeniu przychodzącym w usłudze BarTalk i odebranie połączenia z BarTalk zakończy jego rozmowę.

Zmiana na domyślną aplikację telefoniczną

Domyślna aplikacja telefonu/telefon to aplikacja, która wyświetla interfejs użytkownika połączenia, gdy urządzenie trwa. Dzięki temu użytkownik może też nawiązywać połączenia i wyświetlać historię połączeń na swoim urządzeniu. Urządzenie jest w pakiecie z udostępnioną przez system domyślną aplikacją telefonu/telefonem. Użytkownik może wybrać jedną aplikację, która przejmie tę rolę w aplikacji systemowej. Aplikacja, która chce pełnić tę rolę, korzysta z funkcji RoleManager, aby poprosić o przyjęcie roli RoleManager.ROLE_DIALER.

Domyślna aplikacja telefoniczna udostępnia interfejs, gdy urządzenie wykonuje połączenie, a urządzenie nie działa w trybie samochodowym (tzn. UiModeManager#getCurrentModeType() to nie Configuration.UI_MODE_TYPE_CAR).

Aby można było spełnić rolę RoleManager.ROLE_DIALER, aplikacja musi spełniać kilka wymagań:

  • Musi obsługiwać intencję Intent#ACTION_DIAL. Oznacza to, że aplikacja musi udostępniać interfejs klawiatury telefonu, aby użytkownik mógł nawiązywać połączenia wychodzące.
  • Musi w pełni wdrożyć interfejs InCallService API oraz udostępniać interfejs do wywołań przychodzących, a także interfejs trwającego wywołania.

Uwaga: jeśli podczas wiązania aplikacja, która wypełnia RoleManager.ROLE_DIALER, zwraca wartość InCallService null, platforma telekomunikacyjna automatycznie powraca do używania aplikacji telefonu wstępnie zainstalowanej na urządzeniu. System wyświetli użytkownikowi powiadomienie z informacją, że nadal dzwonił przy użyciu wstępnie zainstalowanej aplikacji telefonu. Aplikacja nigdy nie powinna zwracać powiązania null, co oznacza, że nie spełnia wymagań zasady RoleManager.ROLE_DIALER.

Uwaga: jeśli aplikacja wypełnia funkcję RoleManager.ROLE_DIALER i wprowadzi w niej zmiany w czasie działania, co sprawi, że przestanie spełniać wymagania tej roli, RoleManager automatycznie usunie aplikację z tej roli i zamknie aplikację. Jeśli na przykład za pomocą PackageManager.setComponentEnabledSetting(ComponentName, int, int) automatycznie wyłączysz funkcję InCallService deklarowaną w jej manifeście, aplikacja nie będzie już spełniać oczekiwanych wymagań RoleManager.ROLE_DIALER.

Wstępnie załadowany telefon będzie ZAWSZE używany, gdy użytkownik nawiąże połączenie alarmowe, nawet jeśli aplikacja pełni rolę RoleManager.ROLE_DIALER. Aby połączenie alarmowe działało jak najlepiej, domyślny numer telefonu ZAWSZE powinien używać TelecomManager.placeCall(Uri, Bundle) do wykonywania połączeń (w tym połączeń alarmowych). Dzięki temu platforma może sprawdzić, czy żądanie pochodzi z domyślnego telefonu. Jeśli niezainstalowana wcześniej aplikacja telefonu nawiązuje połączenie alarmowe przez Intent#ACTION_CALL, połączenie zostanie przekazane do wstępnie zainstalowanej aplikacji telefonu przez Intent#ACTION_DIAL w celu potwierdzenia. Nie jest to optymalne rozwiązanie dla użytkowników.

Poniżej znajdziesz przykład rejestracji w pliku manifestu domeny InCallService. Metadane TelecomManager#METADATA_IN_CALL_SERVICE_UI wskazują, że ta konkretna implementacja InCallService ma zastąpić wbudowany interfejs użytkownika. Metadane TelecomManager#METADATA_IN_CALL_SERVICE_RINGING wskazują, że urządzenie InCallService będzie odtwarzać dzwonek w przypadku połączeń przychodzących. Poniżej znajdziesz więcej informacji o wyświetlaniu interfejsu połączenia przychodzącego i odtwarzaniu dzwonka w aplikacji.

 <service android:name="your.package.YourInCallServiceImplementation"
          android:permission="android.permission.BIND_INCALL_SERVICE"
          android:exported="true">
      <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
      <meta-data android:name="android.telecom.IN_CALL_SERVICE_RINGING"
          android:value="true" />
      <intent-filter>
          <action android:name="android.telecom.InCallService"/>
      </intent-filter>
 </service>

Uwaga: NIE należy oznaczać tagu InCallService atrybutem android:exported="false", ponieważ może to spowodować błędy w powiązaniu z implementacją podczas wywołań.

Oprócz zaimplementowania interfejsu InCallService API musisz też zadeklarować w pliku manifestu działanie, które obsługuje intencję Intent#ACTION_DIAL. Poniższy przykład pokazuje, jak to się robi:

 <activity android:name="your.package.YourDialerActivity"
           android:label="@string/yourDialerActivityLabel">
      <intent-filter>
           <action android:name="android.intent.action.DIAL" />
           <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
      <intent-filter>
           <action android:name="android.intent.action.DIAL" />
           <category android:name="android.intent.category.DEFAULT" />
           <data android:scheme="tel" />
      </intent-filter>
 </activity>

Gdy użytkownik zainstaluje Twoją aplikację i uruchomi ją po raz pierwszy, użyj elementu RoleManager, aby zapytać go, czy chce, aby Twoja aplikacja była nową domyślną aplikacją telefonu.

Poniższy kod pokazuje, w jaki sposób aplikacja może zostać domyślną aplikacją do telefonu/dialera:

 private static final int REQUEST_ID = 1;

 public void requestRole() {
     RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
     Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER);
     startActivityForResult(intent, REQUEST_ID);
 }

 public void onActivityResult(int requestCode, int resultCode, Intent data) {
     if (requestCode == REQUEST_ID) {
         if (resultCode == android.app.Activity.RESULT_OK) {
             // Your app is now the default dialer app
         } else {
             // Your app is not the default dialer app
         }
     }
 }

Dostęp do usługi InCallService na urządzeniach do noszenia

    Jeśli Twoja aplikacja jest aplikacją towarzyszącą innej firmy i chce uzyskać dostęp do interfejsów InCallService API, może ona:

    1. Zadeklaruj uprawnienie MANAGE_ONGOING_CALLS w pliku manifestu
    2. Powiąż z fizycznym urządzeniem do noszenia za pomocą interfejsu API CompanionDeviceManager jako aplikację towarzyszącą. Więcej informacji: https://developer.android.com/guide/topics/connectivity/companion-device-pairing
    3. Wdróż tę usługę InCallService z uprawnieniem BIND_INCALL_SERVICE

Pokazywanie powiadomienia o połączeniu przychodzącym

Gdy aplikacja odbiera nowe połączenie przychodzące przez InCallService#onCallAdded(Call), jest odpowiedzialna za wyświetlanie interfejsu połączenia przychodzącego. Powinien to zrobić za pomocą interfejsów API NotificationManager, aby opublikować nowe powiadomienia o połączeniu przychodzącym.

Jeśli aplikacja deklaruje metadane TelecomManager#METADATA_IN_CALL_SERVICE_RINGING, to jest ona odpowiedzialna za odtwarzanie dzwonka dla połączeń przychodzących. Aplikacja powinna utworzyć NotificationChannel, który określa wybrany dzwonek. Na przykład:

 NotificationChannel channel = new NotificationChannel(YOUR_CHANNEL_ID, "Incoming Calls",
          NotificationManager.IMPORTANCE_MAX);
 // other channel setup stuff goes here.

 // We'll use the default system ringtone for our incoming call notification channel.  You can
 // use your own audio resource here.
 Uri ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
 channel.setSound(ringtoneUri, new AudioAttributes.Builder()
          // Setting the AudioAttributes is important as it identifies the purpose of your
          // notification sound.
          .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
          .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
      .build());

 NotificationManager mgr = getSystemService(NotificationManager.class);
 mgr.createNotificationChannel(channel);

Gdy aplikacja odbiera nowe połączenie przychodzące, tworzy identyfikator Notification dla połączenia przychodzącego i powiązuje go z kanałem powiadomień o połączeniach przychodzących. Możesz określić PendingIntent w powiadomieniu, które uruchomi pełnoekranowy interfejs połączeń przychodzących. Platforma menedżera powiadomień wyświetli Twoje powiadomienie jako powiadomienie z ostrzeżeniem, jeśli użytkownik będzie aktywnie korzystać z telefonu. Gdy użytkownik nie korzysta z telefonu, używany jest pełnoekranowy interfejs połączeń przychodzących. Na przykład:

 // Create an intent which triggers your fullscreen incoming call user interface.
 Intent intent = new Intent(Intent.ACTION_MAIN, null);
 intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
 intent.setClass(context, YourIncomingCallActivity.class);
 PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_MUTABLE_UNAUDITED);
 // Build the notification as an ongoing high priority item; this ensures it will show as
 // a heads up notification which slides down over top of the current content.
 final Notification.Builder builder = new Notification.Builder(context);
 builder.setOngoing(true);
 builder.setPriority(Notification.PRIORITY_HIGH);
 // Set notification content intent to take user to the fullscreen UI if user taps on the
 // notification body.
 builder.setContentIntent(pendingIntent);
 // Set full screen intent to trigger display of the fullscreen UI when the notification
 // manager deems it appropriate.
 builder.setFullScreenIntent(pendingIntent, true);
 // Setup notification content.
 builder.setSmallIcon( yourIconResourceId );
 builder.setContentTitle("Your notification title");
 builder.setContentText("Your notification content.");
 // Use builder.addAction(..) to add buttons to answer or reject the call.
 NotificationManager notificationManager = mContext.getSystemService(
     NotificationManager.class);
 notificationManager.notify(YOUR_CHANNEL_ID, YOUR_TAG, YOUR_ID, builder.build());
```