Merge "Improved audio focus handling for CARSM" into nyc-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4262877..7ace0e0 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -70,8 +70,8 @@
             android:supportsRtl="true"
             android:process="system"
             android:usesCleartextTraffic="false"
-            android:forceDeviceEncrypted="true"
-            android:encryptionAware="true">
+            android:defaultToDeviceProtectedStorage="true"
+            android:directBootAware="true">
 
         <!-- CALL vs CALL_PRIVILEGED vs CALL_EMERGENCY
              We have three different intents through which a call can be initiated each with its
diff --git a/res/values-be-rBY/strings.xml b/res/values-be-rBY/strings.xml
new file mode 100644
index 0000000..0ef388c
--- /dev/null
+++ b/res/values-be-rBY/strings.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--  Copyright (C) 2013 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.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Кіраванне тэлефоннымі выклікамі"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Патэлефанаваць"</string>
+    <string name="unknown" msgid="6878797917991465859">"Невядомы"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Прапушчаны выклік"</string>
+    <string name="notification_missedWorkCallTitle" msgid="6242489980390803090">"Прапушчаны выклік па працы"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Прапушчаныя выклікі"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Прапушчаных выклікаў: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Прапушчаны выклік ад <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Адказаць"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Паведамленне"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Выклік сцішаны."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Уключаная гучная сувязь."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Не магу размаўляць. У чым справа?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Я ператэлефаную."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Я патэлефаную пазней."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Не магу размаўляць. Набяры пазней."</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Хуткія адказы"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Рэдагаваць хуткія адказы"</string>
+    <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Хуткі адказ"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Паведамленне адпраўлена на нумар <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Уліковыя запісы для выклікаў"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="6872406278300131364">"Дазволены толькі экстранныя выклікі."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Гэта праграма не можа рабіць выходныя выклікі без дазволу тэлефона."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Каб зрабіць выклік, увядзіце сапраўдны нумар."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Зараз немагчыма дадаць выклік."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"Адсутнічае нумар галасавой пошты"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"На SIM-карце няма нумару галасавой пошты."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"Дадаць нумар"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Змяніць стандартны Набіральнік нумара?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Выкарыстоўваць <xliff:g id="NEW_APP">%1$s</xliff:g> замест <xliff:g id="CURRENT_APP">%2$s</xliff:g> у якасці вашага стандартнага набіральніка нумара?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Выкарыстоўваць <xliff:g id="NEW_APP">%s</xliff:g> у якасці вашага стандартнага набіральніка нумара?"</string>
+    <string name="blocked_numbers" msgid="2751843139572970579">"Заблакіраваныя нумары"</string>
+    <string name="blocked_numbers_msg" msgid="1045015186124965643">"Вы не будзеце атрымліваць выклікі ці тэкставыя паведамленні ад заблакаваных нумароў."</string>
+    <string name="block_number" msgid="1101252256321306179">"Дадаць нумар"</string>
+    <string name="unblock_dialog_body" msgid="1614238499771862793">"Разблакіраваць <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string>
+    <string name="unblock_button" msgid="3078048901972674170">"Разблакiраваць"</string>
+    <string name="add_blocked_dialog_body" msgid="9030243212265516828">"Блакіраваць выклікі і тэкставыя паведамленні ад"</string>
+    <string name="add_blocked_number_hint" msgid="6847675097085433553">"Нумар тэлефона"</string>
+    <string name="block_button" msgid="8822290682524373357">"Заблакiраваць"</string>
+    <string name="non_primary_user" msgid="5180129233352533459">"Толькі ўладальнік прылады можа праглядаць блакіраваныя нумары і кіраваць імі."</string>
+    <string name="delete_icon_description" msgid="1828583824185681368">"Закладка для разблакіравання"</string>
+    <string name="blocked_numbers_butter_bar_title" msgid="438170866438793182">"Блакіроўка часова адключана"</string>
+    <string name="blocked_numbers_butter_bar_body" msgid="2223244484319442431">"Пасля тэлефанавання або адпраўкі SMS на экстранны нумар блакіроўка адключаецца, каб аварыйныя службы маглі звязацца з вамі."</string>
+    <string name="blocked_numbers_butter_bar_button" msgid="2197943354922010696">"Паўторна ўключыць зараз"</string>
+    <string name="toast_personal_call_msg" msgid="5115361633476779723">"Выкарыстанне асабістага набіральніка нумара для выканання выкліку"</string>
+</resources>
diff --git a/res/values-bs-rBA/strings.xml b/res/values-bs-rBA/strings.xml
index da4224d..1c595b7 100644
--- a/res/values-bs-rBA/strings.xml
+++ b/res/values-bs-rBA/strings.xml
@@ -16,90 +16,50 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- no translation found for telecommAppLabel (9166784827254469057) -->
-    <skip />
-    <!-- no translation found for userCallActivityLabel (5415173590855187131) -->
-    <skip />
-    <!-- no translation found for unknown (6878797917991465859) -->
-    <skip />
-    <!-- no translation found for notification_missedCallTitle (7554385905572364535) -->
-    <skip />
-    <!-- no translation found for notification_missedWorkCallTitle (6242489980390803090) -->
-    <skip />
-    <!-- no translation found for notification_missedCallsTitle (1361677948941502522) -->
-    <skip />
-    <!-- no translation found for notification_missedCallsMsg (4575787816055205600) -->
-    <skip />
-    <!-- no translation found for notification_missedCallTicker (504686252427747209) -->
-    <skip />
-    <!-- no translation found for notification_missedCall_call_back (2684890353590890187) -->
-    <skip />
-    <!-- no translation found for notification_missedCall_message (3049928912736917988) -->
-    <skip />
-    <!-- no translation found for accessibility_call_muted (2776111226185342220) -->
-    <skip />
-    <!-- no translation found for accessibility_speakerphone_enabled (1988512040421036359) -->
-    <skip />
-    <!-- no translation found for respond_via_sms_canned_response_1 (2461606462788380215) -->
-    <skip />
-    <!-- no translation found for respond_via_sms_canned_response_2 (4074450431532859214) -->
-    <skip />
-    <!-- no translation found for respond_via_sms_canned_response_3 (3496079065723960450) -->
-    <skip />
-    <!-- no translation found for respond_via_sms_canned_response_4 (1698989243040062190) -->
-    <skip />
-    <!-- no translation found for respond_via_sms_setting_title (3754000371039709383) -->
-    <skip />
-    <!-- no translation found for respond_via_sms_setting_title_2 (6104662227299493906) -->
-    <skip />
+    <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Upravljanje telefonskim pozivima"</string>
+    <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Telefon"</string>
+    <string name="unknown" msgid="6878797917991465859">"Nepoznato"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Propušteni poziv"</string>
+    <string name="notification_missedWorkCallTitle" msgid="6242489980390803090">"Propušteni poslovni poziv"</string>
+    <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Propušteni pozivi"</string>
+    <string name="notification_missedCallsMsg" msgid="4575787816055205600">"Propušteni pozivi: <xliff:g id="NUM_MISSED_CALLS">%s</xliff:g>"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Propušteni poziv od kontakta <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Povr. poziv"</string>
+    <string name="notification_missedCall_message" msgid="3049928912736917988">"Poruka"</string>
+    <string name="accessibility_call_muted" msgid="2776111226185342220">"Zvuk poziva je isključen."</string>
+    <string name="accessibility_speakerphone_enabled" msgid="1988512040421036359">"Zvučnik je omogućen."</string>
+    <string name="respond_via_sms_canned_response_1" msgid="2461606462788380215">"Ne mogu sada pričati. Šta ima?"</string>
+    <string name="respond_via_sms_canned_response_2" msgid="4074450431532859214">"Nazvat ću te uskoro."</string>
+    <string name="respond_via_sms_canned_response_3" msgid="3496079065723960450">"Nazvat ću te kasnije."</string>
+    <string name="respond_via_sms_canned_response_4" msgid="1698989243040062190">"Ne mogu pričati. Nazovi kasnije?"</string>
+    <string name="respond_via_sms_setting_title" msgid="3754000371039709383">"Brzi odgovori"</string>
+    <string name="respond_via_sms_setting_title_2" msgid="6104662227299493906">"Uredi brze odgovore"</string>
     <string name="respond_via_sms_setting_summary" msgid="9150281183930613065"></string>
-    <!-- no translation found for respond_via_sms_edittext_dialog_title (20379890418289778) -->
-    <skip />
-    <!-- no translation found for respond_via_sms_confirmation_format (7229149977515784269) -->
-    <skip />
-    <!-- no translation found for enable_account_preference_title (2021848090086481720) -->
-    <skip />
-    <!-- no translation found for outgoing_call_not_allowed_user_restriction (6872406278300131364) -->
-    <skip />
-    <!-- no translation found for outgoing_call_not_allowed_no_permission (1996571596464271228) -->
-    <skip />
-    <!-- no translation found for outgoing_call_error_no_phone_number_supplied (1940125199802007505) -->
-    <skip />
-    <!-- no translation found for duplicate_video_call_not_allowed (3749211605014548386) -->
-    <skip />
-    <!-- no translation found for no_vm_number (4164780423805688336) -->
-    <skip />
-    <!-- no translation found for no_vm_number_msg (1300729501030053828) -->
-    <skip />
-    <!-- no translation found for add_vm_number_str (4676479471644687453) -->
-    <skip />
-    <!-- no translation found for change_default_dialer_dialog_title (4430590714918044425) -->
-    <skip />
-    <!-- no translation found for change_default_dialer_with_previous_app_set_text (3213396537499337949) -->
-    <skip />
-    <!-- no translation found for change_default_dialer_no_previous_app_set_text (7608426684114545221) -->
-    <skip />
-    <!-- no translation found for blocked_numbers (2751843139572970579) -->
-    <skip />
+    <string name="respond_via_sms_edittext_dialog_title" msgid="20379890418289778">"Brzi odgovor"</string>
+    <string name="respond_via_sms_confirmation_format" msgid="7229149977515784269">"Poruka poslana na <xliff:g id="PHONE_NUMBER">%s</xliff:g>."</string>
+    <string name="enable_account_preference_title" msgid="2021848090086481720">"Računi za pozivanje"</string>
+    <string name="outgoing_call_not_allowed_user_restriction" msgid="6872406278300131364">"Dozvoljeni su samo hitni pozivi."</string>
+    <string name="outgoing_call_not_allowed_no_permission" msgid="1996571596464271228">"Ova aplikacija ne može upućivati odlazne pozive bez dozvole za Telefon."</string>
+    <string name="outgoing_call_error_no_phone_number_supplied" msgid="1940125199802007505">"Da uputite poziv, upišite važeći broj."</string>
+    <string name="duplicate_video_call_not_allowed" msgid="3749211605014548386">"Trenutno nije moguće dodati poziv."</string>
+    <string name="no_vm_number" msgid="4164780423805688336">"Nedostaje broj govorne pošte"</string>
+    <string name="no_vm_number_msg" msgid="1300729501030053828">"Broj govorne pošte nije pohranjen na SIM kartici."</string>
+    <string name="add_vm_number_str" msgid="4676479471644687453">"Dodaj broj"</string>
+    <string name="change_default_dialer_dialog_title" msgid="4430590714918044425">"Promijeniti zadanu aplikaciju za biranje?"</string>
+    <string name="change_default_dialer_with_previous_app_set_text" msgid="3213396537499337949">"Koristiti <xliff:g id="NEW_APP">%1$s</xliff:g> umjesto <xliff:g id="CURRENT_APP">%2$s</xliff:g> kao zadanu aplikaciju za biranje?"</string>
+    <string name="change_default_dialer_no_previous_app_set_text" msgid="7608426684114545221">"Koristiti <xliff:g id="NEW_APP">%s</xliff:g> kao zadanu aplikaciju za biranje?"</string>
+    <string name="blocked_numbers" msgid="2751843139572970579">"Blokirani brojevi"</string>
     <string name="blocked_numbers_msg" msgid="1045015186124965643">"Nećete primati pozive i poruke od blokiranih brojeva."</string>
-    <!-- no translation found for block_number (1101252256321306179) -->
-    <skip />
-    <!-- no translation found for unblock_dialog_body (1614238499771862793) -->
-    <skip />
-    <!-- no translation found for unblock_button (3078048901972674170) -->
-    <skip />
-    <!-- no translation found for add_blocked_dialog_body (9030243212265516828) -->
-    <skip />
+    <string name="block_number" msgid="1101252256321306179">"Dodaj broj"</string>
+    <string name="unblock_dialog_body" msgid="1614238499771862793">"Odblokirati <xliff:g id="NUMBER_TO_BLOCK">%1$s</xliff:g>?"</string>
+    <string name="unblock_button" msgid="3078048901972674170">"Odblokiraj"</string>
+    <string name="add_blocked_dialog_body" msgid="9030243212265516828">"Blokiraj pozive i tekstualne poruke od"</string>
     <string name="add_blocked_number_hint" msgid="6847675097085433553">"Telefonski broj"</string>
