[automerger skipped] Import translations. DO NOT MERGE ANYWHERE am: a520091742 -s ours

am skip reason: subject contains skip directive

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/services/Telecomm/+/18396353

Change-Id: Ie08d559ca39b62b1475f646c807be704cdec224f
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c38fa4e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea
+*.iml
diff --git a/Android.bp b/Android.bp
index b7eb450..1b422aa 100644
--- a/Android.bp
+++ b/Android.bp
@@ -25,6 +25,9 @@
         ":Telecom-srcs",
         "proto/**/*.proto",
     ],
+    static_libs: [
+        "androidx.annotation_annotation",
+    ],
     resource_dirs: ["res"],
     proto: {
         type: "nano",
@@ -37,7 +40,6 @@
     optimize: {
         proguard_flags_files: ["proguard.flags"],
     },
-    defaults: ["SettingsLibDefaults"],
 }
 
 android_test {
@@ -52,7 +54,8 @@
         "androidx.legacy_legacy-support-core-utils",
         "androidx.core_core",
         "androidx.fragment_fragment",
-        "androidx.test.ext.junit"
+        "androidx.test.ext.junit",
+        "platform-compat-test-rules",
     ],
     srcs: [
         "tests/src/**/*.java",
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 45e3151..d376b6a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -31,6 +31,7 @@
     <uses-permission android:name="android.permission.BIND_INCALL_SERVICE"/>
     <uses-permission android:name="android.permission.BLUETOOTH"/>
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
+    <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED"/>
     <uses-permission android:name="android.permission.BROADCAST_CALLLOG_INFO"/>
     <uses-permission android:name="android.permission.BROADCAST_PHONE_ACCOUNT_REGISTRATION"/>
     <uses-permission android:name="android.permission.CALL_PRIVILEGED"/>
@@ -45,6 +46,10 @@
     <uses-permission android:name="android.permission.MODIFY_AUDIO_ROUTING"/>
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/>
     <uses-permission android:name="android.permission.READ_CALL_LOG"/>
+    <!-- Required to check for direct to voicemail, to load custom ringtones for incoming calls
+        which are specified on a per contact basis, and also to determine user preferred
+        PhoneAccountHandles for outgoing calls. -->
+    <uses-permission android:name="android.permission.READ_CONTACTS"/>
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/>
     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.READ_PROJECTION_STATE"/>
@@ -56,6 +61,8 @@
     <uses-permission android:name="android.permission.READ_BLOCKED_NUMBERS"/>
     <uses-permission android:name="android.permission.WRITE_BLOCKED_NUMBERS"/>
     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"/>
+    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
+    <uses-permission android:name="com.android.phone.permission.ACCESS_LAST_KNOWN_CELL_ID"/>
 
     <permission android:name="android.permission.BROADCAST_CALLLOG_INFO"
          android:label="Broadcast the call type/duration information"
@@ -256,7 +263,7 @@
         <activity android:name=".RespondViaSmsSettings"
              android:label="@string/respond_via_sms_setting_title"
              android:configChanges="orientation|screenSize|keyboardHidden"
-             android:theme="@style/Theme.Telecom.DialerSettings"
+             android:theme="@style/CallSettingsWithoutDividerTheme"
              android:process=":ui"
              android:exported="true">
             <intent-filter>
@@ -314,6 +321,9 @@
             <intent-filter>
                 <action android:name="android.bluetooth.IBluetoothHeadsetPhone"/>
             </intent-filter>
+            <intent-filter>
+                <action android:name="android.bluetooth.IBluetoothLeCallControlCallback" />
+            </intent-filter>
         </service>
 
         <service android:name=".components.TelecomService"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 2e14650..acab8ef 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -15,6 +15,38 @@
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
+    },
+    {
+      "name": "CtsTelephony2TestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsTelephony3TestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsSimRestrictedApisTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsTelephonyProviderTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
     }
   ],
   "presubmit-large": [
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 408021f..2707a08 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokkeer oproepe vanaf telefoonhokkies"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Onbekend"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokkeer oproepe vanaf onbekende bellers"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Onbeskikbaar"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokkeer oproepe waarvan die nommer nie beskikbaar is nie"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Oproepblokkering"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Oproepblokkering is gedeaktiveer"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Noodoproep gemaak"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Oproepblokkering is gedeaktiveer sodat noodeenhede jou kan kontak."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom-ontwikkelaarkieslys"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Oproepe kan nie gedurende \'n noodoproep geneem word nie."</string>
+    <string name="cancel" msgid="6733466216239934756">"Kanselleer"</string>
 </resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index a5fe872..b171af6 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"የክፍያ ስልኮች የሚመጡ ጥሪዎችን አግድ"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ያልታወቀ"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ካልታወቁ ደዋዮች የሚመጡ ጥሪዎችን አግድ"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"የለውም"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"ቁጥር የሌላቸውን ጥሪዎች አግድ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ጥሪን ማገድ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ጥሪ ማገድ ተሰናክሏል"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"የአደጋ ጊዜ ጥሪ ተደርጓል"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"የአደጋ ጊዜ ምላሽ ሰጪዎች እርስዎን ለማግኘት እንዲችሉ ጥሪ ማገድ ተሰናክሏል።"</string>
     <string name="developer_title" msgid="9146088855661672353">"የቴሌኮም ገንቢ ምናሌ"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ጥሪዎች በአደጋ ጊዜ ጥሪ ላይ ሊነሱ አይችሉም።"</string>
+    <string name="cancel" msgid="6733466216239934756">"ይቅር"</string>
 </resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 8dc37e7..d310271 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"حظر المكالمات من الهواتف المدفوعة"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"غير معروف"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"حظر المكالمات من المتّصلين مجهولي الهوية"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"غير معروف"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"حظر المكالمات عندما يكون الرقم غير معروف"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"حظر المكالمات"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"تم إيقاف حظر المكالمات"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"تم إجراء مكالمة طوارئ"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"تم إيقاف حظر المكالمات للسماح لمسؤولي استجابة الطوارئ بالاتصال بك."</string>
     <string name="developer_title" msgid="9146088855661672353">"قائمة مطوّر برامج الاتصالات"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"لا يمكن تلقّي المكالمات أثناء إجراء مكالمة طوارئ."</string>
+    <string name="cancel" msgid="6733466216239934756">"إلغاء"</string>
 </resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 0808bbf..33a56ad 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"পে\'ফ\'নৰ পৰা অহা কল অৱৰোধ কৰক"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"অজ্ঞাত"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"অচিনাক্ত কল কৰোঁতাৰ পৰা অহা কল অৱৰোধ কৰক"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"উপলব্ধ নহয়"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"নম্বৰ উপলব্ধ নোহোৱা কল অৱৰোধ কৰক"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"কল অৱৰোধ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"কল অৱৰোধ সুবিধাটো অক্ষম কৰি থোৱা আছে"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"জৰুৰীকালীন কল ম\'ড"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"আপোনাক যাতে জৰুৰীকালীন সেৱা প্ৰদানকাৰীসকলে যোগাযোগ কৰিব পাৰে তাৰ বাবে কল অৱৰোধ সুবিধাটো অক্ষম কৰি থোৱা হৈছে।"</string>
     <string name="developer_title" msgid="9146088855661672353">"দূৰ-সংযোগ সম্পৰ্কীয় বিকাশকৰ্তাৰ মেনু"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"কোনো জৰুৰীকালীন কলত থাকিলে কলসমূহ গ্ৰহণ কৰিব নোৱাৰি।"</string>
+    <string name="cancel" msgid="6733466216239934756">"বাতিল কৰক"</string>
 </resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index e38e653..61dbd67 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Ödənişli telefon zənglərini blok edin"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Naməlum"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Naməlum şəxslərdən gələn zəngləri blok edin"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Əlçatan deyil"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Nömrə əlçatan olmadıqda zəngləri bloklayın"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Zəng bloklanması"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Zəng bloklanmır"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Təcili zəng edildi"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Təcili xidmətlərin sizinlə əlaqə saxlamaları üçün zənglər bloklanmır."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom Tərtibatçı Menyusu"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Təcili zəng zamanı zəng edilə bilməz."</string>
+    <string name="cancel" msgid="6733466216239934756">"Ləğv edin"</string>
 </resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 5646cb4..85dc005 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokirajte pozive sa telefonskih govornica"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Nepoznati brojevi"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokirajte pozive neidentifikovanih pozivalaca"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Nedostupno"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokirajte pozive ako je broj nedostupan"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokiranje poziva"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokiranje poziva je onemogućeno"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Upućen je hitni poziv"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokiranje poziva je onemogućeno da bi hitne službe mogle da vas kontaktiraju."</string>
     <string name="developer_title" msgid="9146088855661672353">"Meni za programere Telecom-a"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Za vreme hitnog poziva nije moguće preuzimati druge pozive."</string>
+    <string name="cancel" msgid="6733466216239934756">"Otkaži"</string>
 </resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index b92f69a..07e0adf 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Блакіраваць выклікі з таксафонаў"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Невядомыя нумары"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Блакіраваць выклікі ад неапазнаных абанентаў"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Нумар невядомы"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Блакіраваць выклікі, калі нумар невядомы"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Блакіраванне выклікаў"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Блакіраванне выклікаў адключана"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Зроблены экстранны выклік"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Блакіраванне выклікаў было адключана, каб дазволіць аварыйнай брыгадзе звязацца з вамі."</string>
     <string name="developer_title" msgid="9146088855661672353">"Меню распрацоўшчыка Telecom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Падчас экстраннага выкліку іншыя выклікі прымаць немагчыма."</string>
+    <string name="cancel" msgid="6733466216239934756">"Скасаваць"</string>
 </resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 84e1a3d..4bc13bb 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Блокиране на обаждания от импулсни телефони"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Неизвестни"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Блокиране на обажданията от неидентифицирани обаждащи се"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Номерът не е налице"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Блокиране на обажданията, когато номерът не е налице"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Блокиране на обажданията"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Блокирането на обажданията е деактивирано"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Извършено бе спешно обаждане"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Блокирането на обажданията е деактивирано, за да могат службите за спешни случаи да се свържат с вас."</string>
     <string name="developer_title" msgid="9146088855661672353">"Меню за програмисти на Telecom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"По време на спешно обаждане не могат да се поемат обаждания."</string>
+    <string name="cancel" msgid="6733466216239934756">"Отказ"</string>
 </resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 3da181c..2ecd8e1 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"পাবলিক ফোন থেকে করা কল ব্লক করুন"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"অজানা"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"অচেনা নম্বর থেকে করা কল ব্লক করুন"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"উপলভ্য নেই"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"ব্লক করা কলের ক্ষেত্রে ফোন নম্বর দেখা যায় না"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"কল ব্লক করা"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"কল ব্লক করার বৈশিষ্ট্য বন্ধ করা হয়েছে"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"জরুরি অবস্থার কল করা হয়েছে"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"কল ব্লক করার বৈশিষ্ট্য বন্ধ করা হয়েছে যাতে জরুরি অবস্থার সাহায্যকারী ব্যক্তি আপনার সাথে যোগাযোগ করতে পারেন।"</string>
     <string name="developer_title" msgid="9146088855661672353">"টেলিকম ডেভেলপার মেনু"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"জরুরি কল চলাকালীন কোনও কল রিসিভ করা যাবে না।"</string>
+    <string name="cancel" msgid="6733466216239934756">"বাতিল করুন"</string>
 </resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index d56feeb..a1f9156 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokirajte pozive s telefonskih govornica"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Nepoznato"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokiraj pozive neidentificiranih pozivaoca"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Nedostupno"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokirajte pozive kod kojih nije dostupan broj"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokiranje poziva"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokiranje poziva je onemogućeno"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Upućen je hitni poziv"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokiranje poziva je onemogućeno kako bi se omogućilo osobama koje reagiraju u hitnim slučajevima da vas kontaktiraju."</string>
     <string name="developer_title" msgid="9146088855661672353">"Meni za programere iz telekoma"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Pozivi se ne mogu primati tokom hitnog poziva"</string>
+    <string name="cancel" msgid="6733466216239934756">"Otkaži"</string>
 </resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 7e2c81e..3978d69 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloqueja les trucades de telèfons públics"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Desconeguts"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloqueja les trucades de números no identificats"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"No disponibles"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bloqueja les trucades de números no disponibles"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bloqueig de trucades"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"El bloqueig de trucades s\'ha desactivat"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"S\'ha fet una trucada d\'emergència"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"El bloqueig de trucades s\'ha desactivat perquè els serveis d\'emergència puguin contactar amb tu."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menú per a desenvolupadors de telecomunicacions"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"No es poden respondre trucades durant una trucada d\'emergència."</string>
+    <string name="cancel" msgid="6733466216239934756">"Cancel·la"</string>
 </resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index ec6125b..3b144aa 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokovat hovory z veřejných telefonů"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Z nerozpoznaných čísel"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokovat hovory od nerozpoznaných volajících"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Neznámé"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokovat hovory z neznámých čísel"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokování hovorů"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokování hovorů bylo vypnuto"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Uskutečněno tísňové volání"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokování hovorů bylo vypnuto, aby vás mohli kontaktovat pracovníci tísňových služeb."</string>
     <string name="developer_title" msgid="9146088855661672353">"Nabídka pro vývojáře Telecomu"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Během tísňového volání není možné přijímat hovory."</string>
+    <string name="cancel" msgid="6733466216239934756">"Zrušit"</string>
 </resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index d4bc20e..70a19ce 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloker opkald fra mønttelefoner"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Ukendt"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloker opkald fra numre uden opkalds-id"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Ikke tilgængeligt"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bloker opkald, når nummeret ikke er tilgængeligt"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Opkaldsblokering"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Opkaldsblokering er deaktiveret"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Foretagne nødopkald"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Opkaldsblokering er blevet deaktiveret for at give nødnumre mulighed for at kontakte dig."</string>
     <string name="developer_title" msgid="9146088855661672353">"Udviklermenu for Telecom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Du kan ikke besvare opkald, mens du er i et nødopkald."</string>
+    <string name="cancel" msgid="6733466216239934756">"Annuller"</string>
 </resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index bcf62ed..e73ac10 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Anrufe von öffentlichen Telefonen blockieren"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Unbekannt"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Anrufe von nicht identifizierten Anrufern blockieren"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Nicht verfügbar"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Anrufe blockieren, bei denen die Telefonnummer nicht verfügbar ist"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Anrufblockierung"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Anrufblockierung deaktiviert"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Notruf abgesetzt"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Die Anrufblockierung wurde deaktiviert, damit Ersthelfer und Rettungskräfte dich kontaktieren können."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom-Entwicklermenü"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Während eines Notrufs kannst du keine Anrufe annehmen."</string>
+    <string name="cancel" msgid="6733466216239934756">"Abbrechen"</string>
 </resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index a4498ce..b677874 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Αποκλεισμός κλήσεων από καρτοτηλέφωνα"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Άγνωστος"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Αποκλεισμός κλήσεων από αγνώστους"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Μη διαθέσιμος"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Αποκλεισμός κλήσεων όταν ο αριθμός δεν είναι διαθέσιμος"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Φραγή κλήσεων"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Φραγή κλήσεων απενεργοποιημένη"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Πραγματοποιήθηκε κλήση έκτακτης ανάγκης"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Η φραγή κλήσεων έχει απενεργοποιηθεί, ώστε να επιτρέπεται σε άτομα που ανταποκρίνονται σε έκτακτες ανάγκες να επικοινωνούν μαζί σας."</string>
     <string name="developer_title" msgid="9146088855661672353">"Μενού προγραμματιστών τηλεπικοινωνιών"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Δεν είναι δυνατή η λήψη κλήσεων κατά τη διάρκεια κλήσης επείγουσας ανάγκης."</string>
+    <string name="cancel" msgid="6733466216239934756">"Ακύρωση"</string>
 </resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index d422e58..cef6db5 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Block calls from pay phones"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Unknown"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Block calls from unidentified callers"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Unavailable"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Block calls where the number is unavailable"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Call Blocking"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Call Blocking disabled"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Emergency call made"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Call Blocking has been disabled to allow emergency responders to contact you."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom Developer Menu"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Calls can not be taken while in an emergency call."</string>
+    <string name="cancel" msgid="6733466216239934756">"Cancel"</string>
 </resources>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index d422e58..cef6db5 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Block calls from pay phones"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Unknown"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Block calls from unidentified callers"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Unavailable"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Block calls where the number is unavailable"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Call Blocking"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Call Blocking disabled"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Emergency call made"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Call Blocking has been disabled to allow emergency responders to contact you."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom Developer Menu"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Calls can not be taken while in an emergency call."</string>
+    <string name="cancel" msgid="6733466216239934756">"Cancel"</string>
 </resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index d422e58..cef6db5 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Block calls from pay phones"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Unknown"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Block calls from unidentified callers"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Unavailable"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Block calls where the number is unavailable"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Call Blocking"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Call Blocking disabled"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Emergency call made"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Call Blocking has been disabled to allow emergency responders to contact you."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom Developer Menu"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Calls can not be taken while in an emergency call."</string>
+    <string name="cancel" msgid="6733466216239934756">"Cancel"</string>
 </resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index d422e58..cef6db5 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Block calls from pay phones"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Unknown"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Block calls from unidentified callers"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Unavailable"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Block calls where the number is unavailable"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Call Blocking"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Call Blocking disabled"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Emergency call made"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Call Blocking has been disabled to allow emergency responders to contact you."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom Developer Menu"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Calls can not be taken while in an emergency call."</string>
+    <string name="cancel" msgid="6733466216239934756">"Cancel"</string>
 </resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index f533e0a..da9faf3 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‎‎‎‏‏‎‏‏‏‎‎‏‎‎‎‏‏‎‏‏‎‏‎‎‎‏‎‎‏‎‏‎‎‏‏‎‏‏‎‏‎‏‎‎‎‎‎‏‎‎‎‏‎Block calls from pay phones‎‏‎‎‏‎"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‎‏‏‏‎‎‎‎‏‏‎‏‎‏‏‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‏‏‎‎‎‎Unknown‎‏‎‎‏‎"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‏‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‎‏‎‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‏‎‏‎Block calls from unidentified callers‎‏‎‎‏‎"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‎‎‏‎‎‎‎‎‎‎‎‏‏‎‏‏‎‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎Unavailable‎‏‎‎‏‎"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‏‎Block calls where the number is unavailable‎‏‎‎‏‎"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‏‏‎‎‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‏‏‏‎Call Blocking‎‏‎‎‏‎"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‎‎‎‎‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎‏‏‏‏‎‎‎‏‏‎‏‎‏‏‎Call Blocking disabled‎‏‎‎‏‎"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‏‎‎‏‏‏‏‎‎‎‏‏‎‏‎‏‏‎‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‏‎Emergency call made‎‏‎‎‏‎"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‏‏‏‏‎‏‎‏‏‎‎Call Blocking has been disabled to allow emergency responders to contact you.‎‏‎‎‏‎"</string>
     <string name="developer_title" msgid="9146088855661672353">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎Telecom Developer Menu‎‏‎‎‏‎"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‏‎‏‎‏‎Calls can not be taken while in an emergency call.‎‏‎‎‏‎"</string>
+    <string name="cancel" msgid="6733466216239934756">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‎‎‏‎‎‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‏‎‎‎Cancel‎‏‎‎‏‎"</string>
 </resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 9da169d..ac0b22c 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquear llamadas provenientes de teléfonos públicos"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Desconocido"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquear llamadas de emisores desconocidos"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"No disponible"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bloquear llamadas con número no disponible"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bloqueo de llamadas"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Se inhabilitó el bloqueo de llamadas"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Se realizó una llamada de emergencia"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Se inhabilitó el bloqueo de llamadas para permitir que los servicios de emergencia se comuniquen contigo."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menú para desarrolladores de Telecom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"No puedes contestar llamadas mientras estés en una llamada de emergencia."</string>
+    <string name="cancel" msgid="6733466216239934756">"Cancelar"</string>
 </resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 68499c2..1d2aa15 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquea las llamadas de teléfonos públicos"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Desconocidos"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquea las llamadas de números desconocidos"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"No disponible"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bloquear llamadas en las que el número no esté disponible"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bloqueo de llamadas"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Se ha inhabilitado el bloqueo de llamadas"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Se ha hecho una llamada de emergencia"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Se ha inhabilitado el bloqueo de llamadas para que los servicios de emergencia puedan ponerse en contacto contigo."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menú para desarrolladores de telecomunicaciones"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"No se pueden responder llamadas durante una llamada de emergencia."</string>
+    <string name="cancel" msgid="6733466216239934756">"Cancelar"</string>
 </resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 34bd333..4075aec 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Kõnede blokeerimine telefoniautomaatidest"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Tundmatud"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Kõnede blokeerimine tuvastamata helistajatelt"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Pole kättesaadav"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Kõned blokeeritakse numbritelt, mis ei ole kättesaadavad"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Kõnede blokeerimine"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Kõnede blokeerimine on keelatud"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Tehti hädaabikõne"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Kõnede blokeerimine on keelatud, et lubada hädaabiteenustel teiega ühendust võtta."</string>
     <string name="developer_title" msgid="9146088855661672353">"Teenuse Telecom arendaja menüü"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Hädaabikõne ajal ei saa kõnesid vastu võtta."</string>
+    <string name="cancel" msgid="6733466216239934756">"Tühista"</string>
 </resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index b9c3a67..120dd6e 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokeatu telefono publikoen deiak"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Ezezagunak"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokeatu identifikatu gabeko deitzaileen deiak"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Zenbakia agerian ez dutenak"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokeatu zenbakia agerian ez duten deiak"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Deiak blokeatzeko aukera"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Desgaitu da deiak blokeatzeko aukera"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Larrialdi-deia egin da"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Desgaitu da deiak blokeatzeko aukera, larrialdietako zerbitzuak zurekin harremanetan jarri ahal daitezen."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telekomunikazioen garatzaileen menua"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Ezin duzu hartu deirik larrialdi-dei bat abian den bitartean."</string>
+    <string name="cancel" msgid="6733466216239934756">"Utzi"</string>
 </resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 991ee5b..7425bfc 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"مسدود کردن تماس‌ها از تلفن‌های عمومی"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ناشناس"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"مسدود کردن تماس‌های تماس‌گیرندگان ناشناس"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"دردسترس نیست"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"وقتی شماره دردسترس نباشد، تماس‌ها مسدود می‌شود"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"مسدود کردن تماس"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"مسدود کردن تماس غیرفعال شد"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"تماس اضطراری برقرار شد"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"مسدود کردن تماس غیرفعال شده است تا پاسخ‌دهندگان اضطراری بتوانند با شما تماس بگیرند."</string>
     <string name="developer_title" msgid="9146088855661672353">"‏منوی برنامه‌نویس Telecom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"درحین برقراری تماسی اضطراری، نمی‌توان به تماس‌ها پاسخ داد."</string>
+    <string name="cancel" msgid="6733466216239934756">"لغو"</string>
 </resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 3ad0c23..c04c43e 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Estä yleisöpuhelimista soitetut puhelut"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Tuntematon"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Estä tuntemattomien soittajien puhelut"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Ei saatavilla"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Estä puhelut, kun numero ei ole saatavilla"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Puhelujen esto"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Puhelujen esto poistettu käytöstä"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Hätäpuhelu soitettu"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Puhelujen esto on poistettu käytöstä, jotta pelastusviranomaiset voivat soittaa puhelimeesi."</string>
     <string name="developer_title" msgid="9146088855661672353">"Televiestinnän kehittäjävalikko"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Puheluita ei voi välittää hätäpuhelun aikana."</string>
+    <string name="cancel" msgid="6733466216239934756">"Peru"</string>
 </resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 46bc45a..0a04f2c 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquer les appels provenant de téléphones publics"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Inconnu"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquer les appels provenant d\'appelants non identifiés"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Indisponible"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bloquer les appels dont le numéro est indisponible"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blocage des appels"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blocage des appels désactivé"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Appel d\'urgence effectué"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Le blocage des appels a été désactivé pour permettre aux intervenants d\'urgence de communiquer avec vous."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menu Telecom Developer"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Les appels ne peuvent pas être pris pendant un appel d\'urgence."</string>
+    <string name="cancel" msgid="6733466216239934756">"Annuler"</string>
 </resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index bee3695..4396bd5 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquez les appels provenant de cabines téléphoniques"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Numéros inconnus"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquer les appels provenant de personnes non identifiées"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Non disponible"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bloquer les appels lorsque le numéro n\'est pas disponible"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blocage d\'appels"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blocage d\'appels désactivé"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Appel d\'urgence"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Le blocage d\'appels a été désactivé pour que les services d\'urgence puissent vous contacter."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menu Telecom Developer"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Impossible de prendre un appel au cours d\'un appel d\'urgence."</string>
+    <string name="cancel" msgid="6733466216239934756">"Annuler"</string>
 </resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index cc5efc2..ef3465d 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquea as chamadas de teléfonos públicos"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Descoñecido"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquear as chamadas de emisores non identificados"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Non dispoñible"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bloquea as chamadas de números non dispoñibles"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bloqueo de chamadas"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Desactivouse o bloqueo de chamadas"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Realizouse unha chamada de emerxencia"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Desactivouse o bloqueo de chamadas parar permitir que os servizos de emerxencias se poidan poñer en contacto contigo."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menú para programadores de telecomunicacións"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Non se pode responder ás chamadas durante unha chamada de emerxencia."</string>
+    <string name="cancel" msgid="6733466216239934756">"Cancelar"</string>
 </resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index e04f38c..2729d22 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"પે ફોન પરના કૉલ બ્લૉક કરો"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"અજાણ્યા"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"અજાણ્યા કૉલરના કૉલ બ્લૉક કરો"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"અનુપલબ્ધ"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"જ્યાં નંબર અનુપલબ્ધ હોય ત્યાં કૉલ બ્લૉક કરો"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"કૉલ બ્લૉક કરી રહ્યાં છીએ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"કૉલ બ્લૉક કરવાનું બંધ કરવામાં આવ્યું છે"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"કટોકટીનો કૉલ કર્યો"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"કટોકટીમાં પ્રતિસાદ કરનારાઓ તમારો સંપર્ક કરી શકે તે માટે કૉલ બ્લૉક કરવાનું બંધ કરવામાં આવ્યું છે."</string>
     <string name="developer_title" msgid="9146088855661672353">"ટેલિકોમ ડેવલપર મેનૂ"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ઇમર્જન્સી કૉલ ચાલુ હોય, ત્યારે બીજા કોઈ કૉલ લઈ શકાતા નથી."</string>
+    <string name="cancel" msgid="6733466216239934756">"રદ કરો"</string>
 </resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 94fcdb1..3013ee9 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"पे फ़ोन से आने वाले कॉल पर रोक लगाएं"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"अज्ञात"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"अनजान कॉलर के कॉल पर रोक लगाएं"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"उपलब्ध नहीं है"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"ऐसे कॉल ब्लॉक करें जिनका नंबर उपलब्ध नहीं है"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"कॉल पर रोक"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"कॉल पर रोक लगाने की सुविधा बंद है"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"आपातकालीन कॉल किया गया"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"आपातकालीन सहायता कर्मचारी आपसे संपर्क कर सकें, इसलिए कॉल पर रोक लगाने की सुविधा बंद कर दी गई है."</string>
     <string name="developer_title" msgid="9146088855661672353">"टेलीकॉम डेवलपर मेन्यू"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"आपातकालीन कॉल के दौरान कॉल नहीं उठाया जा सकता."</string>
+    <string name="cancel" msgid="6733466216239934756">"रद्द करें"</string>
 </resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 7928978..e84fe62 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokirajte pozive s telefonskih govornica"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Nepoznato"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokirajte pozive nepoznatih pozivatelja"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Nedostupno"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokiranje poziva s nedostupnim brojem"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokiranje poziva"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokiranje poziva je onemogućeno"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Hitni je poziv upućen"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokiranje poziva onemogućeno je da bi vas mogli kontaktirati djelatnici hitnih službi."</string>
     <string name="developer_title" msgid="9146088855661672353">"Izbornik Telecom Developer"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Pozivi se ne mogu primiti tijekom hitnog poziva."</string>
+    <string name="cancel" msgid="6733466216239934756">"Odustani"</string>
 </resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 7bbff68..75b8190 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"A nyilvános telefonokról bejövő hívások letiltása"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Ismeretlen"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"A nem azonosított hívók letiltása"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Nem áll rendelkezésre"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Azoknak a hívásoknak a letiltása, amelyeknél a szám nem áll rendelkezésre"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Hívásletiltás"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Hívásletiltás kikapcsolva"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Segélyhívás indítva"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"A hívásletiltás ki van kapcsolva, hogy a segélyszolgálatok kapcsolatba léphessenek Önnel."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telekommunikációs fejlesztői menü"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Segélyhívás közben nem lehet hívást fogadni."</string>
+    <string name="cancel" msgid="6733466216239934756">"Mégse"</string>
 </resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index f702f66..f511fcd 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Արգելափակել ավտոմատ հեռախոսներից եկող զանգերը"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Անհայտ համարներ"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Արգելափակել անհայտ համարներից եկող զանգերը"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Անհասանելի է"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Արգելափակել զանգերը, երբ համարն անհասանելի է"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Զանգերի արգելափակում"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Զանգերի արգելափակումն անջատված է"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Կատարվեց շտապ կանչ"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Զանգերի արգելափակումն անջատվել է, որպեսզի արտակարգ ծառայությունները կարողանան ձեզ զանգել:"</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom-ի մշակողի ընտրացանկ"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Շտապ կանչի ժամանակ այլ զանգեր չեք կարող ընդւնել։"</string>
+    <string name="cancel" msgid="6733466216239934756">"Չեղարկել"</string>
 </resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index d71cd15..2465076 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokir panggilan dari telepon umum"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Tidak dikenal"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokir panggilan dari penelepon yang tidak dikenal"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Tidak tersedia"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokir panggilan yang nomornya tidak tersedia"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Pemblokiran Panggilan"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Pemblokiran Panggilan dinonaktifkan"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Panggilan darurat dibuat"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Pemblokiran Panggilan dinonaktifkan untuk mengizinkan penjawab darurat menghubungi Anda."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menu Developer Telecom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Panggilan tidak dapat diterima saat sedang melakukan panggilan darurat."</string>
+    <string name="cancel" msgid="6733466216239934756">"Batal"</string>
 </resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 2c5ef10..fe6cf7f 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Loka fyrir símtöl úr almenningssímum"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Óþekkt"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Loka fyrir símtöl frá óþekktum hringjendum"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Ekki í boði"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Loka fyrir símtöl þegar númerið er ekki tiltækt"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Lokað fyrir símtöl"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Ekki er lokað fyrir símtöl"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Neyðarsímtal var hringt"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Slökkt hefur verið á „Lokað fyrir símtöl“ svo neyðarþjónustuaðilar geti haft samband við þig."</string>
     <string name="developer_title" msgid="9146088855661672353">"Forritaravalmynd fyrir fjarskipti"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Ekki er hægt að svara símtölum meðan á neyðarsímtali stendur."</string>
+    <string name="cancel" msgid="6733466216239934756">"Hætta við"</string>
 </resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 97a23d0..dd9ccbe 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blocca le chiamate dalle cabine telefoniche"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Sconosciuto"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blocca le chiamate da chiamanti non identificati"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Non disponibile"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blocca le chiamate quando il numero non è disponibile"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blocco delle chiamate"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blocco delle chiamate disattivato"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Chiamata di emergenza effettuata"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Il blocco delle chiamate è stato disattivato per consentire ai servizi di emergenza di contattarti."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menu sviluppatore telecomunicazioni"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Impossibile accettare una chiamata durante una chiamata di emergenza."</string>
+    <string name="cancel" msgid="6733466216239934756">"Annulla"</string>
 </resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 8811efb..2f37355 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"חסימת שיחות מטלפונים ציבוריים"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"מספרים לא ידועים"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"חסימת שיחות ממספרים לא מזוהים"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"מספרים לא ידועים"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"חסימת שיחות ממספרים לא ידועים"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"חסימת שיחות"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"חסימת השיחות הושבתה"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"בוצעה שיחת חירום"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"חסימת השיחות הושבתה כדי לאפשר לצוותי עזרה ראשונה להתקשר אליך."</string>
     <string name="developer_title" msgid="9146088855661672353">"תפריט למפתחי מערכות תקשורת"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"אי אפשר לענות לשיחות אחרות בזמן שיחת חירום."</string>
+    <string name="cancel" msgid="6733466216239934756">"ביטול"</string>
 </resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index c59d551..50956bf 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"公衆電話からの着信をブロック"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"不明な発信者"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"不明な発信者からの着信をブロック"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"発信者番号が不明"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"発信者番号が不明な通話がブロックされます"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"着信のブロック"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"着信のブロックを無効にしました"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"緊急通報"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"着信のブロックを無効して、救急隊員などがあなたに連絡できるようにしました。"</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom デベロッパー メニュー"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"緊急通報中は、他の電話を受けることができません。"</string>
+    <string name="cancel" msgid="6733466216239934756">"キャンセル"</string>
 </resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index f3ac3d6..b6fe683 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ზარების დაბლოკვა საზოგადოებრივი ტელეფონებიდან"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"უცნობი"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ზარების დაბლოკვა ამოუცნობი აბონენტებისგან"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"მიუწვდომელი"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"ზარების დაბლოკვა, რომლებშიც ნომერი მიუწვდომელია"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ზარების დაბლოკვა"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ზარების დაბლოკვა გათიშულია"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"საგანგებო ზარი შესრულდა"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ზარების დაბლოკვა გათიშულია, რათა საგანგებო სიტუაციებში მოპასუხეებმა თქვენთან დაკავშირება შეძლონ"</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom-ის დეველოპერის მენიუ"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"გადაუდებელი ზარის დროს ზარების მიღება შეუძლებელია."</string>
+    <string name="cancel" msgid="6733466216239934756">"გაუქმება"</string>
 </resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 22f7d28..aaa8229 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Ақылы телефон қоңырауларын бөгеу"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Белгісіз"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Белгісіз қоңырауларды бөгеу"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Қолжетімсіз"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Нөмір қолжетімсіз болған кезде қоңырауларды бөгеу"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Қоңырауды бөгеу"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Қоңырау бөгеу функциясы өшірулі"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Төтенше жағдай қоңырауы шалынды"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Төтенше жағдай қызметтері сізге хабарласа алуы үшін, қоңырау бөгеу функциясы өшірілді."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom Developer мәзірі"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Құтқару қызметімен сөйлесіп жатқанда, басқа қоңырауларды қабылдай алмайсыз."</string>
+    <string name="cancel" msgid="6733466216239934756">"Бас тарту"</string>
 </resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 7186180..82deb2a 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ទប់ស្កាត់​ការហៅ​ពី​ទូរសព្ទ​ដែល​បង់ប្រាក់"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"មិនស្គាល់"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ទប់ស្កាត់​ការហៅ​ទូរសព្ទពី​អ្នក​ហៅ​ដែល​មិន​ស្គាល់អត្តសញ្ញាណ"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"មិន​អាច​ប្រើ​បាន"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"ទប់ស្កាត់​ការហៅ​ទូរសព្ទ​នៅ​កន្លែង​ដែល​មិន​អាច​ប្រើ​លេខ​នេះ​បាន"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ការទប់ស្កាត់​ការហៅ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"បាន​បិទ​ការទប់ស្កាត់​ការហៅ"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"បាន​ធ្វើការហៅ​បន្ទាន់"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ការទប់ស្កាត់​ការហៅ​ត្រូវបាន​បិទ ដើម្បី​អនុញ្ញាត​ឲ្យ​អ្នក​ឆ្លើយតប​បន្ទាន់​អាច​ទាក់ទង​អ្នក​បាន។"</string>
     <string name="developer_title" msgid="9146088855661672353">"ម៉ឺនុយ​អ្នក​អភិវឌ្ឍន៍​ទូរគមនាគមន៍"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"មិន​អាច​ទទួល​ការហៅ​ទូរសព្ទ​បាន​ទេ ពេល​កំពុង​ហៅ​ទៅ​លេខ​សង្គ្រោះ​បន្ទាន់។"</string>
+    <string name="cancel" msgid="6733466216239934756">"បោះបង់"</string>
 </resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index acee7a9..bf5ea45 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ಪಾವತಿ ಫೋನ್‌ಗಳಿಂದ ಕರೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ಅಪರಿಚಿತ"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ಗುರುತಿಸದ ಕರೆದಾರರಿಂದ ಕರೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"ಲಭ್ಯವಿಲ್ಲ"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"ಸಂಖ್ಯೆ ಲಭ್ಯವಿಲ್ಲದಿದ್ದಾಗ ಕರೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ಕರೆ ನಿರ್ಬಂಧಿಸುವಿಕೆ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ಕರೆ ನಿರ್ಬಂಧಿಸುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"ತುರ್ತು ಕರೆ ಮಾಡಲಾಗಿದೆ"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ನಿಮ್ಮನ್ನು ಸಂಪರ್ಕಿಸುವುದಕ್ಕಾಗಿ ತುರ್ತಾಗಿ ಪ್ರತಿಕ್ರಿಯಿಸುವವರ ಸಂಖ್ಯೆಯನ್ನು ನಿರ್ಬಂಧಿಸುವುದನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
     <string name="developer_title" msgid="9146088855661672353">"ಟೆಲಿಕಾಂ ಡೆವಲಪರ್ ಮೆನು"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ತುರ್ತು ಕರೆಯಲ್ಲಿರುವಾಗ ಕರೆಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+    <string name="cancel" msgid="6733466216239934756">"ರದ್ದುಮಾಡಿ"</string>
 </resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 0134017..d51eb1c 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"공중전화에서 걸려 온 통화 차단"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"알 수 없는 발신자"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"신원을 확인할 수 없는 발신자로부터 걸려 온 통화 차단"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"확인할 수 없음"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"확인할 수 없는 번호로 걸려온 전화를 차단합니다."</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"통화 차단"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"통화 차단이 사용 중지됨"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"긴급 통화가 사용됨"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"응급 구조 요원이 연락할 수 있도록 통화 차단이 사용 중지되었습니다."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom 개발자 메뉴"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"긴급 전화 중에는 전화를 받을 수 없습니다."</string>
+    <string name="cancel" msgid="6733466216239934756">"취소"</string>
 </resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index ad7a017..ec00c40 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Телефон-автоматтардан келген чалууларды бөгөттөө"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Белгисиз"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Белгисиз чалуучуларды бөгөттөө"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Белгисиз номер"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Номер белгисиз болсо, чалууларды бөгөттөө"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Чалууну бөгөттөө"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Чалууну бөгөттөө өчүрүлдү"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Шашылыш чалуу аткарылды"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Өзгөчө кырдаалдардагы кызматчылар сиз менен байланышуусу үчүн чалууну бөгөттөө функциясы өчүрүлгөн."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom иштеп чыгуучусунун менюсу"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Шашылыш учурунда чалуулар кабыл алынбайт."</string>
+    <string name="cancel" msgid="6733466216239934756">"Жокко чыгаруу"</string>
 </resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 8118fa8..15cdb69 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ບລັອກສາຍຈາກຕູ້ໂທ"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ບໍ່ຮູ້ຈັກ"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ບລັອກສາຍຈາກຜູ້ໂທທີ່ລະບຸຕົວຕົນບໍ່ໄດ້"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"ບໍ່ສາມາດໃຊ້ໄດ້"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"ບລັອກການໂທເມື່ອໝາຍເລກບໍ່ສາມາດໃຊ້ໄດ້"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ການບລັອກສາຍ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ປິດການບລັອກສາຍແລ້ວ"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"ໂທສຸກເສີນແລ້ວ"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ປິດການບລັອກສາຍແລ້ວເພື່ອອະນຸຍາດໃຫ້ສາຍສຸກເສີນສາມາດຕິດຕໍ່ຫາທ່ານໄດ້."</string>
     <string name="developer_title" msgid="9146088855661672353">"ເມນູນັກພັດທະນາໂທລະຄົມ"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ບໍ່ສາມາດໂທໄດ້ໃນຂະນະທີ່ຢູ່ໃນການໂທສຸກເສີນ."</string>
+    <string name="cancel" msgid="6733466216239934756">"ຍົກເລີກ"</string>
 </resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 34c2997..2549087 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokuoti skambučius iš taksofonų"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Nežinomas"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokuoti skambučius nuo nenustatytų skambintojų"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Nežinomas numeris"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokuoti skambučius, jei numeris nežinomas"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Skambučių blokavimas"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Skambučių blokavimas išjungtas"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Atliktas skambutis pagalbos numeriu"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Skambučių blokavimas išjungtas, kad pagalbos numeriu atsiliepusiems žmonėms būtų leidžiama su jumis susisiekti."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telekomunikacijų kūrėjų meniu"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Atliekant skambutį pagalbos numeriu negalima atsiliepti į kitus skambučius."</string>
+    <string name="cancel" msgid="6733466216239934756">"Atšaukti"</string>
 </resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 65fe942..b8d6b51 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloķēt zvanus no taksofoniem"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Nezināms"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloķēt zvanus no neidentificētiem zvanītājiem"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Nav pieejams"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bloķēt zvanus, ja numurs nav pieejams"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Zvanu bloķēšana"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Zvanu bloķēšana atspējota"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Ārkārtas zvans ir veikts"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Zvanu bloķēšana ir atspējota, lai ļautu ar jums sazināties avārijas dienestu darbiniekiem."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom izstrādātāja izvēlne"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Ārkārtas izsaukuma laikā nevar pieņemt zvanus."</string>
+    <string name="cancel" msgid="6733466216239934756">"Atcelt"</string>
 </resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 87de64f..c425177 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Блокирај повици од телефонски говорници"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Непознато"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Блокирај повици од неидентификувани повикувачи"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Недостапно"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Блокирај ги повиците од недостапен број"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Блокирање повици"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Блокирањето повици е оневозможено"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Воспоставен е итен повик"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Блокирањето повици е оневозможено за да им се овозможи на лицата од службите за итни случаи да контактираат со вас."</string>
     <string name="developer_title" msgid="9146088855661672353">"Програмерско мени за телекомуникации"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Не може да примате повици во тек на итен повик."</string>
+    <string name="cancel" msgid="6733466216239934756">"Откажи"</string>
 </resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 36bb494..47b4aa6c 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"പേ ഫോണുകളിൽ നിന്നുള്ള കോളുകൾ ബ്ലോക്ക് ചെയ്യുക"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"അജ്ഞാതം"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"തിരിച്ചറിയാത്ത കോളർമാരിൽ നിന്നുള്ള കോളുകൾ ബ്ലോക്ക് ചെയ്യുക"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"ലഭ്യമല്ല"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"നമ്പർ ലഭ്യമല്ലാത്ത കോളുകൾ ബ്ലോക്ക് ചെയ്യുക"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"കോൾ ബ്ലോക്ക് ചെയ്യൽ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"കോൾ ബ്ലോക്ക് ചെയ്യൽ പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"അടിയന്തര കോൾ ചെയ്തു"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"അടിയന്തരമായി ബന്ധപ്പെടുന്നവരെ അനുവദിക്കാനായി കോൾ ബ്ലോക്ക് ചെയ്യൽ പ്രവർത്തനരഹിതമാക്കി."</string>
     <string name="developer_title" msgid="9146088855661672353">"ടെലികോം ഡെവലപ്പര്‍ മെനു"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"അടിയന്തര കോളിലായിരിക്കുമ്പോൾ കോളുകൾ എടുക്കാനാവില്ല."</string>
+    <string name="cancel" msgid="6733466216239934756">"റദ്ദാക്കുക"</string>
 </resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index d1f5273..4ba44f3 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Төлбөртэй утаснаас залгасан дуудлагуудыг хориглох"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Тодорхойгүй"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Тодорхойгүй дугаараас ирсэн дуудлагуудыг блоклох"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Боломжгүй"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Дугаар нь боломжгүй дуудлагуудыг блоклох"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Дуудлага хориглох"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Дуудлага хориглохыг идэвхгүй болгосон"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Яаралтай тусламжийн дуудлага хийсэн"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Яаралтай тусламжийнханд тантай холбогдохыг зөвшөөрөхийн тулд дуудлага хориглохыг идэвхгүй болгосон."</string>
     <string name="developer_title" msgid="9146088855661672353">"Телеком хөгжүүлэгчийн цэс"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Яаралтай дуудлагын үеэр дуудлага авах боломжгүй."</string>
+    <string name="cancel" msgid="6733466216239934756">"Цуцлах"</string>
 </resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index f9ac70b..1def59a 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -70,15 +70,15 @@
     <string name="add_blocked_dialog_body" msgid="8599974422407139255">"यावरील कॉल आणि एसएमएस ब्लॉक करा"</string>
     <string name="add_blocked_number_hint" msgid="8769422085658041097">"फोन नंबर"</string>
     <string name="block_button" msgid="485080149164258770">"ब्लॉक करा"</string>
-    <string name="non_primary_user" msgid="315564589279622098">"फक्त डिव्हाइस मालक अवरोधित केलेले नंबर पाहू आणि व्यवस्थापित करू शकतो."</string>
+    <string name="non_primary_user" msgid="315564589279622098">"फक्त डिव्हाइस मालक ब्लॉक केलेले नंबर पाहू आणि व्यवस्थापित करू शकतो."</string>
     <string name="delete_icon_description" msgid="5335959254954774373">"ब्लॉक करा"</string>
-    <string name="blocked_numbers_butter_bar_title" msgid="582982373755950791">"अवरोधित करणे तात्पुरते बंद आहे"</string>
-    <string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"तुम्ही एखादा आणीबाणी नंबर डायल केला किंवा त्यावर मजकूर पाठविल्यानंतर, आणीबाणी सेवा आपल्याशी संपर्क साधू शकतात हे सुनिश्चित करण्यासाठी अवरोधित करणे बंद करते."</string>
+    <string name="blocked_numbers_butter_bar_title" msgid="582982373755950791">"ब्लॉक करणे तात्पुरते बंद आहे"</string>
+    <string name="blocked_numbers_butter_bar_body" msgid="1261213114919301485">"तुम्ही एखादा आणीबाणी नंबर डायल केला किंवा त्यावर मेसेज पाठवल्यानंतर, आणीबाणी सेवा तुमच्याशी संपर्क साधू शकतात याची खात्री करण्यासाठी ब्लॉक करणे बंद केले जाते."</string>
     <string name="blocked_numbers_butter_bar_button" msgid="2704456308072489793">"आता पुन्हा-सक्षम करा"</string>
-    <string name="blocked_numbers_number_blocked_message" msgid="4314736791180919167">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> अवरोधित केला"</string>
+    <string name="blocked_numbers_number_blocked_message" msgid="4314736791180919167">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> ब्लॉक केला"</string>
     <string name="blocked_numbers_number_unblocked_message" msgid="2933071624674945601">"<xliff:g id="UNBLOCKED_NUMBER">%1$s</xliff:g> अनब्लॉक केला"</string>
-    <string name="blocked_numbers_block_emergency_number_message" msgid="4198550501500893890">"आणीबाणी नंबर अवरोधित करण्यात अक्षम."</string>
-    <string name="blocked_numbers_number_already_blocked_message" msgid="2301270825735665458">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> आधीपासून अवरोधित केला आहे."</string>
+    <string name="blocked_numbers_block_emergency_number_message" msgid="4198550501500893890">"आणीबाणी नंबर ब्लॉक करता आला नाही."</string>
+    <string name="blocked_numbers_number_already_blocked_message" msgid="2301270825735665458">"<xliff:g id="BLOCKED_NUMBER">%1$s</xliff:g> आधीपासून ब्लॉक केला आहे."</string>
     <string name="toast_personal_call_msg" msgid="5817631570381795610">"कॉल करण्यासाठी वैयक्तिक डायलर वापरणे"</string>
     <string name="notification_incoming_call" msgid="1233481138362230894">"<xliff:g id="CALL_FROM">%2$s</xliff:g> कडील <xliff:g id="CALL_VIA">%1$s</xliff:g> मधील कॉल"</string>
     <string name="notification_incoming_video_call" msgid="5795968314037063900">"<xliff:g id="CALL_FROM">%2$s</xliff:g> कडील <xliff:g id="CALL_VIA">%1$s</xliff:g> मधील व्हिडिओ कॉल"</string>
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"पे फोनवरून इनकमिंग कॉल ब्‍लॉक करा"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"अज्ञात"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"अनोळखी कॉलरकडून इनकमिंग कॉल ब्‍लॉक करा"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"उपलब्ध नाही"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"नंबर उपलब्ध नसल्यास, कॉल ब्लॉक करा"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"कॉल ब्‍लॉक करणे"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"कॉल ब्‍लॉक करणे बंद केले"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"आणीबाणी कॉल केला"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"आणीबाणीत प्रतिसाद देणार्‍यांना तुमच्‍याशी संपर्क साधण्‍याची अनुमती देण्‍यासाठी कॉल ब्‍लॉक करणे बंद केले आहे."</string>
     <string name="developer_title" msgid="9146088855661672353">"टेलिकॉम डेव्‍हलपर मेनू"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"आणीबाणी कॉल दरम्यान कॉल घेतला जाऊ शकत नाही."</string>
+    <string name="cancel" msgid="6733466216239934756">"रद्द करा"</string>
 </resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 7571b9d..c9aff1b 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Sekat panggilan daripada telefon awam"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Tidak diketahui"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Sekat panggilan daripada pemanggil yang tidak dikenal pasti"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Tidak tersedia"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Sekat panggilan sekiranya nombor tidak tersedia"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Sekatan Panggilan"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Sekatan Panggilan dilumpuhkan"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Panggilan kecemasan dibuat"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Sekatan Panggilan telah dilumpuhkan untuk membolehkan pasukan bantuan kecemasan menghubungi anda."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menu Pembangun Telekom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Panggilan tidak boleh dijawab semasa dalam panggilan kecemasan."</string>
+    <string name="cancel" msgid="6733466216239934756">"Batal"</string>
 </resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index ac6965f..616bc7c 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"အများသုံးဖုန်းများမှ ခေါ်ဆိုမှုများကို ပိတ်ပါ"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"အမည်မသိ"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"အမည်မသိသော ခေါ်ဆိုသူများကို ပိတ်ပါ"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"မသိနိုင်ပါ"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"နံပါတ် မသိနိုင်သော ခေါ်ဆိုမှုများကို ပိတ်ထားပါ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ခေါ်ဆိုမှု ပိတ်ထားခြင်း"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"\'ခေါ်ဆိုမှု ပိတ်ခြင်း\' ကို ရပ်ထားပါသည်"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"အရေးပေါ် ခေါ်ဆိုမှု ပြုလုပ်ထားပါသည်"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"အရေးပေါ်တုံ့ပြန်သူများက သင့်အား ဆက်သွယ်နိုင်စေရန် \'ခေါ်ဆိုမှု ပိတ်ခြင်း\' ကို ရပ်ထားပါသည်။"</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom ဆော့ဖ်ဝဲအင်ဂျင်နီယာ မီနူး"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"အရေးပေါ်ခေါ်ဆိုမှု ပြုလုပ်နေစဉ် ဖုန်းမခေါ်နိုင်ပါ။"</string>
+    <string name="cancel" msgid="6733466216239934756">"မလုပ်တော့"</string>
 </resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index df39be6..a981507 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokkér anrop fra telefonkiosker"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Ukjent"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokkér anrop fra oppringere som ikke er identifisert"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Utilgjengelig"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokkér anrop der nummeret er utilgjengelig"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Anropsblokkering"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Anropsblokkering er slått av"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Nødanrop utført"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Anropsblokkering er slått av for å gjøre det mulig for nødtjenester å kontakte deg."</string>
     <string name="developer_title" msgid="9146088855661672353">"Meny for telekommunikasjonsutviklere"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Du kan ikke besvare anrop mens du har et pågående nødanrop."</string>
+    <string name="cancel" msgid="6733466216239934756">"Avbryt"</string>
 </resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 522f360..8741730 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"पे फोनहरूबाट आउने कलहरूमाथि रोक लगाउनुहोस्"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"अज्ञात"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"अज्ञात कल गर्ने व्यक्तिहरूको कलमाथि रोक लगाउनुहोस्"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"उपलब्ध छैन"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"नम्बर उपलब्ध नभएका कल ब्लक गर्नुहोस्"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"कलमाथि रोक लगाउने सुविधा"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"कलमाथि रोक लगाउने सुविधालाई असक्षम पारियो"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"आपत्‌कालीन कल गरियो"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"आपत्‌कालीन अवस्थामा उद्दार गर्ने मान्छेहरूलाई तपाईंलाई सम्पर्क गर्न दिन कलमाथि रोक लगाउने सुविधा असक्षम पारिएको छ।"</string>
     <string name="developer_title" msgid="9146088855661672353">"टेलिकमको विकासकर्ताको मेनु"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"आपत्‌कालीन कल चलिराखेको बेलामा अरु कल स्वीकार गर्न सकिँदैन।"</string>
+    <string name="cancel" msgid="6733466216239934756">"रद्द गर्नुहोस्"</string>
 </resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index fd051e5..be67223 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Gesprekken van betaaltelefoons blokkeren"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Onbekend"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Gesprekken van onbekende bellers blokkeren"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Niet beschikbaar"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Gesprekken blokkeren waarvoor het nummer niet beschikbaar is"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Gesprekken blokkeren"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Gesprekken blokkeren staat uit"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Noodoproep geplaatst"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Gesprekken blokkeren is uitgezet zodat nooddiensten je kunnen bereiken."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecomontwikkelaarsmenu"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Gesprekken kunnen niet worden aangenomen tijdens een noodoproep."</string>
+    <string name="cancel" msgid="6733466216239934756">"Annuleren"</string>
 </resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 758beda..5c62bb1 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ପେ-ଫୋନ୍‌ରୁ କଲ୍‌କୁ ଅବରୋଧ କରନ୍ତୁ"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ଅଜଣା"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ଅଜଣା କଲରର କଲ୍‌କୁ ବ୍ଲକ୍ କରନ୍ତୁ"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"ଉପଲବ୍ଧ ନାହିଁ"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"ନମ୍ଵର ଉପଲବ୍ଧ ନଥିବା କ୍ଷେତ୍ରରେ କଲଗୁଡ଼ିକୁ ବ୍ଲକ କରନ୍ତୁ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"କଲ୍‌ ବ୍ଲକିଂ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"କଲ୍ ବ୍ଲକିଂକୁ ଅକ୍ଷମ କରାଯାଇଛି"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"ଜରୁରିକାଳୀନ କଲ୍ କରାଗଲା"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ଜରୁରିକାଳୀନ ସହାୟତା କର୍ମଚାରୀମାନେ ଆପଣଙ୍କୁ ଯୋଗଯୋଗ କରିବା ପାଇଁ କଲ୍ ଅବରୋଧକୁ ଅକ୍ଷମ କରାଯାଇଛି।"</string>
     <string name="developer_title" msgid="9146088855661672353">"ଟେଲେକମ୍ ଡେଭେଲପର୍ ମେନୁ"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ଜରୁରୀକାଳୀନ କଲ୍ ବେଳେ ଅନ୍ୟ କଲ୍ ଉଠାଇ ପାରିବେ ନାହିଁ।"</string>
+    <string name="cancel" msgid="6733466216239934756">"ବାତିଲ୍ କରନ୍ତୁ"</string>
 </resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index e08b5e9..bc3d7fa 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ਜਨਤਕ ਫ਼ੋਨਾਂ ਵਾਲੀਆਂ ਕਾਲਾਂ ਬਲਾਕ ਕਰੋ"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ਅਗਿਆਤ"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"ਅਣਪਛਾਤੇ ਕਾਲਰਾਂ ਵਾਲੀਆਂ ਕਾਲਾਂ ਬਲਾਕ ਕਰੋ"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"ਉਪਲਬਧ ਨਹੀਂ"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"ਨੰਬਰ ਉਪਲਬਧ ਨਾ ਹੋਣ \'ਤੇ ਕਾਲਾਂ ਨੂੰ ਬਲਾਕ ਕਰੋ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ਕਾਲ ਬਲਾਕ ਕਰਨਾ"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ਕਾਲ ਬਲਾਕਿੰਗ ਵਿਕਲਪ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"ਸੰਕਟਕਾਲੀਨ ਕਾਲ ਕੀਤੀ ਗਈ"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ਸੰਕਟਕਾਲੀਨ ਸਥਿਤੀ ਵਿੱਚ ਮਦਦ ਕਰਨ ਵਾਲੇ ਵਿਅਕਤੀ ਨੂੰ ਤੁਹਾਨੂੰ ਸੰਪਰਕ ਕਰਨ ਦੇਣ ਲਈ ਕਾਲ ਬਲਾਕਿੰਗ ਵਿਕਲਪ ਬੰਦ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ।"</string>
     <string name="developer_title" msgid="9146088855661672353">"ਟੈਲੀਕੋਮ ਵਿਕਾਸਕਾਰ ਮੀਨੂ"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ਕਿਸੇ ਸੰਕਟਕਾਲੀਨ ਕਾਲ ਦੌਰਾਨ ਹੋਰ ਕਾਲਾਂ ਨਹੀਂ ਲਈਆਂ ਜਾ ਸਕਦੀਆਂ।"</string>
+    <string name="cancel" msgid="6733466216239934756">"ਰੱਦ ਕਰੋ"</string>
 </resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index f341da7..958412d 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokuj połączenia z budek telefonicznych"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Nieznane"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokuj połączenia z nieznanych numerów"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Niedostępny"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Zablokuj połączenie, jeśli numer telefonu nie jest dostępny"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokowanie połączeń"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokowanie połączeń wyłączone"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Wykonano połączenie alarmowe"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokowanie połączeń zostało wyłączone, aby służby ratownicze mogły się z Tobą skontaktować."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menu programisty Telecom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Nie można odbierać rozmów przy nawiązanym połączeniu alarmowym."</string>
+    <string name="cancel" msgid="6733466216239934756">"Anuluj"</string>
 </resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 42b435e..462e6f6 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquear chamadas de telefones públicos"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Desconhecidas"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquear chamadas não identificadas"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Indisponível"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bloquear chamadas quando o número está indisponível"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bloqueio de chamadas"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Bloqueio de chamadas desativado"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Chamada de emergência efetuada"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"O bloqueio de chamadas foi desativado para permitir a receção de contactos de resposta a emergências."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menu do programador de telecomunicações"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Não é possível atender chamadas durante uma chamada de emergência."</string>
+    <string name="cancel" msgid="6733466216239934756">"Cancelar"</string>
 </resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 68bd2c5..9e9fb32 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bloquear chamadas de orelhão"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Desconhecido"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bloquear chamadas de autores não identificados"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Indisponível"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bloquear chamadas onde o número estiver indisponível"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bloqueio de chamadas"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Bloqueio de chamadas desativado"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"A chamada de emergência foi feita"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"O bloqueio de chamadas foi desativado para permitir que a equipe de emergência entre em contato com você."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menu do desenvolvedor de telecomunicação"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Durante uma chamada de emergência, não é possível transferir chamadas para o dispositivo."</string>
+    <string name="cancel" msgid="6733466216239934756">"Cancelar"</string>
 </resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index adb1ff8..d0b56f4 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blocați apelurile de la telefoane publice"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Necunoscut"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blocați apelurile de la apelanți neidentificați"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Indisponibil"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blocați apelurile unde numărul de telefon este indisponibil"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blocarea apelurilor"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blocarea apelurilor este dezactivată."</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"S-a efectuat un apel de urgență."</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blocarea apelurilor a fost dezactivată pentru a permite serviciilor de urgență să vă contacteze."</string>
     <string name="developer_title" msgid="9146088855661672353">"Meniu pentru dezvoltatori de telecomunicații"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Nu puteți răspunde la apeluri în timpul unui apel de urgență."</string>
+    <string name="cancel" msgid="6733466216239934756">"Anulați"</string>
 </resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 49ab1db..6382c7b 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Блокировать вызовы с телефонов-автоматов"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Неизвестные номера"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Блокировать вызовы с неопределяемых номеров"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Неизвестный номер"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Блокировать звонки, если номер неизвестен"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Блокировка вызовов"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Блокировка вызовов отключена"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Выполнен экстренный вызов"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Блокировка вызовов отключена, чтобы у экстренных служб была возможность позвонить вам."</string>
     <string name="developer_title" msgid="9146088855661672353">"Меню разработчика Telecom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Невозможно принять вызов, когда уже выполняется экстренный вызов."</string>
+    <string name="cancel" msgid="6733466216239934756">"Отмена"</string>
 </resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 315a0dc..6cbaaa5 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"ගෙවුම් දුරකථන වෙතින් වන ඇමතුම් අවහිර කරන්න"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"නොදනී"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"නොහඳුනන අමතන්නන් වෙතින් වන ඇමතුම් අවහිර කරන්න"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"නොමැත"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"අංකය නොමැති ඇමතුම් අවහිර කරන්න"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"ඇමතුම් අවහිර කිරීම"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ඇමතුම් අවහිර කිරීම අබල කර ඇත"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"හදිසි ඇමතුම් ගැනීම"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"හදිසි අමතන්නන්ට ඔබව සම්බන්ධ කර ගැනීමට ඉඩ දීමට ඇමතුම් අවහිර කිරීම අබල කර ඇත."</string>
     <string name="developer_title" msgid="9146088855661672353">"ටෙලිකොම් සංවර්ධක මෙනුව"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"හදිසි ඇමතුමක් අතරතුර ඇමතුම් ගත නොහැකිය."</string>
+    <string name="cancel" msgid="6733466216239934756">"අවලංගු කරන්න"</string>
 </resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 5209880..c49ffc5 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokovať hovory z verejných telefónov"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Neznáme číslo"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokovať hovory od nerozpoznaných volajúcich"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Nedostupné"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokovať hovory, ak je číslo nedostupné"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokovanie hovorov"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokovanie hovorov je vypnuté"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Bolo uskutočnené tiesňové volanie"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokovanie hovorov bolo vypnuté, aby vás mohli kontaktovať pracovníci tiesňových služieb."</string>
     <string name="developer_title" msgid="9146088855661672353">"Ponuka pre vývojárov Telecomu"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Počas tiesňového volania nie je možné prijímať hovory."</string>
+    <string name="cancel" msgid="6733466216239934756">"Zrušiť"</string>
 </resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 845e88b..5bc9d83 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blokirajte klice iz telefonskih govorilnic"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Neznano"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blokiranje klicev neznanih klicateljev"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Ni na voljo"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blokirajte klice, pri katerih številka ni na voljo."</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Blokiranje klicev"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Blokiranje klicev je onemogočeno"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Opravljen je klic v sili"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Blokiranje klicev je onemogočeno, da lahko stik z vami vzpostavijo uslužbenci služb za klic v sili."</string>
     <string name="developer_title" msgid="9146088855661672353">"Meni za razvijalce Telecom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Med klicem v sili ni mogoče sprejeti klicev."</string>
+    <string name="cancel" msgid="6733466216239934756">"Prekliči"</string>
 </resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 6ae9e26..db3eda3 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blloko telefonatat nga telefonat me pagesë"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"E panjohur"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blloko telefonatat nga telefonuesit e paidentifikuar"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Nuk ofrohet"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blloko telefonatat kur nuk ofrohet numri"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Bllokimi i telefonatave"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Bllokimi i telefonatave u çaktivizua"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Telefonata e urgjencës u krye"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Bllokimi i telefonatave është çaktivizuar për të lejuar që personat që përgjigjen në rast urgjence të kontaktojnë me ty."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menyja e zhvilluesit të telekomunikimit"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Nuk mund të marrësh telefonata kur je në një telefonatë urgjence."</string>
+    <string name="cancel" msgid="6733466216239934756">"Anulo"</string>
 </resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 6d83483..36bf352 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Блокирајте позиве са телефонских говорница"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Непознати бројеви"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Блокирајте позиве неидентификованих позивалаца"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Недоступно"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Блокирајте позиве ако је број недоступан"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Блокирање позива"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Блокирање позива је онемогућено"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Упућен је хитни позив"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Блокирање позива је онемогућено да би хитне службе могле да вас контактирају."</string>
     <string name="developer_title" msgid="9146088855661672353">"Мени за програмере Telecom-а"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"За време хитног позива није могуће преузимати друге позиве."</string>
+    <string name="cancel" msgid="6733466216239934756">"Откажи"</string>
 </resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 22e526b..34a3b6d 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Blockera samtal från telefonautomater"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Okänd"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Blockera samtal från oidentifierade uppringare"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Inte tillgängligt"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Blockera samtal med ej tillgängligt nummer"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Samtalsblockering"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Samtalsblockering inaktiverad"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Nödsamtal ringt"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Samtalsblockering har inaktiverats för att tillåta att räddningstjänsten kontaktar dig."</string>
     <string name="developer_title" msgid="9146088855661672353">"Meny för telekomutvecklare"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Det går inte att besvara samtal medan ett nödsamtal pågår."</string>
+    <string name="cancel" msgid="6733466216239934756">"Avbryt"</string>
 </resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index cc17765..1eb5293 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Zuia simu kutoka kwa nambari ya simu za kulipia"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Zisizojulikani"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Zuia simu kutoka kwa wapigaji wasiojulikana"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Zisizotambulishwa"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Zuia simu zinazopigwa bila kutambulisha nambari ya simu"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Kuzuia Simu"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Kipengele cha Kuzuia Simu kimezimwa"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Simu ya dharura imepigwa"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Kipengele cha Kuzuia Simu kimezimwa ili kuruhusu wapigaji simu za dharura kuwasiliana nawe."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menyu ya Msanidi programu wa Telecom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Huwezi kupokea simu nyingine wakati unashiriki katika simu ya dharura."</string>
+    <string name="cancel" msgid="6733466216239934756">"Ghairi"</string>
 </resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 0608652..90a33a7 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"கட்டண ஃபோன்களில் இருந்து வரும் அழைப்புகளைத் தடுக்கும்"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"தெரியாத அழைப்புகள்"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"அடையாளம் தெரியாத அழைப்பாளர்களின் அழைப்புகளைத் தடுக்கும்"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"மறைக்கப்பட்ட எண்கள்"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"மறைக்கப்பட்ட எண்களில் இருந்து வரும் அழைப்புகளைத் தடுக்கும்"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"அழைப்புத் தடுப்பு"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"அழைப்புத் தடுப்பு முடக்கப்பட்டுள்ளது"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"அவசர அழைப்பு செய்யப்பட்டது"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"அவசரநிலையில் பதிலளிப்பவர்களை உங்களைத் தொடர்புகொள்வதற்கு அனுமதிக்க, அழைப்புத் தடுப்பு முடக்கப்பட்டுள்ளது."</string>
     <string name="developer_title" msgid="9146088855661672353">"டெலிகாம் டெவெலப்பர் மெனு"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"அவசர அழைப்பின்போது அழைப்புகளை ஏற்க முடியாது."</string>
+    <string name="cancel" msgid="6733466216239934756">"ரத்துசெய்"</string>
 </resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 6500bd1..b904115 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"పే ఫోన్‌ల నుండి కాల్స్‌ను బ్లాక్ చేయండి"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"తెలియని"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"తెలియని కాలర్‌ల నుండి కాల్స్‌ను బ్లాక్ చేయండి"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"అందుబాటులో లేని నంబర్‌లు"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"నంబర్ అందుబాటులో లేనప్పుడు కాల్స్‌ను బ్లాక్ చేయండి"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"కాల్ బ్లాక్ చేయడం"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"కాల్ బ్లాక్ చేయడం నిలిపివేయబడింది"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"అత్యవసర కాల్ చేయబడింది"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"మిమ్మల్ని సంప్రదించడానికి అత్యవసర ప్రతిస్పందనదారులను అనుమతించడానికి కాల్ బ్లాక్ చేయడం నిలిపివేయబడింది."</string>
     <string name="developer_title" msgid="9146088855661672353">"టెలికామ్ డెవలపర్ మెనూ"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"అత్యవసర కాల్‌లో వున్నప్పుడు కాల్స్‌ను స్వీకరించడానికి వీలుపడదు."</string>
+    <string name="cancel" msgid="6733466216239934756">"రద్దు చేయండి"</string>
 </resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 0def6f6..4f1c825 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"บล็อกสายจากโทรศัพท์สาธารณะ"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"ไม่รู้จัก"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"บล็อกสายจากผู้โทรที่ไม่สามารถระบุได้"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"ไม่ได้บันทึก"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"บล็อกสายที่ไม่ได้บันทึกหมายเลขไว้"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"การบล็อกสาย"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"ปิดใช้การบล็อกสาย"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"โทรหมายเลขฉุกเฉินแล้ว"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ปิดใช้การบล็อกสายแล้วเพื่อให้ทีมฉุกเฉินติดต่อคุณ"</string>
     <string name="developer_title" msgid="9146088855661672353">"เมนูนักพัฒนาโทรคมนาคม"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"การโทรนั้นจะทำขณะอยู่ในการโทรฉุกเฉินไม่ได้"</string>
+    <string name="cancel" msgid="6733466216239934756">"ยกเลิก"</string>
 </resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 2889d15..85c1b3f 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Bina-block ang mga tawag mula sa mga pay phone"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Hindi Alam"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Bina-block ang mga tumatawag mula sa mga hindi kilalang tumatawag"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Hindi available"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"I-block ang mga tawag kung saan hindi available ang numero"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Pag-block ng Tawag"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Naka-disable ang Pag-block ng Tawag"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Ginawang emergency na tawag"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Na-disable ang Pag-block ng Tawag para payagan ang mga tumutugon sa emergency na kontakin ka."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menu ng Telecom Developer"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Hindi puwedeng sumagot ng mga tawag habang nasa emergency na tawag."</string>
+    <string name="cancel" msgid="6733466216239934756">"Kanselahin"</string>
 </resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 2b3cfc5..66da8ab 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Ankesörlü telefonlardan gelen çağrılar engellenir"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Bilinmeyen numaralar"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Tanımlanamayan arayanlardan gelen aramaları engelle"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Bilinmiyor"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Bilinmeyen numara söz konusu olduğunda aramaları engelle"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Çağrı Engelleme"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Çağrı Engelleme devre dışı bırakıldı"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Acil durum çağrısı yapıldı"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Acil durum müdahale ekibinin sizinle iletişime geçmesine olanak tanımak için Çağrı Engelleme devre dışı bırakıldı."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telekomünikasyon Geliştirici Menüsü"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Acil durum araması sırasında arama alınamaz."</string>
+    <string name="cancel" msgid="6733466216239934756">"İptal"</string>
 </resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 762341c..6eddc79 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Блокування викликів із таксофонів"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Невідомі"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Блокувати виклики від невизначених абонентів"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"З недоступних номерів"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Блокувати виклик, якщо номер недоступний"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Блокування викликів"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Блокування викликів вимкнено"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Здійснено екстрений виклик"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Блокування викликів вимкнено, щоб ви могли отримувати екстрені сповіщення."</string>
     <string name="developer_title" msgid="9146088855661672353">"Меню розробника Telecom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Під час екстрених викликів не можна приймати інші."</string>
+    <string name="cancel" msgid="6733466216239934756">"Скасувати"</string>
 </resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index bc81512..c42f5d9 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"پے فونز سے آنے والی کالز کو مسدود کریں"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"نامعلوم"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"غیر شناخت کردہ کالرز سے آنے والی کالز کو مسدود کریں"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"غیر دستیاب"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"کالز کو مسدود کریں جہاں یہ نمبر دستیاب نہ ہو"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"کال مسدود کرنا"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"کال مسدود کرنا غیر فعال ہو گیا ہے"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"ہنگامی کال کی گئی"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"ہنگامی حالت میں جواب دہندگان کو آپ سے رابطہ کرنے کی اجازت دینے کیلئے کال مسدود کرنا غیر فعال ہو گیا ہے۔"</string>
     <string name="developer_title" msgid="9146088855661672353">"ٹیلی کام ڈویلپر مینو"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"ہنگامی کال کے دوران کالز نہیں لی جائیں گی۔"</string>
+    <string name="cancel" msgid="6733466216239934756">"منسوخ کریں"</string>
 </resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index cda0a1b..c3ae499 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Taksofondan keluvchi chaqiruvlarni bloklash"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Notanish raqamlar"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Aniqlanmagan raqamlardan keluvchi chaqiruvlarni bloklash"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Raqam aniqlanmadi"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Aniqlanmagan raqamdan kiruvchi chaqiruv bloklansin"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Chaqiruvlarni bloklash"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Chaqiruvlarni bloklash funksiyasi yoqilmagan"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Favqulodda chaqiruv qilindi"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Sizga favqulodda chiqiruv qilish imkoni bo‘lishi uchun chaqiruvlarni bloklash funksiyasi o‘chirib qo‘yilgan."</string>
     <string name="developer_title" msgid="9146088855661672353">"Telecom dasturchisi menyusi"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Favqulodda chaqiruv vaqtida boshqa chaqiruvlarni qabul qilish imkonsiz."</string>
+    <string name="cancel" msgid="6733466216239934756">"Bekor qilish"</string>
 </resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index d4195b6..dfe6b7b 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Chặn các cuộc gọi từ điện thoại công cộng"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Không xác định"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Chặn cuộc gọi từ người gọi không xác định"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Không có sẵn"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Chặn cuộc gọi khi không có sẵn số điện thoại"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Chặn cuộc gọi"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Đã tắt tính năng Chặn cuộc gọi"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Đã thực hiện cuộc gọi khẩn cấp"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Đã tắt tính năng Chặn cuộc gọi để cho phép người trả lời khẩn cấp liên hệ với bạn."</string>
     <string name="developer_title" msgid="9146088855661672353">"Menu nhà phát triển dịch vụ viễn thông"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Bạn không thể gọi điện trong khi thực hiện cuộc gọi khẩn cấp."</string>
+    <string name="cancel" msgid="6733466216239934756">"Hủy"</string>
 </resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 1c9ed1b..d91c260 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"屏蔽公用电话来电"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"未知"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"屏蔽不明身份人员的来电"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"未显示号码"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"屏蔽未显示号码的来电"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"来电屏蔽"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"来电屏蔽功能已停用"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"已拨打紧急呼救电话"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"系统已停用来电屏蔽功能,以便急救人员与您联系。"</string>
     <string name="developer_title" msgid="9146088855661672353">"电信开发者菜单"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"紧急呼叫时无法接听来电。"</string>
+    <string name="cancel" msgid="6733466216239934756">"取消"</string>
 </resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 98f1fa1..df1a850 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"封鎖公共電話來電"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"不明"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"封鎖不明來電者的來電"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"無法顯示"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"封鎖無法顯示號碼的來電"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"來電封鎖"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"已停用來電封鎖功能"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"已撥緊急電話"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"已停用來電封鎖功能,以便救援人員與您聯絡。"</string>
     <string name="developer_title" msgid="9146088855661672353">"電信開發商選單"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"使用緊急電話期間無法接聽電話。"</string>
+    <string name="cancel" msgid="6733466216239934756">"取消"</string>
 </resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 3c87562..39359b3 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"封鎖公共電話來電"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"不明"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"封鎖不明來電者的來電"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"未顯示號碼"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"封鎖未顯示號碼的來電"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"來電封鎖"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"已停用來電封鎖"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"已撥打緊急電話"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"系統已停用來電封鎖功能,以便緊急應變人員與你聯絡。"</string>
     <string name="developer_title" msgid="9146088855661672353">"電信開發人員選單"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"如果裝置已撥打緊急電話,就無法進行其他通話。"</string>
+    <string name="cancel" msgid="6733466216239934756">"取消"</string>
 </resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 9f5ef44..a98e4f0 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -114,10 +114,13 @@
     <string name="phone_settings_payphone_summary_txt" msgid="3936631076065563665">"Vimbela amakholi kusukela kumafoni akhokhelwayo"</string>
     <string name="phone_settings_unknown_txt" msgid="3577926178354772728">"Akwaziwa"</string>
     <string name="phone_settings_unknown_summary_txt" msgid="5446657192535779645">"Vimbela amakholi kusukela kwabashayayo abangaziwa"</string>
+    <string name="phone_settings_unavailable_txt" msgid="825918186053980858">"Akutholakali"</string>
+    <string name="phone_settings_unavailable_summary_txt" msgid="8221686031038282633">"Vimba amakholi lapho inombolo ingatholakali"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt" msgid="2895809176537908791">"Ukuvimbela ikholi"</string>
     <string name="phone_strings_call_blocking_turned_off_notification_text_txt" msgid="1713632946174016619">"Ukuvimbela ikholi kukhutshaziwe"</string>
     <string name="phone_strings_emergency_call_made_dialog_title_txt" msgid="6629412508584507377">"Ikholi ephuthumayo yenziwe"</string>
     <string name="phone_strings_emergency_call_made_dialog_call_blocking_text_txt" msgid="3140411733995271126">"Ukuvimbela ikholi kukhutshaziwe ukuze kuvunyelwe abaphenduli besimo esiphuthumayo ukuthi baxhumane nawe."</string>
     <string name="developer_title" msgid="9146088855661672353">"Imenyu yonjiniyela we-Telecom"</string>
     <string name="toast_emergency_can_not_pull_call" msgid="9074229465338410869">"Amakholi awakwazi ukuthathwa ngesikhathi ukukholi yesimo esiphuthumayo."</string>
+    <string name="cancel" msgid="6733466216239934756">"Khansela"</string>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 01bb88c..6b8c0b2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -356,6 +356,10 @@
     <string name="phone_settings_unknown_txt">Unknown</string>
     <!-- Explanatory text under the call type "phone_settings_unknown_txt". This occurs when no caller ID information unavailable (e.g., international calls, IP phones that operators cannot identify the caller) -->
     <string name="phone_settings_unknown_summary_txt">Block calls from unidentified callers</string>
+    <!-- Call type to be blocked. See the explanatory text "phone_settings_unavailable_summary_txt".  -->
+    <string name="phone_settings_unavailable_txt">Unavailable</string>
+    <!-- Explanatory text under the call type "phone_settings_unavailable_txt". -->
+    <string name="phone_settings_unavailable_summary_txt">Block calls where the number is unavailable</string>
     <!-- Notification. Make this translation consistent with "phone_settings_call_blocking_txt". -->
     <string name="phone_strings_call_blocking_turned_off_notification_title_txt">Call Blocking</string>
     <!-- Notification that appears when the feature Call Blocking has been disabled. -->
@@ -375,4 +379,6 @@
          blocking functionality (for test purposes).
          DO NOT TRANSLATE -->
     <string name="developer_enhanced_call_blocking" translatable="false">Enhanced Call Blocking</string>
+    <!-- Button label for generic cancel action [CHAR LIMIT=20] -->
+    <string name="cancel">Cancel</string>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 5ba0a3f..64dfabd 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -92,4 +92,9 @@
         <item name="android:lineSpacingExtra">@dimen/blocked_numbers_secondary_line_spacing</item>
         <item name="android:capitalize">sentences</item>
     </style>
+
+    <style name="CallSettingsWithoutDividerTheme" parent="Theme.Telecom.DialerSettings">
+        <item name="android:listDivider">@null</item>
+    </style>
+
 </resources>
diff --git a/res/xml/activity_blocked_numbers.xml b/res/xml/activity_blocked_numbers.xml
index df1a759..f884ec9 100644
--- a/res/xml/activity_blocked_numbers.xml
+++ b/res/xml/activity_blocked_numbers.xml
@@ -75,7 +75,7 @@
                     <TextView
                             android:id="@+id/add_blocked"
                             android:layout_width="wrap_content"
-                            android:layout_height="48dp"
+                            android:layout_height="wrap_content"
                             android:text="@string/block_number"
                             android:layout_marginBottom="@dimen/blocked_numbers_button_bottom_margin"
                             android:paddingTop="@dimen/blocked_numbers_button_large_padding"
diff --git a/res/xml/enhanced_call_blocking_settings.xml b/res/xml/enhanced_call_blocking_settings.xml
index 73ed2af..50c9b36 100644
--- a/res/xml/enhanced_call_blocking_settings.xml
+++ b/res/xml/enhanced_call_blocking_settings.xml
@@ -40,5 +40,11 @@
         android:summary="@string/phone_settings_unknown_summary_txt"
         android:persistent="false"
         android:defaultValue="false"/>
+    <SwitchPreference
+        android:key="block_unavailable_calls_setting"
+        android:title="@string/phone_settings_unavailable_txt"
+        android:summary="@string/phone_settings_unavailable_summary_txt"
+        android:persistent="false"
+        android:defaultValue="false"/>
     <!--Add divider to separate this enhanced call blocking settings from other settings-->
 </PreferenceScreen>
\ No newline at end of file
diff --git a/src/com/android/server/telecom/AsyncRingtonePlayer.java b/src/com/android/server/telecom/AsyncRingtonePlayer.java
index bf2472f..7f51f1b 100644
--- a/src/com/android/server/telecom/AsyncRingtonePlayer.java
+++ b/src/com/android/server/telecom/AsyncRingtonePlayer.java
@@ -77,8 +77,10 @@
      *         {@code False} indicates that a haptic track is NOT present on the ringtone;
      *         in this case the default vibration in {@link Ringer} should be trigger if needed.
      */
-    public @NonNull CompletableFuture<Boolean> play(RingtoneFactory factory, Call incomingCall,
-            @Nullable VolumeShaper.Configuration volumeShaperConfig, boolean isVibrationEnabled) {
+    public @NonNull
+    CompletableFuture<Boolean> play(RingtoneFactory factory, Call incomingCall,
+            @Nullable VolumeShaper.Configuration volumeShaperConfig, boolean isRingerAudible,
+            boolean isVibrationEnabled) {
         Log.d(this, "Posting play.");
         if (mHapticsFuture == null) {
             mHapticsFuture = new CompletableFuture<>();
@@ -88,7 +90,8 @@
         args.arg2 = incomingCall;
         args.arg3 = volumeShaperConfig;
         args.arg4 = isVibrationEnabled;
-        args.arg5 = Log.createSubsession();
+        args.arg5 = isRingerAudible;
+        args.arg6 = Log.createSubsession();
         postMessage(EVENT_PLAY, true /* shouldCreateHandler */, args);
         return mHapticsFuture;
     }
@@ -152,71 +155,70 @@
         Call incomingCall = (Call) args.arg2;
         VolumeShaper.Configuration volumeShaperConfig = (VolumeShaper.Configuration) args.arg3;
         boolean isVibrationEnabled = (boolean) args.arg4;
-        Session session = (Session) args.arg5;
+        boolean isRingerAudible = (boolean) args.arg5;
+        Session session = (Session) args.arg6;
         args.recycle();
 
         Log.continueSession(session, "ARP.hP");
         try {
             // don't bother with any of this if there is an EVENT_STOP waiting.
             if (mHandler.hasMessages(EVENT_STOP)) {
-                if (mHapticsFuture != null) {
-                    mHapticsFuture.complete(false /* ringtoneHasHaptics */);
-                    mHapticsFuture = null;
-                }
+                completeHapticFuture(false /* ringtoneHasHaptics */);
                 return;
             }
 
-            // If the Ringtone Uri is EMPTY, then the "None" Ringtone has been selected. Do not play
-            // anything.
-            if (Uri.EMPTY.equals(incomingCall.getRingtone())) {
-                mRingtone = null;
-                if (mHapticsFuture != null) {
-                    mHapticsFuture.complete(false /* ringtoneHasHaptics */);
-                    mHapticsFuture = null;
+            // If the Ringtone Uri is EMPTY, then the "None" Ringtone has been selected.
+            // If ringer is not audible for this call, then the phone is in "Vibrate" mode.
+            // Use haptic-only ringtone or do not play anything.
+            if (!isRingerAudible || Uri.EMPTY.equals(incomingCall.getRingtone())) {
+                if (isVibrationEnabled) {
+                    setRingtone(factory.getHapticOnlyRingtone());
+                    if (mRingtone == null) {
+                        completeHapticFuture(false /* ringtoneHasHaptics */);
+                        return;
+                    }
+                } else {
+                    setRingtone(null);
+                    completeHapticFuture(false /* ringtoneHasHaptics */);
+                    return;
                 }
-
-                return;
             }
 
             ThreadUtil.checkNotOnMainThread();
             Log.i(this, "handlePlay: Play ringtone.");
 
             if (mRingtone == null) {
-                mRingtone = factory.getRingtone(incomingCall, volumeShaperConfig);
+                setRingtone(factory.getRingtone(incomingCall, volumeShaperConfig));
                 if (mRingtone == null) {
                     Uri ringtoneUri = incomingCall.getRingtone();
                     String ringtoneUriString = (ringtoneUri == null) ? "null" :
                             ringtoneUri.toSafeString();
                     Log.addEvent(null, LogUtils.Events.ERROR_LOG, "Failed to get ringtone from " +
                             "factory. Skipping ringing. Uri was: " + ringtoneUriString);
-                    if (mHapticsFuture != null) {
-                        mHapticsFuture.complete(false /* ringtoneHasHaptics */);
-                        mHapticsFuture = null;
-                    }
+                    completeHapticFuture(false /* ringtoneHasHaptics */);
                     return;
                 }
+            }
 
-                // With the ringtone to play now known, we can determine if it has haptic channels or
-                // not; we will complete the haptics future so the default vibration code in Ringer
-                // can know whether to trigger the vibrator.
-                if (mHapticsFuture != null && !mHapticsFuture.isDone()) {
-                    boolean hasHaptics = factory.hasHapticChannels(mRingtone);
-                    Log.i(this, "handlePlay: hasHaptics=%b, isVibrationEnabled=%b", hasHaptics,
-                            isVibrationEnabled);
-                    SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil();
-                    if (hasHaptics && (volumeShaperConfig == null
-                            || systemSettingsUtil.enableAudioCoupledVibrationForRampingRinger())) {
-                        AudioAttributes attributes = mRingtone.getAudioAttributes();
-                        Log.d(this, "handlePlay: %s haptic channel",
-                                (isVibrationEnabled ? "unmuting" : "muting"));
-                        mRingtone.setAudioAttributes(
-                                new AudioAttributes.Builder(attributes)
-                                        .setHapticChannelsMuted(!isVibrationEnabled)
-                                        .build());
-                    }
-                    mHapticsFuture.complete(hasHaptics);
-                    mHapticsFuture = null;
+            // With the ringtone to play now known, we can determine if it has haptic channels or
+            // not; we will complete the haptics future so the default vibration code in Ringer can
+            // know whether to trigger the vibrator.
+            if (mHapticsFuture != null && !mHapticsFuture.isDone()) {
+                boolean hasHaptics = factory.hasHapticChannels(mRingtone);
+                Log.i(this, "handlePlay: hasHaptics=%b, isVibrationEnabled=%b", hasHaptics,
+                        isVibrationEnabled);
+                SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil();
+                if (hasHaptics && (volumeShaperConfig == null
+                        || systemSettingsUtil.isAudioCoupledVibrationForRampingRingerEnabled())) {
+                    AudioAttributes attributes = mRingtone.getAudioAttributes();
+                    Log.d(this, "handlePlay: %s haptic channel",
+                            (isVibrationEnabled ? "unmuting" : "muting"));
+                    mRingtone.setAudioAttributes(
+                            new AudioAttributes.Builder(attributes)
+                                    .setHapticChannelsMuted(!isVibrationEnabled)
+                                    .build());
                 }
+                completeHapticFuture(hasHaptics);
             }
 
             mRingtone.setLooping(true);
@@ -238,11 +240,7 @@
         ThreadUtil.checkNotOnMainThread();
         Log.i(this, "Stop ringtone.");
 
-        if (mRingtone != null) {
-            Log.d(this, "Ringtone.stop() invoked.");
-            mRingtone.stop();
-            mRingtone = null;
-        }
+        setRingtone(null);
 
         synchronized(this) {
             if (mHandler.hasMessages(EVENT_PLAY)) {
@@ -259,4 +257,22 @@
     public boolean isPlaying() {
         return mRingtone != null;
     }
+
+    private void setRingtone(@Nullable Ringtone ringtone) {
+        // Make sure that any previously created instance of Ringtone is stopped so the MediaPlayer
+        // can be released, before replacing mRingtone with a new instance. This is always created
+        // as a looping Ringtone, so if not stopped it will keep playing on the background.
+        if (mRingtone != null) {
+            Log.d(this, "Ringtone.stop() invoked.");
+            mRingtone.stop();
+        }
+        mRingtone = ringtone;
+    }
+
+    private void completeHapticFuture(boolean ringtoneHasHaptics) {
+        if (mHapticsFuture != null) {
+            mHapticsFuture.complete(ringtoneHasHaptics);
+            mHapticsFuture = null;
+        }
+    }
 }
diff --git a/src/com/android/server/telecom/BluetoothAdapterProxy.java b/src/com/android/server/telecom/BluetoothAdapterProxy.java
deleted file mode 100644
index ee9cde3..0000000
--- a/src/com/android/server/telecom/BluetoothAdapterProxy.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.telecom;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
-import android.content.Context;
-
-/**
- * Proxy class used so that BluetoothAdapter can be mocked for testing.
- */
-public class BluetoothAdapterProxy {
-    private BluetoothAdapter mBluetoothAdapter;
-
-    public BluetoothAdapterProxy() {
-        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
-    }
-
-    public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
-            int profile) {
-        if (mBluetoothAdapter == null) {
-            return false;
-        }
-        return mBluetoothAdapter.getProfileProxy(context, listener, profile);
-    }
-
-    public boolean setActiveDevice(BluetoothDevice device, int profiles) {
-        if (mBluetoothAdapter == null) {
-            return false;
-        }
-        if (device != null) {
-            return mBluetoothAdapter.setActiveDevice(device, profiles);
-        } else {
-            return mBluetoothAdapter.removeActiveDevice(profiles);
-        }
-    }
-}
diff --git a/src/com/android/server/telecom/BluetoothHeadsetProxy.java b/src/com/android/server/telecom/BluetoothHeadsetProxy.java
deleted file mode 100644
index e4eed87..0000000
--- a/src/com/android/server/telecom/BluetoothHeadsetProxy.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.server.telecom;
-
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothHeadset;
-
-import java.util.List;
-
-/**
- * A proxy class that facilitates testing of the BluetoothPhoneServiceImpl class.
- *
- * This is necessary due to the "final" attribute of the BluetoothHeadset class. In order to
- * test the correct functioning of the BluetoothPhoneServiceImpl class, the final class must be put
- * into a container that can be mocked correctly.
- */
-public class BluetoothHeadsetProxy {
-
-    private BluetoothHeadset mBluetoothHeadset;
-
-    public BluetoothHeadsetProxy(BluetoothHeadset headset) {
-        mBluetoothHeadset = headset;
-    }
-
-    public List<BluetoothDevice> getConnectedDevices() {
-        return mBluetoothHeadset.getConnectedDevices();
-    }
-
-    public int getConnectionState(BluetoothDevice device) {
-        return mBluetoothHeadset.getConnectionState(device);
-    }
-
-    public int getAudioState(BluetoothDevice device) {
-        return mBluetoothHeadset.getAudioState(device);
-    }
-
-    public boolean connectAudio() {
-        return mBluetoothHeadset.connectAudio();
-    }
-
-    public boolean setActiveDevice(BluetoothDevice device) {
-        return mBluetoothHeadset.setActiveDevice(device);
-    }
-
-    public BluetoothDevice getActiveDevice() {
-        return mBluetoothHeadset.getActiveDevice();
-    }
-
-    public boolean isAudioOn() {
-        return mBluetoothHeadset.isAudioOn();
-    }
-
-    public boolean disconnectAudio() {
-        return mBluetoothHeadset.disconnectAudio();
-    }
-
-    public boolean isInbandRingingEnabled() {
-        return mBluetoothHeadset.isInbandRingingEnabled();
-    }
-}
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 0218124..60016fd 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -471,7 +471,6 @@
     /** Whether an attempt has been made to load the text message responses. */
     private boolean mCannedSmsResponsesLoadingStarted = false;
 
-    private IVideoProvider mVideoProvider;
     private VideoProviderProxy mVideoProviderProxy;
 
     private boolean mIsVoipAudioMode;
@@ -831,10 +830,10 @@
     }
 
     public void initAnalytics() {
-        initAnalytics(null);
+        initAnalytics(null, null);
     }
 
-    public void initAnalytics(String callingPackage) {
+    public void initAnalytics(String callingPackage, String extraCreationLogs) {
         int analyticsDirection;
         switch (mCallDirection) {
             case CALL_DIRECTION_OUTGOING:
@@ -850,7 +849,7 @@
         }
         mAnalytics = Analytics.initiateCallAnalytics(mId, analyticsDirection);
         mAnalytics.setCallIsEmergency(mIsEmergencyCall);
-        Log.addEvent(this, LogUtils.Events.CREATED, callingPackage);
+        Log.addEvent(this, LogUtils.Events.CREATED, callingPackage + ";" + extraCreationLogs);
     }
 
     public Analytics.CallInfo getAnalytics() {
@@ -899,7 +898,7 @@
     @Override
     public String toString() {
         return String.format(Locale.US, "[Call id=%s, state=%s, tpac=%s, cmgr=%s, handle=%s, "
-                        + "vidst=%s, childs(%d), has_parent(%b), cap=%s, prop=%s]",
+                        + "vidst=%s, childs(%d), has_parent(%b), cap=%s, prop=%s], voip=%b",
                 mId,
                 CallState.toString(getParcelableCallState()),
                 getTargetPhoneAccount(),
@@ -909,7 +908,8 @@
                 getChildCalls().size(),
                 getParentCall() != null,
                 Connection.capabilitiesToStringShort(getConnectionCapabilities()),
-                Connection.propertiesToStringShort(getConnectionProperties()));
+                Connection.propertiesToStringShort(getConnectionProperties()),
+                mIsVoipAudioMode);
     }
 
     @Override
@@ -998,6 +998,9 @@
             case TelecomManager.PRESENTATION_UNKNOWN:
                 s.append("Unknown");
                 break;
+            case TelecomManager.PRESENTATION_UNAVAILABLE:
+                s.append("Unavailable");
+                break;
             default:
                 s.append("<undefined>");
         }
@@ -1260,7 +1263,7 @@
         }
     }
 
-    boolean isRingbackRequested() {
+    public boolean isRingbackRequested() {
         return mRingbackRequested;
     }
 
@@ -3562,8 +3565,6 @@
             }
         }
 
-        mVideoProvider = videoProvider;
-
         for (Listener l : mListeners) {
             l.onVideoCallProviderChanged(Call.this);
         }
@@ -3653,6 +3654,9 @@
     }
 
     public void setIsVoipAudioMode(boolean audioModeIsVoip) {
+        if (mIsVoipAudioMode != audioModeIsVoip) {
+            Log.addEvent(this, LogUtils.Events.SET_VOIP_MODE, audioModeIsVoip ? "Y" : "N");
+        }
         mIsVoipAudioMode = audioModeIsVoip;
         for (Listener l : mListeners) {
             l.onIsVoipAudioModeChanged(this);
@@ -4138,8 +4142,8 @@
         return mStartRingTime;
     }
 
-    public void setStartRingTime(long startRingTime) {
-        mStartRingTime = startRingTime;
+    public void setStartRingTime() {
+        mStartRingTime = mClockProxy.elapsedRealtime();
     }
 
     public CharSequence getCallScreeningAppName() {
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 6a7261e..1863cde 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -107,6 +107,10 @@
             // No audio management for calls in a conference, or external calls.
             return;
         }
+        if (oldState == newState) {
+            // State did not change, so no need to do anything.
+            return;
+        }
         Log.d(LOG_TAG, "Call state changed for TC@%s: %s -> %s", call.getId(),
                 CallState.toString(oldState), CallState.toString(newState));
 
@@ -464,8 +468,13 @@
     @VisibleForTesting
     public boolean startRinging() {
         synchronized (mCallsManager.getLock()) {
-            return mRinger.startRinging(mForegroundCall,
+            Call localForegroundCall = mForegroundCall;
+            boolean result = mRinger.startRinging(localForegroundCall,
                     mCallAudioRouteStateMachine.isHfpDeviceAvailable());
+            if (result) {
+                localForegroundCall.setStartRingTime();
+            }
+            return result;
         }
     }
 
@@ -537,14 +546,14 @@
         pw.println("Foreground call:");
         pw.println(mForegroundCall);
 
-        pw.println("CallAudioModeStateMachine pending messages:");
+        pw.println("CallAudioModeStateMachine:");
         pw.increaseIndent();
-        mCallAudioModeStateMachine.dumpPendingMessages(pw);
+        mCallAudioModeStateMachine.dump(pw);
         pw.decreaseIndent();
 
-        pw.println("CallAudioRouteStateMachine pending messages:");
+        pw.println("CallAudioRouteStateMachine:");
         pw.increaseIndent();
-        mCallAudioRouteStateMachine.dumpPendingMessages(pw);
+        mCallAudioRouteStateMachine.dump(pw);
         pw.decreaseIndent();
 
         pw.println("BluetoothDeviceManager:");
@@ -557,6 +566,7 @@
 
     @VisibleForTesting
     public void setIsTonePlaying(boolean isTonePlaying) {
+        Log.i(this, "setIsTonePlaying; isTonePlaying=%b", isTonePlaying);
         mIsTonePlaying = isTonePlaying;
         mCallAudioModeStateMachine.sendMessageWithArgs(
                 isTonePlaying ? CallAudioModeStateMachine.TONE_STARTED_PLAYING
@@ -728,10 +738,31 @@
                 .setHasAudioProcessingCalls(mAudioProcessingCalls.size() > 0)
                 .setIsTonePlaying(mIsTonePlaying)
                 .setForegroundCallIsVoip(
-                        mForegroundCall != null && mForegroundCall.getIsVoipAudioMode())
+                        mForegroundCall != null && isCallVoip(mForegroundCall))
                 .setSession(Log.createSubsession()).build();
     }
 
+    /**
+     * Determines if a {@link Call} is a VOIP call for audio purposes.
+     * For top level calls, we get this from {@link Call#getIsVoipAudioMode()}.  A {@link Call}
+     * representing a {@link android.telecom.Conference}, however, has no means of specifying that
+     * it is a VOIP conference, so we will get that attribute from one of the children.
+     * @param call The call.
+     * @return {@code true} if the call is a VOIP call, {@code false} if is a SIM call.
+     */
+    @VisibleForTesting
+    public boolean isCallVoip(Call call) {
+        if (call.isConference() && call.getChildCalls() != null
+                && call.getChildCalls().size() > 0 ) {
+            // If this is a conference with children, we can get the VOIP audio mode attribute from
+            // one of the children.  The Conference doesn't have a VOIP audio mode property, so we
+            // need to infer from the first child.
+            Call firstChild = call.getChildCalls().get(0);
+            return firstChild.getIsVoipAudioMode();
+        }
+        return call.getIsVoipAudioMode();
+    }
+
     private HashSet<Call> getBinForCall(Call call) {
         if (call.getState() == CallState.ANSWERED) {
             // If the call has the speed-up-mt-audio capability, treat answered state as active
diff --git a/src/com/android/server/telecom/CallAudioModeStateMachine.java b/src/com/android/server/telecom/CallAudioModeStateMachine.java
index 2aa9d5d..a1c5f4b 100644
--- a/src/com/android/server/telecom/CallAudioModeStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioModeStateMachine.java
@@ -22,6 +22,7 @@
 import android.telecom.Log;
 import android.telecom.Logging.Runnable;
 import android.telecom.Logging.Session;
+import android.util.LocalLog;
 import android.util.SparseArray;
 
 import com.android.internal.util.IState;
@@ -30,6 +31,11 @@
 import com.android.internal.util.StateMachine;
 
 public class CallAudioModeStateMachine extends StateMachine {
+    /**
+     * Captures the most recent CallAudioModeStateMachine state transitions and the corresponding
+     * changes to the {@link AudioManager#setMode}.
+     */
+    private LocalLog mLocalLog = new LocalLog(20);
     public static class Factory {
         public CallAudioModeStateMachine create(SystemStateHelper systemStateHelper,
                 AudioManager am) {
@@ -227,9 +233,12 @@
     private class UnfocusedState extends BaseState {
         @Override
         public void enter() {
+            Log.i(LOG_TAG, "Audio focus entering UNFOCUSED state");
+            mLocalLog.log("Enter UNFOCUSED");
             if (mIsInitialized) {
                 mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.NO_FOCUS);
                 mAudioManager.setMode(AudioManager.MODE_NORMAL);
+                mLocalLog.log("Mode MODE_NORMAL");
                 mMostRecentMode = AudioManager.MODE_NORMAL;
                 // Don't release focus here -- wait until we get a signal that any other audio
                 // operations triggered by this are done before releasing focus.
@@ -290,9 +299,12 @@
     private class AudioProcessingFocusState extends BaseState {
         @Override
         public void enter() {
+            Log.i(LOG_TAG, "Audio focus entering AUDIO_PROCESSING state");
+            mLocalLog.log("Enter AUDIO_PROCESSING");
             if (mIsInitialized) {
                 mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.NO_FOCUS);
                 mAudioManager.setMode(NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING);
+                mLocalLog.log("Mode MODE_CALL_SCREENING");
                 mMostRecentMode = NEW_AUDIO_MODE_FOR_AUDIO_PROCESSING;
             }
         }
@@ -371,6 +383,7 @@
                 // trips up the audio system.
                 if (mAudioManager.getMode() != AudioManager.MODE_CALL_SCREENING) {
                     mAudioManager.setMode(AudioManager.MODE_RINGTONE);
+                    mLocalLog.log("Mode MODE_RINGTONE");
                 }
                 mCallAudioManager.setCallAudioRouteFocusState(
                         CallAudioRouteStateMachine.RINGING_FOCUS);
@@ -383,6 +396,7 @@
         @Override
         public void enter() {
             Log.i(LOG_TAG, "Audio focus entering RINGING state");
+            mLocalLog.log("Enter RINGING");
             tryStartRinging();
             mCallAudioManager.stopCallWaiting();
         }
@@ -456,9 +470,11 @@
         @Override
         public void enter() {
             Log.i(LOG_TAG, "Audio focus entering SIM CALL state");
+            mLocalLog.log("Enter SIM_CALL");
             mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
                     AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
             mAudioManager.setMode(AudioManager.MODE_IN_CALL);
+            mLocalLog.log("Mode MODE_IN_CALL");
             mMostRecentMode = AudioManager.MODE_IN_CALL;
             mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS);
         }
@@ -537,9 +553,11 @@
         @Override
         public void enter() {
             Log.i(LOG_TAG, "Audio focus entering VOIP CALL state");
+            mLocalLog.log("Enter VOIP_CALL");
             mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
                     AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
             mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
+            mLocalLog.log("Mode MODE_IN_COMMUNICATION");
             mMostRecentMode = AudioManager.MODE_IN_COMMUNICATION;
             mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS);
         }
@@ -614,9 +632,11 @@
         @Override
         public void enter() {
             Log.i(LOG_TAG, "Audio focus entering TONE/HOLDING state");
+            mLocalLog.log("Enter TONE/HOLDING");
             mAudioManager.requestAudioFocusForCall(AudioManager.STREAM_VOICE_CALL,
                     AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
             mAudioManager.setMode(mMostRecentMode);
+            mLocalLog.log("Mode " + mMostRecentMode);
             mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS);
         }
 
@@ -763,6 +783,13 @@
         getHandler().getLooper().dump(pw::println, "");
     }
 
+    public void dump(IndentingPrintWriter pw) {
+        pw.println("History:");
+        mLocalLog.dump(pw);
+        pw.println("Pending Msg:");
+        dumpPendingMessages(pw);
+    }
+
     @Override
     protected void onPostHandleMessage(Message msg) {
         Log.endSession();
diff --git a/src/com/android/server/telecom/CallAudioRoutePeripheralAdapter.java b/src/com/android/server/telecom/CallAudioRoutePeripheralAdapter.java
index 2b6ba64..d96f953 100644
--- a/src/com/android/server/telecom/CallAudioRoutePeripheralAdapter.java
+++ b/src/com/android/server/telecom/CallAudioRoutePeripheralAdapter.java
@@ -45,6 +45,16 @@
         return mBluetoothRouteManager.isBluetoothAudioConnectedOrPending();
     }
 
+    public boolean isHearingAidDeviceOn() {
+        return mBluetoothRouteManager.isCachedHearingAidDevice(
+                mBluetoothRouteManager.getBluetoothAudioConnectedDevice());
+    }
+
+    public boolean isLeAudioDeviceOn() {
+        return mBluetoothRouteManager.isCachedLeAudioDevice(
+                mBluetoothRouteManager.getBluetoothAudioConnectedDevice());
+    }
+
     @Override
     public void onBluetoothDeviceListChanged() {
         mCallAudioRouteStateMachine.sendMessageWithSessionInfo(
diff --git a/src/com/android/server/telecom/CallAudioRouteStateMachine.java b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
index e5a6ecc..2ed7d95 100644
--- a/src/com/android/server/telecom/CallAudioRouteStateMachine.java
+++ b/src/com/android/server/telecom/CallAudioRouteStateMachine.java
@@ -411,6 +411,8 @@
                         Log.w(this, "Ignoring switch to headset command. Not available.");
                     }
                     return HANDLED;
+                case CONNECT_DOCK:
+                    // fall through; we want to switch to speaker mode when docked and in a call.
                 case SWITCH_SPEAKER:
                 case USER_SWITCH_SPEAKER:
                     setSpeakerphoneOn(true);
@@ -486,6 +488,8 @@
                         Log.w(this, "Ignoring switch to headset command. Not available.");
                     }
                     return HANDLED;
+                case CONNECT_DOCK:
+                    // fall through; we want to go to the quiescent speaker route when out of a call
                 case SWITCH_SPEAKER:
                 case USER_SWITCH_SPEAKER:
                     transitionTo(mQuiescentSpeakerRoute);
@@ -537,10 +541,6 @@
                 case BT_AUDIO_DISCONNECTED:
                     // This may be sent as a confirmation by the BT stack after switch off BT.
                     return HANDLED;
-                case CONNECT_DOCK:
-                    setSpeakerphoneOn(true);
-                    sendInternalMessage(SWITCH_SPEAKER);
-                    return HANDLED;
                 case DISCONNECT_DOCK:
                     // Nothing to do here
                     return HANDLED;
@@ -875,8 +875,8 @@
                     return HANDLED;
                 case SWITCH_FOCUS:
                     if (msg.arg1 == NO_FOCUS) {
-                        // Only disconnect SCO audio here instead of routing away from BT entirely.
-                        mBluetoothRouteManager.disconnectSco();
+                        // Only disconnect audio here instead of routing away from BT entirely.
+                        mBluetoothRouteManager.disconnectAudio();
                         reinitialize();
                         mCallAudioManager.notifyAudioOperationsComplete();
                     } else if (msg.arg1 == RINGING_FOCUS
@@ -1273,6 +1273,8 @@
                 case SPEAKER_ON:
                     // Nothing to do
                     return HANDLED;
+                case DISCONNECT_DOCK:
+                    // Fall-through; same as if speaker goes off, we want to switch baseline.
                 case SPEAKER_OFF:
                     sendInternalMessage(SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE);
                     return HANDLED;
@@ -1619,6 +1621,15 @@
         quitNow();
     }
 
+    public void dump(IndentingPrintWriter pw) {
+        pw.print("Current state: ");
+        pw.println(getCurrentState().getName());
+        pw.println("Pending messages:");
+        pw.increaseIndent();
+        dumpPendingMessages(pw);
+        pw.decreaseIndent();
+    }
+
     public void dumpPendingMessages(IndentingPrintWriter pw) {
         getHandler().getLooper().dump(pw::println, "");
     }
@@ -1629,8 +1640,26 @@
 
     private void setSpeakerphoneOn(boolean on) {
         Log.i(this, "turning speaker phone %s", on);
-        mAudioManager.setSpeakerphoneOn(on);
-        mStatusBarNotifier.notifySpeakerphone(on);
+        AudioDeviceInfo speakerDevice = null;
+        for (AudioDeviceInfo info : mAudioManager.getAvailableCommunicationDevices()) {
+            if (info.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
+                speakerDevice = info;
+                break;
+            }
+        }
+        boolean speakerOn = false;
+        if (speakerDevice != null && on) {
+            boolean result = mAudioManager.setCommunicationDevice(speakerDevice);
+            if (result) {
+                speakerOn = true;
+            }
+        } else {
+            AudioDeviceInfo curDevice = mAudioManager.getCommunicationDevice();
+            if (curDevice != null && curDevice.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
+                mAudioManager.clearCommunicationDevice();
+            }
+        }
+        mStatusBarNotifier.notifySpeakerphone(speakerOn);
     }
 
     private void setBluetoothOn(String address) {
@@ -1678,8 +1707,8 @@
                     // may run as a separate user from the foreground user. If we
                     // used AudioManager directly, we would change mute for the system's
                     // user and not the current foreground, which we want to avoid.
-                    audio.setMicrophoneMute(
-                            mute, mContext.getOpPackageName(), getCurrentUserId());
+                    audio.setMicrophoneMute(mute, mContext.getOpPackageName(),
+                            getCurrentUserId(), mContext.getAttributionTag());
                 } catch (RemoteException e) {
                     Log.e(this, e, "Remote exception while toggling mute.");
                 }
diff --git a/src/com/android/server/telecom/CallDiagnosticServiceController.java b/src/com/android/server/telecom/CallDiagnosticServiceController.java
index d8ee475..7bd7288 100644
--- a/src/com/android/server/telecom/CallDiagnosticServiceController.java
+++ b/src/com/android/server/telecom/CallDiagnosticServiceController.java
@@ -60,7 +60,7 @@
      */
     public interface ContextProxy {
         List<ResolveInfo> queryIntentServicesAsUser(@NonNull Intent intent,
-                @PackageManager.ResolveInfoFlags int flags, @UserIdInt int userId);
+                int resolveInfoFlags, @UserIdInt int userId);
         boolean bindServiceAsUser(@NonNull @RequiresPermission Intent service,
                 @NonNull ServiceConnection conn, int flags, @NonNull UserHandle user);
         void unbindService(@NonNull ServiceConnection conn);
diff --git a/src/com/android/server/telecom/CallScreeningServiceHelper.java b/src/com/android/server/telecom/CallScreeningServiceHelper.java
index 9435250..167bd1b 100644
--- a/src/com/android/server/telecom/CallScreeningServiceHelper.java
+++ b/src/com/android/server/telecom/CallScreeningServiceHelper.java
@@ -145,9 +145,9 @@
 
         if (!bindCallScreeningService(mContext, mUserHandle, mPackageName, serviceConnection)) {
             Log.i(this, "bindAndGetCallIdentification - bind failed");
-            Log.addEvent(mCall, LogUtils.Events.BIND_SCREENING, mPackageName);
             mFuture.complete(null);
         }
+        Log.addEvent(mCall, LogUtils.Events.BIND_SCREENING, mPackageName);
 
         // Set up a timeout so that we're not waiting forever for the caller ID information.
         Handler handler = new Handler();
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index ea45abb..ef98e5a 100755
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -17,6 +17,10 @@
 package com.android.server.telecom;
 
 import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
+import static android.provider.CallLog.Calls.SHORT_RING_THRESHOLD;
+import static android.provider.CallLog.Calls.USER_MISSED_NEVER_RANG;
+import static android.provider.CallLog.Calls.USER_MISSED_NO_ANSWER;
+import static android.provider.CallLog.Calls.USER_MISSED_SHORT_RING;
 import static android.telecom.TelecomManager.ACTION_POST_CALL;
 import static android.telecom.TelecomManager.DURATION_LONG;
 import static android.telecom.TelecomManager.DURATION_MEDIUM;
@@ -136,6 +140,7 @@
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
@@ -339,10 +344,8 @@
     private RespondViaSmsManager mRespondViaSmsManager;
     private final Ringer mRinger;
     private final InCallWakeLockController mInCallWakeLockController;
-    // For this set initial table size to 16 because we add 13 listeners in
-    // the CallsManager constructor.
-    private final Set<CallsManagerListener> mListeners = Collections.newSetFromMap(
-            new ConcurrentHashMap<CallsManagerListener, Boolean>(16, 0.9f, 1));
+    private final CopyOnWriteArrayList<CallsManagerListener> mListeners =
+            new CopyOnWriteArrayList<>();
     private final HeadsetMediaButton mHeadsetMediaButton;
     private final WiredHeadsetManager mWiredHeadsetManager;
     private final SystemStateHelper mSystemStateHelper;
@@ -575,7 +578,6 @@
         mListeners.add(mInCallWakeLockController);
         mListeners.add(statusBarNotifier);
         mListeners.add(mCallLogManager);
-        mListeners.add(mPhoneStateBroadcaster);
         mListeners.add(mInCallController);
         mListeners.add(mCallDiagnosticServiceController);
         mListeners.add(mCallAudioManager);
@@ -586,6 +588,9 @@
         mListeners.add(mProximitySensorManager);
         mListeners.add(audioProcessingNotification);
 
+        // this needs to be after the mCallAudioManager
+        mListeners.add(mPhoneStateBroadcaster);
+
         // There is no USER_SWITCHED broadcast for user 0, handle it here explicitly.
         final UserManager userManager = UserManager.get(mContext);
         // Don't load missed call if it is run in split user model.
@@ -596,7 +601,7 @@
         IntentFilter intentFilter = new IntentFilter(
                 CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
         intentFilter.addAction(SystemContract.ACTION_BLOCK_SUPPRESSION_STATE_CHANGED);
-        context.registerReceiver(mReceiver, intentFilter);
+        context.registerReceiver(mReceiver, intentFilter, Context.RECEIVER_EXPORTED);
         mGraphHandlerThreads = new LinkedList<>();
     }
 
@@ -1526,6 +1531,16 @@
         Bundle phoneAccountExtra = account != null ? account.getExtras() : null;
         boolean isSelfManaged = account != null && account.isSelfManaged();
 
+        StringBuffer creationLogs = new StringBuffer();
+        creationLogs.append("requestedAcct:");
+        if (requestedAccountHandle == null) {
+            creationLogs.append("none");
+        } else {
+            creationLogs.append(requestedAccountHandle);
+        }
+        creationLogs.append(", selfMgd:");
+        creationLogs.append(isSelfManaged);
+
         // Create a call with original handle. The handle may be changed when the call is attached
         // to a connection service, but in most cases will remain the same.
         if (call == null) {
@@ -1544,7 +1559,7 @@
                     isConference, /* isConference */
                     mClockProxy,
                     mToastFactory);
-            call.initAnalytics(callingPackage);
+            call.initAnalytics(callingPackage, creationLogs.toString());
 
             // Ensure new calls related to self-managed calls/connections are set as such.  This
             // will be overridden when the actual connection is returned in startCreateConnection,
@@ -1616,7 +1631,8 @@
         // retrieved.
         CompletableFuture<List<PhoneAccountHandle>> setAccountHandle =
                 accountsForCall.whenCompleteAsync((potentialPhoneAccounts, exception) -> {
-                    Log.i(CallsManager.this, "set outgoing call phone acct stage");
+                    Log.i(CallsManager.this, "set outgoing call phone acct; potentialAccts=%s",
+                            potentialPhoneAccounts);
                     PhoneAccountHandle phoneAccountHandle;
                     if (potentialPhoneAccounts.size() == 1) {
                         phoneAccountHandle = potentialPhoneAccounts.get(0);
@@ -2032,6 +2048,8 @@
 
         return userPreferredAccountForContact.thenApply(phoneAccountHandle -> {
             if (phoneAccountHandle != null) {
+                Log.i(CallsManager.this, "findOutgoingCallPhoneAccount; contactPrefAcct=%s",
+                        phoneAccountHandle);
                 return Collections.singletonList(phoneAccountHandle);
             }
             // No preset account, check if default exists that supports the URI scheme for the
@@ -2041,6 +2059,8 @@
                             handle.getScheme(), initiatingUser);
             if (defaultPhoneAccountHandle != null &&
                     possibleAccounts.contains(defaultPhoneAccountHandle)) {
+                Log.i(CallsManager.this, "findOutgoingCallPhoneAccount; defaultAcctForScheme=%s",
+                        defaultPhoneAccountHandle);
                 return Collections.singletonList(defaultPhoneAccountHandle);
             }
             return possibleAccounts;
@@ -2066,7 +2086,7 @@
                                           int videoState, boolean shouldCancelCall,
                                           String uiAction) {
         Log.i(this, "onCallRedirectionComplete for Call %s with handle %s" +
-                " and phoneAccountHandle %s", call, handle, phoneAccountHandle);
+                " and phoneAccountHandle %s", call, Log.pii(handle), phoneAccountHandle);
 
         boolean endEarly = false;
         String disconnectReason = "";
@@ -2178,7 +2198,7 @@
      * @param callId The ID of the call to show the redirection dialog for.
      */
     private void showRedirectionDialog(@NonNull String callId, @NonNull CharSequence appName) {
-        AlertDialog confirmDialog = new AlertDialog.Builder(mContext).create();
+        AlertDialog confirmDialog = FrameworksUtils.makeAlertDialogBuilder(mContext).create();
         LayoutInflater layoutInflater = LayoutInflater.from(mContext);
         View dialogView = layoutInflater.inflate(R.layout.call_redirection_confirm_dialog, null);
 
@@ -3127,6 +3147,22 @@
             // be marked as missed.
             call.setOverrideDisconnectCauseCode(new DisconnectCause(DisconnectCause.MISSED));
         }
+        if (call.getState() == CallState.NEW
+                && disconnectCause.getCode() == DisconnectCause.MISSED) {
+            Log.i(this, "markCallAsDisconnected: missed call never rang ", call.getId());
+            call.setMissedReason(USER_MISSED_NEVER_RANG);
+        }
+        if (call.getState() == CallState.RINGING
+                || call.getState() == CallState.SIMULATED_RINGING) {
+            if (call.getStartRingTime() > 0
+                    && (mClockProxy.elapsedRealtime() - call.getStartRingTime())
+                    < SHORT_RING_THRESHOLD) {
+                Log.i(this, "markCallAsDisconnected; callid=%s, short ring.", call.getId());
+                call.setUserMissed(USER_MISSED_SHORT_RING);
+            } else if (call.getStartRingTime() > 0) {
+                call.setUserMissed(USER_MISSED_NO_ANSWER);
+            }
+        }
 
         // If a call diagnostic service is in use, we will log the original telephony-provided
         // disconnect cause, inform the CDS of the disconnection, and then chain the update of the
@@ -3285,7 +3321,7 @@
      *
      * @return {@code True} if there are any non-external calls, {@code false} otherwise.
      */
-    boolean hasAnyCalls() {
+    public boolean hasAnyCalls() {
         if (mCalls.isEmpty()) {
             return false;
         }
@@ -3972,6 +4008,19 @@
         return false;
     }
 
+    /**
+     * Determines if there are any ongoing self managed calls for the given package/user.
+     * @param packageName The package name to check.
+     * @param userHandle The userhandle to check.
+     * @return {@code true} if the app has ongoing calls, or {@code false} otherwise.
+     */
+    public boolean isInSelfManagedCall(String packageName, UserHandle userHandle) {
+        return mCalls.stream().anyMatch(
+                c -> c.isSelfManaged()
+                && c.getTargetPhoneAccount().getComponentName().getPackageName().equals(packageName)
+                && c.getTargetPhoneAccount().getUserHandle().equals(userHandle));
+    }
+
     @VisibleForTesting
     public int getNumCallsWithState(final boolean isSelfManaged, Call excludeCall,
                                     PhoneAccountHandle phoneAccountHandle, int... states) {
@@ -5568,4 +5617,21 @@
             UserHandle userHandle, ConnectionServiceWrapper service) {
         mConnectionServiceRepository.setService(componentName, userHandle, service);
     }
+
+    /**
+     * Generates a log "marking".  This is a unique call event which contains a specified message.
+     * A log mark is triggered by the command: adb shell telecom log-mark MESSAGE
+     * A tester can use this when executing tests to make it very clear when a particular test step
+     * was reached.
+     * @param message the message to mark in the logs.
+     */
+    public void requestLogMark(String message) {
+        mCalls.forEach(c -> Log.addEvent(c, LogUtils.Events.USER_LOG_MARK, message));
+        Log.addEvent(null /* global */, LogUtils.Events.USER_LOG_MARK, message);
+    }
+
+    @VisibleForTesting
+    public Ringer getRinger() {
+        return mRinger;
+    }
 }
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index da2669c..5bb1dbe 100755
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -45,6 +45,8 @@
 import android.telecom.StatusHints;
 import android.telecom.TelecomManager;
 import android.telecom.VideoProfile;
+import android.telephony.CellIdentity;
+import android.telephony.TelephonyManager;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telecom.IConnectionService;
@@ -60,6 +62,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.Objects;
 
 /**
  * Wrapper for {@link IConnectionService}s, handles binding to {@link IConnectionService} and keeps
@@ -965,6 +968,31 @@
 
                         if (alreadyAddedConnection != null
                                 && mCallIdMapper.getCall(callId) == null) {
+                            if (!Objects.equals(connection.getHandle(),
+                                    alreadyAddedConnection.getHandle())) {
+                                alreadyAddedConnection.setHandle(connection.getHandle());
+                            }
+                            if (connection.getHandlePresentation() !=
+                                    alreadyAddedConnection.getHandlePresentation()) {
+                                alreadyAddedConnection.setHandle(connection.getHandle(),
+                                        connection.getHandlePresentation());
+                            }
+                            if (!Objects.equals(connection.getCallerDisplayName(),
+                                    alreadyAddedConnection.getCallerDisplayName())) {
+                                alreadyAddedConnection.setCallerDisplayName(connection
+                                                .getCallerDisplayName(),
+                                        connection.getCallerDisplayNamePresentation());
+                            }
+                            if (connection.getConnectionCapabilities() !=
+                                    alreadyAddedConnection.getConnectionCapabilities()) {
+                                alreadyAddedConnection.setConnectionCapabilities(connection
+                                        .getConnectionCapabilities());
+                            }
+                            if (connection.getConnectionProperties() !=
+                                    alreadyAddedConnection.getConnectionProperties()) {
+                                alreadyAddedConnection.setConnectionCapabilities(connection
+                                        .getConnectionProperties());
+                            }
                             mCallIdMapper.addCall(alreadyAddedConnection, callId);
                             alreadyAddedConnection
                                     .replaceConnectionService(ConnectionServiceWrapper.this);
@@ -1236,6 +1264,24 @@
         }
     }
 
+    private CellIdentity getLastKnownCellIdentity() {
+        TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
+        if (telephonyManager != null) {
+            CellIdentity lastKnownCellIdentity = telephonyManager.getLastKnownCellIdentity();
+            try {
+                mAppOpsManager.noteOp(AppOpsManager.OP_FINE_LOCATION,
+                        mContext.getPackageManager().getPackageUid(
+                                getComponentName().getPackageName(), 0),
+                        getComponentName().getPackageName());
+            } catch (PackageManager.NameNotFoundException nameNotFoundException) {
+                Log.e(this, nameNotFoundException, "could not find the package -- %s",
+                        getComponentName().getPackageName());
+            }
+            return lastKnownCellIdentity;
+        }
+        return null;
+    }
+
     /**
      * Creates a conference for a new outgoing call or attach to an existing incoming call.
      */
@@ -1355,6 +1401,11 @@
                         Log.piiHandle(call.getHandle()) + " via:" +
                                 getComponentName().getPackageName());
 
+                if (call.isEmergencyCall()) {
+                    extras.putParcelable(Connection.EXTRA_LAST_KNOWN_CELL_IDENTITY,
+                            getLastKnownCellIdentity());
+                }
+
                 ConnectionRequest connectionRequest = new ConnectionRequest.Builder()
                         .setAccountHandle(call.getTargetPhoneAccount())
                         .setAddress(call.getHandle())
@@ -2066,11 +2117,11 @@
             // failure to connect; we handle all failures uniformly
             Call foundCall = mCallIdMapper.getCall(callId);
 
-            if (connection.getConnectTimeMillis() != 0) {
-                foundCall.setConnectTimeMillis(connection.getConnectTimeMillis());
-            }
-
             if (foundCall != null) {
+                if (connection.getConnectTimeMillis() != 0) {
+                    foundCall.setConnectTimeMillis(connection.getConnectTimeMillis());
+                }
+
                 // The post-dial digits are created when the call is first created.  Normally
                 // the ConnectionService is responsible for stripping them from the address, but
                 // since a failed connection will not have done this, we could end up with duplicate
diff --git a/src/com/android/server/telecom/CreateConnectionProcessor.java b/src/com/android/server/telecom/CreateConnectionProcessor.java
index e3b8dee..3561211 100644
--- a/src/com/android/server/telecom/CreateConnectionProcessor.java
+++ b/src/com/android/server/telecom/CreateConnectionProcessor.java
@@ -39,6 +39,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  * This class creates connections to place new outgoing calls or to attach to an existing incoming
@@ -386,8 +387,13 @@
             mAttemptRecords.clear();
             // Phone accounts in profile do not handle emergency call, use phone accounts in
             // current user.
+            // ONLY include phone accounts which are NOT self-managed; we will never consider a self
+            // managed phone account for placing an emergency call.
             List<PhoneAccount> allAccounts = mPhoneAccountRegistrar
-                    .getAllPhoneAccountsOfCurrentUser();
+                    .getAllPhoneAccountsOfCurrentUser()
+                    .stream()
+                    .filter(act -> !act.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED))
+                    .collect(Collectors.toList());
 
             if (allAccounts.isEmpty() && mContext.getPackageManager().hasSystemFeature(
                     PackageManager.FEATURE_TELEPHONY)) {
diff --git a/src/com/android/server/telecom/DockManager.java b/src/com/android/server/telecom/DockManager.java
index 46b2efc..dda5711 100644
--- a/src/com/android/server/telecom/DockManager.java
+++ b/src/com/android/server/telecom/DockManager.java
@@ -29,7 +29,12 @@
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
-/** Listens for and caches car dock state. */
+/**
+ * Listens for and caches car dock state.
+ * Testing; you can enable/disable dock with adb commands:
+ *   adb shell dumpsys DockObserver set state 3
+ *   adb shell dumpsys DockObserver set state 0
+ */
 @VisibleForTesting
 public class DockManager {
     @VisibleForTesting
diff --git a/src/com/android/server/telecom/FrameworksUtils.java b/src/com/android/server/telecom/FrameworksUtils.java
new file mode 100644
index 0000000..08a19f5
--- /dev/null
+++ b/src/com/android/server/telecom/FrameworksUtils.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.res.Configuration;
+
+/**
+ * This class provides utility functions over framework APIs
+ */
+public class FrameworksUtils {
+    /**
+     * Create a new instance of {@link AlertDialog.Builder}.
+     * @param context reference to a Context
+     * @return an instance of AlertDialog.Builder
+     */
+    public static AlertDialog.Builder makeAlertDialogBuilder(Context context) {
+        boolean isDarkTheme = (context.getResources().getConfiguration().uiMode
+                & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
+        return new AlertDialog.Builder(context, isDarkTheme
+                ? android.R.style.Theme_DeviceDefault_Dialog_Alert : 0);
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/server/telecom/HeadsetMediaButton.java b/src/com/android/server/telecom/HeadsetMediaButton.java
index ad95c34..b1471c2 100644
--- a/src/com/android/server/telecom/HeadsetMediaButton.java
+++ b/src/com/android/server/telecom/HeadsetMediaButton.java
@@ -46,6 +46,47 @@
     private static final int MSG_MEDIA_SESSION_INITIALIZE = 0;
     private static final int MSG_MEDIA_SESSION_SET_ACTIVE = 1;
 
+    /**
+     * Wrapper class that abstracts an instance of {@link MediaSession} to the
+     * {@link MediaSessionAdapter} interface this class uses.  This is done because
+     * {@link MediaSession} is a final class and cannot be mocked for testing purposes.
+     */
+    public class MediaSessionWrapper implements MediaSessionAdapter {
+        private final MediaSession mMediaSession;
+
+        public MediaSessionWrapper(MediaSession mediaSession) {
+            mMediaSession = mediaSession;
+        }
+
+        /**
+         * Sets the underlying {@link MediaSession} active status.
+         * @param active
+         */
+        @Override
+        public void setActive(boolean active) {
+            mMediaSession.setActive(active);
+        }
+
+        /**
+         * Gets the underlying {@link MediaSession} active status.
+         * @return {@code true} if active, {@code false} otherwise.
+         */
+        @Override
+        public boolean isActive() {
+            return mMediaSession.isActive();
+        }
+    }
+
+    /**
+     * Interface which defines the basic functionality of a {@link MediaSession} which is important
+     * for the {@link HeadsetMediaButton} to operator; this is for testing purposes so we can mock
+     * out that functionality.
+     */
+    public interface MediaSessionAdapter {
+        void setActive(boolean active);
+        boolean isActive();
+    }
+
     private final MediaSession.Callback mSessionCallback = new MediaSession.Callback() {
         @Override
         public boolean onMediaButtonEvent(Intent intent) {
@@ -81,7 +122,7 @@
                     session.setFlags(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY
                             | MediaSession.FLAG_HANDLES_MEDIA_BUTTONS);
                     session.setPlaybackToLocal(AUDIO_ATTRIBUTES);
-                    mSession = session;
+                    mSession = new MediaSessionWrapper(session);
                     break;
                 }
                 case MSG_MEDIA_SESSION_SET_ACTIVE: {
@@ -102,9 +143,37 @@
     private final Context mContext;
     private final CallsManager mCallsManager;
     private final TelecomSystem.SyncRoot mLock;
-    private MediaSession mSession;
+    private MediaSessionAdapter mSession;
     private KeyEvent mLastHookEvent;
 
+    /**
+     * Constructor used for testing purposes to initialize a {@link HeadsetMediaButton} with a
+     * specified {@link MediaSessionAdapter}.  Will not trigger MSG_MEDIA_SESSION_INITIALIZE and
+     * cause an actual {@link MediaSession} instance to be created.
+     * @param context the context
+     * @param callsManager the mock calls manager
+     * @param lock the lock
+     * @param adapter the adapter
+     */
+    @VisibleForTesting
+    public HeadsetMediaButton(
+            Context context,
+            CallsManager callsManager,
+            TelecomSystem.SyncRoot lock,
+            MediaSessionAdapter adapter) {
+        mContext = context;
+        mCallsManager = callsManager;
+        mLock = lock;
+        mSession = adapter;
+    }
+
+    /**
+     * Production code constructor; this version triggers MSG_MEDIA_SESSION_INITIALIZE which will
+     * create an actual instance of {@link MediaSession}.
+     * @param context the context
+     * @param callsManager the calls manager
+     * @param lock the telecom lock
+     */
     public HeadsetMediaButton(
             Context context,
             CallsManager callsManager,
@@ -155,6 +224,13 @@
         if (call.isExternalCall()) {
             return;
         }
+        handleCallAddition();
+    }
+
+    /**
+     * Triggers session activation due to call addition.
+     */
+    private void handleCallAddition() {
         mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_SET_ACTIVE, 1, 0).sendToTarget();
     }
 
@@ -164,6 +240,13 @@
         if (call.isExternalCall()) {
             return;
         }
+        handleCallRemoval();
+    }
+
+    /**
+     * Triggers session deactivation due to call removal.
+     */
+    private void handleCallRemoval() {
         if (!mCallsManager.hasAnyCalls()) {
             mMediaSessionHandler.obtainMessage(MSG_MEDIA_SESSION_SET_ACTIVE, 0, 0).sendToTarget();
         }
@@ -172,10 +255,20 @@
     /** ${inheritDoc} */
     @Override
     public void onExternalCallChanged(Call call, boolean isExternalCall) {
+        // Note: We don't use the onCallAdded/onCallRemoved methods here since they do checks to see
+        // if the call is external or not and would skip the session activation/deactivation.
         if (isExternalCall) {
-            onCallRemoved(call);
+            handleCallRemoval();
         } else {
-            onCallAdded(call);
+            handleCallAddition();
         }
     }
+
+    @VisibleForTesting
+    /**
+     * @return the handler this class instance uses for operation; used for unit testing.
+     */
+    public Handler getHandler() {
+        return mMediaSessionHandler;
+    }
 }
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index ca76456..ec87555 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -21,9 +21,13 @@
 
 import android.Manifest;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.AppOpsManager;
+import android.app.compat.CompatChanges;
 import android.app.Notification;
 import android.app.NotificationManager;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
 import android.content.AttributionSource;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -37,6 +41,7 @@
 import android.content.pm.ServiceInfo;
 import android.hardware.SensorPrivacyManager;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -86,7 +91,6 @@
         AppOpsManager.OnOpActiveChangedListener {
     public static final String NOTIFICATION_TAG = InCallController.class.getSimpleName();
     public static final int IN_CALL_SERVICE_NOTIFICATION_ID = 3;
-
     public class InCallServiceConnection {
         /**
          * Indicates that a call to {@link #connect(Call)} has succeeded and resulted in a
@@ -616,24 +620,17 @@
                     getInCallServiceComponent(packageName,
                             IN_CALL_SERVICE_TYPE_CAR_MODE_UI, true /* ignoreDisabed */);
 
-            if (!Objects.equals(currentConnectionInfo, carModeConnectionInfo)) {
+            if (!Objects.equals(currentConnectionInfo, carModeConnectionInfo)
+                    && carModeConnectionInfo != null) {
                 Log.i(this, "changeCarModeApp: " + currentConnectionInfo + " => "
                         + carModeConnectionInfo);
                 if (mIsConnected) {
                     mCurrentConnection.disconnect();
                 }
 
-                if (carModeConnectionInfo != null) {
-                    // Valid car mode app.
-                    mCarModeConnection = mCurrentConnection =
-                            new InCallServiceBindingConnection(carModeConnectionInfo);
-                    mIsCarMode = true;
-                } else {
-                    // The app is not enabled. Using the default dialer connection instead
-                    mCarModeConnection = null;
-                    mIsCarMode = false;
-                    mCurrentConnection = mDialerConnection;
-                }
+                mCarModeConnection = mCurrentConnection =
+                        new InCallServiceBindingConnection(carModeConnectionInfo);
+                mIsCarMode = true;
 
                 int result = mCurrentConnection.connect(null);
                 mIsConnected = result == CONNECTION_SUCCEEDED;
@@ -947,6 +944,15 @@
         }
     };
 
+    private final BroadcastReceiver mUserAddedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
+                restrictPhoneCallOps();
+            }
+        }
+    };
+
     private final SystemStateListener mSystemStateListener = new SystemStateListener() {
         @Override
         public void onCarModeChanged(int priority, String packageName, boolean isCarMode) {
@@ -1055,6 +1061,7 @@
         mSystemStateHelper.addListener(mSystemStateListener);
         mClockProxy = clockProxy;
         restrictPhoneCallOps();
+        mContext.registerReceiver(mUserAddedReceiver, new IntentFilter(Intent.ACTION_USER_ADDED));
     }
 
     private void restrictPhoneCallOps() {
@@ -1615,25 +1622,31 @@
         mNonUIInCallServiceConnections.connect(call);
     }
 
-    private InCallServiceInfo getDefaultDialerComponent() {
-        String packageName = mDefaultDialerCache.getDefaultDialerApplication(
+    private @Nullable InCallServiceInfo getDefaultDialerComponent() {
+        String defaultPhoneAppName = mDefaultDialerCache.getDefaultDialerApplication(
                 mCallsManager.getCurrentUserHandle().getIdentifier());
-        String systemPackageName = mDefaultDialerCache.getSystemDialerApplication();
-        Log.d(this, "Default Dialer package: " + packageName);
+        String systemPhoneAppName = mDefaultDialerCache.getSystemDialerApplication();
 
-        InCallServiceInfo defaultDialerComponent =
-                (systemPackageName != null && systemPackageName.equals(packageName))
-                        ? getInCallServiceComponent(packageName, IN_CALL_SERVICE_TYPE_SYSTEM_UI,
-                        true /* ignoreDisabled */)
-                        : getInCallServiceComponent(packageName,
+        Log.d(this, "getDefaultDialerComponent: defaultPhoneAppName=[%s]", defaultPhoneAppName);
+        Log.d(this, "getDefaultDialerComponent: systemPhoneAppName=[%s]", systemPhoneAppName);
+
+        // Get the defaultPhoneApp InCallService component...
+        InCallServiceInfo defaultPhoneAppComponent =
+                (systemPhoneAppName != null && systemPhoneAppName.equals(defaultPhoneAppName)) ?
+                        /* The defaultPhoneApp is also the systemPhoneApp. Get systemPhoneApp info*/
+                        getInCallServiceComponent(defaultPhoneAppName,
+                                IN_CALL_SERVICE_TYPE_SYSTEM_UI, true /* ignoreDisabled */)
+                        /* The defaultPhoneApp is NOT the systemPhoneApp. Get defaultPhoneApp info*/
+                        : getInCallServiceComponent(defaultPhoneAppName,
                                 IN_CALL_SERVICE_TYPE_DEFAULT_DIALER_UI, true /* ignoreDisabled */);
-        /* TODO: in Android 12 re-enable this an InCallService is required by the dialer role.
-            if (packageName != null && defaultDialerComponent == null) {
-                // The in call service of default phone app is disabled, send notification.
-                sendCrashedInCallServiceNotification(packageName);
-            }
-        */
-        return defaultDialerComponent;
+
+        Log.d(this, "getDefaultDialerComponent: defaultPhoneAppComponent=[%s]",
+                defaultPhoneAppComponent);
+
+        // defaultPhoneAppComponent is null in the case when the defaultPhoneApp does not implement
+        // the InCallService && is the package is different from the systemPhoneApp
+
+        return defaultPhoneAppComponent;
     }
 
     private InCallServiceInfo getCurrentCarModeComponent() {
@@ -1696,11 +1709,16 @@
         }
 
         PackageManager packageManager = mContext.getPackageManager();
+        Context userContext = mContext.createContextAsUser(mCallsManager.getCurrentUserHandle(),
+                0 /* flags */);
+        PackageManager userPackageManager = userContext != null ?
+                userContext.getPackageManager() : packageManager;
         for (ResolveInfo entry : packageManager.queryIntentServicesAsUser(
                 serviceIntent,
                 PackageManager.GET_META_DATA | PackageManager.MATCH_DISABLED_COMPONENTS,
                 mCallsManager.getCurrentUserHandle().getIdentifier())) {
             ServiceInfo serviceInfo = entry.serviceInfo;
+
             if (serviceInfo != null) {
                 boolean isExternalCallsSupported = serviceInfo.metaData != null &&
                         serviceInfo.metaData.getBoolean(
@@ -1718,7 +1736,7 @@
                 }
 
                 boolean isEnabled = isServiceEnabled(foundComponentName,
-                        serviceInfo, packageManager);
+                        serviceInfo, userPackageManager);
                 boolean isRequestedType;
                 if (requestedType == IN_CALL_SERVICE_TYPE_INVALID) {
                     isRequestedType = true;
@@ -1737,6 +1755,10 @@
 
     private boolean isServiceEnabled(ComponentName componentName,
             ServiceInfo serviceInfo, PackageManager packageManager) {
+        if (packageManager == null) {
+            return serviceInfo.isEnabled();
+        }
+
         int componentEnabledState = packageManager.getComponentEnabledSetting(componentName);
 
         if (componentEnabledState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
@@ -2166,6 +2188,10 @@
     public void handleCarModeChange(int priority, String packageName, boolean isCarMode) {
         Log.i(this, "handleCarModeChange: packageName=%s, priority=%d, isCarMode=%b",
                 packageName, priority, isCarMode);
+        if (packageName == null) {
+            Log.i(this, "handleCarModeChange: Got null packageName, ignoring");
+            return;
+        }
         // Don't ignore the signal if we are disabling car mode; package may be uninstalled.
         if (isCarMode && !isCarModeInCallService(packageName)) {
             Log.i(this, "handleCarModeChange: not a valid InCallService; packageName=%s",
diff --git a/src/com/android/server/telecom/InCallTonePlayer.java b/src/com/android/server/telecom/InCallTonePlayer.java
index 524d119..4665ec2 100644
--- a/src/com/android/server/telecom/InCallTonePlayer.java
+++ b/src/com/android/server/telecom/InCallTonePlayer.java
@@ -33,6 +33,7 @@
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * Play a call-related tone (ringback, busy signal, etc.) either through ToneGenerator, or using a
@@ -181,12 +182,15 @@
     private static final int STATE_ON = 1;
     private static final int STATE_STOPPED = 2;
 
+    // Invalid audio stream
+    private static final int STREAM_INVALID = -1;
+
     /**
      * Keeps count of the number of actively playing tones so that we can notify CallAudioManager
      * when we need focus and when it can be release. This should only be manipulated from the main
      * thread.
      */
-    private static int sTonesPlaying = 0;
+    private static AtomicInteger sTonesPlaying = new AtomicInteger(0);
 
     private final CallAudioManager mCallAudioManager;
     private final CallAudioRoutePeripheralAdapter mCallAudioRoutePeripheralAdapter;
@@ -213,6 +217,12 @@
     private final AudioManagerAdapter mAudioManagerAdapter;
 
     /**
+     * Latch used for awaiting on playback, which may be interrupted if the tone is stopped from
+     * outside the playback.
+     */
+    private final CountDownLatch mPlaybackLatch = new CountDownLatch(1);
+
+    /**
      * Initializes the tone player. Private; use the {@link Factory} to create tone players.
      *
      * @param toneId ID of the tone to play, see TONE_* constants.
@@ -355,8 +365,14 @@
             if (mCallAudioRoutePeripheralAdapter.isBluetoothAudioOn()) {
                 stream = AudioManager.STREAM_BLUETOOTH_SCO;
             }
-
             if (toneType != ToneGenerator.TONE_UNKNOWN) {
+                if (stream == AudioManager.STREAM_BLUETOOTH_SCO) {
+                    // Override audio stream for BT le device and hearing aid device
+                    if (mCallAudioRoutePeripheralAdapter.isLeAudioDeviceOn()
+                            || mCallAudioRoutePeripheralAdapter.isHearingAidDeviceOn()) {
+                        stream = AudioManager.STREAM_VOICE_CALL;
+                    }
+                }
                 playToneGeneratorTone(stream, toneVolume, toneType, toneLengthMillis);
             } else if (mediaResourceId != TONE_RESOURCE_ID_UNDEFINED) {
                 playMediaTone(stream, mediaResourceId);
@@ -388,26 +404,21 @@
             }
 
             Log.i(this, "playToneGeneratorTone: toneType=%d", toneType);
-            // TODO: Certain CDMA tones need to check the ringer-volume state before
-            // playing. See CallNotifier.InCallTonePlayer.
 
-            // TODO: Some tones play through the end of a call so we need to inform
-            // CallAudioManager that we want focus the same way that Ringer does.
-
-            synchronized (this) {
-                if (mState != STATE_STOPPED) {
-                    mState = STATE_ON;
-                    toneGenerator.startTone(toneType);
-                    try {
-                        Log.v(this, "Starting tone %d...waiting for %d ms.", mToneId,
-                                toneLengthMillis + TIMEOUT_BUFFER_MILLIS);
-                        wait(toneLengthMillis + TIMEOUT_BUFFER_MILLIS);
-                    } catch (InterruptedException e) {
-                        Log.w(this, "wait interrupted", e);
-                    }
+            mState = STATE_ON;
+            toneGenerator.startTone(toneType);
+            try {
+                Log.v(this, "Starting tone %d...waiting for %d ms.", mToneId,
+                        toneLengthMillis + TIMEOUT_BUFFER_MILLIS);
+                if (mPlaybackLatch.await(toneLengthMillis + TIMEOUT_BUFFER_MILLIS,
+                        TimeUnit.MILLISECONDS)) {
+                    Log.i(this, "playToneGeneratorTone: tone playback stopped.");
                 }
+            } catch (InterruptedException e) {
+                Log.w(this, "playToneGeneratorTone: wait interrupted", e);
             }
-            mState = STATE_OFF;
+            // Redundant; don't want anyone re-using at this point.
+            mState = STATE_STOPPED;
         } finally {
             if (toneGenerator != null) {
                 toneGenerator.release();
@@ -421,42 +432,40 @@
      * @param toneResourceId The resource ID of the tone to play.
      */
     private void playMediaTone(int stream, int toneResourceId) {
-        synchronized (this) {
-            if (mState != STATE_STOPPED) {
-                mState = STATE_ON;
+        mState = STATE_ON;
+        Log.i(this, "playMediaTone: toneResourceId=%d", toneResourceId);
+        AudioAttributes attributes = new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
+                .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
+                .setLegacyStreamType(stream)
+                .build();
+        mToneMediaPlayer = mMediaPlayerFactory.get(toneResourceId, attributes);
+        mToneMediaPlayer.setLooping(false);
+        int durationMillis = mToneMediaPlayer.getDuration();
+        mToneMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+            @Override
+            public void onCompletion(MediaPlayer mp) {
+                Log.i(InCallTonePlayer.this, "playMediaTone: toneResourceId=%d completed.",
+                        toneResourceId);
+                mPlaybackLatch.countDown();
             }
-            Log.i(this, "playMediaTone: toneResourceId=%d", toneResourceId);
-            AudioAttributes attributes = new AudioAttributes.Builder()
-                    .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION)
-                    .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
-                    .setLegacyStreamType(stream)
-                    .build();
-            mToneMediaPlayer = mMediaPlayerFactory.get(toneResourceId, attributes);
-            mToneMediaPlayer.setLooping(false);
-            int durationMillis = mToneMediaPlayer.getDuration();
-            final CountDownLatch toneLatch = new CountDownLatch(1);
-            mToneMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
-                @Override
-                public void onCompletion(MediaPlayer mp) {
-                    Log.i(this, "playMediaTone: toneResourceId=%d completed.", toneResourceId);
-                    synchronized (InCallTonePlayer.this) {
-                        mState = STATE_OFF;
-                    }
-                    mToneMediaPlayer.release();
-                    mToneMediaPlayer = null;
-                    toneLatch.countDown();
-                }
-            });
-            mToneMediaPlayer.start();
-            try {
-                // Wait for the tone to stop playing; timeout at 2x the length of the file just to
-                // be on the safe side.
-                toneLatch.await(durationMillis * 2, TimeUnit.MILLISECONDS);
-            } catch (InterruptedException ie) {
-                Log.e(this, ie, "playMediaTone: tone playback interrupted.");
-            }
-        }
+        });
 
+        try {
+            mToneMediaPlayer.start();
+            // Wait for the tone to stop playing; timeout at 2x the length of the file just to
+            // be on the safe side.  Playback can also be stopped via stopTone().
+            if (mPlaybackLatch.await(durationMillis * 2, TimeUnit.MILLISECONDS)) {
+                Log.i(this, "playMediaTone: tone playback stopped.");
+            }
+        } catch (InterruptedException ie) {
+            Log.e(this, ie, "playMediaTone: tone playback interrupted.");
+        } finally {
+            // Redundant; don't want anyone re-using at this point.
+            mState = STATE_STOPPED;
+            mToneMediaPlayer.release();
+            mToneMediaPlayer = null;
+        }
     }
 
     @VisibleForTesting
@@ -467,8 +476,12 @@
             return false;
         }
 
-        sTonesPlaying++;
-        if (sTonesPlaying == 1) {
+        // Tone already done; don't allow re-used
+        if (mState == STATE_STOPPED) {
+            return false;
+        }
+
+        if (sTonesPlaying.incrementAndGet() == 1) {
             mCallAudioManager.setIsTonePlaying(true);
         }
 
@@ -493,29 +506,38 @@
      */
     @VisibleForTesting
     public void stopTone() {
-        synchronized (this) {
-            if (mState == STATE_ON) {
-                Log.d(this, "Stopping the tone %d.", mToneId);
-                notify();
-            }
-            mState = STATE_STOPPED;
-        }
+        Log.i(this, "stopTone: Stopping the tone %d.", mToneId);
+        // Notify the playback to end early.
+        mPlaybackLatch.countDown();
+
+        mState = STATE_STOPPED;
     }
 
     @VisibleForTesting
     public void cleanup() {
-        sTonesPlaying = 0;
+        sTonesPlaying.set(0);
     }
 
     private void cleanUpTonePlayer() {
+        Log.d(this, "cleanUpTonePlayer(): posting cleanup");
         // Release focus on the main thread.
         mMainThreadHandler.post(new Runnable("ICTP.cUTP", mLock) {
             @Override
             public void loggedRun() {
-                if (sTonesPlaying == 0) {
-                    Log.wtf(this, "Over-releasing focus for tone player.");
-                } else if (--sTonesPlaying == 0 && mCallAudioManager != null) {
-                    mCallAudioManager.setIsTonePlaying(false);
+                int newToneCount = sTonesPlaying.updateAndGet( t -> Math.min(0, t--));
+
+                if (newToneCount == 0) {
+                    Log.i(InCallTonePlayer.this,
+                            "cleanUpTonePlayer(): tonesPlaying=%d, tone completed", newToneCount);
+                    if (mCallAudioManager != null) {
+                        mCallAudioManager.setIsTonePlaying(false);
+                    } else {
+                        Log.w(InCallTonePlayer.this,
+                                "cleanUpTonePlayer(): mCallAudioManager is null!");
+                    }
+                } else {
+                    Log.i(InCallTonePlayer.this,
+                            "cleanUpTonePlayer(): tonesPlaying=%d; still playing", newToneCount);
                 }
             }
         }.prepare());
diff --git a/src/com/android/server/telecom/InCallWakeLockController.java b/src/com/android/server/telecom/InCallWakeLockController.java
index b37883d..bc555e2 100644
--- a/src/com/android/server/telecom/InCallWakeLockController.java
+++ b/src/com/android/server/telecom/InCallWakeLockController.java
@@ -60,10 +60,18 @@
         handleWakeLock();
     }
 
+    @Override
+    public void onExternalCallChanged(Call call, boolean isExternalCall) {
+        // In case a call changes its external call state during ringing, we need to trigger
+        // the wake lock update correspondingly. External call is handled by another device
+        // and should not hold a wake lock on the local device.
+        handleWakeLock();
+    }
+
     private void handleWakeLock() {
         // We grab a full lock as long as there exists a ringing call.
         Call ringingCall = mCallsManager.getRingingOrSimulatedRingingCall();
-        if (ringingCall != null) {
+        if (ringingCall != null && !ringingCall.isExternalCall()) {
             mTelecomWakeLock.acquire();
             Log.i(this, "Acquiring full wake lock");
         } else {
diff --git a/src/com/android/server/telecom/LogUtils.java b/src/com/android/server/telecom/LogUtils.java
index f53f239..12e780f 100644
--- a/src/com/android/server/telecom/LogUtils.java
+++ b/src/com/android/server/telecom/LogUtils.java
@@ -21,6 +21,8 @@
 import android.telecom.Logging.EventManager;
 import android.telecom.Logging.EventManager.TimedEventPair;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -34,6 +36,9 @@
     private static final String LOGUTILS_TAG = "LogUtils";
 
     public static final boolean SYSTRACE_DEBUG = false; /* STOP SHIP if true */
+    private static boolean sInitializedLoggerListeners = false; // used to gate re-init of listeners
+    private static int sInitializedCounter = 0; /* For testing purposes only */
+    private static final Object sLock = new Object(); // Coarse lock for all of LogUtils
 
     public static class EventTimer {
         private long mLastElapsedMillis;
@@ -203,6 +208,7 @@
         public static final String CALL_DIAGNOSTIC_SERVICE_TIMEOUT =
                 "CALL_DIAGNOSTIC_SERVICE_TIMEOUT";
         public static final String VERSTAT_CHANGED = "VERSTAT_CHANGED";
+        public static final String SET_VOIP_MODE = "SET_VOIP_MODE";
 
         public static class Timings {
             public static final String ACCEPT_TIMING = "accept";
@@ -250,12 +256,13 @@
         EventManager.Loggable recordEntry = eventRecord.getRecordEntry();
         if (recordEntry instanceof Call) {
             Call callRecordEntry = (Call) recordEntry;
-            android.telecom.Log.i(LOGUTILS_TAG, "EventRecord added as Call: " + callRecordEntry);
             Analytics.CallInfo callInfo = callRecordEntry.getAnalytics();
             if(callInfo != null) {
                 callInfo.setCallEvents(eventRecord);
             } else {
-                android.telecom.Log.w(LOGUTILS_TAG, "Could not get Analytics CallInfo.");
+                if(!android.telecom.Log.isUnitTestingEnabled()) {
+                    android.telecom.Log.w(LOGUTILS_TAG, "Could not get Analytics CallInfo.");
+                }
             }
         } else {
             android.telecom.Log.w(LOGUTILS_TAG, "Non-Call EventRecord Added.");
@@ -263,13 +270,41 @@
     }
 
     public static void initLogging(Context context) {
-        android.telecom.Log.setTag(TAG);
-        android.telecom.Log.setSessionContext(context);
-        for (EventManager.TimedEventPair p : Events.Timings.sTimedEvents) {
-            android.telecom.Log.addRequestResponsePair(p);
+        android.telecom.Log.d(LOGUTILS_TAG, "initLogging: attempting to acquire LogUtils sLock");
+        synchronized (sLock) {
+            android.telecom.Log.d(LOGUTILS_TAG, "initLogging: grabbed LogUtils sLock");
+            if (!sInitializedLoggerListeners) {
+                android.telecom.Log.d(LOGUTILS_TAG,
+                        "initLogging: called for first time. Registering the EventListener &"
+                                + " SessionListener.");
+
+                android.telecom.Log.setTag(TAG);
+                android.telecom.Log.setSessionContext(context);
+                for (EventManager.TimedEventPair p : Events.Timings.sTimedEvents) {
+                    android.telecom.Log.addRequestResponsePair(p);
+                }
+                android.telecom.Log.registerEventListener(LogUtils::eventRecordAdded);
+                // Store analytics about recently completed Sessions.
+                android.telecom.Log.registerSessionListener(Analytics::addSessionTiming);
+
+                // Ensure LogUtils#initLogging(Context) is called once throughout the entire
+                // lifecycle of not only TelecomSystem, but the Testing Framework.
+                sInitializedLoggerListeners = true;
+                sInitializedCounter++; /* For testing purposes only */
+            } else {
+                android.telecom.Log.d(LOGUTILS_TAG, "initLogging: called again. Doing nothing.");
+            }
         }
-        android.telecom.Log.registerEventListener(LogUtils::eventRecordAdded);
-        // Store analytics about recently completed Sessions.
-        android.telecom.Log.registerSessionListener(Analytics::addSessionTiming);
+    }
+
+    /**
+     * Needed in order to test if the registerEventListener & registerSessionListener are ever
+     * re-initialized in the entire process of the Testing Framework or TelecomSystem.
+     *
+     * @return the number of times initLogging(Context) listeners have been initialized
+     */
+    @VisibleForTesting
+    public static int getInitializedCounter() {
+        return sInitializedCounter;
     }
 }
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index f500828..0becaef 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -509,7 +509,11 @@
         android.telecom.Call.Details.CAPABILITY_TRANSFER,
 
         Connection.CAPABILITY_TRANSFER_CONSULTATIVE,
-        android.telecom.Call.Details.CAPABILITY_TRANSFER_CONSULTATIVE
+        android.telecom.Call.Details.CAPABILITY_TRANSFER_CONSULTATIVE,
+
+        Connection.CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT,
+        android.telecom.Call.Details.CAPABILITY_REMOTE_PARTY_SUPPORTS_RTT
+
     };
 
     private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
diff --git a/src/com/android/server/telecom/PhoneAccountRegistrar.java b/src/com/android/server/telecom/PhoneAccountRegistrar.java
index ff7c031..c566e5a 100644
--- a/src/com/android/server/telecom/PhoneAccountRegistrar.java
+++ b/src/com/android/server/telecom/PhoneAccountRegistrar.java
@@ -19,9 +19,11 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -45,6 +47,7 @@
 import android.telecom.PhoneAccountHandle;
 import android.telephony.CarrierConfigManager;
 import android.telephony.PhoneNumberUtils;
+import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
@@ -76,6 +79,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -131,6 +135,26 @@
                 PhoneAccount phoneAccount) {}
     }
 
+    /**
+     * Receiver for detecting when a managed profile has been removed so that PhoneAccountRegistrar
+     * can clean up orphan {@link PhoneAccount}s
+     */
+    private final BroadcastReceiver mManagedProfileReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Log.startSession("PARbR.oR");
+            try {
+                synchronized (mLock) {
+                    if (intent.getAction().equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)) {
+                        cleanupOrphanedPhoneAccounts();
+                    }
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
+    };
+
     public static final String FILE_NAME = "phone-account-registrar-state.xml";
     @VisibleForTesting
     public static final int EXPECTED_STATE_VERSION = 9;
@@ -143,9 +167,11 @@
     private final AtomicFile mAtomicFile;
     private final Context mContext;
     private final UserManager mUserManager;
+    private final TelephonyManager mTelephonyManager;
     private final SubscriptionManager mSubscriptionManager;
     private final DefaultDialerCache mDefaultDialerCache;
     private final AppLabelProxy mAppLabelProxy;
+    private final TelecomSystem.SyncRoot mLock;
     private State mState;
     private UserHandle mCurrentUserHandle;
     private String mTestPhoneAccountPackageNameFilter;
@@ -154,24 +180,31 @@
             new PhoneAccountRegistrarWriteLock() {};
 
     @VisibleForTesting
-    public PhoneAccountRegistrar(Context context, DefaultDialerCache defaultDialerCache,
-                                 AppLabelProxy appLabelProxy) {
-        this(context, FILE_NAME, defaultDialerCache, appLabelProxy);
+    public PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock,
+            DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy) {
+        this(context, lock, FILE_NAME, defaultDialerCache, appLabelProxy);
     }
 
     @VisibleForTesting
-    public PhoneAccountRegistrar(Context context, String fileName,
+    public PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock, String fileName,
             DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy) {
 
         mAtomicFile = new AtomicFile(new File(context.getFilesDir(), fileName));
 
         mState = new State();
         mContext = context;
+        mLock = lock;
         mUserManager = UserManager.get(context);
         mDefaultDialerCache = defaultDialerCache;
         mSubscriptionManager = SubscriptionManager.from(mContext);
+        mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
         mAppLabelProxy = appLabelProxy;
         mCurrentUserHandle = Process.myUserHandle();
+
+        // register context based receiver to clean up orphan phone accounts
+        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+        mContext.registerReceiver(mManagedProfileReceiver, intentFilter);
+
         read();
     }
 
@@ -187,9 +220,7 @@
         PhoneAccount account = getPhoneAccountUnchecked(accountHandle);
 
         if (account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
-            TelephonyManager tm =
-                    (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-            return tm.getSubscriptionId(accountHandle);
+            return mTelephonyManager.getSubscriptionId(accountHandle);
         }
         return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
     }
@@ -335,11 +366,11 @@
                 isSimAccount = true;
             }
 
-            Log.i(this, "setUserSelectedOutgoingPhoneAccount: %s", accountHandle);
             mState.defaultOutgoingAccountHandles
                     .put(userHandle, new DefaultPhoneAccountHandle(userHandle, accountHandle,
                             account.getGroupId()));
         }
+        Log.i(this, "setUserSelectedOutgoingPhoneAccount: %s", accountHandle);
 
         // Potentially update the default voice subid in SubscriptionManager.
         if (!Objects.equals(currentDefaultPhoneAccount, accountHandle)) {
@@ -453,6 +484,31 @@
     }
 
     /**
+     * Loops through all SIM accounts ({@link #getSimPhoneAccounts}) and returns those with SIM call
+     * manager components specified in carrier config that match {@code simCallManagerHandle}.
+     *
+     * <p>Note that this will return handles even when {@code simCallManagerHandle} has not yet been
+     * registered or was recently unregistered.
+     *
+     * <p>If the given {@code simCallManagerHandle} is not the SIM call manager for any active SIMs,
+     * returns an empty list.
+     */
+    public @NonNull List<PhoneAccountHandle> getSimPhoneAccountsFromSimCallManager(
+            @NonNull PhoneAccountHandle simCallManagerHandle) {
+        List<PhoneAccountHandle> matchingSimHandles = new ArrayList<>();
+        for (PhoneAccountHandle simHandle :
+                getSimPhoneAccounts(simCallManagerHandle.getUserHandle())) {
+            ComponentName simCallManager =
+                    getSystemSimCallManagerComponent(getSubscriptionIdForPhoneAccount(simHandle));
+            if (simCallManager == null) continue;
+            if (simCallManager.equals(simCallManagerHandle.getComponentName())) {
+                matchingSimHandles.add(simHandle);
+            }
+        }
+        return matchingSimHandles;
+    }
+
+    /**
      * Sets a filter for which {@link PhoneAccount}s will be returned from
      * {@link #filterRestrictedPhoneAccounts(List)}. If non-null, only {@link PhoneAccount}s
      * with the package name packageNameFilter will be returned. If null, no filter is set.
@@ -753,6 +809,25 @@
     }
 
     /**
+     * Retrieves a list of all {@link PhoneAccount#CAPABILITY_SELF_MANAGED} phone accounts
+     * registered by a specified package.
+     *
+     * @param packageName The name of the package that registered the phone accounts.
+     * @return The self-managed phone account handles for the given package.
+     */
+    public List<PhoneAccountHandle> getSelfManagedPhoneAccountsForPackage(String packageName,
+            UserHandle userHandle) {
+        List<PhoneAccountHandle> phoneAccountsHandles = new ArrayList<>();
+        for (PhoneAccountHandle pah : getPhoneAccountsForPackage(packageName,
+                userHandle)) {
+            if (isSelfManagedPhoneAccount(pah)) {
+                phoneAccountsHandles.add(pah);
+            }
+        }
+        return phoneAccountsHandles;
+    }
+
+    /**
      * Determines if a {@link PhoneAccountHandle} is for a self-managed {@link ConnectionService}.
      * @param handle The handle.
      * @return {@code true} if for a self-managed {@link ConnectionService}, {@code false}
@@ -865,6 +940,9 @@
         } else {
             fireAccountChanged(account);
         }
+        // If this is the SIM call manager, tell telephony when the voice ServiceState override
+        // needs to be updated.
+        maybeNotifyTelephonyForVoiceServiceState(account, /* registered= */ true);
     }
 
     public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) {
@@ -874,6 +952,9 @@
                 write();
                 fireAccountsChanged();
                 fireAccountUnRegistered(accountHandle);
+                // If this is the SIM call manager, tell telephony when the voice ServiceState
+                // override needs to be updated.
+                maybeNotifyTelephonyForVoiceServiceState(account, /* registered= */ false);
             }
         }
     }
@@ -1016,6 +1097,71 @@
         }
     }
 
+    private void maybeNotifyTelephonyForVoiceServiceState(
+            @NonNull PhoneAccount account, boolean registered) {
+        // TODO(b/215419665) what about SIM_SUBSCRIPTION accounts? They could theoretically also use
+        // these capabilities, but don't today. If they do start using them, then there will need to
+        // be a kind of "or" logic between SIM_SUBSCRIPTION and CONNECTION_MANAGER accounts to get
+        // the correct value of hasService for a given SIM.
+        boolean hasService = false;
+        List<PhoneAccountHandle> simHandlesToNotify;
+        if (account.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) {
+            // When we unregister the SIM call manager account, we always set hasService back to
+            // false since it is no longer providing OTT calling capability once unregistered.
+            if (registered) {
+                // Note: we do *not* early return when the SUPPORTS capability is not present
+                // because it's possible the SIM call manager could remove either capability at
+                // runtime and re-register. However, it is an error to use the AVAILABLE capability
+                // without also setting SUPPORTS.
+                hasService =
+                        account.hasCapabilities(
+                                PhoneAccount.CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS
+                                        | PhoneAccount.CAPABILITY_VOICE_CALLING_AVAILABLE);
+            }
+            // Notify for all SIMs that named this component as their SIM call manager in carrier
+            // config, since there may be more than one impacted SIM here.
+            simHandlesToNotify = getSimPhoneAccountsFromSimCallManager(account.getAccountHandle());
+        } else if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) {
+            // When new SIMs get registered, we notify them of their current voice status override.
+            // If there is no SIM call manager for this SIM, we treat that as hasService = false and
+            // still notify to ensure consistency.
+            if (!registered) {
+                // We don't do anything when SIMs are unregistered because we won't have an active
+                // subId to map back to phoneId and tell telephony about; that case is handled by
+                // telephony internally.
+                return;
+            }
+            PhoneAccountHandle simCallManagerHandle =
+                    getSimCallManagerFromHandle(
+                            account.getAccountHandle(), account.getAccountHandle().getUserHandle());
+            if (simCallManagerHandle != null) {
+                PhoneAccount simCallManager = getPhoneAccountUnchecked(simCallManagerHandle);
+                hasService =
+                        simCallManager != null
+                                && simCallManager.hasCapabilities(
+                                        PhoneAccount.CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS
+                                                | PhoneAccount.CAPABILITY_VOICE_CALLING_AVAILABLE);
+            }
+            simHandlesToNotify = Collections.singletonList(account.getAccountHandle());
+        } else {
+            // Not a relevant account - we only care about CONNECTION_MANAGER and SIM_SUBSCRIPTION.
+            return;
+        }
+        if (simHandlesToNotify.isEmpty()) return;
+        Log.i(
+                this,
+                "Notifying telephony of voice service override change for %d SIMs, hasService = %b",
+                simHandlesToNotify.size(),
+                hasService);
+        for (PhoneAccountHandle simHandle : simHandlesToNotify) {
+            // This may be null if there are no active SIMs but the device is still camped for
+            // emergency calls and registered a SIM_SUBSCRIPTION for that purpose.
+            TelephonyManager simTm = mTelephonyManager.createForPhoneAccountHandle(simHandle);
+            if (simTm == null) continue;
+            simTm.setVoiceServiceStateOverride(hasService);
+        }
+    }
+
     /**
      * Determines if the connection service specified by a {@link PhoneAccountHandle} requires the
      * {@link Manifest.permission#BIND_TELECOM_CONNECTION_SERVICE} permission.
@@ -1187,6 +1333,53 @@
         return accounts;
     }
 
+    /**
+     * Clean up the orphan {@code PhoneAccount}. An orphan {@code PhoneAccount} is a phone
+     * account that does not have a {@code UserHandle} or belongs to a deleted package.
+     *
+     * @return the number of orphan {@code PhoneAccount} deleted.
+     */
+    public int cleanupOrphanedPhoneAccounts() {
+        ArrayList<PhoneAccount> badAccountsList = new ArrayList<>();
+        HashMap<String, Boolean> packageLookup = new HashMap<>();
+        HashMap<PhoneAccount, Boolean> userHandleLookup = new HashMap<>();
+
+        // iterate over all accounts in registrar
+        for (PhoneAccount pa : mState.accounts) {
+            String packageName = pa.getAccountHandle().getComponentName().getPackageName();
+
+            // check if the package for the PhoneAccount is uninstalled
+            if (packageLookup.computeIfAbsent(packageName,
+                    pn -> isPackageUninstalled(pn))) {
+                badAccountsList.add(pa);
+            }
+            // check if PhoneAccount does not have a valid UserHandle (user was deleted)
+            else if (userHandleLookup.computeIfAbsent(pa,
+                    a -> isUserHandleDeletedForPhoneAccount(a))) {
+                badAccountsList.add(pa);
+            }
+        }
+
+        mState.accounts.removeAll(badAccountsList);
+
+        return badAccountsList.size();
+    }
+
+    public Boolean isPackageUninstalled(String packageName) {
+        try {
+            mContext.getPackageManager().getPackageInfo(packageName, 0);
+            return false;
+        } catch (PackageManager.NameNotFoundException e) {
+            return true;
+        }
+    }
+
+    private Boolean isUserHandleDeletedForPhoneAccount(PhoneAccount phoneAccount) {
+        UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle();
+        return (userHandle == null) ||
+                (mUserManager.getSerialNumberForUser(userHandle) == -1L);
+    }
+
     //
     // State Implementation for PhoneAccountRegistrar
     //
@@ -1221,7 +1414,7 @@
 
         public final UserHandle userHandle;
 
-        public final PhoneAccountHandle phoneAccountHandle;
+        public PhoneAccountHandle phoneAccountHandle;
 
         public final String groupId;
 
@@ -1245,6 +1438,14 @@
                     = mState.defaultOutgoingAccountHandles.get(Process.myUserHandle());
             pw.println("defaultOutgoing: " + (defaultPhoneAccountHandle == null ? "none" :
                     defaultPhoneAccountHandle.phoneAccountHandle));
+            PhoneAccountHandle defaultOutgoing =
+                    getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_TEL, mCurrentUserHandle);
+            pw.print("outgoingPhoneAccountForTelScheme: ");
+            if (defaultOutgoing == null) {
+                pw.println("none");
+            } else {
+                pw.println(defaultOutgoing);
+            }
             pw.println("simCallManager: " + getSimCallManager(mCurrentUserHandle));
             pw.println("phoneAccounts:");
             pw.increaseIndent();
@@ -1332,8 +1533,7 @@
         try {
             sortPhoneAccounts();
             ByteArrayOutputStream os = new ByteArrayOutputStream();
-            XmlSerializer serializer = new FastXmlSerializer();
-            serializer.setOutput(os, "utf-8");
+            XmlSerializer serializer = Xml.resolveSerializer(os);
             writeToXml(mState, serializer, mContext);
             serializer.flush();
             new AsyncXmlWriter().execute(os);
@@ -1352,12 +1552,11 @@
 
         boolean versionChanged = false;
 
-        XmlPullParser parser;
         try {
-            parser = Xml.newPullParser();
-            parser.setInput(new BufferedInputStream(is), null);
+            XmlPullParser parser = Xml.resolvePullParser(is);
             parser.nextTag();
             mState = readFromXml(parser, mContext);
+            migratePhoneAccountHandle(mState);
             versionChanged = mState.versionNumber < EXPECTED_STATE_VERSION;
 
         } catch (IOException | XmlPullParserException e) {
@@ -1402,6 +1601,50 @@
         return s != null ? s : new State();
     }
 
+    /**
+     * Try to migrate the ID of default phone account handle from IccId to SubId.
+     */
+    @VisibleForTesting
+    public void migratePhoneAccountHandle(State state) {
+        if (mSubscriptionManager == null) {
+            return;
+        }
+        // Use getAllSubscirptionInfoList() to get the mapping between iccId and subId
+        // from the subscription database
+        List<SubscriptionInfo> subscriptionInfos = mSubscriptionManager
+                .getAllSubscriptionInfoList();
+        Map<UserHandle, DefaultPhoneAccountHandle> defaultPhoneAccountHandles
+                = state.defaultOutgoingAccountHandles;
+        for (Map.Entry<UserHandle, DefaultPhoneAccountHandle> entry
+                : defaultPhoneAccountHandles.entrySet()) {
+            DefaultPhoneAccountHandle defaultPhoneAccountHandle = entry.getValue();
+
+            // Migrate Telephony PhoneAccountHandle only
+            String telephonyComponentName =
+                    "com.android.phone/com.android.services.telephony.TelephonyConnectionService";
+            if (!defaultPhoneAccountHandle.phoneAccountHandle.getComponentName()
+                    .flattenToString().equals(telephonyComponentName)) {
+                continue;
+            }
+            // Migrate from IccId to SubId
+            for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {
+                String phoneAccountHandleId = defaultPhoneAccountHandle.phoneAccountHandle.getId();
+                // Some phone account handle would store phone account handle id with the IccId
+                // string plus "F", and the getIccId() returns IccId string itself without "F",
+                // so here need to use "startsWith" to match.
+                if (phoneAccountHandleId != null && phoneAccountHandleId.startsWith(
+                        subscriptionInfo.getIccId())) {
+                    Log.i(this, "Found subscription ID to migrate: "
+                            + subscriptionInfo.getSubscriptionId());
+                    defaultPhoneAccountHandle.phoneAccountHandle = new PhoneAccountHandle(
+                            defaultPhoneAccountHandle.phoneAccountHandle.getComponentName(),
+                                    Integer.toString(subscriptionInfo.getSubscriptionId()));
+                    break;
+                }
+            }
+        }
+    }
+
     ////////////////////////////////////////////////////////////////////////////////////////////////
     //
     // XML serialization
diff --git a/src/com/android/server/telecom/RespondViaSmsSettings.java b/src/com/android/server/telecom/RespondViaSmsSettings.java
old mode 100644
new mode 100755
index 6d7c5c6..661038b
--- a/src/com/android/server/telecom/RespondViaSmsSettings.java
+++ b/src/com/android/server/telecom/RespondViaSmsSettings.java
@@ -99,7 +99,7 @@
         Log.d(this, "  preference = '%s'", preference);
         Log.d(this, "  newValue = '%s'", newValue);
 
-        EditTextPreference pref = (EditTextPreference) preference;
+        EditTextPreference pref = (EditTextPreference)findPreference(preference.getKey());
 
         // Copy the new text over to the title, just like in onCreate().
         // (Watch out: onPreferenceChange() is called *before* the
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index 91276de..b29b500 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -16,11 +16,14 @@
 
 package com.android.server.telecom;
 
+import static android.provider.CallLog.Calls.USER_MISSED_DND_MODE;
+import static android.provider.CallLog.Calls.USER_MISSED_LOW_RING_VOLUME;
+import static android.provider.CallLog.Calls.USER_MISSED_NO_VIBRATE;
+
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.Person;
 import android.content.Context;
-import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.Ringtone;
 import android.media.VolumeShaper;
@@ -28,6 +31,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.telecom.Log;
@@ -38,6 +42,7 @@
 
 import java.util.ArrayList;
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -59,6 +64,9 @@
     @VisibleForTesting
     public VibrationEffect mDefaultVibrationEffect;
 
+    // Used for test to notify the completion of RingerAttributes
+    private CountDownLatch mAttributesLatch;
+
     private static final long[] PULSE_PRIMING_PATTERN = {0,12,250,12,500}; // priming  + interval
 
     private static final int[] PULSE_PRIMING_AMPLITUDE = {0,255,0,255,0};  // priming  + interval
@@ -119,12 +127,9 @@
 
     private static final float EPSILON = 1e-6f;
 
-    private static final AudioAttributes VIBRATION_ATTRIBUTES = new AudioAttributes.Builder()
-            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
-            .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
-            .build();
+    private static final VibrationAttributes VIBRATION_ATTRIBUTES =
+            new VibrationAttributes.Builder().setUsage(VibrationAttributes.USAGE_RINGTONE).build();
 
-    private static VibrationEffect mRampingRingerVibrationEffect;
     private static VolumeShaper.Configuration mVolumeShaperConfig;
 
     /**
@@ -167,6 +172,12 @@
 
     private Handler mHandler = null;
 
+    /**
+     * Use lock different from the Telecom sync because ringing process is asynchronous outside that
+     * lock
+     */
+    private final Object mLock;
+
     /** Initializes the Ringer. */
     @VisibleForTesting
     public Ringer(
@@ -179,6 +190,7 @@
             VibrationEffectProxy vibrationEffectProxy,
             InCallController inCallController) {
 
+        mLock = new Object();
         mSystemSettingsUtil = systemSettingsUtil;
         mPlayerFactory = playerFactory;
         mContext = context;
@@ -189,7 +201,6 @@
         mRingtoneFactory = ringtoneFactory;
         mInCallController = inCallController;
         mVibrationEffectProxy = vibrationEffectProxy;
-        mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
 
         if (mContext.getResources().getBoolean(R.bool.use_simple_vibration_pattern)) {
             mDefaultVibrationEffect = mVibrationEffectProxy.createWaveform(SIMPLE_VIBRATION_PATTERN,
@@ -232,6 +243,7 @@
 
         RingerAttributes attributes = null;
         try {
+            mAttributesLatch = new CountDownLatch(1);
             attributes = ringerAttributesFuture.get(
                     RINGER_ATTRIBUTES_TIMEOUT, TimeUnit.MILLISECONDS);
         } catch (ExecutionException | InterruptedException | TimeoutException e) {
@@ -263,7 +275,9 @@
         VibrationEffect effect;
         CompletableFuture<Boolean> hapticsFuture = null;
         // Determine if the settings and DND mode indicate that the vibrator can be used right now.
-        boolean isVibratorEnabled = isVibratorEnabled(mContext, foregroundCall);
+        boolean isVibratorEnabled = isVibratorEnabled(mContext);
+        boolean shouldApplyRampingRinger =
+                isVibratorEnabled && mSystemSettingsUtil.isRampingRingerEnabled(mContext);
         if (attributes.isRingerAudible()) {
             mRingingCall = foregroundCall;
             Log.addEvent(foregroundCall, LogUtils.Events.START_RINGER);
@@ -271,34 +285,42 @@
             // call (for the purposes of direct-to-voicemail), the information about custom
             // ringtones should be available by the time this code executes. We can safely
             // request the custom ringtone from the call and expect it to be current.
-            if (mSystemSettingsUtil.applyRampingRinger(mContext)) {
+            if (shouldApplyRampingRinger) {
                 Log.i(this, "start ramping ringer.");
-                if (mSystemSettingsUtil.enableAudioCoupledVibrationForRampingRinger()) {
+                if (mSystemSettingsUtil.isAudioCoupledVibrationForRampingRingerEnabled()) {
                     effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall);
                 } else {
                     effect = mDefaultVibrationEffect;
                 }
                 if (mVolumeShaperConfig == null) {
                     float silencePoint = (float) (RAMPING_RINGER_VIBRATION_DURATION)
-                        / (float) (RAMPING_RINGER_VIBRATION_DURATION + RAMPING_RINGER_DURATION);
+                            / (float) (RAMPING_RINGER_VIBRATION_DURATION + RAMPING_RINGER_DURATION);
                     mVolumeShaperConfig = new VolumeShaper.Configuration.Builder()
-                        .setDuration(RAMPING_RINGER_VIBRATION_DURATION + RAMPING_RINGER_DURATION)
-                        .setCurve(new float[] {0.f, silencePoint + EPSILON /*keep monotonicity*/,
-                            1.f}, new float[] {0.f, 0.f, 1.f})
-                        .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
-                        .build();
+                            .setDuration(
+                                    RAMPING_RINGER_VIBRATION_DURATION + RAMPING_RINGER_DURATION)
+                            .setCurve(new float[]{0.f, silencePoint + EPSILON /*keep monotonicity*/,
+                                    1.f}, new float[]{0.f, 0.f, 1.f})
+                            .setInterpolatorType(
+                                    VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
+                            .build();
                 }
                 hapticsFuture = mRingtonePlayer.play(mRingtoneFactory, foregroundCall,
-                        mVolumeShaperConfig, isVibratorEnabled);
+                        mVolumeShaperConfig, attributes.isRingerAudible(), isVibratorEnabled);
             } else {
                 // Ramping ringtone is not enabled.
                 hapticsFuture = mRingtonePlayer.play(mRingtoneFactory, foregroundCall, null,
-                        isVibratorEnabled);
+                        attributes.isRingerAudible(), isVibratorEnabled);
                 effect = getVibrationEffectForCall(mRingtoneFactory, foregroundCall);
             }
         } else {
             Log.addEvent(foregroundCall, LogUtils.Events.SKIP_RINGING, "Inaudible: "
                     + attributes.getInaudibleReason());
+            if (isVibratorEnabled && mIsHapticPlaybackSupportedByDevice) {
+                // Attempt to run the attentional haptic ringtone first and fallback to the default
+                // vibration effect if hapticFuture is completed with false.
+                hapticsFuture = mRingtonePlayer.play(mRingtoneFactory, foregroundCall, null,
+                        attributes.isRingerAudible(), isVibratorEnabled);
+            }
             effect = mDefaultVibrationEffect;
         }
 
@@ -311,8 +333,8 @@
                             isUsingAudioCoupledHaptics, mIsHapticPlaybackSupportedByDevice);
                     maybeStartVibration(foregroundCall, shouldRingForContact, effect,
                             isVibratorEnabled, isRingerAudible);
-                } else if (mSystemSettingsUtil.applyRampingRinger(mContext)
-                           && !mSystemSettingsUtil.enableAudioCoupledVibrationForRampingRinger()) {
+                } else if (shouldApplyRampingRinger
+                        && !mSystemSettingsUtil.isAudioCoupledVibrationForRampingRingerEnabled()) {
                     Log.i(this, "startRinging: apply ramping ringer vibration");
                     maybeStartVibration(foregroundCall, shouldRingForContact, effect,
                             isVibratorEnabled, isRingerAudible);
@@ -338,20 +360,29 @@
 
     private void maybeStartVibration(Call foregroundCall, boolean shouldRingForContact,
         VibrationEffect effect, boolean isVibrationEnabled, boolean isRingerAudible) {
-        if (isVibrationEnabled
-                && !mIsVibrating && shouldRingForContact) {
-            if (mSystemSettingsUtil.applyRampingRinger(mContext)
-                    && isRingerAudible) {
-                Log.i(this, "start vibration for ramping ringer.");
+        synchronized (mLock) {
+            mAudioManager = mContext.getSystemService(AudioManager.class);
+            if (isVibrationEnabled && !mIsVibrating && shouldRingForContact) {
+                Log.addEvent(foregroundCall, LogUtils.Events.START_VIBRATOR,
+                        "hasVibrator=%b, userRequestsVibrate=%b, ringerMode=%d, isVibrating=%b",
+                        mVibrator.hasVibrator(),
+                        mSystemSettingsUtil.isRingVibrationEnabled(mContext),
+                        mAudioManager.getRingerModeInternal(), mIsVibrating);
+                if (mSystemSettingsUtil.isRampingRingerEnabled(mContext) && isRingerAudible) {
+                    Log.i(this, "start vibration for ramping ringer.");
+                } else {
+                    Log.i(this, "start normal vibration.");
+                }
                 mIsVibrating = true;
                 mVibrator.vibrate(effect, VIBRATION_ATTRIBUTES);
             } else {
-                Log.i(this, "start normal vibration.");
-                mIsVibrating = true;
-                mVibrator.vibrate(effect, VIBRATION_ATTRIBUTES);
+                foregroundCall.setUserMissed(USER_MISSED_NO_VIBRATE);
+                Log.addEvent(foregroundCall, LogUtils.Events.SKIP_VIBRATION,
+                        "hasVibrator=%b, userRequestsVibrate=%b, ringerMode=%d, isVibrating=%b",
+                        mVibrator.hasVibrator(),
+                        mSystemSettingsUtil.isRingVibrationEnabled(mContext),
+                        mAudioManager.getRingerModeInternal(), mIsVibrating);
             }
-        } else if (mIsVibrating) {
-            Log.addEvent(foregroundCall, LogUtils.Events.SKIP_VIBRATION, "already vibrating");
         }
     }
 
@@ -411,24 +442,26 @@
     }
 
     public void stopRinging() {
-        if (mRingingCall != null) {
-            Log.addEvent(mRingingCall, LogUtils.Events.STOP_RINGER);
-            mRingingCall = null;
-        }
+        synchronized (mLock) {
+            if (mRingingCall != null) {
+                Log.addEvent(mRingingCall, LogUtils.Events.STOP_RINGER);
+                mRingingCall = null;
+            }
 
-        mRingtonePlayer.stop();
+            mRingtonePlayer.stop();
 
-        // If we haven't started vibrating because we were waiting for the haptics info, cancel
-        // it and don't vibrate at all.
-        if (mVibrateFuture != null) {
-            mVibrateFuture.cancel(true);
-        }
+            // If we haven't started vibrating because we were waiting for the haptics info, cancel
+            // it and don't vibrate at all.
+            if (mVibrateFuture != null) {
+                mVibrateFuture.cancel(true);
+            }
 
-        if (mIsVibrating) {
-            Log.addEvent(mVibratingCall, LogUtils.Events.STOP_VIBRATOR);
-            mVibrator.cancel();
-            mIsVibrating = false;
-            mVibratingCall = null;
+            if (mIsVibrating) {
+                Log.addEvent(mVibratingCall, LogUtils.Events.STOP_VIBRATOR);
+                mVibrator.cancel();
+                mIsVibrating = false;
+                mVibratingCall = null;
+            }
         }
     }
 
@@ -464,48 +497,21 @@
     private boolean hasExternalRinger(Call foregroundCall) {
         Bundle intentExtras = foregroundCall.getIntentExtras();
         if (intentExtras != null) {
-            return intentExtras.getBoolean(TelecomManager.EXTRA_CALL_EXTERNAL_RINGER, false);
+            return intentExtras.getBoolean(TelecomManager.EXTRA_CALL_HAS_IN_BAND_RINGTONE, false);
         } else {
             return false;
         }
     }
 
-    private boolean isVibratorEnabled(Context context, Call call) {
+    private boolean isVibratorEnabled(Context context) {
         AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
-        int ringerMode = audioManager.getRingerModeInternal();
-        boolean shouldVibrate;
-        if (getVibrateWhenRinging(context)) {
-            shouldVibrate = ringerMode != AudioManager.RINGER_MODE_SILENT;
-        } else {
-            shouldVibrate = ringerMode == AudioManager.RINGER_MODE_VIBRATE;
-        }
-
-        // Technically this should be in the calling method, but it seemed a little odd to pass
-        // around a whole bunch of state just for logging purposes.
-        if (shouldVibrate) {
-            Log.addEvent(call, LogUtils.Events.START_VIBRATOR,
-                    "hasVibrator=%b, userRequestsVibrate=%b, ringerMode=%d, isVibrating=%b",
-                    mVibrator.hasVibrator(), mSystemSettingsUtil.canVibrateWhenRinging(context),
-                    ringerMode, mIsVibrating);
-        } else {
-            Log.addEvent(call, LogUtils.Events.SKIP_VIBRATION,
-                    "hasVibrator=%b, userRequestsVibrate=%b, ringerMode=%d, isVibrating=%b",
-                    mVibrator.hasVibrator(), mSystemSettingsUtil.canVibrateWhenRinging(context),
-                    ringerMode, mIsVibrating);
-        }
-
-        return shouldVibrate;
-    }
-
-    private boolean getVibrateWhenRinging(Context context) {
-        if (!mVibrator.hasVibrator()) {
-            return false;
-        }
-        return mSystemSettingsUtil.canVibrateWhenRinging(context)
-            || mSystemSettingsUtil.applyRampingRinger(context);
+        return mVibrator.hasVibrator()
+                && mSystemSettingsUtil.isRingVibrationEnabled(context)
+                && audioManager.getRingerModeInternal() != AudioManager.RINGER_MODE_SILENT;
     }
 
     private RingerAttributes getRingerAttributes(Call call, boolean isHfpDeviceAttached) {
+        mAudioManager = mContext.getSystemService(AudioManager.class);
         RingerAttributes.Builder builder = new RingerAttributes.Builder();
 
         LogUtils.EventTimer timer = new EventTimer();
@@ -557,6 +563,15 @@
         boolean shouldAcquireAudioFocus =
                 isRingerAudible || (isHfpDeviceAttached && shouldRingForContact) || isSelfManaged;
 
+        // Set missed reason according to attributes
+        if (!isVolumeOverZero) {
+            call.setUserMissed(USER_MISSED_LOW_RING_VOLUME);
+        }
+        if (!shouldRingForContact) {
+            call.setUserMissed(USER_MISSED_DND_MODE);
+        }
+
+        mAttributesLatch.countDown();
         return builder.setEndEarly(endEarly)
                 .setLetDialerHandleRinging(letDialerHandleRinging)
                 .setAcquireAudioFocus(shouldAcquireAudioFocus)
@@ -575,4 +590,13 @@
         }
         return mHandler;
     }
+
+    @VisibleForTesting
+    public boolean waitForAttributesCompletion() throws InterruptedException {
+        if (mAttributesLatch != null) {
+            return mAttributesLatch.await(RINGER_ATTRIBUTES_TIMEOUT, TimeUnit.MILLISECONDS);
+        } else {
+            return false;
+        }
+    }
 }
diff --git a/src/com/android/server/telecom/RingtoneFactory.java b/src/com/android/server/telecom/RingtoneFactory.java
index df89ee7..b1846fe 100644
--- a/src/com/android/server/telecom/RingtoneFactory.java
+++ b/src/com/android/server/telecom/RingtoneFactory.java
@@ -90,8 +90,14 @@
             if (UserManager.get(contextToUse).isUserUnlocked(contextToUse.getUserId())) {
                 defaultRingtoneUri = RingtoneManager.getActualDefaultRingtoneUri(contextToUse,
                         RingtoneManager.TYPE_RINGTONE);
+                if (defaultRingtoneUri == null) {
+                    Log.i(this, "getRingtone: defaultRingtoneUri for user is null.");
+                }
             } else {
                 defaultRingtoneUri = Settings.System.DEFAULT_RINGTONE_URI;
+                if (defaultRingtoneUri == null) {
+                    Log.i(this, "getRingtone: Settings.System.DEFAULT_RINGTONE_URI is null.");
+                }
             }
             if (defaultRingtoneUri == null) {
                 return null;
@@ -103,6 +109,27 @@
                 Log.e(this, npe, "getRingtone: NPE while getting ringtone.");
             }
         }
+        return setRingtoneAudioAttributes(ringtone);
+    }
+
+    public Ringtone getRingtone(Call incomingCall) {
+        return getRingtone(incomingCall, null);
+    }
+
+    /** Returns a ringtone to be used when ringer is not audible for the incoming call. */
+    @Nullable
+    public Ringtone getHapticOnlyRingtone() {
+        Uri ringtoneUri = Uri.parse("file://" + mContext.getString(
+                com.android.internal.R.string.config_defaultRingtoneVibrationSound));
+        Ringtone ringtone = RingtoneManager.getRingtone(mContext, ringtoneUri, null);
+        if (ringtone != null) {
+            // Make sure the sound is muted.
+            ringtone.setVolume(0);
+        }
+        return setRingtoneAudioAttributes(ringtone);
+    }
+
+    private Ringtone setRingtoneAudioAttributes(Ringtone ringtone) {
         if (ringtone != null) {
             ringtone.setAudioAttributes(new AudioAttributes.Builder()
                     .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
@@ -112,10 +139,6 @@
         return ringtone;
     }
 
-    public Ringtone getRingtone(Call incomingCall) {
-        return getRingtone(incomingCall, null);
-    }
-
     private Context getWorkProfileContextForUser(UserHandle userHandle) {
         // UserManager.getEnabledProfiles returns the enabled profiles along with the user's handle
         // itself (so we must filter out the user).
diff --git a/src/com/android/server/telecom/SystemSettingsUtil.java b/src/com/android/server/telecom/SystemSettingsUtil.java
index 7baae05..cdd14df 100644
--- a/src/com/android/server/telecom/SystemSettingsUtil.java
+++ b/src/com/android/server/telecom/SystemSettingsUtil.java
@@ -18,9 +18,10 @@
 
 import android.content.Context;
 import android.media.AudioManager;
+import android.os.VibrationAttributes;
+import android.os.Vibrator;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
-import android.telecom.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -39,9 +40,16 @@
                 0) == 1;
     }
 
-    public boolean canVibrateWhenRinging(Context context) {
+    public boolean isRingVibrationEnabled(Context context) {
+        // VIBRATE_WHEN_RINGING setting was deprecated, only RING_VIBRATION_INTENSITY controls the
+        // ringtone vibrations on/off state now. Ramping ringer should only be applied when ring
+        // vibration intensity is ON, otherwise the ringtone sound should not be delayed as there
+        // will be no ring vibration.
         return Settings.System.getIntForUser(context.getContentResolver(),
-                Settings.System.VIBRATE_WHEN_RINGING, 0, context.getUserId()) != 0;
+                Settings.System.RING_VIBRATION_INTENSITY,
+                context.getSystemService(Vibrator.class).getDefaultVibrationIntensity(
+                        VibrationAttributes.USAGE_RINGTONE),
+                context.getUserId()) != Vibrator.VIBRATION_INTENSITY_OFF;
     }
 
     public boolean isEnhancedCallBlockingEnabled(Context context) {
@@ -55,12 +63,11 @@
                 context.getUserId());
     }
 
-    public boolean applyRampingRinger(Context context) {
-        return Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.APPLY_RAMPING_RINGER, 0) == 1;
+    public boolean isRampingRingerEnabled(Context context) {
+        return context.getSystemService(AudioManager.class).isRampingRingerEnabled();
     }
 
-    public boolean enableAudioCoupledVibrationForRampingRinger() {
+    public boolean isAudioCoupledVibrationForRampingRingerEnabled() {
         return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY,
                 RAMPING_RINGER_AUDIO_COUPLED_VIBRATION_ENABLED, false);
     }
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index 86d5ebc..06a190b 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -26,6 +26,7 @@
 import static android.Manifest.permission.READ_SMS;
 import static android.Manifest.permission.REGISTER_SIM_SUBSCRIPTION;
 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
+import static android.Manifest.permission.MANAGE_OWN_CALLS;
 
 import android.Manifest;
 import android.app.ActivityManager;
@@ -117,7 +118,7 @@
         public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme,
                 String callingPackage, String callingFeatureId) {
             try {
-                Log.startSession("TSI.gDOPA");
+                Log.startSession("TSI.gDOPA", Log.getPackageAbbreviation(callingPackage));
                 synchronized (mLock) {
                     PhoneAccountHandle phoneAccountHandle = null;
                     final UserHandle callingUserHandle = Binder.getCallingUserHandle();
@@ -149,7 +150,7 @@
         public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount(String callingPackage) {
             synchronized (mLock) {
                 try {
-                    Log.startSession("TSI.gUSOPA");
+                    Log.startSession("TSI.gUSOPA", Log.getPackageAbbreviation(callingPackage));
                     if (!isDialerOrPrivileged(callingPackage, "getDefaultOutgoingPhoneAccount")) {
                         throw new SecurityException("Only the default dialer, or caller with "
                                 + "READ_PRIVILEGED_PHONE_STATE can call this method.");
@@ -193,7 +194,7 @@
         public List<PhoneAccountHandle> getCallCapablePhoneAccounts(
                 boolean includeDisabledAccounts, String callingPackage, String callingFeatureId) {
             try {
-                Log.startSession("TSI.gCCPA");
+                Log.startSession("TSI.gCCPA", Log.getPackageAbbreviation(callingPackage));
                 if (includeDisabledAccounts &&
                         !canReadPrivilegedPhoneState(
                                 callingPackage, "getCallCapablePhoneAccounts")) {
@@ -225,7 +226,7 @@
         public List<PhoneAccountHandle> getSelfManagedPhoneAccounts(String callingPackage,
                 String callingFeatureId) {
             try {
-                Log.startSession("TSI.gSMPA");
+                Log.startSession("TSI.gSMPA", Log.getPackageAbbreviation(callingPackage));
                 if (!canReadPhoneState(callingPackage, callingFeatureId,
                         "Requires READ_PHONE_STATE permission.")) {
                     throw new SecurityException("Requires READ_PHONE_STATE permission.");
@@ -249,10 +250,46 @@
         }
 
         @Override
+        public List<PhoneAccountHandle> getOwnSelfManagedPhoneAccounts(String callingPackage,
+                String callingFeatureId) {
+            try {
+                Log.startSession("TSI.gOSMPA", Log.getPackageAbbreviation(callingPackage));
+                try {
+                    enforceCallingPackage(callingPackage, "getOwnSelfManagedPhoneAccounts");
+                }
+                catch(SecurityException se){
+                    EventLog.writeEvent(0x534e4554, "231986341", Binder.getCallingUid(),
+                            "getOwnSelfManagedPhoneAccounts: invalid calling package");
+                    throw se;
+                }
+                if (!canReadMangeOwnCalls("Requires MANAGE_OWN_CALLS permission.")) {
+                    throw new SecurityException("Requires MANAGE_OWN_CALLS permission.");
+                }
+                synchronized (mLock) {
+                    final UserHandle callingUserHandle = Binder.getCallingUserHandle();
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        return mPhoneAccountRegistrar.getSelfManagedPhoneAccountsForPackage(
+                                callingPackage,
+                                callingUserHandle);
+                    } catch (Exception e) {
+                        Log.e(this, e,
+                                "getSelfManagedPhoneAccountsForPackage");
+                        throw e;
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public List<PhoneAccountHandle> getPhoneAccountsSupportingScheme(String uriScheme,
                 String callingPackage) {
             try {
-                Log.startSession("TSI.gPASS");
+                Log.startSession("TSI.gPASS", Log.getPackageAbbreviation(callingPackage));
                 try {
                     enforceModifyPermission(
                             "getPhoneAccountsSupportingScheme requires MODIFY_PHONE_STATE");
@@ -284,7 +321,7 @@
         public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName) {
             //TODO: Deprecate this in S
             try {
-                enforceCallingPackage(packageName);
+                enforceCallingPackage(packageName, "getPhoneAccountsForPackage");
             } catch (SecurityException se1) {
                 EventLog.writeEvent(0x534e4554, "153995334", Binder.getCallingUid(),
                         "getPhoneAccountsForPackage: invalid calling package");
@@ -319,6 +356,13 @@
         @Override
         public PhoneAccount getPhoneAccount(PhoneAccountHandle accountHandle,
                 String callingPackage) {
+            try {
+                enforceCallingPackage(callingPackage, "getPhoneAccount");
+            } catch (SecurityException se) {
+                EventLog.writeEvent(0x534e4554, "196406138", Binder.getCallingUid(),
+                        "getPhoneAccount: invalid calling package");
+                throw se;
+            }
             synchronized (mLock) {
                 final UserHandle callingUserHandle = Binder.getCallingUserHandle();
                 if (CompatChanges.isChangeEnabled(
@@ -494,12 +538,6 @@
             try {
                 Log.startSession("TSI.rPA");
                 synchronized (mLock) {
-                    if (!((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
-                                .isVoiceCapable()) {
-                        Log.w(this,
-                                "registerPhoneAccount not allowed on non-voice capable device.");
-                        return;
-                    }
                     try {
                         enforcePhoneAccountModificationForPackage(
                                 account.getAccountHandle().getComponentName().getPackageName());
@@ -525,6 +563,15 @@
                         if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) {
                             enforceRegisterMultiUser();
                         }
+                        // These capabilities are for SIM-based accounts only, so only the platform
+                        // and carrier-designated SIM call manager can register accounts with these
+                        // capabilities.
+                        if (account.hasCapabilities(
+                                        PhoneAccount.CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS)
+                                || account.hasCapabilities(
+                                        PhoneAccount.CAPABILITY_VOICE_CALLING_AVAILABLE)) {
+                            enforceRegisterVoiceCallingIndicationCapabilities(account);
+                        }
                         Bundle extras = account.getExtras();
                         if (extras != null
                                 && extras.getBoolean(PhoneAccount.EXTRA_SKIP_CALL_FILTERING)) {
@@ -852,7 +899,7 @@
         public boolean hasManageOngoingCallsPermission(String callingPackage) {
             try {
                 Log.startSession("TSI.hMOCP");
-                enforceCallingPackage(callingPackage);
+                enforceCallingPackage(callingPackage, "hasManageOngoingCallsPermission");
                 return PermissionChecker.checkPermissionForDataDeliveryFromDataSource(
                         mContext, Manifest.permission.MANAGE_ONGOING_CALLS,
                         Binder.getCallingPid(),
@@ -973,7 +1020,7 @@
         @Override
         public boolean endCall(String callingPackage) {
             try {
-                Log.startSession("TSI.eC");
+                Log.startSession("TSI.eC", Log.getPackageAbbreviation(callingPackage));
                 synchronized (mLock) {
                     if (!enforceAnswerCallPermission(callingPackage, Binder.getCallingUid())) {
                         throw new SecurityException("requires ANSWER_PHONE_CALLS permission");
@@ -997,7 +1044,7 @@
         @Override
         public void acceptRingingCall(String packageName) {
             try {
-                Log.startSession("TSI.aRC");
+                Log.startSession("TSI.aRC", Log.getPackageAbbreviation(packageName));
                 synchronized (mLock) {
                     if (!enforceAnswerCallPermission(packageName, Binder.getCallingUid())) return;
 
@@ -1020,7 +1067,7 @@
         @Override
         public void acceptRingingCallWithVideoState(String packageName, int videoState) {
             try {
-                Log.startSession("TSI.aRCWVS");
+                Log.startSession("TSI.aRCWVS", Log.getPackageAbbreviation(packageName));
                 synchronized (mLock) {
                     if (!enforceAnswerCallPermission(packageName, Binder.getCallingUid())) return;
 
@@ -1043,7 +1090,7 @@
         public void showInCallScreen(boolean showDialpad, String callingPackage,
                 String callingFeatureId) {
             try {
-                Log.startSession("TSI.sICS");
+                Log.startSession("TSI.sICS", Log.getPackageAbbreviation(callingPackage));
                 if (!canReadPhoneState(callingPackage, callingFeatureId, "showInCallScreen")) {
                     return;
                 }
@@ -1068,7 +1115,7 @@
         @Override
         public void cancelMissedCallsNotification(String callingPackage) {
             try {
-                Log.startSession("TSI.cMCN");
+                Log.startSession("TSI.cMCN", Log.getPackageAbbreviation(callingPackage));
                 synchronized (mLock) {
                     enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
                     UserHandle userHandle = Binder.getCallingUserHandle();
@@ -1089,7 +1136,7 @@
         @Override
         public boolean handlePinMmi(String dialString, String callingPackage) {
             try {
-                Log.startSession("TSI.hPM");
+                Log.startSession("TSI.hPM", Log.getPackageAbbreviation(callingPackage));
                 enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
 
                 // Switch identity so that TelephonyManager checks Telecom's permissions
@@ -1117,7 +1164,7 @@
         public boolean handlePinMmiForPhoneAccount(PhoneAccountHandle accountHandle,
                 String dialString, String callingPackage) {
             try {
-                Log.startSession("TSI.hPMFPA");
+                Log.startSession("TSI.hPMFPA", Log.getPackageAbbreviation(callingPackage));
 
                 enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
                 UserHandle callingUserHandle = Binder.getCallingUserHandle();
@@ -1158,7 +1205,7 @@
         public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle,
                 String callingPackage) {
             try {
-                Log.startSession("TSI.aAUFPA");
+                Log.startSession("TSI.aAUFPA", Log.getPackageAbbreviation(callingPackage));
                 enforcePermissionOrPrivilegedDialer(MODIFY_PHONE_STATE, callingPackage);
                 synchronized (mLock) {
                     if (!isPhoneAccountHandleVisibleToCallingUser(accountHandle,
@@ -1192,7 +1239,7 @@
         @Override
         public boolean isTtySupported(String callingPackage, String callingFeatureId) {
             try {
-                Log.startSession("TSI.iTS");
+                Log.startSession("TSI.iTS", Log.getPackageAbbreviation(callingPackage));
                 if (!canReadPhoneState(callingPackage, callingFeatureId, "isTtySupported")) {
                     throw new SecurityException("Only default dialer or an app with" +
                             "READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE can call this api");
@@ -1212,7 +1259,7 @@
         @Override
         public int getCurrentTtyMode(String callingPackage, String callingFeatureId) {
             try {
-                Log.startSession("TSI.gCTM");
+                Log.startSession("TSI.gCTM", Log.getPackageAbbreviation(callingPackage));
                 if (!canReadPhoneState(callingPackage, callingFeatureId, "getCurrentTtyMode")) {
                     return TelecomManager.TTY_MODE_OFF;
                 }
@@ -1444,7 +1491,7 @@
         public void startConference(List<Uri> participants, Bundle extras,
                 String callingPackage) {
             try {
-                Log.startSession("TSI.sC");
+                Log.startSession("TSI.sC", Log.getPackageAbbreviation(callingPackage));
                 if (!canCallPhone(callingPackage, "startConference")) {
                     throw new SecurityException("Package " + callingPackage + " is not allowed"
                             + " to start conference call");
@@ -1463,10 +1510,11 @@
         public void placeCall(Uri handle, Bundle extras, String callingPackage,
                 String callingFeatureId) {
             try {
-                Log.startSession("TSI.pC");
-                enforceCallingPackage(callingPackage);
+                Log.startSession("TSI.pC", Log.getPackageAbbreviation(callingPackage));
+                enforceCallingPackage(callingPackage, "placeCall");
 
                 PhoneAccountHandle phoneAccountHandle = null;
+                boolean clearPhoneAccountHandleExtra = false;
                 if (extras != null) {
                     phoneAccountHandle = extras.getParcelable(
                             TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
@@ -1478,17 +1526,24 @@
                 boolean isSelfManaged = phoneAccountHandle != null &&
                         isSelfManagedConnectionService(phoneAccountHandle);
                 if (isSelfManaged) {
-                    mContext.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_OWN_CALLS,
-                            "Self-managed ConnectionServices require MANAGE_OWN_CALLS permission.");
+                    try {
+                        mContext.enforceCallingOrSelfPermission(
+                                Manifest.permission.MANAGE_OWN_CALLS,
+                                "Self-managed ConnectionServices require "
+                                        + "MANAGE_OWN_CALLS permission.");
+                    } catch (SecurityException e) {
+                        // Fallback to use mobile network to avoid disclosing phone account handle
+                        // package information
+                        clearPhoneAccountHandleExtra = true;
+                    }
 
-                    if (!callingPackage.equals(
+                    if (!clearPhoneAccountHandleExtra && !callingPackage.equals(
                             phoneAccountHandle.getComponentName().getPackageName())
                             && !canCallPhone(callingPackage, callingFeatureId,
                             "CALL_PHONE permission required to place calls.")) {
-                        // The caller is not allowed to place calls, so we want to ensure that it
-                        // can only place calls through itself.
-                        throw new SecurityException("Self-managed ConnectionServices can only "
-                                + "place calls through their own ConnectionService.");
+                        // The caller is not allowed to place calls, so fallback to use mobile
+                        // network.
+                        clearPhoneAccountHandleExtra = true;
                     }
                 } else if (!canCallPhone(callingPackage, callingFeatureId, "placeCall")) {
                     throw new SecurityException("Package " + callingPackage
@@ -1523,6 +1578,9 @@
                         final Intent intent = new Intent(hasCallPrivilegedPermission ?
                                 Intent.ACTION_CALL_PRIVILEGED : Intent.ACTION_CALL, handle);
                         if (extras != null) {
+                            if (clearPhoneAccountHandleExtra) {
+                                extras.remove(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE);
+                            }
                             extras.setDefusable(true);
                             intent.putExtras(extras);
                         }
@@ -1696,10 +1754,14 @@
          * @see android.telecom.TelecomManager#isIncomingCallPermitted(PhoneAccountHandle)
          */
         @Override
-        public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
+        public boolean isIncomingCallPermitted(PhoneAccountHandle phoneAccountHandle,
+                String callingPackage) {
+            Log.startSession("TSI.iICP");
             try {
-                Log.startSession("TSI.iICP");
+                enforceCallingPackage(callingPackage, "isIncomingCallPermitted");
+                enforcePhoneAccountHandleMatchesCaller(phoneAccountHandle, callingPackage);
                 enforcePermission(android.Manifest.permission.MANAGE_OWN_CALLS);
+                enforceUserHandleMatchesCaller(phoneAccountHandle);
                 synchronized (mLock) {
                     long token = Binder.clearCallingIdentity();
                     try {
@@ -1717,10 +1779,14 @@
          * @see android.telecom.TelecomManager#isOutgoingCallPermitted(PhoneAccountHandle)
          */
         @Override
-        public boolean isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle) {
+        public boolean isOutgoingCallPermitted(PhoneAccountHandle phoneAccountHandle,
+                String callingPackage) {
+            Log.startSession("TSI.iOCP");
             try {
-                Log.startSession("TSI.iOCP");
+                enforceCallingPackage(callingPackage, "isOutgoingCallPermitted");
+                enforcePhoneAccountHandleMatchesCaller(phoneAccountHandle, callingPackage);
                 enforcePermission(android.Manifest.permission.MANAGE_OWN_CALLS);
+                enforceUserHandleMatchesCaller(phoneAccountHandle);
                 synchronized (mLock) {
                     long token = Binder.clearCallingIdentity();
                     try {
@@ -1857,6 +1923,31 @@
         }
 
         /**
+         * A method intended for test to clean up orphan {@link PhoneAccount}. An orphan
+         * {@link PhoneAccount} is a phone account belongs to an invalid {@link UserHandle} or a
+         * deleted package.
+         *
+         * @return the number of orphan {@code PhoneAccount} deleted.
+         */
+        @Override
+        public int cleanupOrphanPhoneAccounts() {
+            Log.startSession("TCI.cOPA");
+            try {
+                synchronized (mLock) {
+                    enforceShellOnly(Binder.getCallingUid(), "cleanupOrphanPhoneAccounts");
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        return mPhoneAccountRegistrar.cleanupOrphanedPhoneAccounts();
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        /**
          * A method intended for use in testing to reset car mode at all priorities.
          *
          * Runs during setup to avoid cascading failures from failing car mode CTS.
@@ -1943,6 +2034,24 @@
         }
 
         @Override
+        public void requestLogMark(String message) {
+            try {
+                Log.startSession("TSI.rLM");
+                enforceShellOnly(Binder.getCallingUid(), "requestLogMark is for shell only");
+                synchronized (mLock) {
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        mCallsManager.requestLogMark(message);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void setTestPhoneAcctSuggestionComponent(String flattenedComponentName) {
             try {
                 Log.startSession("TSI.sPASA");
@@ -2004,6 +2113,39 @@
                 Log.endSession();
             }
         }
+
+        /**
+         * Determines whether there are any ongoing {@link PhoneAccount#CAPABILITY_SELF_MANAGED}
+         * calls for a given {@code packageName} and {@code userHandle}.
+         *
+         * @param packageName the package name of the app to check calls for.
+         * @param userHandle the user handle on which to check for calls.
+         * @param callingPackage The caller's package name.
+         * @return {@code true} if there are ongoing calls, {@code false} otherwise.
+         */
+        @Override
+        public boolean isInSelfManagedCall(String packageName, UserHandle userHandle,
+                String callingPackage) {
+            try {
+                if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+                    throw new SecurityException("Only the system can call this API");
+                }
+                mContext.enforceCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE,
+                        "READ_PRIVILEGED_PHONE_STATE required.");
+
+                Log.startSession("TSI.iISMC", Log.getPackageAbbreviation(callingPackage));
+                synchronized (mLock) {
+                    long token = Binder.clearCallingIdentity();
+                    try {
+                        return mCallsManager.isInSelfManagedCall(packageName, userHandle);
+                    } finally {
+                        Binder.restoreCallingIdentity(token);
+                    }
+                }
+            } finally {
+                Log.endSession();
+            }
+        }
     };
 
     /**
@@ -2216,9 +2358,9 @@
         if (result != PackageManager.PERMISSION_GRANTED) {
             // Other callers are only allowed to modify PhoneAccounts if the relevant system
             // feature is enabled ...
-            enforceConnectionServiceFeature();
+            enforceTelecomFeature();
             // ... and the PhoneAccounts they refer to are for their own package.
-            enforceCallingPackage(packageName);
+            enforceCallingPackage(packageName, "enforcePhoneAccountModificationForPackage");
         }
     }
 
@@ -2234,12 +2376,31 @@
         }
     }
 
-    private void enforceCallingPackage(String packageName) {
-        mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
+    private void enforceCallingPackage(String packageName, String message) {
+        int packageUid = -1;
+        int callingUid = Binder.getCallingUid();
+        PackageManager pm = mContext.createContextAsUser(
+            UserHandle.getUserHandleForUid(callingUid), 0).getPackageManager();
+        if (pm != null) {
+            try {
+                packageUid = pm.getPackageUid(packageName, 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                // packageUid is -1
+            }
+        }
+        if (packageUid != callingUid && callingUid != Process.ROOT_UID) {
+            throw new SecurityException(message + ": Package " + packageName
+                + " does not belong to " + callingUid);
+        }
     }
 
-    private void enforceConnectionServiceFeature() {
-        enforceFeature(PackageManager.FEATURE_CONNECTION_SERVICE);
+    private void enforceTelecomFeature() {
+        PackageManager pm = mContext.getPackageManager();
+        if (!pm.hasSystemFeature(PackageManager.FEATURE_TELECOM)
+                && !pm.hasSystemFeature(PackageManager.FEATURE_CONNECTION_SERVICE)) {
+            throw new UnsupportedOperationException(
+                    "System does not support feature " + PackageManager.FEATURE_TELECOM);
+        }
     }
 
     private void enforceRegisterSimSubscriptionPermission() {
@@ -2268,6 +2429,24 @@
         }
     }
 
+    private void enforceRegisterVoiceCallingIndicationCapabilities(PhoneAccount account) {
+        // Caller must be able to register a SIM PhoneAccount or be the SIM call manager (as named
+        // in carrier config) to declare the two voice indication capabilities.
+        boolean prerequisiteCapabilitiesOk =
+                account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                        || account.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER);
+        boolean permissionsOk =
+                isCallerSimCallManagerForAnySim(account.getAccountHandle())
+                        || mContext.checkCallingOrSelfPermission(REGISTER_SIM_SUBSCRIPTION)
+                                == PackageManager.PERMISSION_GRANTED;
+        if (!prerequisiteCapabilitiesOk || !permissionsOk) {
+            throw new SecurityException(
+                    "Only SIM subscriptions and connection managers are allowed to declare "
+                            + "CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS and "
+                            + "CAPABILITY_VOICE_CALLING_AVAILABLE");
+        }
+    }
+
     private void enforceRegisterSkipCallFiltering() {
         if (!isCallerSystemApp()) {
             throw new SecurityException(
@@ -2281,6 +2460,13 @@
         }
     }
 
+    private void enforcePhoneAccountHandleMatchesCaller(PhoneAccountHandle phoneAccountHandle,
+            String callingPackage) {
+        if (!callingPackage.equals(phoneAccountHandle.getComponentName().getPackageName())) {
+            throw new SecurityException("Caller does not own the PhoneAccountHandle");
+        }
+    }
+
     private void enforceCrossUserPermission(int callingUid) {
         if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
             mContext.enforceCallingOrSelfPermission(
@@ -2289,14 +2475,6 @@
         }
     }
 
-    private void enforceFeature(String feature) {
-        PackageManager pm = mContext.getPackageManager();
-        if (!pm.hasSystemFeature(feature)) {
-            throw new UnsupportedOperationException(
-                    "System does not support feature " + feature);
-        }
-    }
-
     // to be used for TestApi methods that can only be called with SHELL UID.
     private void enforceShellOnly(int callingUid, String message) {
         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
@@ -2329,6 +2507,15 @@
         }
     }
 
+    private boolean canReadMangeOwnCalls(String message) {
+        try {
+            mContext.enforceCallingOrSelfPermission(MANAGE_OWN_CALLS, message);
+            return true;
+        } catch (SecurityException e) {
+            return false;
+        }
+    }
+
     private boolean canReadPhoneNumbers(String callingPackage, String callingFeatureId,
             String message) {
         boolean targetSdkPreR = false;
@@ -2478,6 +2665,29 @@
         return false;
     }
 
+    /**
+     * Similar to {@link #isCallerSimCallManager}, but works for all SIMs and does not require
+     * {@code accountHandle} to be registered yet.
+     */
+    private boolean isCallerSimCallManagerForAnySim(PhoneAccountHandle accountHandle) {
+        if (isCallerSimCallManager(accountHandle)) {
+            // The caller has already registered a CONNECTION_MANAGER PhoneAccount, so let them pass
+            // (this allows the SIM call manager through in case of SIM switches, where carrier
+            // config may be in a transient state)
+            return true;
+        }
+        // If the caller isn't already registered, then we have to look at the active PSTN
+        // PhoneAccounts and check their carrier configs to see if any point to this one's component
+        final long token = Binder.clearCallingIdentity();
+        try {
+            return !mPhoneAccountRegistrar
+                    .getSimPhoneAccountsFromSimCallManager(accountHandle)
+                    .isEmpty();
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     private boolean isPrivilegedDialerCalling(String callingPackage) {
         mAppOpsManager.checkPackage(Binder.getCallingUid(), callingPackage);
 
diff --git a/src/com/android/server/telecom/TelecomSystem.java b/src/com/android/server/telecom/TelecomSystem.java
index c824a65..237f039 100644
--- a/src/com/android/server/telecom/TelecomSystem.java
+++ b/src/com/android/server/telecom/TelecomSystem.java
@@ -31,6 +31,7 @@
 import com.android.server.telecom.ui.ToastFactory;
 
 import android.app.ActivityManager;
+import android.bluetooth.BluetoothManager;
 import android.Manifest;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -219,7 +220,7 @@
         Log.startSession("TS.init");
         // Wrap this in a try block to ensure session cleanup occurs in the case of error.
         try {
-            mPhoneAccountRegistrar = new PhoneAccountRegistrar(mContext, defaultDialerCache,
+            mPhoneAccountRegistrar = new PhoneAccountRegistrar(mContext, mLock, defaultDialerCache,
                     packageName -> AppLabelProxy.Util.getAppLabel(
                             mContext.getPackageManager(), packageName));
 
@@ -232,7 +233,7 @@
                         }
                     });
             BluetoothDeviceManager bluetoothDeviceManager = new BluetoothDeviceManager(mContext,
-                    new BluetoothAdapterProxy());
+                    mContext.getSystemService(BluetoothManager.class).getAdapter());
             BluetoothRouteManager bluetoothRouteManager = new BluetoothRouteManager(mContext, mLock,
                     bluetoothDeviceManager, new Timeouts.Adapter());
             BluetoothStateReceiver bluetoothStateReceiver = new BluetoothStateReceiver(
diff --git a/src/com/android/server/telecom/TtyManager.java b/src/com/android/server/telecom/TtyManager.java
index 457ba36..10e3348 100644
--- a/src/com/android/server/telecom/TtyManager.java
+++ b/src/com/android/server/telecom/TtyManager.java
@@ -52,7 +52,7 @@
                 TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
         mContext.registerReceiver(mReceiver, intentFilter,
                 android.Manifest.permission.MODIFY_PHONE_STATE,
-                null);
+                null, Context.RECEIVER_EXPORTED);
 
         updateCurrentTtyMode();
     }
@@ -84,7 +84,8 @@
             mCurrentTtyMode = newTtyMode;
             Intent ttyModeChanged = new Intent(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
             ttyModeChanged.putExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE, mCurrentTtyMode);
-            mContext.sendBroadcastAsUser(ttyModeChanged, UserHandle.ALL);
+            mContext.sendBroadcastAsUser(ttyModeChanged, UserHandle.ALL,
+                    android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
 
             updateAudioTtyMode();
         }
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
index 7fd600c..5cc54de 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java
@@ -20,25 +20,66 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
+import android.bluetooth.BluetoothLeAudioCodecStatus;
 import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
 import android.content.Context;
+import android.media.AudioManager;
+import android.media.AudioDeviceInfo;
 import android.telecom.Log;
 import android.util.LocalLog;
 
 import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.telecom.BluetoothAdapterProxy;
-import com.android.server.telecom.BluetoothHeadsetProxy;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.concurrent.Executor;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Objects;
 import java.util.Set;
 
 public class BluetoothDeviceManager {
+
+    public static final int DEVICE_TYPE_HEADSET = 0;
+    public static final int DEVICE_TYPE_HEARING_AID = 1;
+    public static final int DEVICE_TYPE_LE_AUDIO = 2;
+
+    private BluetoothLeAudio.Callback mLeAudioCallbacks =
+        new BluetoothLeAudio.Callback() {
+            @Override
+            public void onCodecConfigChanged(int groupId, BluetoothLeAudioCodecStatus status) {}
+            @Override
+            public void onGroupStatusChanged(int groupId, int groupStatus) {}
+            @Override
+            public void onGroupNodeAdded(BluetoothDevice device, int groupId) {
+                Log.i(this, device.getAddress() + " group added " + groupId);
+                if (device == null || groupId == BluetoothLeAudio.GROUP_ID_INVALID) {
+                    Log.w(this, "invalid parameter");
+                    return;
+                }
+
+                synchronized (mLock) {
+                    mGroupsByDevice.put(device, groupId);
+                }
+            }
+            @Override
+            public void onGroupNodeRemoved(BluetoothDevice device, int groupId) {
+                if (device == null || groupId == BluetoothLeAudio.GROUP_ID_INVALID) {
+                    Log.w(this, "invalid parameter");
+                    return;
+                }
+
+                synchronized (mLock) {
+                    mGroupsByDevice.remove(device);
+                }
+            }
+        };
+
     private final BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
             new BluetoothProfile.ServiceListener() {
                 @Override
@@ -48,13 +89,21 @@
                         synchronized (mLock) {
                             String logString;
                             if (profile == BluetoothProfile.HEADSET) {
-                                mBluetoothHeadsetService =
-                                        new BluetoothHeadsetProxy((BluetoothHeadset) proxy);
-                                logString = "Got BluetoothHeadset: " + mBluetoothHeadsetService;
+                                mBluetoothHeadset = (BluetoothHeadset) proxy;
+                                logString = "Got BluetoothHeadset: " + mBluetoothHeadset;
                             } else if (profile == BluetoothProfile.HEARING_AID) {
-                                mBluetoothHearingAidService = (BluetoothHearingAid) proxy;
+                                mBluetoothHearingAid = (BluetoothHearingAid) proxy;
                                 logString = "Got BluetoothHearingAid: "
-                                        + mBluetoothHearingAidService;
+                                        + mBluetoothHearingAid;
+                            } else if (profile == BluetoothProfile.LE_AUDIO) {
+                                mBluetoothLeAudioService = (BluetoothLeAudio) proxy;
+                                logString = "Got BluetoothLeAudio: "
+                                        + mBluetoothLeAudioService;
+                                if (!mLeAudioCallbackRegistered) {
+                                    mBluetoothLeAudioService.registerCallback(
+                                                mExecutor, mLeAudioCallbacks);
+                                    mLeAudioCallbackRegistered = true;
+                                }
                             } else {
                                 logString = "Connected to non-requested bluetooth service." +
                                         " Not changing bluetooth headset.";
@@ -75,17 +124,26 @@
                             LinkedHashMap<String, BluetoothDevice> lostServiceDevices;
                             String logString;
                             if (profile == BluetoothProfile.HEADSET) {
-                                mBluetoothHeadsetService = null;
+                                mBluetoothHeadset = null;
                                 lostServiceDevices = mHfpDevicesByAddress;
-                                mBluetoothRouteManager.onActiveDeviceChanged(null, false);
+                                mBluetoothRouteManager.onActiveDeviceChanged(null,
+                                        DEVICE_TYPE_HEADSET);
                                 logString = "Lost BluetoothHeadset service. " +
                                         "Removing all tracked devices";
                             } else if (profile == BluetoothProfile.HEARING_AID) {
-                                mBluetoothHearingAidService = null;
+                                mBluetoothHearingAid = null;
                                 logString = "Lost BluetoothHearingAid service. " +
                                         "Removing all tracked devices.";
                                 lostServiceDevices = mHearingAidDevicesByAddress;
-                                mBluetoothRouteManager.onActiveDeviceChanged(null, true);
+                                mBluetoothRouteManager.onActiveDeviceChanged(null,
+                                        DEVICE_TYPE_HEARING_AID);
+                            } else if (profile == BluetoothProfile.LE_AUDIO) {
+                                mBluetoothLeAudioService = null;
+                                logString = "Lost BluetoothLeAudio service. " +
+                                        "Removing all tracked devices.";
+                                lostServiceDevices = mLeAudioDevicesByAddress;
+                                mBluetoothRouteManager.onActiveDeviceChanged(null,
+                                        DEVICE_TYPE_LE_AUDIO);
                             } else {
                                 return;
                             }
@@ -111,24 +169,40 @@
             new LinkedHashMap<>();
     private final LinkedHashMap<BluetoothDevice, Long> mHearingAidDeviceSyncIds =
             new LinkedHashMap<>();
+    private final LinkedHashMap<String, BluetoothDevice> mLeAudioDevicesByAddress =
+            new LinkedHashMap<>();
+    private final LinkedHashMap<BluetoothDevice, Integer> mGroupsByDevice =
+            new LinkedHashMap<>();
+    private int mGroupIdActive = BluetoothLeAudio.GROUP_ID_INVALID;
+    private int mGroupIdPending = BluetoothLeAudio.GROUP_ID_INVALID;
     private final LocalLog mLocalLog = new LocalLog(20);
 
     // This lock only protects internal state -- it doesn't lock on anything going into Telecom.
     private final Object mLock = new Object();
 
     private BluetoothRouteManager mBluetoothRouteManager;
-    private BluetoothHeadsetProxy mBluetoothHeadsetService;
-    private BluetoothHearingAid mBluetoothHearingAidService;
+    private BluetoothHeadset mBluetoothHeadset;
+    private BluetoothHearingAid mBluetoothHearingAid;
+    private boolean mLeAudioCallbackRegistered = false;
+    private BluetoothLeAudio mBluetoothLeAudioService;
+    private boolean mLeAudioSetAsCommunicationDevice = false;
+    private boolean mHearingAidSetAsCommunicationDevice = false;
     private BluetoothDevice mBluetoothHearingAidActiveDeviceCache;
-    private BluetoothAdapterProxy mBluetoothAdapterProxy;
+    private BluetoothAdapter mBluetoothAdapter;
+    private AudioManager mAudioManager;
+    private Executor mExecutor;
 
-    public BluetoothDeviceManager(Context context, BluetoothAdapterProxy bluetoothAdapter) {
+    public BluetoothDeviceManager(Context context, BluetoothAdapter bluetoothAdapter) {
         if (bluetoothAdapter != null) {
-            mBluetoothAdapterProxy = bluetoothAdapter;
+            mBluetoothAdapter = bluetoothAdapter;
             bluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener,
                     BluetoothProfile.HEADSET);
             bluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener,
                     BluetoothProfile.HEARING_AID);
+            bluetoothAdapter.getProfileProxy(context, mBluetoothProfileServiceListener,
+                    BluetoothProfile.LE_AUDIO);
+            mAudioManager = context.getSystemService(AudioManager.class);
+            mExecutor = context.getMainExecutor();
         }
     }
 
@@ -136,9 +210,31 @@
         mBluetoothRouteManager = brm;
     }
 
+    private List<BluetoothDevice> getLeAudioConnectedDevices() {
+        synchronized (mLock) {
+            // Let's get devices which are a group leaders
+            ArrayList<BluetoothDevice> devices = new ArrayList<>();
+
+            if (mGroupsByDevice.isEmpty() || mBluetoothLeAudioService == null) {
+                return devices;
+            }
+
+            for (LinkedHashMap.Entry<BluetoothDevice, Integer> entry : mGroupsByDevice.entrySet()) {
+               if (Objects.equals(entry.getKey(),
+                        mBluetoothLeAudioService.getConnectedGroupLeadDevice(entry.getValue()))) {
+                   devices.add(entry.getKey());
+               }
+            }
+            devices.removeIf(device -> !mLeAudioDevicesByAddress.containsValue(device));
+            return devices;
+        }
+    }
+
     public int getNumConnectedDevices() {
         synchronized (mLock) {
-            return mHfpDevicesByAddress.size() + mHearingAidDevicesByAddress.size();
+            return mHfpDevicesByAddress.size() +
+                    mHearingAidDevicesByAddress.size() +
+                    getLeAudioConnectedDevices().size();
         }
     }
 
@@ -146,6 +242,7 @@
         synchronized (mLock) {
             ArrayList<BluetoothDevice> result = new ArrayList<>(mHfpDevicesByAddress.values());
             result.addAll(mHearingAidDevicesByAddress.values());
+            result.addAll(getLeAudioConnectedDevices());
             return Collections.unmodifiableCollection(result);
         }
     }
@@ -160,8 +257,9 @@
         Set<Long> seenHiSyncIds = new LinkedHashSet<>();
         // Add the left-most active device to the seen list so that we match up with the list
         // generated in BluetoothRouteManager.
-        if (mBluetoothHearingAidService != null) {
-            for (BluetoothDevice device : mBluetoothHearingAidService.getActiveDevices()) {
+        if (mBluetoothAdapter != null) {
+            for (BluetoothDevice device : mBluetoothAdapter.getActiveDevices(
+                        BluetoothProfile.HEARING_AID)) {
                 if (device != null) {
                     result.add(device);
                     seenHiSyncIds.add(mHearingAidDeviceSyncIds.getOrDefault(device, -1L));
@@ -179,44 +277,91 @@
                 seenHiSyncIds.add(hiSyncId);
             }
         }
+
+        if (mBluetoothLeAudioService != null) {
+            result.addAll(getLeAudioConnectedDevices());
+        }
+
         return Collections.unmodifiableCollection(result);
     }
 
-    public BluetoothHeadsetProxy getHeadsetService() {
-        return mBluetoothHeadsetService;
+    public BluetoothHeadset getBluetoothHeadset() {
+        return mBluetoothHeadset;
     }
 
-    public BluetoothHearingAid getHearingAidService() {
-        return mBluetoothHearingAidService;
+    public BluetoothAdapter getBluetoothAdapter() {
+        return mBluetoothAdapter;
     }
 
-    public void setHeadsetServiceForTesting(BluetoothHeadsetProxy bluetoothHeadset) {
-        mBluetoothHeadsetService = bluetoothHeadset;
+    public BluetoothHearingAid getBluetoothHearingAid() {
+        return mBluetoothHearingAid;
+    }
+
+    public BluetoothLeAudio getLeAudioService() {
+        return mBluetoothLeAudioService;
+    }
+
+    public void setHeadsetServiceForTesting(BluetoothHeadset bluetoothHeadset) {
+        mBluetoothHeadset = bluetoothHeadset;
     }
 
     public void setHearingAidServiceForTesting(BluetoothHearingAid bluetoothHearingAid) {
-        mBluetoothHearingAidService = bluetoothHearingAid;
+        mBluetoothHearingAid = bluetoothHearingAid;
     }
 
-    void onDeviceConnected(BluetoothDevice device, boolean isHearingAid) {
-        mLocalLog.log("Device connected -- address: " + device.getAddress() + " isHeadingAid: "
-                + isHearingAid);
+    public void setLeAudioServiceForTesting(BluetoothLeAudio bluetoothLeAudio) {
+        mBluetoothLeAudioService = bluetoothLeAudio;
+        mBluetoothLeAudioService.registerCallback(mExecutor, mLeAudioCallbacks);
+    }
+
+    public static String getDeviceTypeString(int deviceType) {
+        switch (deviceType) {
+            case DEVICE_TYPE_LE_AUDIO:
+                return "LeAudio";
+            case DEVICE_TYPE_HEARING_AID:
+                return "HearingAid";
+            case DEVICE_TYPE_HEADSET:
+                return "HFP";
+            default:
+                return "unknown type";
+        }
+    }
+
+    void onDeviceConnected(BluetoothDevice device, int deviceType) {
         synchronized (mLock) {
             LinkedHashMap<String, BluetoothDevice> targetDeviceMap;
-            if (isHearingAid) {
-                if (mBluetoothHearingAidService == null) {
+            if (deviceType == DEVICE_TYPE_LE_AUDIO) {
+                if (mBluetoothLeAudioService == null) {
+                    Log.w(this, "LE audio service null when receiving device added broadcast");
+                    return;
+                }
+                /* Check if group is known. */
+                if (!mGroupsByDevice.containsKey(device)) {
+                    int groupId = mBluetoothLeAudioService.getGroupId(device);
+                    /* If it is not yet assigned, then it will be provided in the callback */
+                    if (groupId != BluetoothLeAudio.GROUP_ID_INVALID) {
+                        mGroupsByDevice.put(device, groupId);
+                    }
+                }
+                targetDeviceMap = mLeAudioDevicesByAddress;
+            } else if (deviceType == DEVICE_TYPE_HEARING_AID) {
+                if (mBluetoothHearingAid == null) {
                     Log.w(this, "Hearing aid service null when receiving device added broadcast");
                     return;
                 }
-                long hiSyncId = mBluetoothHearingAidService.getHiSyncId(device);
+                long hiSyncId = mBluetoothHearingAid.getHiSyncId(device);
                 mHearingAidDeviceSyncIds.put(device, hiSyncId);
                 targetDeviceMap = mHearingAidDevicesByAddress;
-            } else {
-                if (mBluetoothHeadsetService == null) {
+            } else if (deviceType == DEVICE_TYPE_HEADSET) {
+                if (mBluetoothHeadset == null) {
                     Log.w(this, "Headset service null when receiving device added broadcast");
                     return;
                 }
                 targetDeviceMap = mHfpDevicesByAddress;
+            } else {
+                Log.w(this, "Device: " + device.getAddress() + " with invalid type: "
+                            + getDeviceTypeString(deviceType));
+                return;
             }
             if (!targetDeviceMap.containsKey(device.getAddress())) {
                 targetDeviceMap.put(device.getAddress(), device);
@@ -225,16 +370,22 @@
         }
     }
 
-    void onDeviceDisconnected(BluetoothDevice device, boolean isHearingAid) {
-        mLocalLog.log("Device disconnected -- address: " + device.getAddress() + " isHeadingAid: "
-                + isHearingAid);
+    void onDeviceDisconnected(BluetoothDevice device, int deviceType) {
+        mLocalLog.log("Device disconnected -- address: " + device.getAddress() + " deviceType: "
+                + deviceType);
         synchronized (mLock) {
             LinkedHashMap<String, BluetoothDevice> targetDeviceMap;
-            if (isHearingAid) {
+            if (deviceType == DEVICE_TYPE_LE_AUDIO) {
+                targetDeviceMap = mLeAudioDevicesByAddress;
+            } else if (deviceType == DEVICE_TYPE_HEARING_AID) {
                 mHearingAidDeviceSyncIds.remove(device);
                 targetDeviceMap = mHearingAidDevicesByAddress;
-            } else {
+            } else if (deviceType == DEVICE_TYPE_HEADSET) {
                 targetDeviceMap = mHfpDevicesByAddress;
+            } else {
+                Log.w(this, "Device: " + device.getAddress() + " with invalid type: "
+                            + getDeviceTypeString(deviceType));
+                return;
             }
             if (targetDeviceMap.containsKey(device.getAddress())) {
                 targetDeviceMap.remove(device.getAddress());
@@ -244,54 +395,198 @@
     }
 
     public void disconnectAudio() {
-        if (mBluetoothHearingAidService == null) {
-            Log.w(this, "Trying to disconnect audio but no hearing aid service exists");
-        } else {
-            for (BluetoothDevice device : mBluetoothHearingAidService.getActiveDevices()) {
-                if (device != null) {
-                    mBluetoothAdapterProxy.setActiveDevice(null,
-                        BluetoothAdapter.ACTIVE_DEVICE_ALL);
-                }
-            }
-        }
         disconnectSco();
+        clearLeAudioCommunicationDevice();
+        clearHearingAidCommunicationDevice();
     }
 
     public void disconnectSco() {
-        if (mBluetoothHeadsetService == null) {
+        if (mBluetoothHeadset == null) {
             Log.w(this, "Trying to disconnect audio but no headset service exists.");
         } else {
-            mBluetoothHeadsetService.disconnectAudio();
+            mBluetoothHeadset.disconnectAudio();
         }
     }
 
-    // Connect audio to the bluetooth device at address, checking to see whether it's a hearing aid
-    // or a HFP device, and using the proper BT API.
+    public boolean isLeAudioCommunicationDevice() {
+        return mLeAudioSetAsCommunicationDevice;
+    }
+
+    public boolean isHearingAidSetAsCommunicationDevice() {
+        return mHearingAidSetAsCommunicationDevice;
+    }
+
+    public void clearLeAudioCommunicationDevice() {
+        if (!mLeAudioSetAsCommunicationDevice) {
+            return;
+        }
+
+        if (mAudioManager == null) {
+            Log.i(this, "clearLeAudioCommunicationDevice: mAudioManager is null");
+            mLeAudioSetAsCommunicationDevice = false;
+            return;
+        }
+        if (mAudioManager.getCommunicationDevice() != null
+                && mAudioManager.getCommunicationDevice().getType()
+                == AudioDeviceInfo.TYPE_BLE_HEADSET) {
+            mBluetoothRouteManager.onAudioLost(mAudioManager.getCommunicationDevice().getAddress());
+            mAudioManager.clearCommunicationDevice();
+            mLeAudioSetAsCommunicationDevice = false;
+        }
+    }
+
+    public void clearHearingAidCommunicationDevice() {
+        if (!mHearingAidSetAsCommunicationDevice) {
+            return;
+        }
+
+        if (mAudioManager == null) {
+            Log.i(this, "clearHearingAidCommunicationDevice: mAudioManager is null");
+            mHearingAidSetAsCommunicationDevice = false;
+        }
+        if (mAudioManager.getCommunicationDevice() != null
+                && mAudioManager.getCommunicationDevice().getType()
+                == AudioDeviceInfo.TYPE_HEARING_AID) {
+            mAudioManager.clearCommunicationDevice();
+            mHearingAidSetAsCommunicationDevice = false;
+        }
+    }
+
+    public boolean setLeAudioCommunicationDevice() {
+        Log.i(this, "setLeAudioCommunicationDevice");
+
+        if (mLeAudioSetAsCommunicationDevice) {
+            Log.i(this, "setLeAudioCommunicationDevice already set");
+            return true;
+        }
+
+        if (mAudioManager == null) {
+            Log.w(this, " mAudioManager is null");
+            return false;
+        }
+
+        AudioDeviceInfo bleHeadset = null;
+        List<AudioDeviceInfo> devices = mAudioManager.getAvailableCommunicationDevices();
+        if (devices.size() == 0) {
+            Log.w(this, " No communication devices available.");
+            return false;
+        }
+
+        for (AudioDeviceInfo device : devices) {
+            Log.i(this, " Available device type:  " + device.getType());
+            if (device.getType() == AudioDeviceInfo.TYPE_BLE_HEADSET) {
+                bleHeadset = device;
+                break;
+            }
+        }
+
+        if (bleHeadset == null) {
+            Log.w(this, " No bleHeadset device available");
+            return false;
+        }
+
+        // clear hearing aid communication device if set
+        clearHearingAidCommunicationDevice();
+
+        // Turn BLE_OUT_HEADSET ON.
+        boolean result = mAudioManager.setCommunicationDevice(bleHeadset);
+        if (!result) {
+            Log.w(this, " Could not set bleHeadset device");
+        } else {
+            Log.i(this, " bleHeadset device set");
+            mBluetoothRouteManager.onAudioOn(bleHeadset.getAddress());
+            mLeAudioSetAsCommunicationDevice = true;
+        }
+        return result;
+    }
+
+    public boolean setHearingAidCommunicationDevice() {
+        Log.i(this, "setHearingAidCommunicationDevice");
+
+        if (mHearingAidSetAsCommunicationDevice) {
+            Log.i(this, "mHearingAidSetAsCommunicationDevice already set");
+            return true;
+        }
+
+        if (mAudioManager == null) {
+            Log.w(this, " mAudioManager is null");
+            return false;
+        }
+
+        AudioDeviceInfo hearingAid = null;
+        List<AudioDeviceInfo> devices = mAudioManager.getAvailableCommunicationDevices();
+        if (devices.size() == 0) {
+            Log.w(this, " No communication devices available.");
+            return false;
+        }
+
+        for (AudioDeviceInfo device : devices) {
+            Log.i(this, " Available device type:  " + device.getType());
+            if (device.getType() == AudioDeviceInfo.TYPE_HEARING_AID) {
+                hearingAid = device;
+                break;
+            }
+        }
+
+        if (hearingAid == null) {
+            Log.w(this, " No hearingAid device available");
+            return false;
+        }
+
+        // clear LE audio communication device if set
+        clearLeAudioCommunicationDevice();
+
+        // Turn hearing aid ON.
+        boolean result = mAudioManager.setCommunicationDevice(hearingAid);
+        if (!result) {
+            Log.w(this, " Could not set hearingAid device");
+        } else {
+            Log.i(this, " hearingAid device set");
+            mHearingAidSetAsCommunicationDevice = true;
+        }
+        return result;
+    }
+
+    // Connect audio to the bluetooth device at address, checking to see whether it's
+    // le audio, hearing aid or a HFP device, and using the proper BT API.
     public boolean connectAudio(String address) {
-        if (mHearingAidDevicesByAddress.containsKey(address)) {
-            if (mBluetoothHearingAidService == null) {
+        if (mLeAudioDevicesByAddress.containsKey(address)) {
+            if (mBluetoothLeAudioService == null) {
+                Log.w(this, "Attempting to turn on audio when the le audio service is null");
+                return false;
+            }
+            BluetoothDevice device = mLeAudioDevicesByAddress.get(address);
+            if (mBluetoothAdapter.setActiveDevice(
+                    device, BluetoothAdapter.ACTIVE_DEVICE_ALL)) {
+                return setLeAudioCommunicationDevice();
+            }
+            return false;
+        } else if (mHearingAidDevicesByAddress.containsKey(address)) {
+            if (mBluetoothHearingAid == null) {
                 Log.w(this, "Attempting to turn on audio when the hearing aid service is null");
                 return false;
             }
-            return mBluetoothAdapterProxy.setActiveDevice(
+            if (mBluetoothAdapter.setActiveDevice(
                     mHearingAidDevicesByAddress.get(address),
-                    BluetoothAdapter.ACTIVE_DEVICE_ALL);
+                    BluetoothAdapter.ACTIVE_DEVICE_ALL)) {
+                return setHearingAidCommunicationDevice();
+            }
+            return false;
         } else if (mHfpDevicesByAddress.containsKey(address)) {
             BluetoothDevice device = mHfpDevicesByAddress.get(address);
-            if (mBluetoothHeadsetService == null) {
+            if (mBluetoothHeadset == null) {
                 Log.w(this, "Attempting to turn on audio when the headset service is null");
                 return false;
             }
-            boolean success = mBluetoothAdapterProxy.setActiveDevice(device,
+            boolean success = mBluetoothAdapter.setActiveDevice(device,
                 BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL);
             if (!success) {
                 Log.w(this, "Couldn't set active device to %s", address);
                 return false;
             }
-            if (!mBluetoothHeadsetService.isAudioOn()) {
-                return mBluetoothHeadsetService.connectAudio();
-            }
-            return true;
+            int scoConnectionRequest = mBluetoothHeadset.connectAudio();
+            return scoConnectionRequest == BluetoothStatusCodes.SUCCESS ||
+                scoConnectionRequest == BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_CONNECTED;
         } else {
             Log.w(this, "Attempting to turn on audio for a disconnected device");
             return false;
@@ -299,20 +594,20 @@
     }
 
     public void cacheHearingAidDevice() {
-        if (mBluetoothHearingAidService != null) {
-             for (BluetoothDevice device : mBluetoothHearingAidService.getActiveDevices()) {
-                 if (device != null) {
-                     mBluetoothHearingAidActiveDeviceCache = device;
-                 }
-             }
+        if (mBluetoothAdapter != null) {
+            for (BluetoothDevice device : mBluetoothAdapter.getActiveDevices(
+                        BluetoothProfile.HEARING_AID)) {
+                if (device != null) {
+                    mBluetoothHearingAidActiveDeviceCache = device;
+                }
+            }
         }
     }
 
     public void restoreHearingAidDevice() {
-        if (mBluetoothHearingAidActiveDeviceCache != null && mBluetoothHearingAidService != null) {
-            mBluetoothAdapterProxy.setActiveDevice(
-                mBluetoothHearingAidActiveDeviceCache,
-                BluetoothAdapter.ACTIVE_DEVICE_ALL);
+        if (mBluetoothHearingAidActiveDeviceCache != null) {
+            mBluetoothAdapter.setActiveDevice(mBluetoothHearingAidActiveDeviceCache,
+                    BluetoothAdapter.ACTIVE_DEVICE_ALL);
             mBluetoothHearingAidActiveDeviceCache = null;
         }
     }
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
index 7211990..bd2c6f1 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothRouteManager.java
@@ -16,9 +16,12 @@
 
 package com.android.server.telecom.bluetooth;
 
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothLeAudio;
 import android.content.Context;
 import android.os.Message;
 import android.telecom.Log;
@@ -30,14 +33,15 @@
 import com.android.internal.util.IState;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
-import com.android.server.telecom.BluetoothHeadsetProxy;
 import com.android.server.telecom.TelecomSystem;
 import com.android.server.telecom.Timeouts;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -52,9 +56,9 @@
     private static final SparseArray<String> MESSAGE_CODE_TO_NAME = new SparseArray<String>() {{
          put(NEW_DEVICE_CONNECTED, "NEW_DEVICE_CONNECTED");
          put(LOST_DEVICE, "LOST_DEVICE");
-         put(CONNECT_HFP, "CONNECT_HFP");
-         put(DISCONNECT_HFP, "DISCONNECT_HFP");
-         put(RETRY_HFP_CONNECTION, "RETRY_HFP_CONNECTION");
+         put(CONNECT_BT, "CONNECT_BT");
+         put(DISCONNECT_BT, "DISCONNECT_BT");
+         put(RETRY_BT_CONNECTION, "RETRY_BT_CONNECTION");
          put(BT_AUDIO_IS_ON, "BT_AUDIO_IS_ON");
          put(BT_AUDIO_LOST, "BT_AUDIO_LOST");
          put(CONNECTION_TIMEOUT, "CONNECTION_TIMEOUT");
@@ -94,11 +98,11 @@
     public static final int LOST_DEVICE = 2;
 
     // arg2 (optional): the address of the specific device to connect to.
-    public static final int CONNECT_HFP = 100;
+    public static final int CONNECT_BT = 100;
     // No args.
-    public static final int DISCONNECT_HFP = 101;
+    public static final int DISCONNECT_BT = 101;
     // arg2: the address of the device to connect to.
-    public static final int RETRY_HFP_CONNECTION = 102;
+    public static final int RETRY_BT_CONNECTION = 102;
 
     // arg2: the address of the device that is on
     public static final int BT_AUDIO_IS_ON = 200;
@@ -155,27 +159,29 @@
                     case LOST_DEVICE:
                         removeDevice((String) args.arg2);
                         break;
-                    case CONNECT_HFP:
-                        String actualAddress = connectBtAudio((String) args.arg2);
+                    case CONNECT_BT:
+                        String actualAddress = connectBtAudio((String) args.arg2,
+                            false /* switchingBtDevices*/);
 
                         if (actualAddress != null) {
                             transitionTo(getConnectingStateForAddress(actualAddress,
-                                    "AudioOff/CONNECT_HFP"));
+                                    "AudioOff/CONNECT_BT"));
                         } else {
                             Log.w(LOG_TAG, "Tried to connect to %s but failed to connect to" +
-                                    " any HFP device.", (String) args.arg2);
+                                    " any BT device.", (String) args.arg2);
                         }
                         break;
-                    case DISCONNECT_HFP:
+                    case DISCONNECT_BT:
                         // Ignore.
                         break;
-                    case RETRY_HFP_CONNECTION:
-                        Log.i(LOG_TAG, "Retrying HFP connection to %s", (String) args.arg2);
-                        String retryAddress = connectBtAudio((String) args.arg2, args.argi1);
+                    case RETRY_BT_CONNECTION:
+                        Log.i(LOG_TAG, "Retrying BT connection to %s", (String) args.arg2);
+                        String retryAddress = connectBtAudio((String) args.arg2, args.argi1,
+                            false /* switchingBtDevices*/);
 
                         if (retryAddress != null) {
                             transitionTo(getConnectingStateForAddress(retryAddress,
-                                    "AudioOff/RETRY_HFP_CONNECTION"));
+                                    "AudioOff/RETRY_BT_CONNECTION"));
                         } else {
                             Log.i(LOG_TAG, "Retry failed.");
                         }
@@ -185,12 +191,12 @@
                         break;
                     case BT_AUDIO_IS_ON:
                         String address = (String) args.arg2;
-                        Log.w(LOG_TAG, "HFP audio unexpectedly turned on from device %s", address);
+                        Log.w(LOG_TAG, "BT audio unexpectedly turned on from device %s", address);
                         transitionTo(getConnectedStateForAddress(address,
                                 "AudioOff/BT_AUDIO_IS_ON"));
                         break;
                     case BT_AUDIO_LOST:
-                        Log.i(LOG_TAG, "Received HFP off for device %s while HFP off.",
+                        Log.i(LOG_TAG, "Received BT off for device %s while BT off.",
                                 (String) args.arg2);
                         mListener.onUnexpectedBluetoothStateChange();
                         break;
@@ -243,6 +249,7 @@
 
             SomeArgs args = (SomeArgs) msg.obj;
             String address = (String) args.arg2;
+            boolean switchingBtDevices = !Objects.equals(mDeviceAddress, address);
             try {
                 switch (msg.what) {
                     case NEW_DEVICE_CONNECTED:
@@ -255,35 +262,38 @@
                             transitionToActualState();
                         }
                         break;
-                    case CONNECT_HFP:
-                        if (Objects.equals(mDeviceAddress, address)) {
+                    case CONNECT_BT:
+                        if (!switchingBtDevices) {
                             // Ignore repeated connection attempts to the same device
                             break;
                         }
-                        String actualAddress = connectBtAudio(address);
 
+                        String actualAddress = connectBtAudio(address,
+                            true /* switchingBtDevices*/);
                         if (actualAddress != null) {
                             transitionTo(getConnectingStateForAddress(actualAddress,
-                                    "AudioConnecting/CONNECT_HFP"));
+                                    "AudioConnecting/CONNECT_BT"));
                         } else {
                             Log.w(LOG_TAG, "Tried to connect to %s but failed" +
-                                    " to connect to any HFP device.", (String) args.arg2);
+                                    " to connect to any BT device.", (String) args.arg2);
                         }
                         break;
-                    case DISCONNECT_HFP:
+                    case DISCONNECT_BT:
                         mDeviceManager.disconnectAudio();
                         break;
-                    case RETRY_HFP_CONNECTION:
-                        if (Objects.equals(address, mDeviceAddress)) {
+                    case RETRY_BT_CONNECTION:
+                        if (!switchingBtDevices) {
                             Log.d(LOG_TAG, "Retry message came through while connecting.");
+                            break;
+                        }
+
+                        String retryAddress = connectBtAudio(address, args.argi1,
+                            true /* switchingBtDevices*/);
+                        if (retryAddress != null) {
+                            transitionTo(getConnectingStateForAddress(retryAddress,
+                                    "AudioConnecting/RETRY_BT_CONNECTION"));
                         } else {
-                            String retryAddress = connectBtAudio(address, args.argi1);
-                            if (retryAddress != null) {
-                                transitionTo(getConnectingStateForAddress(retryAddress,
-                                        "AudioConnecting/RETRY_HFP_CONNECTION"));
-                            } else {
-                                Log.i(LOG_TAG, "Retry failed.");
-                            }
+                            Log.i(LOG_TAG, "Retry failed.");
                         }
                         break;
                     case CONNECTION_TIMEOUT:
@@ -293,7 +303,7 @@
                         break;
                     case BT_AUDIO_IS_ON:
                         if (Objects.equals(mDeviceAddress, address)) {
-                            Log.i(LOG_TAG, "HFP connection success for device %s.", mDeviceAddress);
+                            Log.i(LOG_TAG, "BT connection success for device %s.", mDeviceAddress);
                             transitionTo(mAudioConnectedStates.get(mDeviceAddress));
                         } else {
                             Log.w(LOG_TAG, "In connecting state for device %s but %s" +
@@ -308,7 +318,7 @@
                                     mDeviceAddress);
                             transitionToActualState();
                         } else {
-                            Log.w(LOG_TAG, "Got HFP lost message for device %s while" +
+                            Log.w(LOG_TAG, "Got BT lost message for device %s while" +
                                     " connecting to %s.", address, mDeviceAddress);
                             mListener.onUnexpectedBluetoothStateChange();
                         }
@@ -341,7 +351,7 @@
         public void enter() {
             // Remove any of the retries that are still in the queue once any device becomes
             // connected.
-            removeMessages(RETRY_HFP_CONNECTION);
+            removeMessages(RETRY_BT_CONNECTION);
             // Remove and add to ensure that the device is at the top.
             mMostRecentlyUsedDevices.remove(mDeviceAddress);
             mMostRecentlyUsedDevices.add(mDeviceAddress);
@@ -357,6 +367,7 @@
 
             SomeArgs args = (SomeArgs) msg.obj;
             String address = (String) args.arg2;
+            boolean switchingBtDevices = !Objects.equals(mDeviceAddress, address);
             try {
                 switch (msg.what) {
                     case NEW_DEVICE_CONNECTED:
@@ -368,35 +379,41 @@
                             transitionToActualState();
                         }
                         break;
-                    case CONNECT_HFP:
-                        if (Objects.equals(mDeviceAddress, address)) {
-                            // Ignore connection to already connected device.
+                    case CONNECT_BT:
+                        if (!switchingBtDevices) {
+                            // Ignore connection to already connected device but still notify
+                            // CallAudioRouteStateMachine since this might be a switch from other
+                            // to this already connected BT audio
+                            mListener.onBluetoothAudioConnected();
                             break;
                         }
-                        String actualAddress = connectBtAudio(address);
 
+                        String actualAddress = connectBtAudio(address,
+                            true /* switchingBtDevices*/);
                         if (actualAddress != null) {
                             transitionTo(getConnectingStateForAddress(address,
-                                    "AudioConnected/CONNECT_HFP"));
+                                    "AudioConnected/CONNECT_BT"));
                         } else {
                             Log.w(LOG_TAG, "Tried to connect to %s but failed" +
-                                    " to connect to any HFP device.", (String) args.arg2);
+                                    " to connect to any BT device.", (String) args.arg2);
                         }
                         break;
-                    case DISCONNECT_HFP:
+                    case DISCONNECT_BT:
                         mDeviceManager.disconnectAudio();
                         break;
-                    case RETRY_HFP_CONNECTION:
-                        if (Objects.equals(address, mDeviceAddress)) {
+                    case RETRY_BT_CONNECTION:
+                        if (!switchingBtDevices) {
                             Log.d(LOG_TAG, "Retry message came through while connected.");
+                            break;
+                        }
+
+                        String retryAddress = connectBtAudio(address, args.argi1,
+                            true /* switchingBtDevices*/);
+                        if (retryAddress != null) {
+                            transitionTo(getConnectingStateForAddress(retryAddress,
+                                    "AudioConnected/RETRY_BT_CONNECTION"));
                         } else {
-                            String retryAddress = connectBtAudio(address, args.argi1);
-                            if (retryAddress != null) {
-                                transitionTo(getConnectingStateForAddress(retryAddress,
-                                        "AudioConnected/RETRY_HFP_CONNECTION"));
-                            } else {
-                                Log.i(LOG_TAG, "Retry failed.");
-                            }
+                            Log.i(LOG_TAG, "Retry failed.");
                         }
                         break;
                     case CONNECTION_TIMEOUT:
@@ -415,10 +432,10 @@
                         break;
                     case BT_AUDIO_LOST:
                         if (Objects.equals(mDeviceAddress, address) || address == null) {
-                            Log.i(LOG_TAG, "HFP connection with device %s lost.", mDeviceAddress);
+                            Log.i(LOG_TAG, "BT connection with device %s lost.", mDeviceAddress);
                             transitionToActualState();
                         } else {
-                            Log.w(LOG_TAG, "Got HFP lost message for device %s while" +
+                            Log.w(LOG_TAG, "Got BT lost message for device %s while" +
                                     " connected to %s.", address, mDeviceAddress);
                             mListener.onUnexpectedBluetoothStateChange();
                         }
@@ -447,9 +464,10 @@
 
     private BluetoothStateListener mListener;
     private BluetoothDeviceManager mDeviceManager;
-    // Tracks the active devices in the BT stack (HFP or hearing aid).
+    // Tracks the active devices in the BT stack (HFP or hearing aid or le audio).
     private BluetoothDevice mHfpActiveDeviceCache = null;
     private BluetoothDevice mHearingAidActiveDeviceCache = null;
+    private BluetoothDevice mLeAudioActiveDeviceCache = null;
     private BluetoothDevice mMostRecentlyReportedActiveDevice = null;
 
     public BluetoothRouteManager(Context context, TelecomSystem.SyncRoot lock,
@@ -490,7 +508,7 @@
     }
 
     /**
-     * Returns whether there is a HFP device available to route audio to.
+     * Returns whether there is a BT device available to route audio to.
      * @return true if there is a device, false otherwise.
      */
     public boolean isBluetoothAvailable() {
@@ -535,20 +553,20 @@
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = Log.createSubsession();
         args.arg2 = address;
-        sendMessage(CONNECT_HFP, args);
+        sendMessage(CONNECT_BT, args);
     }
 
     /**
-     * Disconnects Bluetooth HFP audio.
+     * Disconnects Bluetooth audio.
      */
     public void disconnectBluetoothAudio() {
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = Log.createSubsession();
-        sendMessage(DISCONNECT_HFP, args);
+        sendMessage(DISCONNECT_BT, args);
     }
 
-    public void disconnectSco() {
-        mDeviceManager.disconnectSco();
+    public void disconnectAudio() {
+        mDeviceManager.disconnectAudio();
     }
 
     public void cacheHearingAidDevice() {
@@ -581,19 +599,43 @@
         mListener.onBluetoothDeviceListChanged();
     }
 
-    public void onActiveDeviceChanged(BluetoothDevice device, boolean isHearingAid) {
-        boolean wasActiveDevicePresent = mHearingAidActiveDeviceCache != null
-                || mHfpActiveDeviceCache != null;
-        if (isHearingAid) {
+    public void onAudioOn(String address) {
+        Session session = Log.createSubsession();
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = session;
+        args.arg2 = address;
+        sendMessage(BT_AUDIO_IS_ON, args);
+    }
+
+    public void onAudioLost(String address) {
+        Session session = Log.createSubsession();
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = session;
+        args.arg2 = address;
+        sendMessage(BT_AUDIO_LOST, args);
+    }
+
+    public void onActiveDeviceChanged(BluetoothDevice device, int deviceType) {
+        boolean wasActiveDevicePresent = hasBtActiveDevice();
+        if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO) {
+            mLeAudioActiveDeviceCache = device;
+            if (device == null) {
+                mDeviceManager.clearLeAudioCommunicationDevice();
+            }
+        } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID) {
             mHearingAidActiveDeviceCache = device;
-        } else {
+            if (device == null) {
+                mDeviceManager.clearHearingAidCommunicationDevice();
+            }
+        } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEADSET) {
             mHfpActiveDeviceCache = device;
+        } else {
+            return;
         }
 
         if (device != null) mMostRecentlyReportedActiveDevice = device;
 
-        boolean isActiveDevicePresent = mHearingAidActiveDeviceCache != null
-                || mHfpActiveDeviceCache != null;
+        boolean isActiveDevicePresent = hasBtActiveDevice();
 
         if (wasActiveDevicePresent && !isActiveDevicePresent) {
             mListener.onBluetoothActiveDeviceGone();
@@ -603,15 +645,25 @@
     }
 
     public boolean hasBtActiveDevice() {
-        return mHearingAidActiveDeviceCache != null || mHfpActiveDeviceCache != null;
+        return mLeAudioActiveDeviceCache != null ||
+                mHearingAidActiveDeviceCache != null ||
+                mHfpActiveDeviceCache != null;
+    }
+
+    public boolean isCachedLeAudioDevice(BluetoothDevice device) {
+        return mLeAudioActiveDeviceCache != null && mLeAudioActiveDeviceCache.equals(device);
+    }
+
+    public boolean isCachedHearingAidDevice(BluetoothDevice device) {
+        return mHearingAidActiveDeviceCache != null && mHearingAidActiveDeviceCache.equals(device);
     }
 
     public Collection<BluetoothDevice> getConnectedDevices() {
         return mDeviceManager.getUniqueConnectedDevices();
     }
 
-    private String connectBtAudio(String address) {
-        return connectBtAudio(address, 0);
+    private String connectBtAudio(String address, boolean switchingBtDevices) {
+        return connectBtAudio(address, 0, switchingBtDevices);
     }
 
     /**
@@ -620,15 +672,21 @@
      * Telecom from within it.
      * @param address The address that should be tried first. May be null.
      * @param retryCount The number of times this connection attempt has been retried.
+     * @param switchingBtDevices Used when there is existing audio connection to other Bt device.
      * @return The address of the device that's actually being connected to, or null if no
      * connection was successful.
      */
-    private String connectBtAudio(String address, int retryCount) {
+    private String connectBtAudio(String address, int retryCount, boolean switchingBtDevices) {
         Collection<BluetoothDevice> deviceList = mDeviceManager.getConnectedDevices();
         Optional<BluetoothDevice> matchingDevice = deviceList.stream()
                 .filter(d -> Objects.equals(d.getAddress(), address))
                 .findAny();
 
+        if (switchingBtDevices) {
+            /* When new Bluetooth connects audio, make sure previous one has disconnected audio. */
+            mDeviceManager.disconnectAudio();
+        }
+
         String actualAddress = matchingDevice.isPresent()
                 ? address : getActiveDeviceAddress();
         if (actualAddress == null) {
@@ -664,7 +722,7 @@
                 args.arg1 = Log.createSubsession();
                 args.arg2 = actualAddress;
                 args.argi1 = retryCount + 1;
-                sendMessageDelayed(RETRY_HFP_CONNECTION, args,
+                sendMessageDelayed(RETRY_BT_CONNECTION, args,
                         mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
                                 mContext.getContentResolver()));
             }
@@ -681,6 +739,9 @@
         if (mHearingAidActiveDeviceCache != null) {
             return mHearingAidActiveDeviceCache.getAddress();
         }
+        if (mLeAudioActiveDeviceCache != null) {
+            return mLeAudioActiveDeviceCache.getAddress();
+        }
         return null;
     }
 
@@ -701,46 +762,83 @@
      */
     @VisibleForTesting
     public BluetoothDevice getBluetoothAudioConnectedDevice() {
-        BluetoothHeadsetProxy bluetoothHeadset = mDeviceManager.getHeadsetService();
-        BluetoothHearingAid bluetoothHearingAid = mDeviceManager.getHearingAidService();
+        BluetoothAdapter bluetoothAdapter = mDeviceManager.getBluetoothAdapter();
+        BluetoothHeadset bluetoothHeadset = mDeviceManager.getBluetoothHeadset();
+        BluetoothHearingAid bluetoothHearingAid = mDeviceManager.getBluetoothHearingAid();
+        BluetoothLeAudio bluetoothLeAudio = mDeviceManager.getLeAudioService();
 
         BluetoothDevice hfpAudioOnDevice = null;
         BluetoothDevice hearingAidActiveDevice = null;
+        BluetoothDevice leAudioActiveDevice = null;
 
-        if (bluetoothHeadset == null && bluetoothHearingAid == null) {
+        if (bluetoothAdapter == null) {
+            Log.i(this, "getBluetoothAudioConnectedDevice: no adapter available.");
+            return null;
+        }
+        if (bluetoothHeadset == null && bluetoothHearingAid == null && bluetoothLeAudio == null) {
             Log.i(this, "getBluetoothAudioConnectedDevice: no service available.");
             return null;
         }
 
+        int activeDevices = 0;
         if (bluetoothHeadset != null) {
-            hfpAudioOnDevice = bluetoothHeadset.getActiveDevice();
+            for (BluetoothDevice device : bluetoothAdapter.getActiveDevices(
+                        BluetoothProfile.HEADSET)) {
+                hfpAudioOnDevice = device;
+                break;
+            }
 
-            if (bluetoothHeadset.getAudioState(hfpAudioOnDevice)
+            if (hfpAudioOnDevice != null && bluetoothHeadset.getAudioState(hfpAudioOnDevice)
                     == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
                 hfpAudioOnDevice = null;
+            } else {
+                activeDevices++;
             }
         }
 
         if (bluetoothHearingAid != null) {
-            for (BluetoothDevice device : bluetoothHearingAid.getActiveDevices()) {
-                if (device != null) {
-                    hearingAidActiveDevice = device;
-                    break;
+            if (mDeviceManager.isHearingAidSetAsCommunicationDevice()) {
+                for (BluetoothDevice device : bluetoothAdapter.getActiveDevices(
+                        BluetoothProfile.HEARING_AID)) {
+                    if (device != null) {
+                        hearingAidActiveDevice = device;
+                        activeDevices++;
+                        break;
+                    }
                 }
             }
         }
 
-        // Return the active device reported by either HFP or hearing aid. If both are reporting
-        // active devices, go with the most recent one as reported by the receiver.
-        if (hfpAudioOnDevice != null) {
-            if (hearingAidActiveDevice != null) {
-                Log.i(this, "Both HFP and hearing aid are reporting active devices. Going with"
-                        + " the most recently reported active device: %s");
-                return mMostRecentlyReportedActiveDevice;
+        if (bluetoothLeAudio != null) {
+            if (mDeviceManager.isLeAudioCommunicationDevice()) {
+                for (BluetoothDevice device : bluetoothAdapter.getActiveDevices(
+                        BluetoothProfile.LE_AUDIO)) {
+                    if (device != null) {
+                        leAudioActiveDevice = device;
+                        activeDevices++;
+                        break;
+                    }
+                }
             }
-            return hfpAudioOnDevice;
         }
-        return hearingAidActiveDevice;
+
+        // Return the active device reported by either HFP, hearing aid or le audio. If more than
+        // one is reporting active devices, go with the most recent one as reported by the receiver.
+        if (activeDevices > 1) {
+            Log.i(this, "More than one profile reporting active devices. Going with the most"
+                    + " recently reported active device: %s", mMostRecentlyReportedActiveDevice);
+            return mMostRecentlyReportedActiveDevice;
+        }
+
+        if (leAudioActiveDevice != null) {
+            return leAudioActiveDevice;
+        }
+
+        if (hearingAidActiveDevice != null) {
+            return hearingAidActiveDevice;
+        }
+
+        return hfpAudioOnDevice;
     }
 
     /**
@@ -751,7 +849,7 @@
      */
     @VisibleForTesting
     public boolean isInbandRingingEnabled() {
-        BluetoothHeadsetProxy bluetoothHeadset = mDeviceManager.getHeadsetService();
+        BluetoothHeadset bluetoothHeadset = mDeviceManager.getBluetoothHeadset();
         if (bluetoothHeadset == null) {
             Log.i(this, "isInbandRingingEnabled: no headset service available.");
             return false;
@@ -836,10 +934,12 @@
     }
 
     @VisibleForTesting
-    public void setActiveDeviceCacheForTesting(BluetoothDevice device, boolean isHearingAid) {
-        if (isHearingAid) {
+    public void setActiveDeviceCacheForTesting(BluetoothDevice device, int deviceType) {
+        if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO) {
+          mLeAudioActiveDeviceCache = device;
+        } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID) {
             mHearingAidActiveDeviceCache = device;
-        } else {
+        } else if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEADSET) {
             mHfpActiveDeviceCache = device;
         }
     }
diff --git a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
index 8a14cbd..e5fe971 100644
--- a/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
+++ b/src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java
@@ -19,6 +19,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -43,6 +44,8 @@
         INTENT_FILTER.addAction(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED);
         INTENT_FILTER.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
         INTENT_FILTER.addAction(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
+        INTENT_FILTER.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED);
+        INTENT_FILTER.addAction(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED);
     }
 
     // If not in a call, BSR won't listen to the Bluetooth stack's HFP on/off messages, since
@@ -59,10 +62,12 @@
                 case BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED:
                     handleAudioStateChanged(intent);
                     break;
+                case BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED:
                 case BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED:
                 case BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED:
                     handleConnectionStateChanged(intent);
                     break;
+                case BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED:
                 case BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED:
                 case BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED:
                     handleActiveDeviceChanged(intent);
@@ -117,29 +122,52 @@
             return;
         }
 
-        Log.i(LOG_TAG, "Device %s changed state to %d",
+        int deviceType;
+        if (BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
+            deviceType = BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO;
+        } else if (BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
+            deviceType = BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID;
+        } else if (BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {
+            deviceType = BluetoothDeviceManager.DEVICE_TYPE_HEADSET;
+        } else {
+            Log.w(LOG_TAG, "handleConnectionStateChanged: %s invalid device type", device);
+            return;
+        }
+
+        Log.i(LOG_TAG, "%s device %s changed state to %d",
+                BluetoothDeviceManager.getDeviceTypeString(deviceType),
                 device.getAddress(), bluetoothHeadsetState);
 
-        boolean isHearingAid = BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED
-                .equals(intent.getAction());
         if (bluetoothHeadsetState == BluetoothProfile.STATE_CONNECTED) {
-            mBluetoothDeviceManager.onDeviceConnected(device, isHearingAid);
+            mBluetoothDeviceManager.onDeviceConnected(device, deviceType);
         } else if (bluetoothHeadsetState == BluetoothProfile.STATE_DISCONNECTED
                 || bluetoothHeadsetState == BluetoothProfile.STATE_DISCONNECTING) {
-            mBluetoothDeviceManager.onDeviceDisconnected(device, isHearingAid);
+            mBluetoothDeviceManager.onDeviceDisconnected(device, deviceType);
         }
     }
 
     private void handleActiveDeviceChanged(Intent intent) {
         BluetoothDevice device =
                 intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-        boolean isHearingAid =
-                BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED.equals(intent.getAction());
-        Log.i(LOG_TAG, "Device %s is now the preferred BT device for %s", device,
-                isHearingAid ? "hearing aid" : "HFP");
 
-        mBluetoothRouteManager.onActiveDeviceChanged(device, isHearingAid);
-        if (isHearingAid) {
+        int deviceType;
+        if (BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED.equals(intent.getAction())) {
+            deviceType = BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO;
+        } else if (BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED.equals(intent.getAction())) {
+            deviceType = BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID;
+        } else if (BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED.equals(intent.getAction())) {
+            deviceType = BluetoothDeviceManager.DEVICE_TYPE_HEADSET;
+        } else {
+            Log.w(LOG_TAG, "handleActiveDeviceChanged: %s invalid device type", device);
+            return;
+        }
+
+        Log.i(LOG_TAG, "Device %s is now the preferred BT device for %s", device,
+                BluetoothDeviceManager.getDeviceTypeString(deviceType));
+
+        mBluetoothRouteManager.onActiveDeviceChanged(device, deviceType);
+        if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID ||
+            deviceType == BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO) {
             Session session = Log.createSubsession();
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = session;
@@ -147,12 +175,32 @@
                 mBluetoothRouteManager.sendMessage(BT_AUDIO_LOST, args);
             } else {
                 if (!mIsInCall) {
-                    Log.i(LOG_TAG, "Ignoring hearing aid audio on since we're not in a call");
+                    Log.i(LOG_TAG, "Ignoring audio on since we're not in a call");
                     return;
                 }
                 args.arg2 = device.getAddress();
-                mBluetoothRouteManager.sendMessage(BT_AUDIO_IS_ON, args);
-            }
+
+                if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO) {
+                    /* In Le Audio case, once device got Active, the Telecom needs to make sure it
+                     * is set as communication device before we can say that BT_AUDIO_IS_ON
+                     */
+                    if (!mBluetoothDeviceManager.setLeAudioCommunicationDevice()) {
+                        Log.w(LOG_TAG,
+                                "Device %s cannot be use as LE audio communication device.",
+                                device);
+                        return;
+                    }
+                } else {
+                    /* deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID */
+                    if (!mBluetoothDeviceManager.setHearingAidCommunicationDevice()) {
+                        Log.w(LOG_TAG,
+                                "Device %s cannot be use as hearing aid communication device.",
+                                device);
+                    } else {
+                        mBluetoothRouteManager.sendMessage(BT_AUDIO_IS_ON, args);
+                    }
+                }
+           }
         }
     }
 
diff --git a/src/com/android/server/telecom/callfiltering/BlockCheckerFilter.java b/src/com/android/server/telecom/callfiltering/BlockCheckerFilter.java
index daf6be0..36f2077 100644
--- a/src/com/android/server/telecom/callfiltering/BlockCheckerFilter.java
+++ b/src/com/android/server/telecom/callfiltering/BlockCheckerFilter.java
@@ -155,6 +155,7 @@
                 return CallLog.Calls.BLOCK_REASON_BLOCKED_NUMBER;
 
             case BlockedNumberContract.STATUS_BLOCKED_UNKNOWN_NUMBER:
+            case BlockedNumberContract.STATUS_BLOCKED_UNAVAILABLE:
                 return CallLog.Calls.BLOCK_REASON_UNKNOWN_NUMBER;
 
             case BlockedNumberContract.STATUS_BLOCKED_RESTRICTED:
diff --git a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
index 4a308e0..51b1bc6 100644
--- a/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
+++ b/src/com/android/server/telecom/callfiltering/CallScreeningServiceFilter.java
@@ -313,11 +313,14 @@
 
     private void bindCallScreeningService(
             CompletableFuture<CallFilteringResult> resultFuture) {
-        mConnection = new CallScreeningServiceConnection(resultFuture);
+        CallScreeningServiceConnection connection = new CallScreeningServiceConnection(
+                resultFuture);
         if (!CallScreeningServiceHelper.bindCallScreeningService(mContext,
-                mCallsManager.getCurrentUserHandle(), mPackageName, mConnection)) {
+                mCallsManager.getCurrentUserHandle(), mPackageName, connection)) {
             Log.i(this, "Call screening service binding failed.");
             resultFuture.complete(mPriorStageResult);
+        } else {
+            mConnection = connection;
         }
     }
 
diff --git a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java
index a1f357b..adeb311 100644
--- a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java
+++ b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java
@@ -124,6 +124,17 @@
             }
         }
 
+        public void notifyTimeout() {
+            if (mService != null) {
+                try {
+                    mService.notifyTimeout();
+                } catch (RemoteException e) {
+                    Log.e(this, e, "Failed to notify call redirection timed out to "
+                            + mServiceType + " call redirection service");
+                }
+            }
+        }
+
         private class CallRedirectionServiceConnection implements ServiceConnection {
             @Override
             public void onServiceConnected(ComponentName componentName, IBinder service) {
@@ -394,6 +405,7 @@
                     Log.addEvent(mCall, serviceType.equals(SERVICE_TYPE_USER_DEFINED)
                             ? LogUtils.Events.REDIRECTION_TIMED_OUT_USER
                             : LogUtils.Events.REDIRECTION_TIMED_OUT_CARRIER);
+                    mAttempt.notifyTimeout();
                     if (serviceType.equals(SERVICE_TYPE_USER_DEFINED)) {
                         mUiAction = UI_TYPE_USER_DEFINED_TIMEOUT;
                         mShouldCancelCall = true;
diff --git a/src/com/android/server/telecom/components/ErrorDialogActivity.java b/src/com/android/server/telecom/components/ErrorDialogActivity.java
index 1bdcdf2..3618b77 100644
--- a/src/com/android/server/telecom/components/ErrorDialogActivity.java
+++ b/src/com/android/server/telecom/components/ErrorDialogActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom.components;
 
+import com.android.server.telecom.FrameworksUtils;
 import com.android.server.telecom.R;
 
 import android.app.Activity;
@@ -84,7 +85,7 @@
             }
         };
 
-        final AlertDialog errorDialog = new AlertDialog.Builder(this)
+        final AlertDialog errorDialog = FrameworksUtils.makeAlertDialogBuilder(this)
                 .setMessage(msg).setPositiveButton(android.R.string.ok, clickListener)
                         .setOnCancelListener(cancelListener).create();
 
@@ -97,7 +98,7 @@
     }
 
     private void showMissingVoicemailErrorDialog() {
-        new AlertDialog.Builder(this)
+        FrameworksUtils.makeAlertDialogBuilder(this)
                 .setTitle(R.string.no_vm_number)
                 .setMessage(R.string.no_vm_number_msg)
                 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
diff --git a/src/com/android/server/telecom/components/UserCallActivity.java b/src/com/android/server/telecom/components/UserCallActivity.java
index ca8fef7..1d85884 100644
--- a/src/com/android/server/telecom/components/UserCallActivity.java
+++ b/src/com/android/server/telecom/components/UserCallActivity.java
@@ -65,7 +65,7 @@
             Intent intent = getIntent();
             verifyCallAction(intent);
             final UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
-            final UserHandle userHandle = new UserHandle(userManager.getUserHandle());
+            final UserHandle userHandle = new UserHandle(userManager.getProcessUserId());
             // Once control flow has passed to this activity, it is no longer guaranteed that we can
             // accurately determine whether the calling package has the CALL_PHONE runtime permission.
             // At this point in time we trust that the ActivityManager has already performed this
diff --git a/src/com/android/server/telecom/components/UserCallIntentProcessor.java b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
old mode 100644
new mode 100755
index 75c1996..cad7b4c
--- a/src/com/android/server/telecom/components/UserCallIntentProcessor.java
+++ b/src/com/android/server/telecom/components/UserCallIntentProcessor.java
@@ -80,11 +80,6 @@
      */
     public void processIntent(Intent intent, String callingPackageName,
             boolean canCallNonEmergency, boolean isLocalInvocation) {
-        // Ensure call intents are not processed on devices that are not capable of calling.
-        if (!isVoiceCapable()) {
-            return;
-        }
-
         String action = intent.getAction();
 
         if (Intent.ACTION_CALL.equals(action) ||
@@ -98,6 +93,7 @@
     private void processOutgoingCallIntent(Intent intent, String callingPackageName,
             boolean canCallNonEmergency, boolean isLocalInvocation) {
         Uri handle = intent.getData();
+        if (handle == null) return;
         String scheme = handle.getScheme();
         String uriString = handle.getSchemeSpecificPart();
 
@@ -159,16 +155,6 @@
     }
 
     /**
-     * Returns whether the device is voice-capable (e.g. a phone vs a tablet).
-     *
-     * @return {@code True} if the device is voice-capable.
-     */
-    private boolean isVoiceCapable() {
-        return ((TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE))
-                .isVoiceCapable();
-    }
-
-    /**
      * Potentially trampolines the intent to Telecom via TelecomServiceImpl.
      * If the caller is local to the Telecom service, we send the intent to Telecom without
      * sending it through TelecomServiceImpl.
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersActivity.java b/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
index 1fe7c5f..cb4b3e3 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
@@ -19,7 +19,6 @@
 import android.annotation.Nullable;
 import android.app.ActionBar;
 import android.app.AlertDialog;
-import android.app.Dialog;
 import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
@@ -35,14 +34,13 @@
 import android.database.Cursor;
 import android.os.Bundle;
 import android.provider.BlockedNumberContract;
-import android.provider.ContactsContract;
 import android.telephony.PhoneNumberFormattingTextWatcher;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
 import android.text.Editable;
-import android.text.InputType;
 import android.text.TextUtils;
 import android.text.TextWatcher;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.View;
@@ -56,6 +54,7 @@
 import android.widget.TextView;
 import android.widget.Toast;
 
+import com.android.server.telecom.FrameworksUtils;
 import com.android.server.telecom.R;
 
 
@@ -216,7 +215,7 @@
     public Loader<Cursor> onCreateLoader(int id, Bundle args) {
         return new CursorLoader(this, BlockedNumberContract.BlockedNumbers.CONTENT_URI,
                 PROJECTION, SELECTION, null,
-                BlockedNumberContract.BlockedNumbers.COLUMN_ID + " DESC");
+                BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER + " ASC");
     }
 
     @Override
@@ -247,7 +246,7 @@
         final EditText editText = (EditText) dialogView.findViewById(R.id.add_blocked_number);
         editText.addTextChangedListener(new PhoneNumberFormattingTextWatcher());
         editText.addTextChangedListener(this);
-        AlertDialog dialog = new AlertDialog.Builder(this)
+        AlertDialog dialog = FrameworksUtils.makeAlertDialogBuilder(this)
                 .setView(dialogView)
                 .setPositiveButton(R.string.block_button, new DialogInterface.OnClickListener() {
                     public void onClick(DialogInterface dialog, int id) {
@@ -262,23 +261,23 @@
                 })
                 .create();
         dialog.setOnShowListener(new AlertDialog.OnShowListener() {
-                    @Override
-                    public void onShow(DialogInterface dialog) {
-                        mBlockButton = ((AlertDialog) dialog)
-                                .getButton(AlertDialog.BUTTON_POSITIVE);
-                        mBlockButtonNegative = ((AlertDialog) dialog)
-                                .getButton(AlertDialog.BUTTON_NEGATIVE);
-                        mBlockButton.setAllCaps(false);
-                        mBlockButtonNegative.setAllCaps(false);
-                        mBlockButton.setEnabled(false);
-                        // show keyboard
-                        InputMethodManager inputMethodManager =
-                                (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
-                        inputMethodManager.showSoftInput(editText,
-                                InputMethodManager.SHOW_IMPLICIT);
+            @Override
+            public void onShow(DialogInterface dialog) {
+                mBlockButton = ((AlertDialog) dialog)
+                        .getButton(AlertDialog.BUTTON_POSITIVE);
+                mBlockButtonNegative = ((AlertDialog) dialog)
+                        .getButton(AlertDialog.BUTTON_NEGATIVE);
+                mBlockButton.setAllCaps(false);
+                mBlockButtonNegative.setAllCaps(false);
+                mBlockButton.setEnabled(false);
+                // show keyboard
+                InputMethodManager inputMethodManager =
+                        (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+                inputMethodManager.showSoftInput(editText,
+                        InputMethodManager.SHOW_IMPLICIT);
 
-                    }
-                });
+            }
+        });
         dialog.show();
     }
 
@@ -338,4 +337,4 @@
         }
         mAddButton.setEnabled(true);
     }
-}
+}
\ No newline at end of file
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java b/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
index df68f6e..333e451 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersAdapter.java
@@ -29,6 +29,7 @@
 import android.widget.SimpleCursorAdapter;
 import android.widget.TextView;
 
+import com.android.server.telecom.FrameworksUtils;
 import com.android.server.telecom.R;
 
 public class BlockedNumbersAdapter extends SimpleCursorAdapter {
@@ -72,7 +73,7 @@
         Spannable messageSpannable = new SpannableString(message);
         PhoneNumberUtils.addTtsSpan(messageSpannable, startingPosition,
                 startingPosition + formattedNumber.length());
-        AlertDialog dialog = new AlertDialog.Builder(context)
+        AlertDialog dialog = FrameworksUtils.makeAlertDialogBuilder(context)
                 .setMessage(messageSpannable)
                 .setPositiveButton(R.string.unblock_button,
                         new DialogInterface.OnClickListener() {
diff --git a/src/com/android/server/telecom/settings/CallBlockDisabledActivity.java b/src/com/android/server/telecom/settings/CallBlockDisabledActivity.java
index 5f42b37..232546b 100644
--- a/src/com/android/server/telecom/settings/CallBlockDisabledActivity.java
+++ b/src/com/android/server/telecom/settings/CallBlockDisabledActivity.java
@@ -22,6 +22,7 @@
 import android.os.Bundle;
 import android.provider.BlockedNumberContract;
 
+import com.android.server.telecom.FrameworksUtils;
 import com.android.server.telecom.R;
 
 /**
@@ -50,7 +51,7 @@
             return;
         }
 
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        AlertDialog.Builder builder = FrameworksUtils.makeAlertDialogBuilder(this);
         mDialog = builder
                 .setTitle(R.string.phone_strings_emergency_call_made_dialog_title_txt)
                 .setMessage(R.string
diff --git a/src/com/android/server/telecom/settings/EnhancedCallBlockingFragment.java b/src/com/android/server/telecom/settings/EnhancedCallBlockingFragment.java
index ecc019f..c0bb56a 100644
--- a/src/com/android/server/telecom/settings/EnhancedCallBlockingFragment.java
+++ b/src/com/android/server/telecom/settings/EnhancedCallBlockingFragment.java
@@ -42,6 +42,8 @@
             "block_private_number_calls_setting";
     private static final String BLOCK_UNKNOWN_NUMBERS_KEY =
             "block_unknown_calls_setting";
+    private static final String BLOCK_UNAVAILABLE_NUMBERS_KEY =
+            "block_unavailable_calls_setting";
     private boolean mIsCombiningRestrictedAndUnknownOption = false;
 
     @Override
@@ -55,6 +57,7 @@
         setOnPreferenceChangeListener(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PRIVATE);
         setOnPreferenceChangeListener(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE);
         setOnPreferenceChangeListener(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNKNOWN);
+        setOnPreferenceChangeListener(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNAVAILABLE);
         if (!showPayPhoneBlocking()) {
             Preference payPhoneOption = getPreferenceScreen().findPreference(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE);
             getPreferenceScreen().removePreference(payPhoneOption);
@@ -90,8 +93,10 @@
         mIsCombiningRestrictedAndUnknownOption = getResources().getBoolean(
                         R.bool.combine_options_to_block_restricted_and_unknown_callers);
         if (mIsCombiningRestrictedAndUnknownOption) {
-            Preference pref = findPreference(BLOCK_RESTRICTED_NUMBERS_KEY);
-            screen.removePreference(pref);
+            Preference restricted_pref = findPreference(BLOCK_RESTRICTED_NUMBERS_KEY);
+            Preference unavailable_pref = findPreference(BLOCK_UNAVAILABLE_NUMBERS_KEY);
+            screen.removePreference(restricted_pref);
+            screen.removePreference(unavailable_pref);
             Log.i(this, "onCreate: removed block restricted preference.");
         }
     }
@@ -116,6 +121,7 @@
             updateEnhancedBlockPref(SystemContract.ENHANCED_SETTING_KEY_BLOCK_PAYPHONE);
         }
         updateEnhancedBlockPref(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNKNOWN);
+        updateEnhancedBlockPref(SystemContract.ENHANCED_SETTING_KEY_BLOCK_UNAVAILABLE);
     }
 
     /**
@@ -136,6 +142,8 @@
                     preference.getKey(), BLOCK_RESTRICTED_NUMBERS_KEY, (boolean) objValue);
             BlockedNumbersUtil.setEnhancedBlockSetting(getActivity(), BLOCK_RESTRICTED_NUMBERS_KEY,
                     (boolean) objValue);
+            BlockedNumbersUtil.setEnhancedBlockSetting(getActivity(),
+                    BLOCK_UNAVAILABLE_NUMBERS_KEY, (boolean) objValue);
         }
         BlockedNumbersUtil.setEnhancedBlockSetting(getActivity(), preference.getKey(),
                 (boolean) objValue);
diff --git a/src/com/android/server/telecom/ui/CallRedirectionTimeoutDialogActivity.java b/src/com/android/server/telecom/ui/CallRedirectionTimeoutDialogActivity.java
index 5aa80c6..b5c850e 100644
--- a/src/com/android/server/telecom/ui/CallRedirectionTimeoutDialogActivity.java
+++ b/src/com/android/server/telecom/ui/CallRedirectionTimeoutDialogActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom.ui;
 
+import com.android.server.telecom.FrameworksUtils;
 import com.android.server.telecom.R;
 
 import android.app.Activity;
@@ -45,7 +46,7 @@
         Log.i(this, "showDialog: timeout redirection with %s", redirectionAppName);
         CharSequence message = getString(
                 R.string.alert_redirect_outgoing_call_timeout, redirectionAppName);
-        final AlertDialog errorDialog = new AlertDialog.Builder(this)
+        final AlertDialog errorDialog = FrameworksUtils.makeAlertDialogBuilder(this)
                 .setMessage(message)
                 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                     @Override
diff --git a/src/com/android/server/telecom/ui/ConfirmCallDialogActivity.java b/src/com/android/server/telecom/ui/ConfirmCallDialogActivity.java
index 4735e3c..e9f99b6 100644
--- a/src/com/android/server/telecom/ui/ConfirmCallDialogActivity.java
+++ b/src/com/android/server/telecom/ui/ConfirmCallDialogActivity.java
@@ -16,6 +16,7 @@
 
 package com.android.server.telecom.ui;
 
+import com.android.server.telecom.FrameworksUtils;
 import com.android.server.telecom.R;
 import com.android.server.telecom.TelecomBroadcastIntentProcessor;
 import com.android.server.telecom.components.TelecomBroadcastReceiver;
@@ -48,7 +49,7 @@
     private void showDialog(final String callId, CharSequence ongoingAppName) {
         Log.i(this, "showDialog: confirming callId=%s, ongoing=%s", callId, ongoingAppName);
         CharSequence message = getString(R.string.alert_outgoing_call, ongoingAppName);
-        final AlertDialog errorDialog = new AlertDialog.Builder(this)
+        final AlertDialog errorDialog = FrameworksUtils.makeAlertDialogBuilder(this)
                 .setMessage(message)
                 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                     @Override
diff --git a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
index 12d3820..6b97f97 100644
--- a/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
+++ b/src/com/android/server/telecom/ui/MissedCallNotifierImpl.java
@@ -17,15 +17,45 @@
 package com.android.server.telecom.ui;
 
 import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.app.admin.DevicePolicyResources.Strings.Telecomm.NOTIFICATION_MISSED_WORK_CALL_TITLE;
 
 import android.annotation.NonNull;
 import android.app.BroadcastOptions;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.app.TaskStackBuilder;
+import android.app.admin.DevicePolicyManager;
+import android.content.AsyncQueryHandler;
 import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Binder;
 import android.os.Bundle;
+import android.os.UserHandle;
+import android.provider.CallLog.Calls;
+import android.telecom.CallerInfo;
+import android.telecom.Log;
 import android.telecom.Logging.Runnable;
+import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+import android.text.BidiFormatter;
+import android.text.TextDirectionHeuristics;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 
 import com.android.server.telecom.CallerInfoLookupHelper;
 import com.android.server.telecom.CallsManagerListenerBase;
@@ -40,42 +70,11 @@
 import com.android.server.telecom.Timeouts;
 import com.android.server.telecom.components.TelecomBroadcastReceiver;
 
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.TaskStackBuilder;
-import android.content.AsyncQueryHandler;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Binder;
-import android.os.UserHandle;
-import android.provider.CallLog.Calls;
-import android.telecom.Log;
-import android.telecom.PhoneAccount;
-import android.telephony.PhoneNumberUtils;
-import android.telephony.TelephonyManager;
-import android.text.BidiFormatter;
-import android.text.TextDirectionHeuristics;
-import android.text.TextUtils;
-
-import android.telecom.CallerInfo;
-import android.util.ArrayMap;
-
-import java.lang.Override;
-import java.lang.String;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Creates a notification for calls that the user missed (neither answered nor rejected).
@@ -141,7 +140,7 @@
     // Used to track the number of missed calls.
     private final Map<UserHandle, Integer> mMissedCallCounts;
 
-    private List<UserHandle> mUsersToLoadAfterBootComplete = new ArrayList<>();
+    private Set<UserHandle> mUsersToLoadAfterBootComplete = new ArraySet<>();
 
     public MissedCallNotifierImpl(Context context, PhoneAccountRegistrar phoneAccountRegistrar,
             DefaultDialerCache defaultDialerCache,
@@ -269,7 +268,9 @@
                     createClearMissedCallsPendingIntent(userHandle))
             .putExtra(TelecomManager.EXTRA_NOTIFICATION_COUNT, missedCallCount)
             .putExtra(TelecomManager.EXTRA_NOTIFICATION_PHONE_NUMBER,
-                    callInfo == null ? null : callInfo.getPhoneNumber());
+                    callInfo == null ? null : callInfo.getPhoneNumber())
+            .putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+                    callInfo == null ? null : callInfo.getPhoneAccountHandle());
 
         if (missedCallCount == 1 && callInfo != null) {
             final Uri handleUri = callInfo.getHandle();
@@ -327,7 +328,7 @@
             return;
         }
 
-        final int titleResId;
+        final String titleText;
         final String expandedText;  // The text in the notification's line 1 and 2.
 
         // Display the first line of the notification:
@@ -338,12 +339,14 @@
 
             CallerInfo ci = callInfo.getCallerInfo();
             if (ci != null && ci.userType == CallerInfo.USER_TYPE_WORK) {
-                titleResId = R.string.notification_missedWorkCallTitle;
+                titleText = mContext.getSystemService(DevicePolicyManager.class).getResources()
+                        .getString(NOTIFICATION_MISSED_WORK_CALL_TITLE, () ->
+                                mContext.getString(R.string.notification_missedWorkCallTitle));
             } else {
-                titleResId = R.string.notification_missedCallTitle;
+                titleText = mContext.getString(R.string.notification_missedCallTitle);
             }
         } else {
-            titleResId = R.string.notification_missedCallsTitle;
+            titleText = mContext.getString(R.string.notification_missedCallsTitle);
             expandedText =
                     mContext.getString(R.string.notification_missedCallsMsg, missedCallCounts);
         }
@@ -361,7 +364,7 @@
                 .setContentTitle(mContext.getText(R.string.userCallActivityLabel))
                 // Notification details shows that there are missed call(s), but does not reveal
                 // the missed caller information.
-                .setContentText(mContext.getText(titleResId))
+                .setContentText(titleText)
                 .setContentIntent(createCallLogPendingIntent(userHandle))
                 .setAutoCancel(true)
                 .setDeleteIntent(createClearMissedCallsPendingIntent(userHandle));
@@ -372,7 +375,7 @@
                 .setColor(mContext.getResources().getColor(R.color.theme_color))
                 .setWhen(callInfo.getCreationTimeMillis())
                 .setShowWhen(true)
-                .setContentTitle(mContext.getText(titleResId))
+                .setContentTitle(titleText)
                 .setContentText(expandedText)
                 .setContentIntent(createCallLogPendingIntent(userHandle))
                 .setAutoCancel(true)
@@ -606,10 +609,12 @@
             CallInfoFactory callInfoFactory, final UserHandle userHandle) {
         Log.d(this, "reloadFromDatabase: user=%d", userHandle.getIdentifier());
         if (TelecomSystem.getInstance() == null || !TelecomSystem.getInstance().isBootComplete()) {
-            Log.i(this, "reloadFromDatabase: Boot not yet complete -- call log db may not be "
-                    + "available. Deferring loading until boot complete for user %d",
-                    userHandle.getIdentifier());
-            mUsersToLoadAfterBootComplete.add(userHandle);
+            if (!mUsersToLoadAfterBootComplete.contains(userHandle)) {
+                Log.i(this, "reloadFromDatabase: Boot not yet complete -- call log db may not be "
+                        + "available. Deferring loading until boot complete for user %d",
+                        userHandle.getIdentifier());
+                mUsersToLoadAfterBootComplete.add(userHandle);
+            }
             return;
         }
 
diff --git a/testapps/src/com/android/server/telecom/testapps/TestCallList.java b/testapps/src/com/android/server/telecom/testapps/TestCallList.java
index 322c94c..32bc372 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestCallList.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestCallList.java
@@ -124,7 +124,7 @@
     }
 
     public Call getCall(int position) {
-        return mCalls.get(position);
+        return (position < mCalls.size()) ? mCalls.get(position) : null;
     }
 
     public void addCall(Call call) {
diff --git a/testapps/src/com/android/server/telecom/testapps/TestCertActivity.java b/testapps/src/com/android/server/telecom/testapps/TestCertActivity.java
index 312b447..a3e434b 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestCertActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestCertActivity.java
@@ -16,21 +16,19 @@
 package com.android.server.telecom.testapps;
 
 import android.app.Activity;
+import android.app.ProgressDialog;
 import android.content.Context;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.telephony.ImsiEncryptionInfo;
-import android.text.TextUtils;
-import android.util.Log;
 import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.widget.ArrayAdapter;
 import android.widget.EditText;
-import android.widget.Toast;
-
-import android.app.ProgressDialog;
-import android.os.AsyncTask;
-import android.util.Log;
 import android.widget.ListView;
 import android.widget.Toast;
 
@@ -38,12 +36,6 @@
 import org.json.JSONException;
 import org.json.JSONObject;
 
-import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.X509EncodedKeySpec;
-
 import java.io.BufferedInputStream;
 import java.io.BufferedReader;
 import java.io.IOException;
@@ -56,8 +48,6 @@
 import java.util.ArrayList;
 import java.util.Date;
 
-import android.util.Base64;
-
 public class TestCertActivity extends Activity {
 
     private EditText mCertUrlView;
@@ -149,15 +139,15 @@
             String mcc = "";
             String mnc = "";
             String networkOperator = telephonyManager.getNetworkOperator();
-
+            int carrierId = telephonyManager.getSimCarrierId();
             if (!TextUtils.isEmpty(networkOperator)) {
                 mcc = networkOperator.substring(0, 3);
                 mnc = networkOperator.substring(3);
-                Log.i(LOG_TAG, "using values for mnc, mcc: " + mnc + "," + mcc);
+                Log.i(LOG_TAG, "using values for mnc, mcc: " + mnc + "," + mcc + ", carrierId = "
+                        + carrierId);
             }
-
             ImsiEncryptionInfo imsiEncryptionInfo = new ImsiEncryptionInfo(mcc,
-                    mnc, type, identifier, keyBytes, new Date());
+                    mnc, type, identifier, keyBytes, new Date(), carrierId);
             telephonyManager.setCarrierInfoForImsiEncryption(imsiEncryptionInfo);
             keyList.add(imsiEncryptionInfo.getKeyType() + "," +
                     imsiEncryptionInfo.getKeyIdentifier());
diff --git a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
index 010d6ee..f17af2c 100644
--- a/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
+++ b/testapps/src/com/android/server/telecom/testapps/TestDialerActivity.java
@@ -4,6 +4,7 @@
 
 import android.app.Activity;
 import android.app.UiModeManager;
+import android.app.role.RoleManager;
 import android.content.ComponentName;
 import android.content.ContentValues;
 import android.content.Context;
@@ -133,9 +134,11 @@
     }
 
     private void setDefault() {
-        final Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER);
-        intent.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME, getPackageName());
-        startActivityForResult(intent, REQUEST_CODE_SET_DEFAULT_DIALER);
+        RoleManager roleManager = getSystemService(RoleManager.class);
+        if(roleManager!= null) {
+            startActivityForResult(roleManager.createRequestRoleIntent(RoleManager.ROLE_DIALER),
+                    REQUEST_CODE_SET_DEFAULT_DIALER);
+        }
     }
 
     private void placeCall() {
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 60d38af..e8c69d4 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -26,6 +26,7 @@
     <!-- TODO: Needed because we call BluetoothAdapter.getDefaultAdapter() statically, and
          BluetoothAdapter is a final class. -->
     <uses-permission android:name="android.permission.BLUETOOTH" />
+    <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
 
     <!-- TODO: Needed because we call ActivityManager.getCurrentUser() statically. -->
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
diff --git a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
index 2a304a4..5da7f31 100644
--- a/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
+++ b/tests/src/com/android/server/telecom/tests/AnalyticsTests.java
@@ -18,6 +18,7 @@
 
 import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
 import static android.provider.CallLog.Calls.USER_MISSED_CALL_FILTERS_TIMEOUT;
+import static android.provider.CallLog.Calls.USER_MISSED_NO_VIBRATE;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -209,7 +210,8 @@
         assertEquals(0, callAnalytics2.endTime);
         long missedReason1 = callAnalytics1.missedReason;
         assertTrue(missedReason1 == MISSED_REASON_NOT_MISSED
-                || missedReason1 == USER_MISSED_CALL_FILTERS_TIMEOUT);
+                || ((missedReason1 & USER_MISSED_CALL_FILTERS_TIMEOUT) > 0)
+                || ((missedReason1 & USER_MISSED_NO_VIBRATE) > 0));
         assertEquals(MISSED_REASON_NOT_MISSED, callAnalytics2.missedReason);
 
         assertEquals(Analytics.INCOMING_DIRECTION, callAnalytics1.callDirection);
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index a3b8654..049a501 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -26,6 +26,7 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
@@ -35,10 +36,14 @@
 
 import android.content.Context;
 import android.content.IContentProvider;
+import android.content.pm.PackageManager;
+import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Process;
+import android.os.UserHandle;
 import android.provider.BlockedNumberContract;
 import android.telecom.Call;
 import android.telecom.CallAudioState;
@@ -85,10 +90,15 @@
     private static final String TEST_BUNDLE_KEY = "android.telecom.extra.TEST";
     private static final String TEST_EVENT = "android.telecom.event.TEST";
 
+    private PackageManager mPackageManager;
+
     @Override
     @Before
     public void setUp() throws Exception {
         super.setUp();
+        doReturn(mContext).when(mContext).createContextAsUser(any(UserHandle.class), anyInt());
+        mPackageManager = mContext.getPackageManager();
+        when(mPackageManager.getPackageUid(anyString(), eq(0))).thenReturn(Binder.getCallingUid());
     }
 
     @Override
@@ -618,22 +628,27 @@
 
         mInCallServiceFixtureX.mInCallAdapter.mute(true);
         verify(mAudioService, timeout(TEST_TIMEOUT))
-                .setMicrophoneMute(eq(true), any(String.class), any(Integer.class));
+                .setMicrophoneMute(eq(true), any(String.class), any(Integer.class),
+                        nullable(String.class));
         mInCallServiceFixtureX.mInCallAdapter.mute(false);
         verify(mAudioService, timeout(TEST_TIMEOUT))
-                .setMicrophoneMute(eq(false), any(String.class), any(Integer.class));
+                .setMicrophoneMute(eq(false), any(String.class), any(Integer.class),
+                        nullable(String.class));
 
         mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_SPEAKER, null);
         waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager()
                 .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT);
-        verify(audioManager, timeout(TEST_TIMEOUT))
-                .setSpeakerphoneOn(true);
+        ArgumentCaptor<AudioDeviceInfo> infoArgumentCaptor =
+                ArgumentCaptor.forClass(AudioDeviceInfo.class);
+        verify(audioManager, timeout(TEST_TIMEOUT)).setCommunicationDevice(
+                infoArgumentCaptor.capture());
+        assertEquals(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, infoArgumentCaptor.getValue().getType());
         mInCallServiceFixtureX.mInCallAdapter.setAudioRoute(CallAudioState.ROUTE_EARPIECE, null);
         waitForHandlerAction(mTelecomSystem.getCallsManager().getCallAudioManager()
                 .getCallAudioRouteStateMachine().getHandler(), TEST_TIMEOUT);
         // setSpeakerPhoneOn(false) gets called once during the call initiation phase
         verify(audioManager, timeout(TEST_TIMEOUT).atLeast(1))
-                .setSpeakerphoneOn(false);
+                .clearCommunicationDevice();
 
         mConnectionServiceFixtureA.
                 sendSetDisconnected(outgoing.mConnectionId, DisconnectCause.REMOTE);
@@ -1033,7 +1048,9 @@
     @Test
     public void testIsOutgoingCallPermitted() throws Exception {
         assertTrue(mTelecomSystem.getTelecomServiceImpl().getBinder()
-                .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle()));
+                .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle(),
+                        mPhoneAccountSelfManaged.getAccountHandle().getComponentName()
+                                .getPackageName()));
     }
 
     /**
@@ -1050,7 +1067,9 @@
         assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
 
         assertTrue(mTelecomSystem.getTelecomServiceImpl().getBinder()
-                .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle()));
+                .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle(),
+                        mPhoneAccountSelfManaged.getAccountHandle().getComponentName()
+                                .getPackageName()));
     }
 
     /**
@@ -1068,7 +1087,9 @@
         assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
 
         assertTrue(mTelecomSystem.getTelecomServiceImpl().getBinder()
-                .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle()));
+                .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle(),
+                        mPhoneAccountSelfManaged.getAccountHandle().getComponentName()
+                                .getPackageName()));
     }
 
     /**
@@ -1185,7 +1206,7 @@
 
         ArgumentCaptor<Boolean> muteValueCaptor = ArgumentCaptor.forClass(Boolean.class);
         verify(mAudioService, times(2)).setMicrophoneMute(muteValueCaptor.capture(),
-                any(String.class), any(Integer.class));
+                any(String.class), any(Integer.class), nullable(String.class));
         List<Boolean> muteValues = muteValueCaptor.getAllValues();
         // Check mute status was changed twice with true and false.
         assertTrue(muteValues.get(0));
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
index bfa7a75..ce1e221 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothDeviceManagerTest.java
@@ -20,14 +20,15 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.Intent;
+import android.media.AudioDeviceInfo;
+import android.media.AudioManager;
 import android.os.Parcel;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.server.telecom.BluetoothAdapterProxy;
-import com.android.server.telecom.BluetoothHeadsetProxy;
 import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
 import com.android.server.telecom.bluetooth.BluetoothRouteManager;
 import com.android.server.telecom.bluetooth.BluetoothStateReceiver;
@@ -44,28 +45,38 @@
 import static org.junit.Assert.assertNull;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
 
 @RunWith(JUnit4.class)
 public class BluetoothDeviceManagerTest extends TelecomTestCase {
     @Mock BluetoothRouteManager mRouteManager;
-    @Mock BluetoothHeadsetProxy mHeadsetProxy;
-    @Mock BluetoothAdapterProxy mAdapterProxy;
+    @Mock BluetoothHeadset mBluetoothHeadset;
+    @Mock BluetoothAdapter mAdapter;
     @Mock BluetoothHearingAid mBluetoothHearingAid;
+    @Mock BluetoothLeAudio mBluetoothLeAudio;
+    @Mock AudioManager mockAudioManager;
 
     BluetoothDeviceManager mBluetoothDeviceManager;
     BluetoothProfile.ServiceListener serviceListenerUnderTest;
     BluetoothStateReceiver receiverUnderTest;
+    ArgumentCaptor<BluetoothLeAudio.Callback> leAudioCallbacksTest;
 
     private BluetoothDevice device1;
     private BluetoothDevice device2;
     private BluetoothDevice device3;
     private BluetoothDevice device4;
+    private BluetoothDevice device5;
+    private BluetoothDevice device6;
 
     @Override
     @Before
@@ -77,24 +88,34 @@
         device3 = makeBluetoothDevice("00:00:00:00:00:03");
         // hearing aid
         device4 = makeBluetoothDevice("00:00:00:00:00:04");
+        // le audio
+        device5 = makeBluetoothDevice("00:00:00:00:00:05");
+        device6 = makeBluetoothDevice("00:00:00:00:00:06");
 
         when(mBluetoothHearingAid.getHiSyncId(device2)).thenReturn(100L);
         when(mBluetoothHearingAid.getHiSyncId(device4)).thenReturn(100L);
 
         mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
-        mBluetoothDeviceManager = new BluetoothDeviceManager(mContext, mAdapterProxy);
+        mBluetoothDeviceManager = new BluetoothDeviceManager(mContext, mAdapter);
         mBluetoothDeviceManager.setBluetoothRouteManager(mRouteManager);
 
+        mockAudioManager = mContext.getSystemService(AudioManager.class);
+
         ArgumentCaptor<BluetoothProfile.ServiceListener> serviceCaptor =
                 ArgumentCaptor.forClass(BluetoothProfile.ServiceListener.class);
-        verify(mAdapterProxy).getProfileProxy(eq(mContext),
+        verify(mAdapter).getProfileProxy(eq(mContext),
                 serviceCaptor.capture(), eq(BluetoothProfile.HEADSET));
         serviceListenerUnderTest = serviceCaptor.getValue();
 
         receiverUnderTest = new BluetoothStateReceiver(mBluetoothDeviceManager, mRouteManager);
 
-        mBluetoothDeviceManager.setHeadsetServiceForTesting(mHeadsetProxy);
+        mBluetoothDeviceManager.setHeadsetServiceForTesting(mBluetoothHeadset);
         mBluetoothDeviceManager.setHearingAidServiceForTesting(mBluetoothHearingAid);
+
+        leAudioCallbacksTest =
+                         ArgumentCaptor.forClass(BluetoothLeAudio.Callback.class);
+        mBluetoothDeviceManager.setLeAudioServiceForTesting(mBluetoothLeAudio);
+        verify(mBluetoothLeAudio).registerCallback(any(), leAudioCallbacksTest.capture());
     }
 
     @Override
@@ -107,10 +128,12 @@
     @Test
     public void testSingleDeviceConnectAndDisconnect() {
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1, false));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
         assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device1, false));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device1,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
         assertEquals(0, mBluetoothDeviceManager.getNumConnectedDevices());
     }
 
@@ -121,59 +144,151 @@
         mBluetoothDeviceManager.setHearingAidServiceForTesting(null);
 
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1, false));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2, true));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
 
         assertEquals(0, mBluetoothDeviceManager.getNumConnectedDevices());
     }
-    
+
     @SmallTest
     @Test
     public void testMultiDeviceConnectAndDisconnect() {
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1, false));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2, true));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device1, false));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
+        when(mBluetoothLeAudio.getConnectedGroupLeadDevice(1)).thenReturn(device5);
+
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device3, false));
-        assertEquals(2, mBluetoothDeviceManager.getNumConnectedDevices());
+                buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device1,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device3, false));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device6,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        leAudioCallbacksTest.getValue().onGroupNodeAdded(device6, 2);
+        when(mBluetoothLeAudio.getConnectedGroupLeadDevice(2)).thenReturn(device6);
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device3,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        assertEquals(3, mBluetoothDeviceManager.getNumConnectedDevices());
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device3,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device6,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
         assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
     }
 
     @SmallTest
     @Test
+    public void testLeAudioMissedGroupCallbackBeforeConnected() {
+        /* This should be called on connection state changed */
+        when(mBluetoothLeAudio.getGroupId(device5)).thenReturn(1);
+        when(mBluetoothLeAudio.getGroupId(device6)).thenReturn(1);
+
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device6,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        when(mBluetoothLeAudio.getConnectedGroupLeadDevice(1)).thenReturn(device5);
+        assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
+        assertEquals(1, mBluetoothDeviceManager.getUniqueConnectedDevices().size());
+    }
+
+    @SmallTest
+    @Test
+    public void testLeAudioGroupAvailableBeforeConnect() {
+        /* Device is known (e.g. from storage) */
+        leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
+        leAudioCallbacksTest.getValue().onGroupNodeAdded(device6, 1);
+        /* Make sure getGroupId is not called for known devices */
+        verify(mBluetoothLeAudio, never()).getGroupId(device5);
+        verify(mBluetoothLeAudio, never()).getGroupId(device6);
+
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device6,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        when(mBluetoothLeAudio.getConnectedGroupLeadDevice(1)).thenReturn(device5);
+        assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
+        assertEquals(1, mBluetoothDeviceManager.getUniqueConnectedDevices().size());
+    }
+
+    @SmallTest
+    @Test
     public void testHearingAidDedup() {
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1, false));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2, true));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device4, true));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device4,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
         assertEquals(3, mBluetoothDeviceManager.getNumConnectedDevices());
         assertEquals(2, mBluetoothDeviceManager.getUniqueConnectedDevices().size());
     }
 
     @SmallTest
     @Test
+    public void testLeAudioDedup() {
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device6,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        leAudioCallbacksTest.getValue().onGroupNodeAdded(device6, 1);
+        when(mBluetoothLeAudio.getConnectedGroupLeadDevice(1)).thenReturn(device5);
+        assertEquals(2, mBluetoothDeviceManager.getNumConnectedDevices());
+        assertEquals(2, mBluetoothDeviceManager.getUniqueConnectedDevices().size());
+    }
+
+    @SmallTest
+    @Test
     public void testHeadsetServiceDisconnect() {
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1, false));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device3, false));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device3,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2, true));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
         serviceListenerUnderTest.onServiceDisconnected(BluetoothProfile.HEADSET);
 
-        verify(mRouteManager).onActiveDeviceChanged(isNull(), eq(false));
+        verify(mRouteManager).onActiveDeviceChanged(isNull(),
+                eq(BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
         verify(mRouteManager).onDeviceLost(device1.getAddress());
         verify(mRouteManager).onDeviceLost(device3.getAddress());
         verify(mRouteManager, never()).onDeviceLost(device2.getAddress());
-        assertNull(mBluetoothDeviceManager.getHeadsetService());
+        assertNull(mBluetoothDeviceManager.getBluetoothHeadset());
         assertEquals(1, mBluetoothDeviceManager.getNumConnectedDevices());
     }
 
@@ -181,18 +296,45 @@
     @Test
     public void testHearingAidServiceDisconnect() {
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1, false));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device3, false));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device3,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2, true));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
         serviceListenerUnderTest.onServiceDisconnected(BluetoothProfile.HEARING_AID);
 
-        verify(mRouteManager).onActiveDeviceChanged(isNull(), eq(true));
+        verify(mRouteManager).onActiveDeviceChanged(isNull(),
+                eq(BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
         verify(mRouteManager).onDeviceLost(device2.getAddress());
         verify(mRouteManager, never()).onDeviceLost(device1.getAddress());
         verify(mRouteManager, never()).onDeviceLost(device3.getAddress());
-        assertNull(mBluetoothDeviceManager.getHearingAidService());
+        assertNull(mBluetoothDeviceManager.getBluetoothHearingAid());
+        assertEquals(2, mBluetoothDeviceManager.getNumConnectedDevices());
+    }
+
+    @SmallTest
+    @Test
+    public void testLeAudioServiceDisconnect() {
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device3,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothLeAudio.STATE_CONNECTED, device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        serviceListenerUnderTest.onServiceDisconnected(BluetoothProfile.LE_AUDIO);
+
+        verify(mRouteManager).onActiveDeviceChanged(isNull(),
+                eq(BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        verify(mRouteManager).onDeviceLost(device5.getAddress());
+        verify(mRouteManager, never()).onDeviceLost(device1.getAddress());
+        verify(mRouteManager, never()).onDeviceLost(device3.getAddress());
+        assertNull(mBluetoothDeviceManager.getLeAudioService());
         assertEquals(2, mBluetoothDeviceManager.getNumConnectedDevices());
     }
 
@@ -201,13 +343,32 @@
     public void testHearingAidChangesIgnoredWhenNotInCall() {
         receiverUnderTest.setIsInCall(false);
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2, true));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
         Intent activeDeviceChangedIntent =
                 new Intent(BluetoothHearingAid.ACTION_ACTIVE_DEVICE_CHANGED);
         activeDeviceChangedIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device2);
         receiverUnderTest.onReceive(mContext, activeDeviceChangedIntent);
 
-        verify(mRouteManager).onActiveDeviceChanged(device2, true);
+        verify(mRouteManager).onActiveDeviceChanged(device2,
+                BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID);
+        verify(mRouteManager, never()).sendMessage(BluetoothRouteManager.BT_AUDIO_IS_ON);
+    }
+
+    @SmallTest
+    @Test
+    public void testLeAudioGroupChangesIgnoredWhenNotInCall() {
+        receiverUnderTest.setIsInCall(false);
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothLeAudio.STATE_CONNECTED, device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        Intent activeDeviceChangedIntent =
+                        new Intent(BluetoothLeAudio.ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED);
+        activeDeviceChangedIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, device5);
+        receiverUnderTest.onReceive(mContext, activeDeviceChangedIntent);
+
+        verify(mRouteManager).onActiveDeviceChanged(device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO);
         verify(mRouteManager, never()).sendMessage(BluetoothRouteManager.BT_AUDIO_IS_ON);
     }
 
@@ -215,37 +376,130 @@
     @Test
     public void testConnectDisconnectAudioHeadset() {
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1, false));
-        when(mAdapterProxy.setActiveDevice(nullable(BluetoothDevice.class), eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device1,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEADSET));
+        when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
+                    eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
         mBluetoothDeviceManager.connectAudio(device1.getAddress());
-        verify(mAdapterProxy).setActiveDevice(device1, BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL);
-        verify(mAdapterProxy, never()).setActiveDevice(nullable(BluetoothDevice.class), eq(BluetoothAdapter.ACTIVE_DEVICE_ALL));
+        verify(mAdapter).setActiveDevice(device1, BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL);
+        verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
+                eq(BluetoothAdapter.ACTIVE_DEVICE_ALL));
         mBluetoothDeviceManager.disconnectAudio();
-        verify(mHeadsetProxy).disconnectAudio();
+        verify(mBluetoothHeadset).disconnectAudio();
     }
 
     @SmallTest
     @Test
     public void testConnectDisconnectAudioHearingAid() {
+        receiverUnderTest.setIsInCall(true);
         receiverUnderTest.onReceive(mContext,
-                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device2, true));
-        mBluetoothDeviceManager.connectAudio(device2.getAddress());
-        verify(mAdapterProxy).setActiveDevice(device2, BluetoothAdapter.ACTIVE_DEVICE_ALL);
-        verify(mHeadsetProxy, never()).connectAudio();
-        verify(mAdapterProxy, never()).setActiveDevice(nullable(BluetoothDevice.class), eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID));
+        leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
+        when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
+                eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
 
-        when(mBluetoothHearingAid.getActiveDevices()).thenReturn(Arrays.asList(device2, null));
+        AudioDeviceInfo mockAudioDeviceInfo = mock(AudioDeviceInfo.class);
+        when(mockAudioDeviceInfo.getType()).thenReturn(AudioDeviceInfo.TYPE_HEARING_AID);
+        List<AudioDeviceInfo> devices = new ArrayList<>();
+        devices.add(mockAudioDeviceInfo);
 
+        when(mockAudioManager.getAvailableCommunicationDevices())
+                .thenReturn(devices);
+        when(mockAudioManager.setCommunicationDevice(eq(mockAudioDeviceInfo)))
+                .thenReturn(true);
+
+        mBluetoothDeviceManager.connectAudio(device5.getAddress());
+        verify(mAdapter).setActiveDevice(device5, BluetoothAdapter.ACTIVE_DEVICE_ALL);
+        verify(mBluetoothHeadset, never()).connectAudio();
+        verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
+                eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
+
+        when(mockAudioManager.getCommunicationDevice()).thenReturn(mockAudioDeviceInfo);
         mBluetoothDeviceManager.disconnectAudio();
-        verify(mAdapterProxy).setActiveDevice(null, BluetoothAdapter.ACTIVE_DEVICE_ALL);
-        verify(mHeadsetProxy).disconnectAudio();
+        verify(mockAudioManager).clearCommunicationDevice();
     }
 
-    private Intent buildConnectionActionIntent(int state, BluetoothDevice device,
-            boolean isHearingAid) {
-        Intent i = new Intent(isHearingAid
-                ? BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED
-                : BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+    @SmallTest
+    @Test
+    public void testConnectDisconnectAudioLeAudio() {
+        receiverUnderTest.setIsInCall(true);
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
+        when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
+                eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
+
+        AudioDeviceInfo mockAudioDeviceInfo = mock(AudioDeviceInfo.class);
+        when(mockAudioDeviceInfo.getType()).thenReturn(AudioDeviceInfo.TYPE_BLE_HEADSET);
+        List<AudioDeviceInfo> devices = new ArrayList<>();
+        devices.add(mockAudioDeviceInfo);
+
+        when(mockAudioManager.getAvailableCommunicationDevices())
+                        .thenReturn(devices);
+        when(mockAudioManager.setCommunicationDevice(mockAudioDeviceInfo))
+                       .thenReturn(true);
+
+        mBluetoothDeviceManager.connectAudio(device5.getAddress());
+        verify(mAdapter).setActiveDevice(device5, BluetoothAdapter.ACTIVE_DEVICE_ALL);
+        verify(mBluetoothHeadset, never()).connectAudio();
+        verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
+                eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
+
+        mBluetoothDeviceManager.disconnectAudio();
+        verify(mockAudioManager).clearCommunicationDevice();
+    }
+
+    @SmallTest
+    @Test
+    public void testConnectEarbudLeAudio() {
+        receiverUnderTest.setIsInCall(true);
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_CONNECTED, device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        leAudioCallbacksTest.getValue().onGroupNodeAdded(device5, 1);
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothLeAudio.STATE_CONNECTED, device6,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+        leAudioCallbacksTest.getValue().onGroupNodeAdded(device6, 1);
+        when(mAdapter.setActiveDevice(nullable(BluetoothDevice.class),
+                eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
+        mBluetoothDeviceManager.connectAudio(device5.getAddress());
+        verify(mAdapter).setActiveDevice(device5, BluetoothAdapter.ACTIVE_DEVICE_ALL);
+        verify(mBluetoothHeadset, never()).connectAudio();
+        verify(mAdapter, never()).setActiveDevice(nullable(BluetoothDevice.class),
+                eq(BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL));
+
+        when(mAdapter.getActiveDevices(eq(BluetoothProfile.LE_AUDIO)))
+                .thenReturn(Arrays.asList(device5, device6));
+
+        receiverUnderTest.onReceive(mContext,
+                buildConnectionActionIntent(BluetoothHeadset.STATE_DISCONNECTED, device5,
+                        BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO));
+
+        mBluetoothDeviceManager.connectAudio(device6.getAddress());
+        verify(mAdapter).setActiveDevice(device6, BluetoothAdapter.ACTIVE_DEVICE_ALL);
+    }
+
+    private Intent buildConnectionActionIntent(int state, BluetoothDevice device, int deviceType) {
+        String intentString;
+
+        switch (deviceType) {
+            case BluetoothDeviceManager.DEVICE_TYPE_HEADSET:
+                intentString = BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED;
+                break;
+            case BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID:
+                intentString = BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED;
+                break;
+            case BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO:
+                intentString = BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED;
+                break;
+            default:
+                return null;
+        }
+
+        Intent i = new Intent(intentString);
         i.putExtra(BluetoothHeadset.EXTRA_STATE, state);
         i.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
         return i;
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
index b20ecfb..e01cbbe 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothRouteManagerTest.java
@@ -16,16 +16,19 @@
 
 package com.android.server.telecom.tests;
 
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
 import android.content.ContentResolver;
 import android.os.Parcel;
 import android.telecom.Log;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.os.SomeArgs;
-import com.android.server.telecom.BluetoothHeadsetProxy;
 import com.android.server.telecom.TelecomSystem;
 import com.android.server.telecom.Timeouts;
 import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
@@ -60,9 +63,11 @@
     static final BluetoothDevice DEVICE3 = makeBluetoothDevice("00:00:00:00:00:03");
     static final BluetoothDevice HEARING_AID_DEVICE = makeBluetoothDevice("00:00:00:00:00:04");
 
+    @Mock private BluetoothAdapter mBluetoothAdapter;
     @Mock private BluetoothDeviceManager mDeviceManager;
-    @Mock private BluetoothHeadsetProxy mHeadsetProxy;
+    @Mock private BluetoothHeadset mBluetoothHeadset;
     @Mock private BluetoothHearingAid mBluetoothHearingAid;
+    @Mock private BluetoothLeAudio mBluetoothLeAudio;
     @Mock private Timeouts.Adapter mTimeoutsAdapter;
     @Mock private BluetoothRouteManager.BluetoothStateListener mListener;
 
@@ -80,14 +85,14 @@
 
     @SmallTest
     @Test
-    public void testConnectHfpRetryWhileNotConnected() {
+    public void testConnectBtRetryWhileNotConnected() {
         BluetoothRouteManager sm = setupStateMachine(
                 BluetoothRouteManager.AUDIO_OFF_STATE_NAME, null);
-        setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null, null, null);
+        setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null, null, null, null, null);
         when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
                 nullable(ContentResolver.class))).thenReturn(0L);
-        when(mHeadsetProxy.connectAudio()).thenReturn(false);
-        executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, DEVICE1.getAddress());
+        when(mBluetoothHeadset.connectAudio()).thenReturn(BluetoothStatusCodes.ERROR_UNKNOWN);
+        executeRoutingAction(sm, BluetoothRouteManager.CONNECT_BT, DEVICE1.getAddress());
         // Wait 3 times: for the first connection attempt, the retry attempt,
         // the second retry, and once more to make sure there are only three attempts.
         waitForHandlerAction(sm.getHandler(), TEST_TIMEOUT);
@@ -106,15 +111,19 @@
         BluetoothRouteManager sm = setupStateMachine(
                 BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1);
         setupConnectedDevices(new BluetoothDevice[]{DEVICE1},
-                new BluetoothDevice[]{HEARING_AID_DEVICE}, DEVICE1, HEARING_AID_DEVICE);
-        sm.onActiveDeviceChanged(DEVICE1, false);
-        sm.onActiveDeviceChanged(HEARING_AID_DEVICE, true);
+                new BluetoothDevice[]{HEARING_AID_DEVICE}, new BluetoothDevice[]{DEVICE2},
+                DEVICE1, HEARING_AID_DEVICE, DEVICE2);
+        sm.onActiveDeviceChanged(DEVICE1, BluetoothDeviceManager.DEVICE_TYPE_HEADSET);
+        sm.onActiveDeviceChanged(DEVICE2, BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO);
+        sm.onActiveDeviceChanged(HEARING_AID_DEVICE,
+                BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID);
         executeRoutingAction(sm, BluetoothRouteManager.BT_AUDIO_LOST, DEVICE1.getAddress());
 
         verifyConnectionAttempt(HEARING_AID_DEVICE, 0);
         verifyConnectionAttempt(DEVICE1, 0);
+        verifyConnectionAttempt(DEVICE2, 0);
         assertEquals(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX
-                        + ":" + HEARING_AID_DEVICE.getAddress(),
+                        + ":" + DEVICE1.getAddress(),
                 sm.getCurrentState().getName());
         sm.quitNow();
     }
@@ -124,8 +133,8 @@
     public void testAudioOnDeviceWithScoOffActiveDevice() {
         BluetoothRouteManager sm = setupStateMachine(
                 BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1);
-        setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null, DEVICE1, null);
-        when(mHeadsetProxy.getAudioState(DEVICE1))
+        setupConnectedDevices(new BluetoothDevice[]{DEVICE1}, null, null, DEVICE1, null, null);
+        when(mBluetoothHeadset.getAudioState(DEVICE1))
                 .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
         executeRoutingAction(sm, BluetoothRouteManager.BT_AUDIO_LOST, DEVICE1.getAddress());
 
@@ -137,14 +146,15 @@
 
     @SmallTest
     @Test
-    public void testConnectHfpRetryWhileConnectedToAnotherDevice() {
+    public void testConnectBtRetryWhileConnectedToAnotherDevice() {
         BluetoothRouteManager sm = setupStateMachine(
                 BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX, DEVICE1);
-        setupConnectedDevices(new BluetoothDevice[]{DEVICE1, DEVICE2}, null, null, null);
+        setupConnectedDevices(new BluetoothDevice[]{DEVICE1, DEVICE2}, null, null, null, null,
+                              null);
         when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
                 nullable(ContentResolver.class))).thenReturn(0L);
-        when(mHeadsetProxy.connectAudio()).thenReturn(false);
-        executeRoutingAction(sm, BluetoothRouteManager.CONNECT_HFP, DEVICE2.getAddress());
+        when(mBluetoothHeadset.connectAudio()).thenReturn(BluetoothStatusCodes.ERROR_UNKNOWN);
+        executeRoutingAction(sm, BluetoothRouteManager.CONNECT_BT, DEVICE2.getAddress());
         // Wait 3 times: the first connection attempt is accounted for in executeRoutingAction,
         // so wait twice for the retry attempt, again to make sure there are only three attempts,
         // and once more for good luck.
@@ -173,27 +183,32 @@
     }
 
     private void setupConnectedDevices(BluetoothDevice[] hfpDevices,
-            BluetoothDevice[] hearingAidDevices,
-            BluetoothDevice hfpActiveDevice, BluetoothDevice hearingAidActiveDevice) {
+            BluetoothDevice[] hearingAidDevices, BluetoothDevice[] leAudioDevices,
+            BluetoothDevice hfpActiveDevice, BluetoothDevice hearingAidActiveDevice,
+            BluetoothDevice leAudioDevice) {
         if (hfpDevices == null) hfpDevices = new BluetoothDevice[]{};
         if (hearingAidDevices == null) hearingAidDevices = new BluetoothDevice[]{};
+        if (leAudioDevice == null) leAudioDevices = new BluetoothDevice[]{};
 
         when(mDeviceManager.getNumConnectedDevices()).thenReturn(
-                hfpDevices.length + hearingAidDevices.length);
-        List<BluetoothDevice> allDevices = Stream.concat(
-                Arrays.stream(hfpDevices), Arrays.stream(hearingAidDevices))
-                .collect(Collectors.toList());
+                hfpDevices.length + hearingAidDevices.length + leAudioDevices.length);
+        List<BluetoothDevice> allDevices = Stream.of(
+                Arrays.stream(hfpDevices), Arrays.stream(hearingAidDevices),
+                Arrays.stream(leAudioDevices)).flatMap(i -> i).collect(Collectors.toList());
 
         when(mDeviceManager.getConnectedDevices()).thenReturn(allDevices);
-        when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(hfpDevices));
-        when(mHeadsetProxy.getActiveDevice()).thenReturn(hfpActiveDevice);
-        when(mHeadsetProxy.getAudioState(hfpActiveDevice))
+        when(mBluetoothHeadset.getConnectedDevices()).thenReturn(Arrays.asList(hfpDevices));
+        when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
+                .thenReturn(Arrays.asList(hfpActiveDevice));
+        when(mBluetoothHeadset.getAudioState(hfpActiveDevice))
                 .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED);
 
         when(mBluetoothHearingAid.getConnectedDevices())
                 .thenReturn(Arrays.asList(hearingAidDevices));
-        when(mBluetoothHearingAid.getActiveDevices())
+        when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEARING_AID)))
                 .thenReturn(Arrays.asList(hearingAidActiveDevice, null));
+        when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.LE_AUDIO)))
+                .thenReturn(Arrays.asList(leAudioDevice, null));
     }
 
     static void executeRoutingAction(BluetoothRouteManager brm, int message, String
@@ -215,11 +230,14 @@
     }
 
     private void resetMocks() {
-        reset(mDeviceManager, mListener, mHeadsetProxy, mTimeoutsAdapter);
-        when(mDeviceManager.getHeadsetService()).thenReturn(mHeadsetProxy);
-        when(mDeviceManager.getHearingAidService()).thenReturn(mBluetoothHearingAid);
-        when(mHeadsetProxy.connectAudio()).thenReturn(true);
-        when(mHeadsetProxy.setActiveDevice(nullable(BluetoothDevice.class))).thenReturn(true);
+        reset(mDeviceManager, mListener, mBluetoothHeadset, mTimeoutsAdapter);
+        when(mDeviceManager.getBluetoothHeadset()).thenReturn(mBluetoothHeadset);
+        when(mDeviceManager.getBluetoothHearingAid()).thenReturn(mBluetoothHearingAid);
+        when(mDeviceManager.getBluetoothAdapter()).thenReturn(mBluetoothAdapter);
+        when(mDeviceManager.getLeAudioService()).thenReturn(mBluetoothLeAudio);
+        when(mBluetoothHeadset.connectAudio()).thenReturn(BluetoothStatusCodes.SUCCESS);
+        when(mBluetoothAdapter.setActiveDevice(nullable(BluetoothDevice.class),
+                eq(BluetoothAdapter.ACTIVE_DEVICE_ALL))).thenReturn(true);
         when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
                 nullable(ContentResolver.class))).thenReturn(100000L);
         when(mTimeoutsAdapter.getBluetoothPendingTimeoutMillis(
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java b/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
index b36d74b..b729f35 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothRouteTransitionTests.java
@@ -16,15 +16,18 @@
 
 package com.android.server.telecom.tests;
 
+import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothStatusCodes;
 import android.content.ContentResolver;
 import android.telecom.Log;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.internal.os.SomeArgs;
-import com.android.server.telecom.BluetoothHeadsetProxy;
 import com.android.server.telecom.TelecomSystem;
 import com.android.server.telecom.Timeouts;
 import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
@@ -42,6 +45,8 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.stream.Stream;
+import java.util.stream.Collectors;
 
 import static com.android.server.telecom.tests.BluetoothRouteManagerTest.DEVICE1;
 import static com.android.server.telecom.tests.BluetoothRouteManagerTest.DEVICE2;
@@ -76,9 +81,10 @@
         private BluetoothDevice expectedConnectionDevice;
         private String expectedFinalStateName;
         private BluetoothDevice[] connectedDevices;
-        // the active device as returned by BluetoothHeadset#getActiveDevice
+        // the active device as returned by BluetoothAdapter#getActiveDevices
         private BluetoothDevice activeDevice = null;
         private List<BluetoothDevice> hearingAidBtDevices = Collections.emptyList();
+        private List<BluetoothDevice> leAudioDevices = Collections.emptyList();
 
         public BluetoothRouteTestParametersBuilder setName(String name) {
             this.name = name;
@@ -153,6 +159,12 @@
             return this;
         }
 
+        public BluetoothRouteTestParametersBuilder setLeAudioDevices(
+                List<BluetoothDevice> leAudioDevices) {
+            this.leAudioDevices = leAudioDevices;
+            return this;
+        }
+
         public BluetoothRouteTestParameters build() {
             return new BluetoothRouteTestParameters(name,
                     initialBluetoothState,
@@ -166,7 +178,8 @@
                     messageDevice,
                     audioOnDevice,
                     activeDevice,
-                    hearingAidBtDevices);
+                    hearingAidBtDevices,
+                    leAudioDevices);
 
         }
     }
@@ -179,13 +192,15 @@
         public int messageType; // Any of the commands from the state machine
         public BluetoothDevice messageDevice; // The device that should be specified in the message.
         public ListenerUpdate[] expectedListenerUpdates; // what the listener should expect.
-        public int expectedBluetoothInteraction; // NONE, CONNECT, or DISCONNECT
+        // NONE, CONNECT, CONNECT_SWITCH_DEVICE or DISCONNECT
+        public int expectedBluetoothInteraction;
         public BluetoothDevice expectedConnectionDevice; // Expected device to connect to.
         public String expectedFinalStateName; // Expected name of the final state.
         public BluetoothDevice[] connectedDevices; // array of connected devices
-        // the active device as returned by BluetoothHeadset#getActiveDevice
+        // the active device as returned by BluetoothAdapter#getActiveDevices
         private BluetoothDevice activeDevice = null;
         private List<BluetoothDevice> hearingAidBtDevices;
+        private List<BluetoothDevice> leAudioDevices;
 
         public BluetoothRouteTestParameters(String name, String initialBluetoothState,
                 BluetoothDevice initialDevice, int messageType, ListenerUpdate[]
@@ -193,7 +208,7 @@
                 expectedConnectionDevice, String expectedFinalStateName,
                 BluetoothDevice[] connectedDevices, BluetoothDevice messageDevice,
                 BluetoothDevice audioOnDevice, BluetoothDevice activeDevice,
-                List<BluetoothDevice> hearingAidBtDevices) {
+                List<BluetoothDevice> hearingAidBtDevices, List<BluetoothDevice> leAudioDevices) {
             this.name = name;
             this.initialBluetoothState = initialBluetoothState;
             this.initialDevice = initialDevice;
@@ -207,23 +222,28 @@
             this.audioOnDevice = audioOnDevice;
             this.activeDevice = activeDevice;
             this.hearingAidBtDevices = hearingAidBtDevices;
+            this.leAudioDevices = leAudioDevices;
         }
 
         @Override
         public String toString() {
+            String expectedListenerUpdatesStr = expectedListenerUpdates == null ? ""
+                    : Arrays.stream(expectedListenerUpdates).map(ListenerUpdate::name)
+                            .collect(Collectors.joining(","));
             return "BluetoothRouteTestParameters{" +
                     "name='" + name + '\'' +
                     ", initialBluetoothState='" + initialBluetoothState + '\'' +
                     ", initialDevice=" + initialDevice +
                     ", messageType=" + messageType +
                     ", messageDevice='" + messageDevice + '\'' +
-                    ", expectedListenerUpdate=" + expectedListenerUpdates +
+                    ", expectedListenerUpdate='" + expectedListenerUpdatesStr + '\'' +
                     ", expectedBluetoothInteraction=" + expectedBluetoothInteraction +
                     ", expectedConnectionDevice='" + expectedConnectionDevice + '\'' +
                     ", expectedFinalStateName='" + expectedFinalStateName + '\'' +
                     ", connectedDevices=" + Arrays.toString(connectedDevices) +
                     ", activeDevice='" + activeDevice + '\'' +
                     ", hearingAidBtDevices ='" + hearingAidBtDevices + '\'' +
+                    ", leAudioDevices ='" + leAudioDevices + '\'' +
                     '}';
         }
     }
@@ -231,13 +251,16 @@
     private static final int NONE = 1;
     private static final int CONNECT = 2;
     private static final int DISCONNECT = 3;
+    private static final int CONNECT_SWITCH_DEVICE = 4;
 
     private static final int TEST_TIMEOUT = 1000;
 
     private final BluetoothRouteTestParameters mParams;
     @Mock private BluetoothDeviceManager mDeviceManager;
-    @Mock private BluetoothHeadsetProxy mHeadsetProxy;
+    @Mock private BluetoothAdapter mBluetoothAdapter;
+    @Mock private BluetoothHeadset mBluetoothHeadset;
     @Mock private BluetoothHearingAid mBluetoothHearingAid;
+    @Mock private BluetoothLeAudio mBluetoothLeAudio;
     @Mock private Timeouts.Adapter mTimeoutsAdapter;
     @Mock private BluetoothRouteManager.BluetoothStateListener mListener;
 
@@ -245,6 +268,7 @@
     @Before
     public void setUp() throws Exception {
         super.setUp();
+        when(mDeviceManager.getBluetoothAdapter()).thenReturn(mBluetoothAdapter);
     }
 
     @Override
@@ -263,33 +287,44 @@
         BluetoothRouteManager sm = setupStateMachine(
                 mParams.initialBluetoothState, mParams.initialDevice);
 
+        int deviceType = BluetoothDeviceManager.DEVICE_TYPE_HEADSET;
+        if (mParams.hearingAidBtDevices.contains(mParams.messageDevice)) {
+            deviceType = BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID;
+        } else if (mParams.hearingAidBtDevices.contains(mParams.messageDevice)) {
+            deviceType = BluetoothDeviceManager.DEVICE_TYPE_LE_AUDIO;
+        }
+
         setupConnectedDevices(mParams.connectedDevices,
                 mParams.audioOnDevice, mParams.activeDevice);
-        sm.setActiveDeviceCacheForTesting(mParams.activeDevice,
-                mParams.hearingAidBtDevices.contains(mParams.messageDevice));
+        sm.setActiveDeviceCacheForTesting(mParams.activeDevice, deviceType);
         if (mParams.initialDevice != null) {
             doAnswer(invocation -> {
                 SomeArgs args = SomeArgs.obtain();
                 args.arg1 = Log.createSubsession();
                 args.arg2 = mParams.initialDevice.getAddress();
-                when(mHeadsetProxy.getActiveDevice()).thenReturn(null);
+                when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
+                    .thenReturn(Arrays.asList((BluetoothDevice) null));
                 sm.sendMessage(BluetoothRouteManager.BT_AUDIO_LOST, args);
-                return true;
+                return BluetoothStatusCodes.SUCCESS;
             }).when(mDeviceManager).disconnectAudio();
         }
 
         // Go through the utility methods for these two messages
         if (mParams.messageType == BluetoothRouteManager.NEW_DEVICE_CONNECTED) {
             sm.onDeviceAdded(mParams.messageDevice.getAddress());
-            sm.onActiveDeviceChanged(mParams.messageDevice,
-                    mParams.hearingAidBtDevices.contains(mParams.messageDevice));
+            sm.onActiveDeviceChanged(mParams.messageDevice, deviceType);
         } else if (mParams.messageType == BluetoothRouteManager.LOST_DEVICE) {
-            sm.onActiveDeviceChanged(null,
-                    mParams.hearingAidBtDevices.contains(mParams.messageDevice));
+            sm.onActiveDeviceChanged(null, deviceType);
             if (mParams.hearingAidBtDevices.contains(mParams.messageDevice)) {
-                when(mBluetoothHearingAid.getActiveDevices()).thenReturn(Arrays.asList(null, null));
+                when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEARING_AID)))
+                    .thenReturn(Arrays.asList(null, null));
+                when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.LE_AUDIO)))
+                    .thenReturn(mParams.leAudioDevices.stream()
+                       .filter(device -> device != mParams.messageDevice)
+                       .collect(Collectors.toList()));
             } else {
-                when(mHeadsetProxy.getActiveDevice()).thenReturn(null);
+                when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
+                    .thenReturn(Arrays.asList((BluetoothDevice) null));
             }
             sm.onDeviceLost(mParams.messageDevice.getAddress());
         } else {
@@ -330,6 +365,10 @@
                 verify(mDeviceManager).connectAudio(mParams.expectedConnectionDevice.getAddress());
                 verify(mDeviceManager, never()).disconnectAudio();
                 break;
+            case CONNECT_SWITCH_DEVICE:
+                verify(mDeviceManager).disconnectAudio();
+                verify(mDeviceManager).connectAudio(mParams.expectedConnectionDevice.getAddress());
+            break;
             case DISCONNECT:
                 verify(mDeviceManager, never()).connectAudio(nullable(String.class));
                 verify(mDeviceManager).disconnectAudio();
@@ -344,13 +383,15 @@
             BluetoothDevice audioOnDevice, BluetoothDevice activeDevice) {
         when(mDeviceManager.getNumConnectedDevices()).thenReturn(devices.length);
         when(mDeviceManager.getConnectedDevices()).thenReturn(Arrays.asList(devices));
-        when(mHeadsetProxy.getConnectedDevices()).thenReturn(Arrays.asList(devices));
-        when(mHeadsetProxy.getActiveDevice()).thenReturn(activeDevice);
-        when(mHeadsetProxy.getAudioState(nullable(BluetoothDevice.class)))
+        when(mBluetoothHeadset.getConnectedDevices()).thenReturn(Arrays.asList(devices));
+        when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
+            .thenReturn(Arrays.asList(activeDevice));
+        when(mBluetoothHeadset.getAudioState(nullable(BluetoothDevice.class)))
                 .thenReturn(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
         if (audioOnDevice != null) {
-            when(mHeadsetProxy.getActiveDevice()).thenReturn(audioOnDevice);
-            when(mHeadsetProxy.getAudioState(audioOnDevice))
+            when(mBluetoothAdapter.getActiveDevices(eq(BluetoothProfile.HEADSET)))
+                .thenReturn(Arrays.asList(audioOnDevice));
+            when(mBluetoothHeadset.getAudioState(audioOnDevice))
                     .thenReturn(BluetoothHeadset.STATE_AUDIO_CONNECTED);
         }
     }
@@ -358,8 +399,9 @@
     private BluetoothRouteManager setupStateMachine(String initialState,
             BluetoothDevice initialDevice) {
         resetMocks();
-        when(mDeviceManager.getHeadsetService()).thenReturn(mHeadsetProxy);
-        when(mDeviceManager.getHearingAidService()).thenReturn(mBluetoothHearingAid);
+        when(mDeviceManager.getBluetoothHeadset()).thenReturn(mBluetoothHeadset);
+        when(mDeviceManager.getBluetoothHearingAid()).thenReturn(mBluetoothHearingAid);
+        when(mDeviceManager.getLeAudioService()).thenReturn(mBluetoothLeAudio);
         when(mDeviceManager.connectAudio(nullable(String.class))).thenReturn(true);
         when(mTimeoutsAdapter.getRetryBluetoothConnectAudioBackoffMillis(
                 nullable(ContentResolver.class))).thenReturn(100000L);
@@ -375,7 +417,7 @@
     }
 
     private void resetMocks() {
-        clearInvocations(mDeviceManager, mListener, mHeadsetProxy, mTimeoutsAdapter);
+        clearInvocations(mDeviceManager, mListener, mBluetoothHeadset, mTimeoutsAdapter);
     }
 
     @Parameterized.Parameters(name = "{0}")
@@ -401,7 +443,7 @@
                 .setInitialDevice(null)
                 .setConnectedDevices(DEVICE2, DEVICE1)
                 .setActiveDevice(DEVICE1)
-                .setMessageType(BluetoothRouteManager.CONNECT_HFP)
+                .setMessageType(BluetoothRouteManager.CONNECT_BT)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
                 .setExpectedBluetoothInteraction(CONNECT)
                 .setExpectedConnectionDevice(DEVICE1)
@@ -425,7 +467,7 @@
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
-                .setName("Device loses HFP audio but remains connected. No fallback.")
+                .setName("Device loses BT audio but remains connected. No fallback.")
                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices(DEVICE2)
@@ -438,7 +480,7 @@
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
-                .setName("Device loses HFP audio but remains connected."
+                .setName("Device loses BT audio but remains connected."
                         + " No fallback even though other devices available.")
                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
                 .setInitialDevice(DEVICE2)
@@ -456,10 +498,10 @@
                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices(DEVICE2, DEVICE1, DEVICE3)
-                .setMessageType(BluetoothRouteManager.CONNECT_HFP)
+                .setMessageType(BluetoothRouteManager.CONNECT_BT)
                 .setMessageDevice(DEVICE3)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
-                .setExpectedBluetoothInteraction(CONNECT)
+                .setExpectedBluetoothInteraction(CONNECT_SWITCH_DEVICE)
                 .setExpectedConnectionDevice(DEVICE3)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
                         + ":" + DEVICE3)
@@ -470,10 +512,10 @@
                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX)
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices(DEVICE2, DEVICE1, DEVICE3)
-                .setMessageType(BluetoothRouteManager.CONNECT_HFP)
+                .setMessageType(BluetoothRouteManager.CONNECT_BT)
                 .setMessageDevice(DEVICE3)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
-                .setExpectedBluetoothInteraction(CONNECT)
+                .setExpectedBluetoothInteraction(CONNECT_SWITCH_DEVICE)
                 .setExpectedConnectionDevice(DEVICE3)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX
                         + ":" + DEVICE3)
@@ -589,22 +631,22 @@
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
-                .setName("Audio routing requests HFP disconnection while a device is active")
+                .setName("Audio routing requests BT disconnection while a device is active")
                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices(DEVICE2, DEVICE3)
-                .setMessageType(BluetoothRouteManager.DISCONNECT_HFP)
+                .setMessageType(BluetoothRouteManager.DISCONNECT_BT)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED)
                 .setExpectedBluetoothInteraction(DISCONNECT)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
                 .build());
 
         result.add(new BluetoothRouteTestParametersBuilder()
-                .setName("Audio routing requests HFP disconnection while a device is pending")
+                .setName("Audio routing requests BT disconnection while a device is pending")
                 .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTING_STATE_NAME_PREFIX)
                 .setInitialDevice(DEVICE2)
                 .setConnectedDevices(DEVICE2, DEVICE3)
-                .setMessageType(BluetoothRouteManager.DISCONNECT_HFP)
+                .setMessageType(BluetoothRouteManager.DISCONNECT_BT)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED)
                 .setExpectedBluetoothInteraction(DISCONNECT)
                 .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
@@ -644,7 +686,7 @@
                 .setActiveDevice(DEVICE2)
                 .setConnectedDevices(DEVICE2, DEVICE3)
                 .setHearingAidBtDevices(Collections.singletonList(DEVICE2))
-                .setMessageType(BluetoothRouteManager.CONNECT_HFP)
+                .setMessageType(BluetoothRouteManager.CONNECT_BT)
                 .setMessageDevice(DEVICE2)
                 .setExpectedListenerUpdates(ListenerUpdate.AUDIO_CONNECTED)
                 .setExpectedBluetoothInteraction(NONE)
@@ -652,6 +694,36 @@
                         + ":" + DEVICE2)
                 .build());
 
+        result.add(new BluetoothRouteTestParametersBuilder()
+                .setName("le audio device disconnects with hearing aid present")
+                .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
+                .setInitialDevice(DEVICE2)
+                .setConnectedDevices(DEVICE2, DEVICE3)
+                .setLeAudioDevices(Collections.singletonList(DEVICE2))
+                .setHearingAidBtDevices(Collections.singletonList(DEVICE3))
+                .setMessageType(BluetoothRouteManager.LOST_DEVICE)
+                .setMessageDevice(DEVICE2)
+                .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED,
+                        ListenerUpdate.DEVICE_LIST_CHANGED)
+                .setExpectedBluetoothInteraction(NONE)
+                .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
+                .build());
+
+        result.add(new BluetoothRouteTestParametersBuilder()
+                .setName("le audio device disconnects with another one connected")
+                .setInitialBluetoothState(BluetoothRouteManager.AUDIO_CONNECTED_STATE_NAME_PREFIX)
+                .setInitialDevice(DEVICE1)
+                .setConnectedDevices(DEVICE1, DEVICE2, DEVICE3)
+                .setHearingAidBtDevices(Collections.singletonList(DEVICE3))
+                .setLeAudioDevices(Arrays.asList(DEVICE1, DEVICE2))
+                .setMessageType(BluetoothRouteManager.LOST_DEVICE)
+                .setMessageDevice(DEVICE1)
+                .setExpectedListenerUpdates(ListenerUpdate.AUDIO_DISCONNECTED,
+                        ListenerUpdate.DEVICE_LIST_CHANGED)
+                .setExpectedBluetoothInteraction(NONE)
+                .setExpectedFinalStateName(BluetoothRouteManager.AUDIO_OFF_STATE_NAME)
+                .build());
+
         return result;
     }
 }
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
index 7af29aa..4adafc8 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioManagerTest.java
@@ -45,6 +45,7 @@
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 
+import java.util.Arrays;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -294,6 +295,60 @@
         verifyProperCleanup();
     }
 
+    @MediumTest
+    @Test
+    public void testRingbackStartStop() {
+        Call call = mock(Call.class);
+        ArgumentCaptor<CallAudioModeStateMachine.MessageArgs> captor = makeNewCaptor();
+        when(call.getState()).thenReturn(CallState.CONNECTING);
+        when(call.isRingbackRequested()).thenReturn(true);
+
+        mCallAudioManager.onCallAdded(call);
+        assertEquals(call, mCallAudioManager.getForegroundCall());
+        verify(mCallAudioRouteStateMachine).sendMessageWithSessionInfo(
+                CallAudioRouteStateMachine.UPDATE_SYSTEM_AUDIO_ROUTE);
+        verify(mCallAudioModeStateMachine).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture());
+        CallAudioModeStateMachine.MessageArgs expectedArgs =
+                new Builder()
+                        .setHasActiveOrDialingCalls(true)
+                        .setHasRingingCalls(false)
+                        .setHasHoldingCalls(false)
+                        .setIsTonePlaying(false)
+                        .setHasAudioProcessingCalls(false)
+                        .setForegroundCallIsVoip(false)
+                        .setSession(null)
+                        .build();
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+
+        when(call.getState()).thenReturn(CallState.DIALING);
+        mCallAudioManager.onCallStateChanged(call, CallState.CONNECTING, CallState.DIALING);
+        verify(mCallAudioModeStateMachine, times(2)).sendMessageWithArgs(
+                eq(CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL), captor.capture());
+        assertMessageArgEquality(expectedArgs, captor.getValue());
+        verify(mCallAudioModeStateMachine, times(2)).sendMessageWithArgs(
+                anyInt(), any(CallAudioModeStateMachine.MessageArgs.class));
+
+        // Ensure we started ringback.
+        verify(mRingbackPlayer).startRingbackForCall(any(Call.class));
+
+        // Report state change from dialing to dialing, which happens when a call is locally
+        // disconnected.
+        mCallAudioManager.onCallStateChanged(call, CallState.DIALING, CallState.DIALING);
+        // Should not have stopped ringback.
+        verify(mRingbackPlayer, never()).stopRingbackForCall(any(Call.class));
+        // Should still only have initial ringback start
+        verify(mRingbackPlayer, times(1)).startRingbackForCall(any(Call.class));
+
+        // Report state to disconnected
+        when(call.getState()).thenReturn(CallState.DISCONNECTED);
+        mCallAudioManager.onCallStateChanged(call, CallState.DIALING, CallState.DISCONNECTED);
+        // Now we should have stopped ringback.
+        verify(mRingbackPlayer).stopRingbackForCall(any(Call.class));
+        // Should still only have initial ringback start recorded from before (don't restart it).
+        verify(mRingbackPlayer, times(1)).startRingbackForCall(any(Call.class));
+    }
+
     @SmallTest
     @Test
     public void testNewCallGoesToAudioProcessing() {
@@ -607,6 +662,21 @@
         verifyProperCleanup();
     }
 
+    @SmallTest
+    @Test
+    public void testGetVoipMode() {
+        Call child = mock(Call.class);
+        when(child.getIsVoipAudioMode()).thenReturn(true);
+
+        Call conference = mock(Call.class);
+        when(conference.isConference()).thenReturn(true);
+        when(conference.getIsVoipAudioMode()).thenReturn(false);
+        when(conference.getChildCalls()).thenReturn(Arrays.asList(child));
+
+        assertTrue(mCallAudioManager.isCallVoip(conference));
+        assertTrue(mCallAudioManager.isCallVoip(child));
+    }
+
     private Call createSimulatedRingingCall() {
         Call call = mock(Call.class);
         when(call.getState()).thenReturn(CallState.SIMULATED_RINGING);
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index 91ec7f3..6092293 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.media.IAudioService;
 import android.os.HandlerThread;
@@ -505,6 +506,37 @@
 
     @SmallTest
     @Test
+    public void testDockWhenInQuiescentState() {
+        CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
+                mContext,
+                mockCallsManager,
+                mockBluetoothRouteManager,
+                mockWiredHeadsetManager,
+                mockStatusBarNotifier,
+                mAudioServiceFactory,
+                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED,
+                mThreadHandler.getLooper());
+        stateMachine.setCallAudioManager(mockCallAudioManager);
+        when(mockAudioManager.isSpeakerphoneOn()).thenReturn(false);
+        CallAudioState initState = new CallAudioState(false, CallAudioState.ROUTE_SPEAKER,
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER);
+        stateMachine.initialize(initState);
+
+        // Raise a dock connect event.
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.CONNECT_DOCK);
+        waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
+        assertTrue(!stateMachine.isInActiveState());
+        verify(mockAudioManager, never()).setSpeakerphoneOn(eq(true));
+
+        // Raise a dock disconnect event.
+        stateMachine.sendMessageWithSessionInfo(CallAudioRouteStateMachine.DISCONNECT_DOCK);
+        waitForHandlerAction(stateMachine.getHandler(), TEST_TIMEOUT);
+        assertTrue(!stateMachine.isInActiveState());
+        verify(mockAudioManager, never()).setSpeakerphoneOn(eq(false));
+    }
+
+    @SmallTest
+    @Test
     public void testFocusChangeFromQuiescentSpeaker() {
         CallAudioRouteStateMachine stateMachine = new CallAudioRouteStateMachine(
                 mContext,
@@ -531,7 +563,10 @@
         // Make sure that we've successfully switched to the active speaker route and that we've
         // called setSpeakerOn
         assertTrue(stateMachine.isInActiveState());
-        verify(mockAudioManager).setSpeakerphoneOn(true);
+        ArgumentCaptor<AudioDeviceInfo> infoArgumentCaptor = ArgumentCaptor.forClass(
+                AudioDeviceInfo.class);
+        verify(mockAudioManager).setCommunicationDevice(infoArgumentCaptor.capture());
+        assertEquals(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, infoArgumentCaptor.getValue().getType());
     }
 
     @SmallTest
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
index 879ed0f..3eacc3a 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteTransitionTests.java
@@ -23,6 +23,7 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
@@ -30,6 +31,7 @@
 
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
+import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.media.IAudioService;
 import android.os.Handler;
@@ -325,11 +327,18 @@
 
         switch (mParams.speakerInteraction) {
             case NONE:
-                verify(mockAudioManager, never()).setSpeakerphoneOn(any(Boolean.class));
+                verify(mockAudioManager, never()).setCommunicationDevice(
+                        any(AudioDeviceInfo.class));
                 break;
-            case ON: // fall through
+            case ON:
+                ArgumentCaptor<AudioDeviceInfo> infoArgumentCaptor = ArgumentCaptor.forClass(
+                        AudioDeviceInfo.class);
+                verify(mockAudioManager).setCommunicationDevice(infoArgumentCaptor.capture());
+                assertEquals(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
+                        infoArgumentCaptor.getValue().getType());
+                break;
             case OFF:
-                verify(mockAudioManager).setSpeakerphoneOn(mParams.speakerInteraction == ON);
+                verify(mockAudioManager).clearCommunicationDevice();
                 break;
             case OPTIONAL:
                 // optional, don't test
@@ -823,6 +832,30 @@
                 CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
         ));
 
+        params.add(new RoutingTestParameters(
+                "Connect dock from earpiece", // name
+                CallAudioState.ROUTE_EARPIECE, // initialRoute
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // availableRoutes
+                ON, // speakerInteraction
+                NONE, // bluetoothInteraction
+                CallAudioRouteStateMachine.CONNECT_DOCK, // action
+                CallAudioState.ROUTE_SPEAKER, // expectedRoute
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // expectedAvailRoutes
+                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
+        ));
+
+        params.add(new RoutingTestParameters(
+                "Disconnect dock from speaker", // name
+                CallAudioState.ROUTE_SPEAKER, // initialRoute
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // availableRoutes
+                OFF, // speakerInteraction
+                NONE, // bluetoothInteraction
+                CallAudioRouteStateMachine.DISCONNECT_DOCK, // action
+                CallAudioState.ROUTE_EARPIECE, // expectedRoute
+                CallAudioState.ROUTE_EARPIECE | CallAudioState.ROUTE_SPEAKER, // expectedAvailRoutes
+                CallAudioRouteStateMachine.EARPIECE_FORCE_ENABLED // earpieceControl
+        ));
+
         return params;
     }
 
diff --git a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
index 68caf67..9ff9986 100644
--- a/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallScreeningServiceFilterTest.java
@@ -62,6 +62,7 @@
 import org.mockito.Mock;
 
 import java.util.Collections;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
 import java.util.concurrent.TimeUnit;
 
@@ -229,12 +230,30 @@
         CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
                 CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
                 mAppLabelProxy, mParcelableCallUtilsConverter);
-        filter.startFilterLookup(inputResult);
+        CompletableFuture<CallFilteringResult> result = filter.startFilterLookup(inputResult)
+                .toCompletableFuture();
+
+        assertEquals(result.isDone(), false);
+
         filter.unbindCallScreeningService();
     }
 
     @SmallTest
     @Test
+    public void testBindingFailed() {
+        // Use an empty package name here, which fails in the bindCallScreeningService.
+        CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, "",
+                CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
+                mAppLabelProxy, mParcelableCallUtilsConverter);
+
+        CompletableFuture<CallFilteringResult> result = filter.startFilterLookup(inputResult)
+                .toCompletableFuture();
+
+        assertEquals(result.isDone(), true);
+    }
+
+    @SmallTest
+    @Test
     public void testAllowCall() throws Exception {
         CallScreeningServiceFilter filter = new CallScreeningServiceFilter(mCall, PKG_NAME,
                 CallScreeningServiceFilter.PACKAGE_TYPE_CARRIER, mContext, mCallsManager,
diff --git a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
index da72933..6fd8334 100644
--- a/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallsManagerTest.java
@@ -1625,6 +1625,57 @@
         verify(callSpy, never()).setDisconnectCause(any(DisconnectCause.class));
     }
 
+    @Test
+    public void testIsInSelfManagedCallOnlyManaged() {
+        Call managedCall = createCall(SIM_1_HANDLE, CallState.ACTIVE);
+        managedCall.setIsSelfManaged(false);
+        mCallsManager.addCall(managedCall);
+
+        // Certainly nothing from the self managed handle.
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                SELF_MANAGED_HANDLE.getComponentName().getPackageName(),
+                SELF_MANAGED_HANDLE.getUserHandle()));
+        // And nothing in a random other package.
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                "com.foo",
+                SELF_MANAGED_HANDLE.getUserHandle()));
+        // And this method is only checking self managed not managed.
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                SIM_1_HANDLE.getComponentName().getPackageName(),
+                SELF_MANAGED_HANDLE.getUserHandle()));
+    }
+
+    @Test
+    public void testIsInSelfManagedCallOnlySelfManaged() {
+        Call selfManagedCall = createCall(SELF_MANAGED_HANDLE, CallState.ACTIVE);
+        selfManagedCall.setIsSelfManaged(true);
+        mCallsManager.addCall(selfManagedCall);
+
+        assertTrue(mCallsManager.isInSelfManagedCall(
+                SELF_MANAGED_HANDLE.getComponentName().getPackageName(),
+                SELF_MANAGED_HANDLE.getUserHandle()));
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                "com.foo",
+                SELF_MANAGED_HANDLE.getUserHandle()));
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                SIM_1_HANDLE.getComponentName().getPackageName(),
+                SELF_MANAGED_HANDLE.getUserHandle()));
+
+        Call managedCall = createCall(SIM_1_HANDLE, CallState.ACTIVE);
+        managedCall.setIsSelfManaged(false);
+        mCallsManager.addCall(managedCall);
+
+        // Still not including managed
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                SIM_1_HANDLE.getComponentName().getPackageName(),
+                SELF_MANAGED_HANDLE.getUserHandle()));
+
+        // Also shouldn't be something in another user's version of the same package.
+        assertFalse(mCallsManager.isInSelfManagedCall(
+                SELF_MANAGED_HANDLE.getComponentName().getPackageName(),
+                new UserHandle(90210)));
+    }
+
     private Call addSpyCall() {
         return addSpyCall(SIM_2_HANDLE, CallState.ACTIVE);
     }
diff --git a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
index ebb336e..639ac22 100644
--- a/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ComponentContextFixture.java
@@ -51,24 +51,22 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.hardware.SensorPrivacyManager;
-import android.location.Country;
 import android.location.CountryDetector;
+import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IInterface;
 import android.os.PersistableBundle;
-import android.os.PowerWhitelistManager;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.Vibrator;
 import android.os.VibratorManager;
 import android.permission.PermissionCheckerManager;
-import android.telecom.CallAudioState;
 import android.telecom.ConnectionService;
 import android.telecom.Log;
 import android.telecom.InCallService;
-import android.telecom.PhoneAccount;
 import android.telecom.TelecomManager;
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
@@ -123,6 +121,11 @@
         }
 
         @Override
+        public Context createContextAsUser(UserHandle userHandle, int flags) {
+            return this;
+        }
+
+        @Override
         public String getPackageName() {
             return "com.android.server.telecom.tests";
         }
@@ -218,6 +221,8 @@
                     return mTelephonyRegistryManager;
                 case Context.UI_MODE_SERVICE:
                     return mUiModeManager;
+                case Context.VIBRATOR_SERVICE:
+                    return mVibrator;
                 case Context.VIBRATOR_MANAGER_SERVICE:
                     return mVibratorManager;
                 case Context.PERMISSION_CHECKER_SERVICE:
@@ -247,6 +252,8 @@
                 return Context.TELEPHONY_REGISTRY_SERVICE;
             } else if (svcClass == UiModeManager.class) {
                 return Context.UI_MODE_SERVICE;
+            } else if (svcClass == Vibrator.class) {
+                return Context.VIBRATOR_SERVICE;
             } else if (svcClass == VibratorManager.class) {
                 return Context.VIBRATOR_MANAGER_SERVICE;
             } else if (svcClass == PermissionCheckerManager.class) {
@@ -327,12 +334,23 @@
         }
 
         @Override
+        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) {
+            return null;
+        }
+
+        @Override
         public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
                 String broadcastPermission, Handler scheduler) {
             return null;
         }
 
         @Override
+        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+                String broadcastPermission, Handler scheduler, int flags) {
+            return null;
+        }
+
+        @Override
         public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle handle,
                 IntentFilter filter, String broadcastPermission, Handler scheduler) {
             return null;
@@ -419,6 +437,7 @@
         private int mAudioStreamValue = 1;
         private int mMode = AudioManager.MODE_NORMAL;
         private int mRingerMode = AudioManager.RINGER_MODE_NORMAL;
+        private AudioDeviceInfo mCommunicationDevice;
 
         public FakeAudioManager(Context context) {
             super(context);
@@ -473,6 +492,22 @@
         public int getStreamVolume(int streamValueUnused) {
             return mAudioStreamValue;
         }
+
+        @Override
+        public void clearCommunicationDevice() {
+            mCommunicationDevice = null;
+        }
+
+        @Override
+        public AudioDeviceInfo getCommunicationDevice() {
+            return mCommunicationDevice;
+        }
+
+        @Override
+        public boolean setCommunicationDevice(AudioDeviceInfo device) {
+            mCommunicationDevice = device;
+            return true;
+        }
     }
 
     private static final String PACKAGE_NAME = "com.android.server.telecom.tests";
@@ -518,7 +553,7 @@
     private final NotificationManager mNotificationManager = mock(NotificationManager.class);
     private final UserManager mUserManager = mock(UserManager.class);
     private final StatusBarManager mStatusBarManager = mock(StatusBarManager.class);
-    private final SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
+    private SubscriptionManager mSubscriptionManager = mock(SubscriptionManager.class);
     private final CarrierConfigManager mCarrierConfigManager = mock(CarrierConfigManager.class);
     private final CountryDetector mCountryDetector = mock(CountryDetector.class);
     private final Map<String, IContentProvider> mIContentProviderByUri = new HashMap<>();
@@ -527,6 +562,7 @@
     private final RoleManager mRoleManager = mock(RoleManager.class);
     private final TelephonyRegistryManager mTelephonyRegistryManager =
             mock(TelephonyRegistryManager.class);
+    private final Vibrator mVibrator = mock(Vibrator.class);
     private final VibratorManager mVibratorManager = mock(VibratorManager.class);
     private final UiModeManager mUiModeManager = mock(UiModeManager.class);
     private final PermissionCheckerManager mPermissionCheckerManager =
@@ -598,7 +634,10 @@
         }
 
         when(mPermissionInfo.isAppOp()).thenReturn(true);
+        when(mVibrator.getDefaultVibrationIntensity(anyInt()))
+                .thenReturn(Vibrator.VIBRATION_INTENSITY_MEDIUM);
         when(mVibratorManager.getVibratorIds()).thenReturn(new int[0]);
+        when(mVibratorManager.getDefaultVibrator()).thenReturn(mVibrator);
 
         // Used in CreateConnectionProcessor to rank emergency numbers by viability.
         // For the test, make them all equal to INVALID so that the preferred PhoneAccount will be
@@ -630,6 +669,7 @@
         // Make sure we do not hide PII during testing.
         Log.setTag("TelecomTEST");
         Log.setIsExtendedLoggingEnabled(true);
+        Log.setUnitTestingEnabled(true);
         Log.VERBOSE = true;
     }
 
@@ -713,10 +753,18 @@
         mTelecomManager = telecomManager;
     }
 
+    public void setSubscriptionManager(SubscriptionManager subscriptionManager) {
+        mSubscriptionManager = subscriptionManager;
+    }
+
     public TelephonyManager getTelephonyManager() {
         return mTelephonyManager;
     }
 
+    public CarrierConfigManager getCarrierConfigManager() {
+        return mCarrierConfigManager;
+    }
+
     public NotificationManager getNotificationManager() {
         return mNotificationManager;
     }
diff --git a/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java b/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
index 845a838..cb376af 100644
--- a/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
+++ b/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
@@ -21,6 +21,7 @@
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.UserHandle;
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
@@ -41,6 +42,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
@@ -49,7 +51,10 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Random;
+import java.util.UUID;
 
+import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.anyList;
 import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Matchers.any;
@@ -546,6 +551,26 @@
         verify(mMockCreateConnectionResponse).handleCreateConnectionSuccess(mockCallIdMapper, null);
     }
 
+    /**
+     * Ensures that a self-managed phone account won't be considered when attempting to place an
+     * emergency call.
+     */
+    @SmallTest
+    @Test
+    public void testDontAttemptSelfManaged() {
+        when(mMockCall.isEmergencyCall()).thenReturn(true);
+        when(mMockCall.isTestEmergencyCall()).thenReturn(false);
+        when(mMockCall.getHandle()).thenReturn(Uri.parse(""));
+
+        PhoneAccount selfManagedAcct = makePhoneAccount("sm-acct",
+                PhoneAccount.CAPABILITY_SELF_MANAGED
+                        | PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS);
+        phoneAccounts.add(selfManagedAcct);
+
+        mTestCreateConnectionProcessor.process();
+        verify(mMockCall, never()).setTargetPhoneAccount(any(PhoneAccountHandle.class));
+    }
+
     @SmallTest
     @Test
     public void testEmergencyCallSimFailToConnectionManager() throws Exception {
@@ -590,6 +615,71 @@
         verify(service).createConnection(eq(mMockCall), any(CreateConnectionResponse.class));
     }
 
+    /**
+     * Tests to verify that the
+     * {@link CreateConnectionProcessor#sortSimPhoneAccountsForEmergency(List, PhoneAccount)} can
+     * successfully sort without running into sort issues related to the hashcodes of the
+     * PhoneAccounts.
+     */
+    @Test
+    public void testSortIntegrity() {
+        // Note: 5L was chosen as a random seed on purpose since in combination with a count of
+        // 500 accounts it would result in a crash in the sort algorithm.
+        ArrayList<PhoneAccount> accounts = generateRandomPhoneAccounts(5L, 500);
+        try {
+            mTestCreateConnectionProcessor.sortSimPhoneAccountsForEmergency(accounts,
+                    null);
+        } catch (Exception e) {
+            fail("Failed to sort phone accounts");
+        }
+    }
+
+    /**
+     * Generates random phone accounts.
+     * @param seed random seed to use for random UUIDs; passed in for determinism.
+     * @param count How many phone accounts to use.
+     * @return Random phone accounts.
+     */
+    private ArrayList<PhoneAccount> generateRandomPhoneAccounts(long seed, int count) {
+        Random random = new Random(seed);
+        ArrayList<PhoneAccount> accounts = new ArrayList<>();
+        for (int ix = 0 ; ix < count; ix++) {
+            ArrayList<String> supportedSchemes = new ArrayList<>();
+            supportedSchemes.add("tel");
+            supportedSchemes.add("sip");
+            supportedSchemes.add("custom");
+
+            PhoneAccountHandle handle = new PhoneAccountHandle(
+                    ComponentName.unflattenFromString(
+                            "com.android.server.telecom.testapps/"
+                                    + "com.android.server.telecom.testapps"
+                                    + ".SelfManagedConnectionService"),
+                    getRandomUuid(random).toString(), new UserHandle(0));
+            PhoneAccount acct = new PhoneAccount.Builder(handle, "TelecommTests")
+                    .setAddress(Uri.fromParts("tel", "555-1212", null))
+                    .setCapabilities(3080)
+                    .setHighlightColor(0)
+                    .setShortDescription("test_" + ix)
+                    .setSupportedUriSchemes(supportedSchemes)
+                    .setIsEnabled(true)
+                    .setSupportedAudioRoutes(15)
+                    .build();
+            accounts.add(acct);
+        }
+        return accounts;
+    }
+
+    /**
+     * Returns a random UUID based on the passed in Random generator.
+     * @param random Random generator.
+     * @return The UUID.
+     */
+    private UUID getRandomUuid(Random random) {
+        byte[] array = new byte[16];
+        random.nextBytes(array);
+        return UUID.nameUUIDFromBytes(array);
+    }
+
     private PhoneAccount makeEmergencyTestPhoneAccount(String id, int capabilities) {
         final PhoneAccount emergencyPhoneAccount = makeQuickAccount(id, capabilities |
                 PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS);
diff --git a/tests/src/com/android/server/telecom/tests/HeadsetMediaButtonTest.java b/tests/src/com/android/server/telecom/tests/HeadsetMediaButtonTest.java
new file mode 100644
index 0000000..6d15e60
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/HeadsetMediaButtonTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.tests;
+
+import com.android.server.telecom.Call;
+import com.android.server.telecom.CallsManager;
+import com.android.server.telecom.HeadsetMediaButton;
+import com.android.server.telecom.TelecomSystem;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(JUnit4.class)
+public class HeadsetMediaButtonTest extends TelecomTestCase {
+    private static final int TEST_TIMEOUT_MILLIS = 1000;
+
+    private HeadsetMediaButton mHeadsetMediaButton;
+
+    @Mock private CallsManager mMockCallsManager;
+    @Mock private HeadsetMediaButton.MediaSessionAdapter mMediaSessionAdapter;
+    private TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() {};
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        mHeadsetMediaButton = new HeadsetMediaButton(mContext, mMockCallsManager, mLock,
+                mMediaSessionAdapter);
+    }
+
+    @Override
+    @After
+    public void tearDown() throws Exception {
+        mHeadsetMediaButton = null;
+        super.tearDown();
+    }
+
+    /**
+     * Nominal case; just add a call and remove it.
+     */
+    @Test
+    public void testAddCall() {
+        Call regularCall = getRegularCall();
+
+        when(mMockCallsManager.hasAnyCalls()).thenReturn(true);
+        mHeadsetMediaButton.onCallAdded(regularCall);
+        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
+        verify(mMediaSessionAdapter).setActive(eq(true));
+        // ... and thus we see how the original code isn't amenable to tests.
+        when(mMediaSessionAdapter.isActive()).thenReturn(true);
+
+        when(mMockCallsManager.hasAnyCalls()).thenReturn(false);
+        mHeadsetMediaButton.onCallRemoved(regularCall);
+        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
+        verify(mMediaSessionAdapter).setActive(eq(false));
+    }
+
+    /**
+     * Test a case where a regular call becomes an external call, and back again.
+     */
+    @Test
+    public void testRegularCallThatBecomesExternal() {
+        Call regularCall = getRegularCall();
+
+        // Start with a regular old call.
+        when(mMockCallsManager.hasAnyCalls()).thenReturn(true);
+        mHeadsetMediaButton.onCallAdded(regularCall);
+        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
+        verify(mMediaSessionAdapter).setActive(eq(true));
+        when(mMediaSessionAdapter.isActive()).thenReturn(true);
+
+        // Change so it is external.
+        when(regularCall.isExternalCall()).thenReturn(true);
+        when(mMockCallsManager.hasAnyCalls()).thenReturn(false);
+        mHeadsetMediaButton.onExternalCallChanged(regularCall, true);
+        // Expect to set session inactive.
+        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
+        verify(mMediaSessionAdapter).setActive(eq(false));
+
+        // For good measure lets make it non-external again.
+        when(regularCall.isExternalCall()).thenReturn(false);
+        when(mMockCallsManager.hasAnyCalls()).thenReturn(true);
+        mHeadsetMediaButton.onExternalCallChanged(regularCall, false);
+        // Expect to set session active.
+        waitForHandlerAction(mHeadsetMediaButton.getHandler(), TEST_TIMEOUT_MILLIS);
+        verify(mMediaSessionAdapter).setActive(eq(true));
+    }
+
+    /**
+     * @return a mock call instance of a regular non-external call.
+     */
+    private Call getRegularCall() {
+        Call regularCall = Mockito.mock(Call.class);
+        when(regularCall.isExternalCall()).thenReturn(false);
+        return regularCall;
+    }
+}
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index 6cc19ad..ddacf43 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -64,6 +64,8 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
+import android.compat.testing.PlatformCompatChangeRule;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -86,7 +88,6 @@
 import com.android.internal.telecom.IInCallAdapter;
 import com.android.internal.telecom.IInCallService;
 import com.android.server.telecom.Analytics;
-import com.android.server.telecom.BluetoothHeadsetProxy;
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallsManager;
 import com.android.server.telecom.CarModeTracker;
@@ -103,7 +104,9 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 import org.mockito.ArgumentCaptor;
@@ -121,11 +124,12 @@
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 
+import libcore.junit.util.compat.CoreCompatChangeRule;
+
 @RunWith(JUnit4.class)
 public class InCallControllerTests extends TelecomTestCase {
     @Mock CallsManager mMockCallsManager;
     @Mock PhoneAccountRegistrar mMockPhoneAccountRegistrar;
-    @Mock BluetoothHeadsetProxy mMockBluetoothHeadset;
     @Mock SystemStateHelper mMockSystemStateHelper;
     @Mock PackageManager mMockPackageManager;
     @Mock PermissionCheckerManager mMockPermissionCheckerManager;
@@ -141,6 +145,9 @@
     @Mock NotificationManager mNotificationManager;
     @Mock PermissionInfo mMockPermissionInfo;
 
+    @Rule
+    public TestRule compatChangeRule = new PlatformCompatChangeRule();
+
     private static final int CURRENT_USER_ID = 900973;
     private static final String DEF_PKG = "defpkg";
     private static final String DEF_CLASS = "defcls";
@@ -911,7 +918,7 @@
 
    /**
      * Ensures that the {@link InCallController} will bind to an {@link InCallService} which
-     * supports third party app
+     * supports third party app.
      */
     @MediumTest
     @Test
@@ -926,6 +933,11 @@
                     true /* system */, false /* external calls */, false /* self mgd in default */,
                     false /* self mgd in car*/);
 
+            ApplicationInfo applicationInfo = new ApplicationInfo();
+            applicationInfo.targetSdkVersion = Build.VERSION_CODES.TIRAMISU;
+            // set up mock call for ICSC#sendCrashedInCallServiceNotification(String)
+            when(mMockContext.getApplicationInfo()).thenReturn(applicationInfo);
+
             // Enable Third Party Companion App
             ExtendedMockito.doReturn(PermissionChecker.PERMISSION_GRANTED).when(() ->
                     PermissionChecker.checkPermissionForDataDeliveryFromDataSource(
@@ -952,6 +964,7 @@
 
             // Should have next bound to the third party app op non ui app.
             verifyBinding(bindIntentCaptor, 1, APPOP_NONUI_PKG, APPOP_NONUI_CLASS);
+
         } finally {
             mockitoSession.finishMocking();
         }
@@ -969,6 +982,13 @@
                 true /* system */, false /* external calls */, false /* self mgd in default */,
                 false /* self mgd in car*/, true /* self managed in nonui */);
 
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.targetSdkVersion = Build.VERSION_CODES.TIRAMISU;
+        when(mMockContext.getApplicationInfo()).thenReturn(applicationInfo);
+        // Package doesn't have metadata of TelecomManager.METADATA_IN_CALL_SERVICE_UI should
+        // not be the default dialer. This is to mock the default dialer is null in this case.
+        when(mDefaultDialerCache.getDefaultDialerApplication(CURRENT_USER_ID)).thenReturn(null);
+
         // we should bind to only the non ui app.
         mInCallController.bindToServices(mMockCall);
 
@@ -986,6 +1006,10 @@
 
         // Should have bound to the third party non ui app.
         verifyBinding(bindIntentCaptor, 0, NONUI_PKG, NONUI_CLASS);
+
+        // Verify notification is not sent by NotificationManager
+        verify(mNotificationManager, times(0)).notify(eq(InCallController.NOTIFICATION_TAG),
+                eq(InCallController.IN_CALL_SERVICE_NOTIFICATION_ID), any());
     }
 
     @MediumTest
diff --git a/tests/src/com/android/server/telecom/tests/InCallTonePlayerTest.java b/tests/src/com/android/server/telecom/tests/InCallTonePlayerTest.java
index cb0497a..eadda0d 100644
--- a/tests/src/com/android/server/telecom/tests/InCallTonePlayerTest.java
+++ b/tests/src/com/android/server/telecom/tests/InCallTonePlayerTest.java
@@ -19,23 +19,32 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.media.AudioManager;
 import android.media.MediaPlayer;
 import android.media.ToneGenerator;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import androidx.test.filters.FlakyTest;
-
 import com.android.server.telecom.CallAudioManager;
 import com.android.server.telecom.CallAudioRoutePeripheralAdapter;
+import com.android.server.telecom.CallAudioRouteStateMachine;
+import com.android.server.telecom.DockManager;
 import com.android.server.telecom.InCallTonePlayer;
 import com.android.server.telecom.TelecomSystem;
+import com.android.server.telecom.Timeouts;
+import com.android.server.telecom.WiredHeadsetManager;
+import com.android.server.telecom.bluetooth.BluetoothDeviceManager;
+import com.android.server.telecom.bluetooth.BluetoothRouteManager;
 
 import org.junit.After;
 import org.junit.Before;
@@ -47,19 +56,21 @@
 @RunWith(JUnit4.class)
 public class InCallTonePlayerTest extends TelecomTestCase {
 
+    private static final long TEST_TIMEOUT = 5000L;
     private InCallTonePlayer.Factory mFactory;
-
-    @Mock
     private CallAudioRoutePeripheralAdapter mCallAudioRoutePeripheralAdapter;
 
-    @Mock
-    private TelecomSystem.SyncRoot mLock;
-
-    @Mock
-    private ToneGenerator mToneGenerator;
-
-    @Mock
-    private InCallTonePlayer.ToneGeneratorFactory mToneGeneratorFactory;
+    @Mock private BluetoothRouteManager mBluetoothRouteManager;
+    @Mock private CallAudioRouteStateMachine mCallAudioRouteStateMachine;
+    @Mock private Timeouts.Adapter mTimeoutsAdapter;
+    @Mock private BluetoothDeviceManager mBluetoothDeviceManager;
+    @Mock private TelecomSystem.SyncRoot mLock;
+    @Mock private ToneGenerator mToneGenerator;
+    @Mock private InCallTonePlayer.ToneGeneratorFactory mToneGeneratorFactory;
+    @Mock private WiredHeadsetManager mWiredHeadsetManager;
+    @Mock private DockManager mDockManager;
+    @Mock private BluetoothDevice mDevice;
+    @Mock private BluetoothAdapter mBluetoothAdapter;
 
     private InCallTonePlayer.MediaPlayerAdapter mMediaPlayerAdapter =
             new InCallTonePlayer.MediaPlayerAdapter() {
@@ -87,7 +98,7 @@
 
         @Override
         public int getDuration() {
-            return 0;
+            return 1000;
         }
     };
 
@@ -109,7 +120,11 @@
 
         when(mToneGeneratorFactory.get(anyInt(), anyInt())).thenReturn(mToneGenerator);
         when(mMediaPlayerFactory.get(anyInt(), any())).thenReturn(mMediaPlayerAdapter);
+        doNothing().when(mCallAudioManager).setIsTonePlaying(anyBoolean());
 
+        mCallAudioRoutePeripheralAdapter = new CallAudioRoutePeripheralAdapter(
+                mCallAudioRouteStateMachine, mBluetoothRouteManager, mWiredHeadsetManager,
+                mDockManager);
         mFactory = new InCallTonePlayer.Factory(mCallAudioRoutePeripheralAdapter, mLock,
                 mToneGeneratorFactory, mMediaPlayerFactory, mAudioManagerAdapter);
         mFactory.setCallAudioManager(mCallAudioManager);
@@ -134,7 +149,43 @@
         verify(mMediaPlayerFactory, never()).get(anyInt(), any());
     }
 
-    @FlakyTest
+    @SmallTest
+    @Test
+    public void testInterruptMediaTone() {
+        when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
+        assertTrue(mInCallTonePlayer.startTone());
+        // Verify we did play a tone.
+        verify(mMediaPlayerFactory, timeout(TEST_TIMEOUT)).get(anyInt(), any());
+        verify(mCallAudioManager).setIsTonePlaying(eq(true));
+
+        mInCallTonePlayer.stopTone();
+        // Timeouts due to threads!
+        verify(mCallAudioManager, timeout(TEST_TIMEOUT)).setIsTonePlaying(eq(false));
+
+        // Correctness check: ensure we can't start the tone again.
+        assertFalse(mInCallTonePlayer.startTone());
+    }
+
+    @SmallTest
+    @Test
+    public void testInterruptToneGenerator() {
+        mInCallTonePlayer = mFactory.createPlayer(InCallTonePlayer.TONE_RING_BACK);
+        when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
+        assertTrue(mInCallTonePlayer.startTone());
+        verify(mToneGenerator, timeout(TEST_TIMEOUT)).startTone(anyInt());
+        verify(mCallAudioManager).setIsTonePlaying(eq(true));
+
+        mInCallTonePlayer.stopTone();
+        // Timeouts due to threads!
+        verify(mCallAudioManager, timeout(TEST_TIMEOUT)).setIsTonePlaying(eq(false));
+        // Ideally it would be nice to verify this, however release is a native method so appears to
+        // cause flakiness when testing on Cuttlefish.
+        // verify(mToneGenerator, timeout(TEST_TIMEOUT)).release();
+
+        // Correctness check: ensure we can't start the tone again.
+        assertFalse(mInCallTonePlayer.startTone());
+    }
+
     @SmallTest
     @Test
     public void testEndCallToneWhenNotSilenced() {
@@ -142,7 +193,79 @@
         assertTrue(mInCallTonePlayer.startTone());
 
         // Verify we did play a tone.
-        verify(mMediaPlayerFactory, timeout(5000)).get(anyInt(), any());
+        verify(mMediaPlayerFactory, timeout(TEST_TIMEOUT)).get(anyInt(), any());
+        verify(mCallAudioManager, timeout(TEST_TIMEOUT)).setIsTonePlaying(eq(true));
+    }
+
+    @SmallTest
+    @Test
+    public void testRingbackToneAudioStreamHeadset() {
+        when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
+        mBluetoothDeviceManager.setBluetoothRouteManager(mBluetoothRouteManager);
+        when(mBluetoothRouteManager.getBluetoothAudioConnectedDevice()).thenReturn(mDevice);
+        when(mBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(true);
+
+        when(mBluetoothRouteManager.isCachedLeAudioDevice(mDevice)).thenReturn(false);
+        when(mBluetoothRouteManager.isCachedHearingAidDevice(mDevice)).thenReturn(false);
+
+        mInCallTonePlayer = mFactory.createPlayer(InCallTonePlayer.TONE_RING_BACK);
+        assertTrue(mInCallTonePlayer.startTone());
+        verify(mToneGeneratorFactory, timeout(TEST_TIMEOUT))
+                .get(eq(AudioManager.STREAM_BLUETOOTH_SCO), anyInt());
+        verify(mCallAudioManager).setIsTonePlaying(eq(true));
+    }
+
+    @SmallTest
+    @Test
+    public void testCallWaitingToneAudioStreamHeadset() {
+        when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
+        mBluetoothDeviceManager.setBluetoothRouteManager(mBluetoothRouteManager);
+        when(mBluetoothRouteManager.getBluetoothAudioConnectedDevice()).thenReturn(mDevice);
+        when(mBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(true);
+
+        when(mBluetoothRouteManager.isCachedLeAudioDevice(mDevice)).thenReturn(false);
+        when(mBluetoothRouteManager.isCachedHearingAidDevice(mDevice)).thenReturn(false);
+
+        mInCallTonePlayer = mFactory.createPlayer(InCallTonePlayer.TONE_CALL_WAITING);
+        assertTrue(mInCallTonePlayer.startTone());
+        verify(mToneGeneratorFactory, timeout(TEST_TIMEOUT))
+                .get(eq(AudioManager.STREAM_BLUETOOTH_SCO), anyInt());
+        verify(mCallAudioManager).setIsTonePlaying(eq(true));
+    }
+
+    @SmallTest
+    @Test
+    public void testRingbackToneAudioStreamHearingAid() {
+        when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
+        mBluetoothDeviceManager.setBluetoothRouteManager(mBluetoothRouteManager);
+        when(mBluetoothRouteManager.getBluetoothAudioConnectedDevice()).thenReturn(mDevice);
+        when(mBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(true);
+
+        when(mBluetoothRouteManager.isCachedLeAudioDevice(mDevice)).thenReturn(false);
+        when(mBluetoothRouteManager.isCachedHearingAidDevice(mDevice)).thenReturn(true);
+
+        mInCallTonePlayer = mFactory.createPlayer(InCallTonePlayer.TONE_RING_BACK);
+        assertTrue(mInCallTonePlayer.startTone());
+        verify(mToneGeneratorFactory, timeout(TEST_TIMEOUT))
+                .get(eq(AudioManager.STREAM_VOICE_CALL), anyInt());
+        verify(mCallAudioManager).setIsTonePlaying(eq(true));
+    }
+
+    @SmallTest
+    @Test
+    public void testCallWaitingToneAudioStreamHearingAid() {
+        when(mAudioManagerAdapter.isVolumeOverZero()).thenReturn(true);
+        mBluetoothDeviceManager.setBluetoothRouteManager(mBluetoothRouteManager);
+        when(mBluetoothRouteManager.getBluetoothAudioConnectedDevice()).thenReturn(mDevice);
+        when(mBluetoothRouteManager.isBluetoothAudioConnectedOrPending()).thenReturn(true);
+
+        when(mBluetoothRouteManager.isCachedLeAudioDevice(mDevice)).thenReturn(false);
+        when(mBluetoothRouteManager.isCachedHearingAidDevice(mDevice)).thenReturn(true);
+
+        mInCallTonePlayer = mFactory.createPlayer(InCallTonePlayer.TONE_CALL_WAITING);
+        assertTrue(mInCallTonePlayer.startTone());
+        verify(mToneGeneratorFactory, timeout(TEST_TIMEOUT))
+                .get(eq(AudioManager.STREAM_VOICE_CALL), anyInt());
         verify(mCallAudioManager).setIsTonePlaying(eq(true));
     }
 }
diff --git a/tests/src/com/android/server/telecom/tests/InCallWakeLockControllerTest.java b/tests/src/com/android/server/telecom/tests/InCallWakeLockControllerTest.java
index fd7505b..f935908 100644
--- a/tests/src/com/android/server/telecom/tests/InCallWakeLockControllerTest.java
+++ b/tests/src/com/android/server/telecom/tests/InCallWakeLockControllerTest.java
@@ -17,6 +17,7 @@
 package com.android.server.telecom.tests;
 
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.never;
@@ -128,4 +129,34 @@
 
         verify(mWakeLockAdapter, never()).acquire();
     }
+
+    @SmallTest
+    @Test
+    public void testExternalCallStateChangeDuringRinging() throws Exception {
+        // A call is ringing on the local device directly.
+        when(mCallsManager.getRingingOrSimulatedRingingCall()).thenReturn(mCall);
+        when(mCall.isExternalCall()).thenReturn(false);
+
+        mInCallWakeLockController.onCallAdded(mCall);
+
+        verify(mWakeLockAdapter).acquire();
+
+        // The call then becomes an external call during ringing. The wake lock should be
+        // released.
+        reset(mWakeLockAdapter);
+        when(mWakeLockAdapter.isHeld()).thenReturn(true);
+        when(mCall.isExternalCall()).thenReturn(true);
+
+        mInCallWakeLockController.onExternalCallChanged(mCall, /* isExternalCall= */ true);
+
+        verify(mWakeLockAdapter).release(0);
+
+        // The call then is pulled to the device, wake up the device and acquire the wake lock.
+        reset(mWakeLockAdapter);
+        when(mCall.isExternalCall()).thenReturn(false);
+
+        mInCallWakeLockController.onExternalCallChanged(mCall, /* isExternalCall= */ true);
+
+        verify(mWakeLockAdapter).acquire();
+    }
 }
diff --git a/tests/src/com/android/server/telecom/tests/LogUtilsTest.java b/tests/src/com/android/server/telecom/tests/LogUtilsTest.java
new file mode 100644
index 0000000..637dfbc
--- /dev/null
+++ b/tests/src/com/android/server/telecom/tests/LogUtilsTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.telecom.tests;
+
+import static org.junit.Assert.assertTrue;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.telecom.LogUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class LogUtilsTest extends TelecomTestCase {
+
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    @After
+    public void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * Tests LogUtils#initLogging(Context) listeners cannot be initialized more than once by calling
+     * the init function multiple times.  If the listeners are ever re-initialized, log spewing
+     * will occur.
+     *
+     * Note, LogUtils will already be initialized at the start of the testing framework,
+     * so you cannot assume it is 0 at the start of this testing class.
+     */
+    @SmallTest
+    @Test
+    public void testLogUtilsIsNotReInitialized() {
+
+        // assert the listeners of LogUtils are never re-initialized
+        assertTrue(LogUtils.getInitializedCounter() <= 1);
+        // call initLogging an arbitrary amount of times...
+        LogUtils.initLogging(mContext);
+        LogUtils.initLogging(mContext);
+        LogUtils.initLogging(mContext);
+        // assert the listeners of LogUtils are never re-initialized
+        assertTrue(LogUtils.getInitializedCounter() <= 1);
+    }
+}
diff --git a/tests/src/com/android/server/telecom/tests/MissedInformationTest.java b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
index a8e1c5f..f2f0cd8 100644
--- a/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
+++ b/tests/src/com/android/server/telecom/tests/MissedInformationTest.java
@@ -22,28 +22,45 @@
 import static android.provider.CallLog.Calls.MISSED_REASON_NOT_MISSED;
 import static android.provider.CallLog.Calls.USER_MISSED_CALL_FILTERS_TIMEOUT;
 import static android.provider.CallLog.Calls.USER_MISSED_CALL_SCREENING_SERVICE_SILENCED;
+import static android.provider.CallLog.Calls.USER_MISSED_DND_MODE;
+import static android.provider.CallLog.Calls.USER_MISSED_LOW_RING_VOLUME;
+import static android.provider.CallLog.Calls.USER_MISSED_NEVER_RANG;
+import static android.provider.CallLog.Calls.USER_MISSED_NO_VIBRATE;
+import static android.provider.CallLog.Calls.USER_MISSED_SHORT_RING;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.NotificationManager;
 import android.content.ContentResolver;
 import android.content.ContentValues;
+import android.content.Context;
 import android.content.IContentProvider;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.media.AudioManager;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
+import android.os.UserHandle;
 import android.provider.CallLog;
 import android.telecom.DisconnectCause;
 import android.telecom.TelecomManager;
+import android.util.Log;
 
 import com.android.server.telecom.Analytics;
 import com.android.server.telecom.Call;
+import com.android.server.telecom.CallAudioManager;
 import com.android.server.telecom.CallIntentProcessor;
 import com.android.server.telecom.CallState;
 import com.android.server.telecom.CallsManager;
@@ -57,9 +74,13 @@
 import org.mockito.Mock;
 
 import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 public class MissedInformationTest extends TelecomSystemTest {
-    private static final int TEST_TIMEOUT_MILLIS = 1000;
+    private static final int TEST_TIMEOUT_MILLIS = 2000;
+    private static final long SHORT_RING_TIME = 2000;
+    private static final long LONG_RING_TIME = 6000;
     private static final String TEST_NUMBER = "650-555-1212";
     private static final String TEST_NUMBER_1 = "7";
     private static final String PACKAGE_NAME = "com.android.server.telecom.tests";
@@ -71,8 +92,13 @@
     @Mock Call mEmergencyCall;
     @Mock Analytics.CallInfo mCallInfo;
     @Mock Call mIncomingCall;
+    @Mock AudioManager mAudioManager;
+    @Mock NotificationManager mNotificationManager;
+
     private CallsManager mCallsManager;
     private CallIntentProcessor.AdapterImpl mAdapter;
+    private PackageManager mPackageManager;
+    private CountDownLatch mCountDownLatch;
 
     @Override
     @Before
@@ -80,11 +106,17 @@
         super.setUp();
         mCallsManager = mTelecomSystem.getCallsManager();
         mAdapter = new CallIntentProcessor.AdapterImpl(mCallsManager.getDefaultDialerCache());
+        mNotificationManager = spy((NotificationManager) mContext.getSystemService(
+                Context.NOTIFICATION_SERVICE));
         when(mContentResolver.getPackageName()).thenReturn(PACKAGE_NAME);
         when(mContentResolver.acquireProvider(any(String.class))).thenReturn(mContentProvider);
         when(mContentProvider.call(any(String.class), any(String.class),
                 any(String.class), any(Bundle.class))).thenReturn(new Bundle());
         doReturn(mContentResolver).when(mSpyContext).getContentResolver();
+        doReturn(mContext).when(mContext).createContextAsUser(any(UserHandle.class), anyInt());
+        mPackageManager = mContext.getPackageManager();
+        when(mPackageManager.getPackageUid(anyString(), eq(0))).thenReturn(Binder.getCallingUid());
+        mCountDownLatch  = new CountDownLatch(1);
     }
 
     @Override
@@ -192,6 +224,7 @@
                 .setShouldAllowCall(true)
                 .build();
         mCallsManager.onCallFilteringComplete(mIncomingCall, result, true);
+        assertTrue(mCountDownLatch.await(TEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
         mCallsManager.markCallAsDisconnected(mIncomingCall,
                     new DisconnectCause(DisconnectCause.MISSED));
         ContentValues values = verifyInsertionWithCapture();
@@ -212,6 +245,7 @@
                 .setCallScreeningComponentName(CALL_SCREENING_COMPONENT_NAME)
                 .build();
         mCallsManager.onCallFilteringComplete(mIncomingCall, result, false);
+        assertTrue(mCountDownLatch.await(TEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
         assertTrue(mIncomingCall.isIncoming());
         mCallsManager.markCallAsDisconnected(mIncomingCall,
                 new DisconnectCause(DisconnectCause.MISSED));
@@ -227,6 +261,132 @@
         assertTrue((missedReason & USER_MISSED_CALL_SCREENING_SERVICE_SILENCED) > 0);
     }
 
+    @Test
+    public void testShortRing() throws Exception {
+        setUpIncomingCall();
+        CallFilteringResult result = new CallFilteringResult.Builder()
+                .setShouldAllowCall(true)
+                .build();
+        mCallsManager.onCallFilteringComplete(mIncomingCall, result, false);
+        assertTrue(mCountDownLatch.await(TEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
+        when(mClockProxy.elapsedRealtime()).thenReturn(1L + SHORT_RING_TIME);
+        mCallsManager.markCallAsDisconnected(mIncomingCall,
+                new DisconnectCause(DisconnectCause.MISSED));
+        ContentValues values = verifyInsertionWithCapture();
+
+        long missedReason = values.getAsLong(CallLog.Calls.MISSED_REASON);
+        assertTrue((missedReason & USER_MISSED_SHORT_RING) > 0);
+        missedReason = ((Analytics.CallInfoImpl) mIncomingCall.getAnalytics()).missedReason;
+        assertTrue((missedReason & USER_MISSED_SHORT_RING) > 0);
+    }
+
+    @Test
+    public void testLongRing() throws Exception {
+        setUpIncomingCall();
+        CallFilteringResult result = new CallFilteringResult.Builder()
+                .setShouldAllowCall(true)
+                .build();
+        mCallsManager.onCallFilteringComplete(mIncomingCall, result, false);
+        assertTrue(mCountDownLatch.await(TEST_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
+        when(mClockProxy.elapsedRealtime()).thenReturn(1L + LONG_RING_TIME);
+        mCallsManager.markCallAsDisconnected(mIncomingCall,
+                new DisconnectCause(DisconnectCause.MISSED));
+        ContentValues values = verifyInsertionWithCapture();
+
+        long missedReason = values.getAsLong(CallLog.Calls.MISSED_REASON);
+        assertEquals(0, missedReason & USER_MISSED_SHORT_RING);
+        missedReason = ((Analytics.CallInfoImpl) mIncomingCall.getAnalytics()).missedReason;
+        assertEquals(0, missedReason & USER_MISSED_SHORT_RING);
+    }
+
+    @Test
+    public void testLowRingVolume() throws Exception {
+        CallAudioManager callAudioManager = mCallsManager.getCallAudioManager();
+        when(mSpyContext.getSystemService(AudioManager.class)).thenReturn(mAudioManager);
+        when(mAudioManager.getStreamVolume(AudioManager.STREAM_RING)).thenReturn(0);
+        setUpIncomingCall();
+        CallFilteringResult result = new CallFilteringResult.Builder()
+                .setShouldAllowCall(true)
+                .build();
+        mCallsManager.onCallFilteringComplete(mIncomingCall, result, false);
+
+        // Wait for ringer attributes build completed
+        verify(mAudioManager, timeout(TEST_TIMEOUT_MILLIS)).getStreamVolume(anyInt());
+        mCallsManager.getRinger().waitForAttributesCompletion();
+
+        mCallsManager.markCallAsDisconnected(mIncomingCall,
+                new DisconnectCause(DisconnectCause.MISSED));
+        ContentValues values = verifyInsertionWithCapture();
+
+        long missedReason = values.getAsLong(CallLog.Calls.MISSED_REASON);
+        assertTrue((missedReason & USER_MISSED_LOW_RING_VOLUME) > 0);
+        missedReason = ((Analytics.CallInfoImpl) mIncomingCall.getAnalytics()).missedReason;
+        assertTrue((missedReason & USER_MISSED_LOW_RING_VOLUME) > 0);
+    }
+
+    @Test
+    public void testNoVibrate() throws Exception {
+        when(mSpyContext.getSystemService(AudioManager.class)).thenReturn(mAudioManager);
+        when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT);
+        setUpIncomingCall();
+        CallFilteringResult result = new CallFilteringResult.Builder()
+                .setShouldAllowCall(true)
+                .build();
+        mCallsManager.onCallFilteringComplete(mIncomingCall, result, false);
+
+        // Wait for ringer attributes build completed
+        verify(mAudioManager, timeout(TEST_TIMEOUT_MILLIS)).getStreamVolume(anyInt());
+        mCallsManager.getRinger().waitForAttributesCompletion();
+
+        mCallsManager.markCallAsDisconnected(mIncomingCall,
+                new DisconnectCause(DisconnectCause.MISSED));
+        ContentValues values = verifyInsertionWithCapture();
+
+        long missedReason = values.getAsLong(CallLog.Calls.MISSED_REASON);
+        assertTrue((missedReason & USER_MISSED_NO_VIBRATE) > 0);
+        missedReason = ((Analytics.CallInfoImpl) mIncomingCall.getAnalytics()).missedReason;
+        assertTrue((missedReason & USER_MISSED_NO_VIBRATE) > 0);
+    }
+
+    @Test
+    public void testDndMode() throws Exception {
+        setUpIncomingCall();
+        doReturn(mNotificationManager).when(mSpyContext)
+                .getSystemService(Context.NOTIFICATION_SERVICE);
+        doReturn(false).when(mNotificationManager).matchesCallFilter(any(Bundle.class));
+        CallFilteringResult result = new CallFilteringResult.Builder()
+                .setShouldAllowCall(true)
+                .build();
+        mCallsManager.onCallFilteringComplete(mIncomingCall, result, false);
+
+        // Wait for ringer attributes build completed
+        verify(mNotificationManager, timeout(TEST_TIMEOUT_MILLIS))
+                .matchesCallFilter(any(Bundle.class));
+        mCallsManager.getRinger().waitForAttributesCompletion();
+
+        mCallsManager.markCallAsDisconnected(mIncomingCall,
+                new DisconnectCause(DisconnectCause.MISSED));
+        ContentValues values = verifyInsertionWithCapture();
+
+        long missedReason = values.getAsLong(CallLog.Calls.MISSED_REASON);
+        assertTrue((missedReason & USER_MISSED_DND_MODE) > 0);
+        missedReason = ((Analytics.CallInfoImpl) mIncomingCall.getAnalytics()).missedReason;
+        assertTrue((missedReason & USER_MISSED_DND_MODE) > 0);
+    }
+
+    @Test
+    public void testNeverRang() throws Exception {
+        setUpIncomingCall();
+        mCallsManager.markCallAsDisconnected(mIncomingCall,
+                new DisconnectCause(DisconnectCause.MISSED));
+        ContentValues values = verifyInsertionWithCapture();
+
+        long missedReason = values.getAsLong(CallLog.Calls.MISSED_REASON);
+        assertEquals(USER_MISSED_NEVER_RANG, missedReason);
+        missedReason = ((Analytics.CallInfoImpl) mIncomingCall.getAnalytics()).missedReason;
+        assertEquals(USER_MISSED_NEVER_RANG, missedReason);
+    }
+
     private ContentValues verifyInsertionWithCapture() {
         ArgumentCaptor<ContentValues> captor = ArgumentCaptor.forClass(ContentValues.class);
         verify(mContentResolver, timeout(TEST_TIMEOUT_MILLIS))
@@ -250,8 +410,11 @@
                 null, null, mPhoneAccountA0.getAccountHandle(),
                 Call.CALL_DIRECTION_INCOMING, false, false,
                 mClockProxy, null));
+        doReturn(1L).when(mIncomingCall).getStartRingTime();
+        doAnswer((x) -> {
+            mCountDownLatch.countDown();
+            return 1L;
+        }).when(mClockProxy).elapsedRealtime();
         mIncomingCall.initAnalytics();
-        when(mIncomingCall.getIntentExtras()).thenReturn(new Bundle());
-        when(mIncomingCall.getViaNumber()).thenReturn(TEST_NUMBER);
     }
 }
diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index a56036a..ffa08e2 100644
--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -22,18 +22,27 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.graphics.BitmapFactory;
 import android.graphics.Rect;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
+import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -41,6 +50,9 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Xml;
@@ -53,6 +65,7 @@
 import com.android.server.telecom.DefaultDialerCache;
 import com.android.server.telecom.PhoneAccountRegistrar;
 import com.android.server.telecom.PhoneAccountRegistrar.DefaultPhoneAccountHandle;
+import com.android.server.telecom.TelecomSystem;
 
 import org.junit.After;
 import org.junit.Before;
@@ -72,6 +85,7 @@
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -82,7 +96,12 @@
     private static final int MAX_VERSION = Integer.MAX_VALUE;
     private static final String FILE_NAME = "phone-account-registrar-test-1223.xml";
     private static final String TEST_LABEL = "right";
+    private final String PACKAGE_1 = "PACKAGE_1";
+    private final String PACKAGE_2 = "PACKAGE_2";
+    private final String COMPONENT_NAME = "com.android.server.telecom.tests.MockConnectionService";
+    private final TelecomSystem.SyncRoot mLock = new TelecomSystem.SyncRoot() { };
     private PhoneAccountRegistrar mRegistrar;
+    @Mock private SubscriptionManager mSubscriptionManager;
     @Mock private TelecomManager mTelecomManager;
     @Mock private DefaultDialerCache mDefaultDialerCache;
     @Mock private AppLabelProxy mAppLabelProxy;
@@ -93,6 +112,7 @@
         super.setUp();
         MockitoAnnotations.initMocks(this);
         mComponentContextFixture.setTelecomManager(mTelecomManager);
+        mComponentContextFixture.setSubscriptionManager(mSubscriptionManager);
         new File(
                 mComponentContextFixture.getTestDouble().getApplicationContext().getFilesDir(),
                 FILE_NAME)
@@ -103,7 +123,7 @@
                 .thenReturn(TEST_LABEL);
         mRegistrar = new PhoneAccountRegistrar(
                 mComponentContextFixture.getTestDouble().getApplicationContext(),
-                FILE_NAME, mDefaultDialerCache, mAppLabelProxy);
+                mLock, FILE_NAME, mDefaultDialerCache, mAppLabelProxy);
     }
 
     @Override
@@ -1015,6 +1035,225 @@
         assertFalse(PhoneAccountHandle.areFromSamePackage(null, d));
     }
 
+    /**
+     * Tests {@link PhoneAccountRegistrar#cleanupOrphanedPhoneAccounts } cleans up / deletes an
+     * orphan account.
+     */
+    @Test
+    public void testCleanUpOrphanAccounts() throws Exception {
+        // GIVEN
+        mComponentContextFixture.addConnectionService(makeQuickConnectionServiceComponentName(),
+                Mockito.mock(IConnectionService.class));
+
+        List<UserHandle> users = Arrays.asList(new UserHandle(0),
+                new UserHandle(1000));
+
+        PhoneAccount pa1 = new PhoneAccount.Builder(
+                new PhoneAccountHandle(new ComponentName(PACKAGE_1, COMPONENT_NAME), "1234",
+                        users.get(0)), "l1").build();
+        PhoneAccount pa2 = new PhoneAccount.Builder(
+                new PhoneAccountHandle(new ComponentName(PACKAGE_2, COMPONENT_NAME), "5678",
+                        users.get(1)), "l2").build();
+
+
+        registerAndEnableAccount(pa1);
+        registerAndEnableAccount(pa2);
+
+        assertEquals(1, mRegistrar.getAllPhoneAccounts(users.get(0)).size());
+        assertEquals(1, mRegistrar.getAllPhoneAccounts(users.get(1)).size());
+
+
+        // WHEN
+        when(mContext.getPackageManager().getPackageInfo(PACKAGE_1, 0))
+                .thenReturn(new PackageInfo());
+
+        when(mContext.getPackageManager().getPackageInfo(PACKAGE_2, 0))
+                .thenThrow(new PackageManager.NameNotFoundException());
+
+        when(UserManager.get(mContext).getSerialNumberForUser(users.get(0)))
+                .thenReturn(0L);
+
+        when(UserManager.get(mContext).getSerialNumberForUser(users.get(1)))
+                .thenReturn(-1L);
+
+        // THEN
+        int deletedAccounts = mRegistrar.cleanupOrphanedPhoneAccounts();
+        assertEquals(1, deletedAccounts);
+    }
+
+    @Test
+    public void testGetSimPhoneAccountsFromSimCallManager() throws Exception {
+        // Register the SIM PhoneAccounts
+        mComponentContextFixture.addConnectionService(
+                makeQuickConnectionServiceComponentName(), Mockito.mock(IConnectionService.class));
+        PhoneAccount sim1Account = makeQuickSimAccount(1);
+        PhoneAccountHandle sim1Handle = sim1Account.getAccountHandle();
+        registerAndEnableAccount(sim1Account);
+        PhoneAccount sim2Account = makeQuickSimAccount(2);
+        PhoneAccountHandle sim2Handle = sim2Account.getAccountHandle();
+        registerAndEnableAccount(sim2Account);
+
+        assertEquals(
+            List.of(sim1Handle, sim2Handle), mRegistrar.getSimPhoneAccountsOfCurrentUser());
+
+        // Set up the SIM call manager app + carrier configs
+        ComponentName simCallManagerComponent =
+                new ComponentName("com.carrier.app", "CarrierConnectionService");
+        PhoneAccountHandle simCallManagerHandle =
+                makeQuickAccountHandle(simCallManagerComponent, "sim-call-manager");
+        setSimCallManagerCarrierConfig(
+                1, new ComponentName("com.other.carrier", "OtherConnectionService"));
+        setSimCallManagerCarrierConfig(2, simCallManagerComponent);
+
+        // Since SIM 1 names another app, so we only get the handle for SIM 2
+        assertEquals(
+                List.of(sim2Handle),
+                mRegistrar.getSimPhoneAccountsFromSimCallManager(simCallManagerHandle));
+        // We do exact component matching, not just package name matching
+        assertEquals(
+                List.of(),
+                mRegistrar.getSimPhoneAccountsFromSimCallManager(
+                        makeQuickAccountHandle(
+                                new ComponentName("com.carrier.app", "SomeOtherUnrelatedService"),
+                                "same-pkg-but-diff-svc")));
+
+        // Results are identical after we register the PhoneAccount
+        mComponentContextFixture.addConnectionService(
+                simCallManagerComponent, Mockito.mock(IConnectionService.class));
+        PhoneAccount simCallManagerAccount =
+                new PhoneAccount.Builder(simCallManagerHandle, "SIM call manager")
+                        .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
+                        .build();
+        mRegistrar.registerPhoneAccount(simCallManagerAccount);
+        assertEquals(
+                List.of(sim2Handle),
+                mRegistrar.getSimPhoneAccountsFromSimCallManager(simCallManagerHandle));
+    }
+
+    @Test
+    public void testMaybeNotifyTelephonyForVoiceServiceState() throws Exception {
+        // Register the SIM PhoneAccounts
+        mComponentContextFixture.addConnectionService(
+                makeQuickConnectionServiceComponentName(), Mockito.mock(IConnectionService.class));
+        PhoneAccount sim1Account = makeQuickSimAccount(1);
+        registerAndEnableAccount(sim1Account);
+        PhoneAccount sim2Account = makeQuickSimAccount(2);
+        registerAndEnableAccount(sim2Account);
+        // Telephony is notified by default when new SIM accounts are registered
+        verify(mComponentContextFixture.getTelephonyManager(), times(2))
+                .setVoiceServiceStateOverride(false);
+        clearInvocations(mComponentContextFixture.getTelephonyManager());
+
+        // Set up the SIM call manager app + carrier configs
+        ComponentName simCallManagerComponent =
+                new ComponentName("com.carrier.app", "CarrierConnectionService");
+        PhoneAccountHandle simCallManagerHandle =
+                makeQuickAccountHandle(simCallManagerComponent, "sim-call-manager");
+        mComponentContextFixture.addConnectionService(
+                simCallManagerComponent, Mockito.mock(IConnectionService.class));
+        setSimCallManagerCarrierConfig(1, simCallManagerComponent);
+        setSimCallManagerCarrierConfig(2, simCallManagerComponent);
+
+        // When the SIM call manager is registered without the SUPPORTS capability, telephony is
+        // still notified for consistency (e.g. runtime capability removal + re-registration).
+        PhoneAccount simCallManagerAccount =
+                new PhoneAccount.Builder(simCallManagerHandle, "SIM call manager")
+                        .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)
+                        .build();
+        mRegistrar.registerPhoneAccount(simCallManagerAccount);
+        verify(mComponentContextFixture.getTelephonyManager(), times(2))
+                .setVoiceServiceStateOverride(false);
+        clearInvocations(mComponentContextFixture.getTelephonyManager());
+
+        // Adding the SUPPORTS capability causes the SIMs to get notified with false again for
+        // consistency purposes
+        simCallManagerAccount =
+                copyPhoneAccountAndAddCapabilities(
+                        simCallManagerAccount,
+                        PhoneAccount.CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS);
+        mRegistrar.registerPhoneAccount(simCallManagerAccount);
+        verify(mComponentContextFixture.getTelephonyManager(), times(2))
+                .setVoiceServiceStateOverride(false);
+        clearInvocations(mComponentContextFixture.getTelephonyManager());
+
+        // Adding the AVAILABLE capability updates the SIMs again, this time with hasService = true
+        simCallManagerAccount =
+                copyPhoneAccountAndAddCapabilities(
+                        simCallManagerAccount, PhoneAccount.CAPABILITY_VOICE_CALLING_AVAILABLE);
+        mRegistrar.registerPhoneAccount(simCallManagerAccount);
+        verify(mComponentContextFixture.getTelephonyManager(), times(2))
+                .setVoiceServiceStateOverride(true);
+        clearInvocations(mComponentContextFixture.getTelephonyManager());
+
+        // Removing a SIM account does nothing, regardless of SIM call manager capabilities
+        mRegistrar.unregisterPhoneAccount(sim1Account.getAccountHandle());
+        verify(mComponentContextFixture.getTelephonyManager(), never())
+                .setVoiceServiceStateOverride(anyBoolean());
+        clearInvocations(mComponentContextFixture.getTelephonyManager());
+
+        // Adding a SIM account while a SIM call manager with both capabilities is registered causes
+        // a call to telephony with hasService = true
+        mRegistrar.registerPhoneAccount(sim1Account);
+        verify(mComponentContextFixture.getTelephonyManager(), times(1))
+                .setVoiceServiceStateOverride(true);
+        clearInvocations(mComponentContextFixture.getTelephonyManager());
+
+        // Removing the SIM call manager while it has both capabilities causes a call to telephony
+        // with hasService = false
+        mRegistrar.unregisterPhoneAccount(simCallManagerHandle);
+        verify(mComponentContextFixture.getTelephonyManager(), times(2))
+                .setVoiceServiceStateOverride(false);
+        clearInvocations(mComponentContextFixture.getTelephonyManager());
+
+        // Removing the SIM call manager while it has the SUPPORTS capability but not AVAILABLE
+        // still causes a call to telephony with hasService = false for consistency
+        simCallManagerAccount =
+                copyPhoneAccountAndRemoveCapabilities(
+                        simCallManagerAccount, PhoneAccount.CAPABILITY_VOICE_CALLING_AVAILABLE);
+        mRegistrar.registerPhoneAccount(simCallManagerAccount);
+        clearInvocations(mComponentContextFixture.getTelephonyManager()); // from re-registration
+        mRegistrar.unregisterPhoneAccount(simCallManagerHandle);
+        verify(mComponentContextFixture.getTelephonyManager(), times(2))
+                .setVoiceServiceStateOverride(false);
+        clearInvocations(mComponentContextFixture.getTelephonyManager());
+
+        // Finally, removing the SIM call manager while it has neither capability still causes a
+        // call to telephony with hasService = false for consistency
+        simCallManagerAccount =
+                copyPhoneAccountAndRemoveCapabilities(
+                        simCallManagerAccount,
+                        PhoneAccount.CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS);
+        mRegistrar.registerPhoneAccount(simCallManagerAccount);
+        clearInvocations(mComponentContextFixture.getTelephonyManager()); // from re-registration
+        mRegistrar.unregisterPhoneAccount(simCallManagerHandle);
+        verify(mComponentContextFixture.getTelephonyManager(), times(2))
+                .setVoiceServiceStateOverride(false);
+        clearInvocations(mComponentContextFixture.getTelephonyManager());
+    }
+
+    /**
+     * Test PhoneAccountHandle Migration Logic.
+     */
+    @Test
+    public void testPhoneAccountMigration() throws Exception {
+        PhoneAccountRegistrar.State testState = makeQuickStateWithTelephonyPhoneAccountHandle();
+        final int mTestPhoneAccountHandleSubIdInt = 123;
+        // Mock SubscriptionManager
+        SubscriptionInfo subscriptionInfo = new SubscriptionInfo(
+                mTestPhoneAccountHandleSubIdInt, "id0", 1, "a", "b", 1, 1, "test",
+                        1, null, null, null, null, false, null, null);
+        List<SubscriptionInfo> subscriptionInfoList = new ArrayList<>();
+        subscriptionInfoList.add(subscriptionInfo);
+        when(mSubscriptionManager.getAllSubscriptionInfoList()).thenReturn(subscriptionInfoList);
+        mRegistrar.migratePhoneAccountHandle(testState);
+        Collection<DefaultPhoneAccountHandle> defaultPhoneAccountHandles
+                = testState.defaultOutgoingAccountHandles.values();
+        DefaultPhoneAccountHandle defaultPhoneAccountHandle
+                = defaultPhoneAccountHandles.iterator().next();
+        assertEquals(Integer.toString(mTestPhoneAccountHandleSubIdInt),
+                defaultPhoneAccountHandle.phoneAccountHandle.getId());
+    }
+
     private static ComponentName makeQuickConnectionServiceComponentName() {
         return new ComponentName(
                 "com.android.server.telecom.tests",
@@ -1035,6 +1274,23 @@
                 "label" + idx);
     }
 
+    private static PhoneAccount copyPhoneAccountAndOverrideCapabilities(
+            PhoneAccount base, int newCapabilities) {
+        return base.toBuilder().setCapabilities(newCapabilities).build();
+    }
+
+    private static PhoneAccount copyPhoneAccountAndAddCapabilities(
+            PhoneAccount base, int capabilitiesToAdd) {
+        return copyPhoneAccountAndOverrideCapabilities(
+                base, base.getCapabilities() | capabilitiesToAdd);
+    }
+
+    private static PhoneAccount copyPhoneAccountAndRemoveCapabilities(
+            PhoneAccount base, int capabilitiesToRemove) {
+        return copyPhoneAccountAndOverrideCapabilities(
+                base, base.getCapabilities() & ~capabilitiesToRemove);
+    }
+
     private PhoneAccount makeQuickAccount(String id, int idx) {
         return makeQuickAccountBuilder(id, idx)
                 .setAddress(Uri.parse("http://foo.com/" + idx))
@@ -1047,6 +1303,44 @@
                 .build();
     }
 
+    /**
+     * Similar to {@link #makeQuickAccount}, but also hooks up {@code TelephonyManager} so that it
+     * returns {@code simId} as the account's subscriptionId.
+     */
+    private PhoneAccount makeQuickSimAccount(int simId) {
+        PhoneAccount simAccount =
+                makeQuickAccountBuilder("sim" + simId, simId)
+                        .setCapabilities(
+                                PhoneAccount.CAPABILITY_CALL_PROVIDER
+                                        | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)
+                        .setIsEnabled(true)
+                        .build();
+        when(mComponentContextFixture
+                        .getTelephonyManager()
+                        .getSubscriptionId(simAccount.getAccountHandle()))
+                .thenReturn(simId);
+        // mComponentContextFixture already sets up the createForSubscriptionId self-reference
+        when(mComponentContextFixture
+                        .getTelephonyManager()
+                        .createForPhoneAccountHandle(simAccount.getAccountHandle()))
+                .thenReturn(mComponentContextFixture.getTelephonyManager());
+        return simAccount;
+    }
+
+    /**
+     * Hooks up carrier config to point to {@code simCallManagerComponent} for the given {@code
+     * subscriptionId}.
+     */
+    private void setSimCallManagerCarrierConfig(
+            int subscriptionId, @Nullable ComponentName simCallManagerComponent) {
+        PersistableBundle config = new PersistableBundle();
+        config.putString(
+                CarrierConfigManager.KEY_DEFAULT_SIM_CALL_MANAGER_STRING,
+                simCallManagerComponent != null ? simCallManagerComponent.flattenToString() : null);
+        when(mComponentContextFixture.getCarrierConfigManager().getConfigForSubId(subscriptionId))
+                .thenReturn(config);
+    }
+
     private static void roundTripPhoneAccount(PhoneAccount original) throws Exception {
         PhoneAccount copy = null;
 
@@ -1181,6 +1475,25 @@
         }
     }
 
+    private PhoneAccountRegistrar.State makeQuickStateWithTelephonyPhoneAccountHandle() {
+        PhoneAccountRegistrar.State s = new PhoneAccountRegistrar.State();
+        s.accounts.add(makeQuickAccount("id0", 0));
+        s.accounts.add(makeQuickAccount("id1", 1));
+        s.accounts.add(makeQuickAccount("id2", 2));
+        PhoneAccountHandle phoneAccountHandle = new PhoneAccountHandle(new ComponentName(
+                "com.android.phone",
+                        "com.android.services.telephony.TelephonyConnectionService"), "id0");
+        UserHandle userHandle = phoneAccountHandle.getUserHandle();
+        when(UserManager.get(mContext).getSerialNumberForUser(userHandle))
+            .thenReturn(0L);
+        when(UserManager.get(mContext).getUserForSerialNumber(0L))
+            .thenReturn(userHandle);
+        s.defaultOutgoingAccountHandles
+            .put(userHandle, new DefaultPhoneAccountHandle(userHandle, phoneAccountHandle,
+                "testGroup"));
+        return s;
+    }
+
     private PhoneAccountRegistrar.State makeQuickState() {
         PhoneAccountRegistrar.State s = new PhoneAccountRegistrar.State();
         s.accounts.add(makeQuickAccount("id0", 0));
diff --git a/tests/src/com/android/server/telecom/tests/RingerTest.java b/tests/src/com/android/server/telecom/tests/RingerTest.java
index 0e93481..59a5f02 100644
--- a/tests/src/com/android/server/telecom/tests/RingerTest.java
+++ b/tests/src/com/android/server/telecom/tests/RingerTest.java
@@ -24,8 +24,8 @@
 import android.media.VolumeShaper;
 import android.net.Uri;
 import android.os.Bundle;
-import android.os.Looper;
 import android.os.Parcel;
+import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.telecom.TelecomManager;
@@ -47,8 +47,6 @@
 import org.junit.runners.JUnit4;
 import org.mockito.Mock;
 import org.mockito.Spy;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -149,7 +147,8 @@
         when(notificationManager.matchesCallFilter(any(Bundle.class))).thenReturn(true);
         when(mockRingtoneFactory.hasHapticChannels(any(Ringtone.class))).thenReturn(false);
         when(mockRingtonePlayer.play(any(RingtoneFactory.class), any(Call.class),
-                nullable(VolumeShaper.Configuration.class), anyBoolean())).thenReturn(mFuture);
+                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean()))
+                .thenReturn(mFuture);
         mRingerUnderTest = new Ringer(mockPlayerFactory, mContext, mockSystemSettingsUtil,
                 mockRingtonePlayer, mockRingtoneFactory, mockVibrator, spyVibrationEffectProxy,
                 mockInCallController);
@@ -174,9 +173,9 @@
         assertFalse(mRingerUnderTest.startRinging(mockCall2, false));
         verify(mockTonePlayer, never()).stopTone();
         verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
-                eq(null), eq(false));
+                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
         verify(mockVibrator, never())
-                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
+                .vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
     }
 
     @SmallTest
@@ -184,7 +183,7 @@
     public void testNoActionWithExternalRinger() {
         mFuture.complete(false); // not using audio coupled haptics
         Bundle externalRingerExtra = new Bundle();
-        externalRingerExtra.putBoolean(TelecomManager.EXTRA_CALL_EXTERNAL_RINGER, true);
+        externalRingerExtra.putBoolean(TelecomManager.EXTRA_CALL_HAS_IN_BAND_RINGTONE, true);
         when(mockCall1.getIntentExtras()).thenReturn(externalRingerExtra);
         when(mockCall2.getIntentExtras()).thenReturn(externalRingerExtra);
         // Start call waiting to make sure that it doesn't stop when we start ringing
@@ -192,9 +191,9 @@
         assertFalse(mRingerUnderTest.startRinging(mockCall2, false));
         verify(mockTonePlayer, never()).stopTone();
         verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
-                any(VolumeShaper.Configuration.class), anyBoolean());
+                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
         verify(mockVibrator, never())
-                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
+                .vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
     }
 
     @SmallTest
@@ -208,7 +207,7 @@
         mRingCompletionFuture.get();
         verify(mockTonePlayer, never()).stopTone();
         verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
-                any(VolumeShaper.Configuration.class), anyBoolean());
+                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
         verify(mockVibrator, never())
                 .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
     }
@@ -225,9 +224,9 @@
         mRingCompletionFuture.get();
         verify(mockTonePlayer, never()).stopTone();
         verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
-                any(VolumeShaper.Configuration.class), anyBoolean());
+                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
         verify(mockVibrator, never())
-                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
+                .vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
     }
 
     @SmallTest
@@ -241,9 +240,9 @@
         assertTrue(mRingerUnderTest.startRinging(mockCall2, true));
         verify(mockTonePlayer, never()).stopTone();
         verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
-                any(VolumeShaper.Configuration.class), anyBoolean());
+                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
         verify(mockVibrator, never())
-                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
+                .vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
     }
 
     @SmallTest
@@ -260,9 +259,9 @@
         assertFalse(mRingerUnderTest.startRinging(mockCall2, false));
         verify(mockTonePlayer).stopTone();
         verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
-                any(VolumeShaper.Configuration.class), anyBoolean());
+                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
         verify(mockVibrator, never())
-                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
+                .vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
     }
 
     @SmallTest
@@ -276,10 +275,10 @@
         assertTrue(mRingerUnderTest.startRinging(mockCall2, false));
         mRingCompletionFuture.get();
         verify(mockTonePlayer).stopTone();
-        verify(mockRingtonePlayer).play(
-                any(RingtoneFactory.class), any(Call.class), isNull(), eq(true));
+        verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), isNull(),
+                eq(true) /* isRingerAudible */, eq(true) /* isVibrationEnabled */);
         verify(mockVibrator, never()).vibrate(any(VibrationEffect.class),
-                any(AudioAttributes.class));
+                any(VibrationAttributes.class));
     }
 
     @SmallTest
@@ -293,10 +292,12 @@
         assertFalse(mRingerUnderTest.startRinging(mockCall2, false));
         mRingCompletionFuture.get();
         verify(mockTonePlayer).stopTone();
-        verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
-                any(VolumeShaper.Configuration.class), anyBoolean());
+        // Try to play a silent haptics ringtone
+        verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), isNull(),
+                eq(false) /* isRingerAudible */, eq(true) /* isVibrationEnabled */);
+        // Play default vibration when future completes with no audio coupled haptics
         verify(mockVibrator).vibrate(eq(mRingerUnderTest.mDefaultVibrationEffect),
-                any(AudioAttributes.class));
+                any(VibrationAttributes.class));
     }
 
     @SmallTest
@@ -305,17 +306,40 @@
         mRingerUnderTest.startCallWaiting(mockCall1);
         Ringtone mockRingtone = mock(Ringtone.class);
         when(mockRingtoneFactory.getRingtone(any(Call.class))).thenReturn(mockRingtone);
-        when(mockAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
+        when(mockAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
         when(mockAudioManager.getStreamVolume(AudioManager.STREAM_RING)).thenReturn(0);
         mFuture.complete(false); // not using audio coupled haptics
         enableVibrationWhenRinging();
         assertFalse(mRingerUnderTest.startRinging(mockCall2, false));
         mRingCompletionFuture.get();
         verify(mockTonePlayer).stopTone();
-        verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
-                any(VolumeShaper.Configuration.class), anyBoolean());
+        // Try to play a silent haptics ringtone
+        verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), isNull(),
+                eq(false) /* isRingerAudible */, eq(true) /* isVibrationEnabled */);
+        // Play default vibration when future completes with no audio coupled haptics
         verify(mockVibrator).vibrate(eq(mRingerUnderTest.mDefaultVibrationEffect),
-                any(AudioAttributes.class));
+                any(VibrationAttributes.class));
+    }
+
+    @SmallTest
+    @Test
+    public void testAudioCoupledHapticsForSilentRingtone() throws Exception {
+        mRingerUnderTest.startCallWaiting(mockCall1);
+        Ringtone mockRingtone = mock(Ringtone.class);
+        when(mockRingtoneFactory.getRingtone(any(Call.class))).thenReturn(mockRingtone);
+        when(mockAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
+        when(mockAudioManager.getStreamVolume(AudioManager.STREAM_RING)).thenReturn(0);
+        mFuture.complete(true); // using audio coupled haptics
+        enableVibrationWhenRinging();
+        assertFalse(mRingerUnderTest.startRinging(mockCall2, false));
+        mRingCompletionFuture.get();
+        verify(mockTonePlayer).stopTone();
+        // Try to play a silent haptics ringtone
+        verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), isNull(),
+                eq(false) /* isRingerAudible */, eq(true) /* isVibrationEnabled */);
+        // Skip vibration for audio coupled haptics
+        verify(mockVibrator, never()).vibrate(any(VibrationEffect.class),
+                any(VibrationAttributes.class));
     }
 
     @SmallTest
@@ -329,9 +353,9 @@
         mRingerUnderTest.startRinging(mockCall1, false);
         // Make sure we haven't started the vibrator yet, but have started ringing.
         verify(mockRingtonePlayer).play(nullable(RingtoneFactory.class), nullable(Call.class),
-                nullable(VolumeShaper.Configuration.class), anyBoolean());
+                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
         verify(mockVibrator, never()).vibrate(nullable(VibrationEffect.class),
-                nullable(AudioAttributes.class));
+                nullable(VibrationAttributes.class));
         // Simulate something stopping the ringer
         mRingerUnderTest.stopRinging();
         verify(mockRingtonePlayer).stop();
@@ -340,7 +364,7 @@
         mFuture.complete(false);
         // Then make sure that we don't actually start vibrating.
         verify(mockVibrator, never()).vibrate(nullable(VibrationEffect.class),
-                nullable(AudioAttributes.class));
+                nullable(VibrationAttributes.class));
     }
 
     @SmallTest
@@ -357,9 +381,9 @@
         mRingCompletionFuture.get();
         verify(mockTonePlayer).stopTone();
         verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), eq(null),
-                eq(true));
+                eq(true) /* isRingerAudible */, eq(true) /* isVibrationEnabled */);
         verify(mockVibrator).vibrate(eq(spyVibrationEffectProxy.get(FAKE_RINGTONE_URI, mContext)),
-                any(AudioAttributes.class));
+                any(VibrationAttributes.class));
     }
 
     @SmallTest
@@ -373,9 +397,9 @@
         mRingCompletionFuture.get();
         verify(mockTonePlayer).stopTone();
         verify(mockRingtonePlayer).play(any(RingtoneFactory.class), any(Call.class), eq(null),
-                eq(false));
+                eq(true) /* isRingerAudible */, eq(false) /* isVibrationEnabled */);
         verify(mockVibrator, never())
-                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
+                .vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
     }
 
     @SmallTest
@@ -391,7 +415,7 @@
         verify(mockTonePlayer).stopTone();
         verify(mockRingtonePlayer).play(
             any(RingtoneFactory.class), any(Call.class), any(VolumeShaper.Configuration.class),
-                eq(true));
+                eq(true) /* isRingerAudible */, eq(true) /* isVibrationEnabled */);
     }
 
     @SmallTest
@@ -408,9 +432,9 @@
         mRingCompletionFuture.get();
         verify(mockTonePlayer).stopTone();
         verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
-                any(VolumeShaper.Configuration.class), anyBoolean());
+                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
         verify(mockVibrator, never())
-                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
+                .vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
     }
 
     @SmallTest
@@ -426,9 +450,9 @@
         mRingCompletionFuture.get();
         verify(mockTonePlayer).stopTone();
         verify(mockRingtonePlayer, never()).play(any(RingtoneFactory.class), any(Call.class),
-                any(VolumeShaper.Configuration.class), anyBoolean());
+                nullable(VolumeShaper.Configuration.class), anyBoolean(), anyBoolean());
         verify(mockVibrator, never())
-                .vibrate(any(VibrationEffect.class), any(AudioAttributes.class));
+                .vibrate(any(VibrationEffect.class), any(VibrationAttributes.class));
     }
 
     private void ensureRingerIsAudible() {
@@ -440,15 +464,15 @@
 
     private void enableVibrationWhenRinging() {
         when(mockVibrator.hasVibrator()).thenReturn(true);
-        when(mockSystemSettingsUtil.canVibrateWhenRinging(any(Context.class))).thenReturn(true);
+        when(mockSystemSettingsUtil.isRingVibrationEnabled(any(Context.class))).thenReturn(true);
     }
 
     private void enableVibrationOnlyWhenNotRinging() {
         when(mockVibrator.hasVibrator()).thenReturn(true);
-        when(mockSystemSettingsUtil.canVibrateWhenRinging(any(Context.class))).thenReturn(false);
+        when(mockSystemSettingsUtil.isRingVibrationEnabled(any(Context.class))).thenReturn(false);
     }
 
     private void enableRampingRinger() {
-        when(mockSystemSettingsUtil.applyRampingRinger(any(Context.class))).thenReturn(true);
+        when(mockSystemSettingsUtil.isRampingRingerEnabled(any(Context.class))).thenReturn(true);
     }
 }
diff --git a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
index 3cec50b..210f80e 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomServiceImplTest.java
@@ -102,6 +102,7 @@
 public class TelecomServiceImplTest extends TelecomTestCase {
 
     public static final String TEST_PACKAGE = "com.test";
+    public static final String PACKAGE_NAME = "test";
 
     public static class CallIntentProcessAdapterFake implements CallIntentProcessor.Adapter {
         @Override
@@ -180,15 +181,17 @@
     private static final UserHandle USER_HANDLE_16 = new UserHandle(16);
     private static final UserHandle USER_HANDLE_17 = new UserHandle(17);
     private static final PhoneAccountHandle TEL_PA_HANDLE_16 = new PhoneAccountHandle(
-            new ComponentName("test", "telComponentName"), "0", USER_HANDLE_16);
+            new ComponentName(PACKAGE_NAME, "telComponentName"), "0", USER_HANDLE_16);
     private static final PhoneAccountHandle SIP_PA_HANDLE_17 = new PhoneAccountHandle(
-            new ComponentName("test", "sipComponentName"), "1", USER_HANDLE_17);
+            new ComponentName(PACKAGE_NAME, "sipComponentName"), "1", USER_HANDLE_17);
     private static final PhoneAccountHandle TEL_PA_HANDLE_CURRENT = new PhoneAccountHandle(
-            new ComponentName("test", "telComponentName"), "2", Binder.getCallingUserHandle());
+            new ComponentName(PACKAGE_NAME, "telComponentName"), "2",
+                    Binder.getCallingUserHandle());
     private static final PhoneAccountHandle SIP_PA_HANDLE_CURRENT = new PhoneAccountHandle(
-            new ComponentName("test", "sipComponentName"), "3", Binder.getCallingUserHandle());
-    private static final ComponentName THIRD_PARTY_CALL_SCREENING = new ComponentName("com.android" +
-            ".thirdparty", "com.android.thirdparty.callscreeningserviceimpl");
+            new ComponentName(PACKAGE_NAME, "sipComponentName"), "3",
+                    Binder.getCallingUserHandle());
+    private static final ComponentName THIRD_PARTY_CALL_SCREENING = new ComponentName(
+            "com.android.thirdparty", "com.android.thirdparty.callscreeningserviceimpl");
 
     @Override
     @Before
@@ -196,11 +199,8 @@
         super.setUp();
         mContext = mComponentContextFixture.getTestDouble().getApplicationContext();
 
-        TelephonyManager mockTelephonyManager =
-                (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
-        when(mockTelephonyManager.isVoiceCapable()).thenReturn(true);
-
         doReturn(mContext).when(mContext).getApplicationContext();
+        doReturn(mContext).when(mContext).createContextAsUser(any(UserHandle.class), anyInt());
         doNothing().when(mContext).sendBroadcastAsUser(any(Intent.class), any(UserHandle.class),
                 anyString());
         doAnswer(invocation -> {
@@ -237,6 +237,7 @@
                 .thenReturn(true);
 
         mPackageManager = mContext.getPackageManager();
+        when(mPackageManager.getPackageUid(anyString(), eq(0))).thenReturn(Binder.getCallingUid());
     }
 
     @Override
@@ -458,12 +459,18 @@
 
     @SmallTest
     @Test
-    public void testGetPhoneAccount() throws RemoteException {
+    public void testGetPhoneAccount() throws Exception {
         makeAccountsVisibleToAllUsers(TEL_PA_HANDLE_16, SIP_PA_HANDLE_17);
         assertEquals(TEL_PA_HANDLE_16, mTSIBinder.getPhoneAccount(TEL_PA_HANDLE_16,
                 mContext.getPackageName()).getAccountHandle());
         assertEquals(SIP_PA_HANDLE_17, mTSIBinder.getPhoneAccount(SIP_PA_HANDLE_17,
                 mContext.getPackageName()).getAccountHandle());
+        try {
+            // Try to call the method without using the caller's package name
+            mTSIBinder.getPhoneAccount(TEL_PA_HANDLE_16, null);
+            fail("Should have thrown a SecurityException");
+        } catch (SecurityException expected) {
+        }
     }
 
     @SmallTest
@@ -505,6 +512,25 @@
         doReturn(PackageManager.PERMISSION_DENIED)
                 .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
         PackageManager pm = mContext.getPackageManager();
+        when(pm.hasSystemFeature(PackageManager.FEATURE_TELECOM)).thenReturn(true);
+
+        registerPhoneAccountTestHelper(phoneAccount, true);
+    }
+
+    @SmallTest
+    @Test
+    public void testRegisterPhoneAccountWithOldFeatureFlag() throws RemoteException {
+        // tests the case where the package does not have MODIFY_PHONE_STATE but is
+        // registering its own phone account as a third-party connection service
+        String packageNameToUse = "com.thirdparty.connectionservice";
+        PhoneAccountHandle phHandle = new PhoneAccountHandle(new ComponentName(
+                packageNameToUse, "cs"), "asdf", Binder.getCallingUserHandle());
+        PhoneAccount phoneAccount = makePhoneAccount(phHandle).build();
+
+        doReturn(PackageManager.PERMISSION_DENIED)
+                .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
+        PackageManager pm = mContext.getPackageManager();
+        when(pm.hasSystemFeature(PackageManager.FEATURE_TELECOM)).thenReturn(false);
         when(pm.hasSystemFeature(PackageManager.FEATURE_CONNECTION_SERVICE)).thenReturn(true);
 
         registerPhoneAccountTestHelper(phoneAccount, true);
@@ -523,7 +549,7 @@
         doReturn(PackageManager.PERMISSION_DENIED)
                 .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
         PackageManager pm = mContext.getPackageManager();
-        when(pm.hasSystemFeature(PackageManager.FEATURE_CONNECTION_SERVICE)).thenReturn(false);
+        when(pm.hasSystemFeature(PackageManager.FEATURE_TELECOM)).thenReturn(false);
 
         registerPhoneAccountTestHelper(phoneAccount, false);
     }
@@ -612,7 +638,7 @@
         doReturn(PackageManager.PERMISSION_DENIED)
                 .when(mContext).checkCallingOrSelfPermission(MODIFY_PHONE_STATE);
         PackageManager pm = mContext.getPackageManager();
-        when(pm.hasSystemFeature(PackageManager.FEATURE_CONNECTION_SERVICE)).thenReturn(false);
+        when(pm.hasSystemFeature(PackageManager.FEATURE_TELECOM)).thenReturn(false);
 
         try {
             mTSIBinder.unregisterPhoneAccount(phHandle);
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index 7f462d4..d6ff196 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -39,6 +39,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.AppOpsManager;
+import android.bluetooth.BluetoothManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -348,6 +349,7 @@
         doNothing().when(mSpyContext).sendBroadcastAsUser(any(), any(), any());
 
         doReturn(mock(AppOpsManager.class)).when(mSpyContext).getSystemService(AppOpsManager.class);
+        doReturn(mock(BluetoothManager.class)).when(mSpyContext).getSystemService(BluetoothManager.class);
 
         mHandlerThread = new HandlerThread("TelecomHandlerThread");
         mHandlerThread.start();
@@ -571,9 +573,6 @@
                 com.android.server.telecom.R.string.incall_default_class,
                 mInCallServiceComponentNameX.getClassName());
 
-        doReturn(true).when(mComponentContextFixture.getTelephonyManager())
-                .isVoiceCapable();
-
         mInCallServiceFixtureX = new InCallServiceFixture();
         mInCallServiceFixtureY = new InCallServiceFixture();
 
@@ -604,8 +603,8 @@
                     doReturn(args[0]).when(fakeAudioManager).isMicrophoneMute();
                     return null;
                 }
-            }).when(audioService)
-                    .setMicrophoneMute(any(Boolean.class), any(String.class), any(Integer.class));
+            }).when(audioService).setMicrophoneMute(any(Boolean.class), any(String.class),
+                    any(Integer.class), nullable(String.class));
 
         } catch (android.os.RemoteException e) {
             // Do nothing, leave the faked microphone state as-is
diff --git a/tests/src/com/android/server/telecom/tests/TelecomTestCase.java b/tests/src/com/android/server/telecom/tests/TelecomTestCase.java
index 264e087..5353bc6 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomTestCase.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomTestCase.java
@@ -40,6 +40,7 @@
     public void setUp() throws Exception {
         Log.setTag(TESTING_TAG);
         Log.setIsExtendedLoggingEnabled(true);
+        Log.setUnitTestingEnabled(true);
         mMockitoHelper.setUp(InstrumentationRegistry.getContext(), getClass());
         mComponentContextFixture = new ComponentContextFixture();
         mContext = mComponentContextFixture.getTestDouble().getApplicationContext();