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