-    <!-- no translation found for block_button (8822290682524373357) -->
-    <skip />
-    <!-- no translation found for non_primary_user (5180129233352533459) -->
-    <skip />
-    <!-- no translation found for delete_icon_description (1828583824185681368) -->
-    <skip />
+    <string name="block_button" msgid="8822290682524373357">"Blokiraj"</string>
+    <string name="non_primary_user" msgid="5180129233352533459">"Samo vlasnik uređaja može pregledati i upravljati blokiranim brojevima."</string>
+    <string name="delete_icon_description" msgid="1828583824185681368">"Dodirnite da odblokirate"</string>
     <string name="blocked_numbers_butter_bar_title" msgid="438170866438793182">"Blokiranje je privremeno isključeno"</string>
     <string name="blocked_numbers_butter_bar_body" msgid="2223244484319442431">"Nakon što pozovete ili pošaljete poruku na broj za hitne slučajeve, blokiranje se isključuje da bi vas hitna služba mogla kontaktirati."</string>
     <string name="blocked_numbers_butter_bar_button" msgid="2197943354922010696">"Ponovo omogući sada"</string>
-    <!-- no translation found for toast_personal_call_msg (5115361633476779723) -->
-    <skip />
+    <string name="toast_personal_call_msg" msgid="5115361633476779723">"Za upućivanje poziva koristi se lična brojčana tastatura"</string>
 </resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index f123ca9..85f9cb9 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -19,11 +19,11 @@
     <string name="telecommAppLabel" product="default" msgid="9166784827254469057">"Usimamizi wa Mazunguzo ya Simu"</string>
     <string name="userCallActivityLabel" product="default" msgid="5415173590855187131">"Simu"</string>
     <string name="unknown" msgid="6878797917991465859">"Haijulikani"</string>
-    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Simu isiyojibiwa"</string>
+    <string name="notification_missedCallTitle" msgid="7554385905572364535">"Simu uliyokosa"</string>
     <string name="notification_missedWorkCallTitle" msgid="6242489980390803090">"Simu ya kazini ambayo hukujibu"</string>
     <string name="notification_missedCallsTitle" msgid="1361677948941502522">"Simu zisizojibiwa"</string>
     <string name="notification_missedCallsMsg" msgid="4575787816055205600">"<xliff:g id="NUM_MISSED_CALLS">%s</xliff:g> simu ambazo hazijajibiwa"</string>
-    <string name="notification_missedCallTicker" msgid="504686252427747209">"Simu isiyojibiwa kutoka <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
+    <string name="notification_missedCallTicker" msgid="504686252427747209">"Ulikosa simu kutoka kwa <xliff:g id="MISSED_CALL_FROM">%s</xliff:g>"</string>
     <string name="notification_missedCall_call_back" msgid="2684890353590890187">"Mpigie"</string>
     <string name="notification_missedCall_message" msgid="3049928912736917988">"Ujumbe"</string>
     <string name="accessibility_call_muted" msgid="2776111226185342220">"Simu imezimwa."</string>
diff --git a/res/xml/activity_blocked_numbers.xml b/res/xml/activity_blocked_numbers.xml
index 681cf89..17bc99c 100644
--- a/res/xml/activity_blocked_numbers.xml
+++ b/res/xml/activity_blocked_numbers.xml
@@ -28,6 +28,7 @@
 
         <include
                 android:id="@+id/butter_bar"
+                android:visibility="gone"
                 layout="@xml/blocking_suppressed_butterbar" />
 
         <FrameLayout
diff --git a/src/com/android/server/telecom/AsyncRingtonePlayer.java b/src/com/android/server/telecom/AsyncRingtonePlayer.java
index bb2e9cd..cc8cdcc 100644
--- a/src/com/android/server/telecom/AsyncRingtonePlayer.java
+++ b/src/com/android/server/telecom/AsyncRingtonePlayer.java
@@ -47,11 +47,11 @@
     private Ringtone mRingtone;
 
     /** Plays the ringtone. */
-    public void play(RingtoneFactory factory, Uri ringtoneUri) {
+    public void play(RingtoneFactory factory, Call incomingCall) {
         Log.d(this, "Posting play.");
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = factory;
-        args.arg2 = ringtoneUri;
+        args.arg2 = incomingCall;
         postMessage(EVENT_PLAY, true /* shouldCreateHandler */, args);
     }
 
@@ -114,7 +114,7 @@
      */
     private void handlePlay(SomeArgs args) {
         RingtoneFactory factory = (RingtoneFactory) args.arg1;
-        Uri ringtoneUri = (Uri) args.arg2;
+        Call incomingCall = (Call) args.arg2;
         args.recycle();
         // don't bother with any of this if there is an EVENT_STOP waiting.
         if (mHandler.hasMessages(EVENT_STOP)) {
@@ -125,10 +125,13 @@
         Log.i(this, "Play ringtone.");
 
         if (mRingtone == null) {
-            mRingtone = factory.getRingtone(ringtoneUri);
+            mRingtone = factory.getRingtone(incomingCall);
             if (mRingtone == null) {
+                Uri ringtoneUri = incomingCall.getRingtone();
+                String ringtoneUriString = (ringtoneUri == null) ? "null" :
+                        ringtoneUri.toSafeString();
                 Log.event(null, Log.Events.ERROR_LOG, "Failed to get ringtone from factory. " +
-                        "Skipping ringing. Uri was: " + ringtoneUri.toSafeString());
+                        "Skipping ringing. Uri was: " + ringtoneUriString);
                 return;
             }
         }
diff --git a/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
index 6680eb6..33ca531 100644
--- a/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
+++ b/src/com/android/server/telecom/BluetoothPhoneServiceImpl.java
@@ -401,7 +401,7 @@
         }
     };
 
-    private BluetoothAdapter mBluetoothAdapter;
+    private BluetoothAdapterProxy mBluetoothAdapter;
     private BluetoothHeadsetProxy mBluetoothHeadset;
 
     // A map from Calls to indexes used to identify calls for CLCC (C* List Current Calls).
@@ -422,6 +422,7 @@
             Context context,
             TelecomSystem.SyncRoot lock,
             CallsManager callsManager,
+            BluetoothAdapterProxy bluetoothAdapter,
             PhoneAccountRegistrar phoneAccountRegistrar) {
         Log.d(this, "onCreate");
 
@@ -430,7 +431,7 @@
         mCallsManager = callsManager;
         mPhoneAccountRegistrar = phoneAccountRegistrar;
 
-        mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+        mBluetoothAdapter = bluetoothAdapter;
         if (mBluetoothAdapter == null) {
             Log.d(this, "BluetoothPhoneService shutting down, no BT Adapter found.");
             return;
diff --git a/src/com/android/server/telecom/Call.java b/src/com/android/server/telecom/Call.java
index 2a56422..3402cc4 100644
--- a/src/com/android/server/telecom/Call.java
+++ b/src/com/android/server/telecom/Call.java
@@ -105,6 +105,7 @@
         void onConferenceableCallsChanged(Call call);
         boolean onCanceledViaNewOutgoingCallBroadcast(Call call);
         void onHoldToneRequested(Call call);
+        void onConnectionEvent(Call call, String event, Bundle extras);
     }
 
     public abstract static class ListenerBase implements Listener {
@@ -165,6 +166,8 @@
 
         @Override
         public void onHoldToneRequested(Call call) {}
+        @Override
+        public void onConnectionEvent(Call call, String event, Bundle extras) {}
     }
 
     private final OnQueryCompleteListener mCallerInfoQueryListener =
@@ -1424,6 +1427,55 @@
         }
     }
 
+    /**
+     * Initiates a request to the connection service to pull this call.
+     * <p>
+     * This method can only be used for calls that have the
+     * {@link android.telecom.Connection#CAPABILITY_CAN_PULL_CALL} and
+     * {@link android.telecom.Connection#CAPABILITY_IS_EXTERNAL_CALL} capabilities set.
+     * <p>
+     * An external call is a representation of a call which is taking place on another device
+     * associated with a PhoneAccount on this device.  Issuing a request to pull the external call 
+     * tells the {@link android.telecom.ConnectionService} that it should move the call from the
+     * other device to this one.  An example of this is the IMS multi-endpoint functionality.  A
+     * user may have two phones with the same phone number.  If the user is engaged in an active
+     * call on their first device, the network will inform the second device of that ongoing call in
+     * the form of an external call.  The user may wish to continue their conversation on the second
+     * device, so will issue a request to pull the call to the second device.
+     * <p>
+     * Requests to pull a call which is not external, or a call which is not pullable are ignored.
+     */
+    public void pullExternalCall() {
+        if (mConnectionService == null) {
+            Log.w(this, "pulling a call without a connection service.");
+        }
+
+        if (!can(Connection.CAPABILITY_IS_EXTERNAL_CALL)) {
+            Log.w(this, "pullExternalCall - call %s is not an external call.", mId);
+            return;
+        }
+
+        if (!can(Connection.CAPABILITY_CAN_PULL_CALL)) {
+            Log.w(this, "pullExternalCall - call %s is external but cannot be pulled.", mId);
+            return;
+        }
+
+        Log.event(this, Log.Events.PULL);
+        mConnectionService.pullExternalCall(this);
+    }
+
+    /**
+     * Sends a call event to the {@link ConnectionService} for this call.
+     *
+     * See {@link Call#sendCallEvent(String, Bundle)}.
+     *
+     * @param event The call event.
+     * @param extras Associated extras.
+     */
+    public void sendCallEvent(String event, Bundle extras) {
+        mConnectionService.sendCallEvent(this, event, extras);
+    }
+
     void setParentCall(Call parentCall) {
         if (parentCall == this) {
             Log.e(this, new Exception(), "setting the parent to self");
@@ -1948,8 +2000,9 @@
      * Handles Connection events received from a {@link ConnectionService}.
      *
      * @param event The event.
+     * @param extras The extras.
      */
-    public void onConnectionEvent(String event) {
+    public void onConnectionEvent(String event, Bundle extras) {
         if (Connection.EVENT_ON_HOLD_TONE_START.equals(event)) {
             mIsRemotelyHeld = true;
             Log.event(this, Log.Events.REMOTELY_HELD);
@@ -1964,6 +2017,10 @@
             for (Listener l : mListeners) {
                 l.onHoldToneRequested(this);
             }
+        } else {
+            for (Listener l : mListeners) {
+                l.onConnectionEvent(this, event, extras);
+            }
         }
     }
 }
diff --git a/src/com/android/server/telecom/CallAudioManager.java b/src/com/android/server/telecom/CallAudioManager.java
index 3028398..7740668 100644
--- a/src/com/android/server/telecom/CallAudioManager.java
+++ b/src/com/android/server/telecom/CallAudioManager.java
@@ -39,7 +39,7 @@
 
     private final String LOG_TAG = CallAudioManager.class.getSimpleName();
 
-    private final LinkedHashSet<Call> mActiveOrDialingCalls;
+    private final LinkedHashSet<Call> mActiveDialingOrConnectingCalls;
     private final LinkedHashSet<Call> mRingingCalls;
     private final LinkedHashSet<Call> mHoldingCalls;
     private final Set<Call> mCalls;
@@ -64,13 +64,14 @@
             Ringer ringer,
             RingbackPlayer ringbackPlayer,
             DtmfLocalTonePlayer dtmfLocalTonePlayer) {
-        mActiveOrDialingCalls = new LinkedHashSet<>();
+        mActiveDialingOrConnectingCalls = new LinkedHashSet<>();
         mRingingCalls = new LinkedHashSet<>();
         mHoldingCalls = new LinkedHashSet<>();
         mCalls = new HashSet<>();
         mCallStateToCalls = new SparseArray<LinkedHashSet<Call>>() {{
-            put(CallState.ACTIVE, mActiveOrDialingCalls);
-            put(CallState.DIALING, mActiveOrDialingCalls);
+            put(CallState.CONNECTING, mActiveDialingOrConnectingCalls);
+            put(CallState.ACTIVE, mActiveDialingOrConnectingCalls);
+            put(CallState.DIALING, mActiveDialingOrConnectingCalls);
             put(CallState.RINGING, mRingingCalls);
             put(CallState.ON_HOLD, mHoldingCalls);
         }};
@@ -171,17 +172,14 @@
                 if (mCallStateToCalls.get(call.getState()) != null) {
                     mCallStateToCalls.get(call.getState()).remove(call);
                 }
-                mActiveOrDialingCalls.add(call);
+                mActiveDialingOrConnectingCalls.add(call);
                 mCallAudioModeStateMachine.sendMessage(
                         CallAudioModeStateMachine.MT_AUDIO_SPEEDUP_FOR_RINGING_CALL,
                         makeArgsForModeStateMachine());
             }
         }
 
