Merge "Migrated to new Person API" into pi-dev
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 80754b8..b3f8d1e 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -82,5 +82,19 @@
<string name="cant_call_due_to_ongoing_unknown_call" msgid="149091978697302211">"به دلیل تماسی در برنامه دیگر، نمیتوان تماسی برقرار کرد."</string>
<string name="notification_channel_incoming_call" msgid="3513761697082968084">"تماسهای ورودی"</string>
<string name="notification_channel_missed_call" msgid="8727062678632713146">"تماسهای بیپاسخ"</string>
+ <string name="notification_channel_call_blocking" msgid="2943358779746676070">"مسدود کردن تماس"</string>
<string name="alert_outgoing_call" msgid="982908156825958001">"اگر این تماس را برقرار کنید، تماس <xliff:g id="OTHER_APP">%1$s</xliff:g> شما قطع میشود."</string>
+ <string name="phone_settings_call_blocking_txt" msgid="3976004073043846733">"مسدود کردن تماس"</string>
+ <string name="phone_settings_number_not_in_contact_txt" msgid="3126829421867168652">"شمارههایی که در «مخاطبین» نیستند"</string>
+ <string name="phone_settings_number_not_in_contact_summary_txt" msgid="9043147855140079119">"مسدود کردن شمارههایی که در «مخاطبین» شما نیستند"</string>
+ <string name="phone_settings_private_num_txt" msgid="8623574188879134262">"خصوصی"</string>
+ <string name="phone_settings_private_num_summary_txt" msgid="7516314821207782191">"مسدود کردن تماسگیرندگانی که شمارهشان را افشا نمیکنند"</string>
+ <string name="phone_settings_payphone_txt" msgid="2493356957416981318">"تلفن عمومی"</string>
+ <string name="phone_settings_payphone_summary_txt" msgid="6126709946103814653">"مسدود کردن تماسها از تلفنهای عمومی"</string>
+ <string name="phone_settings_unknown_txt" msgid="5836407031508172721">"ناشناس"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="3457690230497753233">"مسدودن تماسهای تماسگیرندگان ناشناس"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="628536625775266096">"مسدود کردن تماس"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="6264230048947693941">"مسدود کردن تماس غیرفعال شد"</string>
+ <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="7421611725400166580">"تماس اضطراری برقرار شد"</string>
+ <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="4083285098613193052">"مسدود کردن تماس غیرفعال شده است تا پاسخدهندگان اضطراری بتوانند با شما تماس بگیرند."</string>
</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index d65e584..73cb390 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -82,5 +82,19 @@
<string name="cant_call_due_to_ongoing_unknown_call" msgid="149091978697302211">"Puhelua ei voi soittaa, koska toisessa sovelluksessa on puhelu käynnissä."</string>
<string name="notification_channel_incoming_call" msgid="3513761697082968084">"Saapuvat puhelut"</string>
<string name="notification_channel_missed_call" msgid="8727062678632713146">"Vastaamattomat puhelut"</string>
+ <string name="notification_channel_call_blocking" msgid="2943358779746676070">"Puhelujen esto"</string>
<string name="alert_outgoing_call" msgid="982908156825958001">"Tämän puhelun soittaminen päättää puhelun sovelluksessa <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
+ <string name="phone_settings_call_blocking_txt" msgid="3976004073043846733">"Puhelujen esto"</string>
+ <string name="phone_settings_number_not_in_contact_txt" msgid="3126829421867168652">"Numerot eivät ole yhteystiedoissa"</string>
+ <string name="phone_settings_number_not_in_contact_summary_txt" msgid="9043147855140079119">"Toiminto estää numerot, jotka eivät ole yhteystiedoissasi"</string>
+ <string name="phone_settings_private_num_txt" msgid="8623574188879134262">"Yksityinen"</string>
+ <string name="phone_settings_private_num_summary_txt" msgid="7516314821207782191">"Estä soittajat, jotka ovat estäneet oman numeronsa näkymisen"</string>
+ <string name="phone_settings_payphone_txt" msgid="2493356957416981318">"Yleisöpuhelin"</string>
+ <string name="phone_settings_payphone_summary_txt" msgid="6126709946103814653">"Estä yleisöpuhelimista soitetut puhelut"</string>
+ <string name="phone_settings_unknown_txt" msgid="5836407031508172721">"Tuntematon"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="3457690230497753233">"Estä tuntemattomien soittajien puhelut"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="628536625775266096">"Puhelujen esto"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="6264230048947693941">"Puhelujen esto poistettu käytöstä"</string>
+ <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="7421611725400166580">"Hätäpuhelu soitettu"</string>
+ <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="4083285098613193052">"Puhelujen esto on poistettu käytöstä, jotta pelastusviranomaiset voivat soittaa puhelimeesi."</string>
</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 6889507..1b46287 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -82,5 +82,19 @@
<string name="cant_call_due_to_ongoing_unknown_call" msgid="149091978697302211">"Poziv se ne može uspostaviti zbog poziva u drugoj aplikaciji."</string>
<string name="notification_channel_incoming_call" msgid="3513761697082968084">"Dolazni pozivi"</string>
<string name="notification_channel_missed_call" msgid="8727062678632713146">"Propušteni pozivi"</string>
+ <string name="notification_channel_call_blocking" msgid="2943358779746676070">"Blokiranje poziva"</string>
<string name="alert_outgoing_call" msgid="982908156825958001">"Upućivanjem ovog poziva prekinut ćete poziv u aplikaciji <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
+ <string name="phone_settings_call_blocking_txt" msgid="3976004073043846733">"Blokiranje poziva"</string>
+ <string name="phone_settings_number_not_in_contact_txt" msgid="3126829421867168652">"Brojevi koji nisu u kontaktima"</string>
+ <string name="phone_settings_number_not_in_contact_summary_txt" msgid="9043147855140079119">"Blokirajte brojeve koje nemate u kontaktima"</string>
+ <string name="phone_settings_private_num_txt" msgid="8623574188879134262">"Privatno"</string>
+ <string name="phone_settings_private_num_summary_txt" msgid="7516314821207782191">"Blokirajte pozivatelje koji ne žele otkriti svoj broj"</string>
+ <string name="phone_settings_payphone_txt" msgid="2493356957416981318">"Telefonska govornica"</string>
+ <string name="phone_settings_payphone_summary_txt" msgid="6126709946103814653">"Blokirajte pozive s telefonskih govornica"</string>
+ <string name="phone_settings_unknown_txt" msgid="5836407031508172721">"Nepoznato"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="3457690230497753233">"Blokirajte pozive nepoznatih pozivatelja"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="628536625775266096">"Blokiranje poziva"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="6264230048947693941">"Blokiranje poziva je onemogućeno"</string>
+ <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="7421611725400166580">"Hitni je poziv upućen"</string>
+ <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="4083285098613193052">"Blokiranje poziva onemogućeno je da bi vas mogli kontaktirati djelatnici hitnih službi."</string>
</resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 743aa5a..c41f657 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -82,5 +82,19 @@
<string name="cant_call_due_to_ongoing_unknown_call" msgid="149091978697302211">"Ekki er hægt að hringja sökum símtals í öðru forriti."</string>
<string name="notification_channel_incoming_call" msgid="3513761697082968084">"Móttekin símtöl"</string>
<string name="notification_channel_missed_call" msgid="8727062678632713146">"Ósvöruð símtöl"</string>
+ <string name="notification_channel_call_blocking" msgid="2943358779746676070">"Lokað fyrir símtöl"</string>
<string name="alert_outgoing_call" msgid="982908156825958001">"Ef þú hringir mun þessu símtali í <xliff:g id="OTHER_APP">%1$s</xliff:g> ljúka."</string>
+ <string name="phone_settings_call_blocking_txt" msgid="3976004073043846733">"Lokað fyrir símtöl"</string>
+ <string name="phone_settings_number_not_in_contact_txt" msgid="3126829421867168652">"Númer sem eru ekki í tengiliðum"</string>
+ <string name="phone_settings_number_not_in_contact_summary_txt" msgid="9043147855140079119">"Loka fyrir númer sem eru ekki á tengiliðalista"</string>
+ <string name="phone_settings_private_num_txt" msgid="8623574188879134262">"Lokað"</string>
+ <string name="phone_settings_private_num_summary_txt" msgid="7516314821207782191">"Loka á hringjendur sem birta ekki símanúmer"</string>
+ <string name="phone_settings_payphone_txt" msgid="2493356957416981318">"Almenningssími"</string>
+ <string name="phone_settings_payphone_summary_txt" msgid="6126709946103814653">"Loka fyrir símtöl úr almenningssímum"</string>
+ <string name="phone_settings_unknown_txt" msgid="5836407031508172721">"Óþekkt"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="3457690230497753233">"Loka fyrir símtöl frá óþekktum hringjendum"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="628536625775266096">"Lokað fyrir símtöl"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="6264230048947693941">"Ekki er lokað fyrir símtöl"</string>
+ <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="7421611725400166580">"Neyðarsímtal var hringt"</string>
+ <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="4083285098613193052">"Slökkt hefur verið á „Lokað fyrir símtöl“ svo neyðarþjónustuaðilar geti haft samband við þig."</string>
</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 45f125c..4891114 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -82,5 +82,19 @@
<string name="cant_call_due_to_ongoing_unknown_call" msgid="149091978697302211">"Negalima skambinti dėl skambučio kitoje programoje."</string>
<string name="notification_channel_incoming_call" msgid="3513761697082968084">"Gaunamieji skambučiai"</string>
<string name="notification_channel_missed_call" msgid="8727062678632713146">"Praleisti skambučiai"</string>
+ <string name="notification_channel_call_blocking" msgid="2943358779746676070">"Skambučių blokavimas"</string>
<string name="alert_outgoing_call" msgid="982908156825958001">"Atliekant šį skambutį bus užbaigtas „<xliff:g id="OTHER_APP">%1$s</xliff:g>“ skambutis."</string>
+ <string name="phone_settings_call_blocking_txt" msgid="3976004073043846733">"Skambučių blokavimas"</string>
+ <string name="phone_settings_number_not_in_contact_txt" msgid="3126829421867168652">"Numerių nėra Kontaktuose"</string>
+ <string name="phone_settings_number_not_in_contact_summary_txt" msgid="9043147855140079119">"Blokuoti Kontaktuose nepateiktus numerius"</string>
+ <string name="phone_settings_private_num_txt" msgid="8623574188879134262">"Privatus"</string>
+ <string name="phone_settings_private_num_summary_txt" msgid="7516314821207782191">"Blokuoti skambintojus, neatskleidžiančius savo numerių"</string>
+ <string name="phone_settings_payphone_txt" msgid="2493356957416981318">"Taksofonas"</string>
+ <string name="phone_settings_payphone_summary_txt" msgid="6126709946103814653">"Blokuoti skambučius iš taksofonų"</string>
+ <string name="phone_settings_unknown_txt" msgid="5836407031508172721">"Nežinomas"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="3457690230497753233">"Blokuoti skambučius nuo nenustatytų skambintojų"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="628536625775266096">"Skambučių blokavimas"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="6264230048947693941">"Skambučių blokavimas išjungtas"</string>
+ <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="7421611725400166580">"Atliktas skambutis pagalbos numeriu"</string>
+ <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="4083285098613193052">"Skambučių blokavimas išjungtas, kad pagalbos numeriu atsiliepusiems žmonėms būtų leidžiama su jumis susisiekti."</string>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index cd5b1cd..6e63c1e 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -82,5 +82,19 @@
<string name="cant_call_due_to_ongoing_unknown_call" msgid="149091978697302211">"Kan ikke ringe ut på grunn av en samtale i en annen app."</string>
<string name="notification_channel_incoming_call" msgid="3513761697082968084">"Innkommende anrop"</string>
<string name="notification_channel_missed_call" msgid="8727062678632713146">"Tapte anrop"</string>
+ <string name="notification_channel_call_blocking" msgid="2943358779746676070">"Anropsblokkering"</string>
<string name="alert_outgoing_call" msgid="982908156825958001">"Samtalen din i <xliff:g id="OTHER_APP">%1$s</xliff:g> avsluttes hvis du foretar dette anropet."</string>
+ <string name="phone_settings_call_blocking_txt" msgid="3976004073043846733">"Anropsblokkering"</string>
+ <string name="phone_settings_number_not_in_contact_txt" msgid="3126829421867168652">"Numre som ikke står i Kontakter"</string>
+ <string name="phone_settings_number_not_in_contact_summary_txt" msgid="9043147855140079119">"Blokkér numre som ikke står i kontaktene mine"</string>
+ <string name="phone_settings_private_num_txt" msgid="8623574188879134262">"Privat"</string>
+ <string name="phone_settings_private_num_summary_txt" msgid="7516314821207782191">"Blokkér oppringere som ikke viser telefonnummeret sitt"</string>
+ <string name="phone_settings_payphone_txt" msgid="2493356957416981318">"Telefonkiosk"</string>
+ <string name="phone_settings_payphone_summary_txt" msgid="6126709946103814653">"Blokkér anrop fra telefonkiosker"</string>
+ <string name="phone_settings_unknown_txt" msgid="5836407031508172721">"Ukjent"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="3457690230497753233">"Blokkér anrop fra oppringere som ikke er identifisert"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="628536625775266096">"Anropsblokkering"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="6264230048947693941">"Anropsblokkering er slått av"</string>
+ <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="7421611725400166580">"Nødanrop utført"</string>
+ <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="4083285098613193052">"Anropsblokkering er slått av for å gjøre det mulig for nødtjenester å kontakte deg."</string>
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 324b5fb..c23cbb7 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -82,5 +82,19 @@
<string name="cant_call_due_to_ongoing_unknown_call" msgid="149091978697302211">"Oproep kan niet worden gestart vanwege een oproep in een andere app."</string>
<string name="notification_channel_incoming_call" msgid="3513761697082968084">"Inkomende oproepen"</string>
<string name="notification_channel_missed_call" msgid="8727062678632713146">"Gemiste oproepen"</string>
+ <string name="notification_channel_call_blocking" msgid="2943358779746676070">"Oproepen blokkeren"</string>
<string name="alert_outgoing_call" msgid="982908156825958001">"Als je deze oproep start, wordt je <xliff:g id="OTHER_APP">%1$s</xliff:g>-oproep beëindigd."</string>
+ <string name="phone_settings_call_blocking_txt" msgid="3976004073043846733">"Oproepen blokkeren"</string>
+ <string name="phone_settings_number_not_in_contact_txt" msgid="3126829421867168652">"Nummers die niet op je contactenlijst staan"</string>
+ <string name="phone_settings_number_not_in_contact_summary_txt" msgid="9043147855140079119">"Blokkeer nummers die niet op je contactenlijst staan"</string>
+ <string name="phone_settings_private_num_txt" msgid="8623574188879134262">"Privé"</string>
+ <string name="phone_settings_private_num_summary_txt" msgid="7516314821207782191">"Bellers met een anoniem nummer blokkeren"</string>
+ <string name="phone_settings_payphone_txt" msgid="2493356957416981318">"Betaaltelefoon"</string>
+ <string name="phone_settings_payphone_summary_txt" msgid="6126709946103814653">"Oproepen van betaaltelefoons blokkeren"</string>
+ <string name="phone_settings_unknown_txt" msgid="5836407031508172721">"Onbekend"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="3457690230497753233">"Oproepen van onbekende bellers blokkeren"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="628536625775266096">"Oproepen blokkeren"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="6264230048947693941">"Oproepen blokkeren uitgeschakeld"</string>
+ <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="7421611725400166580">"Noodoproep geplaatst"</string>
+ <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="4083285098613193052">"Oproepen blokkeren is uitgeschakeld zodat nooddiensten je kunnen bereiken."</string>
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 597e75e..8b3e634 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -45,10 +45,10 @@
<string name="no_vm_number" msgid="4164780423805688336">"Número correio de voz ausente"</string>
<string name="no_vm_number_msg" msgid="1300729501030053828">"Não há um número correio de voz armazenado no cartão SIM."</string>
<string name="add_vm_number_str" msgid="4676479471644687453">"Adicionar número"</string>
- <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Usar o <xliff:g id="NEW_APP">%s</xliff:g> como seu aplicativo de smartphone padrão?"</string>
+ <string name="change_default_dialer_dialog_title" msgid="9101655962941740507">"Usar o <xliff:g id="NEW_APP">%s</xliff:g> como seu app de telefone padrão?"</string>
<string name="change_default_dialer_dialog_affirmative" msgid="8606546663509166276">"Definir padrão"</string>
<string name="change_default_dialer_dialog_negative" msgid="9078144617060173845">"Cancelar"</string>
- <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"O <xliff:g id="NEW_APP">%s</xliff:g> poderá ligar e controlar todos os aspectos das chamadas. Defina como aplicativo de smartphone padrão somente aqueles em que você confia."</string>
+ <string name="change_default_dialer_warning_message" msgid="1417671460801684999">"O <xliff:g id="NEW_APP">%s</xliff:g> poderá ligar e controlar todos os aspectos das chamadas. Defina como aplicativo Telefone padrão somente aqueles em que você confia."</string>
<string name="blocked_numbers" msgid="2751843139572970579">"Números bloqueados"</string>
<string name="blocked_numbers_msg" msgid="1045015186124965643">"Você não receberá chamadas nem mensagens de texto dos números bloqueados."</string>
<string name="block_number" msgid="1101252256321306179">"Adicionar um número"</string>
@@ -82,5 +82,19 @@
<string name="cant_call_due_to_ongoing_unknown_call" msgid="149091978697302211">"Não é possível ligar com uma chamada em andamento em outro aplicativo."</string>
<string name="notification_channel_incoming_call" msgid="3513761697082968084">"Chamadas recebidas"</string>
<string name="notification_channel_missed_call" msgid="8727062678632713146">"Chamadas perdidas"</string>
+ <string name="notification_channel_call_blocking" msgid="2943358779746676070">"Bloqueio de chamadas"</string>
<string name="alert_outgoing_call" msgid="982908156825958001">"Se você ligar agora, sua chamada será encerrada no <xliff:g id="OTHER_APP">%1$s</xliff:g>."</string>
+ <string name="phone_settings_call_blocking_txt" msgid="3976004073043846733">"Bloqueio de chamadas"</string>
+ <string name="phone_settings_number_not_in_contact_txt" msgid="3126829421867168652">"Números que não estão nos contatos"</string>
+ <string name="phone_settings_number_not_in_contact_summary_txt" msgid="9043147855140079119">"Bloquear os números que não estão nos seus contatos"</string>
+ <string name="phone_settings_private_num_txt" msgid="8623574188879134262">"Particular"</string>
+ <string name="phone_settings_private_num_summary_txt" msgid="7516314821207782191">"Bloquear os autores das chamadas que não divulgam o número"</string>
+ <string name="phone_settings_payphone_txt" msgid="2493356957416981318">"Orelhão"</string>
+ <string name="phone_settings_payphone_summary_txt" msgid="6126709946103814653">"Bloquear chamadas de orelhão"</string>
+ <string name="phone_settings_unknown_txt" msgid="5836407031508172721">"Desconhecido"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="3457690230497753233">"Bloquear chamadas de autores não identificados"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="628536625775266096">"Bloqueio de chamadas"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="6264230048947693941">"Bloqueio de chamadas desativado"</string>
+ <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="7421611725400166580">"A chamada de emergência foi feita"</string>
+ <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="4083285098613193052">"O bloqueio de chamadas foi desativado para permitir que a equipe de emergência entre em contato com você."</string>
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index d1a7a56..8b56d7b 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -82,5 +82,19 @@
<string name="cant_call_due_to_ongoing_unknown_call" msgid="149091978697302211">"Вы не можете отправить новый вызов, пока не завершите текущий в другом приложении"</string>
<string name="notification_channel_incoming_call" msgid="3513761697082968084">"Входящие вызовы"</string>
<string name="notification_channel_missed_call" msgid="8727062678632713146">"Пропущенные вызовы"</string>
+ <string name="notification_channel_call_blocking" msgid="2943358779746676070">"Блокировка вызовов"</string>
<string name="alert_outgoing_call" msgid="982908156825958001">"Если вы начнете этот звонок, вызов в <xliff:g id="OTHER_APP">%1$s</xliff:g> будет завершен."</string>
+ <string name="phone_settings_call_blocking_txt" msgid="3976004073043846733">"Блокировка вызовов"</string>
+ <string name="phone_settings_number_not_in_contact_txt" msgid="3126829421867168652">"Незнакомые номера"</string>
+ <string name="phone_settings_number_not_in_contact_summary_txt" msgid="9043147855140079119">"Блокировать номера, которых нет в ваших контактах"</string>
+ <string name="phone_settings_private_num_txt" msgid="8623574188879134262">"Скрытые номера"</string>
+ <string name="phone_settings_private_num_summary_txt" msgid="7516314821207782191">"Блокировать вызовы со скрытых номеров"</string>
+ <string name="phone_settings_payphone_txt" msgid="2493356957416981318">"Телефоны-автоматы"</string>
+ <string name="phone_settings_payphone_summary_txt" msgid="6126709946103814653">"Блокировать вызовы с телефонов-автоматов"</string>
+ <string name="phone_settings_unknown_txt" msgid="5836407031508172721">"Неизвестные номера"</string>
+ <string name="phone_settings_unknown_summary_txt" msgid="3457690230497753233">"Блокировать вызовы с неопределяемых номеров"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="628536625775266096">"Блокировка вызовов"</string>
+ <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="6264230048947693941">"Блокировка вызовов отключена"</string>
+ <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="7421611725400166580">"Выполнен экстренный вызов"</string>
+ <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="4083285098613193052">"Блокировка вызовов отключена, чтобы у экстренных служб была возможность позвонить вам."</string>
</resources>
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index d8f3fbc..b5e2958 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -802,6 +802,18 @@
return mState;
}
+ /**
+ * Determines if this {@link Call} can receive call focus via the
+ * {@link ConnectionServiceFocusManager}.
+ * Only top-level calls and non-external calls are eligible.
+ * @return {@code true} if this call is focusable, {@code false} otherwise.
+ */
+ @Override
+ public boolean isFocusable() {
+ boolean isChild = getParentCall() != null;
+ return !isChild && !isExternalCall();
+ }
+
private boolean shouldContinueProcessingAfterDisconnect() {
// Stop processing once the call is active.
if (!CreateConnectionTimeout.isCallBeingPlaced(this)) {
@@ -1160,6 +1172,12 @@
return false;
}
+ if (!PhoneAccount.SCHEME_SIP.equals(getHandle().getScheme()) &&
+ !PhoneAccount.SCHEME_TEL.equals(getHandle().getScheme())) {
+ // Can't log schemes other than SIP or TEL for now.
+ return false;
+ }
+
return phoneAccount.getExtras() != null && phoneAccount.getExtras().getBoolean(
PhoneAccount.EXTRA_LOG_SELF_MANAGED_CALLS, false);
}
@@ -1433,6 +1451,10 @@
if ((mConnectionProperties & Connection.PROPERTY_IS_RTT) ==
Connection.PROPERTY_IS_RTT) {
createRttStreams();
+ if (isEmergencyCall()) {
+ mCallsManager.setAudioRoute(CallAudioState.ROUTE_SPEAKER, null);
+ mCallsManager.mute(false);
+ }
}
mWasHighDefAudio = (connectionProperties & Connection.PROPERTY_HIGH_DEF_AUDIO) ==
Connection.PROPERTY_HIGH_DEF_AUDIO;
@@ -1730,20 +1752,28 @@
disconnect(0);
}
- /**
- * Attempts to disconnect the call through the connection service.
- */
@VisibleForTesting
- public void disconnect(long disconnectionTimeout) {
- disconnect(disconnectionTimeout, "internal" /** callingPackage */);
+ public void disconnect(String reason) {
+ disconnect(0, reason);
}
/**
* Attempts to disconnect the call through the connection service.
*/
@VisibleForTesting
- public void disconnect(long disconnectionTimeout, String callingPackage) {
- Log.addEvent(this, LogUtils.Events.REQUEST_DISCONNECT, callingPackage);
+ public void disconnect(long disconnectionTimeout) {
+ disconnect(disconnectionTimeout, "internal" /** reason */);
+ }
+
+ /**
+ * Attempts to disconnect the call through the connection service.
+ * @param reason the reason for the disconnect; used for logging purposes only. In some cases
+ * this can be a package name if the disconnect was initiated through an API such
+ * as TelecomManager.
+ */
+ @VisibleForTesting
+ public void disconnect(long disconnectionTimeout, String reason) {
+ Log.addEvent(this, LogUtils.Events.REQUEST_DISCONNECT, reason);
// Track that the call is now locally disconnecting.
setLocallyDisconnecting(true);
@@ -1864,7 +1894,7 @@
*/
@VisibleForTesting
public void reject(boolean rejectWithMessage, String textMessage) {
- reject(rejectWithMessage, textMessage, "internal" /** callingPackage */);
+ reject(rejectWithMessage, textMessage, "internal" /** reason */);
}
/**
@@ -1872,9 +1902,11 @@
*
* @param rejectWithMessage Whether to send a text message as part of the call rejection.
* @param textMessage An optional text message to send as part of the rejection.
+ * @param reason The reason for the reject; used for logging purposes. May be a package name
+ * if the reject is initiated from an API such as TelecomManager.
*/
@VisibleForTesting
- public void reject(boolean rejectWithMessage, String textMessage, String callingPackage) {
+ public void reject(boolean rejectWithMessage, String textMessage, String reason) {
// Check to verify that the call is still in the ringing state. A call can change states
// between the time the user hits 'reject' and Telecomm receives the command.
if (isRinging("reject")) {
@@ -1887,7 +1919,7 @@
Log.e(this, new NullPointerException(),
"reject call failed due to null CS callId=%s", getId());
}
- Log.addEvent(this, LogUtils.Events.REQUEST_REJECT, callingPackage);
+ Log.addEvent(this, LogUtils.Events.REQUEST_REJECT, reason);
}
}
@@ -1896,6 +1928,10 @@
*/
@VisibleForTesting
public void hold() {
+ hold(null /* reason */);
+ }
+
+ public void hold(String reason) {
if (mState == CallState.ACTIVE) {
if (mConnectionService != null) {
mConnectionService.hold(this);
@@ -1903,7 +1939,7 @@
Log.e(this, new NullPointerException(),
"hold call failed due to null CS callId=%s", getId());
}
- Log.addEvent(this, LogUtils.Events.REQUEST_HOLD);
+ Log.addEvent(this, LogUtils.Events.REQUEST_HOLD, reason);
}
}
@@ -1912,6 +1948,10 @@
*/
@VisibleForTesting
public void unhold() {
+ unhold(null /* reason */);
+ }
+
+ public void unhold(String reason) {
if (mState == CallState.ON_HOLD) {
if (mConnectionService != null) {
mConnectionService.unhold(this);
@@ -1919,7 +1959,7 @@
Log.e(this, new NullPointerException(),
"unhold call failed due to null CS callId=%s", getId());
}
- Log.addEvent(this, LogUtils.Events.REQUEST_UNHOLD);
+ Log.addEvent(this, LogUtils.Events.REQUEST_UNHOLD, reason);
}
}
@@ -2955,7 +2995,7 @@
return mOriginalConnectionId;
}
- ConnectionServiceFocusManager getConnectionServiceFocusManager() {
+ public ConnectionServiceFocusManager getConnectionServiceFocusManager() {
return mCallsManager.getConnectionServiceFocusManager();
}
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index ad446ec..56f8db9 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -93,6 +93,7 @@
mPlayerFactory.setCallAudioManager(this);
mCallAudioModeStateMachine.setCallAudioManager(this);
+ mCallAudioRouteStateMachine.setCallAudioManager(this);
}
@Override
@@ -385,6 +386,12 @@
CallAudioRouteStateMachine.TOGGLE_MUTE);
}
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void onRingerModeChange() {
+ mCallAudioModeStateMachine.sendMessageWithArgs(
+ CallAudioModeStateMachine.RINGER_MODE_CHANGE, makeArgsForModeStateMachine());
+ }
+
@VisibleForTesting
public void mute(boolean shouldMute) {
Log.v(this, "mute, shouldMute: %b", shouldMute);
diff --git a/src/com/android/server/telecom/CallAudioModeStateMachine.java b/src/com/android/server/telecom/CallAudioModeStateMachine.java
index b5c7e7a..716f23a 100644
--- a/src/com/android/server/telecom/CallAudioModeStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioModeStateMachine.java
@@ -87,6 +87,8 @@
public static final int FOREGROUND_VOIP_MODE_CHANGE = 4001;
+ public static final int RINGER_MODE_CHANGE = 5001;
+
public static final int RUN_RUNNABLE = 9001;
private static final SparseArray<String> MESSAGE_CODE_TO_NAME = new SparseArray<String>() {{
@@ -105,6 +107,7 @@
put(TONE_STARTED_PLAYING, "TONE_STARTED_PLAYING");
put(TONE_STOPPED_PLAYING, "TONE_STOPPED_PLAYING");
put(FOREGROUND_VOIP_MODE_CHANGE, "FOREGROUND_VOIP_MODE_CHANGE");
+ put(RINGER_MODE_CHANGE, "RINGER_MODE_CHANGE");
put(RUN_RUNNABLE, "RUN_RUNNABLE");
}};
@@ -202,18 +205,22 @@
}
private class RingingFocusState extends BaseState {
- @Override
- public void enter() {
- Log.i(LOG_TAG, "Audio focus entering RINGING state");
+ private void tryStartRinging() {
if (mCallAudioManager.startRinging()) {
mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_RING,
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
mAudioManager.setMode(AudioManager.MODE_RINGTONE);
- mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.RINGING_FOCUS);
+ mCallAudioManager.setCallAudioRouteFocusState(
+ CallAudioRouteStateMachine.RINGING_FOCUS);
} else {
- Log.i(LOG_TAG, "Entering RINGING but not acquiring focus -- silent ringtone");
+ Log.i(LOG_TAG, "RINGING state, try start ringing but not acquiring audio focus");
}
+ }
+ @Override
+ public void enter() {
+ Log.i(LOG_TAG, "Audio focus entering RINGING state");
+ tryStartRinging();
mCallAudioManager.stopCallWaiting();
}
@@ -275,6 +282,11 @@
transitionTo(args.foregroundCallIsVoip
? mVoipCallFocusState : mSimCallFocusState);
return HANDLED;
+ case RINGER_MODE_CHANGE: {
+ Log.i(LOG_TAG, "RINGING state, received RINGER_MODE_CHANGE");
+ tryStartRinging();
+ return HANDLED;
+ }
default:
// The forced focus switch commands are handled by BaseState.
return NOT_HANDLED;
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index facbf39..a1581f1 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -179,6 +179,7 @@
put(MUTE_ON, "MUTE_ON");
put(MUTE_OFF, "MUTE_OFF");
put(TOGGLE_MUTE, "TOGGLE_MUTE");
+ put(MUTE_EXTERNALLY_CHANGED, "MUTE_EXTERNALLY_CHANGED");
put(SWITCH_FOCUS, "SWITCH_FOCUS");
@@ -745,6 +746,10 @@
mBluetoothRouteManager.getConnectedDevices());
setSystemAudioState(newState, true);
updateInternalCallAudioState();
+ // Do not send RINGER_MODE_CHANGE if no Bluetooth SCO audio device is available
+ if (mBluetoothRouteManager.getBluetoothAudioConnectedDevice() != null) {
+ mCallAudioManager.onRingerModeChange();
+ }
}
@Override
@@ -770,7 +775,9 @@
}
return HANDLED;
case BT_AUDIO_CONNECTED:
- // Nothing to do
+ // Send ringer mode change because we transit to ActiveBluetoothState even
+ // when HFP is connecting
+ mCallAudioManager.onRingerModeChange();
return HANDLED;
case SWITCH_BLUETOOTH:
case USER_SWITCH_BLUETOOTH:
@@ -1230,7 +1237,13 @@
public void onReceive(Context context, Intent intent) {
Log.startSession("CARSM.mCR");
if (AudioManager.ACTION_MICROPHONE_MUTE_CHANGED.equals(intent.getAction())) {
- sendInternalMessage(MUTE_EXTERNALLY_CHANGED);
+ if (mCallsManager.hasEmergencyCall()) {
+ Log.i(this, "Mute was externally changed when there's an emergency call. " +
+ "Forcing mute back off.");
+ sendInternalMessage(MUTE_OFF);
+ } else {
+ sendInternalMessage(MUTE_EXTERNALLY_CHANGED);
+ }
} else {
Log.w(this, "Received non-mute-change intent");
}
@@ -1276,6 +1289,8 @@
private CallAudioState mCurrentCallAudioState;
private CallAudioState mLastKnownCallAudioState;
+ private CallAudioManager mCallAudioManager;
+
public CallAudioRouteStateMachine(
Context context,
CallsManager callsManager,
@@ -1332,6 +1347,10 @@
mRouteCodeToQuiescentState.put(ROUTE_WIRED_HEADSET, mQuiescentHeadsetRoute);
}
+ public void setCallAudioManager(CallAudioManager callAudioManager) {
+ mCallAudioManager = callAudioManager;
+ }
+
/**
* Initializes the state machine with info on initial audio route, supported audio routes,
* and mute status.
diff --git a/src/com/android/server/telecom/CallIntentProcessor.java b/src/com/android/server/telecom/CallIntentProcessor.java
index d90cba4..ff3b7b2 100644
--- a/src/com/android/server/telecom/CallIntentProcessor.java
+++ b/src/com/android/server/telecom/CallIntentProcessor.java
@@ -101,9 +101,9 @@
String scheme = handle.getScheme();
String uriString = handle.getSchemeSpecificPart();
- if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
- handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?
- PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null);
+ // Ensure sip URIs dialed using TEL scheme get converted to SIP scheme.
+ if (PhoneAccount.SCHEME_TEL.equals(scheme) && PhoneNumberUtils.isUriNumber(uriString)) {
+ handle = Uri.fromParts(PhoneAccount.SCHEME_SIP, uriString, null);
}
PhoneAccountHandle phoneAccountHandle = intent.getParcelableExtra(
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 14b662c..f7953b1 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -286,7 +286,8 @@
ConnectionServiceFocusManager.ConnectionServiceFocus connectionService) {
mCalls.stream()
.filter(c -> c.getConnectionServiceWrapper().equals(connectionService))
- .forEach(c -> c.disconnect());
+ .forEach(c -> c.disconnect("release " +
+ connectionService.getComponentName().getPackageName()));
}
@Override
@@ -835,6 +836,15 @@
return false;
}
+ public boolean hasEmergencyRttCall() {
+ for (Call call : mCalls) {
+ if (call.isEmergencyCall() && call.isRttCall()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@VisibleForTesting
public boolean hasOnlyDisconnectedCalls() {
if (mCalls.size() == 0) {
@@ -1413,11 +1423,8 @@
notifyCreateConnectionFailed(call.getTargetPhoneAccount(), call);
} else {
if (call.isEmergencyCall()) {
- // Disconnect calls from other ConnectionServices other than the one the
- // emergency call targets.
- // Except, do not disconnect calls from the Connection Manager's
- // ConnectionService.
- disconnectCallsHaveDifferentConnectionService(call);
+ // Drop any ongoing self-managed calls to make way for an emergency call.
+ disconnectSelfManagedCalls("place emerg call" /* reason */);
}
call.startCreateConnection(mPhoneAccountRegistrar);
@@ -1459,21 +1466,7 @@
// Hold or disconnect the active call and request call focus for the incoming call.
Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall();
Log.d(this, "Incoming call = %s Ongoing call %s", call, activeCall);
- if (activeCall != null && activeCall != call) {
- // Hold the telephony call even if it doesn't have the hold capability.
- if (canHold(activeCall)) {
- Log.d(this, "Answer %s, hold %s", call, activeCall);
- activeCall.hold();
- } else {
- // This call does not support hold. If it is from a different connection
- // service, then disconnect it, otherwise allow the connection service to
- // figure out the right states.
- if (activeCall.getConnectionService() != call.getConnectionService()) {
- activeCall.disconnect();
- }
- }
- }
-
+ holdActiveCallForNewCall(call);
mConnectionSvrFocusMgr.requestFocus(
call,
new RequestCallback(new ActionAnswerCall(call, videoState)));
@@ -1661,25 +1654,27 @@
Log.w(this, "Unknown call (%s) asked to be removed from hold", call);
} else {
Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall();
+ String activeCallId = null;
if (activeCall != null) {
+ activeCallId = activeCall.getId();
if (canHold(activeCall)) {
- activeCall.hold();
- Log.addEvent(activeCall, LogUtils.Events.SWAP);
- Log.addEvent(call, LogUtils.Events.SWAP);
+ activeCall.hold("Swap to " + call.getId());
+ Log.addEvent(activeCall, LogUtils.Events.SWAP, "To " + call.getId());
+ Log.addEvent(call, LogUtils.Events.SWAP, "From " + activeCall.getId());
} else {
// This call does not support hold. If it is from a different connection
// service, then disconnect it, otherwise invoke call.hold() and allow the
// connection service to handle the situation.
if (activeCall.getConnectionService() != call.getConnectionService()) {
- activeCall.disconnect();
+ activeCall.disconnect("Swap to " + call.getId());
} else {
- activeCall.hold();
+ activeCall.hold("Swap to " + call.getId());
}
}
}
mConnectionSvrFocusMgr.requestFocus(
call,
- new RequestCallback(new ActionUnHoldCall(call)));
+ new RequestCallback(new ActionUnHoldCall(call, activeCallId)));
}
}
@@ -1783,6 +1778,10 @@
/** Called by the in-call UI to change the mute state. */
void mute(boolean shouldMute) {
+ if (hasEmergencyCall() && shouldMute) {
+ Log.i(this, "Refusing to turn on mute because we're in an emergency call");
+ shouldMute = false;
+ }
mCallAudioManager.mute(shouldMute);
}
@@ -1791,6 +1790,11 @@
* speaker phone.
*/
void setAudioRoute(int route, String bluetoothAddress) {
+ if (hasEmergencyRttCall() && route != CallAudioState.ROUTE_SPEAKER) {
+ Log.i(this, "In an emergency RTT call. Forcing route to speaker.");
+ route = CallAudioState.ROUTE_SPEAKER;
+ bluetoothAddress = null;
+ }
mCallAudioManager.setAudioRoute(route, bluetoothAddress);
}
@@ -1809,8 +1813,8 @@
}
private boolean isRttSettingOn() {
- return Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.RTT_CALLING_MODE, 0) != 0;
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.RTT_CALLING_MODE, 0) != 0;
}
void phoneAccountSelected(Call call, PhoneAccountHandle account, boolean setDefault) {
@@ -1848,7 +1852,7 @@
if (makeRoomForOutgoingCall(call, false /* isEmergencyCall */)) {
call.startCreateConnection(mPhoneAccountRegistrar);
} else {
- call.disconnect();
+ call.disconnect("no room");
}
if (setDefault) {
@@ -1898,11 +1902,43 @@
maybeMoveToSpeakerPhone(call);
}
- void markCallAsActive(Call call) {
+ /**
+ * Returns true if the active call is held.
+ */
+ boolean holdActiveCallForNewCall(Call call) {
+ Call activeCall = (Call) mConnectionSvrFocusMgr.getCurrentFocusCall();
+ if (activeCall != null && activeCall != call) {
+ if (canHold(activeCall)) {
+ activeCall.hold();
+ return true;
+ } else if (supportsHold(call)) {
+ Call heldCall = getHeldCallByConnectionService(call.getConnectionService());
+ if (heldCall != null) {
+ heldCall.disconnect();
+ Log.i(this, "Disconnecting held call %s before holding active call.", heldCall);
+ }
+ activeCall.hold();
+ return true;
+ } else {
+ // This call does not support hold. If it is from a different connection
+ // service, then disconnect it, otherwise allow the connection service to
+ // figure out the right states.
+ if (activeCall.getConnectionService() != call.getConnectionService()) {
+ activeCall.disconnect();
+ }
+ }
+ }
+ return false;
+ }
+
+ @VisibleForTesting
+ public void markCallAsActive(Call call) {
if (call.isSelfManaged()) {
// backward compatibility, the self-managed connection service will set the call state
- // to active directly. We should request the call focus for self-managed call before
- // the state change
+ // to active directly. We should hold or disconnect the current active call based on the
+ // holdability, and request the call focus for the self-managed call before the state
+ // change.
+ holdActiveCallForNewCall(call);
mConnectionSvrFocusMgr.requestFocus(
call,
new RequestCallback(new ActionSetCallState(
@@ -2134,6 +2170,14 @@
return getFirstCallWithState(CallState.ON_HOLD);
}
+ public Call getHeldCallByConnectionService(ConnectionServiceWrapper connSvr) {
+ Optional<Call> heldCall = mCalls.stream()
+ .filter(call -> call.getConnectionService() == connSvr
+ && call.getState() == CallState.ON_HOLD)
+ .findFirst();
+ return heldCall.isPresent() ? heldCall.get() : null;
+ }
+
@VisibleForTesting
public int getNumHeldCalls() {
int count = 0;
@@ -2807,7 +2851,7 @@
if (isEmergency && !canHold(liveCall)) {
call.getAnalytics().setCallIsAdditional(true);
liveCall.getAnalytics().setCallIsInterrupted(true);
- liveCall.disconnect();
+ liveCall.disconnect("emergency, can't hold");
return true;
}
@@ -2850,7 +2894,7 @@
Log.i(this, "makeRoomForOutgoingCall: holding live call.");
call.getAnalytics().setCallIsAdditional(true);
liveCall.getAnalytics().setCallIsInterrupted(true);
- liveCall.hold();
+ liveCall.hold("calling " + call.getId());
return true;
}
@@ -3149,7 +3193,7 @@
// We are going to place the new outgoing call, so disconnect any ongoing self-managed
// calls which are ongoing at this time.
- disconnectSelfManagedCalls();
+ disconnectSelfManagedCalls("outgoing call " + callId);
// Kick of the new outgoing call intent from where it left off prior to confirming the
// call.
@@ -3211,14 +3255,14 @@
/**
* Disconnects all self-managed calls.
*/
- private void disconnectSelfManagedCalls() {
+ private void disconnectSelfManagedCalls(String reason) {
// Disconnect all self-managed calls to make priority for emergency call.
// Use Call.disconnect() to command the ConnectionService to disconnect the calls.
// CallsManager.markCallAsDisconnected doesn't actually tell the ConnectionService to
// disconnect.
mCalls.stream()
.filter(c -> c.isSelfManaged())
- .forEach(c -> c.disconnect());
+ .forEach(c -> c.disconnect(reason));
// When disconnecting all self-managed calls, switch audio routing back to the baseline
// route. This ensures if, for example, the self-managed ConnectionService was routed to
@@ -3227,14 +3271,6 @@
mCallAudioManager.switchBaseline();
}
- private void disconnectCallsHaveDifferentConnectionService(Call exceptCall) {
- mCalls.stream().filter(c ->
- c.getConnectionService() != exceptCall.getConnectionService()
- && c.getConnectionManagerPhoneAccount()
- != exceptCall.getConnectionManagerPhoneAccount())
- .forEach(c -> c.disconnect());
- }
-
/**
* Dumps the state of the {@link CallsManager}.
*
@@ -3361,7 +3397,7 @@
ConnectionServiceWrapper service = call.getConnectionService();
service.handoverFailed(call, reason);
call.setDisconnectCause(new DisconnectCause(DisconnectCause.CANCELED));
- call.disconnect();
+ call.disconnect("handover failed");
}
/**
@@ -3541,7 +3577,7 @@
} else {
if (call.isEmergencyCall()) {
// Disconnect all self-managed calls to make priority for emergency call.
- disconnectSelfManagedCalls();
+ disconnectSelfManagedCalls("emergency call");
}
call.startCreateConnection(mPhoneAccountRegistrar);
@@ -3733,6 +3769,10 @@
return call.can(Connection.CAPABILITY_HOLD);
}
+ private boolean supportsHold(Call call) {
+ return call.can(Connection.CAPABILITY_SUPPORT_HOLD);
+ }
+
private final class ActionSetCallState implements PendingAction {
private final Call mCall;
@@ -3754,15 +3794,17 @@
private final class ActionUnHoldCall implements PendingAction {
private final Call mCall;
+ private final String mPreviouslyHeldCallId;
- ActionUnHoldCall(Call call) {
+ ActionUnHoldCall(Call call, String previouslyHeldCallId) {
mCall = call;
+ mPreviouslyHeldCallId = previouslyHeldCallId;
}
@Override
public void performAction() {
Log.d(this, "perform unhold call for %s", mCall);
- mCall.unhold();
+ mCall.unhold("held " + mPreviouslyHeldCallId);
}
}
diff --git a/src/com/android/server/telecom/ConnectionServiceFocusManager.java b/src/com/android/server/telecom/ConnectionServiceFocusManager.java
index f296502..92570a0 100644
--- a/src/com/android/server/telecom/ConnectionServiceFocusManager.java
+++ b/src/com/android/server/telecom/ConnectionServiceFocusManager.java
@@ -17,6 +17,7 @@
package com.android.server.telecom;
import android.annotation.Nullable;
+import android.content.ComponentName;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -64,6 +65,12 @@
* @see {@link ConnectionServiceFocusListener}.
*/
void setConnectionServiceFocusListener(ConnectionServiceFocusListener listener);
+
+ /**
+ * Get the {@link ComponentName} of the ConnectionService for logging purposes.
+ * @return the {@link ComponentName}.
+ */
+ ComponentName getComponentName();
}
/**
@@ -105,6 +112,11 @@
* @see {@link CallState}
*/
int getState();
+
+ /**
+ * @return {@code True} if this call can receive focus, {@code false} otherwise.
+ */
+ boolean isFocusable();
}
/** Interface define a call back for focus request event. */
@@ -323,7 +335,8 @@
List<CallFocus> calls = mCalls
.stream()
- .filter(call -> mCurrentFocus.equals(call.getConnectionServiceWrapper()))
+ .filter(call -> mCurrentFocus.equals(call.getConnectionServiceWrapper())
+ && call.isFocusable())
.collect(Collectors.toList());
for (int i = 0; i < PRIORITY_FOCUS_CALL_STATE.length; i++) {
diff --git a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
index a7e21ad..3797c68 100644
--- a/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
+++ b/src/com/android/server/telecom/NewOutgoingCallIntentBroadcaster.java
@@ -144,6 +144,9 @@
return;
}
+ // TODO: Remove the assumption that phone numbers are either SIP or TEL.
+ // This does not impact self-managed ConnectionServices as they do not use the
+ // NewOutgoingCallIntentBroadcaster.
Uri resultHandleUri = Uri.fromParts(
mPhoneNumberUtilsAdapter.isUriNumber(resultNumber) ?
PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL,
@@ -219,73 +222,88 @@
}
}
- String number = mPhoneNumberUtilsAdapter.getNumberFromIntent(intent, mContext);
- if (TextUtils.isEmpty(number)) {
- Log.w(this, "Empty number obtained from the call intent.");
- return DisconnectCause.NO_PHONE_NUMBER_SUPPLIED;
- }
-
- boolean isUriNumber = mPhoneNumberUtilsAdapter.isUriNumber(number);
- if (!isUriNumber) {
- number = mPhoneNumberUtilsAdapter.convertKeypadLettersToDigits(number);
- number = mPhoneNumberUtilsAdapter.stripSeparators(number);
- }
-
- final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(number);
- Log.v(this, "isPotentialEmergencyNumber = %s", isPotentialEmergencyNumber);
-
- rewriteCallIntentAction(intent, isPotentialEmergencyNumber);
- action = intent.getAction();
- // True for certain types of numbers that are not intended to be intercepted or modified
- // by third parties (e.g. emergency numbers).
- boolean callImmediately = false;
-
- if (Intent.ACTION_CALL.equals(action)) {
- if (isPotentialEmergencyNumber) {
- if (!mIsDefaultOrSystemPhoneApp) {
- Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s "
- + "unless caller is system or default dialer.", number, intent);
- launchSystemDialer(intent.getData());
- return DisconnectCause.OUTGOING_CANCELED;
- } else {
- callImmediately = true;
- }
- }
- } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {
- if (!isPotentialEmergencyNumber) {
- Log.w(this, "Cannot call non-potential-emergency number %s with EMERGENCY_CALL "
- + "Intent %s.", number, intent);
- return DisconnectCause.OUTGOING_CANCELED;
- }
- callImmediately = true;
- } else {
- Log.w(this, "Unhandled Intent %s. Ignoring and not placing call.", intent);
- return DisconnectCause.INVALID_NUMBER;
- }
-
- // True for all managed calls, false for self-managed calls.
- boolean sendNewOutgoingCallBroadcast = true;
PhoneAccountHandle targetPhoneAccount = mIntent.getParcelableExtra(
TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
+ boolean isSelfManaged = false;
if (targetPhoneAccount != null) {
PhoneAccount phoneAccount =
mCallsManager.getPhoneAccountRegistrar().getPhoneAccountUnchecked(
targetPhoneAccount);
- if (phoneAccount != null && phoneAccount.isSelfManaged()) {
- callImmediately = true;
- sendNewOutgoingCallBroadcast = false;
- Log.i(this, "Skipping NewOutgoingCallBroadcast for self-managed call.");
+ if (phoneAccount != null) {
+ isSelfManaged = phoneAccount.isSelfManaged();
}
}
- if (callImmediately) {
+ String number = "";
+ // True for certain types of numbers that are not intended to be intercepted or modified
+ // by third parties (e.g. emergency numbers).
+ boolean callImmediately = false;
+ // True for all managed calls, false for self-managed calls.
+ boolean sendNewOutgoingCallBroadcast = true;
+ Uri callingAddress = handle;
+
+ if (!isSelfManaged) {
+ // Placing a managed call
+ number = mPhoneNumberUtilsAdapter.getNumberFromIntent(intent, mContext);
+ if (TextUtils.isEmpty(number)) {
+ Log.w(this, "Empty number obtained from the call intent.");
+ return DisconnectCause.NO_PHONE_NUMBER_SUPPLIED;
+ }
+
+ // TODO: Cleanup this dialing code; it makes the assumption that we're dialing with a
+ // SIP or TEL URI.
+ boolean isUriNumber = mPhoneNumberUtilsAdapter.isUriNumber(number);
+ if (!isUriNumber) {
+ number = mPhoneNumberUtilsAdapter.convertKeypadLettersToDigits(number);
+ number = mPhoneNumberUtilsAdapter.stripSeparators(number);
+ }
+
+ final boolean isPotentialEmergencyNumber = isPotentialEmergencyNumber(number);
+ Log.v(this, "isPotentialEmergencyNumber = %s", isPotentialEmergencyNumber);
+
+ rewriteCallIntentAction(intent, isPotentialEmergencyNumber);
+ action = intent.getAction();
+
+ if (Intent.ACTION_CALL.equals(action)) {
+ if (isPotentialEmergencyNumber) {
+ if (!mIsDefaultOrSystemPhoneApp) {
+ Log.w(this, "Cannot call potential emergency number %s with CALL Intent %s "
+ + "unless caller is system or default dialer.", number, intent);
+ launchSystemDialer(intent.getData());
+ return DisconnectCause.OUTGOING_CANCELED;
+ } else {
+ callImmediately = true;
+ }
+ }
+ } else if (Intent.ACTION_CALL_EMERGENCY.equals(action)) {
+ if (!isPotentialEmergencyNumber) {
+ Log.w(this, "Cannot call non-potential-emergency number %s with EMERGENCY_CALL "
+ + "Intent %s.", number, intent);
+ return DisconnectCause.OUTGOING_CANCELED;
+ }
+ callImmediately = true;
+ } else {
+ Log.w(this, "Unhandled Intent %s. Ignoring and not placing call.", intent);
+ return DisconnectCause.INVALID_NUMBER;
+ }
+
+ // TODO: Support dialing using URIs instead of just assuming SIP or TEL.
String scheme = isUriNumber ? PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL;
+ callingAddress = Uri.fromParts(scheme, number, null);
+ } else {
+ // Self-managed call.
+ callImmediately = true;
+ sendNewOutgoingCallBroadcast = false;
+ Log.i(this, "Skipping NewOutgoingCallBroadcast for self-managed call.");
+ }
+
+ if (callImmediately) {
boolean speakerphoneOn = mIntent.getBooleanExtra(
TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
int videoState = mIntent.getIntExtra(
TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
VideoProfile.STATE_AUDIO_ONLY);
- placeOutgoingCallImmediately(mCall, Uri.fromParts(scheme, number, null), null,
+ placeOutgoingCallImmediately(mCall, callingAddress, null,
speakerphoneOn, videoState);
// Don't return but instead continue and send the ACTION_NEW_OUTGOING_CALL broadcast
diff --git a/src/com/android/server/telecom/ServiceBinder.java b/src/com/android/server/telecom/ServiceBinder.java
index 44ddc24..f7844b4 100644
--- a/src/com/android/server/telecom/ServiceBinder.java
+++ b/src/com/android/server/telecom/ServiceBinder.java
@@ -309,7 +309,7 @@
}
}
- final ComponentName getComponentName() {
+ public final ComponentName getComponentName() {
return mComponentName;
}
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index a72e5b6..2c00941 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -17,6 +17,7 @@
package com.android.server.telecom;
import static android.Manifest.permission.CALL_PHONE;
+import static android.Manifest.permission.CALL_PRIVILEGED;
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.MODIFY_PHONE_STATE;
import static android.Manifest.permission.READ_PHONE_STATE;
@@ -1227,12 +1228,20 @@
final boolean hasCallPermission = mContext.checkCallingPermission(CALL_PHONE) ==
PackageManager.PERMISSION_GRANTED;
+ // The Emergency Dialer has call privileged permission and uses this to place
+ // emergency calls. We ensure permission checks in
+ // NewOutgoingCallIntentBroadcaster#process pass by sending this to
+ // Telecom as an ACTION_CALL_PRIVILEGED intent (which makes sense since the
+ // com.android.phone process has that permission).
+ final boolean hasCallPrivilegedPermission = mContext.checkCallingPermission(
+ CALL_PRIVILEGED) == PackageManager.PERMISSION_GRANTED;
synchronized (mLock) {
final UserHandle userHandle = Binder.getCallingUserHandle();
long token = Binder.clearCallingIdentity();
try {
- final Intent intent = new Intent(Intent.ACTION_CALL, handle);
+ final Intent intent = new Intent(hasCallPrivilegedPermission ?
+ Intent.ACTION_CALL_PRIVILEGED : Intent.ACTION_CALL, handle);
if (extras != null) {
extras.setDefusable(true);
intent.putExtras(extras);
@@ -1240,7 +1249,8 @@
mUserCallIntentProcessorFactory.create(mContext, userHandle)
.processIntent(
intent, callingPackage, isSelfManaged ||
- (hasCallAppOp && hasCallPermission));
+ (hasCallAppOp && hasCallPermission),
+ true /* isLocalInvocation */);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/src/com/android/server/telecom/components/UserCallActivity.java b/src/com/android/server/telecom/components/UserCallActivity.java
index dbee450..ca8fef7 100644
--- a/src/com/android/server/telecom/components/UserCallActivity.java
+++ b/src/com/android/server/telecom/components/UserCallActivity.java
@@ -74,7 +74,7 @@
// ActivityThread.ActivityClientRecord#intent directly.
// Modifying directly may be a potential risk when relaunching this activity.
new UserCallIntentProcessor(this, userHandle).processIntent(new Intent(intent),
- getCallingPackage(), true /* hasCallAppOp*/);
+ getCallingPackage(), true /* hasCallAppOp*/, false /* isLocalInvocation */);
} finally {
Log.endSession();
wakelock.release();
diff --git a/src/com/android/server/telecom/components/UserCallIntentProcessor.java b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
index a95768e..1a76043 100644
--- a/src/com/android/server/telecom/components/UserCallIntentProcessor.java
+++ b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
@@ -18,15 +18,14 @@
import com.android.server.telecom.CallIntentProcessor;
import com.android.server.telecom.R;
+import com.android.server.telecom.TelecomSystem;
import com.android.server.telecom.TelephonyUtil;
import com.android.server.telecom.UserUtil;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.UserHandle;
import android.os.UserManager;
@@ -37,7 +36,6 @@
import android.telecom.VideoProfile;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
-import android.widget.Toast;
// TODO: Needed for move to system service: import com.android.internal.R;
@@ -72,9 +70,18 @@
* Processes intents sent to the activity.
*
* @param intent The intent.
+ * @param callingPackageName The package name of the calling app.
+ * @param canCallNonEmergency {@code true} if the caller is permitted to call non-emergency
+ * numbers.
+ * @param isLocalInvocation {@code true} if the caller is within the system service (i.e. the
+ * caller is {@link com.android.server.telecom.TelecomServiceImpl})
+ * and we can skip the re-broadcast of the intent to Telecom.
+ * When {@code false}, we need to re-broadcast the intent to Telcom
+ * to trampoline it to the system service where the Telecom
+ * service resides.
*/
public void processIntent(Intent intent, String callingPackageName,
- boolean canCallNonEmergency) {
+ boolean canCallNonEmergency, boolean isLocalInvocation) {
// Ensure call intents are not processed on devices that are not capable of calling.
if (!isVoiceCapable()) {
return;
@@ -85,19 +92,20 @@
if (Intent.ACTION_CALL.equals(action) ||
Intent.ACTION_CALL_PRIVILEGED.equals(action) ||
Intent.ACTION_CALL_EMERGENCY.equals(action)) {
- processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency);
+ processOutgoingCallIntent(intent, callingPackageName, canCallNonEmergency,
+ isLocalInvocation);
}
}
private void processOutgoingCallIntent(Intent intent, String callingPackageName,
- boolean canCallNonEmergency) {
+ boolean canCallNonEmergency, boolean isLocalInvocation) {
Uri handle = intent.getData();
String scheme = handle.getScheme();
String uriString = handle.getSchemeSpecificPart();
- if (!PhoneAccount.SCHEME_VOICEMAIL.equals(scheme)) {
- handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(uriString) ?
- PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL, uriString, null);
+ // Ensure sip URIs dialed using TEL scheme get converted to SIP scheme.
+ if (PhoneAccount.SCHEME_TEL.equals(scheme) && PhoneNumberUtils.isUriNumber(uriString)) {
+ handle = Uri.fromParts(PhoneAccount.SCHEME_SIP, uriString, null);
}
// Check DISALLOW_OUTGOING_CALLS restriction. Note: We are skipping this check in a managed
@@ -144,7 +152,7 @@
// Save the user handle of current user before forwarding the intent to primary user.
intent.putExtra(CallIntentProcessor.KEY_INITIATING_USER, mUserHandle);
- sendBroadcastToReceiver(intent);
+ sendIntentToDestination(intent, isLocalInvocation);
}
private boolean isDefaultOrSystemDialer(String callingPackageName) {
@@ -174,14 +182,28 @@
}
/**
- * Trampolines the intent to the broadcast receiver that runs only as the primary user.
+ * Potentially trampolines the intent to the broadcast receiver that runs only as the primary
+ * user. If the caller is local to the Telecom service, we send the intent to Telecom without
+ * rebroadcasting it.
*/
- private boolean sendBroadcastToReceiver(Intent intent) {
+ private boolean sendIntentToDestination(Intent intent, boolean isLocalInvocation) {
intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, false);
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.setClass(mContext, PrimaryCallReceiver.class);
- Log.d(this, "Sending broadcast as user to CallReceiver");
- mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+ if (isLocalInvocation) {
+ // We are invoking this from TelecomServiceImpl, so TelecomSystem is available. Don't
+ // bother trampolining the intent, just sent it directly to the call intent processor.
+ // TODO: We should not be using an intent here; this whole flows needs cleanup.
+ Log.i(this, "sendIntentToDestination: send intent to Telecom directly.");
+ synchronized (TelecomSystem.getInstance().getLock()) {
+ TelecomSystem.getInstance().getCallIntentProcessor().processIntent(intent);
+ }
+ } else {
+ // We're calling from the UserCallActivity, so the TelecomSystem is not in the same
+ // process; we need to trampoline to TelecomSystem in the system server process.
+ Log.i(this, "sendIntentToDestination: trampoline to Telecom.");
+ mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+ }
return true;
}
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
index ec80911..7fee263 100644
--- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -583,6 +583,7 @@
|| TextUtils.isEmpty(handleString)) {
handle = null;
} else {
+ // TODO: Remove the assumption that numbers are SIP or TEL only.
handle = Uri.fromParts(PhoneNumberUtils.isUriNumber(handleString) ?
PhoneAccount.SCHEME_SIP : PhoneAccount.SCHEME_TEL,
handleString, null);
diff --git a/testapps/res/layout/self_managed_call_list_item.xml b/testapps/res/layout/self_managed_call_list_item.xml
index 7e149a8..66b5b21 100644
--- a/testapps/res/layout/self_managed_call_list_item.xml
+++ b/testapps/res/layout/self_managed_call_list_item.xml
@@ -72,5 +72,10 @@
android:layout_height="wrap_content"
android:text="Earpiece"
android:id="@+id/earpieceButton" />
+ <CheckBox
+ android:id="@+id/holdable"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" android:layout_weight="1"
+ android:text="Holdable"/>
</LinearLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/testapps/res/layout/self_managed_sample_main.xml b/testapps/res/layout/self_managed_sample_main.xml
index e55de33..68ae65c 100644
--- a/testapps/res/layout/self_managed_sample_main.xml
+++ b/testapps/res/layout/self_managed_sample_main.xml
@@ -30,43 +30,42 @@
android:layout_height="wrap_content"
android:text="This app provides two sample implementations of the self-managed ConnectionService API. Use this UI to add simulated self-managed calls:" />
- <RadioGroup
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
- <RadioButton
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Sample Source 1"
- android:id="@+id/useAcct1Button"
- android:background="@color/test_call_a_color"/>
- <RadioButton
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Sample Source 2"
- android:id="@+id/useAcct2Button"
- android:background="@color/test_call_b_color"/>
- </RadioGroup>
-
- <RadioGroup
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal">
- <RadioButton
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Video Call"
- android:id="@+id/videoCallButton"/>
- <RadioButton
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Audio Call"
- android:id="@+id/audioCallButton"/>
- </RadioGroup>
+ <TextView
+ android:id="@+id/textView"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" android:layout_weight="1"
+ android:text="Acct:"/>
+ <RadioGroup
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_weight="1" android:orientation="horizontal">
+ <RadioButton
+ android:id="@+id/useAcct1Button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@color/test_call_a_color"
+ android:checked="true" android:text="1"/>
+ <RadioButton
+ android:id="@+id/useAcct2Button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@color/test_call_b_color"
+ android:text="2"/>
+ </RadioGroup>
+ <TextView
+ android:id="@+id/hasFocus"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" android:layout_weight="1"
+ android:text="👎 No Focus 👎"/>
+ </LinearLayout>
<LinearLayout android:orientation="horizontal"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content">
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -76,6 +75,16 @@
android:layout_height="wrap_content"
android:id="@+id/phoneNumber"
android:text="tel:555-1212"/>
+ <CheckBox
+ android:id="@+id/holdable"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" android:layout_weight="1"
+ android:checked="true" android:text="Holdable"/>
+ <CheckBox
+ android:id="@+id/videoCall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" android:layout_weight="1"
+ android:text="Video"/>
</LinearLayout>
<LinearLayout android:orientation="horizontal"
@@ -83,20 +92,20 @@
android:layout_height="wrap_content">
<Button
+ android:id="@+id/placeOutgoingCallButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Outgoing Call"
- android:id="@+id/placeOutgoingCallButton" />
+ android:text="Outgoing"/>
<Button
+ android:id="@+id/placeIncomingCallButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Incoming Call"
- android:id="@+id/placeIncomingCallButton" />
+ android:text="Incoming"/>
<Button
+ android:id="@+id/handoverFrom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Handover From"
- android:id="@+id/handoverFrom" />
+ android:text="Accept Handover"/>
</LinearLayout>
<ListView
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
index f9bce35..4b5fa57 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallList.java
@@ -40,12 +40,15 @@
public void onCreateIncomingConnectionFailed(ConnectionRequest request) {};
public void onCreateOutgoingConnectionFailed(ConnectionRequest request) {};
public void onConnectionListChanged() {};
+ public void onConnectionServiceFocusLost() {};
+ public void onConnectionServiceFocusGained() {};
}
public static String SELF_MANAGED_ACCOUNT_1 = "1";
public static String SELF_MANAGED_ACCOUNT_2 = "2";
public static String SELF_MANAGED_NAME_1 = "SuperCall";
public static String SELF_MANAGED_NAME_2 = "Mega Call";
+ public static String CUSTOM_URI_SCHEME = "custom";
private static SelfManagedCallList sInstance;
private static ComponentName COMPONENT_NAME = new ComponentName(
@@ -110,6 +113,7 @@
PhoneAccount.Builder builder = PhoneAccount.builder(handle, name)
.addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
.addSupportedUriScheme(PhoneAccount.SCHEME_SIP)
+ .addSupportedUriScheme(CUSTOM_URI_SCHEME)
.setAddress(address)
.setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED |
PhoneAccount.CAPABILITY_VIDEO_CALLING |
@@ -136,6 +140,18 @@
}
}
+ public void notifyConnectionServiceFocusGained() {
+ if (mListener != null) {
+ mListener.onConnectionServiceFocusGained();
+ }
+ }
+
+ public void notifyConnectionServiceFocusLost() {
+ if (mListener != null) {
+ mListener.onConnectionServiceFocusLost();
+ }
+ }
+
public void addConnection(SelfManagedConnection connection) {
Log.i(this, "addConnection %s", connection);
mConnections.add(connection);
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallListAdapter.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallListAdapter.java
index 71e8922..8eaa282 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallListAdapter.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallListAdapter.java
@@ -17,6 +17,7 @@
package com.android.server.telecom.testapps;
import android.telecom.CallAudioState;
+import android.telecom.Connection;
import android.telecom.DisconnectCause;
import android.telecom.PhoneAccountHandle;
import android.util.Log;
@@ -24,6 +25,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
+import android.widget.CheckBox;
import android.widget.TextView;
import com.android.server.telecom.testapps.R;
@@ -102,6 +104,22 @@
}
};
+ private View.OnClickListener mHoldableListener = new View.OnClickListener() {
+ @Override
+ public void onClick (View v) {
+ View parent = (View) v.getParent().getParent();
+ SelfManagedConnection connection = (SelfManagedConnection) parent.getTag();
+ int capabilities = connection.getConnectionCapabilities();
+ if ((capabilities & Connection.CAPABILITY_HOLD) == Connection.CAPABILITY_HOLD) {
+ capabilities &= ~(Connection.CAPABILITY_HOLD | Connection.CAPABILITY_SUPPORT_HOLD);
+ } else {
+ capabilities |= (Connection.CAPABILITY_HOLD | Connection.CAPABILITY_SUPPORT_HOLD);
+ }
+ connection.setConnectionCapabilities(capabilities);
+ notifyDataSetChanged();
+ }
+ };
+
private final LayoutInflater mLayoutInflater;
private List<SelfManagedConnection> mConnections;
@@ -175,7 +193,8 @@
}
setInfoForRow(result, phoneAccountHandle.getId(), connection.getAddress().toString(),
android.telecom.Connection.stateToString(connection.getState()), audioRoute,
- callType, connection.getState() == android.telecom.Connection.STATE_RINGING);
+ callType, connection.getState() == android.telecom.Connection.STATE_RINGING,
+ connection.isHoldable());
result.setTag(connection);
return result;
}
@@ -188,7 +207,7 @@
private void setInfoForRow(View view, String accountName, String number,
String status, String audioRoute, String callType,
- boolean isRinging) {
+ boolean isRinging, boolean isHoldable) {
TextView numberTextView = (TextView) view.findViewById(R.id.phoneNumber);
TextView statusTextView = (TextView) view.findViewById(R.id.callState);
@@ -207,6 +226,9 @@
missedButton.setVisibility(isRinging ? View.VISIBLE : View.GONE);
setHeldButton.setVisibility(!isRinging ? View.VISIBLE : View.GONE);
disconnectButton.setVisibility(!isRinging ? View.VISIBLE : View.GONE);
+ CheckBox holdableCheckbox = view.findViewById(R.id.holdable);
+ holdableCheckbox.setOnClickListener(mHoldableListener);
+ holdableCheckbox.setChecked(isHoldable);
numberTextView.setText(accountName + " - " + number + " (" + audioRoute + ")");
statusTextView.setText(callType + " - Status: " + status);
}
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
index 6139e33..a7b1350 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedCallingActivity.java
@@ -31,6 +31,7 @@
import android.widget.EditText;
import android.widget.ListView;
import android.widget.RadioButton;
+import android.widget.TextView;
import android.widget.Toast;
import com.android.server.telecom.testapps.R;
@@ -50,10 +51,12 @@
private Button mHandoverFrom;
private RadioButton mUseAcct1Button;
private RadioButton mUseAcct2Button;
- private RadioButton mVideoCallButton;
- private RadioButton mAudioCallButton;
+ private CheckBox mHoldableCheckbox;
+ private CheckBox mVideoCallCheckbox;
private EditText mNumber;
private ListView mListView;
+ private TextView mHasFocus;
+
private SelfManagedCallListAdapter mListAdapter;
private SelfManagedCallList.Listener mCallListListener = new SelfManagedCallList.Listener() {
@@ -76,6 +79,16 @@
Log.i(TAG, "onConnectionListChanged");
mListAdapter.updateConnections();
};
+
+ @Override
+ public void onConnectionServiceFocusLost() {
+ mHasFocus.setText("\uD83D\uDC4E No Focus \uD83D\uDC4E");
+ };
+
+ @Override
+ public void onConnectionServiceFocusGained() {
+ mHasFocus.setText("\uD83D\uDC4D Has Focus \uD83D\uDC4D");
+ };
};
@Override
@@ -109,10 +122,11 @@
placeIncomingCall(true /* isHandoverFrom */);
}));
- mUseAcct1Button = (RadioButton) findViewById(R.id.useAcct1Button);
- mUseAcct2Button = (RadioButton) findViewById(R.id.useAcct2Button);
- mVideoCallButton = (RadioButton) findViewById(R.id.videoCallButton);
- mAudioCallButton = (RadioButton) findViewById(R.id.audioCallButton);
+ mUseAcct1Button = findViewById(R.id.useAcct1Button);
+ mUseAcct2Button = findViewById(R.id.useAcct2Button);
+ mHasFocus = findViewById(R.id.hasFocus);
+ mVideoCallCheckbox = findViewById(R.id.videoCall);
+ mHoldableCheckbox = findViewById(R.id.holdable);
mNumber = (EditText) findViewById(R.id.phoneNumber);
mListView = (ListView) findViewById(R.id.callList);
mCallList.setListener(mCallListListener);
@@ -146,10 +160,14 @@
Bundle extras = new Bundle();
extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
getSelectedPhoneAccountHandle());
- if (mVideoCallButton.isChecked()) {
+ if (mVideoCallCheckbox.isChecked()) {
extras.putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE,
VideoProfile.STATE_BIDIRECTIONAL);
}
+ Bundle clientExtras = new Bundle();
+ clientExtras.putBoolean(SelfManagedConnectionService.EXTRA_HOLDABLE,
+ mHoldableCheckbox.isChecked());
+ extras.putBundle(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, clientExtras);
tm.placeCall(Uri.parse(mNumber.getText().toString()), extras);
}
@@ -167,7 +185,9 @@
Bundle extras = new Bundle();
extras.putParcelable(TelecomManager.EXTRA_INCOMING_CALL_ADDRESS,
Uri.parse(mNumber.getText().toString()));
- if (mVideoCallButton.isChecked()) {
+ extras.putBoolean(SelfManagedConnectionService.EXTRA_HOLDABLE,
+ mHoldableCheckbox.isChecked());
+ if (mVideoCallCheckbox.isChecked()) {
extras.putInt(TelecomManager.EXTRA_INCOMING_VIDEO_STATE,
VideoProfile.STATE_BIDIRECTIONAL);
}
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java
index a84dd90..8d0af04 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnection.java
@@ -138,11 +138,17 @@
@Override
public void onHold() {
+ if (mMediaPlayer != null) {
+ mMediaPlayer.pause();
+ }
setOnHold();
}
@Override
public void onUnhold() {
+ if (mMediaPlayer != null) {
+ mMediaPlayer.start();
+ }
setActive();
}
@@ -218,6 +224,10 @@
return mIsHandover;
}
+ public boolean isHoldable() {
+ return (getConnectionCapabilities() & Connection.CAPABILITY_HOLD) != 0;
+ }
+
private MediaPlayer createMediaPlayer(Context context) {
int audioToPlay = (Math.random() > 0.5f) ? R.raw.sample_audio : R.raw.sample_audio2;
MediaPlayer mediaPlayer = MediaPlayer.create(context, audioToPlay);
diff --git a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java
index 12d1552..d5d79af 100644
--- a/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java
+++ b/testapps/src/com/android/server/telecom/testapps/SelfManagedConnectionService.java
@@ -35,6 +35,7 @@
* See {@link android.telecom} for more information on self-managed {@link ConnectionService}s.
*/
public class SelfManagedConnectionService extends ConnectionService {
+ public static final String EXTRA_HOLDABLE = "com.android.server.telecom.testapps.HOLDABLE";
private static final String[] TEST_NAMES = {"Tom Smith", "Jane Appleseed", "Joseph Engleton",
"Claudia McPherson", "Chris P. Bacon", "Seymour Butz", "Hugh Mungus", "Anita Bath"};
private final SelfManagedCallList mCallList = SelfManagedCallList.getInstance();
@@ -65,6 +66,17 @@
mCallList.notifyCreateOutgoingConnectionFailed(request);
}
+ @Override
+ public void onConnectionServiceFocusLost() {
+ mCallList.notifyConnectionServiceFocusLost();
+ connectionServiceFocusReleased();
+ }
+
+ @Override
+ public void onConnectionServiceFocusGained() {
+ mCallList.notifyConnectionServiceFocusGained();
+ }
+
private Connection createSelfManagedConnection(ConnectionRequest request, boolean isIncoming) {
SelfManagedConnection connection = new SelfManagedConnection(mCallList,
getApplicationContext(), isIncoming);
@@ -83,11 +95,17 @@
}
Bundle requestExtras = request.getExtras();
if (requestExtras != null) {
- Log.i(this, "createConnection: isHandover=%b, handoverFrom=%s",
+ boolean isHoldable = requestExtras.getBoolean(EXTRA_HOLDABLE, false);
+ Log.i(this, "createConnection: isHandover=%b, handoverFrom=%s, holdable=%b",
requestExtras.getBoolean(TelecomManager.EXTRA_IS_HANDOVER),
- requestExtras.getString(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT));
+ requestExtras.getString(TelecomManager.EXTRA_HANDOVER_FROM_PHONE_ACCOUNT),
+ isHoldable);
connection.setIsHandover(requestExtras.getBoolean(TelecomManager.EXTRA_IS_HANDOVER,
false));
+ if (isHoldable) {
+ connection.setConnectionCapabilities(connection.getConnectionCapabilities() |
+ Connection.CAPABILITY_HOLD | Connection.CAPABILITY_SUPPORT_HOLD);
+ }
if (!isIncoming && connection.isHandover()) {
Intent intent = new Intent(Intent.ACTION_MAIN, null);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/tests/Android.mk b/tests/Android.mk
index 1892357..5f083de 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -18,17 +18,22 @@
include $(CLEAR_VARS)
LOCAL_STATIC_JAVA_LIBRARIES := \
- android-ex-camera2 \
- android-support-v4 \
- android-support-test \
- guava \
- mockito-target \
- platform-test-annotations
+ android-ex-camera2 \
+ guava \
+ mockito-target \
+ android-support-test \
+ platform-test-annotations
+
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+ android-support-core-ui \
+ android-support-core-utils \
+ android-support-compat \
+ android-support-fragment
LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-java-files-under, ../src) \
- $(call all-proto-files-under, ../proto)
+ $(call all-java-files-under, src) \
+ $(call all-java-files-under, ../src) \
+ $(call all-proto-files-under, ../proto)
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/../proto/
@@ -36,19 +41,19 @@
LOCAL_RESOURCE_DIR := \
$(LOCAL_PATH)/res \
- $(LOCAL_PATH)/../res \
+ $(LOCAL_PATH)/../res
LOCAL_JAVA_LIBRARIES := \
- android.test.mock \
- android.test.base \
- android.test.runner \
- telephony-common
+ android.test.mock \
+ android.test.base \
+ android.test.runner \
+ telephony-common
LOCAL_USE_AAPT2 := true
LOCAL_AAPT_FLAGS := \
--auto-add-overlay \
- --extra-packages com.android.server.telecom:android.support.compat
+ --extra-packages com.android.server.telecom
LOCAL_JACK_FLAGS := --multi-dex native
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index 9302eaa..e304d34 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -442,6 +442,7 @@
@LargeTest
@Test
+ @FlakyTest
public void testIncomingCallFromBlockedNumberIsRejected() throws Exception {
String phoneNumber = "650-555-1212";
blockNumber(phoneNumber);
@@ -986,19 +987,37 @@
}
/**
- * Basic test to ensure that when there are other calls, we do not permit outgoing calls by a
- * self managed CS.
+ * Ensure if there is a holdable call ongoing we'll be able to place another call.
* @throws Exception
*/
@LargeTest
@Test
- public void testIsOutgoingCallPermittedOngoing() throws Exception {
- // Start a regular call; the self-managed CS can't make a call now.
+ public void testIsOutgoingCallPermittedOngoingHoldable() throws Exception {
+ // Start a regular call; the self-managed CS can make a call now since ongoing call can be
+ // held
IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
- assertFalse(mTelecomSystem.getTelecomServiceImpl().getBinder()
+ assertTrue(mTelecomSystem.getTelecomServiceImpl().getBinder()
+ .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle()));
+ }
+
+ /**
+ * Ensure if there is an unholdable call we can't place another call.
+ * @throws Exception
+ */
+ @LargeTest
+ @Test
+ public void testIsOutgoingCallPermittedOngoingUnHoldable() throws Exception {
+ // Start a regular call; the self-managed CS can't make a call now because the ongoing call
+ // can't be held.
+ mConnectionServiceFixtureA.mConnectionServiceDelegate.mCapabilities = 0;
+ IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+ mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+ assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+
+ assertTrue(mTelecomSystem.getTelecomServiceImpl().getBinder()
.isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle()));
}
@@ -1009,6 +1028,7 @@
*/
@LargeTest
@Test
+ @FlakyTest
public void testDisconnectSelfManaged() throws Exception {
// Add a self-managed call.
PhoneAccountHandle phoneAccountHandle = mPhoneAccountSelfManaged.getAccountHandle();
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
index 64f5fb8..f253d19 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
@@ -21,6 +21,7 @@
import com.android.server.telecom.CallAudioManager;
import com.android.server.telecom.CallAudioModeStateMachine;
+import com.android.server.telecom.CallAudioRouteStateMachine;
import org.junit.Before;
import org.junit.Test;
@@ -80,6 +81,51 @@
verify(mCallAudioManager).stopCallWaiting();
}
+ @SmallTest
+ @Test
+ public void testRegainFocusWhenHfpIsConnectedSilenced() throws Throwable {
+ CallAudioModeStateMachine sm = new CallAudioModeStateMachine(mAudioManager);
+ sm.setCallAudioManager(mCallAudioManager);
+ sm.sendMessage(CallAudioModeStateMachine.ABANDON_FOCUS_FOR_TESTING);
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+
+ resetMocks();
+ when(mCallAudioManager.startRinging()).thenReturn(false);
+
+ sm.sendMessage(CallAudioModeStateMachine.NEW_RINGING_CALL,
+ new CallAudioModeStateMachine.MessageArgs(
+ false, // hasActiveOrDialingCalls
+ true, // hasRingingCalls
+ false, // hasHoldingCalls
+ false, // isTonePlaying
+ false, // foregroundCallIsVoip
+ null // session
+ ));
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+
+ assertEquals(CallAudioModeStateMachine.RING_STATE_NAME, sm.getCurrentStateName());
+
+ verify(mAudioManager, never()).requestAudioFocusForCall(anyInt(), anyInt());
+ verify(mAudioManager, never()).setMode(anyInt());
+
+ verify(mCallAudioManager, never()).stopRinging();
+
+ verify(mCallAudioManager).stopCallWaiting();
+
+ when(mCallAudioManager.startRinging()).thenReturn(true);
+
+ sm.sendMessage(CallAudioModeStateMachine.RINGER_MODE_CHANGE);
+ waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
+
+ verify(mCallAudioManager).startRinging();
+ verify(mAudioManager).requestAudioFocusForCall(AudioManager.STREAM_RING,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
+ verify(mAudioManager).setMode(AudioManager.MODE_RINGTONE);
+ verify(mCallAudioManager).setCallAudioRouteFocusState(
+ CallAudioRouteStateMachine.RINGING_FOCUS);
+ }
+
+
private void resetMocks() {
reset(mCallAudioManager, mAudioManager);
}
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index 76048b7..d4c3d1d 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -82,6 +82,7 @@
@Mock WiredHeadsetManager mockWiredHeadsetManager;
@Mock StatusBarNotifier mockStatusBarNotifier;
@Mock Call fakeCall;
+ @Mock CallAudioManager mockCallAudioManager;
private CallAudioManager.AudioServiceFactory mAudioServiceFactory;
private static final int TEST_TIMEOUT = 500;
@@ -187,6 +188,7 @@
mockStatusBarNotifier,
mAudioServiceFactory,
CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED);
+ stateMachine.setCallAudioManager(mockCallAudioManager);
when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true);
@@ -229,6 +231,7 @@
mockStatusBarNotifier,
mAudioServiceFactory,
CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED);
+ stateMachine.setCallAudioManager(mockCallAudioManager);
Collection<BluetoothDevice> availableDevices = Collections.singleton(bluetoothDevice1);
when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
@@ -301,6 +304,7 @@
mockStatusBarNotifier,
mAudioServiceFactory,
CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED);
+ stateMachine.setCallAudioManager(mockCallAudioManager);
when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(true);
@@ -335,6 +339,7 @@
mockStatusBarNotifier,
mAudioServiceFactory,
CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED);
+ stateMachine.setCallAudioManager(mockCallAudioManager);
setInBandRing(false);
when(mockBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(false);
when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(false);
@@ -368,6 +373,12 @@
CallAudioRouteStateMachine.ACTIVE_FOCUS);
waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
verify(mockBluetoothRouteManager, times(1)).connectBluetoothAudio(null);
+
+ when(mockBluetoothRouteManager.getBluetoothAudioConnectedDevice())
+ .thenReturn(bluetoothDevice1);
+ stateMachine.sendMessage(CallAudioRouteStateMachine.BT_AUDIO_CONNECTED);
+ waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
+ verify(mockCallAudioManager, times(1)).onRingerModeChange();
}
@SmallTest
@@ -381,6 +392,7 @@
mockStatusBarNotifier,
mAudioServiceFactory,
CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED);
+ stateMachine.setCallAudioManager(mockCallAudioManager);
List<BluetoothDevice> availableDevices =
Arrays.asList(bluetoothDevice1, bluetoothDevice2, bluetoothDevice3);
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
index 345312e..609a488 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
@@ -146,6 +146,7 @@
@Mock WiredHeadsetManager mockWiredHeadsetManager;
@Mock StatusBarNotifier mockStatusBarNotifier;
@Mock Call fakeCall;
+ @Mock CallAudioManager mockCallAudioManager;
private CallAudioManager.AudioServiceFactory mAudioServiceFactory;
private static final int TEST_TIMEOUT = 500;
private AudioManager mockAudioManager;
@@ -218,6 +219,7 @@
mockStatusBarNotifier,
mAudioServiceFactory,
mParams.earpieceControl);
+ stateMachine.setCallAudioManager(mockCallAudioManager);
setupMocksForParams(stateMachine, mParams);
@@ -303,6 +305,7 @@
mockStatusBarNotifier,
mAudioServiceFactory,
mParams.earpieceControl);
+ stateMachine.setCallAudioManager(mockCallAudioManager);
// Set up bluetooth and speakerphone state
when(mockBluetoothRouteManager.isBluetoothAvailable()).thenReturn(
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index 6bba7af..ed2f6b1 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -23,8 +23,6 @@
import static org.mockito.ArgumentMatchers.anyChar;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
@@ -421,6 +419,7 @@
// GIVEN a CallsManager with ongoing call, and this call can be held
Call ongoingCall = addSpyCall();
doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// and a held call
@@ -430,11 +429,11 @@
mCallsManager.unholdCall(heldCall);
// THEN the ongoing call is held, and the focus request for incoming call is sent
- verify(ongoingCall).hold();
+ verify(ongoingCall).hold(any());
verifyFocusRequestAndExecuteCallback(heldCall);
// and held call is unhold now
- verify(heldCall).unhold();
+ verify(heldCall).unhold(any());
}
@SmallTest
@@ -446,6 +445,7 @@
// GIVEN a CallsManager with ongoing call, and this call can not be held
Call ongoingCall = addSpyCallWithConnectionService(connSvr1);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// and a held call which has different ConnectionService
@@ -455,13 +455,14 @@
mCallsManager.unholdCall(heldCall);
// THEN the ongoing call is disconnected, and the focus request for incoming call is sent
- verify(ongoingCall).disconnect();
+ verify(ongoingCall).disconnect(any());
verifyFocusRequestAndExecuteCallback(heldCall);
// and held call is unhold now
- verify(heldCall).unhold();
+ verify(heldCall).unhold(any());
}
+ @SmallTest
@Test
public void testUnholdCallWhenOngoingCallCanNotBeHeldAndHasSameConnectionService() {
ConnectionServiceWrapper connSvr = Mockito.mock(ConnectionServiceWrapper.class);
@@ -469,6 +470,7 @@
// GIVEN a CallsManager with ongoing call, and this call can not be held
Call ongoingCall = addSpyCallWithConnectionService(connSvr);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// and a held call which has different ConnectionService
@@ -478,11 +480,11 @@
mCallsManager.unholdCall(heldCall);
// THEN the ongoing call is held
- verify(ongoingCall).hold();
+ verify(ongoingCall).hold(any());
verifyFocusRequestAndExecuteCallback(heldCall);
// and held call is unhold now
- verify(heldCall).unhold();
+ verify(heldCall).unhold(any());
}
@SmallTest
@@ -491,6 +493,7 @@
// GIVEN a CallsManager with ongoing call, and this call can be held
Call ongoingCall = addSpyCall();
doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// WHEN answer an incoming call
@@ -528,13 +531,14 @@
@SmallTest
@Test
- public void testANswerCallWhenOngoingHasDifferentConnectionService() {
+ public void testAnswerCallWhenOngoingHasDifferentConnectionService() {
ConnectionServiceWrapper connSvr1 = Mockito.mock(ConnectionServiceWrapper.class);
ConnectionServiceWrapper connSvr2 = Mockito.mock(ConnectionServiceWrapper.class);
// GIVEN a CallsManager with ongoing call, and this call can not be held
Call ongoingCall = addSpyCallWithConnectionService(connSvr1);
doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
// WHEN answer an incoming call
@@ -551,6 +555,44 @@
@SmallTest
@Test
+ public void testAnswerCallWhenMultipleHeldCallsExisted() {
+ ConnectionServiceWrapper connSvr1 = Mockito.mock(ConnectionServiceWrapper.class);
+ ConnectionServiceWrapper connSvr2 = Mockito.mock(ConnectionServiceWrapper.class);
+
+ // Given an ongoing call and held call with the ConnectionService connSvr1. The
+ // ConnectionService connSvr1 can handle one held call
+ Call ongoingCall = addSpyCallWithConnectionService(connSvr1);
+ doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
+ Call heldCall = addSpyCallWithConnectionService(connSvr1);
+ doReturn(CallState.ON_HOLD).when(heldCall).getState();
+
+ // and other held call has difference ConnectionService
+ Call heldCall2 = addSpyCallWithConnectionService(connSvr2);
+ doReturn(CallState.ON_HOLD).when(heldCall2).getState();
+
+ // WHEN answer an incoming call which ConnectionService is connSvr1
+ Call incomingCall = addSpyCallWithConnectionService(connSvr1);
+ mCallsManager.answerCall(incomingCall, VideoProfile.STATE_AUDIO_ONLY);
+
+ // THEN the previous held call is disconnected
+ verify(heldCall).disconnect();
+
+ // and the ongoing call is held
+ verify(ongoingCall).hold();
+
+ // and the heldCall2 is not disconnected
+ verify(heldCall2, never()).disconnect();
+
+ // and the focus request is sent
+ verifyFocusRequestAndExecuteCallback(incomingCall);
+
+ // and the incoming call is answered
+ verify(incomingCall).answer(VideoProfile.STATE_AUDIO_ONLY);
+ }
+
+ @SmallTest
+ @Test
public void testAnswerCallWhenNoOngoingCallExisted() {
// GIVEN a CallsManager with no ongoing call.
@@ -565,6 +607,83 @@
verify(incomingCall).answer(VideoProfile.STATE_AUDIO_ONLY);
}
+ @SmallTest
+ @Test
+ public void testSetActiveCallWhenOngoingCallCanNotBeHeldAndFromDifferentConnectionService() {
+ ConnectionServiceWrapper connSvr1 = Mockito.mock(ConnectionServiceWrapper.class);
+ ConnectionServiceWrapper connSvr2 = Mockito.mock(ConnectionServiceWrapper.class);
+
+ // GIVEN a CallsManager with ongoing call, and this call can not be held
+ Call ongoingCall = addSpyCallWithConnectionService(connSvr1);
+ doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
+ doReturn(ongoingCall).when(mConnectionSvrFocusMgr).getCurrentFocusCall();
+
+ // and a new self-managed call which has different ConnectionService
+ Call newCall = addSpyCallWithConnectionService(connSvr2);
+ doReturn(true).when(newCall).isSelfManaged();
+
+ // WHEN active the new call
+ mCallsManager.markCallAsActive(newCall);
+
+ // THEN the ongoing call is disconnected, and the focus request for the new call is sent
+ verify(ongoingCall).disconnect();
+ verifyFocusRequestAndExecuteCallback(newCall);
+
+ // and the new call is active
+ assertEquals(CallState.ACTIVE, newCall.getState());
+ }
+
+ @SmallTest
+ @Test
+ public void testSetActiveCallWhenOngoingCallCanNotBeHeldAndHasSameConnectionService() {
+ ConnectionServiceWrapper connSvr = Mockito.mock(ConnectionServiceWrapper.class);
+
+ // GIVEN a CallsManager with ongoing call, and this call can not be held
+ Call ongoingCall = addSpyCallWithConnectionService(connSvr);
+ doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ doReturn(false).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
+ when(mConnectionSvrFocusMgr.getCurrentFocusCall()).thenReturn(ongoingCall);
+
+ // and a new self-managed call which has the same ConnectionService
+ Call newCall = addSpyCallWithConnectionService(connSvr);
+ doReturn(true).when(newCall).isSelfManaged();
+
+ // WHEN active the new call
+ mCallsManager.markCallAsActive(newCall);
+
+ // THEN the ongoing call isn't disconnected
+ verify(ongoingCall, never()).disconnect();
+ verifyFocusRequestAndExecuteCallback(newCall);
+
+ // and the new call is active
+ assertEquals(CallState.ACTIVE, newCall.getState());
+ }
+
+ @SmallTest
+ @Test
+ public void testSetActiveCallWhenOngoingCallCanBeHeld() {
+ // GIVEN a CallsManager with ongoing call, and this call can be held
+ Call ongoingCall = addSpyCall();
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_HOLD);
+ doReturn(true).when(ongoingCall).can(Connection.CAPABILITY_SUPPORT_HOLD);
+ doReturn(ongoingCall).when(mConnectionSvrFocusMgr).getCurrentFocusCall();
+
+ // and a new self-managed call
+ Call newCall = addSpyCall();
+ doReturn(true).when(newCall).isSelfManaged();
+
+ // WHEN active the new call
+ mCallsManager.markCallAsActive(newCall);
+
+ // THEN the ongoing call is held
+ verify(ongoingCall).hold();
+ verifyFocusRequestAndExecuteCallback(newCall);
+
+ // and the new call is active
+ assertEquals(CallState.ACTIVE, newCall.getState());
+ }
+
private Call addSpyCallWithConnectionService(ConnectionServiceWrapper connSvr) {
Call call = addSpyCall();
doReturn(connSvr).when(call).getConnectionService();
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index 9cc2b87..01d312b 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -437,6 +437,7 @@
MockitoAnnotations.initMocks(this);
when(mResources.getConfiguration()).thenReturn(mResourceConfiguration);
when(mResources.getString(anyInt())).thenReturn("");
+ when(mResources.getStringArray(anyInt())).thenReturn(new String[0]);
mResourceConfiguration.setLocale(Locale.TAIWAN);
// TODO: Move into actual tests
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFocusManagerTest.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFocusManagerTest.java
index bd855f9..3c2cc61 100644
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFocusManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFocusManagerTest.java
@@ -307,6 +307,20 @@
assertTrue(mFocusManagerUT.getAllCall().contains(mActiveCall));
}
+ @SmallTest
+ @Test
+ public void testNonFocusableDoesntChangeFocus() {
+ // GIVEN the ConnectionServiceFocusManager with the focus ConnectionService
+ requestFocus(mActiveCall, null);
+
+ // WHEN a new non-focusable call is added.
+ when(mNewCall.isFocusable()).thenReturn(false);
+ mCallsManagerListener.onCallAdded((Call) mNewCall);
+
+ // THEN the call focus isn't changed.
+ assertEquals(mActiveCall, mFocusManagerUT.getCurrentFocusCall());
+ }
+
private void requestFocus(CallFocus call, RequestFocusCallback callback) {
mCallsManagerListener.onCallAdded((Call) call);
mFocusManagerUT.requestFocus(call, callback);
@@ -344,6 +358,7 @@
Call call = Mockito.mock(Call.class);
when(call.getConnectionServiceWrapper()).thenReturn(connSvr);
when(call.getState()).thenReturn(state);
+ when(call.isFocusable()).thenReturn(true);
return call;
}
}
diff --git a/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java b/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
index be8b9b9..48319ad 100644
--- a/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
+++ b/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
@@ -16,6 +16,8 @@
package com.android.server.telecom.tests;
+import static com.android.server.telecom.tests.TelecomSystemTest.TEST_TIMEOUT;
+
import android.content.ComponentName;
import android.graphics.drawable.Icon;
import android.net.Uri;
@@ -27,6 +29,7 @@
import com.android.server.telecom.Call;
import com.android.server.telecom.CallIdMapper;
+import com.android.server.telecom.ConnectionServiceFocusManager;
import com.android.server.telecom.ConnectionServiceRepository;
import com.android.server.telecom.ConnectionServiceWrapper;
import com.android.server.telecom.CreateConnectionProcessor;
@@ -40,15 +43,20 @@
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
import java.util.ArrayList;
+import java.util.Arrays;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -70,6 +78,8 @@
CreateConnectionResponse mMockCreateConnectionResponse;
@Mock
Call mMockCall;
+ @Mock
+ ConnectionServiceFocusManager mConnectionServiceFocusManager;
CreateConnectionProcessor mTestCreateConnectionProcessor;
@@ -80,6 +90,22 @@
MockitoAnnotations.initMocks(this);
mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
+ when(mMockCall.getConnectionServiceFocusManager()).thenReturn(
+ mConnectionServiceFocusManager);
+ doAnswer(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ ConnectionServiceFocusManager.CallFocus focus =
+ (ConnectionServiceFocusManager.CallFocus) args[0];
+ ConnectionServiceFocusManager.RequestFocusCallback callback =
+ (ConnectionServiceFocusManager.RequestFocusCallback) args[1];
+ callback.onRequestFocusDone(focus);
+ return null;
+ }
+ }
+ ).when(mConnectionServiceFocusManager).requestFocus(any(), any());
+
mTestCreateConnectionProcessor = new CreateConnectionProcessor(mMockCall,
mMockConnectionServiceRepository, mMockCreateConnectionResponse,
mMockAccountRegistrar, mContext);
@@ -151,7 +177,8 @@
verify(mMockCall).setConnectionManagerPhoneAccount(eq(callManagerPAHandle));
verify(mMockCall).setTargetPhoneAccount(eq(pAHandle));
verify(mMockCall).setConnectionService(eq(service));
- verify(service).createConnection(eq(mMockCall), any(CreateConnectionResponse.class));
+ verify(service).createConnection(eq(mMockCall),
+ any(CreateConnectionResponse.class));
// Notify successful connection to call
CallIdMapper mockCallIdMapper = mock(CallIdMapper.class);
mTestCreateConnectionProcessor.handleCreateConnectionSuccess(mockCallIdMapper, null);
@@ -177,6 +204,8 @@
reset(mMockCall);
reset(service);
+ when(mMockCall.getConnectionServiceFocusManager()).thenReturn(
+ mConnectionServiceFocusManager);
// Notify that the ConnectionManager has denied the call.
when(mMockCall.getConnectionManagerPhoneAccount()).thenReturn(callManagerPAHandle);
when(mMockCall.getConnectionService()).thenReturn(service);
@@ -213,6 +242,8 @@
reset(mMockCall);
reset(service);
+ when(mMockCall.getConnectionServiceFocusManager()).thenReturn(
+ mConnectionServiceFocusManager);
// Notify that the ConnectionManager has rejected the call.
when(mMockCall.getConnectionManagerPhoneAccount()).thenReturn(callManagerPAHandle);
when(mMockCall.getConnectionService()).thenReturn(service);
@@ -268,6 +299,9 @@
mTestCreateConnectionProcessor.process();
reset(mMockCall);
reset(service);
+
+ when(mMockCall.getConnectionServiceFocusManager()).thenReturn(
+ mConnectionServiceFocusManager);
when(mMockCall.isEmergencyCall()).thenReturn(true);
// When Notify SIM connection fails, fall back to connection manager
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index 5963f8f..cbca5e1 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -17,6 +17,7 @@
package com.android.server.telecom.tests;
import static android.Manifest.permission.CALL_PHONE;
+import static android.Manifest.permission.CALL_PRIVILEGED;
import static android.Manifest.permission.MODIFY_PHONE_STATE;
import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
@@ -91,6 +92,9 @@
@RunWith(JUnit4.class)
public class TelecomServiceImplTest extends TelecomTestCase {
+
+ public static final String TEST_PACKAGE = "com.test";
+
public static class CallIntentProcessAdapterFake implements CallIntentProcessor.Adapter {
@Override
public void processOutgoingCallIntent(Context context, CallsManager callsManager,
@@ -645,6 +649,8 @@
.thenReturn(AppOpsManager.MODE_ALLOWED);
doReturn(PackageManager.PERMISSION_GRANTED)
.when(mContext).checkCallingPermission(CALL_PHONE);
+ doReturn(PackageManager.PERMISSION_DENIED)
+ .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE);
placeCallTestHelper(handle, extras, true);
@@ -660,6 +666,8 @@
.thenReturn(AppOpsManager.MODE_IGNORED);
doReturn(PackageManager.PERMISSION_GRANTED)
.when(mContext).checkCallingPermission(CALL_PHONE);
+ doReturn(PackageManager.PERMISSION_DENIED)
+ .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE);
placeCallTestHelper(handle, extras, false);
@@ -675,6 +683,8 @@
.thenReturn(AppOpsManager.MODE_ALLOWED);
doReturn(PackageManager.PERMISSION_DENIED)
.when(mContext).checkCallingPermission(CALL_PHONE);
+ doReturn(PackageManager.PERMISSION_DENIED)
+ .when(mContext).checkCallingPermission(CALL_PRIVILEGED);
mTSIBinder.placeCall(handle, extras, DEFAULT_DIALER_PACKAGE);
placeCallTestHelper(handle, extras, false);
@@ -684,7 +694,7 @@
boolean shouldNonEmergencyBeAllowed) {
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
verify(mUserCallIntentProcessor).processIntent(intentCaptor.capture(), anyString(),
- eq(shouldNonEmergencyBeAllowed));
+ eq(shouldNonEmergencyBeAllowed), eq(true));
Intent capturedIntent = intentCaptor.getValue();
assertEquals(Intent.ACTION_CALL, capturedIntent.getAction());
assertEquals(expectedHandle, capturedIntent.getData());
@@ -707,7 +717,7 @@
}
verify(mUserCallIntentProcessor, never())
- .processIntent(any(Intent.class), anyString(), anyBoolean());
+ .processIntent(any(Intent.class), anyString(), anyBoolean(), eq(true));
}
@SmallTest
@@ -843,8 +853,8 @@
Call call = mock(Call.class);
when(call.getState()).thenReturn(CallState.RINGING);
when(mFakeCallsManager.getForegroundCall()).thenReturn(call);
- assertTrue(mTSIBinder.endCall(null));
- verify(call).reject(false, null);
+ assertTrue(mTSIBinder.endCall(TEST_PACKAGE));
+ verify(call).reject(eq(false), isNull(), eq(TEST_PACKAGE));
}
@SmallTest
@@ -853,8 +863,8 @@
Call call = mock(Call.class);
when(call.getState()).thenReturn(CallState.ACTIVE);
when(mFakeCallsManager.getForegroundCall()).thenReturn(call);
- assertTrue(mTSIBinder.endCall(null));
- verify(call).disconnect();
+ assertTrue(mTSIBinder.endCall(TEST_PACKAGE));
+ verify(call).disconnect(eq(0L), eq(TEST_PACKAGE));
}
@SmallTest
@@ -864,8 +874,8 @@
when(call.getState()).thenReturn(CallState.ACTIVE);
when(mFakeCallsManager.getFirstCallWithState(any()))
.thenReturn(call);
- assertTrue(mTSIBinder.endCall(null));
- verify(call).disconnect();
+ assertTrue(mTSIBinder.endCall(TEST_PACKAGE));
+ verify(call).disconnect(eq(0L), eq(TEST_PACKAGE));
}
@SmallTest
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index b26143d..4cf7644 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.isNotNull;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
@@ -593,6 +594,9 @@
startOutgoingPhoneCallPendingCreateConnection(number, phoneAccountHandle,
connectionServiceFixture, initiatingUser, videoState);
+ verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
+ .createConnectionComplete(anyString(), any());
+
return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
phoneAccountHandle, connectionServiceFixture);
}
@@ -669,7 +673,7 @@
final UserHandle userHandle = initiatingUser;
Context localAppContext = mComponentContextFixture.getTestDouble().getApplicationContext();
new UserCallIntentProcessor(localAppContext, userHandle).processIntent(
- actionCallIntent, null, true /* hasCallAppOp*/);
+ actionCallIntent, null, true /* hasCallAppOp*/, false /* isLocal */);
// UserCallIntentProcessor's mContext.sendBroadcastAsUser(...) will call to an empty method
// as to not actually try to send an intent to PrimaryCallReceiver. We verify that it was
// called correctly in order to continue.
@@ -758,13 +762,16 @@
int startingNumCalls, PhoneAccountHandle phoneAccountHandle,
ConnectionServiceFixture connectionServiceFixture) throws Exception {
- assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size());
+ // Wait for the focus tracker.
+ waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
verify(connectionServiceFixture.getTestDouble())
.createConnection(eq(phoneAccountHandle), anyString(), any(ConnectionRequest.class),
eq(false)/*isIncoming*/, anyBoolean(), any());
// Wait for handleCreateConnectionComplete
waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
+ assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size());
+
// Wait for the callback in ConnectionService#onAdapterAttached to execute.
waitForHandlerAction(new Handler(Looper.getMainLooper()), TEST_TIMEOUT);
@@ -833,7 +840,6 @@
verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
.createConnectionComplete(anyString(), any());
-
// Process the CallerInfo lookup reply
mCallerInfoAsyncQueryFactoryFixture.mRequests.forEach(
CallerInfoAsyncQueryFactoryFixture.Request::reply);
@@ -847,7 +853,7 @@
anyString(),
eq(BlockedNumberContract.SystemContract.METHOD_SHOULD_SYSTEM_BLOCK_NUMBER),
eq(number),
- isNull(Bundle.class));
+ isNotNull(Bundle.class));
// For the case of incoming calls, Telecom connecting the InCall services and adding the
// Call is triggered by the async completion of the CallerInfoAsyncQuery. Once the Call
@@ -968,10 +974,10 @@
.answerCall(ids.mCallId, videoState);
if (!VideoProfile.isVideo(videoState)) {
- verify(connectionServiceFixture.getTestDouble())
+ verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
.answer(eq(ids.mConnectionId), any());
} else {
- verify(connectionServiceFixture.getTestDouble())
+ verify(connectionServiceFixture.getTestDouble(), timeout(TEST_TIMEOUT))
.answerVideo(eq(ids.mConnectionId), eq(videoState), any());
}
}