Utwórz aplikację do rozmów

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