-        if (mRingingCalls.size() == 0) {
-            mRinger.stopRinging();
-            mRinger.stopCallWaiting();
-        }
+        maybeStopRingingAndCallWaitingForAnsweredOrRejectedCall(call);
     }
 
     @Override
@@ -242,13 +240,7 @@
 
     @Override
     public void onIncomingCallRejected(Call call, boolean rejectWithMessage, String message) {
-        // This gets called after the UI rejects a call but before the CS processes the rejection.
-        // Will get called before the state change from ringing to not ringing.
-
-        if (mRingingCalls.size() == 0 || call == mRingingCalls.iterator().next()) {
-            mRinger.stopRinging();
-            mRinger.stopCallWaiting();
-        }
+        maybeStopRingingAndCallWaitingForAnsweredOrRejectedCall(call);
     }
 
     @Override
@@ -377,9 +369,9 @@
     }
 
     void dump(IndentingPrintWriter pw) {
-        pw.println("Active or dialing calls:");
+        pw.println("Active dialing, or connecting calls:");
         pw.increaseIndent();
-        dumpCallsInCollection(pw, mActiveOrDialingCalls);
+        dumpCallsInCollection(pw, mActiveDialingOrConnectingCalls);
         pw.decreaseIndent();
 
         pw.println("Ringing calls:");
@@ -408,7 +400,8 @@
     private void onCallLeavingState(Call call, int state) {
         switch (state) {
             case CallState.ACTIVE:
-                onCallLeavingActiveOrDialing();
+            case CallState.CONNECTING:
+                onCallLeavingActiveDialingOrConnecting();
                 break;
             case CallState.RINGING:
                 onCallLeavingRinging();
@@ -418,14 +411,15 @@
                 break;
             case CallState.DIALING:
                 stopRingbackForCall(call);
-                onCallLeavingActiveOrDialing();
+                onCallLeavingActiveDialingOrConnecting();
         }
     }
 
     private void onCallEnteringState(Call call, int state) {
         switch (state) {
             case CallState.ACTIVE:
-                onCallEnteringActiveOrDialing();
+            case CallState.CONNECTING:
+                onCallEnteringActiveDialingOrConnecting();
                 break;
             case CallState.RINGING:
                 onCallEnteringRinging();
@@ -434,14 +428,14 @@
                 onCallEnteringHold();
                 break;
             case CallState.DIALING:
-                onCallEnteringActiveOrDialing();
+                onCallEnteringActiveDialingOrConnecting();
                 playRingbackForCall(call);
                 break;
         }
     }
 
-    private void onCallLeavingActiveOrDialing() {
-        if (mActiveOrDialingCalls.size() == 0) {
+    private void onCallLeavingActiveDialingOrConnecting() {
+        if (mActiveDialingOrConnectingCalls.size() == 0) {
             mCallAudioModeStateMachine.sendMessage(
                     CallAudioModeStateMachine.NO_MORE_ACTIVE_OR_DIALING_CALLS,
                     makeArgsForModeStateMachine());
@@ -462,8 +456,8 @@
         }
     }
 
-    private void onCallEnteringActiveOrDialing() {
-        if (mActiveOrDialingCalls.size() == 1) {
+    private void onCallEnteringActiveDialingOrConnecting() {
+        if (mActiveDialingOrConnectingCalls.size() == 1) {
             mCallAudioModeStateMachine.sendMessage(
                     CallAudioModeStateMachine.NEW_ACTIVE_OR_DIALING_CALL,
                     makeArgsForModeStateMachine());
@@ -486,8 +480,16 @@
 
     private void updateForegroundCall() {
         Call oldForegroundCall = mForegroundCall;
-        if (mActiveOrDialingCalls.size() > 0) {
-            mForegroundCall = mActiveOrDialingCalls.iterator().next();
+        if (mActiveDialingOrConnectingCalls.size() > 0) {
+            // Give preference for connecting calls over active/dialing for foreground-ness.
+            Call possibleConnectingCall = null;
+            for (Call call : mActiveDialingOrConnectingCalls) {
+                if (call.getState() == CallState.CONNECTING) {
+                    possibleConnectingCall = call;
+                }
+            }
+            mForegroundCall = possibleConnectingCall == null ?
+                    mActiveDialingOrConnectingCalls.iterator().next() : possibleConnectingCall;
         } else if (mRingingCalls.size() > 0) {
             mForegroundCall = mRingingCalls.iterator().next();
         } else if (mHoldingCalls.size() > 0) {
@@ -505,7 +507,7 @@
     @NonNull
     private CallAudioModeStateMachine.MessageArgs makeArgsForModeStateMachine() {
         return new CallAudioModeStateMachine.MessageArgs(
-                mActiveOrDialingCalls.size() > 0,
+                mActiveDialingOrConnectingCalls.size() > 0,
                 mRingingCalls.size() > 0,
                 mHoldingCalls.size() > 0,
                 mIsTonePlaying,
@@ -617,4 +619,14 @@
             if (call != null) pw.println(call.getId());
         }
     }
+
+    private void maybeStopRingingAndCallWaitingForAnsweredOrRejectedCall(Call call) {
+        // Check to see if the call being answered/rejected is the only ringing call, since this
+        // will be called before the connection service acknowledges the state change.
+        if (mRingingCalls.size() == 0 ||
+                (mRingingCalls.size() == 1 && call == mRingingCalls.iterator().next())) {
+            mRinger.stopRinging();
+            mRinger.stopCallWaiting();
+        }
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/server/telecom/CallsManager.java b/src/com/android/server/telecom/CallsManager.java
index 7682796..73d5556 100644
--- a/src/com/android/server/telecom/CallsManager.java
+++ b/src/com/android/server/telecom/CallsManager.java
@@ -235,7 +235,7 @@
                 callAudioRoutePeripheralAdapter, lock);
 
         SystemSettingsUtil systemSettingsUtil = new SystemSettingsUtil();
-        RingtoneFactory ringtoneFactory = new RingtoneFactory(context);
+        RingtoneFactory ringtoneFactory = new RingtoneFactory(this, context);
         SystemVibrator systemVibrator = new SystemVibrator(context);
         AsyncRingtonePlayer asyncRingtonePlayer = new AsyncRingtonePlayer();
         mInCallController = new InCallController(context, mLock, this, systemStateProvider);
diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java
index 1feb356..5543f9b 100644
--- a/src/com/android/server/telecom/ConnectionServiceWrapper.java
+++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java
@@ -492,6 +492,7 @@
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
+                    Bundle.setDefusable(extras, true);
                     logIncoming("setExtras %s %s", callId, extras);
                     Call call = mCallIdMapper.getCall(callId);
                     if (call != null) {
@@ -589,14 +590,15 @@
         }
 
         @Override
-        public void onConnectionEvent(String callId, String event) {
+        public void onConnectionEvent(String callId, String event, Bundle extras) {
             Log.startSession("CSW.oCE");
             long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mLock) {
+                    Bundle.setDefusable(extras, true);
                     Call call = mCallIdMapper.getCall(callId);
                     if (call != null) {
-                        call.onConnectionEvent(event);
+                        call.onConnectionEvent(event, extras);
                     }
                 }
             } finally {
@@ -812,7 +814,7 @@
                 logOutgoing("reject %s", callId);
 
                 if (rejectWithMessage && call.can(
-                        android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
+                        Connection.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
                     mServiceInterface.rejectWithMessage(callId, message);
                 } else {
                     mServiceInterface.reject(callId);
@@ -938,6 +940,28 @@
         }
     }
 
+    void pullExternalCall(Call call) {
+        final String callId = mCallIdMapper.getCallId(call);
+        if (callId != null && isServiceValid("pullExternalCall")) {
+            try {
+                logOutgoing("pullExternalCall %s", callId);
+                mServiceInterface.pullExternalCall(callId);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
+    void sendCallEvent(Call call, String event, Bundle extras) {
+        final String callId = mCallIdMapper.getCallId(call);
+        if (callId != null && isServiceValid("sendCallEvent")) {
+            try {
+                logOutgoing("sendCallEvent %s %s", callId, event);
+                mServiceInterface.sendCallEvent(callId, event, extras);
+            } catch (RemoteException ignored) {
+            }
+        }
+    }
+
     /** {@inheritDoc} */
     @Override
     protected void setServiceInterface(IBinder binder) {
diff --git a/src/com/android/server/telecom/InCallAdapter.java b/src/com/android/server/telecom/InCallAdapter.java
index bee03a2..4dd06d2 100644
--- a/src/com/android/server/telecom/InCallAdapter.java
+++ b/src/com/android/server/telecom/InCallAdapter.java
@@ -17,6 +17,7 @@
 package com.android.server.telecom;
 
 import android.os.Binder;
+import android.os.Bundle;
 import android.telecom.PhoneAccountHandle;
 
 import com.android.internal.telecom.IInCallAdapter;
@@ -370,6 +371,50 @@
     }
 
     @Override
+    public void pullExternalCall(String callId) {
+        try {
+            Log.startSession("ICA.pEC", mOwnerComponentName);
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        call.pullExternalCall();
+                    } else {
+                        Log.w(this, "pullExternalCall, unknown call id: %s", callId);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        } finally {
+            Log.endSession();
+        }
+    }
+
+    @Override
+    public void sendCallEvent(String callId, String event, Bundle extras) {
+        try {
+            Log.startSession("ICA.sCE", mOwnerComponentName);
+            long token = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    Call call = mCallIdMapper.getCall(callId);
+                    if (call != null) {
+                        call.sendCallEvent(event, extras);
+                    } else {
+                        Log.w(this, "sendCallEvent, unknown call id: %s", callId);
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        } finally {
+            Log.endSession();
+        }
+    }
+
+    @Override
     public void turnOnProximitySensor() {
         try {
             Log.startSession("ICA.tOnPS", mOwnerComponentName);
diff --git a/src/com/android/server/telecom/InCallController.java b/src/com/android/server/telecom/InCallController.java
index 150879d..93589ed 100644
--- a/src/com/android/server/telecom/InCallController.java
+++ b/src/com/android/server/telecom/InCallController.java
@@ -25,6 +25,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -132,6 +133,11 @@
         public void onConferenceableCallsChanged(Call call) {
             updateCall(call);
         }
+
+        @Override
+        public void onConnectionEvent(Call call, String event, Bundle extras) {
+            notifyConnectionEvent(call, event, extras);
+        }
     };
 
     private final SystemStateListener mSystemStateListener = new SystemStateListener() {
@@ -321,6 +327,17 @@
         }
     }
 
+    private void notifyConnectionEvent(Call call, String event, Bundle extras) {
+        if (!mInCallServices.isEmpty()) {
+            for (IInCallService inCallService : mInCallServices.values()) {
+                try {
+                    inCallService.onConnectionEvent(mCallIdMapper.getCallId(call), event, extras);
+                } catch (RemoteException ignored) {
+                }
+            }
+        }
+    }
+
     /**
      * Unbinds an existing bound connection to the in-call app.
      */
diff --git a/src/com/android/server/telecom/Log.java b/src/com/android/server/telecom/Log.java
index 7b9bcfd..58406f2 100644
--- a/src/com/android/server/telecom/Log.java
+++ b/src/com/android/server/telecom/Log.java
@@ -103,6 +103,7 @@
         public static final String BLOCK_CHECK_FINISHED = "BLOCK_CHECK_FINISHED";
         public static final String REMOTELY_HELD = "REMOTELY_HELD";
         public static final String REMOTELY_UNHELD = "REMOTELY_UNHELD";
+        public static final String PULL = "PULL";
 
         /**
          * Maps from a request to a response.  The same event could be listed as the
diff --git a/src/com/android/server/telecom/ParcelableCallUtils.java b/src/com/android/server/telecom/ParcelableCallUtils.java
index ae8e425..3f5b804 100644
--- a/src/com/android/server/telecom/ParcelableCallUtils.java
+++ b/src/com/android/server/telecom/ParcelableCallUtils.java
@@ -231,7 +231,10 @@
         android.telecom.Call.Details.CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION,
 
         Connection.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
-        android.telecom.Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO
+        android.telecom.Call.Details.CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO,
+
+        Connection.CAPABILITY_CAN_PULL_CALL,
+        android.telecom.Call.Details.CAPABILITY_CAN_PULL_CALL
     };
 
     private static int convertConnectionToCallCapabilities(int connectionCapabilities) {
@@ -257,7 +260,10 @@
         android.telecom.Call.Details.PROPERTY_GENERIC_CONFERENCE,
 
         Connection.CAPABILITY_SHOW_CALLBACK_NUMBER,
-        android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE
+        android.telecom.Call.Details.PROPERTY_EMERGENCY_CALLBACK_MODE,
+
+        Connection.CAPABILITY_IS_EXTERNAL_CALL,
+        android.telecom.Call.Details.PROPERTY_IS_EXTERNAL_CALL
     };
 
     private static int convertConnectionToCallProperties(int connectionCapabilities) {
diff --git a/src/com/android/server/telecom/Ringer.java b/src/com/android/server/telecom/Ringer.java
index ddd2e93..8a2b41c 100644
--- a/src/com/android/server/telecom/Ringer.java
+++ b/src/com/android/server/telecom/Ringer.java
@@ -124,7 +124,7 @@
             // 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.
-            mRingtonePlayer.play(mRingtoneFactory, foregroundCall.getRingtone());
+            mRingtonePlayer.play(mRingtoneFactory, foregroundCall);
         } else {
             Log.v(this, "startRingingOrCallWaiting, skipping because volume is 0");
         }
diff --git a/src/com/android/server/telecom/RingtoneFactory.java b/src/com/android/server/telecom/RingtoneFactory.java
index 5044a90..5e4fe9d 100644
--- a/src/com/android/server/telecom/RingtoneFactory.java
+++ b/src/com/android/server/telecom/RingtoneFactory.java
@@ -17,36 +17,110 @@
 package com.android.server.telecom;
 
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
 import android.media.AudioManager;
 import android.media.RingtoneManager;
 import android.media.Ringtone;
 import android.net.Uri;
+import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
+import android.telecom.PhoneAccount;
+import android.text.TextUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.CallerInfo;
+
+import java.util.List;
 
 /**
- * Uses a Uri to obtain a {@link Ringtone} from the {@link RingtoneManager} that can be played
- * by the system during an incoming call.
+ * Uses the incoming {@link Call}'s ringtone URI (obtained by the Contact Lookup) to obtain a
+ * {@link Ringtone} from the {@link RingtoneManager} that can be played by the system during an
+ * incoming call. If the ringtone URI is null, use the default Ringtone for the active user.
  */
 @VisibleForTesting
 public class RingtoneFactory {
 
     private final Context mContext;
+    private final CallsManager mCallsManager;
 
-    public RingtoneFactory(Context context) {
+    public RingtoneFactory(CallsManager callsManager, Context context) {
         mContext = context;
+        mCallsManager = callsManager;
     }
 
-    public Ringtone getRingtone(Uri ringtoneUri) {
-        if (ringtoneUri == null) {
-            ringtoneUri = Settings.System.DEFAULT_RINGTONE_URI;
-        }
+    public Ringtone getRingtone(Call incomingCall) {
+        // Use the default ringtone of the work profile if the contact is a work profile contact.
+        Context userContext = isWorkContact(incomingCall) ?
+                getWorkProfileContextForUser(mCallsManager.getCurrentUserHandle()) :
+                getContextForUserHandle(mCallsManager.getCurrentUserHandle());
+        Uri ringtoneUri = incomingCall.getRingtone();
+        Ringtone ringtone = null;
 
-        Ringtone ringtone = RingtoneManager.getRingtone(mContext, ringtoneUri);
+        if(ringtoneUri != null && userContext != null) {
+            // Ringtone URI is explicitly specified. First, try to create a Ringtone with that.
+            ringtone = RingtoneManager.getRingtone(userContext, ringtoneUri);
+        }
+        if(ringtone == null) {
+            // Contact didn't specify ringtone or custom Ringtone creation failed. Get default
+            // ringtone for user or profile.
+            ringtone = RingtoneManager.getRingtone(
+                    hasDefaultRingtoneForUser(userContext) ? userContext : mContext,
+                    Settings.System.DEFAULT_RINGTONE_URI);
+        }
         if (ringtone != null) {
             ringtone.setStreamType(AudioManager.STREAM_RING);
         }
         return ringtone;
     }
+
+    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).
+        List<UserInfo> profiles = UserManager.get(mContext).getEnabledProfiles(
+                userHandle.getIdentifier());
+        UserInfo workprofile = null;
+        int managedProfileCount = 0;
+        for (UserInfo profile : profiles) {
+            UserHandle profileUserHandle = profile.getUserHandle();
+            if (profileUserHandle != userHandle && profile.isManagedProfile()) {
+                managedProfileCount++;
+                workprofile = profile;
+            }
+        }
+        // There may be many different types of profiles, so only count Managed (Work) Profiles.
+        if(managedProfileCount == 1) {
+            return getContextForUserHandle(workprofile.getUserHandle());
+        }
+        // There are multiple managed profiles for the associated user and we do not have enough
+        // info to determine which profile is the work profile. Just use the default.
+        return null;
+    }
+
+    private Context getContextForUserHandle(UserHandle userHandle) {
+        if(userHandle == null) {
+            return null;
+        }
+        try {
+            return mContext.createPackageContextAsUser(mContext.getPackageName(), 0, userHandle);
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w("RingtoneFactory", "Package name not found: " + e.getMessage());
+        }
+        return null;
+    }
+
+    private boolean hasDefaultRingtoneForUser(Context userContext) {
+        if(userContext == null) {
+            return false;
+        }
+        return !TextUtils.isEmpty(Settings.System.getString(userContext.getContentResolver(),
+                Settings.System.RINGTONE));
+    }
+
+    private boolean isWorkContact(Call incomingCall) {
+        CallerInfo contactCallerInfo = incomingCall.getCallerInfo();
+        return (contactCallerInfo != null) &&
+                (contactCallerInfo.userType == CallerInfo.USER_TYPE_WORK);
+    }
 }
diff --git a/src/com/android/server/telecom/TelecomServiceImpl.java b/src/com/android/server/telecom/TelecomServiceImpl.java
index c0dc930..07b4ae7 100644
--- a/src/com/android/server/telecom/TelecomServiceImpl.java
+++ b/src/com/android/server/telecom/TelecomServiceImpl.java
@@ -977,6 +977,7 @@
                                     phoneAccountHandle);
                             intent.putExtra(CallIntentProcessor.KEY_IS_INCOMING_CALL, true);
                             if (extras != null) {
+                                extras.setDefusable(true);
                                 intent.putExtra(TelecomManager.EXTRA_INCOMING_CALL_EXTRAS, extras);
                             }
                             mCallIntentProcessorAdapter.processIncomingCallIntent(
@@ -1016,7 +1017,10 @@
 
                         try {
                             Intent intent = new Intent(TelecomManager.ACTION_NEW_UNKNOWN_CALL);
-                            intent.putExtras(extras);
+                            if (extras != null) {
+                                extras.setDefusable(true);
+                                intent.putExtras(extras);
+                            }
                             intent.putExtra(CallIntentProcessor.KEY_IS_UNKNOWN_CALL, true);
                             intent.putExtra(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
                                     phoneAccountHandle);
@@ -1066,7 +1070,10 @@
                     long token = Binder.clearCallingIdentity();
                     try {
                         final Intent intent = new Intent(Intent.ACTION_CALL, handle);
-                        intent.putExtras(extras);
+                        if (extras != null) {
+                            extras.setDefusable(true);
+                            intent.putExtras(extras);
+                        }
                         mUserCallIntentProcessorFactory.create(mContext, userHandle)
                                 .processIntent(
                                         intent, callingPackage, hasCallAppOp && hasCallPermission);
diff --git a/src/com/android/server/telecom/WiredHeadsetManager.java b/src/com/android/server/telecom/WiredHeadsetManager.java
index 253dfca..b73c013 100644
--- a/src/com/android/server/telecom/WiredHeadsetManager.java
+++ b/src/com/android/server/telecom/WiredHeadsetManager.java
@@ -16,10 +16,9 @@
 
 package com.android.server.telecom;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
+import android.media.AudioDeviceCallback;
+import android.media.AudioDeviceInfo;
 import android.media.AudioManager;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -32,30 +31,47 @@
 /** Listens for and caches headset state. */
 @VisibleForTesting
 public class WiredHeadsetManager {
+    private static final int VALID_WIRED_DEVICES = AudioManager.DEVICE_OUT_WIRED_HEADSET |
+            AudioManager.DEVICE_OUT_WIRED_HEADPHONE |
+            AudioManager.DEVICE_OUT_USB_DEVICE;
+
     @VisibleForTesting
     public interface Listener {
         void onWiredHeadsetPluggedInChanged(boolean oldIsPluggedIn, boolean newIsPluggedIn);
     }
 
     /** Receiver for wired headset plugged and unplugged events. */
-    private class WiredHeadsetBroadcastReceiver extends BroadcastReceiver {
+    private class WiredHeadsetCallback extends AudioDeviceCallback {
         @Override
-        public void onReceive(Context context, Intent intent) {
-            Log.startSession("WHBR.oR");
+        public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
+            Log.startSession("WHC.oADA");
             try {
-                if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
-                    boolean isPluggedIn = mAudioManager.isWiredHeadsetOn();
-                    Log.v(WiredHeadsetManager.this, "ACTION_HEADSET_PLUG event, plugged in: %b",
-                            isPluggedIn);
-                    onHeadsetPluggedInChanged(isPluggedIn);
-                }
+                updateHeadsetStatus();
             } finally {
                 Log.endSession();
             }
         }
+
+        @Override
+        public void onAudioDevicesRemoved(AudioDeviceInfo[] devices) {
+            Log.startSession("WHC.oADR");
+            try {
+                updateHeadsetStatus();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        private void updateHeadsetStatus() {
+            int devices = mAudioManager.getDevicesForStream(AudioManager.STREAM_VOICE_CALL);
+
+            boolean isPluggedIn = (devices & VALID_WIRED_DEVICES) != 0;
+            Log.i(WiredHeadsetManager.this, "ACTION_HEADSET_PLUG event, plugged in: %b, " +
+                    "devices: %s", isPluggedIn, Integer.toHexString(devices));
+            onHeadsetPluggedInChanged(isPluggedIn);
+        }
     }
 
-    private final WiredHeadsetBroadcastReceiver mReceiver;
     private final AudioManager mAudioManager;
     private boolean mIsPluggedIn;
     /**
@@ -64,17 +80,13 @@
      * access the map so make only a single shard
      */
     private final Set<Listener> mListeners = Collections.newSetFromMap(
-            new ConcurrentHashMap<Listener, Boolean>(8, 0.9f, 1));
+            new ConcurrentHashMap<>(8, 0.9f, 1));
 
     public WiredHeadsetManager(Context context) {
-        mReceiver = new WiredHeadsetBroadcastReceiver();
-
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
         mIsPluggedIn = mAudioManager.isWiredHeadsetOn();
 
-        // Register for misc other intent broadcasts.
-        IntentFilter intentFilter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
-        context.registerReceiver(mReceiver, intentFilter);
+        mAudioManager.registerAudioDeviceCallback(new WiredHeadsetCallback(), null);
     }
 
     @VisibleForTesting
diff --git a/src/com/android/server/telecom/components/TelecomService.java b/src/com/android/server/telecom/components/TelecomService.java
index 8e4ae57..ad4fd76 100644
--- a/src/com/android/server/telecom/components/TelecomService.java
+++ b/src/com/android/server/telecom/components/TelecomService.java
@@ -26,6 +26,7 @@
 import android.os.ServiceManager;
 
 import com.android.internal.telephony.CallerInfoAsyncQuery;
+import com.android.server.telecom.BluetoothAdapterProxy;
 import com.android.server.telecom.BluetoothPhoneServiceImpl;
 import com.android.server.telecom.CallerInfoAsyncQueryFactory;
 import com.android.server.telecom.CallsManager;
@@ -140,7 +141,8 @@
                                         CallsManager callsManager,
                                         PhoneAccountRegistrar phoneAccountRegistrar) {
                                     return new BluetoothPhoneServiceImpl(context, lock,
-                                            callsManager, phoneAccountRegistrar);
+                                            callsManager, new BluetoothAdapterProxy(),
+                                            phoneAccountRegistrar);
                                 }
                             }
                     ));
diff --git a/src/com/android/server/telecom/settings/BlockedNumbersActivity.java b/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
index 5afe33a..a9e6cdd 100644
--- a/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
+++ b/src/com/android/server/telecom/settings/BlockedNumbersActivity.java
@@ -128,7 +128,9 @@
 
     @Override
     protected void onDestroy() {
-        unregisterReceiver(mBlockingStatusReceiver);
+        if (mBlockingStatusReceiver != null) {
+            unregisterReceiver(mBlockingStatusReceiver);
+        }
         super.onDestroy();
     }
 
diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
index 49c47a1..17cfca2 100644
--- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java
+++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java
@@ -68,10 +68,22 @@
 import java.util.concurrent.CyclicBarrier;
 import java.util.concurrent.TimeUnit;
 
+import org.mockito.ArgumentCaptor;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
 /**
  * Performs various basic call tests in Telecom.
  */
 public class BasicCallTests extends TelecomSystemTest {
+    private static final String TEST_BUNDLE_KEY = "android.telecom.extra.TEST";
+    private static final String TEST_EVENT = "android.telecom.event.TEST";
+
     @LargeTest
     public void testSingleOutgoingCallLocalDisconnect() throws Exception {
         IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212",
@@ -238,6 +250,33 @@
     }
 
     @LargeTest
+    public void testOutgoingCallAndSelectPhoneAccount() throws Exception {
+        // Remove default PhoneAccount so that the Call moves into the correct
+        // SELECT_PHONE_ACCOUNT state.
+        mTelecomSystem.getPhoneAccountRegistrar().setUserSelectedOutgoingPhoneAccount(
+                null, Process.myUserHandle());
+        int startingNumConnections = mConnectionServiceFixtureA.mConnectionById.size();
+        int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
+        String callId = startOutgoingPhoneCallWithNoPhoneAccount("650-555-1212",
+                mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_SELECT_PHONE_ACCOUNT,
+                mInCallServiceFixtureX.getCall(callId).getState());
+        assertEquals(Call.STATE_SELECT_PHONE_ACCOUNT,
+                mInCallServiceFixtureY.getCall(callId).getState());
+        mInCallServiceFixtureX.mInCallAdapter.phoneAccountSelected(callId,
+                mPhoneAccountA0.getAccountHandle(), false);
+
+        IdPair ids = outgoingCallPhoneAccountSelected(mPhoneAccountA0.getAccountHandle(),
+                startingNumConnections, startingNumCalls, mConnectionServiceFixtureA);
+
+        mConnectionServiceFixtureA.sendSetDisconnected(ids.mConnectionId, DisconnectCause.LOCAL);
+        assertEquals(Call.STATE_DISCONNECTED,
+                mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_DISCONNECTED,
+                mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+    }
+
+    @LargeTest
     public void testIncomingCallFromContactWithSendToVoicemailIsRejected() throws Exception {
         Bundle extras = new Bundle();
         extras.putParcelable(
@@ -443,6 +482,7 @@
         mInCallServiceFixtureX.mInCallAdapter.disconnectCall(outgoing.mCallId);
     }
 
+    @LargeTest
     public void testAudioManagerOperations() throws Exception {
         AudioManager audioManager = (AudioManager) mComponentContextFixture.getTestDouble()
                 .getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
@@ -568,6 +608,101 @@
         return conferenceCall;
     }
 
+    /**
+     * Tests the {@link Call#pullExternalCall()} API.  Verifies that if a call is not an external
+     * call, no pull call request is made to the connection service.
+     *
+     * @throws Exception
+     */
+    @MediumTest
+    public void testPullNonExternalCall() throws Exception {
+        // TODO: Revisit this unit test once telecom support for filtering external calls from
+        // InCall services is implemented.
+        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+
+        // Attempt to pull the call and verify the API call makes it through
+        mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId);
+        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT).never())
+                .pullExternalCall(ids.mCallId);
+    }
+
+    /**
+     * Tests the {@link Connection#sendConnectionEvent(String)} API.
+     *
+     * @throws Exception
+     */
+    @MediumTest
+    public void testSendConnectionEventNull() throws Exception {
+        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        mConnectionServiceFixtureA.sendConnectionEvent(ids.mConnectionId, TEST_EVENT, null);
+        verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
+                .onConnectionEvent(ids.mCallId, TEST_EVENT, null);
+    }
+
+    /**
+     * Tests the {@link Connection#sendConnectionEvent(String)} API.
+     *
+     * @throws Exception
+     */
+    @MediumTest
+    public void testSendConnectionEventNotNull() throws Exception {
+        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+
+        Bundle testBundle = new Bundle();
+        testBundle.putString(TEST_BUNDLE_KEY, "TEST");
+
+        ArgumentCaptor<Bundle> bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class);
+        mConnectionServiceFixtureA.sendConnectionEvent(ids.mConnectionId, TEST_EVENT, testBundle);
+        verify(mInCallServiceFixtureX.getTestDouble(), timeout(TEST_TIMEOUT))
+                .onConnectionEvent(eq(ids.mCallId), eq(TEST_EVENT), bundleArgumentCaptor.capture());
+        assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY));
+    }
+
+    /**
+     * Tests the {@link Call#sendCallEvent(String, Bundle)} API.
+     *
+     * @throws Exception
+     */
+    @MediumTest
+    public void testSendCallEventNull() throws Exception {
+        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+
+        mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT, null);
+        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
+                .sendCallEvent(ids.mCallId, TEST_EVENT, null);
+    }
+
+    /**
+     * Tests the {@link Call#sendCallEvent(String, Bundle)} API.
+     *
+     * @throws Exception
+     */
+    @MediumTest
+    public void testSendCallEventNonNull() throws Exception {
+        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+
+        Bundle testBundle = new Bundle();
+        testBundle.putString(TEST_BUNDLE_KEY, "TEST");
+
+        ArgumentCaptor<Bundle> bundleArgumentCaptor = ArgumentCaptor.forClass(Bundle.class);
+        mInCallServiceFixtureX.mInCallAdapter.sendCallEvent(ids.mCallId, TEST_EVENT,
+                testBundle);
+        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
+                .sendCallEvent(eq(ids.mCallId), eq(TEST_EVENT),
+                        bundleArgumentCaptor.capture());
+        assert (bundleArgumentCaptor.getValue().containsKey(TEST_BUNDLE_KEY));
+    }
+
     @MediumTest
     public void testAnalyticsSingleCall() throws Exception {
         IdPair testCall = startAndMakeActiveIncomingCall(
@@ -725,4 +860,51 @@
         assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureX.getCall(callId).getState());
         assertEquals(Call.STATE_DISCONNECTED, mInCallServiceFixtureY.getCall(callId).getState());
     }
+
+    /**
+     * Tests the {@link Call#pullExternalCall()} API.  Ensures that an external call which is
+     * pullable can be pulled.
+     *
+     * @throws Exception
+     */
+    @LargeTest
+    public void testPullExternalCall() throws Exception {
+        // TODO: Revisit this unit test once telecom support for filtering external calls from
+        // InCall services is implemented.
+        mConnectionServiceFixtureA.mConnectionServiceDelegate.mCapabilities =
+                Connection.CAPABILITY_IS_EXTERNAL_CALL | Connection.CAPABILITY_CAN_PULL_CALL;
+
+        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+
+        // Attempt to pull the call and verify the API call makes it through
+        mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId);
+        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT))
+                .pullExternalCall(ids.mCallId);
+    }
+
+    /**
+     * Tests the {@link Call#pullExternalCall()} API.  Verifies that if an external call is not
+     * marked as pullable that the connection service does not get an API call to pull the external
+     * call.
+     *
+     * @throws Exception
+     */
+    @LargeTest
+    public void testPullNonPullableExternalCall() throws Exception {
+        // TODO: Revisit this unit test once telecom support for filtering external calls from
+        // InCall services is implemented.
+        mConnectionServiceFixtureA.mConnectionServiceDelegate.mCapabilities =
+                Connection.CAPABILITY_IS_EXTERNAL_CALL;
+
+        IdPair ids = startAndMakeActiveIncomingCall("650-555-1212",
+                mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+
+        // Attempt to pull the call and verify the API call makes it through
+        mInCallServiceFixtureX.mInCallAdapter.pullExternalCall(ids.mCallId);
+        verify(mConnectionServiceFixtureA.getTestDouble(), timeout(TEST_TIMEOUT).never())
+                .pullExternalCall(ids.mCallId);
+    }
 }
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothManagerTest.java b/tests/src/com/android/server/telecom/tests/BluetoothManagerTest.java
index 09ef9e1..d9a9e14 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothManagerTest.java
@@ -23,6 +23,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.server.telecom.BluetoothAdapterProxy;
 import com.android.server.telecom.BluetoothHeadsetProxy;
@@ -72,24 +73,28 @@
         mBluetoothManager.setBluetoothHeadsetForTesting(mHeadsetProxy);
     }
 
+    @SmallTest
     public void testIsBluetoothAvailableWithNoDevices() {
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
                 Collections.<BluetoothDevice>emptyList());
         assertFalse(mBluetoothManager.isBluetoothAvailable());
     }
 
+    @SmallTest
     public void testIsBluetoothAvailable() {
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
                 Collections.singletonList(device1));
         assertTrue(mBluetoothManager.isBluetoothAvailable());
     }
 
+    @SmallTest
     public void testIsAudioConnectedWithNoDevices() {
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
                 Collections.<BluetoothDevice>emptyList());
         assertFalse(mBluetoothManager.isBluetoothAudioConnected());
     }
 
+    @SmallTest
     public void testIsAudioConnectedWhenAudioNotOn() {
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
                 Collections.singletonList(device1));
@@ -97,6 +102,7 @@
         assertFalse(mBluetoothManager.isBluetoothAudioConnected());
     }
 
+    @SmallTest
     public void testIsAudioConnectedWhenAudioOn() {
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
                 Collections.singletonList(device1));
@@ -104,6 +110,7 @@
         assertTrue(mBluetoothManager.isBluetoothAudioConnected());
     }
 
+    @SmallTest
     public void testShouldBePendingAfterConnectAudio() {
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
                 Collections.singletonList(device1));
@@ -114,17 +121,20 @@
         assertTrue(mBluetoothManager.isBluetoothAudioConnectedOrPending());
     }
 
+    @SmallTest
     public void testDisconnectAudioWhenHeadsetServiceConnected() {
         mBluetoothManager.disconnectBluetoothAudio();
         verify(mHeadsetProxy).disconnectAudio();
     }
 
+    @SmallTest
     public void testDisconnectAudioWithNoHeadsetService() {
         mBluetoothManager.setBluetoothHeadsetForTesting(null);
         mBluetoothManager.disconnectBluetoothAudio();
         verify(mHeadsetProxy, never()).disconnectAudio();
     }
 
+    @SmallTest
     public void testConnectServiceWhenUninitialized1() {
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
                 Collections.<BluetoothDevice>emptyList());
@@ -133,6 +143,7 @@
                 BluetoothManager.BLUETOOTH_DISCONNECTED);
     }
 
+    @SmallTest
     public void testConnectServiceWhenUninitialized2() {
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
                 Collections.singletonList(device1));
@@ -142,6 +153,7 @@
                 BluetoothManager.BLUETOOTH_DEVICE_CONNECTED);
     }
 
+    @SmallTest
     public void testConnectServiceWhenUninitialized3() {
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
                 Collections.singletonList(device1));
@@ -151,6 +163,7 @@
                 BluetoothManager.BLUETOOTH_AUDIO_CONNECTED);
     }
 
+    @SmallTest
     public void testReceiveAudioDisconnectWhenConnected() {
         mBluetoothManager.setInternalBluetoothState(BluetoothManager.BLUETOOTH_AUDIO_CONNECTED);
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
@@ -162,6 +175,7 @@
                 BluetoothManager.BLUETOOTH_DEVICE_CONNECTED);
     }
 
+    @SmallTest
     public void testReceiveAudioConnectWhenDisconnected() {
         mBluetoothManager.setInternalBluetoothState(BluetoothManager.BLUETOOTH_DEVICE_CONNECTED);
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
@@ -173,6 +187,7 @@
                 BluetoothManager.BLUETOOTH_AUDIO_CONNECTED);
     }
 
+    @SmallTest
     public void testReceiveAudioConnectWhenPending() {
         mBluetoothManager.setInternalBluetoothState(BluetoothManager.BLUETOOTH_AUDIO_PENDING);
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
@@ -184,6 +199,7 @@
                 BluetoothManager.BLUETOOTH_AUDIO_CONNECTED);
     }
 
+    @SmallTest
     public void testReceiveAudioDisconnectWhenPending() {
         mBluetoothManager.setInternalBluetoothState(BluetoothManager.BLUETOOTH_AUDIO_PENDING);
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
@@ -195,6 +211,7 @@
                 BluetoothManager.BLUETOOTH_DEVICE_CONNECTED);
     }
 
+    @SmallTest
     public void testReceiveAudioConnectingWhenPending() {
         mBluetoothManager.setInternalBluetoothState(BluetoothManager.BLUETOOTH_AUDIO_PENDING);
         when(mHeadsetProxy.getConnectedDevices()).thenReturn(
diff --git a/tests/src/com/android/server/telecom/tests/BluetoothPhoneServiceTest.java b/tests/src/com/android/server/telecom/tests/BluetoothPhoneServiceTest.java
index 74a2d64..9052134 100644
--- a/tests/src/com/android/server/telecom/tests/BluetoothPhoneServiceTest.java
+++ b/tests/src/com/android/server/telecom/tests/BluetoothPhoneServiceTest.java
@@ -30,7 +30,10 @@
 import android.telecom.TelecomManager;
 import android.telephony.PhoneNumberUtils;
 import android.telephony.TelephonyManager;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.server.telecom.BluetoothAdapterProxy;
 import com.android.server.telecom.BluetoothHeadsetProxy;
 import com.android.server.telecom.BluetoothPhoneServiceImpl;
 import com.android.server.telecom.Call;
@@ -107,7 +110,7 @@
         doReturn(null).when(mMockCallsManager).getOutgoingCall();
         doReturn(0).when(mMockCallsManager).getNumHeldCalls();
         mBluetoothPhoneService = new BluetoothPhoneServiceImpl(mContext, mLock, mMockCallsManager,
-                mMockPhoneAccountRegistrar);
+                mock(BluetoothAdapterProxy.class), mMockPhoneAccountRegistrar);
 
         // Bring in test Bluetooth Headset
         mBluetoothPhoneService.setBluetoothHeadset(mMockBluetoothHeadset);
@@ -120,6 +123,7 @@
         super.tearDown();
     }
 
+    @SmallTest
     public void testHeadsetAnswerCall() throws Exception {
         Call mockCall = createRingingCall();
 
@@ -129,6 +133,7 @@
         assertEquals(callAnswered, true);
     }
 
+    @SmallTest
     public void testHeadsetAnswerCallNull() throws Exception {
         when(mMockCallsManager.getRingingCall()).thenReturn(null);
 
@@ -138,6 +143,7 @@
         assertEquals(callAnswered, false);
     }
 
+    @SmallTest
     public void testHeadsetHangupCall() throws Exception {
         Call mockCall = createForegroundCall();
 
@@ -147,6 +153,7 @@
         assertEquals(callHungup, true);
     }
 
+    @SmallTest
     public void testHeadsetHangupCallNull() throws Exception {
         when(mMockCallsManager.getForegroundCall()).thenReturn(null);
 
@@ -156,6 +163,7 @@
         assertEquals(callHungup, false);
     }
 
+    @SmallTest
     public void testHeadsetSendDTMF() throws Exception {
         Call mockCall = createForegroundCall();
 
@@ -166,6 +174,7 @@
         assertEquals(sentDtmf, true);
     }
 
+    @SmallTest
     public void testHeadsetSendDTMFNull() throws Exception {
         when(mMockCallsManager.getForegroundCall()).thenReturn(null);
 
@@ -176,6 +185,7 @@
         assertEquals(sentDtmf, false);
     }
 
+    @SmallTest
     public void testGetNetworkOperator() throws Exception {
         Call mockCall = createForegroundCall();
         PhoneAccount fakePhoneAccount = makeQuickAccount("id0", TEST_ACCOUNT_INDEX);
@@ -187,6 +197,7 @@
         assertEquals(networkOperator, "label0");
     }
 
+    @SmallTest
     public void testGetNetworkOperatorNoPhoneAccount() throws Exception {
         when(mMockCallsManager.getForegroundCall()).thenReturn(null);
 
@@ -195,6 +206,7 @@
         assertEquals(networkOperator, "label1");
     }
 
+    @SmallTest
     public void testGetSubscriberNumber() throws Exception {
         Call mockCall = createForegroundCall();
         PhoneAccount fakePhoneAccount = makeQuickAccount("id0", TEST_ACCOUNT_INDEX);
@@ -206,6 +218,7 @@
         assertEquals(subscriberNumber, TEST_ACCOUNT_ADDRESS + TEST_ACCOUNT_INDEX);
     }
 
+    @SmallTest
     public void testGetSubscriberNumberFallbackToTelephony() throws Exception {
         Call mockCall = createForegroundCall();
         String fakeNumber = "8675309";
@@ -220,6 +233,7 @@
         assertEquals(subscriberNumber, fakeNumber);
     }
 
+    @MediumTest
     public void testListCurrentCallsOneCall() throws Exception {
         ArrayList<Call> calls = new ArrayList<>();
         Call activeCall = createActiveCall();
@@ -236,6 +250,7 @@
         verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
     }
 
+    @MediumTest
     public void testConferenceInProgressCDMA() throws Exception {
         // If two calls are being conferenced and updateHeadsetWithCallState runs while this is
         // still occuring, it will look like there is an active and held call still while we are
@@ -285,6 +300,7 @@
                 any(int.class), any(int.class), any(String.class), any(int.class));
     }
 
+    @MediumTest
     public void testListCurrentCallsCdmaHold() throws Exception {
         // Call has been put into a CDMA "conference" with one call on hold.
         ArrayList<Call> calls = new ArrayList<>();
@@ -325,6 +341,7 @@
         verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
     }
 
+    @MediumTest
     public void testListCurrentCallsCdmaConference() throws Exception {
         // Call is in a true CDMA conference
         ArrayList<Call> calls = new ArrayList<>();
@@ -365,6 +382,7 @@
         verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
     }
 
+    @MediumTest
     public void testWaitingCallClccResponse() throws Exception {
         ArrayList<Call> calls = new ArrayList<>();
         when(mMockCallsManager.getCalls()).thenReturn(calls);
@@ -386,6 +404,7 @@
                 anyInt(), anyInt(), anyInt(), anyBoolean(), anyString(), anyInt());
     }
 
+    @MediumTest
     public void testNewCallClccResponse() throws Exception {
         ArrayList<Call> calls = new ArrayList<>();
         when(mMockCallsManager.getCalls()).thenReturn(calls);
@@ -400,6 +419,7 @@
                 anyInt(), anyInt(), anyInt(), anyBoolean(), anyString(), anyInt());
     }
 
+    @MediumTest
     public void testRingingCallClccResponse() throws Exception {
         ArrayList<Call> calls = new ArrayList<>();
         when(mMockCallsManager.getCalls()).thenReturn(calls);
@@ -419,6 +439,7 @@
                 anyInt(), anyInt(), anyInt(), anyBoolean(), anyString(), anyInt());
     }
 
+    @MediumTest
     public void testCallClccCache() throws Exception {
         ArrayList<Call> calls = new ArrayList<>();
         when(mMockCallsManager.getCalls()).thenReturn(calls);
@@ -452,6 +473,7 @@
         verify(mMockBluetoothHeadset, times(2)).clccResponse(0, 0, 0, 0, false, null, 0);
     }
 
+    @MediumTest
     public void testAlertingCallClccResponse() throws Exception {
         ArrayList<Call> calls = new ArrayList<>();
         when(mMockCallsManager.getCalls()).thenReturn(calls);
@@ -471,6 +493,7 @@
                 anyInt(), anyInt(), anyInt(), anyBoolean(), anyString(), anyInt());
     }
 
+    @MediumTest
     public void testHoldingCallClccResponse() throws Exception {
         ArrayList<Call> calls = new ArrayList<>();
         when(mMockCallsManager.getCalls()).thenReturn(calls);
@@ -499,6 +522,7 @@
                 anyInt(), anyInt(), anyInt(), anyBoolean(), anyString(), anyInt());
     }
 
+    @MediumTest
     public void testListCurrentCallsImsConference() throws Exception {
         ArrayList<Call> calls = new ArrayList<>();
         Call parentCall = createActiveCall();
@@ -516,6 +540,7 @@
         verify(mMockBluetoothHeadset).clccResponse(0, 0, 0, 0, false, null, 0);
     }
 
+    @MediumTest
     public void testQueryPhoneState() throws Exception {
         Call ringingCall = createRingingCall();
         when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
@@ -526,6 +551,7 @@
                 eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown));
     }
 
+    @MediumTest
     public void testCDMAConferenceQueryState() throws Exception {
         Call parentConfCall = createActiveCall();
         final Call confCall1 = mock(Call.class);
@@ -545,6 +571,7 @@
                 eq(""), eq(128));
     }
 
+    @MediumTest
     public void testProcessChldTypeReleaseHeldRinging() throws Exception {
         Call ringingCall = createRingingCall();
 
@@ -554,6 +581,7 @@
         assertEquals(didProcess, true);
     }
 
+    @MediumTest
     public void testProcessChldTypeReleaseHeldHold() throws Exception {
         Call onHoldCall = createHeldCall();
 
@@ -563,6 +591,7 @@
         assertEquals(didProcess, true);
     }
 
+    @MediumTest
     public void testProcessChldReleaseActiveRinging() throws Exception {
         Call activeCall = createActiveCall();
         Call ringingCall = createRingingCall();
@@ -575,6 +604,7 @@
         assertEquals(didProcess, true);
     }
 
+    @MediumTest
     public void testProcessChldReleaseActiveHold() throws Exception {
         Call activeCall = createActiveCall();
         Call heldCall = createHeldCall();
@@ -587,6 +617,7 @@
         assertEquals(didProcess, true);
     }
 
+    @MediumTest
     public void testProcessChldHoldActiveRinging() throws Exception {
         Call ringingCall = createRingingCall();
 
@@ -597,6 +628,7 @@
         assertEquals(didProcess, true);
     }
 
+    @MediumTest
     public void testProcessChldHoldActiveUnhold() throws Exception {
         Call heldCall = createHeldCall();
 
@@ -607,6 +639,7 @@
         assertEquals(didProcess, true);
     }
 
+    @MediumTest
     public void testProcessChldHoldActiveHold() throws Exception {
         Call activeCall = createActiveCall();
         addCallCapability(activeCall, Connection.CAPABILITY_HOLD);
@@ -618,6 +651,7 @@
         assertEquals(didProcess, true);
     }
 
+    @MediumTest
     public void testProcessChldAddHeldToConfHolding() throws Exception {
         Call activeCall = createActiveCall();
         addCallCapability(activeCall, Connection.CAPABILITY_MERGE_CONFERENCE);
@@ -628,6 +662,7 @@
         assertEquals(didProcess, true);
     }
 
+    @MediumTest
     public void testProcessChldAddHeldToConf() throws Exception {
         Call activeCall = createActiveCall();
         removeCallCapability(activeCall, Connection.CAPABILITY_MERGE_CONFERENCE);
@@ -642,6 +677,7 @@
         assertEquals(didProcess, true);
     }
 
+    @MediumTest
     public void testProcessChldHoldActiveSwapConference() throws Exception {
         // Create an active CDMA Call with a call on hold and simulate a swapConference().
         Call parentCall = createActiveCall();
@@ -666,6 +702,7 @@
     }
 
     // Testing the CallsManager Listener Functionality on Bluetooth
+    @MediumTest
     public void testOnCallAddedRinging() throws Exception {
         Call ringingCall = createRingingCall();
         when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-000"));
@@ -677,6 +714,7 @@
 
     }
 
+    @MediumTest
     public void testOnCallAddedCdmaActiveHold() throws Exception {
         // Call has been put into a CDMA "conference" with one call on hold.
         Call parentCall = createActiveCall();
@@ -697,6 +735,7 @@
 
     }
 
+    @MediumTest
     public void testOnCallRemoved() throws Exception {
         Call activeCall = createActiveCall();
         mBluetoothPhoneService.mCallsManagerListener.onCallAdded(activeCall);
@@ -707,6 +746,7 @@
                 eq(""), eq(128));
     }
 
+    @MediumTest
     public void testOnCallStateChangedConnectingCall() throws Exception {
         Call activeCall = mock(Call.class);
         Call connectingCall = mock(Call.class);
@@ -723,6 +763,7 @@
                 anyString(), anyInt());
     }
 
+    @MediumTest
     public void testOnCallStateChangedDialing() throws Exception {
         Call activeCall = createActiveCall();
 
@@ -733,6 +774,7 @@
                 anyString(), anyInt());
     }
 
+    @MediumTest
     public void testOnCallStateChangedAlerting() throws Exception {
         Call outgoingCall = createOutgoingCall();
 
@@ -743,6 +785,7 @@
         verify(mMockBluetoothHeadset).phoneStateChanged(0, 0, CALL_STATE_ALERTING, "", 128);
     }
 
+    @MediumTest
     public void testOnCallStateChanged() throws Exception {
         Call ringingCall = createRingingCall();
         when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
@@ -762,6 +805,7 @@
                 eq(""), eq(128));
     }
 
+    @MediumTest
     public void testOnCallStateChangedGSMSwap() throws Exception {
         Call heldCall = createHeldCall();
         when(heldCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
@@ -773,6 +817,7 @@
                 eq("555-0000"), eq(PhoneNumberUtils.TOA_Unknown));
     }
 
+    @MediumTest
     public void testOnIsConferencedChanged() throws Exception {
         // Start with two calls that are being merged into a CDMA conference call. The
         // onIsConferencedChanged method will be called multiple times during the call. Make sure
@@ -808,6 +853,7 @@
                 eq(""), eq(128));
     }
 
+    @MediumTest
     public void testBluetoothAdapterReceiver() throws Exception {
         Call ringingCall = createRingingCall();
         when(ringingCall.getHandle()).thenReturn(Uri.parse("tel:555-0000"));
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
index 4c32dd7..f9502dd 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioModeStateMachineTest.java
@@ -16,9 +16,7 @@
 
 package com.android.server.telecom.tests;
 
-import android.content.Context;
 import android.media.AudioManager;
-import android.telecom.CallAudioState;
 import android.test.suitebuilder.annotation.LargeTest;
 
 import com.android.server.telecom.CallAudioManager;
diff --git a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
index 7a23923..c4526e4 100644
--- a/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallAudioRouteStateMachineTest.java
@@ -792,4 +792,4 @@
         doNothing().when(mockConnectionServiceWrapper).onCallAudioStateChanged(any(Call.class),
                 any(CallAudioState.class));
     }
-}
\ No newline at end of file
+}
diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
index 30cb1cd..27f169d 100644
--- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java
@@ -60,6 +60,7 @@
  */
 public class ConnectionServiceFixture implements TestFixture<IConnectionService> {
     static int INVALID_VIDEO_STATE = -1;
+    static int CAPABILITIES_NOT_SPECIFIED = 0;
 
     /**
      * Implementation of ConnectionService that performs no-ops for tasks normally meant for
@@ -67,6 +68,7 @@
      */
     public class FakeConnectionServiceDelegate extends ConnectionService {
         int mVideoState = INVALID_VIDEO_STATE;
+        int mCapabilities = CAPABILITIES_NOT_SPECIFIED;
 
         @Override
         public Connection onCreateUnknownConnection(
@@ -77,9 +79,14 @@
         @Override
         public Connection onCreateIncomingConnection(
                 PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
-            return new FakeConnection(
+            FakeConnection fakeConnection =  new FakeConnection(
                     mVideoState == INVALID_VIDEO_STATE ? request.getVideoState() : mVideoState,
                     request.getAddress());
+            if (mCapabilities != CAPABILITIES_NOT_SPECIFIED) {
+                fakeConnection.setConnectionCapabilities(mCapabilities);
+            }
+
+            return fakeConnection;
         }
 
         @Override
@@ -235,6 +242,13 @@
         public void onPostDialContinue(String callId, boolean proceed) throws RemoteException { }
 
         @Override
+        public void pullExternalCall(String callId) throws RemoteException { }
+
+        @Override
+        public void sendCallEvent(String callId, String event, Bundle extras) throws RemoteException
+        {}
+
+        @Override
         public IBinder asBinder() {
             return this;
         }
@@ -471,6 +485,12 @@
         }
     }
 
+    public void sendConnectionEvent(String id, String event, Bundle extras) throws Exception {
+        for (IConnectionServiceAdapter a : mConnectionServiceAdapters) {
+            a.onConnectionEvent(id, event, extras);
+        }
+    }
+
     private ParcelableConference parcelable(ConferenceInfo c) {
         return new ParcelableConference(
                 c.phoneAccount,
diff --git a/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java b/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
index e8bd05c..0104172 100644
--- a/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
+++ b/tests/src/com/android/server/telecom/tests/CreateConnectionProcessorTest.java
@@ -24,6 +24,7 @@
 import android.telecom.DisconnectCause;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallIdMapper;
@@ -83,6 +84,7 @@
         super.tearDown();
     }
 
+    @SmallTest
     public void testSimPhoneAccountSuccess() throws Exception {
         PhoneAccountHandle pAHandle = getNewTargetPhoneAccountHandle("tel_acct");
         when(mMockCall.isEmergencyCall()).thenReturn(false);
@@ -102,6 +104,7 @@
         verify(mMockCreateConnectionResponse).handleCreateConnectionSuccess(mockCallIdMapper, null);
     }
 
+    @SmallTest
     public void testbadPhoneAccount() throws Exception {
         PhoneAccountHandle pAHandle = null;
         when(mMockCall.isEmergencyCall()).thenReturn(false);
@@ -119,6 +122,7 @@
                 eq(new DisconnectCause(DisconnectCause.ERROR)));
     }
 
+    @SmallTest
     public void testConnectionManagerSuccess() throws Exception {
         PhoneAccountHandle pAHandle = getNewTargetPhoneAccountHandle("tel_acct");
         when(mMockCall.isEmergencyCall()).thenReturn(false);
@@ -143,6 +147,7 @@
         verify(mMockCreateConnectionResponse).handleCreateConnectionSuccess(mockCallIdMapper, null);
     }
 
+    @SmallTest
     public void testConnectionManagerFailedFallToSim() throws Exception {
         PhoneAccountHandle pAHandle = getNewTargetPhoneAccountHandle("tel_acct");
         when(mMockCall.isEmergencyCall()).thenReturn(false);
@@ -177,6 +182,7 @@
         verify(mMockCreateConnectionResponse).handleCreateConnectionSuccess(mockCallIdMapper, null);
     }
 
+    @SmallTest
     public void testConnectionManagerFailedDoNotFallToSim() throws Exception {
         PhoneAccountHandle pAHandle = getNewTargetPhoneAccountHandle("tel_acct");
         when(mMockCall.isEmergencyCall()).thenReturn(false);
@@ -206,6 +212,7 @@
                 new DisconnectCause(DisconnectCause.OTHER));
     }
 
+    @SmallTest
     public void testEmergencyCallToSim() throws Exception {
         when(mMockCall.isEmergencyCall()).thenReturn(true);
         // Put in a regular phone account to be sure it doesn't call that
@@ -228,6 +235,7 @@
         verify(mMockCreateConnectionResponse).handleCreateConnectionSuccess(mockCallIdMapper, null);
     }
 
+    @SmallTest
     public void testEmergencyCallSimFailToConnectionManager() throws Exception {
         when(mMockCall.isEmergencyCall()).thenReturn(true);
         when(mMockCall.getHandle()).thenReturn(Uri.parse(""));
diff --git a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
index ee3f691..5d98c0a 100644
--- a/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
+++ b/tests/src/com/android/server/telecom/tests/InCallControllerTests.java
@@ -30,6 +30,7 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.test.mock.MockContext;
+import android.test.suitebuilder.annotation.MediumTest;
 
 import com.android.server.telecom.BluetoothHeadsetProxy;
 import com.android.server.telecom.Call;
@@ -98,6 +99,7 @@
         super.tearDown();
     }
 
+    @MediumTest
     public void testBindToService_NoServicesFound_IncomingCall() throws Exception {
         when(mMockCallsManager.getCurrentUserHandle()).thenReturn(mUserHandle);
         when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
@@ -124,6 +126,7 @@
         assertNull(bindIntent.getExtras());
     }
 
+    @MediumTest
     public void testBindToService_NoServicesFound_OutgoingCall() throws Exception {
         Bundle callExtras = new Bundle();
         callExtras.putBoolean("whatever", true);
diff --git a/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java b/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
index 53e58af..eb007a3 100644
--- a/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
+++ b/tests/src/com/android/server/telecom/tests/InCallServiceFixture.java
@@ -21,6 +21,7 @@
 
 import org.mockito.Mockito;
 
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.IInterface;
 import android.os.RemoteException;
@@ -111,6 +112,11 @@
         }
 
         @Override
+        public void onConnectionEvent(String callId, String event, Bundle extras)
+                throws RemoteException {
+        }
+
+        @Override
         public IBinder asBinder() {
             return this;
         }
diff --git a/tests/src/com/android/server/telecom/tests/InCallWakeLockControllerTest.java b/tests/src/com/android/server/telecom/tests/InCallWakeLockControllerTest.java
index 76bac9f..3a8c2d9 100644
--- a/tests/src/com/android/server/telecom/tests/InCallWakeLockControllerTest.java
+++ b/tests/src/com/android/server/telecom/tests/InCallWakeLockControllerTest.java
@@ -22,6 +22,7 @@
 import static org.mockito.Mockito.never;
 
 import android.os.PowerManager;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallState;
@@ -54,6 +55,7 @@
         super.tearDown();
     }
 
+    @SmallTest
     public void testRingingCallAdded() throws Exception {
         when(mCallsManager.getRingingCall()).thenReturn(mCall);
         when(mWakeLockAdapter.isHeld()).thenReturn(false);
@@ -63,6 +65,7 @@
         verify(mWakeLockAdapter).acquire();
     }
 
+    @SmallTest
     public void testNonRingingCallAdded() throws Exception {
         when(mCallsManager.getRingingCall()).thenReturn(null);
         when(mWakeLockAdapter.isHeld()).thenReturn(false);
@@ -72,6 +75,7 @@
         verify(mWakeLockAdapter, never()).acquire();
     }
 
+    @SmallTest
     public void testRingingCallTransition() throws Exception {
         when(mCallsManager.getRingingCall()).thenReturn(mCall);
         when(mWakeLockAdapter.isHeld()).thenReturn(false);
@@ -81,6 +85,7 @@
         verify(mWakeLockAdapter).acquire();
     }
 
+    @SmallTest
     public void testRingingCallRemoved() throws Exception {
         when(mCallsManager.getRingingCall()).thenReturn(null);
         when(mWakeLockAdapter.isHeld()).thenReturn(false);
@@ -90,6 +95,7 @@
         verify(mWakeLockAdapter, never()).acquire();
     }
 
+    @SmallTest
     public void testWakeLockReleased() throws Exception {
         when(mCallsManager.getRingingCall()).thenReturn(null);
         when(mWakeLockAdapter.isHeld()).thenReturn(true);
@@ -99,6 +105,7 @@
         verify(mWakeLockAdapter).release(0);
     }
 
+    @SmallTest
     public void testAcquireWakeLockWhenHeld() throws Exception {
         when(mCallsManager.getRingingCall()).thenReturn(mCall);
         when(mWakeLockAdapter.isHeld()).thenReturn(true);
diff --git a/tests/src/com/android/server/telecom/tests/LogTest.java b/tests/src/com/android/server/telecom/tests/LogTest.java
index 7db000f..586105f 100644
--- a/tests/src/com/android/server/telecom/tests/LogTest.java
+++ b/tests/src/com/android/server/telecom/tests/LogTest.java
@@ -21,6 +21,7 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
+import android.test.suitebuilder.annotation.MediumTest;
 
 import com.android.internal.os.SomeArgs;
 import com.android.server.telecom.Runnable;
@@ -237,6 +238,7 @@
         super.tearDown();
     }
 
+    @MediumTest
     public void testSingleThreadSession() throws Exception {
         String sessionName = "LT.sTS";
         Log.startSession(sessionName);
@@ -252,6 +254,7 @@
         assertEquals(true, mTestSystemLogger.isMessagesEmpty());
     }
 
+    @MediumTest
     public void testSingleHandlerThreadSession() throws Exception {
         String sessionName = "LT.tSHTS";
         Log.startSession(sessionName);
@@ -275,6 +278,7 @@
         assertEquals(true, mTestSystemLogger.isMessagesEmpty());
     }
 
+    @MediumTest
     public void testSpawnMultipleThreadSessions() throws Exception {
         final String sessionName = "LT.lTR";
         mCompleteCount = new AtomicInteger(0);
@@ -302,6 +306,7 @@
         assertEquals(true, mTestSystemLogger.isMessagesEmpty());
     }
 
+    @MediumTest
     public void testSpawnMultipleThreadMultipleHandlerSession() throws Exception {
         String sessionName = "LT.tSMTMHS";
         Log.startSession(sessionName);
@@ -334,6 +339,7 @@
         assertEquals(true, mTestSystemLogger.isMessagesEmpty());
     }
 
+    @MediumTest
     public void testSpawnMultipleThreadMultipleHandlerSessions() throws Exception {
         String sessionName = "LT.tSMTMHSs";
         isHandlerCompleteWithEvents = false;
@@ -375,6 +381,7 @@
         assertEquals(true, mTestSystemLogger.isMessagesEmpty());
     }
 
+    @MediumTest
     public void testCancelSubsession() throws Exception {
         String sessionName = "LT.tCS";
         Log.startSession(sessionName);
@@ -391,6 +398,7 @@
         assertEquals(true, mTestSystemLogger.isMessagesEmpty());
     }
 
+    @MediumTest
     public void testInternalExternalCallToMethod() throws Exception {
         String sessionName = "LT.tIECTM";
         Log.startSession(sessionName);
@@ -409,6 +417,7 @@
         assertEquals(true, mTestSystemLogger.isMessagesEmpty());
     }
 
+    @MediumTest
     public void testGarbageCollectionWithTimeout() throws Exception {
         String sessionName = "LT.tGCWT";
 
diff --git a/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java b/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
index c997b31..2ac9c50 100644
--- a/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
+++ b/tests/src/com/android/server/telecom/tests/MissedCallNotifierImplTest.java
@@ -30,6 +30,7 @@
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
 import android.telephony.TelephonyManager;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.server.telecom.Call;
 import com.android.server.telecom.Constants;
@@ -112,10 +113,12 @@
         mComponentContextFixture.setTelecomManager(mTelecomManager);
     }
 
+    @SmallTest
     public void testCancelNotificationInPrimaryUser() {
         cancelNotificationTestInternal(PRIMARY_USER);
     }
 
+    @SmallTest
     public void testCancelNotificationInSecondaryUser() {
         cancelNotificationTestInternal(SECONARY_USER);
     }
@@ -147,6 +150,7 @@
         verify(builder2).setContentText(CALLER_NAME);
     }
 
+    @SmallTest
     public void testNotifyMultipleMissedCalls() {
         Notification.Builder[] builders = new Notification.Builder[4];
 
@@ -209,27 +213,32 @@
         }
     }
 
+    @SmallTest
     public void testNotifySingleCallInPrimaryUser() {
         PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
         notifySingleCallTestInternal(phoneAccount, PRIMARY_USER);
     }
 
+    @SmallTest
     public void testNotifySingleCallInSecondaryUser() {
         PhoneAccount phoneAccount = makePhoneAccount(SECONARY_USER, NO_CAPABILITY);
         notifySingleCallTestInternal(phoneAccount, PRIMARY_USER);
     }
 
+    @SmallTest
     public void testNotifySingleCallInSecondaryUserWithMultiUserCapability() {
         PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER,
                 PhoneAccount.CAPABILITY_MULTI_USER);
         notifySingleCallTestInternal(phoneAccount, PRIMARY_USER);
     }
 
+    @SmallTest
     public void testNotifySingleCallWhenCurrentUserIsSecondaryUser() {
         PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
         notifySingleCallTestInternal(phoneAccount, SECONARY_USER);
     }
 
+    @SmallTest
     public void testNotifySingleCall() {
         PhoneAccount phoneAccount = makePhoneAccount(PRIMARY_USER, NO_CAPABILITY);
         notifySingleCallTestInternal(phoneAccount, PRIMARY_USER);
@@ -299,6 +308,7 @@
                 smsIntent, PendingIntent.FLAG_NO_CREATE));
     }
 
+    @SmallTest
     public void testNoSmsBackAfterMissedSipCall() {
         Notification.Builder builder1 = makeNotificationBuilder("builder1");
         MissedCallNotifierImpl.NotificationBuilderFactory fakeBuilderFactory =
diff --git a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
index 67e3f70..ceabc58 100644
--- a/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
+++ b/tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java
@@ -29,6 +29,7 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
+import android.test.suitebuilder.annotation.MediumTest;
 import android.util.Xml;
 
 import com.android.internal.telecom.IConnectionService;
@@ -83,6 +84,7 @@
         super.tearDown();
     }
 
+    @MediumTest
     public void testPhoneAccountHandle() throws Exception {
         PhoneAccountHandle input = new PhoneAccountHandle(new ComponentName("pkg0", "cls0"), "id0");
         PhoneAccountHandle result = roundTripXml(this, input,
@@ -96,6 +98,7 @@
         assertPhoneAccountHandleEquals(inputN, resultN);
     }
 
+    @MediumTest
     public void testPhoneAccount() throws Exception {
         Bundle testBundle = new Bundle();
         testBundle.putInt("EXTRA_INT_1", 1);
@@ -118,9 +121,10 @@
     }
 
     /**
-     * Test to ensure non-supported balues
+     * Test to ensure non-supported values
      * @throws Exception
      */
+    @MediumTest
     public void testPhoneAccountExtrasEdge() throws Exception {
         Bundle testBundle = new Bundle();
         // Ensure null values for string are not persisted.
@@ -149,6 +153,7 @@
         assertFalse(extras.keySet().contains("EXTRA_PARC"));
     }
 
+    @MediumTest
     public void testState() throws Exception {
         PhoneAccountRegistrar.State input = makeQuickState();
         PhoneAccountRegistrar.State result = roundTripXml(this, input,
@@ -162,6 +167,7 @@
         mRegistrar.enablePhoneAccount(account.getAccountHandle(), true);
     }
 
+    @MediumTest
     public void testAccounts() throws Exception {
         int i = 0;
 
@@ -192,10 +198,12 @@
                 PhoneAccount.SCHEME_TEL));
     }
 
+    @MediumTest
     public void testSimCallManager() throws Exception {
         // TODO
     }
 
+    @MediumTest
     public void testDefaultOutgoing() throws Exception {
         mComponentContextFixture.addConnectionService(
                 makeQuickConnectionServiceComponentName(),
@@ -244,6 +252,7 @@
                 mRegistrar.getOutgoingPhoneAccountForSchemeOfCurrentUser(PhoneAccount.SCHEME_TEL));
     }
 
+    @MediumTest
     public void testPhoneAccountParceling() throws Exception {
         PhoneAccountHandle handle = makeQuickAccountHandle("foo");
         roundTripPhoneAccount(new PhoneAccount.Builder(handle, null).build());
diff --git a/tests/src/com/android/server/telecom/tests/ProximitySensorManagerTest.java b/tests/src/com/android/server/telecom/tests/ProximitySensorManagerTest.java
index f08da0c..01bd09e 100644
--- a/tests/src/com/android/server/telecom/tests/ProximitySensorManagerTest.java
+++ b/tests/src/com/android/server/telecom/tests/ProximitySensorManagerTest.java
@@ -17,6 +17,7 @@
 package com.android.server.telecom.tests;
 
 import android.os.PowerManager;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.server.telecom.Call;
 import com.android.server.telecom.CallsManager;
@@ -55,6 +56,7 @@
         super.tearDown();
     }
 
+    @SmallTest
     public void testTurnOnProximityWithCallsActive() throws Exception {
         when(mCallsManager.getCalls()).thenReturn(new ArrayList<Call>(){{
             add(mCall);
@@ -66,6 +68,7 @@
         verify(mWakeLockAdapter).acquire();
     }
 
+    @SmallTest
     public void testTurnOnProximityWithNoCallsActive() throws Exception {
         when(mCallsManager.getCalls()).thenReturn(new ArrayList<Call>());
         when(mWakeLockAdapter.isHeld()).thenReturn(false);
@@ -76,6 +79,7 @@
 
     }
 
+    @SmallTest
     public void testTurnOffProximityExplicitly() throws Exception {
         when(mWakeLockAdapter.isHeld()).thenReturn(true);
 
@@ -84,6 +88,7 @@
         verify(mWakeLockAdapter).release(0);
     }
 
+    @SmallTest
     public void testCallRemovedFromCallsManagerCallsActive() throws Exception {
         when(mCallsManager.getCalls()).thenReturn(new ArrayList<Call>(){{
             add(mCall);
@@ -95,6 +100,7 @@
         verify(mWakeLockAdapter, never()).release(0);
     }
 
+    @SmallTest
     public void testCallRemovedFromCallsManagerNoCallsActive() throws Exception {
         when(mCallsManager.getCalls()).thenReturn(new ArrayList<Call>());
         when(mWakeLockAdapter.isHeld()).thenReturn(true);
diff --git a/tests/src/com/android/server/telecom/tests/SystemStateProviderTest.java b/tests/src/com/android/server/telecom/tests/SystemStateProviderTest.java
index 02e7ecf..ad740f4 100644
--- a/tests/src/com/android/server/telecom/tests/SystemStateProviderTest.java
+++ b/tests/src/com/android/server/telecom/tests/SystemStateProviderTest.java
@@ -26,6 +26,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.Configuration;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.server.telecom.SystemStateProvider;
 import com.android.server.telecom.SystemStateProvider.SystemStateListener;
@@ -58,6 +59,7 @@
         super.tearDown();
     }
 
+    @SmallTest
     public void testListeners() throws Exception {
         SystemStateProvider systemStateProvider = new SystemStateProvider(mContext);
 
@@ -67,18 +69,21 @@
         assertFalse(systemStateProvider.removeListener(mSystemStateListener));
     }
 
+    @SmallTest
     public void testQuerySystemForCarMode_True() {
         when(mContext.getSystemService(Context.UI_MODE_SERVICE)).thenReturn(mUiModeManager);
         when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_CAR);
         assertTrue(new SystemStateProvider(mContext).isCarMode());
     }
 
+    @SmallTest
     public void testQuerySystemForCarMode_False() {
         when(mContext.getSystemService(Context.UI_MODE_SERVICE)).thenReturn(mUiModeManager);
         when(mUiModeManager.getCurrentModeType()).thenReturn(Configuration.UI_MODE_TYPE_NORMAL);
         assertFalse(new SystemStateProvider(mContext).isCarMode());
     }
 
+    @SmallTest
     public void testReceiverAndIntentFilter() {
         ArgumentCaptor<IntentFilter> intentFilter = ArgumentCaptor.forClass(IntentFilter.class);
         new SystemStateProvider(mContext);
@@ -89,6 +94,7 @@
         assertEquals(UiModeManager.ACTION_EXIT_CAR_MODE, intentFilter.getValue().getAction(1));
     }
 
+    @SmallTest
     public void testOnEnterExitCarMode() {
         ArgumentCaptor<BroadcastReceiver> receiver =
                 ArgumentCaptor.forClass(BroadcastReceiver.class);
diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
index ed61378..12d82b3 100644
--- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
+++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java
@@ -371,9 +371,38 @@
         return audioService;
     }
 
+    protected String startOutgoingPhoneCallWithNoPhoneAccount(String number,
+            ConnectionServiceFixture connectionServiceFixture)
+            throws Exception {
+
+        return startOutgoingPhoneCallPendingCreateConnection(number, null,
+                connectionServiceFixture, Process.myUserHandle(), VideoProfile.STATE_AUDIO_ONLY);
+    }
+
+    protected IdPair outgoingCallPhoneAccountSelected(PhoneAccountHandle phoneAccountHandle,
+            int startingNumConnections, int startingNumCalls,
+            ConnectionServiceFixture connectionServiceFixture) throws Exception {
+
+        IdPair ids = outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
+                phoneAccountHandle, connectionServiceFixture);
+
+        connectionServiceFixture.sendSetDialing(ids.mConnectionId);
+        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_DIALING, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+        connectionServiceFixture.sendSetVideoState(ids.mConnectionId);
+
+        connectionServiceFixture.sendSetActive(ids.mConnectionId);
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureX.getCall(ids.mCallId).getState());
+        assertEquals(Call.STATE_ACTIVE, mInCallServiceFixtureY.getCall(ids.mCallId).getState());
+
+        return ids;
+    }
+
     protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle,
             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser)
             throws Exception {
+
         return startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture,
                 initiatingUser, VideoProfile.STATE_AUDIO_ONLY);
     }
@@ -381,6 +410,20 @@
     protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle,
             ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
             int videoState) throws Exception {
+        int startingNumConnections = connectionServiceFixture.mConnectionById.size();
+        int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
+
+        startOutgoingPhoneCallPendingCreateConnection(number, phoneAccountHandle,
+                connectionServiceFixture, initiatingUser, videoState);
+
+        return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls,
+                phoneAccountHandle, connectionServiceFixture);
+    }
+
+    protected String startOutgoingPhoneCallPendingCreateConnection(String number,
+            PhoneAccountHandle phoneAccountHandle,
+            ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser,
+            int videoState) throws Exception {
         reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(),
                 mInCallServiceFixtureY.getTestDouble());
 
@@ -390,8 +433,7 @@
                 (mInCallServiceFixtureY.mInCallAdapter != null));
 
         mNumOutgoingCallsMade++;
-        int startingNumConnections = connectionServiceFixture.mConnectionById.size();
-        int startingNumCalls = mInCallServiceFixtureX.mCallById.size();
+
         boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null;
 
         Intent actionCallIntent = new Intent();
@@ -453,6 +495,13 @@
         newOutgoingCallReceiver.getValue().onReceive(mComponentContextFixture.getTestDouble(),
                 newOutgoingCallIntent.getValue());
 
+        return mInCallServiceFixtureX.mLatestCallId;
+    }
+
+    protected IdPair outgoingCallCreateConnectionComplete(int startingNumConnections,
+            int startingNumCalls, PhoneAccountHandle phoneAccountHandle,
+            ConnectionServiceFixture connectionServiceFixture) throws Exception {
+
         assertEquals(startingNumConnections + 1, connectionServiceFixture.mConnectionById.size());
 
         verify(connectionServiceFixture.getTestDouble())